-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
108 lines (90 loc) · 2.45 KB
/
main.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
101
102
103
104
105
106
107
108
# look at intepreter limits
#####################
################
###########
######
# Adapted from P Norvig's example (http://norvig.com/lispy.html)
# Let's make this clojure flavored
# ast is just a list of lists
'''
Can we do better?
Can we interop with python libs?
Can we write the code in a python file and have it execute without wrapping
'''
'''
Define types
'''
symbol = str # A Scheme Symbol is implemented as a Python str
num = (int, float) # A Scheme Number is implemented as a Python int or float
literal = (Symbol, Number) # A Scheme Atom is a Symbol or Number
list = list # A Scheme List is implemented as a Python list
exp = (Atom, List) # A Scheme expression is an Atom or List
env = dict # A Scheme environment (defined below)
# is a mapping of {variable: value}
def literalize(token: str):
try: return int(token)
except ValueError:
try: return float(token)
except ValueError:
return symbol(token)
def tokenize(code: str):
return code.replace('(', ' ( ').replace(')', ' ) ').split()
def parse(code: str):
return read_tokens(tokenize(code))
def read_tokens(tokens: list) -> list:
if len(tokens) == 0:
raise SyntaxError('unexpected EOF')
token = tokens.pop(0)
if token == '(':
l = []
while tokens[0] != ')':
l.append(read_tokens(tokens))
tokens.pop(0)
return l
elif token == ')':
raise SyntaxError('unexpected )')
else:
return literalize(token)
import math
import operator
def default_env():
''' Set up a basic lisp env '''
return {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv,
'print': print
}
global_env = default_env()
def eval(x: exp, env=global_env):
if isinstance(x, symbol):
return env[x]
if isinstance(x, num):
return x
else:
try:
proc = eval(x[0], env)
args = [eval(arg, env) for arg in x[1:]]
return proc(*args)
except IndexError:
pass
def run(x: exp, env=global_env):
return eval(parse(x), env)
#### Run directly
run('''
(+ 1 1)
''')
#### Run with a decorator
def lispy(func: callable):
def wrap():
out = run(func())
print(out)
return wrap
@lispy
def code():
return '''
(+ 1 1)
'''
#### Run from file TODO
#### Run from repl TODO