-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtree.py
More file actions
119 lines (109 loc) · 3.7 KB
/
tree.py
File metadata and controls
119 lines (109 loc) · 3.7 KB
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
109
110
111
112
113
114
115
116
117
118
119
class SyntaxTree:
def __init__(self, expr, interpreter, left=None, right=None):
self.atom = False
self.raw_expr = expr
self.interpreter = interpreter
if len(split_expr(expr)) == 1:
self.atom = True
return
if not left:
self.make_tree()
else:
self.left = left
def __call__(self):
if self.atom:
return self.raw_expr
if self.symbol in ["lambda", "quote", "define", "import"]:
return self.eval()
try:
self.left = self.left()
except TypeError as e:
# raise for any error other than duck type
if "not callable" not in str(e):
raise
if self.symbol in ['eval', 'cond', 'bool']:
return self.eval()
try:
self.right = self.right()
except TypeError as e:
if "not callable" not in str(e):
raise
return self.eval()
def __str__(self):
return self.raw_expr
def make_tree(self):
symlst = split_expr(self.raw_expr)
self.symbol = symlst[0]
if len(split_expr(symlst[1])) > 1:
self.left = SyntaxTree(symlst[1],
self.interpreter)
else:
self.left = symlst[1]
if len(symlst) == 3:
if len(split_expr(symlst[2]))> 1:
self.right = SyntaxTree(symlst[2],
self.interpreter)
else:
self.right = symlst[2]
else:
self.right = ''
self.naive_tree = True
if is_in("(", self.left) or is_in("(", self.right):
self.naive_tree = False
def group_parens(self, string):
'returns the index of the parenthesis that corresponds to the first one in the string given'
opens = 0
closes = 0
for i in range(len(string)):
if string[i] == "(":
opens += 1
elif string[i] == ")":
closes += 1
if opens == closes:
return i
raise(ValueError("Open Paren doesn't have a corresponding close paren"))
def eval(self):
return self.interpreter.eval(self.symbol,
self.left,
self.right)
def __list__(self):
if self.symbol == 'cons':
if self.interpreter.is_tree(self.left):
if self.intrepeter.is_tree(self.right):
return list(self.left) + list(self.right)
return list(self.left) + [self.right]
if self.interpreter.is_tree(self.right):
return [self.left] + list(self.right)
return [self.left, self.right]
return [self.raw_expr]
def split_expr(string):
if isinstance(string, SyntaxTree):
string = string.raw_expr
if "(" not in string:
return [string]
if string[0] == "(":
string = string[1:]
if string[-1] == ")":
string = string[:-1]
inds = [0]
oparen = 0
clparen = 0
for count, char in enumerate(string):
if char == ' ' and oparen == clparen:
inds.append(count)
clparen = 0
oparen = 0
elif char == "(":
oparen += 1
elif char == ")":
clparen += 1
res = []
for i in range(1, len(inds)):
res.append(string[inds[i-1]:inds[i]].strip())
res.append(string[inds[-1]:].strip())
return res
def is_in(item, container):
'container is either a string, listlike, or SyntaxTree'
if isinstance(container, SyntaxTree):
return item in container.raw_expr
return item in container