Merge pull request #345 from asarhaddon/ada.2
[jackhill/mal.git] / yorick / step7_quote.i
CommitLineData
21986733
DM
1set_path, get_env("YORICK_MAL_PATH") + ":" + get_path()
2require, "reader.i"
3require, "printer.i"
4require, "core.i"
5require, "env.i"
6
7func READ(str)
8{
9 return read_str(str)
10}
11
12func is_pair(ast)
13{
14 type = structof(ast)
15 return ((type == MalList) || (type == MalVector)) && count(ast) > 0
16}
17
18func quasiquote(ast)
19{
20 if (!is_pair(ast)) return MalList(val=&[&MalSymbol(val="quote"), &ast])
21 lst = *ast.val
22 ast1 = *lst(1)
23 if (structof(ast1) == MalSymbol && ast1.val == "unquote") return *lst(2)
24 if (is_pair(ast1)) {
25 ast11 = *((*ast1.val)(1))
26 if (structof(ast11) == MalSymbol && ast11.val == "splice-unquote") {
27 return MalList(val=&[&MalSymbol(val="concat"), (*ast1.val)(2), &quasiquote(rest(ast))])
28 }
29 }
30 return MalList(val=&[&MalSymbol(val="cons"), &quasiquote(ast1), &quasiquote(rest(ast))])
31}
32
33func eval_ast(ast, env)
34{
35 type = structof(ast)
36 if (type == MalSymbol) {
37 return env_get(env, ast.val)
38 } else if (type == MalList) {
39 seq = *(ast.val)
40 if (numberof(seq) == 0) return ast
41 res = array(pointer, numberof(seq))
42 for (i = 1; i <= numberof(seq); ++i) {
43 e = EVAL(*seq(i), env)
44 if (structof(e) == MalError) return e
45 res(i) = &e
46 }
47 return MalList(val=&res)
48 } else if (type == MalVector) {
49 seq = *(ast.val)
50 if (numberof(seq) == 0) return ast
51 res = array(pointer, numberof(seq))
52 for (i = 1; i <= numberof(seq); ++i) {
53 e = EVAL(*seq(i), env)
54 if (structof(e) == MalError) return e
55 res(i) = &e
56 }
57 return MalVector(val=&res)
58 } else if (type == MalHashmap) {
59 h = *(ast.val)
60 if (numberof(*h.keys) == 0) return ast
61 res = hash_new()
62 for (i = 1; i <= numberof(*h.keys); ++i) {
63 new_key = EVAL(hashmap_key_to_obj((*h.keys)(i)), env)
64 if (structof(new_key) == MalError) return new_key
65 new_val = EVAL(*((*h.vals)(i)), env)
66 if (structof(new_val) == MalError) return new_val
67 hash_set, res, hashmap_obj_to_key(new_key), new_val
68 }
69 return MalHashmap(val=&res)
70 } else return ast
71}
72
73func EVAL(ast, env)
74{
75 while (1) {
76 if (structof(ast) == MalError) return ast
77 if (structof(ast) != MalList) return eval_ast(ast, env)
78 lst = *ast.val
79 if (numberof(lst) == 0) return ast
80 a1 = lst(1)->val
81 if (a1 == "def!") {
82 new_value = EVAL(*lst(3), env)
83 if (structof(new_value) == MalError) return new_value
84 return env_set(env, lst(2)->val, new_value)
85 } else if (a1 == "let*") {
86 let_env = env_new(&env)
87 args_lst = *(lst(2)->val)
88 for (i = 1; i <= numberof(args_lst); i += 2) {
89 var_name = args_lst(i)->val
90 var_value = EVAL(*args_lst(i + 1), let_env)
91 if (structof(var_value) == MalError) return var_value
92 env_set, let_env, var_name, var_value
93 }
94 ast = *lst(3)
95 env = let_env
96 // TCO
97 } else if (a1 == "quote") {
98 return *lst(2)
99 } else if (a1 == "quasiquote") {
100 ast = quasiquote(*lst(2)) // TCO
101 } else if (a1 == "do") {
102 for (i = 2; i < numberof(lst); ++i) {
103 ret = EVAL(*lst(i), env)
104 if (structof(ret) == MalError) return ret
105 }
106 ast = *lst(numberof(lst))
107 // TCO
108 } else if (a1 == "if") {
109 cond_val = EVAL(*lst(2), env)
110 if (structof(cond_val) == MalError) return cond_val
111 if ((structof(cond_val) == MalNil) || (structof(cond_val) == MalFalse)) {
112 if (numberof(lst) > 3) {
113 ast = *lst(4)
114 } else {
115 return MAL_NIL
116 }
117 } else {
118 ast = *lst(3)
119 }
120 // TCO
121 } else if (a1 == "fn*") {
122 return MalFunction(env=&env, binds=lst(2)->val, ast=lst(3))
123 } else {
124 el = eval_ast(ast, env)
125 if (structof(el) == MalError) return el
126 seq = *el.val
127 if (structof(*seq(1)) == MalNativeFunction) {
128 args = (numberof(seq) > 1) ? seq(2:) : []
129 return call_core_fn(seq(1)->val, args)
130 } else if (structof(*seq(1)) == MalFunction) {
131 fn = *seq(1)
132 exprs = numberof(seq) > 1 ? seq(2:) : []
133 fn_env = env_new(fn.env, binds=*fn.binds, exprs=exprs)
134 ast = *fn.ast
135 env = fn_env
136 // TCO
137 } else {
138 return MalError(message="Unknown function type")
139 }
140 }
141 }
142}
143
144func PRINT(exp)
145{
146 if (structof(exp) == MalError) return exp
147 return pr_str(exp, 1)
148}
149
150func RE(str, env)
151{
152 return EVAL(READ(str), env)
153}
154
155func REP(str, env)
156{
157 return PRINT(EVAL(READ(str), env))
158}
159
160func get_command_line(void)
161// Force quiet mode (-q) to prevent Yorick from printing its banner
162{
163 argv = get_argv()
164 return numberof(argv) > 1 ? grow([argv(1), "-q"], argv(2:)) : [argv(1), "-q"]
165}
166
167func prepare_argv_list(args)
168{
169 if (numberof(args) <= 1) return MalList(val=&[])
170 str_lst = array(pointer, numberof(args) - 1)
171 for (i = 2; i <= numberof(args); ++i) {
172 str_lst(i - 1) = &MalString(val=args(i))
173 }
174 return MalList(val=&str_lst)
175}
176
177repl_env = nil
178
179func main(void)
180{
181 extern repl_env
182 repl_env = env_new(pointer(0))
183
184 // core.i: defined using Yorick
185 core_symbols = h_keys(core_ns)
186 for (i = 1; i <= numberof(core_symbols); ++i) {
187 env_set, repl_env, core_symbols(i), MalNativeFunction(val=core_symbols(i))
188 }
189 command_line_args = process_argv()
190 env_set, repl_env, "*ARGV*", prepare_argv_list(command_line_args)
191
192 // core.mal: defined using the language itself
193 RE, "(def! not (fn* (a) (if a false true)))", repl_env
194 RE, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env
195
196 if (numberof(command_line_args) > 0) {
197 RE, "(load-file \"" + command_line_args(1) + "\")", repl_env
198 return 0
199 }
200
201 stdin_file = open("/dev/stdin", "r")
202 while (1) {
203 write, format="%s", "user> "
204 line = rdline(stdin_file, prompt="")
205 if (!line) break
206 if (strlen(line) > 0) {
207 result = REP(line, repl_env)
208 if (structof(result) == MalError) write, format="Error: %s\n", result.message
209 else write, format="%s\n", result
210 }
211 }
212 write, ""
213}
214
215main;