Implemented let*
[scheme.forth.jl.git] / src / scheme.4th
1 vocabulary scheme
2 scheme definitions
3
4 include term-colours.4th
5 include defer-is.4th
6 include catch-throw.4th
7 include integer.4th
8 include float.4th
9
10 include debugging.4th
11
12 defer read
13 defer eval
14 defer print
15
16 defer collect-garbage
17
18 \ ---- Types ---- {{{
19
20 variable nexttype
21 0 nexttype !
22 : make-type
23     create nexttype @ ,
24     1 nexttype +!
25     does> @ ;
26
27 make-type fixnum-type
28 make-type flonum-type
29 make-type ratnum-type
30 make-type boolean-type
31 make-type character-type
32 make-type string-type
33 make-type nil-type
34 make-type none-type
35 make-type pair-type
36 make-type symbol-type
37 make-type primitive-proc-type
38 make-type compound-proc-type
39 make-type port-type
40 : istype? ( obj type -- obj bool )
41     over = ;
42
43 \ }}}
44
45 \ ---- Exceptions ---- {{{
46
47 variable nextexception
48 1 nextexception !
49 : make-exception 
50     create nextexception @ ,
51     1 nextexception +!
52     does> @ ;
53
54 : except-message:
55     bold fg red
56     ." Exception: "
57 ;
58
59 make-exception recoverable-exception
60 make-exception unrecoverable-exception
61
62 : throw reset-term throw ;
63
64 \ }}}
65
66 \ ---- List-structured memory ---- {{{
67
68 20000 constant scheme-memsize
69
70 create car-cells scheme-memsize allot
71 create car-type-cells scheme-memsize allot
72 create cdr-cells scheme-memsize allot
73 create cdr-type-cells scheme-memsize allot
74
75 create nextfrees scheme-memsize allot
76 :noname
77     scheme-memsize 0 do
78         i 1+ nextfrees i + !
79     loop
80 ; execute
81         
82 variable nextfree
83 0 nextfree !
84
85 : inc-nextfree
86     nextfrees nextfree @ + @
87     nextfree !
88
89     nextfree @ scheme-memsize >= if
90         collect-garbage
91     then
92
93     nextfree @ scheme-memsize >= if
94         except-message: ." Out of memory!" unrecoverable-exception throw
95     then
96 ;
97
98 : cons ( car-obj cdr-obj -- pair-obj )
99     cdr-type-cells nextfree @ + !
100     cdr-cells nextfree @ + !
101     car-type-cells nextfree @ + !
102     car-cells nextfree @ + !
103
104     nextfree @ pair-type
105     inc-nextfree
106 ;
107
108 : car ( pair-obj -- car-obj )
109     drop
110     dup car-cells + @ swap
111     car-type-cells + @
112 ;
113
114 : cdr ( pair-obj -- car-obj )
115     drop
116     dup cdr-cells + @ swap
117     cdr-type-cells + @
118 ;
119
120 : set-car! ( obj pair-obj -- )
121     drop dup
122     rot swap  car-type-cells + !
123     car-cells + !
124 ;
125
126 : set-cdr! ( obj pair-obj -- )
127     drop dup
128     rot swap  cdr-type-cells + !
129     cdr-cells + !
130 ;
131
132 : nil 0 nil-type ;
133 : nil? nil-type istype? ;
134
135 : none 0 none-type ;
136 : none? none-type istype? ;
137
138 : objvar create nil swap , , ;
139
140 : value@ ( objvar -- val ) @ ;
141 : type@ ( objvar -- type ) 1+ @ ;
142 : value! ( newval objvar -- ) ! ;
143 : type! ( newtype objvar -- ) 1+ ! ;
144 : obj! ( newobj objvar -- ) dup rot swap 1+ ! ! ; 
145 : obj@ ( objvar -- obj ) dup @ swap 1+ @ ; 
146
147 : objeq? ( obj obj -- bool )
148     rot = -rot = and ;
149
150 : 2rot ( a1 a2 b1 b2 c1 c2 -- b1 b2 c1 c2 a1 a2 )
151     >R >R ( a1 a2 b1 b2 )
152     2swap ( b1 b2 a1 a2 )
153     R> R> ( b1 b2 a1 a2 c1 c2 )
154     2swap
155 ;
156
157 : -2rot ( a1 a2 b1 b2 c1 c2 -- c1 c2 a1 a2 b1 b2 )
158     2swap ( a1 a2 c1 c2 b1 b2 )
159     >R >R ( a1 a2 c1 c2 )
160     2swap ( c1 c2 a1 a2 )
161     R> R>
162 ;
163
164 \ }}}
165
166 \ ---- Pre-defined symbols ---- {{{
167
168 objvar symbol-table
169
170 : duplicate-charlist ( charlist -- copy )
171     nil? false = if
172         2dup car 2swap cdr recurse cons
173     then ;
174
175 : charlist-equiv ( charlist charlist -- bool )
176
177     2over 2over
178
179     \ One or both nil
180     nil? -rot 2drop
181     if
182         nil? -rot 2drop
183         if
184             2drop 2drop true exit
185         else
186             2drop 2drop false exit
187         then
188     else
189         nil? -rot 2drop
190         if
191             2drop 2drop false exit
192         then
193     then
194
195     2over 2over
196
197     \ Neither nil
198     car drop -rot car drop = if
199             cdr 2swap cdr recurse
200         else
201             2drop 2drop false
202     then
203 ;
204
205 : charlist>symbol ( charlist -- symbol-obj )
206
207     symbol-table obj@
208
209     begin
210         nil? false =
211     while
212         2over 2over
213         car drop pair-type
214         charlist-equiv if
215             2swap 2drop
216             car
217             exit
218         else
219             cdr
220         then
221     repeat
222
223     2drop
224     drop symbol-type 2dup
225     symbol-table obj@ cons
226     symbol-table obj!
227 ;
228
229
230 : cstr>charlist ( addr n -- charlist )
231     dup 0= if
232         2drop nil
233     else
234         2dup drop @ character-type 2swap
235         swap 1+ swap 1-
236         recurse
237
238         cons
239     then
240 ;
241
242 : create-symbol ( -- )
243     bl word
244     count
245
246     cstr>charlist
247     charlist>symbol
248
249     create swap , ,
250     does> dup @ swap 1+ @
251 ;
252
253 create-symbol quote             quote-symbol
254 create-symbol quasiquote        quasiquote-symbol
255 create-symbol unquote           unquote-symbol
256 create-symbol unquote-splicing  unquote-splicing-symbol
257 create-symbol define            define-symbol
258 create-symbol define-macro      define-macro-symbol
259 create-symbol set!              set!-symbol
260 create-symbol ok                ok-symbol
261 create-symbol if                if-symbol
262 create-symbol lambda            lambda-symbol
263 create-symbol Î»                 Î»-symbol
264 create-symbol begin             begin-symbol
265 create-symbol eof               eof-symbol
266
267 \ Symbol to be bound to welcome message procedure by library
268 create-symbol welcome           welcome-symbol
269
270 \ }}}
271
272 \ ---- Port I/O ----  {{{
273
274 ( Ports are pairs with the fid in the car and the peek buffer in the cdr. )
275
276 : fileport>fid ( fileport -- fid )
277     drop pair-type car drop ;
278
279 : get-last-peek ( fileport -- char/nil )
280     drop pair-type cdr ;
281
282 : set-last-peek ( char/nil fileport -- )
283     drop pair-type set-cdr!
284 ;
285
286 : fid>fileport ( fid -- fileport )
287     fixnum-type nil cons drop port-type ;
288
289 : open-input-file ( addr n -- fileport )
290     r/o open-file drop fid>fileport
291 ;
292
293 : close-port ( fileport -- )
294     fileport>fid close-file drop
295 ;
296
297 objvar console-i/o-port
298 0 fixnum-type nil cons drop port-type console-i/o-port obj!
299
300 objvar current-input-port
301 console-i/o-port obj@ current-input-port obj!
302
303 : read-char ( port -- char ) 
304     2dup get-last-peek nil? if
305         2drop
306         2dup console-i/o-port obj@ objeq? if
307             2drop
308             key character-type
309         else
310             fileport>fid pad 1 rot read-file 0= if
311                 eof-symbol
312             else
313                 pad @ character-type
314             then
315         then
316     else
317         nil 2rot set-cdr!
318     then
319 ;
320
321 : peek-char ( port -- char )
322     2dup get-last-peek nil? if
323         2drop 2dup read-char
324         2dup 2rot set-last-peek
325     else
326         2swap 2drop
327     then
328 ;
329
330 variable read-line-buffer-span
331 variable read-line-buffer-offset
332
333 ( Hack to save original read-line while we transition to new one. )
334 : orig-read-line immediate
335     ['] read-line , ;
336
337 : read-line ( port -- string )
338
339     2dup get-last-peek
340     nil? if
341         2drop
342         0 read-line-buffer-offset !
343     else
344         2over nil 2swap set-last-peek
345         2dup drop '\n' = if
346             2drop nil nil cons exit
347         else
348             drop pad !
349             1 read-line-buffer-offset !
350         then
351     then
352
353     2dup console-i/o-port obj@ objeq? if
354         2drop
355         pad read-line-buffer-offset @ + 200 expect cr
356         span @ read-line-buffer-offset @ + read-line-buffer-span !
357     else
358         pad read-line-buffer-offset @ + 200 2over fileport>fid orig-read-line
359         drop swap read-line-buffer-offset @ + read-line-buffer-span !
360     then
361
362     nil
363     
364     begin
365         read-line-buffer-span @ 0>
366     while
367         pad read-line-buffer-span @ 1- + @ character-type 2swap cons
368         -1 read-line-buffer-span +!
369     repeat
370
371     nil? if
372         nil cons drop string-type
373     else
374         drop string-type
375     then
376 ;
377
378 : read-port ( fileport -- obj )
379     current-input-port obj!
380     read ;
381
382 : read-console ( -- obj )
383     console-i/o-port obj@ read-port ;
384
385 \ }}}
386
387 \ ---- Environments ---- {{{
388
389 : enclosing-env ( env -- env )
390     cdr ;
391
392 : first-frame ( env -- frame )
393     car ;
394
395 : make-frame ( vars vals -- frame )
396     cons ;
397
398 : frame-vars ( frame -- vars )
399     car ;
400
401 : frame-vals ( frame -- vals )
402     cdr ;
403
404 : add-binding ( var val frame -- )
405     2swap 2over frame-vals cons
406     2over set-cdr!
407     2swap 2over frame-vars cons
408     2swap set-car!
409 ;
410
411 : extend-env ( vars vals env -- env )
412     >R >R
413     make-frame
414     R> R>
415     cons
416 ;
417
418 objvar vars
419 objvar vals
420
421 : get-vars-vals-frame ( var frame -- bool )
422     2dup frame-vars vars obj!
423     frame-vals vals obj!
424
425     begin
426         vars obj@ nil objeq? false =
427     while
428         2dup vars obj@ car objeq? if
429             2drop true
430             exit
431         then
432
433         vars obj@ cdr vars obj!
434         vals obj@ cdr vals obj!
435     repeat
436
437     2drop false
438 ;
439
440 : get-vars-vals ( var env -- vars? vals? bool )
441
442     begin
443         nil? false =
444     while
445         2over 2over first-frame
446         get-vars-vals-frame if
447             2drop 2drop
448             vars obj@ vals obj@ true
449             exit
450         then
451
452         enclosing-env
453     repeat
454
455     2drop 2drop
456     false
457 ;
458
459 hide vars
460 hide vals
461
462 objvar var
463
464 : lookup-var ( var env -- val )
465     2over var obj!
466     get-vars-vals if
467         2swap 2drop car
468     else
469         except-message: ." tried to read unbound variable '" var obj@ print ." '." recoverable-exception  throw
470     then
471 ;
472
473 : set-var ( var val env -- )
474     >R >R 2swap R> R> ( val var env )
475     2over var obj!
476     get-vars-vals if
477         2swap 2drop ( val vals )
478         set-car!
479     else
480         except-message: ." tried to set unbound variable '" var obj@ print ." '." recoverable-exception throw
481     then
482 ;
483
484 hide var
485
486 objvar env
487
488 : define-var ( var val env -- )
489     env obj! 
490
491     2over env obj@ ( var val var env )
492     get-vars-vals if
493         2swap 2drop ( var val vals )
494         set-car!
495         2drop
496     else
497         env obj@
498         first-frame ( var val frame )
499         add-binding
500     then
501 ;
502
503 hide env
504
505 : make-procedure ( params body env -- proc )
506     nil
507     cons cons cons
508     drop compound-proc-type
509 ;
510
511 objvar global-env
512 nil nil nil extend-env
513 global-env obj!
514
515 \ }}}
516
517 \ ---- Primitives ---- {{{
518
519 : make-primitive ( cfa -- )
520     bl word
521     count
522
523     cstr>charlist
524     charlist>symbol
525   
526     rot primitive-proc-type ( var prim )
527     global-env obj@ define-var
528 ;
529
530 : ensure-arg-count ( args n -- )
531     dup 0= if
532         drop nil objeq? false = if
533             except-message: ." Too many arguments for primitive procedure." recoverable-exception throw
534         then
535     else
536         -rot nil? if
537             except-message: ." Too few arguments for primitive procedure." recoverable-exception  throw
538         then
539         
540         cdr rot 1- recurse
541     then
542 ;
543
544 : ensure-arg-type-and-count ( tn tn-1 ... t2 t1 args n -- )
545     dup 0= if
546         drop nil objeq? false = if
547             except-message: ." Too many arguments for primitive procedure." recoverable-exception throw
548         then
549     else
550         -rot nil? if
551             except-message: ." Too few arguments for primitive procedure." recoverable-exception throw
552         then
553
554         2dup cdr 2swap car ( ... t1 n args' arg1 )
555         2rot 1- swap 2swap rot ( ... args' n-1 arg1 t1 )
556         istype? false = if
557             except-message: ." Incorrect type for primitive procedure." recoverable-exception throw
558         then
559
560         2drop recurse
561     then
562
563 ;
564
565 : push-args-to-stack ( args -- arg1 arg2 ... argn )
566     begin
567         nil? false =
568     while
569         2dup car 2swap cdr
570     repeat
571
572     2drop
573 ;
574
575 : add-fa-checks ( cfa n -- cfa' )
576     here current @ 1+ dup @ , !
577     0 ,
578     here -rot
579     docol ,
580     ['] 2dup , ['] lit , , ['] ensure-arg-count ,
581     ['] push-args-to-stack ,
582     ['] lit , , ['] execute ,
583     ['] exit ,
584 ;
585
586 : add-fa-type-checks ( cfa t1 t2 ... tn n -- cfa' )
587     here current @ 1+ dup @ , !
588     0 ,
589     here >R
590     docol ,
591     ['] 2dup ,
592     ['] >R , ['] >R ,
593
594     dup ( cfa t1 t2 ... tn n m )
595     
596     begin
597         ?dup 0>
598     while
599         rot ['] lit , , ( cfa t1 t2 ... tn-1 n m )
600         1-
601     repeat
602
603     ['] R> , ['] R> ,
604
605     ['] lit , , ['] ensure-arg-type-and-count ,
606
607     ['] push-args-to-stack ,
608     ['] lit , , ['] execute ,
609     ['] exit ,
610
611     R>
612 ;
613
614 : make-fa-primitive ( cfa n -- )
615     add-fa-checks make-primitive ;
616
617 : make-fa-type-primitive ( cfa t1 t2 ... tn n -- )
618     add-fa-type-checks make-primitive ;
619
620 : arg-type-error
621             bold fg red ." Incorrect argument type." reset-term cr
622             abort
623 ;
624
625 : ensure-arg-type ( arg type -- arg )
626     istype? false = if
627         except-message: ." Incorrect argument type for primitive procedure." recoverable-exception throw
628     then
629 ;
630
631
632 \ }}}
633
634 \ ---- Macros ---- {{{
635
636 objvar macro-table
637
638 ( Look up macro in macro table. Returns nil if
639   no macro is found. )
640 : lookup-macro ( name_symbol -- proc )
641
642     symbol-type istype? invert if
643         \ Early exit if argument is not a symbol
644         2drop nil exit
645     then
646     
647     macro-table obj@
648
649     begin
650         nil? false =
651     while
652         2over 2over
653         car car objeq? if
654             2swap 2drop
655             car cdr
656             exit
657         then
658
659         cdr
660     repeat
661
662     2swap 2drop
663 ;
664
665 : make-macro ( name_symbol params body env -- )
666     make-procedure
667
668     2swap ( proc name_symbol )
669
670     macro-table obj@
671
672     begin
673         nil? false =
674     while
675         2over 2over ( proc name table name table )
676         car car objeq? if
677             2swap 2drop ( proc table )
678             car ( proc entry )
679             set-cdr!
680             exit
681         then
682
683         cdr
684     repeat
685
686     2drop
687
688     2swap cons
689     macro-table obj@ cons
690     macro-table obj!
691 ;
692
693 \ }}}
694
695 \ ---- Read ---- {{{
696
697 variable parse-idx
698 variable stored-parse-idx
699 create parse-str 161 allot
700 variable parse-str-span
701
702 create parse-idx-stack 10 allot 
703 variable parse-idx-sp
704 parse-idx-stack parse-idx-sp !
705
706 : push-parse-idx
707     parse-idx @ parse-idx-sp @ !
708     1 parse-idx-sp +!
709 ;
710
711 : pop-parse-idx
712     parse-idx-sp @ parse-idx-stack <= abort" Parse index stack underflow."
713
714     1 parse-idx-sp -!
715
716     parse-idx-sp @ @ parse-idx ! ;
717
718
719 : append-newline
720     '\n' parse-str parse-str-span @ + !
721     1 parse-str-span +! ;
722
723 : append-eof
724     4 parse-str parse-str-span @ + !
725     1 parse-str-span +!  ;
726
727 : empty-parse-str
728     0 parse-str-span !
729     0 parse-idx ! ;
730
731 : getline
732     current-input-port obj@ console-i/o-port obj@ objeq? if
733         parse-str 160 expect cr
734         span @ parse-str-span !
735     else
736         parse-str 160 current-input-port obj@ fileport>fid orig-read-line
737         drop swap parse-str-span !
738
739         parse-str-span @ 0= and if append-eof then
740     then
741     append-newline
742     0 parse-idx ! ;
743
744 : inc-parse-idx
745     1 parse-idx +! ;
746
747 : dec-parse-idx
748     1 parse-idx -! ;
749
750 : charavailable? ( -- bool )
751     parse-str-span @ parse-idx @ > ;
752
753 : nextchar ( -- char )
754     charavailable? false = if getline then
755     parse-str parse-idx @ + @ ;
756
757 : '\t' 9 ;
758 : whitespace? ( -- bool )
759     nextchar BL = 
760     nextchar '\n' =
761     nextchar '\t' =
762     or or ;
763
764 : EOF 4 ; 
765 : eof? ( -- bool )
766     nextchar EOF = ;
767
768 : delim? ( -- bool )
769     whitespace?
770     nextchar [char] ( = or
771     nextchar [char] ) = or
772 ;
773
774 : commentstart? ( -- bool )
775     nextchar [char] ; = ;
776
777 : eatspaces
778
779     false \ Indicates whether or not we're eating a comment
780
781     begin
782         dup whitespace? or commentstart? or
783     while
784         dup nextchar '\n' = and if
785             invert \ Stop eating comment
786         else
787             dup false = commentstart? and if   
788                 invert \ Begin eating comment
789             then
790         then
791
792         inc-parse-idx
793     repeat
794     drop
795 ;
796
797 : digit? ( -- bool )
798     nextchar [char] 0 >=
799     nextchar [char] 9 <=
800     and ;
801
802 : minus? ( -- bool )
803     nextchar [char] - = ;
804
805 : plus? ( -- bool )
806     nextchar [char] + = ;
807
808 : fixnum? ( -- bool )
809     minus? plus? or if
810         inc-parse-idx
811
812         delim? if
813             dec-parse-idx
814             false exit
815         else
816             dec-parse-idx
817         then
818     else
819         digit? false = if
820             false exit
821         then
822     then
823
824     push-parse-idx
825     inc-parse-idx
826
827     begin digit? while
828         inc-parse-idx
829     repeat
830
831     delim? pop-parse-idx
832 ;
833
834 : flonum? ( -- bool )
835     push-parse-idx
836
837     minus? plus? or if
838         inc-parse-idx
839     then
840
841     \ Record starting parse idx:
842     \ Want to detect whether any characters (following +/-) were eaten.
843     parse-idx @
844
845     begin digit? while
846             inc-parse-idx
847     repeat
848
849     [char] . nextchar = if
850         inc-parse-idx
851         begin digit? while
852                 inc-parse-idx
853         repeat
854     then
855
856     [char] e nextchar = [char] E nextchar = or if
857         inc-parse-idx
858
859         minus? plus? or if
860             inc-parse-idx
861         then
862
863         digit? invert if
864             drop pop-parse-idx false exit
865         then
866
867         begin digit? while
868                 inc-parse-idx
869         repeat
870     then
871
872     \ This is a real number if characters were
873     \ eaten and the next characer is a delimiter.
874     parse-idx @ < delim? and
875
876     pop-parse-idx
877 ;
878
879 : ratnum? ( -- bool )
880     push-parse-idx
881
882     minus? plus? or if
883         inc-parse-idx
884     then
885
886     digit? invert if
887         pop-parse-idx false exit
888     else
889         inc-parse-idx
890     then
891
892     begin digit? while
893         inc-parse-idx
894     repeat
895
896     [char] / nextchar <> if
897         pop-parse-idx false exit
898     else
899         inc-parse-idx
900     then
901
902     digit? invert if
903         pop-parse-idx false exit
904     else
905         inc-parse-idx
906     then
907
908     begin digit? while
909         inc-parse-idx
910     repeat
911
912     delim? pop-parse-idx
913 ;
914
915 : boolean? ( -- bool )
916     nextchar [char] # <> if false exit then
917
918     push-parse-idx
919     inc-parse-idx
920
921     nextchar [char] t <>
922     nextchar [char] f <>
923     and if pop-parse-idx false exit then
924
925     inc-parse-idx
926     delim? if
927         pop-parse-idx
928         true
929     else
930         pop-parse-idx
931         false
932     then
933 ;
934
935 : str-equiv? ( str -- bool )
936
937     push-parse-idx
938
939     true -rot
940
941     swap dup rot + swap
942
943     do
944         i @ nextchar <> if
945             drop false
946             leave
947         then
948
949         inc-parse-idx
950     loop
951
952     delim? false = if drop false then
953
954     pop-parse-idx
955 ;
956
957 : character? ( -- bool )
958     nextchar [char] # <> if false exit then
959
960     push-parse-idx
961     inc-parse-idx
962
963     nextchar [char] \ <> if pop-parse-idx false exit then
964
965     inc-parse-idx
966
967     S" newline" str-equiv? if pop-parse-idx true exit then
968     S" space" str-equiv? if pop-parse-idx true exit then
969     S" tab" str-equiv? if pop-parse-idx true exit then
970
971     charavailable? false = if pop-parse-idx false exit then
972
973     pop-parse-idx true
974 ;
975
976 : pair? ( -- bool )
977     nextchar [char] ( = ;
978
979 : string? ( -- bool )
980     nextchar [char] " = ;
981
982 : readfixnum ( -- fixnum )
983     plus? minus? or if
984         minus?
985         inc-parse-idx
986     else
987         false
988     then
989
990     0
991
992     begin digit? while
993         10 * nextchar [char] 0 - +
994         inc-parse-idx
995     repeat
996
997     swap if negate then
998
999     fixnum-type
1000 ;
1001
1002 : readflonum ( -- flonum )
1003     readfixnum drop
1004     dup 0< swap abs i->f
1005
1006     [char] . nextchar = if
1007         inc-parse-idx
1008
1009         10.0 ( f exp )
1010
1011         begin digit? while
1012             nextchar [char] 0 - i->f ( f exp d )
1013             over f/ rot f+ ( exp f' )
1014             swap 10.0 f* ( f' exp' )
1015             inc-parse-idx
1016         repeat
1017
1018         drop
1019     then
1020
1021     [char] e nextchar = [char] E nextchar = or if
1022         inc-parse-idx
1023         10.0
1024         readfixnum drop i->f
1025         f^ f*
1026     then
1027
1028     swap if
1029         -1.0 f*
1030     then
1031
1032     flonum-type
1033 ;
1034
1035 : make-rational ( fixnum fixnum -- ratnum|fixnum )
1036     drop swap drop
1037     simplify
1038
1039     dup 1 = if
1040         drop fixnum-type
1041     else
1042         fixnum-type swap fixnum-type
1043         cons drop ratnum-type
1044     then
1045 ;
1046
1047 : readratnum ( -- ratnum )
1048     readfixnum inc-parse-idx readfixnum
1049     make-rational
1050 ;
1051
1052 : readbool ( -- bool-obj )
1053     inc-parse-idx
1054     
1055     nextchar [char] f = if
1056         false
1057     else
1058         true
1059     then
1060
1061     inc-parse-idx
1062
1063     boolean-type
1064 ;
1065
1066 : readchar ( -- char-obj )
1067     inc-parse-idx
1068     inc-parse-idx
1069
1070     S" newline" str-equiv? if 7 parse-idx +! '\n' character-type exit then
1071     S" space" str-equiv? if 5 parse-idx +! bl character-type exit then
1072     S" tab" str-equiv? if 3 parse-idx +! 9 character-type exit then
1073
1074     nextchar character-type
1075
1076     inc-parse-idx
1077 ;
1078
1079 : readstring ( -- charlist )
1080
1081     nil nil
1082
1083     begin
1084         nextchar [char] " <>
1085     while
1086         nextchar [char] \ = if
1087             inc-parse-idx
1088             nextchar case
1089                 [char] n of '\n' endof
1090                 [char] " of [char] " endof
1091                 [char] \
1092             endcase
1093         else
1094             nextchar
1095         then
1096         inc-parse-idx character-type
1097         nil cons
1098
1099         ( firstchar prevchar thischar )
1100
1101         2swap nil? if
1102             2drop 2swap 2drop 2dup  ( thischar thischar )
1103         else
1104             ( firstchar thischar prevchar )
1105             2over 2swap  set-cdr! ( firstchar thischar )
1106         then
1107     repeat
1108
1109     \ Discard previous character
1110     2drop
1111
1112     inc-parse-idx
1113     delim? false = if
1114         bold fg red
1115         ." No delimiter following right double quote. Aborting." cr
1116         reset-term abort
1117     then
1118
1119     dec-parse-idx
1120
1121     nil? if
1122         nil cons
1123     then
1124     drop string-type
1125 ;
1126
1127 : readsymbol ( -- charlist )
1128     delim? if nil exit then
1129
1130     nextchar inc-parse-idx character-type
1131
1132     recurse
1133
1134     cons
1135 ;
1136
1137 : readpair ( -- pairobj )
1138     eatspaces
1139
1140     \ Empty lists
1141     nextchar [char] ) = if
1142         inc-parse-idx
1143
1144         delim? false = if
1145             bold fg red
1146             ." No delimiter following right paren. Aborting." cr
1147             reset-term abort
1148         then
1149
1150         dec-parse-idx
1151
1152         0 nil-type exit
1153     then
1154
1155     \ Read first pair element
1156     read
1157
1158     \ Pairs
1159     eatspaces
1160     nextchar [char] . = if
1161         inc-parse-idx
1162
1163         delim? false = if
1164             bold fg red
1165             ." No delimiter following '.'. Aborting." cr
1166             reset-term abort
1167         then
1168
1169         eatspaces read
1170     else
1171         recurse
1172     then
1173
1174     eatspaces
1175
1176     cons
1177 ;
1178
1179 \ Parse a scheme expression
1180 :noname ( -- obj )
1181
1182     eatspaces
1183
1184     fixnum? if
1185         readfixnum
1186         exit
1187     then
1188
1189     flonum? if
1190         readflonum
1191         exit
1192     then
1193
1194     ratnum? if
1195         readratnum
1196         exit
1197     then
1198
1199     boolean? if
1200         readbool
1201         exit
1202     then
1203
1204     character? if
1205         readchar
1206         exit
1207     then
1208
1209     string? if
1210         inc-parse-idx
1211
1212         readstring
1213
1214         nextchar [char] " <> if
1215             bold red ." Missing closing double-quote." reset-term cr
1216             abort
1217         then
1218
1219         inc-parse-idx
1220
1221         exit
1222     then
1223
1224     pair? if
1225         inc-parse-idx
1226
1227         eatspaces
1228
1229         readpair
1230
1231         eatspaces
1232
1233         nextchar [char] ) <> if
1234             bold red ." Missing closing paren." reset-term cr
1235             abort
1236         then
1237
1238         inc-parse-idx
1239
1240         exit
1241     then
1242
1243     nextchar [char] ' = if
1244         inc-parse-idx
1245         quote-symbol recurse nil cons cons exit
1246     then
1247
1248     nextchar [char] ` = if
1249         inc-parse-idx
1250         quasiquote-symbol recurse nil cons cons exit
1251     then
1252
1253     nextchar [char] , = if
1254         inc-parse-idx
1255         nextchar [char] @ = if
1256             inc-parse-idx
1257             unquote-splicing-symbol recurse nil cons cons exit
1258         else
1259             unquote-symbol recurse nil cons cons exit
1260         then
1261     then
1262
1263     eof? if
1264         EOF character-type
1265         inc-parse-idx
1266         exit
1267     then
1268
1269     \ Anything else is parsed as a symbol
1270     readsymbol charlist>symbol
1271
1272     \ Replace Î» with lambda
1273     2dup Î»-symbol objeq? if
1274         2drop lambda-symbol
1275     then
1276     
1277
1278 ; is read
1279
1280 \ }}}
1281
1282 \ ---- Eval ---- {{{
1283
1284 : self-evaluating? ( obj -- obj bool )
1285     boolean-type istype? if true exit then
1286     fixnum-type istype? if true exit then
1287     flonum-type istype? if true exit then
1288     ratnum-type istype? if true exit then
1289     character-type istype? if true exit then
1290     string-type istype? if true exit then
1291     nil-type istype? if true exit then
1292     none-type istype? if true exit then
1293
1294     false
1295 ;
1296
1297 : tagged-list? ( obj tag-obj -- obj bool )
1298     2over 
1299     pair-type istype? false = if
1300         2drop 2drop false
1301     else
1302         car objeq?
1303     then ;
1304
1305 : quote? ( obj -- obj bool )
1306     quote-symbol tagged-list?  ;
1307
1308 : quote-body ( quote-obj -- quote-body-obj )
1309     cdr car ;
1310
1311 : quasiquote? ( obj -- obj bool )
1312     quasiquote-symbol tagged-list? ;
1313
1314 : unquote? ( obj -- obj bool )
1315     unquote-symbol tagged-list? ;
1316
1317 : unquote-splicing? ( obj -- obj bool )
1318     unquote-splicing-symbol tagged-list? ;
1319
1320 : eval-unquote ( env obj -- res )
1321     cdr ( env args )
1322
1323     nil? if
1324         except-message: ." no arguments to unquote." recoverable-exception throw
1325     then
1326
1327     2dup cdr
1328     nil? false = if
1329         except-message: ." too many arguments to unquote." recoverable-exception throw
1330     then
1331
1332     2drop car 2swap eval
1333 ;
1334
1335 ( Create a new list from elements of l1 consed on to l2 )
1336 : join-lists ( l2 l1 -- l3 )
1337     nil? if 2drop exit then
1338
1339     2dup car
1340     -2rot cdr
1341     recurse cons
1342 ;
1343
1344 defer eval-quasiquote-item
1345 : eval-quasiquote-pair ( env obj -- res )
1346     2over 2over ( env obj env obj )
1347
1348     cdr eval-quasiquote-item
1349
1350     -2rot car ( cdritem env objcar )
1351
1352     unquote-splicing? if
1353         eval-unquote ( cdritems caritem )
1354
1355         2swap nil? if
1356             2drop
1357         else
1358             2swap join-lists
1359         then
1360     else
1361         eval-quasiquote-item ( cdritems caritem )
1362         2swap cons
1363     then
1364
1365 ;
1366
1367 :noname ( env obj )
1368     nil? if
1369         2swap 2drop exit
1370     then
1371
1372     unquote? if
1373         eval-unquote exit
1374     then
1375
1376     pair-type istype? if
1377         eval-quasiquote-pair exit
1378     then
1379
1380     2swap 2drop
1381 ; is eval-quasiquote-item
1382
1383 : eval-quasiquote ( obj env -- res )
1384     2swap cdr ( env args )
1385
1386     nil? if
1387         except-message: ." no arguments to quasiquote." recoverable-exception throw
1388     then
1389
1390     2dup cdr ( env args args-cdr )
1391     nil? false = if
1392         except-message: ." too many arguments to quasiquote." recoverable-exception throw
1393     then
1394
1395     2drop car ( env arg )
1396
1397     eval-quasiquote-item
1398 ;
1399
1400 : variable? ( obj -- obj bool )
1401     symbol-type istype? ;
1402
1403 : definition? ( obj -- obj bool )
1404     define-symbol tagged-list? ;
1405
1406 : make-lambda ( params body -- lambda-exp )
1407     lambda-symbol -2rot cons cons ;
1408
1409 ( Handles iterative expansion of defines in
1410   terms of nested lambdas. Most Schemes only
1411   handle one iteration of expansion! )
1412 : definition-var-val ( obj -- var val )
1413
1414     cdr 2dup cdr 2swap car ( val var )
1415
1416     begin
1417         symbol-type istype? false =
1418     while
1419         2dup cdr 2swap car ( val formals var' )
1420         -2rot 2swap ( var' formals val )
1421         make-lambda nil cons ( var' val' )
1422         2swap ( val' var' )
1423     repeat
1424
1425     2swap car
1426 ;
1427
1428 : eval-definition ( obj env -- res )
1429     2dup 2rot ( env env obj )
1430     definition-var-val ( env env var val )
1431     2rot eval  ( env var val )
1432
1433     2rot ( var val env )
1434     define-var
1435
1436     ok-symbol
1437 ;
1438
1439 : assignment? ( obj -- obj bool )
1440     set!-symbol tagged-list? ;
1441
1442 : assignment-var ( obj -- var )
1443     cdr car ;
1444     
1445 : assignment-val ( obj -- val )
1446     cdr cdr car ;
1447
1448 : eval-assignment ( obj env -- res )
1449     2swap 
1450     2over 2over ( env obj env obj )
1451     assignment-val 2swap ( env obj valexp env )
1452     eval  ( env obj val )
1453     
1454     2swap assignment-var 2swap ( env var val )
1455
1456     2rot ( var val env )
1457     set-var
1458
1459     ok-symbol
1460 ;
1461
1462 : macro-definition? ( obj -- obj bool )
1463     define-macro-symbol tagged-list? ;
1464
1465 : macro-definition-name ( exp -- mname )
1466     cdr car car ;
1467
1468 : macro-definition-params ( exp -- params )
1469     cdr car cdr ;
1470
1471 : macro-definition-body ( exp -- body )
1472     cdr cdr ;
1473
1474 objvar env
1475 : eval-define-macro ( obj env -- res )
1476     env obj!
1477
1478     2dup macro-definition-name 2swap ( name obj )
1479     2dup macro-definition-params 2swap ( name params obj )
1480     macro-definition-body ( name params body )
1481
1482     env obj@ ( name params body env )
1483
1484     make-macro
1485
1486     ok-symbol
1487 ;
1488 hide env
1489
1490 : if? ( obj -- obj bool )
1491     if-symbol tagged-list? ;
1492
1493 : if-predicate ( ifobj -- pred )
1494     cdr car ;
1495
1496 : if-consequent ( ifobj -- conseq )
1497     cdr cdr car ;
1498
1499 : if-alternative ( ifobj -- alt|none )
1500     cdr cdr cdr
1501     nil? if
1502         2drop none
1503     else
1504         car
1505     then ;
1506
1507 : false? ( boolobj -- boolean )
1508     boolean-type istype? if
1509         false boolean-type objeq?
1510     else
1511         2drop false
1512     then
1513 ;
1514
1515 : true? ( boolobj -- bool )
1516     false? invert ;
1517
1518 : lambda? ( obj -- obj bool )
1519     lambda-symbol tagged-list? ;
1520
1521 : lambda-parameters ( obj -- params )
1522     cdr car ;
1523
1524 : lambda-body ( obj -- body )
1525     cdr cdr ;
1526
1527 : begin? ( obj -- obj bool )
1528     begin-symbol tagged-list? ;
1529
1530 : begin-actions ( obj -- actions )
1531     cdr ;
1532
1533 : eval-sequence ( explist env -- finalexp env )
1534     ( Evaluates all bar the final expressions in
1535       an an expression list. The final expression
1536       is returned to allow for tail optimization. )
1537
1538     2swap ( env explist )
1539
1540     \ Abort on empty list
1541     nil? if
1542         2drop none
1543         2swap exit
1544     then
1545
1546     begin
1547         2dup cdr ( env explist nextexplist )
1548         nil? false =
1549     while
1550         -2rot car 2over ( nextexplist env exp env )
1551         eval
1552         2drop \ discard result
1553         2swap ( env nextexplist )
1554     repeat
1555
1556     2drop car 2swap ( finalexp env )
1557 ;
1558
1559 : application? ( obj -- obj bool )
1560     pair-type istype? ;
1561
1562 : operator ( obj -- operator )
1563     car ;
1564
1565 : operands ( obj -- operands )
1566     cdr ;
1567
1568 : nooperands? ( operands -- bool )
1569     nil objeq? ;
1570
1571 : first-operand ( operands -- operand )
1572     car ;
1573
1574 : rest-operands ( operands -- other-operands )
1575     cdr ;
1576
1577 : list-of-vals ( args env -- vals )
1578     2swap
1579
1580     2dup nooperands? if
1581         2swap 2drop
1582     else
1583         2over 2over first-operand 2swap eval
1584         -2rot rest-operands 2swap recurse
1585         cons
1586     then
1587 ;
1588
1589 : procedure-params ( proc -- params )
1590     drop pair-type car ;
1591
1592 : procedure-body ( proc -- body )
1593     drop pair-type cdr car ;
1594
1595 : procedure-env ( proc -- body )
1596     drop pair-type cdr cdr car ;
1597
1598 ( Ensure terminating symbol arg name is handled
1599   specially to allow for variadic procedures. )
1600 : flatten-proc-args ( argvals argnames -- argvals' argnames' )
1601     nil? if
1602         2over nil? false = if
1603             except-message: ." Too many arguments for compound procedure." recoverable-exception throw
1604         else
1605             2drop
1606         then
1607         exit
1608     then
1609
1610     symbol-type istype? if
1611         nil cons
1612         2swap
1613         nil cons
1614         2swap
1615         exit
1616     then
1617
1618     2over
1619     nil? if
1620         except-message: ." Too few arguments for compound procedure." recoverable-exception throw
1621     else
1622         cdr
1623     then
1624
1625     2over cdr
1626
1627     recurse ( argvals argnames argvals'' argnames'' )
1628     2rot car 2swap cons  ( argvals argvals'' argnames' )
1629     2rot car 2rot cons ( argnames' argvals' )
1630     2swap
1631 ;
1632
1633 : apply ( proc argvals -- result )
1634         2swap dup case
1635             primitive-proc-type of
1636                 drop execute     
1637             endof
1638
1639             compound-proc-type of
1640                 2dup procedure-body ( argvals proc body )
1641                 -2rot 2dup procedure-params ( body argvals proc argnames )
1642                 -2rot procedure-env ( body argnames argvals procenv )
1643
1644                 -2rot 2swap
1645                 flatten-proc-args
1646                 2swap 2rot
1647
1648                 extend-env ( body env )
1649
1650                 eval-sequence
1651
1652                 R> drop ['] eval goto-deferred  \ Tail call optimization
1653             endof
1654
1655             except-message: ." object '" drop print ." ' not applicable." recoverable-exception throw
1656         endcase
1657 ;
1658
1659 ( Simply evaluates the given procedure with expbody as its argument. )
1660 : macro-expand ( proc expbody -- result )
1661     2swap
1662     2dup procedure-body ( expbody proc procbody )
1663     -2rot 2dup procedure-params ( procbody expbody proc argnames )
1664     -2rot procedure-env ( procbody argnames expbody procenv )
1665     
1666     -2rot 2swap
1667     flatten-proc-args
1668     2swap 2rot
1669
1670     extend-env eval-sequence eval
1671 ;
1672
1673 :noname ( obj env -- result )
1674     2swap
1675
1676     \ --- DEBUG ---
1677     ( 
1678       fg yellow ." Evaluating: " bold 2dup print reset-term
1679       space fg green ." PS: " bold depth . reset-term
1680       space fg blue  ." RS: " bold RSP@ RSP0 - . reset-term cr
1681     )
1682
1683     self-evaluating? if
1684         2swap 2drop
1685         exit
1686     then
1687
1688     quote? if
1689         quote-body
1690         2swap 2drop
1691         exit
1692     then
1693
1694     quasiquote? if
1695         2swap eval-quasiquote
1696         exit
1697     then
1698
1699     variable? if
1700         2swap lookup-var
1701         exit
1702     then
1703
1704     definition? if
1705         2swap eval-definition
1706         exit
1707     then
1708
1709     assignment? if
1710         2swap eval-assignment
1711         exit
1712     then
1713
1714     macro-definition? if
1715         2swap eval-define-macro
1716         exit
1717     then
1718
1719     if? if
1720         2over 2over
1721         if-predicate
1722         2swap eval 
1723
1724         true? if
1725             if-consequent
1726         else
1727             if-alternative
1728         then
1729
1730         2swap
1731         ['] eval goto-deferred
1732     then
1733
1734     lambda? if
1735         2dup lambda-parameters
1736         2swap lambda-body
1737         2rot make-procedure
1738         exit
1739     then
1740
1741     begin? if
1742         begin-actions 2swap
1743         eval-sequence
1744         ['] eval goto-deferred
1745     then
1746
1747     application? if
1748
1749         2over 2over ( env exp env exp )
1750         operator ( env exp env opname )
1751
1752         2dup lookup-macro nil? false = if
1753              \ Macro function evaluation
1754
1755             ( env exp env opname mproc )
1756             2swap 2drop -2rot 2drop cdr ( env mproc body )
1757
1758             macro-expand
1759
1760             2swap
1761             ['] eval goto-deferred
1762         else
1763            \ Regular function application
1764
1765             2drop ( env exp env opname )
1766
1767             2swap eval ( env exp proc )
1768
1769             -2rot ( proc env exp )
1770             operands 2swap ( proc operands env )
1771             list-of-vals ( proc argvals )
1772
1773             apply
1774             exit
1775         then
1776     then
1777
1778     except-message: ." tried to evaluate object with unknown type." recoverable-exception throw
1779 ; is eval
1780
1781 \ }}}
1782
1783 \ ---- Print ---- {{{
1784
1785 : printfixnum ( fixnum -- ) drop 0 .R ;
1786
1787 : printflonum ( flonum -- ) drop f. ;
1788
1789 : printratnum ( ratnum -- )
1790     drop pair-type 2dup
1791     car print ." /" cdr print
1792 ;
1793
1794 : printbool ( bool -- )
1795     drop if
1796         ." #t"
1797     else
1798         ." #f"
1799     then
1800 ;
1801
1802 : printchar ( charobj -- )
1803     drop
1804     case
1805         9 of ." #\tab" endof
1806         bl of ." #\space" endof
1807         '\n' of ." #\newline" endof
1808         
1809         dup ." #\" emit
1810     endcase
1811 ;
1812
1813 : (printstring) ( stringobj -- )
1814     nil? if 2drop exit then
1815
1816     2dup car drop dup
1817     case
1818         '\n' of ." \n" drop endof
1819         [char] \ of ." \\" drop endof
1820         [char] " of [char] \ emit [char] " emit drop endof
1821         emit
1822     endcase
1823
1824     cdr recurse
1825 ;
1826 : printstring ( stringobj -- )
1827     [char] " emit
1828     (printstring)
1829     [char] " emit ;
1830
1831 : printsymbol ( symbolobj -- )
1832     nil-type istype? if 2drop exit then
1833
1834     2dup car drop emit
1835     cdr recurse
1836 ;
1837
1838 : printnil ( nilobj -- )
1839     2drop ." ()" ;
1840
1841 : printpair ( pairobj -- )
1842     2dup
1843     car print
1844     cdr
1845     nil-type istype? if 2drop exit then
1846     pair-type istype? if space recurse exit then
1847     ."  . " print
1848 ;
1849
1850 : printprim ( primobj -- )
1851     2drop ." <primitive procedure>" ;
1852
1853 : printcomp ( primobj -- )
1854     2drop ." <compound procedure>" ;
1855
1856 : printnone ( noneobj -- )
1857     2drop ." Unspecified return value" ;
1858
1859 : printport ( port -- )
1860     2drop ." <port>" ;
1861
1862 :noname ( obj -- )
1863     fixnum-type istype? if printfixnum exit then
1864     flonum-type istype? if printflonum exit then
1865     ratnum-type istype? if printratnum exit then
1866     boolean-type istype? if printbool exit then
1867     character-type istype? if printchar exit then
1868     string-type istype? if printstring exit then
1869     symbol-type istype? if printsymbol exit then
1870     nil-type istype? if printnil exit then
1871     pair-type istype? if ." (" printpair ." )" exit then
1872     primitive-proc-type istype? if printprim exit then
1873     compound-proc-type istype? if printcomp exit then
1874     none-type istype? if printnone exit then
1875     port-type istype? if printport exit then
1876
1877     except-message: ." tried to print object with unknown type." recoverable-exception throw
1878 ; is print
1879
1880 \ }}}
1881
1882 \ ---- Garbage Collection ---- {{{
1883
1884 variable gc-enabled
1885 false gc-enabled !
1886
1887 variable gc-stack-depth
1888
1889 : enable-gc
1890     depth gc-stack-depth !
1891     true gc-enabled ! ;
1892
1893 : disable-gc
1894     false gc-enabled ! ;
1895
1896 : gc-enabled?
1897     gc-enabled @ ;
1898
1899 : pairlike? ( obj -- obj bool )
1900     pair-type istype? if true exit then
1901     string-type istype? if true exit then
1902     symbol-type istype? if true exit then
1903     compound-proc-type istype? if true exit then
1904     port-type istype? if true exit then
1905
1906     false
1907 ;
1908
1909 : pairlike-marked? ( obj -- obj bool )
1910     over nextfrees + @ 0=
1911 ;
1912
1913 : mark-pairlike ( obj -- obj )
1914         over nextfrees + 0 swap !
1915 ;
1916
1917 : gc-unmark ( -- )
1918     scheme-memsize 0 do
1919         1 nextfrees i + !
1920     loop
1921 ;
1922
1923 : gc-mark-obj ( obj -- )
1924
1925     pairlike? invert if 2drop exit then
1926     pairlike-marked? if 2drop exit then
1927
1928     mark-pairlike
1929
1930     drop pair-type 2dup
1931
1932     car recurse
1933     cdr recurse
1934 ;
1935
1936 : gc-sweep
1937     scheme-memsize nextfree !
1938     0 scheme-memsize 1- do
1939         nextfrees i + @ 0<> if
1940             nextfree @ nextfrees i + !
1941             i nextfree !
1942         then
1943     -1 +loop
1944 ;
1945
1946 \ Following a GC, this gives the amount of free memory
1947 : gc-count-marked
1948     0
1949     scheme-memsize 0 do
1950         nextfrees i + @ 0= if 1+ then
1951     loop
1952 ;
1953
1954 \ Debugging word - helps spot memory that is retained
1955 : gc-zero-unmarked
1956     scheme-memsize 0 do
1957         nextfrees i + @ 0<> if
1958             0 car-cells i + !
1959             0 cdr-cells i + !
1960         then
1961     loop
1962 ;
1963
1964 :noname
1965     \ ." GC! "
1966
1967     gc-unmark
1968
1969     symbol-table obj@ gc-mark-obj
1970     macro-table obj@ gc-mark-obj
1971     console-i/o-port obj@ gc-mark-obj
1972     global-env obj@ gc-mark-obj
1973
1974     depth gc-stack-depth @ do
1975         PSP0 i + 1 + @
1976         PSP0 i + 2 + @
1977
1978         gc-mark-obj
1979     2 +loop
1980
1981     gc-sweep
1982
1983     \ ." (" gc-count-marked . ." pairs marked as used.)" cr
1984 ; is collect-garbage
1985
1986 \ }}}
1987
1988 \ ---- Loading files ---- {{{
1989
1990 : load ( addr n -- finalResult )
1991     open-input-file
1992
1993     empty-parse-str
1994
1995     ok-symbol ( port res )
1996
1997     begin
1998         2over read-port ( port res obj )
1999
2000         2dup EOF character-type objeq? if
2001             2drop 2swap close-port
2002             exit
2003         then
2004
2005         2swap 2drop ( port obj )
2006
2007         global-env obj@ eval ( port res )
2008     again
2009 ;
2010
2011 \ }}}
2012
2013 \ ---- Standard Library ---- {{{
2014
2015     include scheme-primitives.4th
2016
2017     s" scheme-library.scm" load 2drop
2018     
2019 \ }}}
2020
2021 \ ---- REPL ----
2022
2023 ( REPL calls REPL-BODY in a loop until repl-body returns true. )
2024 : repl-body ( -- bool )
2025     cr bold fg green ." > " reset-term
2026
2027     read-console
2028
2029     2dup EOF character-type objeq? if
2030         2drop
2031         bold fg blue ." Moriturus te saluto." reset-term cr
2032         true exit
2033     then
2034
2035     global-env obj@ eval
2036
2037     fg cyan ." ; " print reset-term
2038
2039     false
2040 ;
2041
2042 : repl
2043     empty-parse-str
2044
2045     enable-gc
2046
2047     \ Display welcome message
2048     welcome-symbol nil cons global-env obj@ eval 2drop
2049
2050     begin
2051         ['] repl-body catch
2052         case
2053             recoverable-exception of false endof
2054             unrecoverable-exception of true endof
2055
2056             throw false
2057         endcase
2058     until
2059 ;
2060
2061 forth definitions
2062
2063 \ vim:fdm=marker