OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 rewrite_async; | 5 library rewrite_async; |
6 | 6 |
7 import "dart:math" show max; | 7 import "dart:math" show max; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 | 9 |
10 import 'package:js_runtime/shared/async_await_error_codes.dart' as error_codes; | 10 import 'package:js_runtime/shared/async_await_error_codes.dart' as error_codes; |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 labelComments[result] = comment; | 276 labelComments[result] = comment; |
277 } | 277 } |
278 return result; | 278 return result; |
279 } | 279 } |
280 | 280 |
281 /// Begins outputting statements to a new buffer with label [label]. | 281 /// Begins outputting statements to a new buffer with label [label]. |
282 /// | 282 /// |
283 /// Each buffer ends up as its own case part in the big state-switch. | 283 /// Each buffer ends up as its own case part in the big state-switch. |
284 void beginLabel(int label) { | 284 void beginLabel(int label) { |
285 assert(!labelledParts.containsKey(label)); | 285 assert(!labelledParts.containsKey(label)); |
286 currentStatementBuffer = <js.Statement>[]; | 286 currentStatementBuffer = new List<js.Statement>(); |
287 labelledParts[label] = currentStatementBuffer; | 287 labelledParts[label] = currentStatementBuffer; |
288 addStatement(new js.Comment(labelComments[label])); | 288 addStatement(new js.Comment(labelComments[label])); |
289 } | 289 } |
290 | 290 |
291 /// Returns a statement assigning to the variable named [gotoName]. | 291 /// Returns a statement assigning to the variable named [gotoName]. |
292 /// This should be followed by a break for the goto to be executed. Use | 292 /// This should be followed by a break for the goto to be executed. Use |
293 /// [gotoWithBreak] or [addGoto] for this. | 293 /// [gotoWithBreak] or [addGoto] for this. |
294 js.Statement setGotoVariable(int label) { | 294 js.Statement setGotoVariable(int label) { |
295 return js.js.statement('# = #;', [goto, js.number(label)]); | 295 return js.js.statement('# = #;', [goto, js.number(label)]); |
296 } | 296 } |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
960 | 960 |
961 @override | 961 @override |
962 void visitDefault(js.Default node) => unreachable(node); | 962 void visitDefault(js.Default node) => unreachable(node); |
963 | 963 |
964 @override | 964 @override |
965 void visitDo(js.Do node) { | 965 void visitDo(js.Do node) { |
966 if (!shouldTransform(node)) { | 966 if (!shouldTransform(node)) { |
967 bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable; | 967 bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable; |
968 insideUntranslatedBreakable = true; | 968 insideUntranslatedBreakable = true; |
969 addStatement(js.js.statement('do {#} while (#)', | 969 addStatement(js.js.statement('do {#} while (#)', |
970 [translateToStatement(node.body), visitExpression(node.condition)])); | 970 [translateInBlock(node.body), visitExpression(node.condition)])); |
971 insideUntranslatedBreakable = oldInsideUntranslatedBreakable; | 971 insideUntranslatedBreakable = oldInsideUntranslatedBreakable; |
972 return; | 972 return; |
973 } | 973 } |
974 int startLabel = newLabel("do body"); | 974 int startLabel = newLabel("do body"); |
975 | 975 |
976 int continueLabel = newLabel("do condition"); | 976 int continueLabel = newLabel("do condition"); |
977 continueLabels[node] = continueLabel; | 977 continueLabels[node] = continueLabel; |
978 | 978 |
979 int afterLabel = newLabel("after do"); | 979 int afterLabel = newLabel("after do"); |
980 breakLabels[node] = afterLabel; | 980 breakLabels[node] = afterLabel; |
(...skipping 25 matching lines...) Expand all Loading... |
1006 @override | 1006 @override |
1007 void visitFor(js.For node) { | 1007 void visitFor(js.For node) { |
1008 if (!shouldTransform(node)) { | 1008 if (!shouldTransform(node)) { |
1009 bool oldInsideUntranslated = insideUntranslatedBreakable; | 1009 bool oldInsideUntranslated = insideUntranslatedBreakable; |
1010 insideUntranslatedBreakable = true; | 1010 insideUntranslatedBreakable = true; |
1011 // Note that node.init, node.condition, node.update all can be null, but | 1011 // Note that node.init, node.condition, node.update all can be null, but |
1012 // withExpressions handles that. | 1012 // withExpressions handles that. |
1013 withExpressions([node.init, node.condition, node.update], | 1013 withExpressions([node.init, node.condition, node.update], |
1014 (List<js.Expression> transformed) { | 1014 (List<js.Expression> transformed) { |
1015 addStatement(new js.For(transformed[0], transformed[1], transformed[2], | 1015 addStatement(new js.For(transformed[0], transformed[1], transformed[2], |
1016 translateToStatement(node.body))); | 1016 translateInBlock(node.body))); |
1017 }); | 1017 }); |
1018 insideUntranslatedBreakable = oldInsideUntranslated; | 1018 insideUntranslatedBreakable = oldInsideUntranslated; |
1019 return; | 1019 return; |
1020 } | 1020 } |
1021 | 1021 |
1022 if (node.init != null) { | 1022 if (node.init != null) { |
1023 visitExpressionIgnoreResult(node.init); | 1023 visitExpressionIgnoreResult(node.init); |
1024 } | 1024 } |
1025 int startLabel = newLabel("for condition"); | 1025 int startLabel = newLabel("for condition"); |
1026 // If there is no update, continuing the loop is the same as going to the | 1026 // If there is no update, continuing the loop is the same as going to the |
(...skipping 29 matching lines...) Expand all Loading... |
1056 void visitForIn(js.ForIn node) { | 1056 void visitForIn(js.ForIn node) { |
1057 // The dart output currently never uses for-in loops. | 1057 // The dart output currently never uses for-in loops. |
1058 throw "Javascript for-in not implemented yet in the await transformation"; | 1058 throw "Javascript for-in not implemented yet in the await transformation"; |
1059 } | 1059 } |
1060 | 1060 |
1061 @override | 1061 @override |
1062 void visitFunctionDeclaration(js.FunctionDeclaration node) { | 1062 void visitFunctionDeclaration(js.FunctionDeclaration node) { |
1063 unsupported(node); | 1063 unsupported(node); |
1064 } | 1064 } |
1065 | 1065 |
1066 List<js.Statement> translateToStatementSequence(js.Statement node) { | 1066 // Only used for code where `!shouldTransform(node)`. |
| 1067 js.Block translateInBlock(js.Statement node) { |
1067 assert(!shouldTransform(node)); | 1068 assert(!shouldTransform(node)); |
1068 List<js.Statement> oldBuffer = currentStatementBuffer; | 1069 List<js.Statement> oldBuffer = currentStatementBuffer; |
1069 currentStatementBuffer = <js.Statement>[]; | 1070 currentStatementBuffer = new List(); |
1070 List<js.Statement> resultBuffer = currentStatementBuffer; | 1071 List<js.Statement> resultBuffer = currentStatementBuffer; |
1071 visitStatement(node); | 1072 visitStatement(node); |
1072 currentStatementBuffer = oldBuffer; | 1073 currentStatementBuffer = oldBuffer; |
1073 return resultBuffer; | 1074 return new js.Block(resultBuffer); |
1074 } | |
1075 | |
1076 js.Statement translateToStatement(js.Statement node) { | |
1077 List<js.Statement> statements = translateToStatementSequence(node); | |
1078 if (statements.length == 1) | |
1079 return statements.single; | |
1080 return new js.Block(statements); | |
1081 } | |
1082 | |
1083 js.Block translateToBlock(js.Statement node) { | |
1084 return new js.Block(translateToStatementSequence(node)); | |
1085 } | 1075 } |
1086 | 1076 |
1087 @override | 1077 @override |
1088 void visitIf(js.If node) { | 1078 void visitIf(js.If node) { |
1089 if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) { | 1079 if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) { |
1090 withExpression(node.condition, (js.Expression condition) { | 1080 withExpression(node.condition, (js.Expression condition) { |
1091 js.Statement translatedThen = translateToStatement(node.then); | 1081 addStatement(new js.If(condition, translateInBlock(node.then), |
1092 js.Statement translatedElse = translateToStatement(node.otherwise); | 1082 translateInBlock(node.otherwise))); |
1093 addStatement(new js.If(condition, translatedThen, translatedElse)); | |
1094 }, store: false); | 1083 }, store: false); |
1095 return; | 1084 return; |
1096 } | 1085 } |
1097 int thenLabel = newLabel("then"); | 1086 int thenLabel = newLabel("then"); |
1098 int joinLabel = newLabel("join"); | 1087 int joinLabel = newLabel("join"); |
1099 int elseLabel = | 1088 int elseLabel = |
1100 (node.otherwise is js.EmptyStatement) ? joinLabel : newLabel("else"); | 1089 (node.otherwise is js.EmptyStatement) ? joinLabel : newLabel("else"); |
1101 | 1090 |
1102 withExpression(node.condition, (js.Expression condition) { | 1091 withExpression(node.condition, (js.Expression condition) { |
1103 addExpressionStatement(new js.Assignment( | 1092 addExpressionStatement(new js.Assignment( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1141 | 1130 |
1142 @override | 1131 @override |
1143 visitInterpolatedStatement(js.InterpolatedStatement node) { | 1132 visitInterpolatedStatement(js.InterpolatedStatement node) { |
1144 return unsupported(node); | 1133 return unsupported(node); |
1145 } | 1134 } |
1146 | 1135 |
1147 @override | 1136 @override |
1148 void visitLabeledStatement(js.LabeledStatement node) { | 1137 void visitLabeledStatement(js.LabeledStatement node) { |
1149 if (!shouldTransform(node)) { | 1138 if (!shouldTransform(node)) { |
1150 addStatement( | 1139 addStatement( |
1151 new js.LabeledStatement(node.label, translateToStatement(node.body))); | 1140 new js.LabeledStatement(node.label, translateInBlock(node.body))); |
1152 return; | 1141 return; |
1153 } | 1142 } |
1154 // `continue label` is really continuing the nested loop. | 1143 // `continue label` is really continuing the nested loop. |
1155 // This is set up in [PreTranslationAnalysis.visitContinue]. | 1144 // This is set up in [PreTranslationAnalysis.visitContinue]. |
1156 // Here we only need a breakLabel: | 1145 // Here we only need a breakLabel: |
1157 int breakLabel = newLabel("break ${node.label}"); | 1146 int breakLabel = newLabel("break ${node.label}"); |
1158 breakLabels[node] = breakLabel; | 1147 breakLabels[node] = breakLabel; |
1159 | 1148 |
1160 jumpTargets.add(node); | 1149 jumpTargets.add(node); |
1161 visitStatement(node.body); | 1150 visitStatement(node.body); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 @override | 1295 @override |
1307 void visitSwitch(js.Switch node) { | 1296 void visitSwitch(js.Switch node) { |
1308 if (!node.cases.any(shouldTransform)) { | 1297 if (!node.cases.any(shouldTransform)) { |
1309 // If only the key has an await, translation can be simplified. | 1298 // If only the key has an await, translation can be simplified. |
1310 bool oldInsideUntranslated = insideUntranslatedBreakable; | 1299 bool oldInsideUntranslated = insideUntranslatedBreakable; |
1311 insideUntranslatedBreakable = true; | 1300 insideUntranslatedBreakable = true; |
1312 withExpression(node.key, (js.Expression key) { | 1301 withExpression(node.key, (js.Expression key) { |
1313 List<js.SwitchClause> cases = node.cases.map((js.SwitchClause clause) { | 1302 List<js.SwitchClause> cases = node.cases.map((js.SwitchClause clause) { |
1314 if (clause is js.Case) { | 1303 if (clause is js.Case) { |
1315 return new js.Case( | 1304 return new js.Case( |
1316 clause.expression, translateToBlock(clause.body)); | 1305 clause.expression, translateInBlock(clause.body)); |
1317 } else if (clause is js.Default) { | 1306 } else if (clause is js.Default) { |
1318 return new js.Default(translateToBlock(clause.body)); | 1307 return new js.Default(translateInBlock(clause.body)); |
1319 } | 1308 } |
1320 }).toList(); | 1309 }).toList(); |
1321 addStatement(new js.Switch(key, cases)); | 1310 addStatement(new js.Switch(key, cases)); |
1322 }, store: false); | 1311 }, store: false); |
1323 insideUntranslatedBreakable = oldInsideUntranslated; | 1312 insideUntranslatedBreakable = oldInsideUntranslated; |
1324 return; | 1313 return; |
1325 } | 1314 } |
1326 int before = newLabel("switch"); | 1315 int before = newLabel("switch"); |
1327 int after = newLabel("after switch"); | 1316 int after = newLabel("after switch"); |
1328 breakLabels[node] = after; | 1317 breakLabels[node] = after; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1430 if (finallyLabel != null) { | 1419 if (finallyLabel != null) { |
1431 result.add(finallyLabel); | 1420 result.add(finallyLabel); |
1432 } | 1421 } |
1433 } | 1422 } |
1434 return result.reversed.toList(); | 1423 return result.reversed.toList(); |
1435 } | 1424 } |
1436 | 1425 |
1437 /// See the comments of [rewriteFunction] for more explanation. | 1426 /// See the comments of [rewriteFunction] for more explanation. |
1438 void visitTry(js.Try node) { | 1427 void visitTry(js.Try node) { |
1439 if (!shouldTransform(node)) { | 1428 if (!shouldTransform(node)) { |
1440 js.Block body = translateToBlock(node.body); | 1429 js.Block body = translateInBlock(node.body); |
1441 js.Catch catchPart = (node.catchPart == null) | 1430 js.Catch catchPart = (node.catchPart == null) |
1442 ? null | 1431 ? null |
1443 : new js.Catch(node.catchPart.declaration, | 1432 : new js.Catch(node.catchPart.declaration, |
1444 translateToBlock(node.catchPart.body)); | 1433 translateInBlock(node.catchPart.body)); |
1445 js.Block finallyPart = (node.finallyPart == null) | 1434 js.Block finallyPart = (node.finallyPart == null) |
1446 ? null | 1435 ? null |
1447 : translateToBlock(node.finallyPart); | 1436 : translateInBlock(node.finallyPart); |
1448 addStatement(new js.Try(body, catchPart, finallyPart)); | 1437 addStatement(new js.Try(body, catchPart, finallyPart)); |
1449 return; | 1438 return; |
1450 } | 1439 } |
1451 | 1440 |
1452 hasTryBlocks = true; | 1441 hasTryBlocks = true; |
1453 int uncaughtLabel = newLabel("uncaught"); | 1442 int uncaughtLabel = newLabel("uncaught"); |
1454 int handlerLabel = | 1443 int handlerLabel = |
1455 (node.catchPart == null) ? uncaughtLabel : newLabel("catch"); | 1444 (node.catchPart == null) ? uncaughtLabel : newLabel("catch"); |
1456 | 1445 |
1457 int finallyLabel = newLabel("finally"); | 1446 int finallyLabel = newLabel("finally"); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 if (renaming == null) return node; | 1569 if (renaming == null) return node; |
1581 return new js.VariableUse(renaming.b); | 1570 return new js.VariableUse(renaming.b); |
1582 } | 1571 } |
1583 | 1572 |
1584 @override | 1573 @override |
1585 void visitWhile(js.While node) { | 1574 void visitWhile(js.While node) { |
1586 if (!shouldTransform(node)) { | 1575 if (!shouldTransform(node)) { |
1587 bool oldInsideUntranslated = insideUntranslatedBreakable; | 1576 bool oldInsideUntranslated = insideUntranslatedBreakable; |
1588 insideUntranslatedBreakable = true; | 1577 insideUntranslatedBreakable = true; |
1589 withExpression(node.condition, (js.Expression condition) { | 1578 withExpression(node.condition, (js.Expression condition) { |
1590 addStatement(new js.While(condition, translateToStatement(node.body))); | 1579 addStatement(new js.While(condition, translateInBlock(node.body))); |
1591 }, store: false); | 1580 }, store: false); |
1592 insideUntranslatedBreakable = oldInsideUntranslated; | 1581 insideUntranslatedBreakable = oldInsideUntranslated; |
1593 return; | 1582 return; |
1594 } | 1583 } |
1595 int continueLabel = newLabel("while condition"); | 1584 int continueLabel = newLabel("while condition"); |
1596 continueLabels[node] = continueLabel; | 1585 continueLabels[node] = continueLabel; |
1597 beginLabel(continueLabel); | 1586 beginLabel(continueLabel); |
1598 | 1587 |
1599 int afterLabel = newLabel("after while"); | 1588 int afterLabel = newLabel("after while"); |
1600 breakLabels[node] = afterLabel; | 1589 breakLabels[node] = afterLabel; |
(...skipping 987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2588 return condition || body; | 2577 return condition || body; |
2589 } | 2578 } |
2590 | 2579 |
2591 @override | 2580 @override |
2592 bool visitDartYield(js.DartYield node) { | 2581 bool visitDartYield(js.DartYield node) { |
2593 hasYield = true; | 2582 hasYield = true; |
2594 visit(node.expression); | 2583 visit(node.expression); |
2595 return true; | 2584 return true; |
2596 } | 2585 } |
2597 } | 2586 } |
OLD | NEW |