-
Notifications
You must be signed in to change notification settings - Fork 0
/
py_lisp.py
100 lines (90 loc) · 2.64 KB
/
py_lisp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from py_env import global_env, Env
class Function(object):
def __init__(self, params, body, env, macro=False):
self.params = params
self.body = body
self.env = env
self.macro = macro
def __call__(self, *args):
return lisp_eval(self.body, Env(self.params, args, self.env))
def tokenize(string):
tokens = string.replace("(", " ( ").replace(")", " ) ").split()
return tokens
def atom(token):
try:
return int(token)
except ValueError:
try:
return float(token)
except ValueError:
return str(token)
def lisp_ast(tokens):
if not tokens:
raise SyntaxError("unexpected EOF while reading")
token = tokens.pop(0)
if token == "'":
_list = list("'")
while tokens[0] is not ")":
_list.append(lisp_ast(tokens))
return _list
if token is "(":
_list = list()
while tokens[0] is not ")":
_list.append(lisp_ast(tokens))
tokens.pop(0)
return _list
elif token is ")":
raise SyntaxError("unexpected ')'")
else:
return atom(token)
def parse(lisp_string):
tokens = tokenize(lisp_string)
if tokens.count("(") != tokens.count(")"):
raise SyntaxError("unbalanced parenthesis")
else:
ast = lisp_ast(tokens)
#print(ast)
return ast
def lisp_eval(x, env=global_env):
if isinstance(x, str):
return env.find(x)[x]
elif not isinstance(x, list):
return x
elif (x[0] == "quote"):
(_, exp) = x
return exp
elif (x[0] == "'"):
(_, exp) = x
return exp
elif x[0] == "if":
(_, condition, true_exp, false_exp) = x
exp = (true_exp if lisp_eval(condition, env) else false_exp)
return lisp_eval(exp, env)
elif x[0] == "define":
(_, var, exp) = x
env[var] = lisp_eval(exp, env)
elif x[0] == "lambda":
(_, params, body) = x
return Function(params, body, env)
elif x[0] == "defmacro":
'''
(defmacro name (params) (body-with-params))
'''
(_, name, params, body) = x
env[name] = Function(params, body, env, True)
else:
function = lisp_eval(x[0], env)
try:
if function.macro:
return lisp_eval(function(x[1:][0]), env)
except AttributeError:
args = [lisp_eval(arg, env) for arg in x[1:]]
return function(*args)
def interface():
string = input()
parsed = parse(string)
print("AST", parsed)
result = lisp_eval(parsed, global_env)
print(result)
if __name__ == "__main__":
interface()