All: remove slurp-do, use str around slurp instead.
[jackhill/mal.git] / python / step6_file.py
1 import sys, traceback
2 import mal_readline
3 from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q,
4 vector_Q, hash_map_Q, new_symbol, new_function,
5 new_list, new_vector, new_hash_map, Env, types_ns)
6 from reader import (read_str, Blank)
7
8 # read
9 def READ(str):
10 return read_str(str)
11
12 # eval
13 def eval_ast(ast, env):
14 if symbol_Q(ast):
15 return env.get(ast)
16 elif list_Q(ast):
17 return new_list(*map(lambda a: EVAL(a, env), ast))
18 elif vector_Q(ast):
19 return new_vector(*map(lambda a: EVAL(a, env), ast))
20 elif hash_map_Q(ast):
21 keyvals = []
22 for k in ast.keys():
23 keyvals.append(EVAL(k, env))
24 keyvals.append(EVAL(ast[k], env))
25 return new_hash_map(*keyvals)
26 else:
27 return ast # primitive value, return unchanged
28
29 def EVAL(ast, env):
30 while True:
31 #print("EVAL %s" % ast)
32 if not list_Q(ast):
33 return eval_ast(ast, env)
34
35 # apply list
36 if len(ast) == 0: return ast
37 a0 = ast[0]
38
39 if "def!" == a0:
40 a1, a2 = ast[1], ast[2]
41 res = EVAL(a2, env)
42 return env.set(a1, res)
43 elif "let*" == a0:
44 a1, a2 = ast[1], ast[2]
45 let_env = Env(env)
46 for i in range(0, len(a1), 2):
47 let_env.set(a1[i], EVAL(a1[i+1], let_env))
48 return EVAL(a2, let_env)
49 elif "do" == a0:
50 eval_ast(ast[1:-1], env)
51 ast = ast[-1]
52 # Continue loop (TCO)
53 elif "if" == a0:
54 a1, a2 = ast[1], ast[2]
55 cond = EVAL(a1, env)
56 if cond is None or cond is False:
57 if len(ast) > 3: ast = ast[3]
58 else: ast = None
59 else:
60 ast = a2
61 # Continue loop (TCO)
62 elif "fn*" == a0:
63 a1, a2 = ast[1], ast[2]
64 return new_function(EVAL, a2, env, a1)
65 else:
66 el = eval_ast(ast, env)
67 f = el[0]
68 if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
69 m = f.__meta__
70 ast = m['exp']
71 env = Env(m['env'], m['params'], el[1:])
72 else:
73 return f(*el[1:])
74
75 # print
76 def PRINT(exp):
77 return pr_str(exp)
78
79 # repl
80 repl_env = Env()
81 def REP(str):
82 return PRINT(EVAL(READ(str), repl_env))
83 def _ref(k,v): repl_env.set(k, v)
84
85 # Import types functions
86 for name, val in types_ns.items(): _ref(name, val)
87
88 _ref('read-string', read_str)
89 _ref('eval', lambda ast: EVAL(ast, repl_env))
90 _ref('slurp', lambda file: open(file).read())
91
92 # Defined using the language itself
93 REP("(def! not (fn* (a) (if a false true)))")
94 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
95
96 if len(sys.argv) >= 2:
97 REP('(load-file "' + sys.argv[1] + '")')
98 else:
99 while True:
100 try:
101 line = mal_readline.readline("user> ")
102 if line == None: break
103 if line == "": continue
104 print(REP(line))
105 except Blank: continue
106 except Exception as e:
107 print "".join(traceback.format_exception(*sys.exc_info()))