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