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