Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(401)

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 725293004: Add support for if, while, break, continue to js-cps (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add test file Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library code_generator; 5 library code_generator;
6 6
7 import 'glue.dart'; 7 import 'glue.dart';
8 8
9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; 9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
10 import '../../js/js.dart' as js; 10 import '../../js/js.dart' as js;
(...skipping 21 matching lines...) Expand all
32 /// Maps variables to their name. 32 /// Maps variables to their name.
33 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; 33 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
34 34
35 /// Maps local constants to their name. 35 /// Maps local constants to their name.
36 Maplet<VariableElement, String> constantNames = 36 Maplet<VariableElement, String> constantNames =
37 new Maplet<VariableElement, String>(); 37 new Maplet<VariableElement, String>();
38 38
39 /// Variable names that have already been used. Used to avoid name clashes. 39 /// Variable names that have already been used. Used to avoid name clashes.
40 Set<String> usedVariableNames = new Set<String>(); 40 Set<String> usedVariableNames = new Set<String>();
41 41
42 List<js.Parameter> parameters = new List<js.Parameter>(); 42 /// Input to [visitStatement]. Denotes the statement that will execute next
43 /// if the statements produced by [visitStatement] complete normally.
44 /// Set to null if control will fall over the end of the method.
45 tree_ir.Statement fallthrough = null;
46
47 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
48
43 List<js.Statement> accumulator = new List<js.Statement>(); 49 List<js.Statement> accumulator = new List<js.Statement>();
44 50
45 js.Block body; 51 CodeGenerator(this.glue, this.registry);
46 52
47 /// Generates JavaScript code for the body of [function]. 53 /// Generates JavaScript code for the body of [function].
48 /// The code will be in [body] and the parameters will be in [parameters]. 54 js.Fun buildFunction(tree_ir.FunctionDefinition function) {
49 CodeGenerator(this.glue, this.registry);
50
51 void buildFunction(tree_ir.FunctionDefinition function) {
52 currentFunction = function.element; 55 currentFunction = function.element;
53 visitStatement(function.body); 56 visitStatement(function.body);
54 57
58 List<js.Parameter> parameters = new List<js.Parameter>();
55 Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>(); 59 Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>();
56 60
57 for (tree_ir.Variable parameter in function.parameters) { 61 for (tree_ir.Variable parameter in function.parameters) {
58 String name = getVariableName(parameter); 62 String name = getVariableName(parameter);
59 parameters.add(new js.Parameter(name)); 63 parameters.add(new js.Parameter(name));
60 parameterSet.add(parameter); 64 parameterSet.add(parameter);
61 } 65 }
62 66
63 List<js.VariableInitialization> jsVariables = <js.VariableInitialization>[]; 67 List<js.VariableInitialization> jsVariables = <js.VariableInitialization>[];
64 68
65 for (tree_ir.Variable variable in variableNames.keys) { 69 for (tree_ir.Variable variable in variableNames.keys) {
66 if (parameterSet.contains(variable)) continue; 70 if (parameterSet.contains(variable)) continue;
67 String name = getVariableName(variable); 71 String name = getVariableName(variable);
68 js.VariableInitialization jsVariable = new js.VariableInitialization( 72 js.VariableInitialization jsVariable = new js.VariableInitialization(
69 new js.VariableDeclaration(name), 73 new js.VariableDeclaration(name),
70 null); 74 null);
71 jsVariables.add(jsVariable); 75 jsVariables.add(jsVariable);
72 } 76 }
73 77
74 if (jsVariables.length > 0) { 78 if (jsVariables.length > 0) {
75 // Would be nice to avoid inserting at the beginning of list. 79 // Would be nice to avoid inserting at the beginning of list.
76 accumulator.insert(0, new js.ExpressionStatement( 80 accumulator.insert(0, new js.ExpressionStatement(
77 new js.VariableDeclarationList(jsVariables))); 81 new js.VariableDeclarationList(jsVariables)));
78 } 82 }
79 body = new js.Block(accumulator); 83 return new js.Fun(parameters, new js.Block(accumulator));
80 } 84 }
81 85
82 js.Expression visit(tree_ir.Expression node) { 86 js.Expression visit(tree_ir.Expression node) {
83 js.Expression result = node.accept(this); 87 js.Expression result = node.accept(this);
84 if (result == null) { 88 if (result == null) {
85 glue.reportInternalError('$node did not produce code.'); 89 glue.reportInternalError('$node did not produce code.');
86 } 90 }
87 return result; 91 return result;
88 } 92 }
89 93
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 // TODO: implement visitLiteralMap 213 // TODO: implement visitLiteralMap
210 } 214 }
211 215
212 @override 216 @override
213 js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) { 217 js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
214 return new js.Binary(node.operator, visit(node.left), visit(node.right)); 218 return new js.Binary(node.operator, visit(node.left), visit(node.right));
215 } 219 }
216 220
217 @override 221 @override
218 js.Expression visitNot(tree_ir.Not node) { 222 js.Expression visitNot(tree_ir.Not node) {
219 return giveup(node); 223 return new js.Prefix("!", visitExpression(node.operand));
220 // TODO: implement visitNot
221 } 224 }
222 225
223 @override 226 @override
224 js.Expression visitReifyTypeVar(tree_ir.ReifyTypeVar node) { 227 js.Expression visitReifyTypeVar(tree_ir.ReifyTypeVar node) {
225 return giveup(node); 228 return giveup(node);
226 // TODO: implement visitReifyTypeVar 229 // TODO: implement visitReifyTypeVar
227 } 230 }
228 231
229 @override 232 @override
230 js.Expression visitThis(tree_ir.This node) { 233 js.Expression visitThis(tree_ir.This node) {
231 // TODO(sigurdm): Inside a js closure this will not work. 234 // TODO(sigurdm): Inside a js closure this will not work.
232 return new js.This(); 235 return new js.This();
233 } 236 }
234 237
235 @override 238 @override
236 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { 239 js.Expression visitTypeOperator(tree_ir.TypeOperator node) {
237 return giveup(node); 240 return giveup(node);
238 // TODO: implement visitTypeOperator 241 // TODO: implement visitTypeOperator
239 } 242 }
240 243
241 @override 244 @override
242 js.Expression visitVariable(tree_ir.Variable node) { 245 js.Expression visitVariable(tree_ir.Variable node) {
243 return new js.VariableUse(getVariableName(node)); 246 return new js.VariableUse(getVariableName(node));
244 } 247 }
245 248
246 @override 249 @override
247 void visitContinue(tree_ir.Continue node) { 250 void visitContinue(tree_ir.Continue node) {
248 return giveup(node); 251 tree_ir.Statement fallthrough = this.fallthrough;
249 // TODO: implement visitContinue 252 if (node.target.binding == fallthrough) {
253 // Fall through to continue target
254 } else if (fallthrough is tree_ir.Continue &&
255 fallthrough.target == node.target) {
256 // Fall through to equivalent continue
257 } else {
258 usedLabels.add(node.target);
259 accumulator.add(new js.Continue(node.target.name));
260 }
250 } 261 }
251 262
252 @override 263 @override
253 void visitExpressionStatement(tree_ir.ExpressionStatement node) { 264 void visitExpressionStatement(tree_ir.ExpressionStatement node) {
254 accumulator.add(new js.ExpressionStatement( 265 accumulator.add(new js.ExpressionStatement(
255 visitExpression(node.expression))); 266 visitExpression(node.expression)));
256 visitStatement(node.next); 267 visitStatement(node.next);
257 } 268 }
258 269
259 @override 270 @override
260 void visitFunctionDeclaration(tree_ir.FunctionDeclaration node) { 271 void visitFunctionDeclaration(tree_ir.FunctionDeclaration node) {
261 giveup(node); 272 giveup(node);
262 // TODO: implement visitFunctionDeclaration 273 // TODO: implement visitFunctionDeclaration
263 } 274 }
264 275
265 @override 276 @override
266 void visitIf(tree_ir.If node) { 277 void visitIf(tree_ir.If node) {
267 giveup(node); 278 js.Statement elseStatement = buildBody(node.elseStatement);
268 // TODO: implement visitIf 279 accumulator.add(new js.If(visitExpression(node.condition),
280 buildBody(node.thenStatement),
281 elseStatement is js.EmptyStatement
282 ? new js.EmptyStatement()
floitsch 2014/11/24 16:37:47 why? looks like just "elseStatement" would do it.
sigurdm 2014/11/25 08:29:50 Right - I had a null check here, but it was unnece
283 : elseStatement));
269 } 284 }
270 285
271 @override 286 @override
272 void visitLabeledStatement(tree_ir.LabeledStatement node) { 287 void visitLabeledStatement(tree_ir.LabeledStatement node) {
273 giveup(node); 288 accumulator.add(buildLabeled(() => buildBody(node.body),
274 // TODO: implement visitLabeledStatement 289 node.label,
290 node.next));
291 visitStatement(node.next);
292 }
293
294 js.Statement buildLabeled(js.Statement buildBody(),
295 tree_ir.Label label,
296 tree_ir.Statement fallthroughStatement) {
297 tree_ir.Statement savedFallthrough = fallthrough;
298 fallthrough = fallthroughStatement;
299 js.Statement result = buildBody();
300 if (usedLabels.remove(label)) {
301 result = new js.LabeledStatement(label.name, result);
302 }
303 fallthrough = savedFallthrough;
304 return result;
275 } 305 }
276 306
277 @override 307 @override
278 void visitAssign(tree_ir.Assign node) { 308 void visitAssign(tree_ir.Assign node) {
279 tree_ir.Expression value = node.definition; 309 tree_ir.Expression value = node.definition;
280 js.Expression definition = visitExpression(value); 310 js.Expression definition = visitExpression(value);
281 311
282 accumulator.add(new js.ExpressionStatement(new js.Assignment( 312 accumulator.add(new js.ExpressionStatement(new js.Assignment(
283 visitVariable(node.variable), 313 visitVariable(node.variable),
284 definition))); 314 definition)));
285 visitStatement(node.next); 315 visitStatement(node.next);
286 } 316 }
287 317
288 @override 318 @override
289 void visitBreak(tree_ir.Break node) { 319 void visitBreak(tree_ir.Break node) {
290 giveup(node); 320 tree_ir.Statement fallthrough = this.fallthrough;
291 // TODO: implement visitBreak 321 if (node.target.binding.next == fallthrough) {
322 // Fall through to break target
323 } else if (fallthrough is tree_ir.Break &&
324 fallthrough.target == node.target) {
325 // Fall through to equivalent break
326 } else {
327 usedLabels.add(node.target);
328 accumulator.add(new js.Break(node.target.name));
329 }
330 }
331
332 /// Returns the current [accumulator] wrapped in a block if neccessary.
333 js.Statement _bodyAsStatement() {
334 if (accumulator.length == 0) {
335 return new js.EmptyStatement();
336 }
337 if (accumulator.length == 1) {
338 return accumulator.single;
339 }
340 return new js.Block(accumulator);
341 }
342
343 /// Builds a nested statement.
344 js.Statement buildBody(tree_ir.Statement statement) {
345 List<js.Statement> savedAccumulator = accumulator;
346 accumulator = new List<js.Statement>();
347 visitStatement(statement);
348 js.Statement result = _bodyAsStatement();
349 accumulator = savedAccumulator;
350 return result;
351 }
352
353 js.Statement buildWhile(js.Expression condition,
354 tree_ir.Statement body,
355 tree_ir.Label label,
356 tree_ir.Statement fallthroughStatement) {
357 return buildLabeled(() => new js.While(condition, buildBody(body)),
358 label,
359 fallthroughStatement);
292 } 360 }
293 361
294 @override 362 @override
295 void visitWhileCondition(tree_ir.WhileCondition node) { 363 void visitWhileCondition(tree_ir.WhileCondition node) {
296 giveup(node); 364 accumulator.add(
297 // TODO: implement visitWhileCondition 365 buildWhile(visitExpression(node.condition),
366 node.body,
367 node.label,
368 node));
369 visitStatement(node.next);
298 } 370 }
299 371
300 @override 372 @override
301 void visitWhileTrue(tree_ir.WhileTrue node) { 373 void visitWhileTrue(tree_ir.WhileTrue node) {
302 giveup(node); 374 accumulator.add(
303 // TODO: implement visitWhileTrue 375 buildWhile(new js.LiteralBool(true), node.body, node.label, node));
304 } 376 }
305 377
306 @override 378 @override
307 void visitReturn(tree_ir.Return node) { 379 void visitReturn(tree_ir.Return node) {
308 accumulator.add(new js.Return(visitExpression(node.value))); 380 accumulator.add(new js.Return(visitExpression(node.value)));
309 } 381 }
310 382
311 bool isNullLiteral(js.Expression exp) => exp is js.LiteralNull;
312
313 } 383 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698