Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 /** | 5 /** |
| 6 * Top level generator object for writing code and keeping track of | 6 * Top level generator object for writing code and keeping track of |
| 7 * dependencies. | 7 * dependencies. |
| 8 * | 8 * |
| 9 * Should have two compilation models, but only one implemented so far. | 9 * Should have two compilation models, but only one implemented so far. |
| 10 * | 10 * |
| (...skipping 1054 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1065 void visitFunctionDefinition(FunctionDefinition node) { | 1065 void visitFunctionDefinition(FunctionDefinition node) { |
| 1066 var name = world.toJsIdentifier(node.name.name); | 1066 var name = world.toJsIdentifier(node.name.name); |
| 1067 | 1067 |
| 1068 var meth = _makeLambdaMethod(name, node); | 1068 var meth = _makeLambdaMethod(name, node); |
| 1069 | 1069 |
| 1070 // TODO(jimhug): Pass js name into writeDefinition? | 1070 // TODO(jimhug): Pass js name into writeDefinition? |
| 1071 var funcValue = _scope.create(name, meth.functionType, method.definition); | 1071 var funcValue = _scope.create(name, meth.functionType, method.definition); |
| 1072 meth.generator.writeDefinition(writer, null); | 1072 meth.generator.writeDefinition(writer, null); |
| 1073 } | 1073 } |
| 1074 | 1074 |
| 1075 void visitReturnStatement(ReturnStatement node) { | 1075 /** |
| 1076 * Returns true indicating that code will return after executing this | |
|
jimhug
2011/10/28 14:33:34
Returns true indicating that normal control-flow i
| |
| 1077 * statement. | |
| 1078 */ | |
| 1079 bool visitReturnStatement(ReturnStatement node) { | |
| 1076 if (node.value == null) { | 1080 if (node.value == null) { |
| 1077 writer.writeln('return;'); | 1081 writer.writeln('return;'); |
| 1078 } else { | 1082 } else { |
| 1079 writer.writeln('return ${visitValue(node.value).code};'); | 1083 writer.writeln('return ${visitValue(node.value).code};'); |
| 1080 } | 1084 } |
| 1085 return true; | |
| 1081 } | 1086 } |
| 1082 | 1087 |
| 1083 void visitThrowStatement(ThrowStatement node) { | 1088 bool visitThrowStatement(ThrowStatement node) { |
| 1084 // Dart allows throwing anything, just like JS | 1089 // Dart allows throwing anything, just like JS |
| 1085 if (node.value != null) { | 1090 if (node.value != null) { |
| 1086 var value = visitValue(node.value); | 1091 var value = visitValue(node.value); |
| 1087 // Ensure that we generate a toString() method for things that we throw | 1092 // Ensure that we generate a toString() method for things that we throw |
| 1088 value.invoke(parent, 'toString', node, Arguments.EMPTY); | 1093 value.invoke(parent, 'toString', node, Arguments.EMPTY); |
| 1089 writer.writeln('\$throw(${value.code});'); | 1094 writer.writeln('\$throw(${value.code});'); |
| 1090 } else { | 1095 } else { |
| 1091 var rethrow = _scope.getRethrow(); | 1096 var rethrow = _scope.getRethrow(); |
| 1092 if (rethrow == null) { | 1097 if (rethrow == null) { |
| 1093 world.error('rethrow outside of catch', node.span); | 1098 world.error('rethrow outside of catch', node.span); |
| 1094 } else { | 1099 } else { |
| 1095 // Use a normal throw instead of $throw so we don't capture a new stack | 1100 // Use a normal throw instead of $throw so we don't capture a new stack |
| 1096 writer.writeln('throw ${rethrow.code};'); | 1101 writer.writeln('throw ${rethrow.code};'); |
| 1097 } | 1102 } |
| 1098 } | 1103 } |
| 1104 return true; | |
| 1099 } | 1105 } |
| 1100 | 1106 |
| 1101 void visitAssertStatement(AssertStatement node) { | 1107 void visitAssertStatement(AssertStatement node) { |
|
jimhug
2011/10/28 14:33:34
For type safety, you need to update all of the oth
| |
| 1102 // be sure to walk test for static checking even is asserts disabled | 1108 // be sure to walk test for static checking even is asserts disabled |
| 1103 var test = visitValue(node.test); // TODO(jimhug): check bool or callable. | 1109 var test = visitValue(node.test); // TODO(jimhug): check bool or callable. |
| 1104 if (options.enableAsserts) { | 1110 if (options.enableAsserts) { |
| 1105 var err = world.corelib.types['AssertError']; | 1111 var err = world.corelib.types['AssertError']; |
| 1106 err.markUsed(); | 1112 err.markUsed(); |
| 1107 parent.genMethod(err.getConstructor('')); | 1113 parent.genMethod(err.getConstructor('')); |
| 1108 parent.genMethod(err.members['toString']); | 1114 parent.genMethod(err.members['toString']); |
| 1109 var span = node.test.span; | 1115 var span = node.test.span; |
| 1110 | 1116 |
| 1111 var line = span.file.getLine(span.start); | 1117 var line = span.file.getLine(span.start); |
| 1112 var column = span.file.getColumn(line, span.start); | 1118 var column = span.file.getColumn(line, span.start); |
| 1113 writer.writeln('\$assert(${test.code}, "${_escapeString(span.text)}",' + | 1119 writer.writeln('\$assert(${test.code}, "${_escapeString(span.text)}",' + |
| 1114 ' "${span.file.filename}", ${line + 1}, ${column + 1});'); | 1120 ' "${span.file.filename}", ${line + 1}, ${column + 1});'); |
| 1115 } | 1121 } |
| 1116 } | 1122 } |
| 1117 | 1123 |
| 1118 void visitBreakStatement(BreakStatement node) { | 1124 bool visitBreakStatement(BreakStatement node) { |
| 1119 // TODO(jimhug): Lots of flow error checking here and below. | 1125 // TODO(jimhug): Lots of flow error checking here and below. |
| 1120 if (node.label == null) { | 1126 if (node.label == null) { |
| 1121 writer.writeln('break;'); | 1127 writer.writeln('break;'); |
| 1122 } else { | 1128 } else { |
| 1123 writer.writeln('break ${node.label.name};'); | 1129 writer.writeln('break ${node.label.name};'); |
| 1124 } | 1130 } |
| 1131 return true; | |
| 1125 } | 1132 } |
| 1126 | 1133 |
| 1127 void visitContinueStatement(ContinueStatement node) { | 1134 bool visitContinueStatement(ContinueStatement node) { |
| 1128 if (node.label == null) { | 1135 if (node.label == null) { |
| 1129 writer.writeln('continue;'); | 1136 writer.writeln('continue;'); |
| 1130 } else { | 1137 } else { |
| 1131 writer.writeln('continue ${node.label.name};'); | 1138 writer.writeln('continue ${node.label.name};'); |
| 1132 } | 1139 } |
| 1140 return true; | |
| 1133 } | 1141 } |
| 1134 | 1142 |
| 1135 void visitIfStatement(IfStatement node) { | 1143 bool visitIfStatement(IfStatement node) { |
| 1136 var test = visitBool(node.test); | 1144 var test = visitBool(node.test); |
| 1145 var return1, return2; | |
|
jimhug
2011/10/28 14:33:34
I'd suggest the name "exit" here instead of return
Emily Fortuna
2011/10/28 17:23:23
I tested this out before I wrote this, and if(null
| |
| 1137 writer.write('if (${test.code}) '); | 1146 writer.write('if (${test.code}) '); |
| 1138 node.trueBranch.visit(this); | 1147 return1 = node.trueBranch.visit(this); |
| 1139 if (node.falseBranch != null) { | 1148 if (node.falseBranch != null) { |
| 1140 writer.write('else '); | 1149 writer.write('else '); |
| 1141 node.falseBranch.visit(this); | 1150 return2 = node.falseBranch.visit(this); |
|
jimhug
2011/10/28 14:33:34
if (node.falseBranch.visit(this) && exit1) return
| |
| 1142 } | 1151 } |
| 1152 return (return1 && return2); | |
|
jimhug
2011/10/28 14:33:34
return false;
| |
| 1143 } | 1153 } |
| 1144 | 1154 |
| 1145 void visitWhileStatement(WhileStatement node) { | 1155 void visitWhileStatement(WhileStatement node) { |
| 1146 var test = visitBool(node.test); | 1156 var test = visitBool(node.test); |
| 1147 writer.write('while (${test.code}) '); | 1157 writer.write('while (${test.code}) '); |
| 1148 _pushBlock(/*reentrant:*/true); | 1158 _pushBlock(/*reentrant:*/true); |
| 1149 node.body.visit(this); | 1159 node.body.visit(this); |
| 1150 _popBlock(); | 1160 _popBlock(); |
| 1151 } | 1161 } |
| 1152 | 1162 |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1321 writer.nextBlock('} finally {'); | 1331 writer.nextBlock('} finally {'); |
| 1322 _pushBlock(); | 1332 _pushBlock(); |
| 1323 visitStatementsInBlock(node.finallyBlock); | 1333 visitStatementsInBlock(node.finallyBlock); |
| 1324 _popBlock(); | 1334 _popBlock(); |
| 1325 } | 1335 } |
| 1326 | 1336 |
| 1327 // Close the try-catch-finally | 1337 // Close the try-catch-finally |
| 1328 writer.exitBlock('}'); | 1338 writer.exitBlock('}'); |
| 1329 } | 1339 } |
| 1330 | 1340 |
| 1331 void visitSwitchStatement(SwitchStatement node) { | 1341 bool visitSwitchStatement(SwitchStatement node) { |
| 1332 // TODO(jimhug): Lots of negative tests to check for. | 1342 // TODO(jimhug): Lots of negative tests to check for. |
| 1333 var test = visitValue(node.test); | 1343 var test = visitValue(node.test); |
| 1334 writer.enterBlock('switch (${test.code}) {'); | 1344 writer.enterBlock('switch (${test.code}) {'); |
| 1345 bool allCasesReturn = true; | |
|
jimhug
2011/10/28 14:33:34
I don't think that you can use this effectively he
| |
| 1335 for (var case_ in node.cases) { | 1346 for (var case_ in node.cases) { |
| 1336 if (case_.label != null) { | 1347 if (case_.label != null) { |
| 1337 world.error('unimplemented: labeled case statement', case_.span); | 1348 world.error('unimplemented: labeled case statement', case_.span); |
| 1338 } | 1349 } |
| 1339 _pushBlock(); | 1350 _pushBlock(); |
| 1340 for (int i=0; i < case_.cases.length; i++) { | 1351 for (int i=0; i < case_.cases.length; i++) { |
| 1341 var expr = case_.cases[i]; | 1352 var expr = case_.cases[i]; |
| 1342 if (expr == null) { | 1353 if (expr == null) { |
| 1343 // Default can only be the last case. | 1354 // Default can only be the last case. |
| 1344 if (i < case_.cases.length - 1) { | 1355 if (i < case_.cases.length - 1) { |
| 1345 world.error('default clause must be the last case', case_.span); | 1356 world.error('default clause must be the last case', case_.span); |
| 1346 } | 1357 } |
| 1347 writer.writeln('default:'); | 1358 writer.writeln('default:'); |
| 1348 } else { | 1359 } else { |
| 1349 var value = visitValue(expr); | 1360 var value = visitValue(expr); |
| 1350 writer.writeln('case ${value.code}:'); | 1361 writer.writeln('case ${value.code}:'); |
| 1351 } | 1362 } |
| 1352 } | 1363 } |
| 1353 writer.enterBlock(''); | 1364 writer.enterBlock(''); |
| 1365 bool caseReturns; | |
|
jimhug
2011/10/28 14:33:34
This needs to be initialized to false.
| |
| 1354 for (var stmt in case_.statements) { | 1366 for (var stmt in case_.statements) { |
| 1355 stmt.visit(this); | 1367 caseReturns = stmt.visit(this); |
|
jimhug
2011/10/28 14:33:34
This should have the same checking for previous st
| |
| 1356 } | 1368 } |
| 1357 if (case_ != node.cases[node.cases.length - 1]) { | 1369 if (case_ != node.cases[node.cases.length - 1] && !caseReturns) { |
| 1358 var span = case_.statements[case_.statements.length - 1].span; | 1370 var span = case_.statements[case_.statements.length - 1].span; |
| 1371 //TODO(efortuna): This error message isn't 100% correct because | |
| 1372 // constructors are not being built correctly. Check back when I've | |
| 1373 // fixed constructors. | |
| 1374 writer.writeln('\$throw(new FallThroughError("${span.file.filename}",' + | |
| 1375 ' ${span.file.getLine(span.start)}))'); | |
| 1376 allCasesReturn = false; | |
|
jimhug
2011/10/28 14:33:34
See above on allCasesReturn - but this shouldn't b
| |
| 1359 } | 1377 } |
| 1360 writer.exitBlock(''); | 1378 writer.exitBlock(''); |
| 1361 _popBlock(); | 1379 _popBlock(); |
| 1362 } | 1380 } |
| 1363 writer.exitBlock('}'); | 1381 writer.exitBlock('}'); |
| 1382 return allCasesReturn; | |
|
jimhug
2011/10/28 14:33:34
return false;
| |
| 1364 } | 1383 } |
| 1365 | 1384 |
| 1366 void visitBlockStatement(BlockStatement node) { | 1385 bool visitBlockStatement(BlockStatement node) { |
| 1367 _pushBlock(); | 1386 _pushBlock(); |
| 1368 writer.enterBlock('{'); | 1387 writer.enterBlock('{'); |
| 1388 var returns; | |
|
jimhug
2011/10/28 14:33:34
Needs to be initialized.
| |
| 1369 for (var stmt in node.body) { | 1389 for (var stmt in node.body) { |
| 1370 stmt.visit(this); | 1390 returns = stmt.visit(this); |
|
Emily Fortuna
2011/10/27 22:11:24
I should add a warning here if we have a return st
jimhug
2011/10/28 14:33:34
I think that your warning should work here just fi
| |
| 1371 } | 1391 } |
| 1372 writer.exitBlock('}'); | 1392 writer.exitBlock('}'); |
| 1373 _popBlock(); | 1393 _popBlock(); |
| 1394 return returns; | |
| 1374 } | 1395 } |
| 1375 | 1396 |
| 1376 void visitLabeledStatement(LabeledStatement node) { | 1397 void visitLabeledStatement(LabeledStatement node) { |
| 1377 writer.writeln('${node.name.name}:'); | 1398 writer.writeln('${node.name.name}:'); |
| 1378 node.body.visit(this); | 1399 node.body.visit(this); |
| 1379 } | 1400 } |
| 1380 | 1401 |
| 1381 void visitExpressionStatement(ExpressionStatement node) { | 1402 void visitExpressionStatement(ExpressionStatement node) { |
| 1382 if (node.body is VarExpression || node.body is ThisExpression) { | 1403 if (node.body is VarExpression || node.body is ThisExpression) { |
| 1383 // TODO(jmesserly): this is a "warning" but not a "type warning", | 1404 // TODO(jmesserly): this is a "warning" but not a "type warning", |
| (...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2142 | 2163 |
| 2143 static removeTrailingNulls(List<Value> argsCode) { | 2164 static removeTrailingNulls(List<Value> argsCode) { |
| 2144 // We simplify calls with null defaults by relying on JS and our | 2165 // We simplify calls with null defaults by relying on JS and our |
| 2145 // choice to make undefined === null for Dart generated code. This helps | 2166 // choice to make undefined === null for Dart generated code. This helps |
| 2146 // and ensures correct defaults values for native calls. | 2167 // and ensures correct defaults values for native calls. |
| 2147 while (argsCode.length > 0 && argsCode.last() == 'null') { | 2168 while (argsCode.length > 0 && argsCode.last() == 'null') { |
| 2148 argsCode.removeLast(); | 2169 argsCode.removeLast(); |
| 2149 } | 2170 } |
| 2150 } | 2171 } |
| 2151 } | 2172 } |
| OLD | NEW |