[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] scratch/record 6d6b9b1 01/10: Add record objects with user
From: |
Lars Brinkhoff |
Subject: |
[Emacs-diffs] scratch/record 6d6b9b1 01/10: Add record objects with user-defined types. |
Date: |
Fri, 24 Mar 2017 11:51:41 -0400 (EDT) |
branch: scratch/record
commit 6d6b9b1c97d2ea877012d41f200883bd91eb39d8
Author: Lars Brinkhoff <address@hidden>
Commit: Lars Brinkhoff <address@hidden>
Add record objects with user-defined types.
* src/alloc.c (allocate_record): New function.
(Fmake_record, Frecord, Fcopy_record): New functions.
(syms_of_alloc): defsubr them.
(purecopy): Work with records.
* src/data.c (Ftype_of): Return slot 0 for record objects.
(Frecordp): New function.
(syms_of_data): defsubr it. Define `Qrecordp'.
(Faref, Faset): Work with records.
* src/fns.c (Flength): Work with records.
* src/lisp.h (prec_type): Add PVEC_RECORD.
(RECORDP, CHECK_RECORD, CHECK_RECORD_TYPE): New functions.
* src/lread.c (read1): Add syntax for records.
* src/print.c (PRINT_CIRCLE_CANDIDATE_P): Add RECORDP.
(print_object): Add syntax for records.
* test/lisp/emacs-lisp/cl-print-tests.el (cl-print-tests-2):
New test.
* test/src/alloc-tests.el (record-1, record-2, record-3):
New tests.
* doc/lispref/elisp.texi, doc/lispref/objects.texi,
doc/lispref/records.texi: Add documentation for records.
---
doc/lispref/elisp.texi | 7 +++
doc/lispref/objects.texi | 24 +++++++--
doc/lispref/records.texi | 98 ++++++++++++++++++++++++++++++++++
src/alloc.c | 95 +++++++++++++++++++++++++++++++-
src/data.c | 29 ++++++++--
src/fns.c | 2 +-
src/lisp.h | 23 ++++++++
src/lread.c | 13 +++++
src/print.c | 10 +++-
test/lisp/emacs-lisp/cl-print-tests.el | 10 ++++
test/src/alloc-tests.el | 20 +++++++
11 files changed, 322 insertions(+), 9 deletions(-)
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index e0bd337..0f7efb6 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -180,6 +180,7 @@ To view this manual in other formats, click
* Sequences Arrays Vectors:: Lists, strings and vectors are called sequences.
Certain functions act on any kind of sequence.
The description of vectors is here as well.
+* Records:: Compound objects with programmer-defined types.
* Hash Tables:: Very fast lookup-tables.
* Symbols:: Symbols represent names, uniquely.
@@ -314,6 +315,7 @@ Programming Types
expression, more fundamental but less pretty.
* Primitive Function Type:: A function written in C, callable from Lisp.
* Byte-Code Type:: A function written in Lisp, then compiled.
+* Record Type:: Compound objects with programmer-defined types.
* Autoload Type:: A type used for automatically loading seldom-used
functions.
* Finalizer Type:: Runs code when no longer reachable.
@@ -418,6 +420,10 @@ Sequences, Arrays, and Vectors
* Bool-Vectors:: How to work with bool-vectors.
* Rings:: Managing a fixed-size ring of objects.
+Records
+
+* Record Functions:: Functions for records.
+
Hash Tables
* Creating Hash:: Functions to create hash tables.
@@ -1594,6 +1600,7 @@ Object Internals
@include lists.texi
@include sequences.texi
address@hidden records.texi
@include hash.texi
@include symbols.texi
@include eval.texi
diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi
index 56049af..90cafbe 100644
--- a/doc/lispref/objects.texi
+++ b/doc/lispref/objects.texi
@@ -25,9 +25,10 @@ but not for @emph{the} type of an object.
which all other types are constructed, are called @dfn{primitive types}.
Each object belongs to one and only one primitive type. These types
include @dfn{integer}, @dfn{float}, @dfn{cons}, @dfn{symbol},
address@hidden, @dfn{vector}, @dfn{hash-table}, @dfn{subr}, and
address@hidden function}, plus several special types, such as
address@hidden, that are related to editing. (@xref{Editing Types}.)
address@hidden, @dfn{vector}, @dfn{hash-table}, @dfn{subr},
address@hidden function}, and @dfn{record}, plus several special
+types, such as @dfn{buffer}, that are related to editing.
+(@xref{Editing Types}.)
Each primitive type has a corresponding Lisp function that checks
whether an object is a member of that type.
@@ -154,6 +155,7 @@ latter are unique to Emacs Lisp.
expression, more fundamental but less pretty.
* Primitive Function Type:: A function written in C, callable from Lisp.
* Byte-Code Type:: A function written in Lisp, then compiled.
+* Record Type:: Compound objects with programmer-defined types.
* Autoload Type:: A type used for automatically loading seldom-used
functions.
* Finalizer Type:: Runs code when no longer reachable.
@@ -1347,6 +1349,16 @@ The printed representation and read syntax for a
byte-code function
object is like that for a vector, with an additional @samp{#} before the
opening @samp{[}.
address@hidden Record Type
address@hidden Record Type
+
+ A @dfn{record} is much like a @code{vector}. However, the first
+element is used to hold its type as returned by @code{type-of}. The
+purpose of records is to allow programmers to create objects with new
+types that are not built into Emacs.
+
+ @xref{Records}, for functions that work with records.
+
@node Autoload Type
@subsection Autoload Type
@@ -1959,6 +1971,9 @@ with references to further information.
@item processp
@xref{Processes, processp}.
address@hidden recordp
address@hidden Type, recordp}.
+
@item sequencep
@xref{Sequence Functions, sequencep}.
@@ -2022,6 +2037,7 @@ This function returns a symbol naming the primitive type
of
@code{marker}, @code{mutex}, @code{overlay}, @code{process},
@code{string}, @code{subr}, @code{symbol}, @code{thread},
@code{vector}, @code{window}, or @code{window-configuration}.
+However, if @var{object} is a record, its first slot is returned.
@example
(type-of 1)
@@ -2033,6 +2049,8 @@ This function returns a symbol naming the primitive type
of
@result{} symbol
(type-of '(x))
@result{} cons
+(type-of (record 'foo))
+ @result{} foo
@end group
@end example
@end defun
diff --git a/doc/lispref/records.texi b/doc/lispref/records.texi
new file mode 100644
index 0000000..a11b431
--- /dev/null
+++ b/doc/lispref/records.texi
@@ -0,0 +1,98 @@
address@hidden -*-texinfo-*-
address@hidden This is part of the GNU Emacs Lisp Reference Manual.
address@hidden Copyright (C) 2017 Free Software
address@hidden Foundation, Inc.
address@hidden See the file elisp.texi for copying conditions.
address@hidden Records
address@hidden Records
address@hidden record
+
+ The purpose of records is to allow programmers to create objects
+with new types that are not built into Emacs.
+
+ Internally, a record object is much like a vector; its slots can be
+accessed using @code{aref}. However, the first slot is used to hold
+its type as returned by @code{type-of}. Like arrays, records use
+zero-origin indexing: the first slot has index 0.
+
+ The printed representation of records is like that for a vector,
+with an additional @samp{#%} before the opening @samp{[}. It must have
+at least one slot: the type.
+
+ A record is considered a constant for evaluation: the result of
+evaluating it is the same record. This does not evaluate or even
+examine the slots. @xref{Self-Evaluating Forms}.
+
address@hidden
+* Record Functions:: Functions for records.
address@hidden menu
+
address@hidden Record Functions
address@hidden Record Functions
+
address@hidden recordp object
+This function returns @code{t} if @var{object} is a record.
+
address@hidden
address@hidden
+(recordp #%[a])
+ @result{} t
address@hidden group
address@hidden example
address@hidden defun
+
address@hidden record type &rest objects
+This function creates and returns a record whose type is @var{type}
+and remaining slots are the rest of thearguments, @var{objects}.
+
address@hidden
address@hidden
+(vector 'foo 23 [bar baz] "rats")
+ @result{} #%[foo 23 [bar baz] "rats"]
address@hidden group
address@hidden example
address@hidden defun
+
address@hidden make-record type length object
+This function returns a new record with type @var{type} and
address@hidden more slots, each initialized to @var{object}.
+
address@hidden
address@hidden
+(setq sleepy (make-record 'foo 9 'Z))
+ @result{} #%[foo Z Z Z Z Z Z Z Z Z]
address@hidden group
address@hidden example
address@hidden defun
+
address@hidden copy-record record
+This function returns a shallow copy of @var{record}. The copy is the
+same type of as the original record, and it has the same slots in the
+same order.
+
+ Storing a new slot into the copy does not affect the original
address@hidden, and vice versa. However, the slots of the new record
+are not copies; they are identical (@code{eq}) to the slots of the
+original. Therefore, changes made within these slots, as found via
+the copied record, are also visible in the original record.
+
address@hidden
address@hidden
+(setq x (record 'foo 1 2))
+ @result{} #%[foo 1 2]
address@hidden group
address@hidden
+(setq y (copy-record x))
+ @result{} #%[foo 1 2]
address@hidden group
+
address@hidden
+(eq x y)
+ @result{} nil
address@hidden group
address@hidden
+(equal x y)
+ @result{} t
address@hidden group
address@hidden example
address@hidden defun
diff --git a/src/alloc.c b/src/alloc.c
index ae3e151..d46f2a7 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3392,6 +3392,96 @@ allocate_buffer (void)
return b;
}
+
+/* Allocate a new record with COUNT slots. Return NULL if COUNT is
+ too large. */
+
+static struct Lisp_Vector *
+allocate_record (int count)
+{
+ if (count >= (1 << PSEUDOVECTOR_SIZE_BITS))
+ return NULL;
+
+ struct Lisp_Vector *p = allocate_vector (count);
+ XSETPVECTYPE (p, PVEC_RECORD);
+ return p;
+}
+
+
+DEFUN ("make-record", Fmake_record, Smake_record, 3, 3, 0,
+ doc: /* Create a new record.
+TYPE is its type as returned by `type-of'. SLOTS is the number of
+slots, each initialized to INIT. The number of slots, including the
+type slot, must fit in PSEUDOVECTOR_SIZE_BITS. */)
+ (Lisp_Object type, Lisp_Object slots, Lisp_Object init)
+{
+ Lisp_Object record;
+ ptrdiff_t size, i;
+ struct Lisp_Vector *p;
+
+ CHECK_RECORD_TYPE (type);
+ CHECK_NATNUM (slots);
+
+ size = XFASTINT (slots) + 1;
+ p = allocate_record (size);
+ if (p == NULL)
+ error ("Attempt to allocate a record of %ld slots; max is %d",
+ size, (1 << PSEUDOVECTOR_SIZE_BITS) - 1);
+
+ p->contents[0] = type;
+ for (i = 1; i < size; i++)
+ p->contents[i] = init;
+
+ XSETVECTOR (record, p);
+ return record;
+}
+
+
+DEFUN ("record", Frecord, Srecord, 1, MANY, 0,
+ doc: /* Create a new record.
+TYPE is its type as returned by `type-of'. SLOTS is used to
+initialize the record slots with shallow copies of the arguments. The
+number of slots, including the type slot, must fit in
+PSEUDOVECTOR_SIZE_BITS.
+usage: (record TYPE &rest SLOTS) */)
+ (ptrdiff_t nargs, Lisp_Object *args)
+{
+ struct Lisp_Vector *p = allocate_record (nargs);
+ if (p == NULL)
+ error ("Attempt to allocate a record of %ld slots; max is %d",
+ nargs, (1 << PSEUDOVECTOR_SIZE_BITS) - 1);
+
+ Lisp_Object type = args[0];
+ Lisp_Object record;
+
+ CHECK_RECORD_TYPE (type);
+ p->contents[0] = type;
+ memcpy (p->contents + 1, args + 1, (nargs - 1) * sizeof *args);
+
+ XSETVECTOR (record, p);
+ return record;
+}
+
+
+DEFUN ("copy-record", Fcopy_record, Scopy_record, 1, 1, 0,
+ doc: /* Return a new record that is a shallow copy of the argument
RECORD. */)
+ (Lisp_Object record)
+{
+ CHECK_RECORD (record);
+ struct Lisp_Vector *src = XVECTOR (record);
+ ptrdiff_t size = ASIZE (record) & PSEUDOVECTOR_SIZE_MASK;
+ struct Lisp_Vector *new = allocate_record (size);
+ if (new == NULL)
+ error ("Attempt to allocate a record of %ld slots; max is %d",
+ size, (1 << PSEUDOVECTOR_SIZE_BITS) - 1);
+
+ memcpy (&(new->contents[0]), &(src->contents[0]),
+ size * sizeof (Lisp_Object));
+ XSETVECTOR (record, new);
+ return record;
+}
+
+
DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0,
doc: /* Return a newly created vector of length LENGTH, with each
element being INIT.
See also the function `vector'. */)
@@ -5532,7 +5622,7 @@ purecopy (Lisp_Object obj)
struct Lisp_Hash_Table *h = purecopy_hash_table (table);
XSET_HASH_TABLE (obj, h);
}
- else if (COMPILEDP (obj) || VECTORP (obj))
+ else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
{
struct Lisp_Vector *objp = XVECTOR (obj);
ptrdiff_t nbytes = vector_nbytes (objp);
@@ -7461,10 +7551,13 @@ The time is in seconds as a floating point value. */);
defsubr (&Scons);
defsubr (&Slist);
defsubr (&Svector);
+ defsubr (&Srecord);
+ defsubr (&Scopy_record);
defsubr (&Sbool_vector);
defsubr (&Smake_byte_code);
defsubr (&Smake_list);
defsubr (&Smake_vector);
+ defsubr (&Smake_record);
defsubr (&Smake_string);
defsubr (&Smake_bool_vector);
defsubr (&Smake_symbol);
diff --git a/src/data.c b/src/data.c
index ae8dd97..8e0bccc 100644
--- a/src/data.c
+++ b/src/data.c
@@ -267,6 +267,7 @@ for example, (type-of 1) returns `integer'. */)
case PVEC_MUTEX: return Qmutex;
case PVEC_CONDVAR: return Qcondition_variable;
case PVEC_TERMINAL: return Qterminal;
+ case PVEC_RECORD: return AREF (object, 0);
/* "Impossible" cases. */
case PVEC_XWIDGET:
case PVEC_OTHER:
@@ -359,6 +360,15 @@ DEFUN ("vectorp", Fvectorp, Svectorp, 1, 1, 0,
return Qnil;
}
+DEFUN ("recordp", Frecordp_p, Srecordp, 1, 1, 0,
+ doc: /* Return t if OBJECT is a record. */)
+ (Lisp_Object object)
+{
+ if (RECORDP (object))
+ return Qt;
+ return Qnil;
+}
+
DEFUN ("stringp", Fstringp, Sstringp, 1, 1, 0,
doc: /* Return t if OBJECT is a string. */
attributes: const)
@@ -2287,7 +2297,7 @@ or a byte-code object. IDX starts at 0. */)
ptrdiff_t size = 0;
if (VECTORP (array))
size = ASIZE (array);
- else if (COMPILEDP (array))
+ else if (COMPILEDP (array) || RECORDP (array))
size = ASIZE (array) & PSEUDOVECTOR_SIZE_MASK;
else
wrong_type_argument (Qarrayp, array);
@@ -2308,7 +2318,8 @@ bool-vector. IDX starts at 0. */)
CHECK_NUMBER (idx);
idxval = XINT (idx);
- CHECK_ARRAY (array, Qarrayp);
+ if (! RECORDP (array))
+ CHECK_ARRAY (array, Qarrayp);
if (VECTORP (array))
{
@@ -2328,7 +2339,16 @@ bool-vector. IDX starts at 0. */)
CHECK_CHARACTER (idx);
CHAR_TABLE_SET (array, idxval, newelt);
}
- else
+ else if (RECORDP (array))
+ {
+ ptrdiff_t size = ASIZE (array) & PSEUDOVECTOR_SIZE_MASK;
+ if (idxval < 0 || idxval >= size)
+ args_out_of_range (array, idx);
+ if (idxval == 0)
+ CHECK_RECORD_TYPE (newelt);
+ ASET (array, idxval, newelt);
+ }
+ else /* STRINGP */
{
int c;
@@ -3604,6 +3624,7 @@ syms_of_data (void)
DEFSYM (Qsequencep, "sequencep");
DEFSYM (Qbufferp, "bufferp");
DEFSYM (Qvectorp, "vectorp");
+ DEFSYM (Qrecordp, "recordp");
DEFSYM (Qbool_vector_p, "bool-vector-p");
DEFSYM (Qchar_or_string_p, "char-or-string-p");
DEFSYM (Qmarkerp, "markerp");
@@ -3714,6 +3735,7 @@ syms_of_data (void)
DEFSYM (Qbuffer, "buffer");
DEFSYM (Qframe, "frame");
DEFSYM (Qvector, "vector");
+ DEFSYM (Qrecord, "record");
DEFSYM (Qchar_table, "char-table");
DEFSYM (Qbool_vector, "bool-vector");
DEFSYM (Qhash_table, "hash-table");
@@ -3750,6 +3772,7 @@ syms_of_data (void)
defsubr (&Sstringp);
defsubr (&Smultibyte_string_p);
defsubr (&Svectorp);
+ defsubr (&Srecordp);
defsubr (&Schar_table_p);
defsubr (&Svector_or_char_table_p);
defsubr (&Sbool_vector_p);
diff --git a/src/fns.c b/src/fns.c
index 1065355..36bde20 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -104,7 +104,7 @@ To get the number of bytes, use `string-bytes'. */)
XSETFASTINT (val, MAX_CHAR);
else if (BOOL_VECTOR_P (sequence))
XSETFASTINT (val, bool_vector_size (sequence));
- else if (COMPILEDP (sequence))
+ else if (COMPILEDP (sequence) || RECORDP (sequence))
XSETFASTINT (val, ASIZE (sequence) & PSEUDOVECTOR_SIZE_MASK);
else if (CONSP (sequence))
{
diff --git a/src/lisp.h b/src/lisp.h
index 4b9cd3c..b7c4d69 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -889,6 +889,7 @@ enum pvec_type
PVEC_COMPILED,
PVEC_CHAR_TABLE,
PVEC_SUB_CHAR_TABLE,
+ PVEC_RECORD,
PVEC_FONT /* Should be last because it's used for range checking. */
};
@@ -1412,6 +1413,7 @@ CHECK_VECTOR (Lisp_Object x)
CHECK_TYPE (VECTORP (x), Qvectorp, x);
}
+
/* A pseudovector is like a vector, but has other non-Lisp components. */
INLINE enum pvec_type
@@ -2732,6 +2734,27 @@ FRAMEP (Lisp_Object a)
return PSEUDOVECTORP (a, PVEC_FRAME);
}
+INLINE bool
+RECORDP (Lisp_Object a)
+{
+ return PSEUDOVECTORP (a, PVEC_RECORD);
+}
+
+INLINE void
+CHECK_RECORD (Lisp_Object x)
+{
+ CHECK_TYPE (RECORDP (x), Qrecordp, x);
+}
+
+INLINE void
+CHECK_RECORD_TYPE (Lisp_Object x)
+{
+ /* We don't yet know exactly what to check for, or if there should
+ be a check. */
+
+ /* eassert (SYMBOLP (x) || CLASSP (x)); */
+}
+
/* Test for image (image . spec) */
INLINE bool
IMAGEP (Lisp_Object x)
diff --git a/src/lread.c b/src/lread.c
index 5c6a7f9..1fcbc37 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2762,6 +2762,19 @@ read1 (Lisp_Object readcharfun, int *pch, bool
first_in_list)
make_byte_code (vec);
return tmp;
}
+ if (c == '%')
+ {
+ c = READCHAR;
+ if (c == '[')
+ {
+ Lisp_Object tmp;
+ tmp = read_vector (readcharfun, 1);
+ XSETPVECTYPE (XVECTOR(tmp), PVEC_RECORD);
+ return tmp;
+ }
+ UNREAD (c);
+ invalid_syntax ("#");
+ }
if (c == '(')
{
Lisp_Object tmp;
diff --git a/src/print.c b/src/print.c
index e857761..402df03 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1135,7 +1135,8 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool
escapeflag)
|| (VECTORLIKEP (obj) \
&& (VECTORP (obj) || COMPILEDP (obj) \
|| CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) \
- || HASH_TABLE_P (obj) || FONTP (obj))) \
+ || HASH_TABLE_P (obj) || FONTP (obj) \
+ || RECORDP (obj))) \
|| (! NILP (Vprint_gensym) \
&& SYMBOLP (obj) \
&& !SYMBOL_INTERNED_P (obj)))
@@ -1966,6 +1967,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun,
bool escapeflag)
case PVEC_SUB_CHAR_TABLE:
case PVEC_COMPILED:
case PVEC_CHAR_TABLE:
+ case PVEC_RECORD:
case PVEC_NORMAL_VECTOR: ;
{
ptrdiff_t size = ASIZE (obj);
@@ -1974,6 +1976,12 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun,
bool escapeflag)
printchar ('#', printcharfun);
size &= PSEUDOVECTOR_SIZE_MASK;
}
+ if (RECORDP (obj))
+ {
+ printchar ('#', printcharfun);
+ printchar ('%', printcharfun);
+ size &= PSEUDOVECTOR_SIZE_MASK;
+ }
if (CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj))
{
/* We print a char-table as if it were a vector,
diff --git a/test/lisp/emacs-lisp/cl-print-tests.el
b/test/lisp/emacs-lisp/cl-print-tests.el
index 04ddfee..547dbe7 100644
--- a/test/lisp/emacs-lisp/cl-print-tests.el
+++ b/test/lisp/emacs-lisp/cl-print-tests.el
@@ -37,4 +37,14 @@
(should (string-match "\\`#f(compiled-function (x) .*\n\n.*)\\'"
(cl-prin1-to-string (symbol-function #'caar))))))
+(ert-deftest cl-print-tests-2 ()
+ (let ((x (record 'foo 1 2 3)))
+ (should (equal
+ x
+ (car (read-from-string (with-output-to-string (prin1 x))))))
+ (let ((print-circle t))
+ (should (string-match
+ "\\`(#1=.* #1#)\\'"
+ (cl-prin1-to-string (list x x)))))))
+
;;; cl-print-tests.el ends here.
diff --git a/test/src/alloc-tests.el b/test/src/alloc-tests.el
index af4ad6c..8b4ef8c 100644
--- a/test/src/alloc-tests.el
+++ b/test/src/alloc-tests.el
@@ -31,3 +31,23 @@
(ert-deftest finalizer-object-type ()
(should (equal (type-of (make-finalizer nil)) 'finalizer)))
+
+(ert-deftest record-1 ()
+ (let ((x (record 'foo 1 2 3)))
+ (should (recordp x))
+ (should (eq (type-of x) 'foo))
+ (should (eq (aref x 0) 'foo))
+ (should (eql (aref x 3) 3))
+ (should (eql (length x) 4))))
+
+(ert-deftest record-2 ()
+ (let ((x (make-record 'bar 1 0)))
+ (should (eql (length x) 2))
+ (should (eql (aref x 1) 0))))
+
+(ert-deftest record-3 ()
+ (let* ((x (record 'foo 1 2 3))
+ (y (copy-record x)))
+ (should-not (eq x y))
+ (dotimes (i 4)
+ (should (eql (aref x i) (aref y i))))))
- [Emacs-diffs] branch scratch/record created (now 4ea0d9d), Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record b5475b8 07/10: Remove CHECK_RECORD_TYPE., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 96a0547 08/10: The sky isn't so blue after all., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 0013635 06/10: Change read/print syntax to use #s., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 3cda36e 05/10: Backward compatibility with pre-existing struct instances., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 584c08c 04/10: Make the URL library use records., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 8b1b962 03/10: Make EIEIO use records., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 6d6b9b1 01/10: Add record objects with user-defined types.,
Lars Brinkhoff <=
- [Emacs-diffs] scratch/record 603f016 02/10: Make cl-defstruct use records., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 7dbb1dc 09/10: * src/data.c (Ftype_of): Return type name, if record's type holds class., Lars Brinkhoff, 2017/03/24
- [Emacs-diffs] scratch/record 4ea0d9d 10/10: Make type-of return the type, even for old-style structs, Lars Brinkhoff, 2017/03/24