2 IS_RPYTHON
= sys
.argv
[0].endswith('rpython')
5 #from rpython.rlib.debug import fatalerror
6 from rpython
.rtyper
.lltypesystem
import lltype
7 from rpython
.rtyper
.lltypesystem
.lloperation
import llop
12 import mal_types
as types
13 from mal_types
import (MalSym
, MalInt
, MalStr
,
14 nil
, true
, false
, _symbol
, _keywordu
,
15 MalList
, _list
, MalVector
, MalHashMap
, MalFunc
)
16 import reader
, printer
22 return reader
.read_str(str)
26 return types
._sequential
_Q
(x
) and len(x
) > 0
30 return _list(_symbol(u
"quote"), ast
)
33 if isinstance(a0
, MalSym
):
34 if a0
.value
== u
'unquote':
36 if is_pair(a0
) and isinstance(a0
[0], MalSym
):
38 if (isinstance(a00
, MalSym
) and
39 a00
.value
== u
'splice-unquote'):
40 return _list(_symbol(u
"concat"),
42 quasiquote(ast
.rest()))
43 return _list(_symbol(u
"cons"),
45 quasiquote(ast
.rest()))
47 def is_macro_call(ast
, env
):
48 if types
._list
_Q
(ast
):
50 if isinstance(a0
, MalSym
):
51 if not env
.find(a0
) is None:
52 return env
.get(a0
).ismacro
55 def macroexpand(ast
, env
):
56 while is_macro_call(ast
, env
):
57 assert isinstance(ast
[0], MalSym
)
59 ast
= macroexpand(mac
.apply(ast
.rest()), env
)
62 def eval_ast(ast
, env
):
63 if types
._symbol
_Q
(ast
):
64 assert isinstance(ast
, MalSym
)
66 elif types
._list
_Q
(ast
):
69 res
.append(EVAL(a
, env
))
71 elif types
._vector
_Q
(ast
):
74 res
.append(EVAL(a
, env
))
76 elif types
._hash
_map
_Q
(ast
):
78 for k
in ast
.dct
.keys():
79 new_dct
[k
] = EVAL(ast
.dct
[k
], env
)
80 return MalHashMap(new_dct
)
82 return ast
# primitive value, return unchanged
86 #print("EVAL %s" % printer._pr_str(ast))
87 if not types
._list
_Q
(ast
):
88 return eval_ast(ast
, env
)
89 if len(ast
) == 0: return ast
92 ast
= macroexpand(ast
, env
)
93 if not types
._list
_Q
(ast
):
94 return eval_ast(ast
, env
)
95 if len(ast
) == 0: return ast
97 if isinstance(a0
, MalSym
):
100 a0sym
= u
"__<*fn*>__"
103 a1
, a2
= ast
[1], ast
[2]
105 return env
.set(a1
, res
)
106 elif u
"let*" == a0sym
:
107 a1
, a2
= ast
[1], ast
[2]
109 for i
in range(0, len(a1
), 2):
110 let_env
.set(a1
[i
], EVAL(a1
[i
+1], let_env
))
112 env
= let_env
# Continue loop (TCO)
113 elif u
"quote" == a0sym
:
115 elif u
"quasiquote" == a0sym
:
116 ast
= quasiquote(ast
[1]) # Continue loop (TCO)
117 elif u
"defmacro!" == a0sym
:
118 func
= EVAL(ast
[2], env
)
120 return env
.set(ast
[1], func
)
121 elif u
"macroexpand" == a0sym
:
122 return macroexpand(ast
[1], env
)
123 elif u
"try*" == a0sym
:
125 return EVAL(ast
[1], env
);
126 a1
, a2
= ast
[1], ast
[2]
128 if isinstance(a20
, MalSym
):
129 if a20
.value
== u
"catch*":
131 return EVAL(a1
, env
);
132 except types
.MalException
as exc
:
134 catch_env
= Env(env
, _list(a2
[1]), _list(exc
))
135 return EVAL(a2
[2], catch_env
)
136 except Exception as exc
:
137 exc
= MalStr(unicode("%s" % exc
))
138 catch_env
= Env(env
, _list(a2
[1]), _list(exc
))
139 return EVAL(a2
[2], catch_env
)
140 return EVAL(a1
, env
);
145 eval_ast(ast
.slice2(1, len(ast
)-1), env
)
146 ast
= ast
[-1] # Continue loop (TCO)
148 a1
, a2
= ast
[1], ast
[2]
150 if cond
is nil
or cond
is false
:
151 if len(ast
) > 3: ast
= ast
[3] # Continue loop (TCO)
154 ast
= a2
# Continue loop (TCO)
155 elif u
"fn*" == a0sym
:
156 a1
, a2
= ast
[1], ast
[2]
157 return MalFunc(None, a2
, env
, a1
, EVAL
)
159 el
= eval_ast(ast
, env
)
161 if isinstance(f
, MalFunc
):
164 env
= f
.gen_env(el
.rest()) # Continue loop (TCO)
166 return f
.apply(el
.rest())
168 raise Exception("%s is not callable" % f
)
172 return printer
._pr
_str
(exp
)
175 class MalEval(MalFunc
):
176 def apply(self
, args
):
177 return self
.EvalFunc(args
[0], self
.env
)
179 def entry_point(argv
):
182 return PRINT(EVAL(READ(str), env
))
184 # core.py: defined using python
185 for k
, v
in core
.ns
.items():
186 repl_env
.set(_symbol(unicode(k
)), MalFunc(v
))
187 repl_env
.set(types
._symbol
(u
'eval'),
188 MalEval(None, env
=repl_env
, EvalFunc
=EVAL
))
191 for a
in argv
[2:]: mal_args
.append(MalStr(unicode(a
)))
192 repl_env
.set(_symbol(u
'*ARGV*'), MalList(mal_args
))
194 # core.mal: defined using the language itself
195 REP("(def! *host-language* \"rpython\")", repl_env
)
196 REP("(def! not (fn* (a) (if a false true)))", repl_env
)
197 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env
)
198 REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", repl_env
)
199 REP("(def! inc (fn* [x] (+ x 1)))", repl_env
)
200 REP("(def! gensym (let* [counter (atom 0)] (fn* [] (symbol (str \"G__\" (swap! counter inc))))))", repl_env
)
201 REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))", repl_env
)
204 REP('(load-file "' + argv
[1] + '")', repl_env
)
207 REP("(println (str \"Mal [\" *host-language* \"]\"))", repl_env
)
210 line
= mal_readline
.readline("user> ")
211 if line
== "": continue
212 print(REP(line
, repl_env
))
213 except EOFError as e
:
217 except types
.MalException
as e
:
218 print(u
"Error: %s" % printer
._pr
_str
(e
.object, False))
219 except Exception as e
:
220 print("Error: %s" % e
)
222 llop
.debug_print_traceback(lltype
.Void
)
224 print("".join(traceback
.format_exception(*sys
.exc_info())))
227 # _____ Define and setup target ___
231 # Just run entry_point if not RPython compilation
233 if not sys
.argv
[0].endswith('rpython'):
234 entry_point(sys
.argv
)