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

Side by Side Diff: gen.dart

Issue 8343037: Throw FallThroughError when we fall through a case in a switch statement. Fixes (Closed) Base URL: http://dart.googlecode.com/svn/experimental/frog/
Patch Set: '' Created 9 years, 1 month 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
« no previous file with comments | « frogsh ('k') | lib/corelib.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « frogsh ('k') | lib/corelib.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698