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

Side by Side Diff: frog/leg/resolver.dart

Issue 9632018: Switch-implementation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Finished implementation Created 8 years, 9 months 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
OLDNEW
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698