ref: 12c9d2fc728b51aa1eb9a70d0d331eb9464912d9
parent: 177cf681e5cf46117196a78c21ae0e6f5671a639
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Mar 13 13:42:46 EDT 2025
defstruct: more :constructor logic * accept (the default) T to make a keyworded constructor with make-* name. * support NIL to disable making constructor * support just a custom name by specifying a single symbol References: https://todo.sr.ht/~ft/sl/48
--- a/boot/sl.boot
+++ b/boot/sl.boot
@@ -16,10 +16,10 @@
(data :size
decompressed-bytes)) void? ((x)) >= ((a . rest)) defstruct ((name
doc options... (slot-1 DEFAULT) slot-2 (slot-3 :read-only))
- (name (:type vector) (:named T) (:constructor NIL) (:conc-name NIL) (:predicate NIL) . slots)
+ (name (:type vector) (:named T) (:constructor T) (:conc-name NIL) (:predicate NIL) . slots)
(name doc options... (slot-1 DEFAULT) slot-2 (slot-3 :read-only))) help ((term)) length= ((lst
n)) __finish ((status)) doc-for ((term (doc NIL))) rand-u32 (NIL) = ((a . rest)) rand-u64 (NIL) car ((lst)) <= ((a . rest)) add-exit-hook ((fun)) /= ((a . rest)) lz-pack ((data
- (level 0))) rand (NIL) nan? ((x)) rand-float (NIL) void (rest) cons? ((value)) vm-stats (NIL) rand-double (NIL) * ((number…)) cdr ((lst)) + ((number…)) > ((a . rest))) *doc* #table(>= "Return T if the arguments are in non-increasing order (previous\none is greater than or equal to the next one)." void? "Return T if x is #<void>, NIL otherwise." length= "Bounded length test.\nUse this instead of (= (length lst) n), since it avoids unnecessary\nwork and always terminates." doc-for "Define documentation for a top level term.\nIf the optional doc argument is missing and the term is a function\nsignture, adds it to the documentation." car "Return the first element of a list or NIL if not available." *builtins* "VM instructions as closures." <= "Return T if the arguments are in non-decreasing order (previous\none is less than or equal to the next one)." void "Return the constant #<void> while ignoring any arguments.\n#<void> is mainly used when a function has side effects but does not\nproduce any meaningful value to return, so even though T or NIL could\nbe returned instead, in case of #<void> alone, REPL will not print\nit." rand "Return a random non-negative fixnum on its maximum range." nan? "Return T if the argument is NaN, regardless of the sign." Instructions "VM instructions mapped to their encoded byte representation." rand-double "Return a random double on [0.0, 1.0] interval." > "Return T if the arguments are in strictly decreasing order (previous\none is greater than the next one)." cdr "Return the tail of a list or NIL if not available." + "Return sum of the numbers or 0 with no arguments." __finish "A function called right before exit by the VM." lz-unpack "Return decompressed data previously compressed using lz-pack.\nEither destination for the decompressed data or the expected size of\nthe decompressed data must be specified. In the latter case a new\narray is allocated." help "Display documentation for the specified term, if available." defstruct "Defines a structure type with a specific name and slots.\nThe default underlying type is a named vector, ie the first element is\nthe name of the structure type, the rest are the slot values.\n\nIf the name as the first element isn't required, \":named NIL\" should\nbe used.\n\nA list can be used instead of a vector, e.g.:\n (defstruct st :type list ...)\n\nThe option :conc-name specifies the slot accessor prefix, which\ndefaults to \"name-\".\n\nDefault predicate name (\"name?\") can be changed:\n (defstruct blah :predicate blargh? a b c)" rand-u32 "Return a random integer on [0, 2³²-1] interval." = "Return T if the arguments are equal." rand-u64 "Return a random integer on [0, 2⁶⁴-1] interval." add-exit-hook "Puts an one-argument function on top of the list of exit hooks.\nOn shutdown each exit hook is called with the exit status as a single\nargument, which is (usually) 0 on success and any other number on\nerror." /= "Return T if not all arguments are equal. Shorthand for (not (= …))." lz-pack "Return data compressed using Lempel-Ziv.\nThe data must be an array, returned value will have the same type.\nThe optional level is between 0 and 10. With level 0 a simple LZSS\nusing hashing will be performed. Levels between 1 and 9 offer a\ntrade-off between time/space and ratio. Level 10 is optimal but very\nslow." arg-counts "VM instructions mapped to their expected arguments count." rand-float "Return a random float on [0.0, 1.0] interval." *prompt* "Function called by REPL to signal the user input is required.\nDefault function prints \"#;> \"." cons? "Return T if the value is a cons cell." vm-stats "Print various VM-related information, such as the number of GC calls\nso far, heap and stack size, etc." * "Return product of the numbers or 1 with no arguments." *properties* "All properties of symbols recorded with putprop are recorded in this table."))
+ (level 0))) rand (NIL) nan? ((x)) rand-float (NIL) void (rest) cons? ((value)) vm-stats (NIL) rand-double (NIL) * ((number…)) cdr ((lst)) + ((number…)) > ((a . rest))) *doc* #table(>= "Return T if the arguments are in non-increasing order (previous\none is greater than or equal to the next one)." void? "Return T if x is #<void>, NIL otherwise." length= "Bounded length test.\nUse this instead of (= (length lst) n), since it avoids unnecessary\nwork and always terminates." doc-for "Define documentation for a top level term.\nIf the optional doc argument is missing and the term is a function\nsignture, adds it to the documentation." car "Return the first element of a list or NIL if not available." *builtins* "VM instructions as closures." <= "Return T if the arguments are in non-decreasing order (previous\none is less than or equal to the next one)." void "Return the constant #<void> while ignoring any arguments.\n#<void> is mainly used when a function has side effects but does not\nproduce any meaningful value to return, so even though T or NIL could\nbe returned instead, in case of #<void> alone, REPL will not print\nit." rand "Return a random non-negative fixnum on its maximum range." nan? "Return T if the argument is NaN, regardless of the sign." Instructions "VM instructions mapped to their encoded byte representation." rand-double "Return a random double on [0.0, 1.0] interval." > "Return T if the arguments are in strictly decreasing order (previous\none is greater than the next one)." cdr "Return the tail of a list or NIL if not available." + "Return sum of the numbers or 0 with no arguments." __finish "A function called right before exit by the VM." lz-unpack "Return decompressed data previously compressed using lz-pack.\nEither destination for the decompressed data or the expected size of\nthe decompressed data must be specified. In the latter case a new\narray is allocated." help "Display documentation for the specified term, if available." defstruct "Defines a structure type with a specific name and slots.\nThe default underlying type is a named vector, ie the first element is\nthe name of the structure type, the rest are the slot values. If the\nname as the first element isn't required, \":named NIL\" should be\nused. A list can be used instead of a vector by adding \":type list\"\noption.\n\nThe option :conc-name specifies the slot accessor prefix, which\ndefaults to \"name-\".\n\nDefault predicate name (\"name?\") can be changed:\n (defstruct blah :predicate blargh? a b c)" rand-u32 "Return a random integer on [0, 2³²-1] interval." = "Return T if the arguments are equal." rand-u64 "Return a random integer on [0, 2⁶⁴-1] interval." add-exit-hook "Puts an one-argument function on top of the list of exit hooks.\nOn shutdown each exit hook is called with the exit status as a single\nargument, which is (usually) 0 on success and any other number on\nerror." /= "Return T if not all arguments are equal. Shorthand for (not (= …))." lz-pack "Return data compressed using Lempel-Ziv.\nThe data must be an array, returned value will have the same type.\nThe optional level is between 0 and 10. With level 0 a simple LZSS\nusing hashing will be performed. Levels between 1 and 9 offer a\ntrade-off between time/space and ratio. Level 10 is optimal but very\nslow." arg-counts "VM instructions mapped to their expected arguments count." rand-float "Return a random float on [0.0, 1.0] interval." *prompt* "Function called by REPL to signal the user input is required.\nDefault function prints \"#;> \"." cons? "Return T if the value is a cons cell." vm-stats "Print various VM-related information, such as the number of GC calls\nso far, heap and stack size, etc." * "Return product of the numbers or 1 with no arguments." *properties* "All properties of symbols recorded with putprop are recorded in this table."))
*syntax-environment* #table(bcode:nconst #fn("n1200r2e3:" #(aref)) doc-for #fn("\x8710002000W1000J60q?140B86;35040<;J404086;35040=863H020212287e212288e2e4e2:20212287e21e3e2:" #(void
symbol-set-doc quote)) with-input-from #fn("z12021e1220e2e1e12315163:" #(#fn(nconc)
with-bindings
@@ -37,7 +37,7 @@
#fn("n10B3500T:7060:" #(void)) letrec)) bcode:code #fn("n1200Ee3:" #(aref)) make-label #fn("n120e1:" #(gensym)) bcode:cenv #fn("n1200r3e3:" #(aref)) > #fn("z12021e12273151510e163:" #(#fn(nconc)
< #fn(copy-list) reverse!)) when #fn("z1200211Pqe4:" #(if begin)) quasiquote #fn("n1700E62:" #(bq-process)) help #fn("n17002152853W072855147350424250>170026q535247350@B0722728051524735047960:" #(getprop
*doc* princ newline #fn(for-each) #fn("n17050471A0P61:" #(newline print)) *funvars* "no help for "
- #fn(string) void)) defstruct #fn("O10005000*///W1000J7071?14W2000J60D?24W3000J60q?34W4000J60q?44W5000J60q?54z6IIb;228;230>1_5142224?<5142586<51;360486<8=;360486=;J50486268>5127288>528<8>51292:12;525185;J>04292:02;525183;JA04292:2<052518AP82;36040e184;J:042:02=522>2?e12@8C2Ae22B8B2Ae22C2D2E8Ee2e22F2G2AEe32E0e2e3e32H2I2Ae2268E518?Me3e4e3e12J8=2K2E0e28=e3e3e12@8D2>1e12>2Ee12L8E5152e12L8@5153e3e12L7M2N8;8A8@8F8C8E0>78?525165:" #(#(NIL
+ #fn(string) void)) defstruct #fn("O10005000*///W1000J7071?14W2000J60D?24W3000J60D?34W4000J60q?44W5000J60q?54z6IIb;228;230>1_5142224?<5142586<51;360486<8=;360486=;J50486268>5127288>528<8>51292:12;525185;J>04292:02;525183;3`0483H;3Q0483DQ;3>04292:2<05251;J504838AP;J5048382;36040e184;J:042:02=522>2?e12@8C2Ae22B8B2Ae22C2D2E8Ee2e22F2G2AEe32E0e2e3e32H2I2Ae2268E518?Me3e4e3e12J8=2K2E0e28=e3e3e18D3X02@8D2>1e12>2Ee12L8E5152e12L8@5153e3@30qe12L7M2N8;8A8@8F8C8E0>78?525165:" #(#(NIL
NIL :named 1 :conc-name 3 :type 0 NIL NIL NIL NIL NIL NIL :predicate 4 NIL NIL NIL NIL NIL NIL
:constructor 2) vector #0# #fn("n17005121220A>28552485:" #(cddr #fn(for-each)
#fn("n17002152340q:722324A<25F2605661:" #(member
--- a/src/system.lsp
+++ b/src/system.lsp
@@ -857,20 +857,17 @@
(defmacro (defstruct name (:type vector)
(:named T)
- (:constructor NIL)
+ (:constructor T)
(:conc-name NIL)
(:predicate NIL)
. slots)
"Defines a structure type with a specific name and slots.
The default underlying type is a named vector, ie the first element is
-the name of the structure type, the rest are the slot values.
+the name of the structure type, the rest are the slot values. If the
+name as the first element isn't required, \":named NIL\" should be
+used. A list can be used instead of a vector by adding \":type list\"
+option.
-If the name as the first element isn't required, \":named NIL\" should
-be used.
-
-A list can be used instead of a vector, e.g.:
- (defstruct st :type list ...)
-
The option :conc-name specifies the slot accessor prefix, which
defaults to \"name-\".
@@ -915,14 +912,20 @@
; slots, but with default values added (if not set)
; and keywords for names
[slots-kw (tokw slots)]
- ; struct's underlying type predicate (either vector? or list?)
+ ; struct's underlying type's predicate (either vector? or list?)
[type? (symbol (string type "?"))]
; struct's predicate name
[is? (or predicate
(symbol (string name "?")))]
; constructor name and arguments
- [constructor (or constructor
- (cons (symbol (string "make-" name)) slots-kw))]
+ [constructor
+ (and constructor ; NIL means none to make at all
+ (or (and (atom? constructor) ; a single argument
+ (cons (or (and (eq? constructor T) ; T means the defaults
+ (symbol (string "make-" name)))
+ constructor) ; else a custom name
+ slots-kw))
+ constructor))] ; anything else means custom name and args
; should the struct name appear as the first element?
[named (and named (list name))]
; accessor prefix
@@ -938,8 +941,8 @@
(when ,doc
(symbol-set-doc ',name ,doc))
; constructor
- (def ,constructor
- (,type ',@named ,@slots-car))
+ ,(when constructor `(def ,constructor
+ (,type ',@named ,@slots-car)))
; accessor per slot
,@(map-int (λ (i) [let* {[opts (slot-opts (list-ref slots-kw i))]
[fld (list-ref slots-car i)]