OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library ir_builder; | |
6 | |
7 import 'ir_nodes.dart'; | |
8 import '../elements/elements.dart'; | |
9 import '../dart2jslib.dart'; | |
10 import '../source_file.dart'; | |
11 import '../tree/tree.dart'; | |
12 import '../scanner/scannerlib.dart' show Token; | |
13 import '../js_backend/js_backend.dart' show JavaScriptBackend; | |
14 | |
15 class IrBuilderTask extends CompilerTask { | |
16 final Map<Element, IrNode> nodes = new Map<Element, IrNode>(); | |
17 | |
18 IrBuilderTask(Compiler compiler) : super(compiler); | |
19 | |
20 String get name => 'IR builder'; | |
21 | |
22 void buildNodes() { | |
23 Map<Element, TreeElements> resolved = | |
24 compiler.enqueuer.resolution.resolvedElements; | |
25 resolved.forEach((Element element, TreeElements elementsMapping) { | |
26 element = element.implementation; | |
27 | |
28 SourceFile sourceFile = elementSourceFile(element); | |
29 IrNodeBuilderVisitor visitor = | |
30 new IrNodeBuilderVisitor(elementsMapping, compiler, sourceFile); | |
31 IrNode irNode; | |
32 ElementKind kind = element.kind; | |
33 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
34 // TODO(lry): build ir for constructors. | |
35 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || | |
36 kind == ElementKind.FUNCTION || | |
37 kind == ElementKind.GETTER || | |
38 kind == ElementKind.SETTER) { | |
39 irNode = visitor.buildMethod(element); | |
40 } else if (kind == ElementKind.FIELD) { | |
41 // TODO(lry): build ir for lazy initializers of static fields. | |
42 } else { | |
43 compiler.internalErrorOnElement(element, | |
44 'unexpected element kind $kind'); | |
45 } | |
46 | |
47 if (irNode != null) { | |
48 nodes[element] = irNode; | |
49 unlinkTreeAndToken(element); | |
50 } | |
51 }); | |
52 } | |
53 | |
54 void unlinkTreeAndToken(Element element) { | |
ngeoffray
2013/11/20 14:55:27
I'd just untype element to avoid the 'as dynamic'.
lukas
2013/11/21 12:20:21
Done.
| |
55 if (compiler.backend is JavaScriptBackend) { | |
56 (element as dynamic).beginToken.next = null; | |
57 (element as dynamic).cachedNode = null; | |
58 } | |
59 } | |
60 | |
61 SourceFile elementSourceFile(Element element) { | |
62 if (element is FunctionElement) { | |
63 FunctionElement functionElement = element; | |
64 if (functionElement.patch != null) element = functionElement.patch; | |
65 } | |
66 return element.getCompilationUnit().script.file; | |
67 } | |
68 } | |
69 | |
70 | |
71 class IrNodeBuilderVisitor extends ResolvedVisitor<IrNode> { | |
72 SourceFile sourceFile; | |
73 | |
74 Context context; | |
75 | |
76 IrNodeBuilderVisitor(TreeElements elements, Compiler compiler, | |
77 this.sourceFile) : super(elements, compiler) { | |
ngeoffray
2013/11/20 14:55:27
Nit: One argument per line, and super on a new lin
lukas
2013/11/21 12:20:21
Done.
| |
78 context = new Context(this); | |
79 } | |
80 | |
81 IrNode buildMethod(FunctionElement functionElement) { | |
82 assert(invariant(functionElement, functionElement.isImplementation)); | |
83 FunctionExpression function = functionElement.parseNode(compiler); | |
84 assert(function != null); | |
85 assert(!function.modifiers.isExternal()); | |
86 assert(elements[function] != null); | |
87 return buildNode(function); | |
88 } | |
89 | |
90 IrNode buildNode(Node node) { | |
91 try { | |
92 return node.accept(this); | |
93 } catch(e) { | |
94 if (e == ABORT_IRNODE_BUILDER) return null; | |
95 rethrow; | |
96 } | |
97 } | |
98 | |
99 ConstantSystem get constantSystem => compiler.backend.constantSystem; | |
100 | |
101 /* int | PositionWithIdentifierName */ nodePosition(Node node) { | |
102 Token token = node.getBeginToken(); | |
103 if (token.isIdentifier()) { | |
104 return new PositionWithIdentifierName(token.charOffset, token.value); | |
105 } else { | |
106 return token.charOffset; | |
107 } | |
108 } | |
109 | |
110 IrNode visitFunctionExpression(FunctionExpression node) { | |
111 int endPosition = node.getEndToken().charOffset; | |
112 int namePosition = elements[node].position().charOffset; | |
113 IrFunction result = new IrFunction( | |
114 nodePosition(node), endPosition, namePosition, <IrNode>[]); | |
115 context.openFunction(result); | |
116 if (node.hasBody()) { | |
117 node.body.accept(this); | |
118 ensureReturn(node); | |
119 result.statements..addAll(context.constants)..addAll(context.statements); | |
120 } | |
121 context.closeFunction(); | |
122 if (!context.isTopLevel()) { | |
123 context.enterStatement(result); | |
124 } | |
125 return result; | |
126 } | |
127 | |
128 void ensureReturn(FunctionExpression node) { | |
129 if (!context.returnOnAllBranches) { | |
130 IrConstant nullValue = | |
131 context.enterConstant(constantSystem.createNull(), node); | |
132 context.enterStatement(new IrReturn(nodePosition(node), nullValue)); | |
133 } | |
134 } | |
135 | |
136 IrNode visitBlock(Block node) { | |
137 for (Node n in node.statements.nodes) { | |
138 n.accept(this); | |
139 } | |
140 } | |
141 | |
142 IrNode visitReturn(Return node) { | |
143 IrNode value; | |
144 if (node.expression == null) { | |
145 if (node.beginToken.value == 'native') return giveup(); | |
146 value = context.enterConstant(constantSystem.createNull(), node); | |
147 } else { | |
148 value = node.expression.accept(this); | |
149 } | |
150 context.branchReturns(); | |
151 return context.enterStatement( | |
152 new IrReturn(nodePosition(node), value)); | |
153 } | |
154 | |
155 IrConstant visitLiteralBool(LiteralBool node) => | |
156 context.enterConstant(constantSystem.createBool(node.value), node); | |
157 | |
158 IrConstant visitLiteralDouble(LiteralDouble node) => | |
159 context.enterConstant(constantSystem.createDouble(node.value), node); | |
160 | |
161 IrConstant visitLiteralInt(LiteralInt node) => | |
162 context.enterConstant(constantSystem.createInt(node.value), node); | |
163 | |
164 IrConstant visitLiteralString(LiteralString node) => | |
165 context.enterConstant( | |
166 constantSystem.createString(node.dartString, node), node); | |
167 | |
168 IrConstant visitLiteralNull(LiteralNull node) => | |
169 context.enterConstant(constantSystem.createNull(), node); | |
170 | |
171 // IrNode visitLiteralList(LiteralList node) => visitExpression(node); | |
172 // IrNode visitLiteralMap(LiteralMap node) => visitExpression(node); | |
173 // IrNode visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node); | |
174 // IrNode visitLiteralSymbol(LiteralSymbol node) => visitExpression(node); | |
175 | |
176 | |
177 IrNode visitAssert(Send node) { | |
178 return giveup(); | |
179 } | |
180 | |
181 IrNode visitClosureSend(Send node) { | |
182 return giveup(); | |
183 } | |
184 | |
185 IrNode visitDynamicSend(Send node) { | |
186 return giveup(); | |
187 } | |
188 | |
189 IrNode visitGetterSend(Send node) { | |
190 return giveup(); | |
191 } | |
192 | |
193 IrNode visitOperatorSend(Send node) { | |
194 return giveup(); | |
195 } | |
196 | |
197 IrNode visitStaticSend(Send node) { | |
198 return giveup(); | |
199 } | |
200 | |
201 IrNode visitSuperSend(Send node) { | |
202 return giveup(); | |
203 } | |
204 | |
205 IrNode visitTypeReferenceSend(Send node) { | |
206 return giveup(); | |
207 } | |
208 | |
209 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | |
210 | |
211 IrNode giveup() => throw ABORT_IRNODE_BUILDER; | |
212 | |
213 void internalError(String reason, {Node node}) { | |
214 giveup(); | |
215 } | |
216 } | |
217 | |
218 class Context { | |
219 IrNodeBuilderVisitor visitor; | |
220 Context(this.visitor); | |
221 | |
222 List<IrFunction> currentFunctionList = <IrFunction>[]; | |
223 IrFunction get currentFunction => currentFunctionList.last; | |
ngeoffray
2013/11/20 14:55:27
Actually, we will probably not inline at this leve
lukas
2013/11/21 12:20:21
Maybe we want to keep nested functions as such in
| |
224 | |
225 // TODO(lry): Need to fix this once we actually have branching. The things we | |
226 // currently achieve with the Conctext class might overlap with LocalHandlers. | |
ngeoffray
2013/11/20 14:55:27
Conctext -> Context
lukas
2013/11/21 12:20:21
Done.
| |
227 List<bool> returnOnAllBranchesList = <bool>[]; | |
228 bool get returnOnAllBranches => returnOnAllBranchesList.last; | |
229 void branchReturns() { | |
230 returnOnAllBranchesList[returnOnAllBranchesList.length - 1] = true; | |
231 } | |
232 | |
233 List<List<IrNode>> statementsList = <List<IrNode>>[]; | |
234 List<IrNode> get statements => statementsList.last; | |
235 | |
236 List<List<IrConstant>> constantsList = <List<IrConstant>>[]; | |
237 List<IrConstant> get constants => constantsList.last; | |
238 | |
239 IrConstant enterConstant(Constant value, Node node) { | |
ngeoffray
2013/11/20 14:55:27
Why not a Map of Constant -> IrConstant? Like we h
lukas
2013/11/21 12:20:21
Done.
| |
240 return constants.firstWhere((c) => c.value == value, orElse: () { | |
241 IrConstant c = new IrConstant(visitor.nodePosition(node), value); | |
242 constants.add(c); | |
243 return c; | |
244 }); | |
245 } | |
246 | |
247 IrNode enterStatement(IrNode statement) { | |
248 statements.add(statement); | |
249 return statement; | |
250 } | |
251 | |
252 void openFunction(IrFunction function) { | |
253 currentFunctionList.add(function); | |
254 statementsList.add(<IrNode>[]); | |
255 returnOnAllBranchesList.add(false); | |
256 constantsList.add(<IrConstant>[]); | |
257 } | |
258 | |
259 void closeFunction() { | |
260 currentFunctionList.removeLast(); | |
261 statementsList.removeLast(); | |
262 returnOnAllBranchesList.removeLast(); | |
263 constantsList.removeLast(); | |
264 } | |
265 | |
266 void openContinuation() { | |
ngeoffray
2013/11/20 14:55:27
Unused.
lukas
2013/11/21 12:20:21
Done.
| |
267 statementsList.add(<IrNode>[]); | |
268 } | |
269 | |
270 void closeContinuation() { | |
ngeoffray
2013/11/20 14:55:27
Unused.
lukas
2013/11/21 12:20:21
Done.
| |
271 statementsList.removeLast(); | |
272 } | |
273 | |
274 isTopLevel() => currentFunctionList.isEmpty; | |
275 } | |
OLD | NEW |