3 import mal_types
as types
4 from mal_types
import (MalSym
, MalInt
, MalStr
,
5 nil
, true
, false
, _symbol
, _keywordu
,
6 MalList
, _list
, MalVector
, MalHashMap
, MalFunc
)
13 return reader
.read_str(str)
16 def qq_loop(elt
, acc
):
17 if types
._list
_Q
(elt
) and len(elt
) == 2:
19 if isinstance(fst
, MalSym
) and fst
.value
== u
"splice-unquote":
20 return _list(_symbol(u
"concat"), elt
[1], acc
)
21 return _list(_symbol(u
"cons"), quasiquote(elt
), acc
)
25 for elt
in reversed(seq
):
26 acc
= qq_loop (elt
, acc
)
30 if types
._list
_Q
(ast
):
33 if isinstance(fst
, MalSym
) and fst
.value
== u
"unquote":
35 return qq_foldr(ast
.values
)
36 elif types
._vector
_Q
(ast
):
37 return _list(_symbol(u
"vec"), qq_foldr(ast
.values
))
38 elif types
._symbol
_Q
(ast
) or types
._hash
_map
_Q
(ast
):
39 return _list(_symbol(u
"quote"), ast
)
43 def eval_ast(ast
, env
):
44 if types
._symbol
_Q
(ast
):
45 assert isinstance(ast
, MalSym
)
47 elif types
._list
_Q
(ast
):
50 res
.append(EVAL(a
, env
))
52 elif types
._vector
_Q
(ast
):
55 res
.append(EVAL(a
, env
))
57 elif types
._hash
_map
_Q
(ast
):
59 for k
in ast
.dct
.keys():
60 new_dct
[k
] = EVAL(ast
.dct
[k
], env
)
61 return MalHashMap(new_dct
)
63 return ast
# primitive value, return unchanged
67 #print("EVAL %s" % printer._pr_str(ast))
68 if not types
._list
_Q
(ast
):
69 return eval_ast(ast
, env
)
72 if len(ast
) == 0: return ast
74 if isinstance(a0
, MalSym
):
80 a1
, a2
= ast
[1], ast
[2]
82 return env
.set(a1
, res
)
83 elif u
"let*" == a0sym
:
84 a1
, a2
= ast
[1], ast
[2]
86 for i
in range(0, len(a1
), 2):
87 let_env
.set(a1
[i
], EVAL(a1
[i
+1], let_env
))
89 env
= let_env
# Continue loop (TCO)
90 elif u
"quote" == a0sym
:
92 elif u
"quasiquoteexpand" == a0sym
:
93 return quasiquote(ast
[1])
94 elif u
"quasiquote" == a0sym
:
95 ast
= quasiquote(ast
[1]) # Continue loop (TCO)
100 eval_ast(ast
.slice2(1, len(ast
)-1), env
)
101 ast
= ast
[-1] # Continue loop (TCO)
103 a1
, a2
= ast
[1], ast
[2]
105 if cond
is nil
or cond
is false
:
106 if len(ast
) > 3: ast
= ast
[3] # Continue loop (TCO)
109 ast
= a2
# Continue loop (TCO)
110 elif u
"fn*" == a0sym
:
111 a1
, a2
= ast
[1], ast
[2]
112 return MalFunc(None, a2
, env
, a1
, EVAL
)
114 el
= eval_ast(ast
, env
)
116 if isinstance(f
, MalFunc
):
119 env
= f
.gen_env(el
.rest()) # Continue loop (TCO)
121 return f
.apply(el
.rest())
123 raise Exception("%s is not callable" % f
)
127 return printer
._pr
_str
(exp
)
130 class MalEval(MalFunc
):
131 def apply(self
, args
):
132 return self
.EvalFunc(args
[0], self
.env
)
134 def entry_point(argv
):
137 return PRINT(EVAL(READ(str), env
))
139 # core.py: defined using python
140 for k
, v
in core
.ns
.items():
141 repl_env
.set(_symbol(unicode(k
)), MalFunc(v
))
142 repl_env
.set(types
._symbol
(u
'eval'),
143 MalEval(None, env
=repl_env
, EvalFunc
=EVAL
))
146 for a
in argv
[2:]: mal_args
.append(MalStr(unicode(a
)))
147 repl_env
.set(_symbol(u
'*ARGV*'), MalList(mal_args
))
149 # core.mal: defined using the language itself
150 REP("(def! not (fn* (a) (if a false true)))", repl_env
)
151 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", repl_env
)
154 REP('(load-file "' + argv
[1] + '")', repl_env
)
159 line
= mal_readline
.readline("user> ")
160 if line
== "": continue
161 print(REP(line
, repl_env
))
162 except EOFError as e
:
166 except types
.MalException
as e
:
167 print(u
"Error: %s" % printer
._pr
_str
(e
.object, False))
168 except Exception as e
:
169 print("Error: %s" % e
)
170 #print("".join(traceback.format_exception(*sys.exc_info())))
173 # _____ Define and setup target ___
177 # Just run entry_point if not RPython compilation
179 if not sys
.argv
[0].endswith('rpython'):
180 entry_point(sys
.argv
)