Merge branch 'ruby1.9' of https://github.com/elektronaut/mal into elektronaut-ruby1.9
[jackhill/mal.git] / forth / step3_env.fs
CommitLineData
69972a83
C
1require reader.fs
2require printer.fs
3require env.fs
4
5: args-as-native { argv argc -- entry*argc... }
6 argc 0 ?do
7 argv i cells + @ as-native
8 loop ;
9
100 MalEnv. constant repl-env
136ce7c9
C
11s" +" MalSymbol. :noname args-as-native + MalInt. ; MalNativeFn. repl-env env/set
12s" -" MalSymbol. :noname args-as-native - MalInt. ; MalNativeFn. repl-env env/set
13s" *" MalSymbol. :noname args-as-native * MalInt. ; MalNativeFn. repl-env env/set
14s" /" MalSymbol. :noname args-as-native / MalInt. ; MalNativeFn. repl-env env/set
69972a83 15
45c1894b
C
16: read read-str ;
17: eval ( env obj ) mal-eval ;
18: print
19 \ ." Type: " dup mal-type @ type-name safe-type cr
20 pr-str ;
69972a83 21
45c1894b 22MalDefault extend mal-eval nip ;; drop \ By default, evalutate to yourself
69972a83
C
23
24MalKeyword
45c1894b
C
25 extend eval-invoke { env list kw -- val }
26 0 kw env list MalList/start @ cell+ @ eval get
e6106d45
C
27 ?dup 0= if
28 \ compute not-found value
29 list MalList/count @ 1 > if
45c1894b 30 env list MalList/start @ 2 cells + @ eval
e6106d45
C
31 else
32 mal-nil
33 endif
34 endif ;;
69972a83
C
35drop
36
45c1894b
C
37\ eval all but the first item of list
38: eval-rest { env list -- argv argc }
39 list MalList/start @ cell+ { expr-start }
40 list MalList/count @ 1- { argc }
41 argc cells allocate throw { target }
42 argc 0 ?do
43 env expr-start i cells + @ eval
44 target i cells + !
69972a83 45 loop
45c1894b
C
46 target argc ;
47
48MalNativeFn
49 extend eval-invoke ( env list this -- list )
50 MalNativeFn/xt @ { xt }
51 eval-rest ( argv argc )
52 xt execute ( return-val ) ;;
69972a83
C
53drop
54
55SpecialOp
45c1894b 56 extend eval-invoke ( env list this -- list )
69972a83
C
57 SpecialOp/xt @ execute ;;
58drop
59
79feb89f
C
60: install-special ( symbol xt )
61 SpecialOp. repl-env env/set ;
69972a83 62
79feb89f
C
63: defspecial
64 parse-allot-name MalSymbol.
65 ['] install-special
66 :noname
67 ;
68
69defspecial quote ( env list -- form )
70 nip MalList/start @ cell+ @ ;;
71
45c1894b 72defspecial def! { env list -- val }
c05d35e8 73 list MalList/start @ cell+ { arg0 }
69972a83 74 arg0 @ ( key )
45c1894b
C
75 env arg0 cell+ @ eval dup { val } ( key val )
76 env env/set val ;;
69972a83 77
45c1894b 78defspecial let* { old-env list -- val }
69972a83 79 old-env MalEnv. { env }
c05d35e8
C
80 list MalList/start @ cell+ dup { arg0 }
81 @ to-list
82 dup MalList/start @ { bindings-start } ( list )
83 MalList/count @ 0 +do
69972a83 84 bindings-start i cells + dup @ swap cell+ @ ( sym expr )
45c1894b 85 env swap eval
69972a83
C
86 env env/set
87 2 +loop
45c1894b 88 env arg0 cell+ @ eval
69972a83 89 \ TODO: dec refcount of env
79feb89f 90 ;;
69972a83
C
91
92MalSymbol
93 extend mal-eval { env sym -- val }
a631063f 94 sym env env/get-addr
69972a83
C
95 dup 0= if
96 drop
a631063f 97 ." Symbol '" sym pr-str safe-type ." ' not found." cr
69972a83 98 1 throw
a631063f
C
99 else
100 @
69972a83
C
101 endif ;;
102drop
103
45c1894b 104: eval-ast { env list -- list }
69972a83 105 here
c05d35e8
C
106 list MalList/start @ { expr-start }
107 list MalList/count @ 0 ?do
45c1894b 108 env expr-start i cells + @ eval ,
69972a83 109 loop
e6106d45
C
110 here>MalList ;
111
112MalList
113 extend mal-eval { env list -- val }
45c1894b
C
114 env list MalList/start @ @ eval
115 env list rot eval-invoke ;;
69972a83
C
116drop
117
118MalVector
119 extend mal-eval ( env vector -- vector )
45c1894b 120 MalVector/list @ eval-ast
69972a83
C
121 MalVector new swap over MalVector/list ! ;;
122drop
123
124MalMap
125 extend mal-eval ( env map -- map )
45c1894b 126 MalMap/list @ eval-ast
69972a83
C
127 MalMap new swap over MalMap/list ! ;;
128drop
129
45c1894b 130: rep ( str-addr str-len -- str-addr str-len )
69972a83
C
131 read
132 repl-env swap eval
133 print ;
134
135create buff 128 allot
45c1894b 13677777777777 constant stack-leak-detect
69972a83
C
137
138: read-lines
139 begin
140 ." user> "
45c1894b 141 stack-leak-detect
69972a83 142 buff 128 stdin read-line throw
45c1894b
C
143 while ( num-bytes-read )
144 buff swap ( str-addr str-len )
69972a83 145 ['] rep
45c1894b
C
146 \ execute safe-type
147 catch ?dup 0= if safe-type else ." Caught error " . endif
69972a83 148 cr
45c1894b 149 stack-leak-detect <> if ." --stack leak--" cr endif
69972a83
C
150 repeat ;
151
152read-lines
153cr
154bye