4 include term-colours.4th
7 include catch-throw.4th
33 make-type boolean-type
34 make-type character-type
40 make-type primitive-proc-type
41 make-type compound-proc-type
43 : istype? ( obj type -- obj bool )
48 \ ---- Exceptions ---- {{{
50 variable nextexception
53 create nextexception @ ,
62 make-exception recoverable-exception
63 make-exception unrecoverable-exception
65 : throw reset-term cr throw ;
69 \ ---- List-structured memory ---- {{{
71 20000 constant scheme-memsize
73 create car-cells scheme-memsize allot
74 create car-type-cells scheme-memsize allot
75 create cdr-cells scheme-memsize allot
76 create cdr-type-cells scheme-memsize allot
84 create nextfrees scheme-memsize allot
95 nextfrees nextfree @ + @
98 nextfree @ scheme-memsize >= if
104 nextfree @ scheme-memsize >= if
105 except-message: ." Out of memory!" unrecoverable-exception throw
109 : cons ( car-obj cdr-obj -- pair-obj )
110 cdr-type-cells nextfree @ + !
111 cdr-cells nextfree @ + !
112 car-type-cells nextfree @ + !
113 car-cells nextfree @ + !
119 : car ( pair-obj -- car-obj )
121 dup car-cells + @ swap
125 : cdr ( pair-obj -- car-obj )
127 dup cdr-cells + @ swap
131 : set-car! ( obj pair-obj -- )
133 rot swap car-type-cells + !
137 : set-cdr! ( obj pair-obj -- )
139 rot swap cdr-type-cells + !
144 : nil? nil-type istype? ;
147 : none? none-type istype? ;
149 : objvar create nil swap , , ;
151 : value@ ( objvar -- val ) @ ;
152 : type@ ( objvar -- type ) 1+ @ ;
153 : value! ( newval objvar -- ) ! ;
154 : type! ( newtype objvar -- ) 1+ ! ;
155 : obj! ( newobj objvar -- ) dup rot swap 1+ ! ! ;
156 : obj@ ( objvar -- obj ) dup @ swap 1+ @ ;
158 : objeq? ( obj obj -- bool )
161 : 2rot ( a1 a2 b1 b2 c1 c2 -- b1 b2 c1 c2 a1 a2 )
162 >R >R ( a1 a2 b1 b2 )
163 2swap ( b1 b2 a1 a2 )
164 R> R> ( b1 b2 a1 a2 c1 c2 )
168 : -2rot ( a1 a2 b1 b2 c1 c2 -- c1 c2 a1 a2 b1 b2 )
169 2swap ( a1 a2 c1 c2 b1 b2 )
170 >R >R ( a1 a2 c1 c2 )
171 2swap ( c1 c2 a1 a2 )
175 : 2pick ( an bn an-1 bn-1 ... a0 b0 n -- an bn an-1 bn-1 ... a0 b0 an bn )
181 \ ---- Pre-defined symbols ---- {{{
185 : duplicate-charlist ( charlist -- copy )
187 2dup car 2swap cdr recurse cons
190 : charlist-equiv ( charlist charlist -- bool )
199 2drop 2drop true exit
201 2drop 2drop false exit
206 2drop 2drop false exit
213 car drop -rot car drop = if
214 cdr 2swap cdr recurse
220 : charlist>symbol ( charlist -- symbol-obj )
239 drop symbol-type 2dup
240 symbol-table obj@ cons
245 : cstr>charlist ( addr n -- charlist )
249 2dup drop @ character-type 2swap
257 : create-symbol ( -- )
265 does> dup @ swap 1+ @
268 create-symbol quote quote-symbol
269 create-symbol quasiquote quasiquote-symbol
270 create-symbol unquote unquote-symbol
271 create-symbol unquote-splicing unquote-splicing-symbol
272 create-symbol define define-symbol
273 create-symbol define-macro define-macro-symbol
274 create-symbol set! set!-symbol
275 create-symbol ok ok-symbol
276 create-symbol if if-symbol
277 create-symbol lambda lambda-symbol
278 create-symbol λ λ-symbol
279 create-symbol eof eof-symbol
280 create-symbol no-match no-match-symbol
282 \ Symbol to be bound to welcome message procedure by library
283 create-symbol welcome welcome-symbol
287 \ ---- Port I/O ---- {{{
289 ( Ports are pairs with the fid in the car and the peek buffer in the cdr. )
291 : fileport>fid ( fileport -- fid )
292 drop pair-type car drop ;
294 : get-last-peek ( fileport -- char/nil )
297 : set-last-peek ( char/nil fileport -- )
298 drop pair-type set-cdr!
301 : fid>fileport ( fid -- fileport )
302 fixnum-type nil cons drop port-type ;
304 : open-input-file ( addr n -- fileport )
305 r/o open-file drop fid>fileport
308 : close-port ( fileport -- )
309 fileport>fid close-file drop
312 objvar console-i/o-port
313 0 fixnum-type nil cons drop port-type console-i/o-port obj!
315 objvar current-input-port
316 console-i/o-port obj@ current-input-port obj!
318 : read-char ( port -- char )
319 2dup get-last-peek nil? if
321 2dup console-i/o-port obj@ objeq? if
325 fileport>fid pad 1 rot read-file 0= if
336 : peek-char ( port -- char )
337 2dup get-last-peek nil? if
339 2dup 2rot set-last-peek
345 variable read-line-buffer-span
346 variable read-line-buffer-offset
348 ( Hack to save original read-line while we transition to new one. )
349 : orig-read-line immediate
352 : read-line ( port -- string )
357 0 read-line-buffer-offset !
359 2over nil 2swap set-last-peek
361 2drop nil nil cons exit
364 1 read-line-buffer-offset !
368 2dup console-i/o-port obj@ objeq? if
370 pad read-line-buffer-offset @ + 200 expect cr
371 span @ read-line-buffer-offset @ + read-line-buffer-span !
373 pad read-line-buffer-offset @ + 200 2over fileport>fid orig-read-line
374 drop swap read-line-buffer-offset @ + read-line-buffer-span !
380 read-line-buffer-span @ 0>
382 pad read-line-buffer-span @ 1- + @ character-type 2swap cons
383 -1 read-line-buffer-span +!
387 nil cons drop string-type
393 : read-port ( fileport -- obj )
394 current-input-port obj!
397 : read-console ( -- obj )
398 console-i/o-port obj@ read-port ;
402 \ ---- Environments ---- {{{
404 : enclosing-env ( env -- env )
407 : first-frame ( env -- frame )
410 : make-frame ( vars vals -- frame )
413 : add-frame-to-env ( frame env -- env )
416 : frame-vars ( frame -- vars )
419 : frame-vals ( frame -- vals )
422 : add-binding ( var val frame -- )
423 2swap 2over frame-vals cons
425 2swap 2over frame-vars cons
429 : extend-env ( vars vals env -- env )
431 2swap add-frame-to-env
434 : get-vals-frame ( var frame -- vals | nil )
436 2swap frame-vals ( var vars vals )
442 -2rot ( vals var vars )
443 2over 2over car objeq? if
455 : get-vals ( var env -- vals | nil )
460 2over 2over first-frame
461 get-vals-frame nil? false = if
462 2swap 2drop 2swap 2drop
474 objvar var \ Used only for error messages
475 : lookup-var ( var env -- val )
479 except-message: ." tried to read unbound variable '" var obj@ print ." '."
480 recoverable-exception throw
486 : set-var ( var val env -- )
487 2rot 2dup var obj! ( val env var )
488 2swap ( val var env )
490 except-message: ." tried to set unbound variable '" var obj@ print ." '."
491 recoverable-exception throw
499 : define-var ( var val env -- )
500 first-frame ( var val frame )
501 2rot 2swap 2over 2over ( val var frame var frame )
503 get-vals-frame nil? if
508 ( val var frame vals )
509 2swap 2drop 2swap 2drop
514 : make-procedure ( params body env -- proc )
517 drop compound-proc-type
521 nil nil nil extend-env
526 \ ---- Primitives ---- {{{
528 : make-primitive ( cfa -- )
535 rot primitive-proc-type ( var prim )
536 global-env obj@ define-var
539 : ensure-arg-count ( args n -- )
541 drop nil objeq? false = if
542 except-message: ." Too many arguments for primitive procedure." recoverable-exception throw
546 except-message: ." Too few arguments for primitive procedure." recoverable-exception throw
553 : ensure-arg-type-and-count ( tn tn-1 ... t2 t1 args n -- )
555 drop nil objeq? false = if
556 except-message: ." Too many arguments for primitive procedure." recoverable-exception throw
560 except-message: ." Too few arguments for primitive procedure." recoverable-exception throw
563 2dup cdr 2swap car ( ... t1 n args' arg1 )
564 2rot 1- swap 2swap rot ( ... args' n-1 arg1 t1 )
566 except-message: ." Incorrect type for primitive procedure." recoverable-exception throw
574 : push-args-to-stack ( args -- arg1 arg2 ... argn )
584 : add-fa-checks ( cfa n -- cfa' )
585 here current @ 1+ dup @ , !
589 ['] 2dup , ['] lit , , ['] ensure-arg-count ,
590 ['] push-args-to-stack ,
591 ['] lit , , ['] execute ,
595 : add-fa-type-checks ( cfa t1 t2 ... tn n -- cfa' )
596 here current @ 1+ dup @ , !
603 dup ( cfa t1 t2 ... tn n m )
608 rot ['] lit , , ( cfa t1 t2 ... tn-1 n m )
614 ['] lit , , ['] ensure-arg-type-and-count ,
616 ['] push-args-to-stack ,
617 ['] lit , , ['] execute ,
623 : make-fa-primitive ( cfa n -- )
624 add-fa-checks make-primitive ;
626 : make-fa-type-primitive ( cfa t1 t2 ... tn n -- )
627 add-fa-type-checks make-primitive ;
630 bold fg red ." Incorrect argument type." reset-term cr
634 : ensure-arg-type ( arg type -- arg )
636 except-message: ." Incorrect argument type for primitive procedure." recoverable-exception throw
643 \ ---- Macros ---- {{{
647 ( Look up macro in macro table. Returns nil if
649 : lookup-macro ( name_symbol -- proc )
651 symbol-type istype? invert if
652 \ Early exit if argument is not a symbol
674 : make-macro ( name_symbol params body env -- )
677 2swap ( proc name_symbol )
684 2over 2over ( proc name table name table )
686 2swap 2drop ( proc table )
698 macro-table obj@ cons
707 variable stored-parse-idx
708 create parse-str 161 allot
709 variable parse-str-span
711 create parse-idx-stack 10 allot
712 variable parse-idx-sp
713 parse-idx-stack parse-idx-sp !
716 parse-idx @ parse-idx-sp @ !
721 parse-idx-sp @ parse-idx-stack <= abort" Parse index stack underflow."
725 parse-idx-sp @ @ parse-idx ! ;
729 '\n' parse-str parse-str-span @ + !
730 1 parse-str-span +! ;
733 4 parse-str parse-str-span @ + !
734 1 parse-str-span +! ;
741 current-input-port obj@ console-i/o-port obj@ objeq? if
742 parse-str 160 expect cr
743 span @ parse-str-span !
745 parse-str 160 current-input-port obj@ fileport>fid orig-read-line
746 drop swap parse-str-span !
748 parse-str-span @ 0= and if append-eof then
759 : charavailable? ( -- bool )
760 parse-str-span @ parse-idx @ > ;
762 : nextchar ( -- char )
763 charavailable? false = if getline then
764 parse-str parse-idx @ + @ ;
767 : whitespace? ( -- bool )
779 nextchar [char] ( = or
780 nextchar [char] ) = or
783 : commentstart? ( -- bool )
784 nextchar [char] ; = ;
788 false \ Indicates whether or not we're eating a comment
791 dup whitespace? or commentstart? or
793 dup nextchar '\n' = and if
794 invert \ Stop eating comment
796 dup false = commentstart? and if
797 invert \ Begin eating comment
812 nextchar [char] - = ;
815 nextchar [char] + = ;
817 : fixnum? ( -- bool )
843 : flonum? ( -- bool )
850 \ Record starting parse idx:
851 \ Want to detect whether any characters (following +/-) were eaten.
858 [char] . nextchar = if
865 [char] e nextchar = [char] E nextchar = or if
873 drop pop-parse-idx false exit
881 \ This is a real number if characters were
882 \ eaten and the next characer is a delimiter.
883 parse-idx @ < delim? and
888 : ratnum? ( -- bool )
896 pop-parse-idx false exit
905 [char] / nextchar <> if
906 pop-parse-idx false exit
912 pop-parse-idx false exit
924 : boolean? ( -- bool )
925 nextchar [char] # <> if false exit then
932 and if pop-parse-idx false exit then
944 : str-equiv? ( str -- bool )
961 delim? false = if drop false then
966 : character? ( -- bool )
967 nextchar [char] # <> if false exit then
972 nextchar [char] \ <> if pop-parse-idx false exit then
976 S" newline" str-equiv? if pop-parse-idx true exit then
977 S" space" str-equiv? if pop-parse-idx true exit then
978 S" tab" str-equiv? if pop-parse-idx true exit then
980 charavailable? false = if pop-parse-idx false exit then
986 nextchar [char] ( = ;
988 : string? ( -- bool )
989 nextchar [char] " = ;
991 : readfixnum ( -- fixnum )
1002 10 * nextchar [char] 0 - +
1011 : readflonum ( -- flonum )
1013 dup 0< swap abs i->f
1015 [char] . nextchar = if
1021 nextchar [char] 0 - i->f ( f exp d )
1022 over f/ rot f+ ( exp f' )
1023 swap 10.0 f* ( f' exp' )
1030 [char] e nextchar = [char] E nextchar = or if
1033 readfixnum drop i->f
1044 : make-rational ( fixnum fixnum -- ratnum|fixnum )
1051 fixnum-type swap fixnum-type
1052 cons drop ratnum-type
1056 : readratnum ( -- ratnum )
1057 readfixnum inc-parse-idx readfixnum
1061 : readbool ( -- bool-obj )
1064 nextchar [char] f = if
1075 : readchar ( -- char-obj )
1079 S" newline" str-equiv? if 7 parse-idx +! '\n' character-type exit then
1080 S" space" str-equiv? if 5 parse-idx +! bl character-type exit then
1081 S" tab" str-equiv? if 3 parse-idx +! 9 character-type exit then
1083 nextchar character-type
1088 : readstring ( -- charlist )
1093 nextchar [char] " <>
1095 nextchar [char] \ = if
1098 [char] n of '\n' endof
1099 [char] " of [char] " endof
1105 inc-parse-idx character-type
1108 ( firstchar prevchar thischar )
1111 2drop 2swap 2drop 2dup ( thischar thischar )
1113 ( firstchar thischar prevchar )
1114 2over 2swap set-cdr! ( firstchar thischar )
1118 \ Discard previous character
1124 ." No delimiter following right double quote. Aborting." cr
1136 : readsymbol ( -- charlist )
1137 delim? if nil exit then
1139 nextchar inc-parse-idx character-type
1146 : readpair ( -- pairobj )
1150 nextchar [char] ) = if
1155 ." No delimiter following right paren. Aborting." cr
1164 \ Read first pair element
1169 nextchar [char] . = if
1174 ." No delimiter following '.'. Aborting." cr
1188 \ Parse a scheme expression
1223 nextchar [char] " <> if
1224 bold red ." Missing closing double-quote." reset-term cr
1242 nextchar [char] ) <> if
1243 bold red ." Missing closing paren." reset-term cr
1252 nextchar [char] ' = if
1254 quote-symbol recurse nil cons cons exit
1257 nextchar [char] ` = if
1259 quasiquote-symbol recurse nil cons cons exit
1262 nextchar [char] , = if
1264 nextchar [char] @ = if
1266 unquote-splicing-symbol recurse nil cons cons exit
1268 unquote-symbol recurse nil cons cons exit
1278 nextchar [char] ) = if
1280 except-message: ." unmatched closing parenthesis." recoverable-exception throw
1283 \ Anything else is parsed as a symbol
1284 readsymbol charlist>symbol
1286 \ Replace λ with lambda
1287 2dup λ-symbol objeq? if
1296 \ ---- Syntax ---- {{{
1298 : self-evaluating? ( obj -- obj bool )
1299 boolean-type istype? if true exit then
1300 fixnum-type istype? if true exit then
1301 flonum-type istype? if true exit then
1302 ratnum-type istype? if true exit then
1303 character-type istype? if true exit then
1304 string-type istype? if true exit then
1305 nil-type istype? if true exit then
1306 none-type istype? if true exit then
1311 : tagged-list? ( obj tag-obj -- obj bool )
1313 pair-type istype? false = if
1319 : quote? ( obj -- obj bool )
1320 quote-symbol tagged-list? ;
1322 : quote-body ( quote-obj -- quote-body-obj )
1325 : variable? ( obj -- obj bool )
1326 symbol-type istype? ;
1328 : definition? ( obj -- obj bool )
1329 define-symbol tagged-list? ;
1331 : definition-var ( obj -- var )
1334 : definition-val ( obj -- val )
1337 : assignment? ( obj -- obj bool )
1338 set!-symbol tagged-list? ;
1340 : assignment-var ( obj -- var )
1343 : assignment-val ( obj -- val )
1346 : macro-definition? ( obj -- obj bool )
1347 define-macro-symbol tagged-list? ;
1349 : macro-definition-name ( exp -- mname )
1352 : macro-definition-params ( exp -- params )
1355 : macro-definition-body ( exp -- body )
1358 : if? ( obj -- obj bool )
1359 if-symbol tagged-list? ;
1361 : if-predicate ( ifobj -- pred )
1364 : if-consequent ( ifobj -- conseq )
1367 : if-alternative ( ifobj -- alt|none )
1375 : false? ( boolobj -- boolean )
1376 boolean-type istype? if
1377 false boolean-type objeq?
1383 : true? ( boolobj -- bool )
1386 : lambda? ( obj -- obj bool )
1387 lambda-symbol tagged-list? ;
1389 : lambda-parameters ( obj -- params )
1392 : lambda-body ( obj -- body )
1395 : application? ( obj -- obj bool )
1398 : operator ( obj -- operator )
1401 : operands ( obj -- operands )
1404 : nooperands? ( operands -- bool )
1407 : first-operand ( operands -- operand )
1410 : rest-operands ( operands -- other-operands )
1413 : procedure-params ( proc -- params )
1414 drop pair-type car ;
1416 : procedure-body ( proc -- body )
1417 drop pair-type cdr car ;
1419 : procedure-env ( proc -- body )
1420 drop pair-type cdr cdr car ;
1422 ( Ensure terminating symbol arg name is handled
1423 specially to allow for variadic procedures. )
1424 : flatten-proc-args ( argvals argnames -- argvals' argnames' )
1426 2over nil? false = if
1427 except-message: ." Too many arguments for compound procedure." recoverable-exception throw
1434 symbol-type istype? if
1444 except-message: ." Too few arguments for compound procedure." recoverable-exception throw
1451 recurse ( argvals argnames argvals'' argnames'' )
1452 2rot car 2swap cons ( argvals argvals'' argnames' )
1453 2rot car 2rot cons ( argnames' argvals' )
1459 \ ---- Analyze ---- {{{
1461 : evaluate-eproc ( eproc env --- res )
1472 2drop \ get rid of null
1476 \ Final element of eproc list is primitive procedure
1477 drop \ dump type signifier
1479 goto \ jump straight to primitive procedure (executor)
1482 : self-evaluating-executor ( exp env -- exp )
1485 : analyze-self-evaluating ( exp --- eproc )
1486 ['] self-evaluating-executor primitive-proc-type
1490 : quote-executor ( exp env -- exp )
1493 : analyze-quoted ( exp -- eproc )
1496 ['] quote-executor primitive-proc-type
1500 : variable-executor ( var env -- val )
1503 : analyze-variable ( exp -- eproc )
1504 ['] variable-executor primitive-proc-type
1508 : definition-executor ( var val-eproc env -- ok )
1509 2swap 2over ( var env val-eproc env )
1510 evaluate-eproc 2swap ( var val env )
1515 : analyze-definition ( exp -- eproc )
1517 2swap definition-val analyze
1519 ['] definition-executor primitive-proc-type
1523 : assignment-executor ( var val-eproc env -- ok )
1524 2swap 2over ( var env val-eproc env )
1525 evaluate-eproc 2swap ( var val env )
1530 : analyze-assignment ( exp -- eproc )
1532 2swap assignment-val analyze ( var val-eproc )
1534 ['] assignment-executor primitive-proc-type
1538 : sequence-executor ( eproc-list env -- res )
1542 2dup cdr ( env elist elist-rest)
1545 -2rot car 2over ( elist-rest env elist-head env )
1546 evaluate-eproc ( elist-rest env head-res )
1547 2drop 2swap ( env elist-rest )
1551 ['] evaluate-eproc goto
1555 : (analyze-sequence) ( explist -- eproc-list )
1564 : analyze-sequence ( explist -- eproc )
1566 ['] sequence-executor primitive-proc-type
1571 : macro-definition-executor ( name params bproc env -- ok )
1572 make-macro ok-symbol
1575 : analyze-macro-definition ( exp -- eproc )
1576 2dup macro-definition-name
1577 2swap 2dup macro-definition-params
1578 2swap macro-definition-body analyze-sequence
1580 ['] macro-definition-executor primitive-proc-type
1581 nil cons cons cons cons
1584 : if-executor ( cproc aproc pproc env -- res )
1585 2swap 2over ( cproc aproc env pproc env -- res )
1594 ['] evaluate-eproc goto
1597 : analyze-if ( exp -- eproc )
1598 2dup if-consequent analyze
1599 2swap 2dup if-alternative analyze
1600 2swap if-predicate analyze
1602 ['] if-executor primitive-proc-type
1603 nil cons cons cons cons
1606 : lambda-executor ( params bproc env -- res )
1608 ( Although this is packaged up as a regular compound procedure,
1609 the "body" element contains an _eproc_ to be evaluated in an
1610 environment resulting from extending env with the parameter
1614 : analyze-lambda ( exp -- eproc )
1615 2dup lambda-parameters
1619 except-message: ." encountered lambda with an empty body." recoverable-exception throw
1624 ['] lambda-executor primitive-proc-type
1628 : operand-eproc-list ( operands -- eprocs )
1636 : evaluate-operand-eprocs ( env aprocs -- vals )
1640 2over 2over car 2swap evaluate-eproc ( env aprocs thisval )
1641 -2rot cdr recurse ( thisval restvals )
1646 : apply ( vals proc )
1648 primitive-proc-type of
1652 compound-proc-type of
1653 2dup procedure-body ( argvals proc bproc )
1654 -2rot 2dup procedure-params ( bproc argvals proc argnames )
1655 -2rot procedure-env ( bproc argnames argvals procenv )
1661 extend-env ( bproc env )
1663 ['] evaluate-eproc goto
1666 except-message: ." object '" drop print ." ' not applicable." recoverable-exception throw
1670 : application-executor ( operator-proc arg-procs env -- res )
1671 2rot 2over ( aprocs env fproc env )
1672 evaluate-eproc ( aprocs env proc )
1674 -2rot 2swap ( proc env aprocs )
1675 evaluate-operand-eprocs ( proc vals )
1682 : analyze-application ( exp -- eproc )
1683 2dup operator analyze
1684 2swap operands operand-eproc-list
1686 ['] application-executor primitive-proc-type
1690 :noname ( exp --- eproc )
1692 self-evaluating? if analyze-self-evaluating exit then
1694 quote? if analyze-quoted exit then
1696 variable? if analyze-variable exit then
1698 definition? if analyze-definition exit then
1700 assignment? if analyze-assignment exit then
1702 macro-definition? if analyze-macro-definition exit then
1704 if? if analyze-if exit then
1706 lambda? if analyze-lambda exit then
1708 application? if analyze-application exit then
1710 except-message: ." tried to analyze unknown expression type." recoverable-exception throw
1716 \ ---- Macro Expansion ---- {{{
1718 ( Simply evaluates the given procedure with expbody as its argument. )
1719 : macro-eval ( proc expbody -- result )
1721 2dup procedure-body ( expbody proc bproc )
1722 -2rot 2dup procedure-params ( bproc expbody proc argnames )
1723 -2rot procedure-env ( bproc argnames expbody procenv )
1729 extend-env ( bproc env )
1731 ['] evaluate-eproc goto
1734 : expand-macro ( exp -- result )
1735 pair-type istype? invert if exit then
1737 2dup car symbol-type istype? invert if 2drop exit then
1739 lookup-macro nil? if 2drop exit then
1741 2over cdr macro-eval
1743 2dup no-match-symbol objeq? if
1749 R> drop ['] expand goto-deferred
1752 : expand-definition ( exp -- result )
1756 2swap definition-val expand
1757 nil ( define var val' nil )
1761 : expand-assignment ( exp -- result )
1765 2swap assignment-val expand
1766 nil ( define var val' nil )
1770 : expand-list ( exp -- res )
1778 : macro-definition-nameparams
1781 : expand-define-macro ( exp -- res )
1782 define-macro-symbol 2swap
1783 2dup macro-definition-nameparams
1784 2swap macro-definition-body expand-list
1788 : expand-lambda ( exp -- res )
1790 2dup lambda-parameters
1791 2swap lambda-body expand-list
1795 : expand-if ( exp -- res )
1798 2dup if-predicate expand
1799 2swap 2dup if-consequent expand
1800 2swap if-alternative none? if
1808 : expand-application ( exp -- res )
1809 2dup operator expand
1810 2swap operands expand-list
1814 :noname ( exp -- result )
1817 self-evaluating? if exit then
1821 definition? if expand-definition exit then
1823 assignment? if expand-assignment exit then
1825 macro-definition? if expand-define-macro exit then
1827 lambda? if expand-lambda exit then
1829 if? if expand-if exit then
1831 application? if expand-application exit then
1837 :noname ( exp env -- res )
1838 2swap expand analyze 2swap evaluate-eproc
1841 \ ---- Print ---- {{{
1843 : printfixnum ( fixnum -- ) drop 0 .R ;
1845 : printflonum ( flonum -- ) drop f. ;
1847 : printratnum ( ratnum -- )
1849 car print ." /" cdr print
1852 : printbool ( bool -- )
1860 : printchar ( charobj -- )
1863 9 of ." #\tab" endof
1864 bl of ." #\space" endof
1865 '\n' of ." #\newline" endof
1871 : (printstring) ( stringobj -- )
1872 nil? if 2drop exit then
1876 '\n' of ." \n" drop endof
1877 [char] \ of ." \\" drop endof
1878 [char] " of [char] \ emit [char] " emit drop endof
1884 : printstring ( stringobj -- )
1889 : printsymbol ( symbolobj -- )
1890 nil-type istype? if 2drop exit then
1896 : printnil ( nilobj -- )
1899 : printpair ( pairobj -- )
1903 nil-type istype? if 2drop exit then
1904 pair-type istype? if space recurse exit then
1908 : printprim ( primobj -- )
1909 2drop ." <primitive procedure>" ;
1911 : printcomp ( primobj -- )
1912 2drop ." <compound procedure>" ;
1914 : printnone ( noneobj -- )
1915 2drop ." Unspecified return value" ;
1917 : printport ( port -- )
1921 fixnum-type istype? if printfixnum exit then
1922 flonum-type istype? if printflonum exit then
1923 ratnum-type istype? if printratnum exit then
1924 boolean-type istype? if printbool exit then
1925 character-type istype? if printchar exit then
1926 string-type istype? if printstring exit then
1927 symbol-type istype? if printsymbol exit then
1928 nil-type istype? if printnil exit then
1929 pair-type istype? if ." (" printpair ." )" exit then
1930 primitive-proc-type istype? if printprim exit then
1931 compound-proc-type istype? if printcomp exit then
1932 none-type istype? if printnone exit then
1933 port-type istype? if printport exit then
1935 except-message: ." tried to print object with unknown type." recoverable-exception throw
1940 \ ---- Garbage Collection ---- {{{
1942 ( Notes on garbage collection:
1943 This is a mark-sweep garbage collector, invoked by cons.
1944 The roots of the object tree used by the marking routine
1945 include all objects in the parameter stack, and several
1946 other fixed roots such as global-env, symbol-table, macro-table,
1947 and the console-i/o-port.
1949 NO OTHER OBJECTS WILL BE MARKED!
1951 This places implicit restrictions on when cons can be invoked.
1952 Invoking cons when live objects are stored on the return stack
1953 or in other variables than the above will result in possible
1954 memory corruption if the cons triggers the GC. )
1956 variable gc-stack-depth
1959 depth gc-stack-depth !
1963 false gc-enabled ! ;
1965 : pairlike? ( obj -- obj bool )
1966 pair-type istype? if true exit then
1967 string-type istype? if true exit then
1968 symbol-type istype? if true exit then
1969 compound-proc-type istype? if true exit then
1970 port-type istype? if true exit then
1975 : pairlike-marked? ( obj -- obj bool )
1976 over nextfrees + @ 0=
1979 : mark-pairlike ( obj -- obj )
1980 over nextfrees + 0 swap !
1989 : gc-mark-obj ( obj -- )
1991 pairlike? invert if 2drop exit then
1992 pairlike-marked? if 2drop exit then
2003 scheme-memsize nextfree !
2004 0 scheme-memsize 1- do
2005 nextfrees i + @ 0<> if
2006 nextfree @ nextfrees i + !
2012 \ Following a GC, this gives the amount of free memory
2016 nextfrees i + @ 0= if 1+ then
2020 \ Debugging word - helps spot memory that is retained
2023 nextfrees i + @ 0<> if
2035 symbol-table obj@ gc-mark-obj
2036 macro-table obj@ gc-mark-obj
2037 console-i/o-port obj@ gc-mark-obj
2038 global-env obj@ gc-mark-obj
2040 depth gc-stack-depth @ do
2049 \ ." (" gc-count-marked . ." pairs marked as used.)" cr
2050 ; is collect-garbage
2054 \ ---- Loading files ---- {{{
2056 : load ( addr n -- finalResult )
2061 ok-symbol ( port res )
2065 \ bold fg blue ." READ from " 2over drop . ." ==> " reset-term
2067 2over read-port ( port res obj )
2072 2dup EOF character-type objeq? if
2073 2drop 2swap close-port
2077 2swap 2drop ( port obj )
2079 global-env obj@ eval ( port res )
2085 \ ---- Standard Library ---- {{{
2087 include scheme-primitives.4th
2091 s" scheme-library.scm" load 2drop
2099 ( REPL calls REPL-BODY in a loop until repl-body returns true. )
2100 : repl-body ( -- bool )
2101 cr bold fg green ." > " reset-term
2105 2dup EOF character-type objeq? if
2107 bold fg blue ." Moriturus te saluto." reset-term cr
2111 global-env obj@ eval
2113 fg cyan ." ; " print reset-term
2123 \ Display welcome message
2124 welcome-symbol nil cons global-env obj@ eval 2drop
2129 recoverable-exception of false endof
2130 unrecoverable-exception of true endof