forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstep4_if_fn_do.rexx
176 lines (165 loc) · 4.71 KB
/
step4_if_fn_do.rexx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
call main
exit
#include "readline.rexx"
#include "reader.rexx"
#include "printer.rexx"
#include "types.rexx"
#include "env.rexx"
#include "core.rexx"
read: procedure expose values. err /* read(str) */
return read_str(arg(1))
eval_ast: procedure expose values. env. err /* eval_ast(ast, env_idx) */
ast = arg(1)
env_idx = arg(2)
type = obj_type(ast)
val = obj_val(ast)
select
when type == "symb" then return env_get(env_idx, val)
when type == "list" then do
res = ""
do i=1 to words(val)
element = eval(word(val, i), env_idx)
if element == "ERR" then return "ERR"
if i > 1 then
res = res || " " || element
else
res = element
end
return new_list(res)
end
when type == "vect" then do
res = ""
do i=1 to words(val)
element = eval(word(val, i), env_idx)
if element == "ERR" then return "ERR"
if i > 1 then
res = res || " " || element
else
res = element
end
return new_vector(res)
end
when type == "hash" then do
res = ""
do i=1 to words(val)
element = eval(word(val, i), env_idx)
if element == "ERR" then return "ERR"
if i > 1 then
res = res || " " || element
else
res = element
end
return new_hashmap(res)
end
otherwise
return ast
end
eval: procedure expose values. env. err /* eval(ast) */
ast = arg(1)
env_idx = arg(2)
if \list?(ast) then return eval_ast(ast, env_idx)
astval = obj_val(ast)
if words(astval) == 0 then return ast
a0sym = obj_val(word(astval, 1))
select
when a0sym == "def!" then do
a1sym = obj_val(word(astval, 2))
a2 = eval(word(astval, 3), env_idx)
if a2 == "ERR" then return "ERR"
return env_set(env_idx, a1sym, a2)
end
when a0sym == "let*" then do
a1lst = obj_val(word(astval, 2))
letenv_idx = new_env(env_idx)
do i=1 to words(a1lst) by 2
k = obj_val(word(a1lst, i))
v = eval(word(a1lst, i + 1), letenv_idx)
if v == "ERR" then return "ERR"
unused = env_set(letenv_idx, k, v)
end
return eval(word(astval, 3), letenv_idx)
end
when a0sym == "do" then do
res = "ERR"
do i=2 to words(astval)
res = eval(word(astval, i), env_idx)
if res == "ERR" then return "ERR"
end
return res
end
when a0sym == "if" then do
condval = eval(word(astval, 2), env_idx)
if false?(condval) | nil?(condval) then
if words(astval) >= 4 then
return eval(word(astval, 4), env_idx)
else
return new_nil()
else
return eval(word(astval, 3), env_idx)
end
when a0sym == "fn*" then return new_func(word(astval, 3), env_idx, word(astval, 2))
otherwise
lst_obj = eval_ast(ast, env_idx)
if lst_obj == "ERR" then return "ERR"
lst = obj_val(lst_obj)
f = word(lst, 1)
select
when nativefn?(f) then do
call_args = subword(lst, 2)
call_list = ""
do i=1 to words(call_args)
element = '"' || word(call_args, i) || '"'
if i > 1 then
call_list = call_list || ', ' || element
else
call_list = element
end
res = ""
interpret "res = " || obj_val(f) || "(" || call_list || ")"
return res
end
when func?(f) then do
call_args = new_list(subword(lst, 2))
return eval(func_body_ast(f), new_env(func_env_idx(f), func_binds(f), call_args))
end
otherwise
err = "Unsupported function object type: " || obj_type(f)
return "ERR"
end
end
print: procedure expose values. /* print(ast) */
return pr_str(arg(1), 1)
re: procedure expose values. env. err repl_env_idx /* re(str) */
str = arg(1)
ast = read(str)
if ast == "ERR" then return "ERR"
return eval(ast, repl_env_idx)
rep: procedure expose values. env. err repl_env_idx /* rep(str) */
str = arg(1)
exp = re(str)
if exp == "ERR" then return "ERR"
return print(exp)
main:
values. = ""
values.0 = 0
env. = ""
env.0 = 0
repl_env_idx = new_env(0)
/* core.rexx: defined using Rexx */
core_ns = get_core_ns()
do i=1 to words(core_ns) by 2
x = env_set(repl_env_idx, word(core_ns, i), new_nativefn(word(core_ns, i + 1)))
end
/* core.mal: defined using the language itself */
x = re("(def! not (fn* (a) (if a false true)))")
err = ""
do while lines() > 0 /* 1 == 1 */
input_line = readline('user> ')
if length(input_line) > 0 then do
res = rep(input_line)
if res == "ERR" then
call lineout , "Error: " || err
else
call lineout , res
end
end