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
42 make-type continuation-type
44 : istype? ( obj type -- obj bool )
49 \ ---- Exceptions ---- {{{
51 variable nextexception
54 create nextexception @ ,
63 make-exception recoverable-exception
64 make-exception unrecoverable-exception
66 : throw reset-term cr throw ;
70 \ ---- List-structured memory ---- {{{
72 20000 constant scheme-memsize
74 create car-cells scheme-memsize allot
75 create car-type-cells scheme-memsize allot
76 create cdr-cells scheme-memsize allot
77 create cdr-type-cells scheme-memsize allot
79 create nextfrees scheme-memsize allot
90 nextfrees nextfree @ + @
93 nextfree @ scheme-memsize >= if
97 nextfree @ scheme-memsize >= if
98 except-message: ." Out of memory!" unrecoverable-exception throw
102 : cons ( car-obj cdr-obj -- pair-obj )
103 cdr-type-cells nextfree @ + !
104 cdr-cells nextfree @ + !
105 car-type-cells nextfree @ + !
106 car-cells nextfree @ + !
112 : car ( pair-obj -- car-obj )
114 dup car-cells + @ swap
118 : cdr ( pair-obj -- car-obj )
120 dup cdr-cells + @ swap
124 : set-car! ( obj pair-obj -- )
126 rot swap car-type-cells + !
130 : set-cdr! ( obj pair-obj -- )
132 rot swap cdr-type-cells + !
136 variable object-stack-base
137 : init-object-stack-base
138 depth object-stack-base ! ;
141 : nil? nil-type istype? ;
144 : none? none-type istype? ;
146 : objvar create nil swap , , ;
148 : value@ ( objvar -- val ) @ ;
149 : type@ ( objvar -- type ) 1+ @ ;
150 : value! ( newval objvar -- ) ! ;
151 : type! ( newtype objvar -- ) 1+ ! ;
152 : obj! ( newobj objvar -- ) dup rot swap 1+ ! ! ;
153 : obj@ ( objvar -- obj ) dup @ swap 1+ @ ;
155 : objeq? ( obj obj -- bool )
158 : 2rot ( a1 a2 b1 b2 c1 c2 -- b1 b2 c1 c2 a1 a2 )
159 >R >R ( a1 a2 b1 b2 )
160 2swap ( b1 b2 a1 a2 )
161 R> R> ( b1 b2 a1 a2 c1 c2 )
165 : -2rot ( a1 a2 b1 b2 c1 c2 -- c1 c2 a1 a2 b1 b2 )
166 2swap ( a1 a2 c1 c2 b1 b2 )
167 >R >R ( a1 a2 c1 c2 )
168 2swap ( c1 c2 a1 a2 )
172 : 2pick ( an bn an-1 bn-1 ... a0 b0 n -- an bn an-1 bn-1 ... a0 b0 an bn )
178 \ ---- Pre-defined symbols ---- {{{
182 : duplicate-charlist ( charlist -- copy )
184 2dup car 2swap cdr recurse cons
187 : charlist-equiv ( charlist charlist -- bool )
196 2drop 2drop true exit
198 2drop 2drop false exit
203 2drop 2drop false exit
210 car drop -rot car drop = if
211 cdr 2swap cdr recurse
217 : charlist>symbol ( charlist -- symbol-obj )
236 drop symbol-type 2dup
237 symbol-table obj@ cons
242 : cstr>charlist ( addr n -- charlist )
246 2dup drop @ character-type 2swap
254 : create-symbol ( -- )
262 does> dup @ swap 1+ @
265 create-symbol quote quote-symbol
266 create-symbol quasiquote quasiquote-symbol
267 create-symbol unquote unquote-symbol
268 create-symbol unquote-splicing unquote-splicing-symbol
269 create-symbol define define-symbol
270 create-symbol define-macro define-macro-symbol
271 create-symbol set! set!-symbol
272 create-symbol ok ok-symbol
273 create-symbol if if-symbol
274 create-symbol lambda lambda-symbol
275 create-symbol λ λ-symbol
276 create-symbol eof eof-symbol
277 create-symbol no-match no-match-symbol
279 \ Symbol to be bound to welcome message procedure by library
280 create-symbol welcome welcome-symbol
284 \ ---- Port I/O ---- {{{
286 ( Ports are pairs with the fid in the car and the peek buffer in the cdr. )
288 : fileport>fid ( fileport -- fid )
289 drop pair-type car drop ;
291 : get-last-peek ( fileport -- char/nil )
294 : set-last-peek ( char/nil fileport -- )
295 drop pair-type set-cdr!
298 : fid>fileport ( fid -- fileport )
299 fixnum-type nil cons drop port-type ;
301 : open-input-file ( addr n -- fileport )
302 r/o open-file drop fid>fileport
305 : close-port ( fileport -- )
306 fileport>fid close-file drop
309 objvar console-i/o-port
310 0 fixnum-type nil cons drop port-type console-i/o-port obj!
312 objvar current-input-port
313 console-i/o-port obj@ current-input-port obj!
315 : read-char ( port -- char )
316 2dup get-last-peek nil? if
318 2dup console-i/o-port obj@ objeq? if
322 fileport>fid pad 1 rot read-file 0= if
333 : peek-char ( port -- char )
334 2dup get-last-peek nil? if
336 2dup 2rot set-last-peek
342 variable read-line-buffer-span
343 variable read-line-buffer-offset
345 ( Hack to save original read-line while we transition to new one. )
346 : orig-read-line immediate
349 : read-line ( port -- string )
354 0 read-line-buffer-offset !
356 2over nil 2swap set-last-peek
358 2drop nil nil cons exit
361 1 read-line-buffer-offset !
365 2dup console-i/o-port obj@ objeq? if
367 pad read-line-buffer-offset @ + 200 expect cr
368 span @ read-line-buffer-offset @ + read-line-buffer-span !
370 pad read-line-buffer-offset @ + 200 2over fileport>fid orig-read-line
371 drop swap read-line-buffer-offset @ + read-line-buffer-span !
377 read-line-buffer-span @ 0>
379 pad read-line-buffer-span @ 1- + @ character-type 2swap cons
380 -1 read-line-buffer-span +!
384 nil cons drop string-type
390 : read-port ( fileport -- obj )
391 current-input-port obj!
394 : read-console ( -- obj )
395 console-i/o-port obj@ read-port ;
399 \ ---- Environments ---- {{{
401 : enclosing-env ( env -- env )
404 : first-frame ( env -- frame )
407 : make-frame ( vars vals -- frame )
410 : add-frame-to-env ( frame env -- env )
413 : frame-vars ( frame -- vars )
416 : frame-vals ( frame -- vals )
419 : add-binding ( var val frame -- )
420 2swap 2over frame-vals cons
422 2swap 2over frame-vars cons
426 : extend-env ( vars vals env -- env )
428 2swap add-frame-to-env
431 : get-vals-frame ( var frame -- vals | nil )
433 2swap frame-vals ( var vars vals )
439 -2rot ( vals var vars )
440 2over 2over car objeq? if
452 : get-vals ( var env -- vals | nil )
457 2over 2over first-frame
458 get-vals-frame nil? false = if
459 2swap 2drop 2swap 2drop
471 objvar var \ Used only for error messages
472 : lookup-var ( var env -- val )
476 except-message: ." tried to read unbound variable '" var obj@ print ." '."
477 recoverable-exception throw
483 : set-var ( var val env -- )
484 2rot 2dup var obj! ( val env var )
485 2swap ( val var env )
487 except-message: ." tried to set unbound variable '" var obj@ print ." '."
488 recoverable-exception throw
496 : define-var ( var val env -- )
497 first-frame ( var val frame )
498 2rot 2swap 2over 2over ( val var frame var frame )
500 get-vals-frame nil? if
505 ( val var frame vals )
506 2swap 2drop 2swap 2drop
511 : make-procedure ( params body env -- proc )
514 drop compound-proc-type
518 nil nil nil extend-env
523 \ ---- Continuations ---- {{{
525 : cons-return-stack ( -- listobj )
531 i 1+ @ fixnum-type 2swap cons
534 rsp@ 1- rsp0 - fixnum-type 2swap cons
537 : cons-param-stack ( -- listobj )
540 depth 2- object-stack-base @ = if
544 depth 2- object-stack-base @ do
551 depth 2- 2/ fixnum-type 2swap cons
554 : make-continuation ( -- continuation true-obj )
555 \ true-obj allows calling code to detect whether
556 \ it is being called immediately following make-continuation
557 \ or by a restore-continuation.
561 cons drop continuation-type
566 : continuation->pstack-list
569 : continuation->rstack-list
572 : stack-list-len ( stack-list -- n )
576 : restore-param-stack ( continuation -- obj_stack )
577 continuation->pstack-list
580 ( Allocate stack space first using psp!,
581 then copy objects from list. )
584 object-stack-base @ psp0 + + psp!
588 stack-list-len 1- 0 swap do
591 PSP0 object-stack-base @ + i 2* + 2 + !
592 PSP0 object-stack-base @ + i 2* + 1 + !
600 ( This word restores the return stack to that contained in the
601 continuation object, and thus NEVER RETURNS. )
602 : restore-return-stack ( continuation -- )
604 continuation->rstack-list
606 2dup cdr 2swap stack-list-len ( list n )
608 dup RSP0 + RSP! \ expand return stack to accommodate entries
612 1- \ initial offset n-1
616 2dup cdr 2swap car drop
623 ( This word restores the parameter and return stacks
624 to those in the continuation object. The restoration of the
625 return stack means that execution continues at the point
626 described in the continuation object, so this word NEVER RETURNS.
628 Note that both obj and a false-obj are added to the parameter
629 stack before the return stack is restored, so that make-continuation
630 knows that this execution path is the result of a continuation
631 restoration rather than the original call to make-continuation. )
632 : restore-continuation-with-arg ( continuation obj -- )
634 >R >R \ Store obj on return stack
636 2dup >R >R \ Store copy of continuation on return stack
640 R> R> \ Pop continuation from return stack
642 R> R> \ Pop obj from return stack
646 false boolean-type \ Add flag signifying continuation restore
655 \ ---- Primitives ---- {{{
657 : make-primitive ( cfa -- )
664 rot primitive-proc-type ( var prim )
665 global-env obj@ define-var
668 : ensure-arg-count ( args n -- )
670 drop nil objeq? false = if
671 except-message: ." Too many arguments for primitive procedure." recoverable-exception throw
675 except-message: ." Too few arguments for primitive procedure." recoverable-exception throw
682 : ensure-arg-type-and-count ( tn tn-1 ... t2 t1 args n -- )
684 drop nil objeq? false = if
685 except-message: ." Too many arguments for primitive procedure." recoverable-exception throw
689 except-message: ." Too few arguments for primitive procedure." recoverable-exception throw
692 2dup cdr 2swap car ( ... t1 n args' arg1 )
693 2rot 1- swap 2swap rot ( ... args' n-1 arg1 t1 )
695 except-message: ." Incorrect type for primitive procedure." recoverable-exception throw
703 : push-args-to-stack ( args -- arg1 arg2 ... argn )
713 : add-fa-checks ( cfa n -- cfa' )
714 here current @ 1+ dup @ , !
718 ['] 2dup , ['] lit , , ['] ensure-arg-count ,
719 ['] push-args-to-stack ,
720 ['] lit , , ['] execute ,
724 : add-fa-type-checks ( cfa t1 t2 ... tn n -- cfa' )
725 here current @ 1+ dup @ , !
732 dup ( cfa t1 t2 ... tn n m )
737 rot ['] lit , , ( cfa t1 t2 ... tn-1 n m )
743 ['] lit , , ['] ensure-arg-type-and-count ,
745 ['] push-args-to-stack ,
746 ['] lit , , ['] execute ,
752 : make-fa-primitive ( cfa n -- )
753 add-fa-checks make-primitive ;
755 : make-fa-type-primitive ( cfa t1 t2 ... tn n -- )
756 add-fa-type-checks make-primitive ;
759 bold fg red ." Incorrect argument type." reset-term cr
763 : ensure-arg-type ( arg type -- arg )
765 except-message: ." Incorrect argument type for primitive procedure." recoverable-exception throw
772 \ ---- Macros ---- {{{
776 ( Look up macro in macro table. Returns nil if
778 : lookup-macro ( name_symbol -- proc )
780 symbol-type istype? invert if
781 \ Early exit if argument is not a symbol
803 : make-macro ( name_symbol params body env -- )
806 2swap ( proc name_symbol )
813 2over 2over ( proc name table name table )
815 2swap 2drop ( proc table )
827 macro-table obj@ cons
836 variable stored-parse-idx
837 create parse-str 161 allot
838 variable parse-str-span
840 create parse-idx-stack 10 allot
841 variable parse-idx-sp
842 parse-idx-stack parse-idx-sp !
845 parse-idx @ parse-idx-sp @ !
850 parse-idx-sp @ parse-idx-stack <= abort" Parse index stack underflow."
854 parse-idx-sp @ @ parse-idx ! ;
858 '\n' parse-str parse-str-span @ + !
859 1 parse-str-span +! ;
862 4 parse-str parse-str-span @ + !
863 1 parse-str-span +! ;
870 current-input-port obj@ console-i/o-port obj@ objeq? if
871 parse-str 160 expect cr
872 span @ parse-str-span !
874 parse-str 160 current-input-port obj@ fileport>fid orig-read-line
875 drop swap parse-str-span !
877 parse-str-span @ 0= and if append-eof then
888 : charavailable? ( -- bool )
889 parse-str-span @ parse-idx @ > ;
891 : nextchar ( -- char )
892 charavailable? false = if getline then
893 parse-str parse-idx @ + @ ;
896 : whitespace? ( -- bool )
908 nextchar [char] ( = or
909 nextchar [char] ) = or
912 : commentstart? ( -- bool )
913 nextchar [char] ; = ;
917 false \ Indicates whether or not we're eating a comment
920 dup whitespace? or commentstart? or
922 dup nextchar '\n' = and if
923 invert \ Stop eating comment
925 dup false = commentstart? and if
926 invert \ Begin eating comment
941 nextchar [char] - = ;
944 nextchar [char] + = ;
946 : fixnum? ( -- bool )
972 : flonum? ( -- bool )
979 \ Record starting parse idx:
980 \ Want to detect whether any characters (following +/-) were eaten.
987 [char] . nextchar = if
994 [char] e nextchar = [char] E nextchar = or if
1002 drop pop-parse-idx false exit
1010 \ This is a real number if characters were
1011 \ eaten and the next characer is a delimiter.
1012 parse-idx @ < delim? and
1017 : ratnum? ( -- bool )
1025 pop-parse-idx false exit
1034 [char] / nextchar <> if
1035 pop-parse-idx false exit
1041 pop-parse-idx false exit
1050 delim? pop-parse-idx
1053 : boolean? ( -- bool )
1054 nextchar [char] # <> if false exit then
1059 nextchar [char] t <>
1060 nextchar [char] f <>
1061 and if pop-parse-idx false exit then
1073 : str-equiv? ( str -- bool )
1090 delim? false = if drop false then
1095 : character? ( -- bool )
1096 nextchar [char] # <> if false exit then
1101 nextchar [char] \ <> if pop-parse-idx false exit then
1105 S" newline" str-equiv? if pop-parse-idx true exit then
1106 S" space" str-equiv? if pop-parse-idx true exit then
1107 S" tab" str-equiv? if pop-parse-idx true exit then
1109 charavailable? false = if pop-parse-idx false exit then
1115 nextchar [char] ( = ;
1117 : string? ( -- bool )
1118 nextchar [char] " = ;
1120 : readfixnum ( -- fixnum )
1131 10 * nextchar [char] 0 - +
1140 : readflonum ( -- flonum )
1142 dup 0< swap abs i->f
1144 [char] . nextchar = if
1150 nextchar [char] 0 - i->f ( f exp d )
1151 over f/ rot f+ ( exp f' )
1152 swap 10.0 f* ( f' exp' )
1159 [char] e nextchar = [char] E nextchar = or if
1162 readfixnum drop i->f
1173 : make-rational ( fixnum fixnum -- ratnum|fixnum )
1180 fixnum-type swap fixnum-type
1181 cons drop ratnum-type
1185 : readratnum ( -- ratnum )
1186 readfixnum inc-parse-idx readfixnum
1190 : readbool ( -- bool-obj )
1193 nextchar [char] f = if
1204 : readchar ( -- char-obj )
1208 S" newline" str-equiv? if 7 parse-idx +! '\n' character-type exit then
1209 S" space" str-equiv? if 5 parse-idx +! bl character-type exit then
1210 S" tab" str-equiv? if 3 parse-idx +! 9 character-type exit then
1212 nextchar character-type
1217 : readstring ( -- charlist )
1222 nextchar [char] " <>
1224 nextchar [char] \ = if
1227 [char] n of '\n' endof
1228 [char] " of [char] " endof
1234 inc-parse-idx character-type
1237 ( firstchar prevchar thischar )
1240 2drop 2swap 2drop 2dup ( thischar thischar )
1242 ( firstchar thischar prevchar )
1243 2over 2swap set-cdr! ( firstchar thischar )
1247 \ Discard previous character
1253 ." No delimiter following right double quote. Aborting." cr
1265 : readsymbol ( -- charlist )
1266 delim? if nil exit then
1268 nextchar inc-parse-idx character-type
1275 : readpair ( -- pairobj )
1279 nextchar [char] ) = if
1284 ." No delimiter following right paren. Aborting." cr
1293 \ Read first pair element
1298 nextchar [char] . = if
1303 ." No delimiter following '.'. Aborting." cr
1317 \ Parse a scheme expression
1352 nextchar [char] " <> if
1353 bold red ." Missing closing double-quote." reset-term cr
1371 nextchar [char] ) <> if
1372 bold red ." Missing closing paren." reset-term cr
1381 nextchar [char] ' = if
1383 quote-symbol recurse nil cons cons exit
1386 nextchar [char] ` = if
1388 quasiquote-symbol recurse nil cons cons exit
1391 nextchar [char] , = if
1393 nextchar [char] @ = if
1395 unquote-splicing-symbol recurse nil cons cons exit
1397 unquote-symbol recurse nil cons cons exit
1407 nextchar [char] ) = if
1409 except-message: ." unmatched closing parenthesis." recoverable-exception throw
1412 \ Anything else is parsed as a symbol
1413 readsymbol charlist>symbol
1415 \ Replace λ with lambda
1416 2dup λ-symbol objeq? if
1425 \ ---- Syntax ---- {{{
1427 : self-evaluating? ( obj -- obj bool )
1428 boolean-type istype? if true exit then
1429 fixnum-type istype? if true exit then
1430 flonum-type istype? if true exit then
1431 ratnum-type istype? if true exit then
1432 character-type istype? if true exit then
1433 string-type istype? if true exit then
1434 nil-type istype? if true exit then
1435 none-type istype? if true exit then
1440 : tagged-list? ( obj tag-obj -- obj bool )
1442 pair-type istype? false = if
1448 : quote? ( obj -- obj bool )
1449 quote-symbol tagged-list? ;
1451 : quote-body ( quote-obj -- quote-body-obj )
1454 : variable? ( obj -- obj bool )
1455 symbol-type istype? ;
1457 : definition? ( obj -- obj bool )
1458 define-symbol tagged-list? ;
1460 : definition-var ( obj -- var )
1463 : definition-val ( obj -- val )
1466 : assignment? ( obj -- obj bool )
1467 set!-symbol tagged-list? ;
1469 : assignment-var ( obj -- var )
1472 : assignment-val ( obj -- val )
1475 : macro-definition? ( obj -- obj bool )
1476 define-macro-symbol tagged-list? ;
1478 : macro-definition-name ( exp -- mname )
1481 : macro-definition-params ( exp -- params )
1484 : macro-definition-body ( exp -- body )
1487 : if? ( obj -- obj bool )
1488 if-symbol tagged-list? ;
1490 : if-predicate ( ifobj -- pred )
1493 : if-consequent ( ifobj -- conseq )
1496 : if-alternative ( ifobj -- alt|none )
1504 : false? ( boolobj -- boolean )
1505 boolean-type istype? if
1506 false boolean-type objeq?
1512 : true? ( boolobj -- bool )
1515 : lambda? ( obj -- obj bool )
1516 lambda-symbol tagged-list? ;
1518 : lambda-parameters ( obj -- params )
1521 : lambda-body ( obj -- body )
1524 : application? ( obj -- obj bool )
1527 : operator ( obj -- operator )
1530 : operands ( obj -- operands )
1533 : nooperands? ( operands -- bool )
1536 : first-operand ( operands -- operand )
1539 : rest-operands ( operands -- other-operands )
1542 : procedure-params ( proc -- params )
1543 drop pair-type car ;
1545 : procedure-body ( proc -- body )
1546 drop pair-type cdr car ;
1548 : procedure-env ( proc -- body )
1549 drop pair-type cdr cdr car ;
1551 ( Ensure terminating symbol arg name is handled
1552 specially to allow for variadic procedures. )
1553 : flatten-proc-args ( argvals argnames -- argvals' argnames' )
1555 2over nil? false = if
1556 except-message: ." Too many arguments for compound procedure." recoverable-exception throw
1563 symbol-type istype? if
1573 except-message: ." Too few arguments for compound procedure." recoverable-exception throw
1580 recurse ( argvals argnames argvals'' argnames'' )
1581 2rot car 2swap cons ( argvals argvals'' argnames' )
1582 2rot car 2rot cons ( argnames' argvals' )
1588 \ ---- Analyze ---- {{{
1590 : evaluate-eproc ( eproc env --- res )
1601 2drop \ get rid of null
1605 \ Final element of eproc list is primitive procedure
1606 drop \ dump type signifier
1608 goto \ jump straight to primitive procedure (executor)
1611 : self-evaluating-executor ( exp env -- exp )
1614 : analyze-self-evaluating ( exp --- eproc )
1615 ['] self-evaluating-executor primitive-proc-type
1619 : quote-executor ( exp env -- exp )
1622 : analyze-quoted ( exp -- eproc )
1625 ['] quote-executor primitive-proc-type
1629 : variable-executor ( var env -- val )
1632 : analyze-variable ( exp -- eproc )
1633 ['] variable-executor primitive-proc-type
1637 : definition-executor ( var val-eproc env -- ok )
1638 2swap 2over ( var env val-eproc env )
1639 evaluate-eproc 2swap ( var val env )
1644 : analyze-definition ( exp -- eproc )
1646 2swap definition-val analyze
1648 ['] definition-executor primitive-proc-type
1652 : assignment-executor ( var val-eproc env -- ok )
1653 2swap 2over ( var env val-eproc env )
1654 evaluate-eproc 2swap ( var val env )
1659 : analyze-assignment ( exp -- eproc )
1661 2swap assignment-val analyze ( var val-eproc )
1663 ['] assignment-executor primitive-proc-type
1667 : sequence-executor ( eproc-list env -- res )
1671 2dup cdr ( env elist elist-rest)
1674 -2rot car 2over ( elist-rest env elist-head env )
1675 evaluate-eproc ( elist-rest env head-res )
1676 2drop 2swap ( env elist-rest )
1680 ['] evaluate-eproc goto
1684 : (analyze-sequence) ( explist -- eproc-list )
1693 : analyze-sequence ( explist -- eproc )
1695 ['] sequence-executor primitive-proc-type
1700 : macro-definition-executor ( name params bproc env -- ok )
1701 make-macro ok-symbol
1704 : analyze-macro-definition ( exp -- eproc )
1705 2dup macro-definition-name
1706 2swap 2dup macro-definition-params
1707 2swap macro-definition-body analyze-sequence
1709 ['] macro-definition-executor primitive-proc-type
1710 nil cons cons cons cons
1713 : if-executor ( cproc aproc pproc env -- res )
1714 2swap 2over ( cproc aproc env pproc env -- res )
1723 ['] evaluate-eproc goto
1726 : analyze-if ( exp -- eproc )
1727 2dup if-consequent analyze
1728 2swap 2dup if-alternative analyze
1729 2swap if-predicate analyze
1731 ['] if-executor primitive-proc-type
1732 nil cons cons cons cons
1735 : lambda-executor ( params bproc env -- res )
1737 ( Although this is packaged up as a regular compound procedure,
1738 the "body" element contains an _eproc_ to be evaluated in an
1739 environment resulting from extending env with the parameter
1743 : analyze-lambda ( exp -- eproc )
1744 2dup lambda-parameters
1748 except-message: ." encountered lambda with an empty body." recoverable-exception throw
1753 ['] lambda-executor primitive-proc-type
1757 : operand-eproc-list ( operands -- eprocs )
1765 : evaluate-operand-eprocs ( env aprocs -- vals )
1769 2over 2over car 2swap evaluate-eproc ( env aprocs thisval )
1770 -2rot cdr recurse ( thisval restvals )
1775 : apply ( vals proc )
1777 primitive-proc-type of
1781 compound-proc-type of
1782 2dup procedure-body ( argvals proc bproc )
1783 -2rot 2dup procedure-params ( bproc argvals proc argnames )
1784 -2rot procedure-env ( bproc argnames argvals procenv )
1790 extend-env ( bproc env )
1792 ['] evaluate-eproc goto
1795 continuation-type of
1798 except-message: ." Continuations expect exactly 1 argument."
1799 recoverable-exception throw
1805 except-message: ." Continuations expect exactly 1 argument."
1806 recoverable-exception throw
1811 restore-continuation-with-arg
1814 except-message: ." object '" drop print ." ' not applicable." recoverable-exception throw
1818 : application-executor ( operator-proc arg-procs env -- res )
1819 2rot 2over ( aprocs env fproc env )
1820 evaluate-eproc ( aprocs env proc )
1822 -2rot 2swap ( proc env aprocs )
1823 evaluate-operand-eprocs ( proc vals )
1830 : analyze-application ( exp -- eproc )
1831 2dup operator analyze
1832 2swap operands operand-eproc-list
1834 ['] application-executor primitive-proc-type
1838 :noname ( exp --- eproc )
1840 self-evaluating? if analyze-self-evaluating exit then
1842 quote? if analyze-quoted exit then
1844 variable? if analyze-variable exit then
1846 definition? if analyze-definition exit then
1848 assignment? if analyze-assignment exit then
1850 macro-definition? if analyze-macro-definition exit then
1852 if? if analyze-if exit then
1854 lambda? if analyze-lambda exit then
1856 application? if analyze-application exit then
1858 except-message: ." tried to analyze unknown expression type." recoverable-exception throw
1864 \ ---- Macro Expansion ---- {{{
1866 ( Simply evaluates the given procedure with expbody as its argument. )
1867 : macro-eval ( proc expbody -- result )
1869 2dup procedure-body ( expbody proc bproc )
1870 -2rot 2dup procedure-params ( bproc expbody proc argnames )
1871 -2rot procedure-env ( bproc argnames expbody procenv )
1877 extend-env ( bproc env )
1879 ['] evaluate-eproc goto
1882 : expand-macro ( exp -- result )
1883 pair-type istype? invert if exit then
1885 2dup car symbol-type istype? invert if 2drop exit then
1887 lookup-macro nil? if 2drop exit then
1889 2over cdr macro-eval
1891 2dup no-match-symbol objeq? if
1897 R> drop ['] expand goto-deferred
1900 : expand-definition ( exp -- result )
1904 2swap definition-val expand
1905 nil ( define var val' nil )
1909 : expand-assignment ( exp -- result )
1913 2swap assignment-val expand
1914 nil ( define var val' nil )
1918 : expand-list ( exp -- res )
1926 : macro-definition-nameparams
1929 : expand-define-macro ( exp -- res )
1930 define-macro-symbol 2swap
1931 2dup macro-definition-nameparams
1932 2swap macro-definition-body expand-list
1936 : expand-lambda ( exp -- res )
1938 2dup lambda-parameters
1939 2swap lambda-body expand-list
1943 : expand-if ( exp -- res )
1946 2dup if-predicate expand
1947 2swap 2dup if-consequent expand
1948 2swap if-alternative none? if
1956 : expand-application ( exp -- res )
1957 2dup operator expand
1958 2swap operands expand-list
1962 :noname ( exp -- result )
1965 self-evaluating? if exit then
1969 definition? if expand-definition exit then
1971 assignment? if expand-assignment exit then
1973 macro-definition? if expand-define-macro exit then
1975 lambda? if expand-lambda exit then
1977 if? if expand-if exit then
1979 application? if expand-application exit then
1985 :noname ( exp env -- res )
1986 2swap expand analyze 2swap evaluate-eproc
1989 \ ---- Print ---- {{{
1991 : printfixnum ( fixnum -- ) drop 0 .R ;
1993 : printflonum ( flonum -- ) drop f. ;
1995 : printratnum ( ratnum -- )
1997 car print ." /" cdr print
2000 : printbool ( bool -- )
2008 : printchar ( charobj -- )
2011 9 of ." #\tab" endof
2012 bl of ." #\space" endof
2013 '\n' of ." #\newline" endof
2019 : (printstring) ( stringobj -- )
2020 nil? if 2drop exit then
2024 '\n' of ." \n" drop endof
2025 [char] \ of ." \\" drop endof
2026 [char] " of [char] \ emit [char] " emit drop endof
2032 : printstring ( stringobj -- )
2037 : printsymbol ( symbolobj -- )
2038 nil-type istype? if 2drop exit then
2044 : printnil ( nilobj -- )
2047 : printpair ( pairobj -- )
2051 nil-type istype? if 2drop exit then
2052 pair-type istype? if space recurse exit then
2056 : printprim ( primobj -- )
2057 2drop ." <primitive procedure>" ;
2059 : printcomp ( primobj -- )
2060 2drop ." <compound procedure>" ;
2062 : printcont ( primobj --)
2063 2drop ." <continuation>" ;
2065 : printnone ( noneobj -- )
2066 2drop ." Unspecified return value" ;
2068 : printport ( port -- )
2072 fixnum-type istype? if printfixnum exit then
2073 flonum-type istype? if printflonum exit then
2074 ratnum-type istype? if printratnum exit then
2075 boolean-type istype? if printbool exit then
2076 character-type istype? if printchar exit then
2077 string-type istype? if printstring exit then
2078 symbol-type istype? if printsymbol exit then
2079 nil-type istype? if printnil exit then
2080 pair-type istype? if ." (" printpair ." )" exit then
2081 primitive-proc-type istype? if printprim exit then
2082 compound-proc-type istype? if printcomp exit then
2083 continuation-type istype? if printcont exit then
2084 none-type istype? if printnone exit then
2085 port-type istype? if printport exit then
2087 except-message: ." tried to print object with unknown type." recoverable-exception throw
2092 \ ---- Garbage Collection ---- {{{
2094 ( Notes on garbage collection:
2095 This is a mark-sweep garbage collector, invoked by cons.
2096 The roots of the object tree used by the marking routine
2097 include all objects in the parameter stack, and several
2098 other fixed roots such as global-env, symbol-table, macro-table,
2099 and the console-i/o-port.
2101 NO OTHER OBJECTS WILL BE MARKED!
2103 This places implicit restrictions on when cons can be invoked.
2104 Invoking cons when live objects are stored on the return stack
2105 or in other variables than the above will result in possible
2106 memory corruption if the cons triggers the GC. )
2109 : pairlike? ( obj -- obj bool )
2110 pair-type istype? if true exit then
2111 string-type istype? if true exit then
2112 symbol-type istype? if true exit then
2113 compound-proc-type istype? if true exit then
2114 port-type istype? if true exit then
2115 continuation-type istype? if true exit then
2120 : pairlike-marked? ( obj -- obj bool )
2121 over nextfrees + @ 0=
2124 : mark-pairlike ( obj -- obj )
2125 over nextfrees + 0 swap !
2134 : gc-mark-obj ( obj -- )
2136 pairlike? invert if 2drop exit then
2137 pairlike-marked? if 2drop exit then
2148 scheme-memsize nextfree !
2149 0 scheme-memsize 1- do
2150 nextfrees i + @ 0<> if
2151 nextfree @ nextfrees i + !
2157 \ Following a GC, this gives the amount of free memory
2161 nextfrees i + @ 0= if 1+ then
2165 \ Debugging word - helps spot memory that is retained
2168 nextfrees i + @ 0<> if
2180 symbol-table obj@ gc-mark-obj
2181 macro-table obj@ gc-mark-obj
2182 console-i/o-port obj@ gc-mark-obj
2183 global-env obj@ gc-mark-obj
2185 depth object-stack-base @ do
2194 \ ." (" gc-count-marked . ." pairs marked as used.)" cr
2195 ; is collect-garbage
2199 \ ---- Loading files ---- {{{
2201 : load ( addr n -- finalResult )
2206 ok-symbol ( port res )
2210 \ bold fg blue ." READ from " 2over drop . ." ==> " reset-term
2212 2over read-port ( port res obj )
2217 2dup EOF character-type objeq? if
2218 2drop 2swap close-port
2222 2swap 2drop ( port obj )
2224 global-env obj@ eval ( port res )
2230 \ ---- Standard Library ---- {{{
2232 include scheme-primitives.4th
2234 init-object-stack-base
2235 s" scheme-library.scm" load 2drop
2241 ( REPL calls REPL-BODY in a loop until repl-body returns true. )
2242 : repl-body ( -- bool )
2243 cr bold fg green ." > " reset-term
2247 2dup EOF character-type objeq? if
2249 bold fg blue ." Moriturus te saluto." reset-term cr
2253 global-env obj@ eval
2255 fg cyan ." ; " print reset-term
2263 init-object-stack-base
2265 \ Display welcome message
2266 welcome-symbol nil cons global-env obj@ eval 2drop
2271 recoverable-exception of false endof
2272 unrecoverable-exception of true endof