Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 interface TreeElements { | 5 interface TreeElements { |
| 6 Element operator[](Node node); | 6 Element operator[](Node node); |
| 7 Selector getSelector(Send send); | 7 Selector getSelector(Send send); |
| 8 } | 8 } |
| 9 | 9 |
| 10 class TreeElementMapping implements TreeElements { | 10 class TreeElementMapping implements TreeElements { |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 471 | 471 |
| 472 interface LabelScope { | 472 interface LabelScope { |
| 473 LabelScope get outer(); | 473 LabelScope get outer(); |
| 474 LabelElement lookup(String label); | 474 LabelElement lookup(String label); |
| 475 } | 475 } |
| 476 | 476 |
| 477 class LabeledStatementLabelScope implements LabelScope { | 477 class LabeledStatementLabelScope implements LabelScope { |
| 478 final LabelScope outer; | 478 final LabelScope outer; |
| 479 final LabelElement label; | 479 final LabelElement label; |
| 480 LabeledStatementLabelScope(this.outer, this.label); | 480 LabeledStatementLabelScope(this.outer, this.label); |
| 481 LabelElement lookup(String labelName) { | 481 LabelElement lookupBreak(String labelName) { |
| 482 if (this.label.labelName == labelName) return label; | 482 if (this.label.labelName == labelName) return label; |
| 483 return outer.lookup(labelName); | 483 return outer.lookupBreak(labelName); |
| 484 } | |
| 485 LabelElement lookupContinue(String labelName) { | |
| 486 if (this.label.labelName == labelName) return label; | |
| 487 return outer.lookupContinue(labelName); | |
| 484 } | 488 } |
| 485 } | 489 } |
| 486 | 490 |
| 491 | |
| 492 class SwitchLabelScope implements LabelScope { | |
| 493 final LabelScope outer; | |
| 494 final Map<String, LabelElement> caseLabels; | |
| 495 SwitchLabelScope(this.outer, this.caseLabels); | |
| 496 LabelElement lookupBreak(String labelName) { | |
| 497 return outer.lookupBreak(labelName); | |
| 498 } | |
| 499 LabelElement lookupContinue(String labelName) { | |
| 500 LabelElement result = caseLabels[labelName]; | |
| 501 if (result !== null) return result; | |
| 502 return outer.lookupContinue(labelName); | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 | |
| 487 class EmptyLabelScope implements LabelScope { | 507 class EmptyLabelScope implements LabelScope { |
| 488 const EmptyLabelScope(); | 508 const EmptyLabelScope(); |
| 489 LabelElement lookup(String label) => null; | 509 LabelElement lookupBreak(String label) => null; |
| 510 LabelElement lookupContinue(String label) => null; | |
| 490 LabelScope get outer() { | 511 LabelScope get outer() { |
| 491 throw 'internal error: empty label scope has no outer'; | 512 throw 'internal error: empty label scope has no outer'; |
| 492 } | 513 } |
| 493 } | 514 } |
| 494 | 515 |
| 495 class StatementScope { | 516 class StatementScope { |
| 496 LabelScope labels; | 517 LabelScope labels; |
| 497 Link<StatementElement> breakTargetStack; | 518 Link<StatementElement> breakTargetStack; |
|
floitsch
2012/03/08 16:35:14
These (the break and the continueTargetStack) are
Lasse Reichstein Nielsen
2012/03/08 18:35:40
Yes. Will add comment.
| |
| 498 Link<StatementElement> continueTargetStack; | 519 Link<StatementElement> continueTargetStack; |
| 499 | 520 |
| 500 StatementScope() | 521 StatementScope() |
| 501 : labels = const EmptyLabelScope(), | 522 : labels = const EmptyLabelScope(), |
| 502 breakTargetStack = const EmptyLink<StatementElement>(), | 523 breakTargetStack = const EmptyLink<StatementElement>(), |
| 503 continueTargetStack = const EmptyLink<StatementElement>(); | 524 continueTargetStack = const EmptyLink<StatementElement>(); |
| 504 | 525 |
| 505 LabelElement lookupLabel(String label) => labels.lookup(label); | 526 LabelElement lookupBreakLabel(String label) => |
| 527 labels.lookupBreak(label); | |
| 528 | |
| 529 LabelElement lookupContinueLabel(String label) => | |
| 530 labels.lookupContinue(label); | |
| 531 | |
| 506 StatementElement currentBreakTarget() => | 532 StatementElement currentBreakTarget() => |
| 507 breakTargetStack.isEmpty() ? null : breakTargetStack.head; | 533 breakTargetStack.isEmpty() ? null : breakTargetStack.head; |
| 534 | |
| 508 StatementElement currentContinueTarget() => | 535 StatementElement currentContinueTarget() => |
| 509 continueTargetStack.isEmpty() ? null : continueTargetStack.head; | 536 continueTargetStack.isEmpty() ? null : continueTargetStack.head; |
| 510 | 537 |
| 511 void enterLabelScope(LabelElement element) { | 538 void enterLabelScope(LabelElement element) { |
| 512 labels = new LabeledStatementLabelScope(labels, element); | 539 labels = new LabeledStatementLabelScope(labels, element); |
| 513 } | 540 } |
| 541 | |
| 514 void exitLabelScope() { | 542 void exitLabelScope() { |
| 515 labels = labels.outer; | 543 labels = labels.outer; |
| 516 } | 544 } |
| 545 | |
| 517 void enterLoop(StatementElement element) { | 546 void enterLoop(StatementElement element) { |
| 518 breakTargetStack = breakTargetStack.prepend(element); | 547 breakTargetStack = breakTargetStack.prepend(element); |
| 519 continueTargetStack = continueTargetStack.prepend(element); | 548 continueTargetStack = continueTargetStack.prepend(element); |
| 520 } | 549 } |
| 550 | |
| 521 void exitLoop() { | 551 void exitLoop() { |
| 522 breakTargetStack = breakTargetStack.tail; | 552 breakTargetStack = breakTargetStack.tail; |
| 523 continueTargetStack = continueTargetStack.tail; | 553 continueTargetStack = continueTargetStack.tail; |
| 524 } | 554 } |
| 555 | |
| 556 void enterSwitch(StatementElement breakElement, | |
| 557 Map<String, LabelElement> continueElements) { | |
| 558 breakTargetStack = breakTargetStack.prepend(breakElement); | |
| 559 labels = new SwitchLabelScope(labels, continueElements); | |
| 560 } | |
| 561 | |
| 562 void exitSwitch() { | |
| 563 breakTargetStack = breakTargetStack.tail; | |
| 564 labels = labels.outer; | |
| 565 } | |
| 525 } | 566 } |
| 526 | 567 |
| 527 | 568 |
| 528 class ResolverVisitor extends CommonResolverVisitor<Element> { | 569 class ResolverVisitor extends CommonResolverVisitor<Element> { |
| 529 final TreeElementMapping mapping; | 570 final TreeElementMapping mapping; |
| 530 final Element enclosingElement; | 571 final Element enclosingElement; |
| 531 bool inInstanceContext; | 572 bool inInstanceContext; |
| 532 Scope context; | 573 Scope context; |
| 533 ClassElement currentClass; | 574 ClassElement currentClass; |
| 534 bool typeRequired = false; | 575 bool typeRequired = false; |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1042 StatementElement target; | 1083 StatementElement target; |
| 1043 if (node.target === null) { | 1084 if (node.target === null) { |
| 1044 target = statementScope.currentBreakTarget(); | 1085 target = statementScope.currentBreakTarget(); |
| 1045 if (target === null) { | 1086 if (target === null) { |
| 1046 error(node, MessageKind.NO_BREAK_TARGET); | 1087 error(node, MessageKind.NO_BREAK_TARGET); |
| 1047 return; | 1088 return; |
| 1048 } | 1089 } |
| 1049 target.isBreakTarget = true; | 1090 target.isBreakTarget = true; |
| 1050 } else { | 1091 } else { |
| 1051 String labelName = node.target.source.slowToString(); | 1092 String labelName = node.target.source.slowToString(); |
| 1052 LabelElement label = statementScope.lookupLabel(labelName); | 1093 LabelElement label = statementScope.lookupBreakLabel(labelName); |
| 1053 if (label === null) { | 1094 if (label === null) { |
| 1054 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); | 1095 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); |
| 1055 return; | 1096 return; |
| 1056 } | 1097 } |
| 1057 target = label.target; | 1098 target = label.target; |
| 1058 label.setBreakTarget(); | 1099 label.setBreakTarget(); |
| 1059 mapping[node.target] = label; | 1100 mapping[node.target] = label; |
| 1060 } | 1101 } |
| 1061 mapping[node] = target; | 1102 mapping[node] = target; |
| 1062 } | 1103 } |
| 1063 | 1104 |
| 1064 visitContinueStatement(ContinueStatement node) { | 1105 visitContinueStatement(ContinueStatement node) { |
| 1065 StatementElement target; | 1106 StatementElement target; |
| 1066 if (node.target === null) { | 1107 if (node.target === null) { |
| 1067 target = statementScope.currentContinueTarget(); | 1108 target = statementScope.currentContinueTarget(); |
| 1068 if (target === null) { | 1109 if (target === null) { |
| 1069 error(node, MessageKind.NO_CONTINUE_TARGET); | 1110 error(node, MessageKind.NO_CONTINUE_TARGET); |
| 1070 return; | 1111 return; |
| 1071 } | 1112 } |
| 1072 } else { | 1113 } else { |
| 1073 String labelName = node.target.source.slowToString(); | 1114 String labelName = node.target.source.slowToString(); |
| 1074 LabelElement label = statementScope.lookupLabel(labelName); | 1115 LabelElement label = statementScope.lookupContinueLabel(labelName); |
| 1075 if (label === null) { | 1116 if (label === null) { |
| 1076 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); | 1117 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); |
| 1077 return; | 1118 return; |
| 1078 } | 1119 } |
| 1079 target = label.target; | 1120 target = label.target; |
| 1080 if (!target.statement.isValidContinueTarget()) { | 1121 if (!target.statement.isValidContinueTarget()) { |
| 1081 error(node.target, MessageKind.INVALID_CONTINUE, [labelName]); | 1122 error(node.target, MessageKind.INVALID_CONTINUE, [labelName]); |
| 1082 } | 1123 } |
| 1083 } | 1124 } |
| 1084 target.isContinueTarget = true; | 1125 target.isContinueTarget = true; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1098 !declaration.asVariableDefinitions().definitions.nodes.tail.isEmpty())) | 1139 !declaration.asVariableDefinitions().definitions.nodes.tail.isEmpty())) |
| 1099 { | 1140 { |
| 1100 // The variable declaration is either not an identifier, not a | 1141 // The variable declaration is either not an identifier, not a |
| 1101 // declaration, or it's declaring more than one variable. | 1142 // declaration, or it's declaring more than one variable. |
| 1102 error(node.declaredIdentifier, MessageKind.INVALID_FOR_IN, []); | 1143 error(node.declaredIdentifier, MessageKind.INVALID_FOR_IN, []); |
| 1103 } | 1144 } |
| 1104 } | 1145 } |
| 1105 | 1146 |
| 1106 visitLabelledStatement(LabelledStatement node) { | 1147 visitLabelledStatement(LabelledStatement node) { |
| 1107 String labelName = node.label.source.slowToString(); | 1148 String labelName = node.label.source.slowToString(); |
| 1108 LabelElement existingElement = statementScope.lookupLabel(labelName); | 1149 LabelElement existingElement = statementScope.lookupBreakLabel(labelName); |
| 1109 if (existingElement !== null) { | 1150 if (existingElement !== null) { |
| 1110 warning(node.label, MessageKind.DUPLICATE_LABEL, [labelName]); | 1151 warning(node.label, MessageKind.DUPLICATE_LABEL, [labelName]); |
| 1111 warning(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]); | 1152 warning(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]); |
| 1112 } | 1153 } |
| 1113 Node body = node.getBody(); | 1154 Node body = node.getBody(); |
| 1114 StatementElement statementElement = getOrCreateStatementElement(body); | 1155 StatementElement statementElement = getOrCreateStatementElement(body); |
| 1115 | 1156 |
| 1116 LabelElement element = statementElement.addLabel(node.label, labelName); | 1157 LabelElement element = statementElement.addLabel(node.label, labelName); |
| 1117 statementScope.enterLabelScope(element); | 1158 statementScope.enterLabelScope(element); |
| 1118 visit(node.statement); | 1159 visit(node.statement); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1136 visitLiteralMapEntry(LiteralMapEntry node) { | 1177 visitLiteralMapEntry(LiteralMapEntry node) { |
| 1137 node.visitChildren(this); | 1178 node.visitChildren(this); |
| 1138 } | 1179 } |
| 1139 | 1180 |
| 1140 visitNamedArgument(NamedArgument node) { | 1181 visitNamedArgument(NamedArgument node) { |
| 1141 visit(node.expression); | 1182 visit(node.expression); |
| 1142 } | 1183 } |
| 1143 | 1184 |
| 1144 visitSwitchStatement(SwitchStatement node) { | 1185 visitSwitchStatement(SwitchStatement node) { |
| 1145 node.expression.accept(this); | 1186 node.expression.accept(this); |
| 1146 StatementElement element = getOrCreateStatementElement(node); | 1187 |
| 1147 statementScope.enterLoop(element); | 1188 StatementElement breakElement = getOrCreateStatementElement(node); |
| 1189 Map<String, LabelElement> continueLabels = <LabelElement>{}; | |
| 1190 for (SwitchCase switchCase in node.cases) { | |
| 1191 if (switchCase.label !== null) { | |
| 1192 Identifier labelIdentifier = switchCase.label; | |
| 1193 String labelName = labelIdentifier.source.slowToString(); | |
| 1194 | |
| 1195 LabelElement existingElement = continueLabels[labelName]; | |
| 1196 if (existingElement !== null) { | |
| 1197 // It's an error if the same label occurs twice in the same switch. | |
| 1198 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]); | |
| 1199 error(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]); | |
| 1200 } else { | |
| 1201 // It's only a warning if it shadows another label. | |
| 1202 existingElement = statementScope.lookupContinue(labelName); | |
| 1203 if (existingElement !== null) { | |
| 1204 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]); | |
| 1205 warning(existingElement.label, | |
| 1206 MessageKind.EXISTING_LABEL, [labelName]); | |
| 1207 } | |
| 1208 } | |
| 1209 | |
| 1210 StatementElement statementElement = | |
| 1211 new StatementElement(switchCase, enclosingElement); | |
| 1212 elements[switchCase] = statementElement; | |
| 1213 | |
| 1214 LabelElement label = | |
| 1215 new LabelElement(currentLabel, labelName, | |
| 1216 statementElement, enclosingElement); | |
| 1217 elements[labelIdentifier] = label; | |
| 1218 continueLabels[labelName] = label; | |
| 1219 | |
| 1220 currentLabel = null; | |
| 1221 } | |
| 1222 } | |
| 1223 statementScope.enterSwitch(breakElement, continueLabels); | |
| 1148 node.cases.accept(this); | 1224 node.cases.accept(this); |
| 1149 statementScope.exitLoop(); | 1225 statementScope.exitSwitch(); |
| 1226 | |
| 1227 // Clean-up unused labels | |
| 1228 continueLabels.forEach((String key, LabelElement label) { | |
| 1229 StatementElement statementElement = label.target; | |
| 1230 SwitchCase switchCase = statementElement.statement; | |
| 1231 if (!label.isContinueTarget) { | |
| 1232 elements.remove(switchCase); | |
| 1233 elements.remove(label.identifier); | |
| 1234 } | |
| 1235 }); | |
| 1150 } | 1236 } |
| 1151 | 1237 |
| 1152 visitSwitchCase(SwitchCase node) { | 1238 visitSwitchCase(SwitchCase node) { |
| 1153 // TODO(ahe): What about the label? | 1239 // The label was handled in [visitSwitchStatement(SwitchStatement)]. |
| 1154 node.expression.accept(this); | 1240 node.expressions.accept(this); |
| 1155 node.statements.accept(this); | 1241 node.statements.accept(this); |
| 1156 } | 1242 } |
| 1157 | 1243 |
| 1158 visitDefaultCase(DefaultCase node) { | |
| 1159 // TODO(ahe): What about the label? | |
| 1160 node.statements.accept(this); | |
| 1161 } | |
| 1162 | |
| 1163 visitTryStatement(TryStatement node) { | 1244 visitTryStatement(TryStatement node) { |
| 1164 visit(node.tryBlock); | 1245 visit(node.tryBlock); |
| 1165 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) { | 1246 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) { |
| 1166 // TODO(ngeoffray): The precise location is | 1247 // TODO(ngeoffray): The precise location is |
| 1167 // node.getEndtoken.next. Adjust when issue #1581 is fixed. | 1248 // node.getEndtoken.next. Adjust when issue #1581 is fixed. |
| 1168 error(node, MessageKind.NO_CATCH_NOR_FINALLY); | 1249 error(node, MessageKind.NO_CATCH_NOR_FINALLY); |
| 1169 } | 1250 } |
| 1170 visit(node.catchBlocks); | 1251 visit(node.catchBlocks); |
| 1171 visit(node.finallyBlock); | 1252 visit(node.finallyBlock); |
| 1172 } | 1253 } |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1481 class TopScope extends Scope { | 1562 class TopScope extends Scope { |
| 1482 LibraryElement get library() => element; | 1563 LibraryElement get library() => element; |
| 1483 | 1564 |
| 1484 TopScope(LibraryElement library) : super(null, library); | 1565 TopScope(LibraryElement library) : super(null, library); |
| 1485 Element lookup(SourceString name) => library.find(name); | 1566 Element lookup(SourceString name) => library.find(name); |
| 1486 | 1567 |
| 1487 Element add(Element element) { | 1568 Element add(Element element) { |
| 1488 throw "Cannot add an element in the top scope"; | 1569 throw "Cannot add an element in the top scope"; |
| 1489 } | 1570 } |
| 1490 } | 1571 } |
| OLD | NEW |