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 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 | 480 |
| 481 class LabeledStatementLabelScope implements LabelScope { | 481 class LabeledStatementLabelScope implements LabelScope { |
| 482 final LabelScope outer; | 482 final LabelScope outer; |
| 483 final LabelElement label; | 483 final LabelElement label; |
| 484 LabeledStatementLabelScope(this.outer, this.label); | 484 LabeledStatementLabelScope(this.outer, this.label); |
| 485 LabelElement lookup(String labelName) { | 485 LabelElement lookup(String labelName) { |
| 486 if (this.label.labelName == labelName) return label; | 486 if (this.label.labelName == labelName) return label; |
| 487 return outer.lookup(labelName); | 487 return outer.lookup(labelName); |
| 488 } | 488 } |
| 489 } | 489 } |
| 490 | 490 |
|
ahe
2012/03/09 13:58:32
Remove extra line
Lasse Reichstein Nielsen
2012/03/12 13:05:23
Done.
| |
| 491 | |
| 492 class SwitchLabelScope implements LabelScope { | |
| 493 final LabelScope outer; | |
| 494 final Map<String, LabelElement> caseLabels; | |
| 495 SwitchLabelScope(this.outer, this.caseLabels); | |
| 496 LabelElement lookup(String labelName) { | |
| 497 LabelElement result = caseLabels[labelName]; | |
| 498 if (result !== null) return result; | |
| 499 return outer.lookup(labelName); | |
| 500 } | |
| 501 } | |
| 502 | |
|
ahe
2012/03/09 13:58:32
Extra line.
Lasse Reichstein Nielsen
2012/03/12 13:05:23
Done.
| |
| 503 | |
| 491 class EmptyLabelScope implements LabelScope { | 504 class EmptyLabelScope implements LabelScope { |
| 492 const EmptyLabelScope(); | 505 const EmptyLabelScope(); |
| 493 LabelElement lookup(String label) => null; | 506 LabelElement lookup(String label) => null; |
| 494 LabelScope get outer() { | 507 LabelScope get outer() { |
| 495 throw 'internal error: empty label scope has no outer'; | 508 throw 'internal error: empty label scope has no outer'; |
| 496 } | 509 } |
| 497 } | 510 } |
| 498 | 511 |
| 499 class StatementScope { | 512 class StatementScope { |
| 500 LabelScope labels; | 513 LabelScope labels; |
| 501 Link<StatementElement> breakTargetStack; | 514 Link<StatementElement> breakTargetStack; |
| 502 Link<StatementElement> continueTargetStack; | 515 Link<StatementElement> continueTargetStack; |
| 503 | 516 |
| 504 StatementScope() | 517 StatementScope() |
| 505 : labels = const EmptyLabelScope(), | 518 : labels = const EmptyLabelScope(), |
| 506 breakTargetStack = const EmptyLink<StatementElement>(), | 519 breakTargetStack = const EmptyLink<StatementElement>(), |
| 507 continueTargetStack = const EmptyLink<StatementElement>(); | 520 continueTargetStack = const EmptyLink<StatementElement>(); |
| 508 | 521 |
| 509 LabelElement lookupLabel(String label) => labels.lookup(label); | 522 LabelElement lookupLabel(String label) => |
| 523 labels.lookup(label); | |
| 524 | |
| 510 StatementElement currentBreakTarget() => | 525 StatementElement currentBreakTarget() => |
| 511 breakTargetStack.isEmpty() ? null : breakTargetStack.head; | 526 breakTargetStack.isEmpty() ? null : breakTargetStack.head; |
| 527 | |
| 512 StatementElement currentContinueTarget() => | 528 StatementElement currentContinueTarget() => |
| 513 continueTargetStack.isEmpty() ? null : continueTargetStack.head; | 529 continueTargetStack.isEmpty() ? null : continueTargetStack.head; |
| 514 | 530 |
| 515 void enterLabelScope(LabelElement element) { | 531 void enterLabelScope(LabelElement element) { |
| 516 labels = new LabeledStatementLabelScope(labels, element); | 532 labels = new LabeledStatementLabelScope(labels, element); |
| 517 } | 533 } |
| 534 | |
| 518 void exitLabelScope() { | 535 void exitLabelScope() { |
| 519 labels = labels.outer; | 536 labels = labels.outer; |
| 520 } | 537 } |
| 538 | |
| 521 void enterLoop(StatementElement element) { | 539 void enterLoop(StatementElement element) { |
| 522 breakTargetStack = breakTargetStack.prepend(element); | 540 breakTargetStack = breakTargetStack.prepend(element); |
| 523 continueTargetStack = continueTargetStack.prepend(element); | 541 continueTargetStack = continueTargetStack.prepend(element); |
| 524 } | 542 } |
| 543 | |
| 525 void exitLoop() { | 544 void exitLoop() { |
| 526 breakTargetStack = breakTargetStack.tail; | 545 breakTargetStack = breakTargetStack.tail; |
| 527 continueTargetStack = continueTargetStack.tail; | 546 continueTargetStack = continueTargetStack.tail; |
| 528 } | 547 } |
| 548 | |
| 549 void enterSwitch(StatementElement breakElement, | |
| 550 Map<String, LabelElement> continueElements) { | |
| 551 breakTargetStack = breakTargetStack.prepend(breakElement); | |
| 552 labels = new SwitchLabelScope(labels, continueElements); | |
| 553 } | |
| 554 | |
| 555 void exitSwitch() { | |
| 556 breakTargetStack = breakTargetStack.tail; | |
| 557 labels = labels.outer; | |
| 558 } | |
| 529 } | 559 } |
| 530 | 560 |
| 531 | 561 |
| 532 class ResolverVisitor extends CommonResolverVisitor<Element> { | 562 class ResolverVisitor extends CommonResolverVisitor<Element> { |
| 533 final TreeElementMapping mapping; | 563 final TreeElementMapping mapping; |
| 534 final Element enclosingElement; | 564 final Element enclosingElement; |
| 535 bool inInstanceContext; | 565 bool inInstanceContext; |
| 536 Scope context; | 566 Scope context; |
| 537 ClassElement currentClass; | 567 ClassElement currentClass; |
| 538 bool typeRequired = false; | 568 bool typeRequired = false; |
| 539 StatementScope statementScope; | 569 StatementScope statementScope; |
| 540 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION; | 570 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION; |
| 571 // For generating locally unique ids. | |
| 572 int sequence = 0; | |
| 541 | 573 |
| 542 ResolverVisitor(Compiler compiler, Element element) | 574 ResolverVisitor(Compiler compiler, Element element) |
| 543 : this.mapping = new TreeElementMapping(), | 575 : this.mapping = new TreeElementMapping(), |
| 544 this.enclosingElement = element, | 576 this.enclosingElement = element, |
| 545 inInstanceContext = element.isInstanceMember() | 577 inInstanceContext = element.isInstanceMember() |
| 546 || element.isGenerativeConstructor(), | 578 || element.isGenerativeConstructor(), |
| 547 this.context = element.isMember() | 579 this.context = element.isMember() |
| 548 ? new ClassScope(element.enclosingElement, element.getLibrary()) | 580 ? new ClassScope(element.enclosingElement, element.getLibrary()) |
| 549 : new TopScope(element.getLibrary()), | 581 : new TopScope(element.getLibrary()), |
| 550 this.currentClass = element.isMember() ? element.enclosingElement : null, | 582 this.currentClass = element.isMember() ? element.enclosingElement : null, |
| 551 this.statementScope = new StatementScope(), | 583 this.statementScope = new StatementScope(), |
| 552 super(compiler); | 584 super(compiler); |
| 553 | 585 |
| 554 Element lookup(Node node, SourceString name) { | 586 Element lookup(Node node, SourceString name) { |
| 555 Element result = context.lookup(name); | 587 Element result = context.lookup(name); |
| 556 if (!inInstanceContext && result != null && result.isInstanceMember()) { | 588 if (!inInstanceContext && result != null && result.isInstanceMember()) { |
| 557 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); | 589 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); |
| 558 } | 590 } |
| 559 return result; | 591 return result; |
| 560 } | 592 } |
| 561 | 593 |
| 562 // Create, or reuse an already created, statement element for a statement. | 594 // Create, or reuse an already created, statement element for a statement. |
| 563 StatementElement getOrCreateStatementElement(Node statement) { | 595 StatementElement getOrCreateStatementElement(Node statement) { |
| 564 StatementElement element = mapping[statement]; | 596 StatementElement element = mapping[statement]; |
| 565 if (element !== null) return element; | 597 if (element !== null) return element; |
| 566 element = new StatementElement(statement, enclosingElement); | 598 if (statement is SwitchStatement) { |
|
ahe
2012/03/09 13:58:32
statement.asSwitchStatement() !== null
Lasse Reichstein Nielsen
2012/03/12 13:05:23
Why use something that's harder to read and is pos
Lasse Reichstein Nielsen
2012/03/12 13:21:28
But I rewrote it anyway :)
| |
| 599 element = new SwitchStatementElement(statement, | |
| 600 enclosingElement, | |
| 601 sequence++); | |
| 602 } else { | |
| 603 element = new StatementElement(statement, enclosingElement); | |
| 604 } | |
| 567 mapping[statement] = element; | 605 mapping[statement] = element; |
| 568 return element; | 606 return element; |
| 569 } | 607 } |
| 570 | 608 |
| 571 inStaticContext(action()) { | 609 inStaticContext(action()) { |
| 572 bool wasInstanceContext = inInstanceContext; | 610 bool wasInstanceContext = inInstanceContext; |
| 573 inInstanceContext = false; | 611 inInstanceContext = false; |
| 574 action(); | 612 action(); |
| 575 inInstanceContext = wasInstanceContext; | 613 inInstanceContext = wasInstanceContext; |
| 576 } | 614 } |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1030 } | 1068 } |
| 1031 target.isBreakTarget = true; | 1069 target.isBreakTarget = true; |
| 1032 } else { | 1070 } else { |
| 1033 String labelName = node.target.source.slowToString(); | 1071 String labelName = node.target.source.slowToString(); |
| 1034 LabelElement label = statementScope.lookupLabel(labelName); | 1072 LabelElement label = statementScope.lookupLabel(labelName); |
| 1035 if (label === null) { | 1073 if (label === null) { |
| 1036 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); | 1074 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); |
| 1037 return; | 1075 return; |
| 1038 } | 1076 } |
| 1039 target = label.target; | 1077 target = label.target; |
| 1078 if (!target.statement.isValidBreakTarget()) { | |
| 1079 error(node.target, MessageKind.INVALID_BREAK, [labelName]); | |
| 1080 return; | |
| 1081 } | |
| 1040 label.setBreakTarget(); | 1082 label.setBreakTarget(); |
| 1041 mapping[node.target] = label; | 1083 mapping[node.target] = label; |
| 1042 } | 1084 } |
| 1043 mapping[node] = target; | 1085 mapping[node] = target; |
| 1044 } | 1086 } |
| 1045 | 1087 |
| 1046 visitContinueStatement(ContinueStatement node) { | 1088 visitContinueStatement(ContinueStatement node) { |
| 1047 StatementElement target; | 1089 StatementElement target; |
| 1048 if (node.target === null) { | 1090 if (node.target === null) { |
| 1049 target = statementScope.currentContinueTarget(); | 1091 target = statementScope.currentContinueTarget(); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1118 visitLiteralMapEntry(LiteralMapEntry node) { | 1160 visitLiteralMapEntry(LiteralMapEntry node) { |
| 1119 node.visitChildren(this); | 1161 node.visitChildren(this); |
| 1120 } | 1162 } |
| 1121 | 1163 |
| 1122 visitNamedArgument(NamedArgument node) { | 1164 visitNamedArgument(NamedArgument node) { |
| 1123 visit(node.expression); | 1165 visit(node.expression); |
| 1124 } | 1166 } |
| 1125 | 1167 |
| 1126 visitSwitchStatement(SwitchStatement node) { | 1168 visitSwitchStatement(SwitchStatement node) { |
| 1127 node.expression.accept(this); | 1169 node.expression.accept(this); |
| 1128 StatementElement element = getOrCreateStatementElement(node); | 1170 |
| 1129 statementScope.enterLoop(element); | 1171 StatementElement breakElement = getOrCreateStatementElement(node); |
| 1172 Map<String, LabelElement> continueLabels = <LabelElement>{}; | |
| 1173 for (SwitchCase switchCase in node.cases) { | |
| 1174 if (switchCase.label !== null) { | |
| 1175 Identifier labelIdentifier = switchCase.label; | |
| 1176 String labelName = labelIdentifier.source.slowToString(); | |
| 1177 | |
| 1178 LabelElement existingElement = continueLabels[labelName]; | |
| 1179 if (existingElement !== null) { | |
| 1180 // It's an error if the same label occurs twice in the same switch. | |
| 1181 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]); | |
| 1182 error(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]); | |
| 1183 } else { | |
| 1184 // It's only a warning if it shadows another label. | |
| 1185 existingElement = statementScope.lookupLabel(labelName); | |
| 1186 if (existingElement !== null) { | |
| 1187 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]); | |
| 1188 warning(existingElement.label, | |
| 1189 MessageKind.EXISTING_LABEL, [labelName]); | |
| 1190 } | |
| 1191 } | |
| 1192 | |
| 1193 StatementElement statementElement = | |
| 1194 new StatementElement(switchCase, enclosingElement); | |
| 1195 mapping[switchCase] = statementElement; | |
| 1196 | |
| 1197 LabelElement label = | |
| 1198 new LabelElement(labelIdentifier, labelName, | |
| 1199 statementElement, enclosingElement); | |
| 1200 mapping[labelIdentifier] = label; | |
| 1201 continueLabels[labelName] = label; | |
| 1202 } | |
| 1203 } | |
| 1204 statementScope.enterSwitch(breakElement, continueLabels); | |
| 1130 node.cases.accept(this); | 1205 node.cases.accept(this); |
| 1131 statementScope.exitLoop(); | 1206 statementScope.exitSwitch(); |
| 1207 | |
| 1208 // Clean-up unused labels | |
| 1209 continueLabels.forEach((String key, LabelElement label) { | |
| 1210 StatementElement statementElement = label.target; | |
| 1211 SwitchCase switchCase = statementElement.statement; | |
| 1212 if (!label.isContinueTarget) { | |
| 1213 mapping.remove(switchCase); | |
| 1214 mapping.remove(label.label); | |
| 1215 } | |
| 1216 }); | |
| 1132 } | 1217 } |
| 1133 | 1218 |
| 1134 visitSwitchCase(SwitchCase node) { | 1219 visitSwitchCase(SwitchCase node) { |
| 1135 // TODO(ahe): What about the label? | 1220 // The label was handled in [visitSwitchStatement(SwitchStatement)]. |
| 1136 node.expression.accept(this); | 1221 node.expressions.accept(this); |
| 1137 visitIn(node.statements, new BlockScope(context)); | 1222 visitIn(node.statements, new BlockScope(context)); |
| 1138 } | 1223 } |
| 1139 | 1224 |
| 1140 visitDefaultCase(DefaultCase node) { | |
| 1141 // TODO(ahe): What about the label? | |
| 1142 visitIn(node.statements, new BlockScope(context)); | |
| 1143 } | |
| 1144 | |
| 1145 visitTryStatement(TryStatement node) { | 1225 visitTryStatement(TryStatement node) { |
| 1146 visit(node.tryBlock); | 1226 visit(node.tryBlock); |
| 1147 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) { | 1227 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) { |
| 1148 // TODO(ngeoffray): The precise location is | 1228 // TODO(ngeoffray): The precise location is |
| 1149 // node.getEndtoken.next. Adjust when issue #1581 is fixed. | 1229 // node.getEndtoken.next. Adjust when issue #1581 is fixed. |
| 1150 error(node, MessageKind.NO_CATCH_NOR_FINALLY); | 1230 error(node, MessageKind.NO_CATCH_NOR_FINALLY); |
| 1151 } | 1231 } |
| 1152 visit(node.catchBlocks); | 1232 visit(node.catchBlocks); |
| 1153 visit(node.finallyBlock); | 1233 visit(node.finallyBlock); |
| 1154 } | 1234 } |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1564 class TopScope extends Scope { | 1644 class TopScope extends Scope { |
| 1565 LibraryElement get library() => element; | 1645 LibraryElement get library() => element; |
| 1566 | 1646 |
| 1567 TopScope(LibraryElement library) : super(null, library); | 1647 TopScope(LibraryElement library) : super(null, library); |
| 1568 Element lookup(SourceString name) => library.find(name); | 1648 Element lookup(SourceString name) => library.find(name); |
| 1569 | 1649 |
| 1570 Element add(Element element) { | 1650 Element add(Element element) { |
| 1571 throw "Cannot add an element in the top scope"; | 1651 throw "Cannot add an element in the top scope"; |
| 1572 } | 1652 } |
| 1573 } | 1653 } |
| OLD | NEW |