ref: ca55a3382bd47c42827184b02ed514b54e97e46d
parent: e0508d01357b9062eabac8c7fe4cdb6ea7c57fc8
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Dec 20 17:06:35 EST 2024
docs: always set the props regardless of environment, set the fun vars separately Also: * make *properties* visible. * allow documentation with (set! x "docs" ...) References: https://todo.sr.ht/~ft/femtolisp/16
--- a/compiler.lsp
+++ b/compiler.lsp
@@ -512,9 +512,17 @@
(while (compile-while g env (cadr x) (cons 'begin (cddr x))))
(return (compile-in g env #t (cadr x))
(emit g 'ret))
- (set! (unless (symbol? (cadr x))
- (error "set!: second argument must be a symbol"))
- (compile-set! g env (cadr x) (caddr x)))
+ (set! (let* ((name (cadr x))
+ (value (cddr x))
+ (doc (value-get-doc value)))
+ (unless (symbol? name)
+ (error "set!: name must be a symbol"))
+ (when doc
+ (set! value (cdr value))
+ (symbol-set-doc name doc (and (cons? (car value))
+ (is-lambda? (car (car value)))
+ (lambda:vars (car value)))))
+ (compile-set! g env name (car value))))
(trycatch (compile-in g env #f `(λ () ,(cadr x)))
(unless (1arg-lambda? (caddr x))
(error "trycatch: second form must be a 1-argument lambda"))
--- a/flisp.boot
+++ b/flisp.boot
@@ -14,7 +14,9 @@
#fn("6000n201l:" #()) #fn("6000n201m:" #()) 0 #fn("8000z0700}2:" #(vector))
#fn("8000z0700}2:" #(aset!)) 0 0 0 0 0 0 0 0 0 0 0 #fn("9000n3012082>1|:" #(#fn("6000n1A061:" #())))
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 #fn("8000z0700}2:" #(aref)) 0)
- *empty-string* "" *runestring-type* (array rune) *string-type* (array byte)
+ *empty-string* "" *properties*
+ #table(*funvars* #table(help (e)) *doc* #table(help "Display documentation for a function or symbol, if available."))
+ *runestring-type* (array rune) *string-type* (array byte)
*syntax-environment* #table(when #fn(";000z1200211POe4:" #(if begin)) with-output-to #fn("<000z12021e1220e2e1e12315163:" #(#fn(nconc)
with-bindings *output-stream* #fn(copy-list))) catch #fn("@000n220502112286e123242586e2262786e22829e2e3262:86e20e3e42;86e22<86e2e4e3e3:" #(#fn(gensym)
trycatch λ if and cons? eq? car quote thrown-value cadr caddr raise)) let* #fn("@000z10H3E02021e1qe12215153e1:2021e173051e1e1220=B3H02024e10=e12215153e1@301515375051e2:" #(#fn(nconc)
@@ -92,8 +94,8 @@
#fn("5000n10T<:" #() caadr) caar #fn("5000n10<<:" #() caar) cadaar
#fn("5000n10<<T:" #() cadaar) cadadr #fn("5000n10TT:" #() cadadr) cadar
#fn("5000n10<T:" #() cadar) caddar #fn("5000n10<=T:" #() caddar) cadddr
- #fn("5000n10==T:" #() cadddr) caddr #3=#fn("5000n10=T:" #() caddr) call-with-values
- #fn("7000n205086B3@0A86<C90186=}2:18661:" #() #(#2=(*values*))) capture-var! #fn("<000n27005171186E5387;IG042286510r323861e152p4:" #(bcode:cenv
+ #fn("5000n10==T:" #() cadddr) caddr #2=#fn("5000n10=T:" #() caddr) call-with-values
+ #fn("7000n205086B3@0A86<C90186=}2:18661:" #() #(#1=(*values*))) capture-var! #fn("<000n27005171186E5387;IG042286510r323861e152p4:" #(bcode:cenv
index-of #fn(length) #fn(nconc)) capture-var!)
cdaaar #fn("5000n10<<<=:" #() cdaaar) cdaadr
#fn("5000n10T<=:" #() cdaadr) cdaar #fn("5000n10<<=:" #() cdaar) cdadar
@@ -129,7 +131,7 @@
encode-byte-code bcode:code const-to-idx-vec bcode:cenv) compile-f-)
compile-if #fn("A000n470051700517005183T718351728351B3;0738351@6074508;DC=07501828<64:8;OC=07501828=64:7501O8;895547602789534780885247501828<544823<07602952@;07602:8:534780895247501828=5447808:62:" #(make-label
caddr cdddr cadddr void compile-in emit brf mark-label ret jmp) compile-if)
- compile-in #fn(">000\x8740005000\x884000I60O?4483R3<0700183D64:83H3\xaf083EC:07102262:83KC:07102362:83DC:07102462:83OC:07102562:83qC:07102662:7783513<0710288363:2983513C07:01822;2<51e164:7102=8363:83<2>C<07?0183=63:83<RS;ID0483<Z;I;047@83<1523=07A01828364:83<892BCS07C83T513>07:018283T64:7102=83T63:892DC=07E01828364:892FC>07G018283=64:892HC;07I018363:892JCD07K2L183>22M01>262:892NC@07O018283=8465:892PC>07Q018283=64:892RCE07S0183T2F7T8351P64:892UCE07:01D83T5447102V62:892WCT083TR360O@807X2Y5147Z0183T7[835164:892\\Cp07:01O2Jq83Te35447]7[835151360O@807X2^5147:01O7[83515447102\\62:7A01828364:" #(compile-sym
+ compile-in #fn("B000\x8740005000\x884000I60O?4483R3<0700183D64:83H3\xaf083EC:07102262:83KC:07102362:83DC:07102462:83OC:07102562:83qC:07102662:7783513<0710288363:2983513C07:01822;2<51e164:7102=8363:83<2>C<07?0183=63:83<RS;ID0483<Z;I;047@83<1523=07A01828364:83<892BCS07C83T513>07:018283T64:7102=83T63:892DC=07E01828364:892FC>07G018283=64:892HC;07I018363:892JCD07K2L183>22M01>262:892NC@07O018283=8465:892PC>07Q018283=64:892RCE07S0183T2F7T8351P64:892UCE07:01D83T5447102V62:892WC\x93083T7T83517X8;518:R360O@807Y2Z5148<3`08;=?;47[8:8<8;<B;3G047\\8;<<51;3:047]8;<5153@30O47^018:8;<64:892_Cp07:01O2Jq83Te35447`7a835151360O@807Y2b5147:01O7a83515447102_62:7A01828364:" #(compile-sym
emit load0 load1 loadt loadf loadnil fits-i8 loadi8 #fn(eof-object?) compile-in #fn(top-level-value)
eof-object loadv aset! compile-aset! in-env? compile-app quote self-evaluating? if compile-if
begin compile-begin prog1 compile-prog1 λ call-with-values #fn("7000n070AF62:" #(compile-f-))
@@ -136,8 +138,8 @@
#fn("9000n270A2105341\x85K02223AF>2152470A242515163:D:" #(emit loadv #fn(for-each)
#fn("9000n170AF0O64:" #(compile-sym))
closure #fn(length))) and compile-and
- or compile-or while compile-while cddr return ret set! error "set!: second argument must be a symbol"
- compile-set! caddr trycatch 1arg-lambda? "trycatch: second form must be a 1-argument lambda") compile-in)
+ or compile-or while compile-while cddr return ret set! value-get-doc error "set!: name must be a symbol"
+ symbol-set-doc is-lambda? lambda:vars compile-set! trycatch 1arg-lambda? caddr "trycatch: second form must be a 1-argument lambda") compile-in)
compile-let #fn("A000n483<83=7005188T71018953728;737488518;528:537508=524268=1<521=P7708>827488515447808<U524798<E523A082I<07:02;8<63:D:" #(bcode:sp
compile-arglist vars-to-env complex-bindings caddr box-vars #fn(nconc) compile-in bcode:stack >
emit shift) compile-let)
@@ -207,7 +209,7 @@
#fn("9000z020210P61:" #(#fn(raise) error) error) eval #fn("7000n170710515160:" #(compile-thunk
expand) eval)
even? #fn("7000n1200K52El:" #(#fn(logand)) even?) every
- #fn("7000n21H;ID0401<51;3:047001=62:" #(every) every) expand #fn("I000n1DDDDDDDDDDDDD\x8a5\x8a6\x8a7\x8a8\x8a9\x8a:\x8a;\x8a<\x8a=\x8a>\x8a?\x8a@\x8aA8520_4862186>1_48722e1_4882385868A87>4_489248A89>2_48:258:>1_48;268:8988>3_48<27_48=28_48>298=8<8A8:8988>6_48?2:888A>2_48@2;_48A2<8A8@8;8>8?>5_48A<0q62:" #(#fn("7000n20Z;I904200152S:" #(#fn(assq)) top?)
+ #fn("7000n21H;ID0401<51;3:047001=62:" #(every) every) expand #fn("F000n1DDDDDDDDDDD\x8a5\x8a6\x8a7\x8a8\x8a9\x8a:\x8a;\x8a<\x8a=\x8a>\x8a?8520_4862186>1_48722e1_4882385868?87>4_489248?89>2_48:258:>1_48;268:8988>3_48<278?8:8988>4_48=28888?>2_48>29_48?2:8?8>8;8<8=>5_48?<0q62:" #(#fn("7000n20Z;I904200152S:" #(#fn(assq)) top?)
#fn("8000n10H3400:020d3400:0<B3P07105122CF023A<7405151A<0=5162:0<A<0=51P:" #(((begin)) caar begin
#fn(append) cdar) splice-begin)
*expanded* #fn("A000n20H3400:A<201523:0F<051@300A<21152873;0728651@30q2324758852152\x8a987IA024269289>28662:D\x8a:8:278:928993>4_48:<^186518:D8;B3c0493<788;51QIC08;92<8;<89<52_@;08;798;51_48;=?;@\xfb/48::" #(begin
@@ -218,14 +220,11 @@
#fn("7000n10H3600e1:0<B3?070051A<0=51P:0<A<0=51P:" #(caar) l-vars)
#fn("?000n20T7005171051A<0T5122237489521522225e1F<868:52e192<888:528764:" #(lastcdr cddr #fn(nconc)
#fn(map) list λ) expand-lambda)
- #fn("=000\x8730004000\x883000I60O?3482JN070021833@022123083P53@30163:O:" #(putprop *doc* #fn(string)
- "\n\n") document)
- #fn("8000n10<0=208551;3=0486B;350485:" #(#fn(string?)) getdoc)
- #fn("D000n20=V;I6040TH3q070051J400:0TA<7005151873C0F<868715340=?0@30O4218692<72051152e3:73051740517005193<8651A<885125267789521528:3F0F<878:18654488=?8@30O42521e18794<868;52Pe195<888;5263:" #(cddr
- define caddr cdadr caadr #fn(nconc) #fn(map) list) expand-define)
- #fn("=000n20T20A<71051222324F1>2865215252P:" #(begin cddr #fn(nconc)
- #fn(map)
- #fn("9000n10<70A<0TF525150Fe3:" #(compile-thunk))) expand-let-syntax)
+ #fn("D000n20=V;I6040TH3o070051J400:0T717005151873B00=?0472868752@30O42386A<74051152e3:750517605170051718851F<86512728798:52152893E088=?847287898653@30O42723e18792<868;52Pe193<888;5263:" #(cddr
+ value-get-doc symbol-set-doc define caddr cdadr caadr #fn(nconc)
+ #fn(map) list) expand-define) #fn("=000n20T20A<71051222324F1>2865215252P:" #(begin cddr #fn(nconc)
+ #fn(map)
+ #fn("9000n10<70A<0TF525150Fe3:" #(compile-thunk))) expand-let-syntax)
#fn("5000n20:" #() local-expansion-env) #fn("<000n20H3400:0<208615221A10>3873P087=B3I0A<87T0=f2F<72875115262:87;I?0486RS;I60486Z3708860:73051893>0A<890=f2162:8624C400:8625C:092<0162:8625C:092<0162:8626C:093<0162:8627C:094<0162:8860:" #(#fn(assq)
#fn(":000n0D\x8a48420AF84>3_484<^19261:" #(#fn("8000n10H3400:0<H3700<@90A<0<F5292<0=51P:" #())))
caddr macrocall? quote λ define let-syntax) expand-in)) expand)
@@ -237,10 +236,10 @@
#fn("9000n382J401:700082<15282=63:" #(foldl) foldl) foldr #fn(":000n382J401:082<700182=5362:" #(foldr) foldr)
get-defined-vars #fn("7000n170A<05161:" #(delete-duplicates) #(#0=(#fn("8000n10H340q:0<20Cj00=B3d00TR;37040Te1;IS040TB;3E0471051R;3:0471051e1;I404q:0<22C?07324A<0=52}2:q:" #(define
caadr begin nconc #fn(map)) #(#0#)))))
- getprop #fn(":000\x8720003000\x882000I60O?2420A1O5387;3<04208708253;I50482:" #(#fn(get)) #(#1=#table()))
- help #fn("=000n10\\3:020051@300717285232425052532662:" #(#fn(function:name) princ
- getprop *doc* #fn(string) "no help for "
- "\n") help)
+ getprop #fn(":000\x8720003000\x882000I60O?2420711O5387;3<04208708253;I50482:" #(#fn(get)
+ *properties*) getprop)
+ help #fn("?000n10\\853:020051@3007186225271862352873X0748751475504883C075504768688P51@30O@>074272886515247560:" #(#fn(function:name)
+ getprop *doc* *funvars* princ newline print "no help for " #fn(string)) help)
hex5 #fn("8000n170210r@52r52263:" #(string-lpad #fn(number->string) #\0) hex5) identity
#fn("5000n10:" #() identity) in-env? #fn("7000n21B;3F042001<52;I:047101=62:" #(#fn(assq)
in-env?) in-env?)
@@ -340,9 +339,9 @@
printable? #fn("6000n120051;I80421051S:" #(#fn(iostream?)
#fn(eof-object?)) printable?)
procedure? #.function? putprop
- #fn(";000n320A1O5387360O@E0215022A18853488?7^14228708253482:" #(#fn(get)
- #fn(table)
- #fn(put!)) #(#1#))
+ #fn(";000n320711O5387360O@F02250237118853488?7^14238708253482:" #(#fn(get) *properties*
+ #fn(table)
+ #fn(put!)) putprop)
quote-value #fn("6000n1700513400:210e2:" #(self-evaluating? quote) quote-value) quoted?
#fn("6000n10<20Q:" #(quote) quoted?) random #fn("7000n1200513<0712250062:23500i2:" #(#fn(integer?)
mod #fn(rand) #fn(rand-double)) random)
@@ -353,9 +352,8 @@
#fn(ash)) ref-int16-LE)
ref-int32-LE #fn("<000n2202101EMGE522101KMGr8522101r2MGr@522101r3MGrH52g461:" #(#fn(int32)
#fn(ash)) ref-int32-LE)
- remprop #fn("8000n220A1O5386;3F042186052;3:042286062:" #(#fn(get)
- #fn(has?)
- #fn(del!)) #(#1#))
+ remprop #fn("8000n220711O5386;3F042286052;3:042386062:" #(#fn(get) *properties* #fn(has?)
+ #fn(del!)) remprop)
repl #fn(":000n0DD\x8a4\x8a58420_485218485>2_485<5047260:" #(#fn("8000n0702151422735142425{267751S;3F04788451798551485w:4D:" #(princ
"> " #fn(io-flush) *output-stream* #fn("5000n02060:" #(#fn(read)))
#fn("6000n1207151422061:" #(#fn(io-discardbuffer) *input-stream* #fn(raise)))
@@ -389,6 +387,8 @@
#fn(string-char) 1+) trim-start) #fn(":000n37082E523R021122073825152523?0A<0173825163:82:" #(> #fn(string-find)
#fn(string-char) 1-) trim-end) #fn(string-length)
#fn(string-sub)) string-trim)
+ symbol-set-doc #fn("9000\x8720003000\x882000I60O?24700211534823<0700228263:D:" #(putprop
+ *doc* *funvars*) symbol-set-doc)
symbol-syntax #fn("8000n120710O63:" #(#fn(get)
*syntax-environment*) symbol-syntax)
table-clone #fn("9000n12050212285>1q053485:" #(#fn(table)
@@ -416,7 +416,8 @@
x newline #.apply)))))
untrace #fn("9000n1200517185513A0220238551r2G62:D:" #(#fn(top-level-value) traced? #fn(set-top-level-value!)
#fn(function:vals)) untrace)
- values #fn("8000z00B3:00=J500<:A0P:" #() #(#2#)) vars-to-env
+ value-get-doc #fn("8000n10<0=208551;3=0486B;350485:" #(#fn(string?)) value-get-doc)
+ values #fn("8000z00B3:00=J500<:A0P:" #() #(#1#)) vars-to-env
#fn(":000n32021182>2072230515163:" #(#fn(map)
#fn("9000n2700210A52SS1FM63:" #(vinfo #fn(memq)))
iota #fn(length)) vars-to-env)
@@ -426,5 +427,5 @@
#fn(vector-alloc)
#fn("9000n1A0F920G51p:" #())) vector-map)
vinfo #fn("7000n30182e3:" #() vinfo) vinfo:heap? #.cadr vinfo:index
- #3# vinfo:sym #.car void
+ #2# vinfo:sym #.car void
#fn("5000n0D:" #() void) zero? #fn("6000n10El:" #() zero?))
--- a/system.lsp
+++ b/system.lsp
@@ -702,33 +702,55 @@
;;
;; The assumption here is that keys will most likely be the same across multiple symbols
;; so it makes more sense to reduce the number of subtables for the *properties* table.
-(let ((*properties* (table)))
- (set! putprop
- (λ (sym key val)
- (let ((kt (get *properties* key #f)))
- (unless kt
- (let ((t (table)))
- (put! *properties* key t)
- (set! kt t)))
- (put! kt sym val)
- val)))
- (set! getprop
- (λ (sym key (def #f))
- (let ((kt (get *properties* key #f)))
- (or (and kt (get kt sym def)) def))))
- (set! remprop
- (λ (sym key)
- (let ((kt (get *properties* key #f)))
- (and kt (has? kt sym) (del! kt sym))))))
+(define *properties* (table))
-; toplevel --------------------------------------------------------------------
+(define (putprop sym key val)
+ (let ((kt (get *properties* key #f)))
+ (unless kt
+ (let ((t (table)))
+ (put! *properties* key t)
+ (set! kt t)))
+ (put! kt sym val)
+ val))
+(define (getprop sym key (def #f))
+ (let ((kt (get *properties* key #f)))
+ (or (and kt (get kt sym def)) def)))
+
+(define (remprop sym key)
+ (let ((kt (get *properties* key #f)))
+ (and kt (has? kt sym) (del! kt sym))))
+
+; documentation ---------------------------------------------------------------
+
+(define (symbol-set-doc sym doc (funvars #f))
+ (putprop sym '*doc* doc)
+ (if funvars (putprop sym '*funvars* funvars)))
+
+(define (value-get-doc body)
+ (let ((first (car body))
+ (rest (cdr body)))
+ (and (string? first) (cons? rest) first)))
+
(define (help e)
- (let ((name (if (function? e)
- (function:name e)
- e)))
- (princ (getprop name '*doc* (string "no help for " e)) "\n")))
+ "Display documentation for a function or symbol, if available."
+ (let* ((func? (function? e))
+ (name (if func? (function:name e) e))
+ (doc (getprop name '*doc*))
+ (funvars (getprop name '*funvars*)))
+ (if doc
+ (begin
+ (princ doc)
+ (newline)
+ (when funvars
+ (newline)
+ (print (cons name funvars))))
+ (begin
+ (princ "no help for " (string name))))
+ (newline)))
+; toplevel --------------------------------------------------------------------
+
(define (macrocall? e) (and (symbol? (car e))
(symbol-syntax (car e))))
@@ -808,36 +830,25 @@
,.(expand-body body env)
. ,name))))
- (define (document sym doc env (formals #f))
- (when (null? env)
- (putprop sym '*doc* (if formals
- (string doc "\n\n" (cons sym formals))
- doc))))
-
- (define (getdoc body)
- (let ((first (car body))
- (rest (cdr body)))
- (and (string? first) (cons? rest) first)))
-
(define (expand-define e env)
(if (or (null? (cdr e)) (atom? (cadr e)))
(if (null? (cddr e))
e
(let ((name (cadr e))
- (doc (getdoc (cddr e))))
+ (doc (value-get-doc (cddr e))))
(when doc
- (document name doc env)
- (set! e (cdr e)))
+ (set! e (cdr e))
+ (symbol-set-doc name doc))
`(define ,name ,(expand-in (caddr e) env))))
(let* ((formals (cdadr e))
(name (caadr e))
(body (cddr e))
+ (doc (value-get-doc body))
(vars (l-vars formals))
- (doc (getdoc body))
(menv (nconc (map list vars) env)))
(when doc
- (document name doc env formals)
- (set! body (cdr body)))
+ (set! body (cdr body))
+ (symbol-set-doc name doc formals))
`(define ,(cons name (expand-lambda-list formals menv))
,.(expand-body body menv)))))