RPython: step4 basics.
[jackhill/mal.git] / rpython / step4_if_fn_do.py
CommitLineData
b0a9121d
JM
1import sys, traceback
2import mal_readline
3import mal_types as types
4from mal_types import (MalSym, MalInt, MalStr, nil, true, false,
5 _symbol, _keywordu, MalList, _list, MalFunc)
6import reader, printer
7from env import Env
8import core
9
10# read
11def READ(str):
12 return reader.read_str(str)
13
14# eval
15def eval_ast(ast, env):
16 if types._symbol_Q(ast):
17 assert isinstance(ast, MalSym)
18 return env.get(ast)
19 elif types._list_Q(ast):
20 res = []
21 for a in ast.values:
22 res.append(EVAL(a, env))
23 return MalList(res)
24## elif types._vector_Q(ast):
25## return types._vector(*map(lambda a: EVAL(a, env), ast))
26## elif types._hash_map_Q(ast):
27## keyvals = []
28## for k in ast.keys():
29## keyvals.append(EVAL(k, env))
30## keyvals.append(EVAL(ast[k], env))
31## return types._hash_map(*keyvals)
32 else:
33 return ast # primitive value, return unchanged
34
35def EVAL(ast, env):
36 #print("EVAL %s" % printer._pr_str(ast))
37 if not types._list_Q(ast):
38 return eval_ast(ast, env)
39
40 # apply list
41 if len(ast) == 0: return ast
42 a0 = ast[0]
43 if isinstance(a0, MalSym):
44 a0sym = a0.value
45 else:
46 a0sym = u"__<*fn*>__"
47
48 if u"def!" == a0sym:
49 a1, a2 = ast[1], ast[2]
50 res = EVAL(a2, env)
51 return env.set(a1, res)
52 elif u"let*" == a0sym:
53 a1, a2 = ast[1], ast[2]
54 let_env = Env(env)
55 for i in range(0, len(a1), 2):
56 let_env.set(a1[i], EVAL(a1[i+1], let_env))
57 return EVAL(a2, let_env)
58 elif u"do" == a0sym:
59 el = eval_ast(ast.rest(), env)
60 return el.values[-1]
61 elif u"if" == a0sym:
62 a1, a2 = ast[1], ast[2]
63 cond = EVAL(a1, env)
64 if cond is nil or cond is false:
65 if len(ast) > 3: return EVAL(ast[3], env)
66 else: return nil
67 else:
68 return EVAL(a2, env)
69 elif u"fn*" == a0sym:
70 a1, a2 = ast[1], ast[2]
71 return MalFunc(None, a2, env, a1, EVAL)
72 else:
73 el = eval_ast(ast, env)
74 f = el.values[0]
75 if isinstance(f, MalFunc):
76 return f.apply(el.rest())
77 else:
78 raise Exception("%s is not callable" % f)
79
80# print
81def PRINT(exp):
82 return printer._pr_str(exp)
83
84# repl
85def entry_point(argv):
86 repl_env = Env()
87 def REP(str, env):
88 return PRINT(EVAL(READ(str), env))
89
90 # core.py: defined using python
91 for k, v in core.ns.items():
92 repl_env.set(_symbol(unicode(k)), MalFunc(v))
93
94 # core.mal: defined using the language itself
95 REP("(def! not (fn* (a) (if a false true)))", repl_env)
96
97 while True:
98 try:
99 line = mal_readline.readline("user> ")
100 if line == "": continue
101 print(REP(line, repl_env))
102 except EOFError as e:
103 break
104 except Exception as e:
105 print(e)
106 #print("".join(traceback.format_exception(*sys.exc_info())))
107 return 0
108
109# _____ Define and setup target ___
110def target(*args):
111 return entry_point
112
113# Just run entry_point if not RPython compilation
114import sys
115if not sys.argv[0].endswith('rpython'):
116 entry_point(sys.argv)