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