-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdlang_ast.py
197 lines (127 loc) · 5.24 KB
/
dlang_ast.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
'''
Definitions for AST nodes
Each node records the lineno and index of its first terminal
Most nodes are just wrappers around a little bit of data, but some do more complex actions
StatementBlock refers to a block of statements (e.g., {int x; int y; return x + y;}
BlockStatement refers to any statement that has a block associated with it (e.g., if's, loops)
'''
class TerminalWrapper:
def __init__(self, terminal, lineno, index):
self.terminal = terminal
self.lineno = lineno
self.index = index
### AST Nodes ###
## Base Nodes ##
class Node:
def __init__(self, lineno=0, index=0):
self.lineno = lineno
self.index = index
class Expression(Node): # every expression at least has a type. some may not have a value (like calls)
value = None
def __init__(self, lineno, index):
self.type = None
super().__init__(lineno, index)
class Statement(Node):
pass
class Declaration(Node): # every declaration has an id and a type
identifier = None
def __init__(self, lineno, index):
self.type = None
super().__init__(lineno, index)
class StatementBlock(Node):
statements = None
declarations = None
symbol_count = 0
block_count = 0
def __init__(self, declarations, statements, lineno, index):
self.statements = statements
self.declarations = declarations
self.breaks = [] # if this continued to code generation, I figured this would be useful for loops
self.returns = []
self.symbol_count = len(declarations) # number of new symbols introduced
for stmt in statements:
if type(stmt) == BreakStatement: # add breaks and returns to appropriate lists
self.breaks.append(stmt)
elif type(stmt) == ReturnStatement:
self.returns.append(stmt)
elif issubclass(type(stmt), BlockStatement): # count number of sub-blocks
self.block_count += 1
# since a return breaks out of any scope, any returns in the sub-block are also returns of the enclosing block
self.returns += stmt.block.returns
super().__init__(lineno, index)
def __repr__(self):
return 'BLOCK (declarations: %d, statements: %d, breaks: %d, returns: %d)' % (len(self.declarations), len(self.statements), len(self.breaks), len(self.returns))
## Expression Derived Nodes ##
class Literal(Expression):
def __repr__(self):
return 'LITERAL (%s, %s)' % (self.type, str(self.value))
class Empty(Expression):
def __init__(self):
self.type = 'nothing'
def __repr__(self):
return 'Empty'
class VariableReference(Expression):
name = None
def __repr__(self):
return 'VAR-REF %s' % self.name
class Operator(Expression):
operation = None
class UnaryOperator(Operator):
rhs = None
def __repr__(self):
return '(%s %s(%s))' % ('LOGICALEXPR' if self.type == 'bool' else 'MATHEXPR', self.operation, repr(self.rhs))
class BinaryOperator(UnaryOperator):
lhs = None
def __repr__(self):
if self.type == 'bool':
return '(LOGICALEXPR A %s B: A=%s B=%s)' % (self.operation, repr(self.lhs), repr(self.rhs))
else:
return '(MATHEXPR %s %s and %s)' % (self.operation, repr(self.lhs), repr(self.rhs))
## Statement Derived Nodes ##
class BreakStatement(Statement):
def __repr__(self):
return 'BREAK'
class BlockStatement(Statement):
block = None
class CallStatement(Statement, Expression):
identifier = None
args = None
def __repr__(self):
return 'CALL %s, args: %s' % (self.identifier, str(self.args))
class ExpressionStatement(Statement):
expression = None
# Block Statement Derived Nodes #
class IfStatement(BlockStatement):
condition = None
alternate = None
def __repr__(self):
return 'BRANCH condition=%s%s' % (repr(self.condition), ', alternative-present' if self.alternate else '')
class ElseStatement(BlockStatement):
def __repr__(self):
return 'ELSE'
class WhileStatement(IfStatement):
def __repr__(self):
return 'LOOP_WHILE condition=%s' % repr(self.condition)
class ForStatement(IfStatement):
initial = None
increment = None
def __repr__(self):
opt = ''.join(['(', ('initial=%s' % repr(self.initial)) if self.initial else '', ('increment=%s' % repr(self.increment)) if self.increment else '', ')'])
return 'LOOP_FOR condition=%s%s' % (repr(self.condition), opt if (self.initial or self.increment) else '')
# Expression Statement Derived Nodes #
class AssignmentStatement(ExpressionStatement):
target = None
def __repr__(self):
return 'ASSIGN %s => VAR-REF %s' % (repr(self.expression), self.target)
class ReturnStatement(ExpressionStatement):
def __repr__(self):
return 'RETURN %s' % (repr(self.expression) if self.expression.type != 'nothing' else '')
## Declaration Derived Nodes ##
class VariableDeclaration(Declaration):
def __repr__(self):
return 'VAR %s: %s' % (self.identifier, self.type)
class FunctionDeclaration(Declaration):
parameters = None
block = None
def __repr__(self):
return 'FUNC %s: %s => %s' % (self.identifier, str(self.parameters), self.type)