-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathir.py
247 lines (189 loc) · 6.86 KB
/
ir.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
import ir_re2coprocessor
from helper import reverse
def _subclasses(cls):
sub_cls = cls.__subclasses__()
sub_sub_cls = [s for c in sub_cls for s in _subclasses(c) ]
return set(cls.__subclasses__()).union(sub_sub_cls)
class IrInstr:
def __init__(self, *some_children):
self.children = list([*some_children])
def replace(self, curr, new_curr):
i = self.children.index(curr)
if(i >= 0):
self.children[i] = new_curr
def append(self, *other):
self.children += list([*other])
def __str__(self):
return f"{id(self)} TYPE: {type(self)} #CHILDREN {len(self.children)}"
def dotty_repr(self):
'''give a representation of this node only. '''
return f"{id(self)} [label=\"unknown\" color=\"black\" fillcolor=\"gray\" style=\"filled\" ]\n"
def dotty_str(self, reset_visited=False):
'''give a representation of the whole subgraph. '''
children_link = [f"{id(self)} -> {id(c)}\n" for c in self.children]
return "".join(children_link)+ self.dotty_repr()
def navigate(self, action, filtering_predicate= None):
#preorder visit
visited = []
to_visit = [self]
while len(to_visit) > 0:
e = to_visit.pop()
visited.append(e)
#print(e,'->', e.children)
action(e)
#append children in reversed order because elements to visit
#are popped from to_visit list. Hence in order to have
# as first elem to visit the first children, just push
# children in to_visit list in reversed order.
visit_next = e.children if filtering_predicate == None else filter(filtering_predicate, e.children)
for child in reversed(visit_next):
#print('\t',child)
if not (child in visited or child in to_visit):
to_visit.append(child)
def getNodes(self):
def accumulate(l):
def action_accumulate(x):
l.append(x)
return action_accumulate
node_list = []
action = accumulate(node_list)
self.navigate(action)
return node_list
def get_ancestors(self):
nodes = self.getNodes()
children = {}
for n in nodes:
if len(n.children)>0:
children[n] = n.children
ancestors = reverse(children)
#NOOO: ancestors[self] = [] not true!!
return ancestors
def deep_copy(self):
nodes = self.getNodes()
nodes_copy = [ copy.copy(n) for n in nodes]
for n in nodes:
for i in range(len(n.children)):
c = n.children[i]
index_child = nodes.index(c)
nodes_copy.children[i] = nodes_copy[index_child]
def _code_gen(self,**args):
pass
def setup(self, codegen_library_name='ir_re2coprocessor_codegen'):
"""
compiler ir frontend and ir backend are decoupled.
This method is responsible of importing the code_gen process
from the correct library. This will ultimately generate the appropriate ir.
"""
#dummy code_gen method
code_gen_dummy_method = lambda self, **args: ''
import importlib
#from types import MethodType
#search for correct <codegen_library> module which contains classes
#that can be used in code generation process.
try :
#set global object "codegen_library" equal to module
global codegen_library
codegen_library = importlib.import_module(codegen_library_name)
except ImportError :
#failed to import code_gen method, set a dummy one
code_gen_dummy_method = lambda self, **args: f'{type(self)} {id(self)}'
print("WARNING: codegen_library not found ")
#look for all subclasses of IrInstr
classes = _subclasses(IrInstr)
#print('classes found', classes)
for c in classes:
try :
if issubclass(c, IrInstr) :
setattr(c, "_code_gen", eval('codegen_library.'+c.__name__))
except Exception as e :
setattr(c, "_code_gen", code_gen_dummy_method)
print("WARNING: codegen_library could not be attached to ",c.__name__)
raise e
def equiv(self, other):
'''verifies whether instruction i is equivalent to instruction j.
Note it does not consider subtree!!'''
#raise NotImplemented("equality was not overridden")
return isinstance(other, type(self))
class Accept(IrInstr):
def __init__(self):
super().__init__()
def dotty_repr(self):
return f"{id(self)} [label=\"\\\\00 => ✓\" color=\"black\" fillcolor=\"#1ac0c6\" style=\"filled\"]\n"
def append(self, *other):
#no instruction should be appended to an Accept
pass
class Accept_Partial(IrInstr):
def __init__(self):
super().__init__()
def dotty_repr(self):
return f"{id(self)} [label=\"✓\" color=\"black\" fillcolor=\"#1ac0c6\" style=\"filled\"]\n"
def append(self, *other):
#no instruction should be appended to an Accept partial
pass
class Split(IrInstr):
def __init__(self, *children):
super().__init__(*children)
def dotty_repr(self):
return f"{id(self)} [label=\"SPLIT\" color=\"black\" fillcolor=\"#dee0e6\" style=\"filled\"]\n"
def equiv(self, other):
#if len(self.children) != len(other.children):
# return False
#for c1 in self.children:
return False
class Match(IrInstr):
def __init__(self, achar):
super().__init__()
if isinstance(achar, str):
self.char = bytes(achar, 'utf-8')[0]
else:
self.char = achar
def dotty_repr(self):
# printable Ascii \x20-\x7F
char = chr(self.char)
if self.char < 32 or self.char > 127 or char == "\"\\":
char = hex(self.char)
return f"{id(self)} [label =\"{char}\" color=\"black\" fillcolor=\"#ffa822\" style=\"filled\"]\n"
def equiv(self, other):
return super().equiv(other) and self.char == other.char
class NotMatch(IrInstr):
def __init__(self, achar):
super().__init__()
if isinstance(achar, str):
self.char = bytes(achar, 'utf-8')[0]
else:
self.char = achar
def dotty_repr(self):
# printable Ascii \x20-\x7F
char = chr(self.char)
if self.char < 32 or self.char > 127 or char == "\"\\":
char = hex(self.char)
return f"{id(self)} [label =\"^{char}\" color=\"black\" fillcolor=\"#ffa822\" style=\"filled\"]\n"
def equiv(self, other):
return super().equiv(other) and self.char == other.char
class Match_any(IrInstr):
def __init__(self, *children):
super().__init__(*children)
def dotty_repr(self):
return f"{id(self)} [label =\"\\.\" color=\"black\" fillcolor=\"#ffa822\" style=\"filled\"]\n"
class Jmp(IrInstr):
def __init__(self, next):
super().__init__(next)
def dotty_repr(self):
return f"{id(self)} [label=\"JMP\" color=\"black\" fillcolor=\"#2792ce\" style=\"filled\"]\n"
def equiv(self, other):
return super().equiv(other) and self.children[0].equiv(self.children[0])
class End_Without_Accepting(IrInstr):
def __init__(self):
super().__init__()
def dotty_repr(self):
return f" {id(self)} [label =\"✗\" color=\"black\" fillcolor=\"#ff6150\" style=\"filled\"]\n"
def append(self, *other):
#no instruction should be appended to an End_Without_Accepting
pass
class PlaceholderNop(IrInstr):
def __init__(self):
super().__init__()
def dotty_repr(self):
return f" {id(self)} [label =\"Nop\" color=\"black\" fillcolor=\"white\" style=\"filled\"]\n"
def equiv(self, other):
return super().equiv(other) and self.children[0].equiv(self.children[0])