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

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: Add missing handling of default in unparser. 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 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 class LabeledStatementLabelScope implements LabelScope { 415 class LabeledStatementLabelScope implements LabelScope {
416 final LabelScope outer; 416 final LabelScope outer;
417 final LabelElement label; 417 final LabelElement label;
418 LabeledStatementLabelScope(this.outer, this.label); 418 LabeledStatementLabelScope(this.outer, this.label);
419 LabelElement lookup(String labelName) { 419 LabelElement lookup(String labelName) {
420 if (this.label.labelName == labelName) return label; 420 if (this.label.labelName == labelName) return label;
421 return outer.lookup(labelName); 421 return outer.lookup(labelName);
422 } 422 }
423 } 423 }
424 424
425 class SwitchLabelScope implements LabelScope {
426 final LabelScope outer;
427 final Map<String, LabelElement> caseLabels;
ahe 2012/03/13 10:17:15 Add an empty line.
Lasse Reichstein Nielsen 2012/03/13 12:09:38 Done.
428 SwitchLabelScope(this.outer, this.caseLabels);
ahe 2012/03/13 10:17:15 Add an empty line.
Lasse Reichstein Nielsen 2012/03/13 12:09:38 Done.
429 LabelElement lookup(String labelName) {
430 LabelElement result = caseLabels[labelName];
431 if (result !== null) return result;
432 return outer.lookup(labelName);
433 }
434 }
435
425 class EmptyLabelScope implements LabelScope { 436 class EmptyLabelScope implements LabelScope {
426 const EmptyLabelScope(); 437 const EmptyLabelScope();
427 LabelElement lookup(String label) => null; 438 LabelElement lookup(String label) => null;
428 LabelScope get outer() { 439 LabelScope get outer() {
429 throw 'internal error: empty label scope has no outer'; 440 throw 'internal error: empty label scope has no outer';
430 } 441 }
431 } 442 }
432 443
433 class StatementScope { 444 class StatementScope {
434 LabelScope labels; 445 LabelScope labels;
435 Link<StatementElement> breakTargetStack; 446 Link<StatementElement> breakTargetStack;
436 Link<StatementElement> continueTargetStack; 447 Link<StatementElement> continueTargetStack;
448 int nestingLevel = 0;
437 449
438 StatementScope() 450 StatementScope()
439 : labels = const EmptyLabelScope(), 451 : labels = const EmptyLabelScope(),
440 breakTargetStack = const EmptyLink<StatementElement>(), 452 breakTargetStack = const EmptyLink<StatementElement>(),
441 continueTargetStack = const EmptyLink<StatementElement>(); 453 continueTargetStack = const EmptyLink<StatementElement>();
442 454
443 LabelElement lookupLabel(String label) => labels.lookup(label); 455 LabelElement lookupLabel(String label) =>
456 labels.lookup(label);
457
444 StatementElement currentBreakTarget() => 458 StatementElement currentBreakTarget() =>
445 breakTargetStack.isEmpty() ? null : breakTargetStack.head; 459 breakTargetStack.isEmpty() ? null : breakTargetStack.head;
460
446 StatementElement currentContinueTarget() => 461 StatementElement currentContinueTarget() =>
447 continueTargetStack.isEmpty() ? null : continueTargetStack.head; 462 continueTargetStack.isEmpty() ? null : continueTargetStack.head;
448 463
449 void enterLabelScope(LabelElement element) { 464 void enterLabelScope(LabelElement element) {
450 labels = new LabeledStatementLabelScope(labels, element); 465 labels = new LabeledStatementLabelScope(labels, element);
466 nestingLevel++;
451 } 467 }
468
452 void exitLabelScope() { 469 void exitLabelScope() {
470 nestingLevel--;
453 labels = labels.outer; 471 labels = labels.outer;
454 } 472 }
473
455 void enterLoop(StatementElement element) { 474 void enterLoop(StatementElement element) {
456 breakTargetStack = breakTargetStack.prepend(element); 475 breakTargetStack = breakTargetStack.prepend(element);
457 continueTargetStack = continueTargetStack.prepend(element); 476 continueTargetStack = continueTargetStack.prepend(element);
477 nestingLevel++;
458 } 478 }
479
459 void exitLoop() { 480 void exitLoop() {
481 nestingLevel--;
460 breakTargetStack = breakTargetStack.tail; 482 breakTargetStack = breakTargetStack.tail;
461 continueTargetStack = continueTargetStack.tail; 483 continueTargetStack = continueTargetStack.tail;
462 } 484 }
485
486 void enterSwitch(StatementElement breakElement,
487 Map<String, LabelElement> continueElements) {
488 breakTargetStack = breakTargetStack.prepend(breakElement);
489 labels = new SwitchLabelScope(labels, continueElements);
490 nestingLevel++;
ahe 2012/03/13 10:17:15 This seems wrong, but perhaps I'm misunderstanding
Lasse Reichstein Nielsen 2012/03/13 12:09:38 The switch level doesn't need to be exact, as long
491 }
492
493 void exitSwitch() {
494 nestingLevel--;
495 breakTargetStack = breakTargetStack.tail;
496 labels = labels.outer;
497 }
463 } 498 }
464 499
465
466 class ResolverVisitor extends CommonResolverVisitor<Element> { 500 class ResolverVisitor extends CommonResolverVisitor<Element> {
467 final TreeElementMapping mapping; 501 final TreeElementMapping mapping;
468 final Element enclosingElement; 502 final Element enclosingElement;
469 bool inInstanceContext; 503 bool inInstanceContext;
470 Scope context; 504 Scope context;
471 ClassElement currentClass; 505 ClassElement currentClass;
472 bool typeRequired = false; 506 bool typeRequired = false;
473 StatementScope statementScope; 507 StatementScope statementScope;
474 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION; 508 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION;
475 509
(...skipping 13 matching lines...) Expand all
489 Element result = context.lookup(name); 523 Element result = context.lookup(name);
490 if (!inInstanceContext && result != null && result.isInstanceMember()) { 524 if (!inInstanceContext && result != null && result.isInstanceMember()) {
491 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); 525 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
492 } 526 }
493 return result; 527 return result;
494 } 528 }
495 529
496 // Create, or reuse an already created, statement element for a statement. 530 // Create, or reuse an already created, statement element for a statement.
497 StatementElement getOrCreateStatementElement(Node statement) { 531 StatementElement getOrCreateStatementElement(Node statement) {
498 StatementElement element = mapping[statement]; 532 StatementElement element = mapping[statement];
499 if (element !== null) return element; 533 if (element === null) {
500 element = new StatementElement(statement, enclosingElement); 534 element = new StatementElement(statement,
501 mapping[statement] = element; 535 statementScope.nestingLevel,
536 enclosingElement);
537 mapping[statement] = element;
538 }
502 return element; 539 return element;
503 } 540 }
504 541
505 inStaticContext(action()) { 542 inStaticContext(action()) {
506 bool wasInstanceContext = inInstanceContext; 543 bool wasInstanceContext = inInstanceContext;
507 inInstanceContext = false; 544 inInstanceContext = false;
508 action(); 545 action();
509 inInstanceContext = wasInstanceContext; 546 inInstanceContext = wasInstanceContext;
510 } 547 }
511 548
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 } 993 }
957 target.isBreakTarget = true; 994 target.isBreakTarget = true;
958 } else { 995 } else {
959 String labelName = node.target.source.slowToString(); 996 String labelName = node.target.source.slowToString();
960 LabelElement label = statementScope.lookupLabel(labelName); 997 LabelElement label = statementScope.lookupLabel(labelName);
961 if (label === null) { 998 if (label === null) {
962 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); 999 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]);
963 return; 1000 return;
964 } 1001 }
965 target = label.target; 1002 target = label.target;
1003 if (!target.statement.isValidBreakTarget()) {
1004 error(node.target, MessageKind.INVALID_BREAK, [labelName]);
1005 return;
ahe 2012/03/13 10:17:15 Thank you :-)
1006 }
966 label.setBreakTarget(); 1007 label.setBreakTarget();
967 mapping[node.target] = label; 1008 mapping[node.target] = label;
968 } 1009 }
969 mapping[node] = target; 1010 mapping[node] = target;
970 } 1011 }
971 1012
972 visitContinueStatement(ContinueStatement node) { 1013 visitContinueStatement(ContinueStatement node) {
973 StatementElement target; 1014 StatementElement target;
974 if (node.target === null) { 1015 if (node.target === null) {
975 target = statementScope.currentContinueTarget(); 1016 target = statementScope.currentContinueTarget();
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1044 visitLiteralMapEntry(LiteralMapEntry node) { 1085 visitLiteralMapEntry(LiteralMapEntry node) {
1045 node.visitChildren(this); 1086 node.visitChildren(this);
1046 } 1087 }
1047 1088
1048 visitNamedArgument(NamedArgument node) { 1089 visitNamedArgument(NamedArgument node) {
1049 visit(node.expression); 1090 visit(node.expression);
1050 } 1091 }
1051 1092
1052 visitSwitchStatement(SwitchStatement node) { 1093 visitSwitchStatement(SwitchStatement node) {
1053 node.expression.accept(this); 1094 node.expression.accept(this);
1054 StatementElement element = getOrCreateStatementElement(node); 1095
1055 statementScope.enterLoop(element); 1096 StatementElement breakElement = getOrCreateStatementElement(node);
ahe 2012/03/13 10:17:15 Nit: I'm not digging this method. I would prefer i
Lasse Reichstein Nielsen 2012/03/13 12:09:38 The problem is that we want to create a StatementE
1097 Map<String, LabelElement> continueLabels = <LabelElement>{};
1098 Link<SwitchCase> cases = node.cases.nodes;
1099 while (!cases.isEmpty()) {
1100 SwitchCase switchCase = cases.head;
1101 if (switchCase.label !== null) {
1102 Identifier labelIdentifier = switchCase.label;
1103 String labelName = labelIdentifier.source.slowToString();
1104
1105 LabelElement existingElement = continueLabels[labelName];
1106 if (existingElement !== null) {
1107 // It's an error if the same label occurs twice in the same switch.
1108 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
1109 error(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]);
1110 } else {
1111 // It's only a warning if it shadows another label.
1112 existingElement = statementScope.lookupLabel(labelName);
1113 if (existingElement !== null) {
1114 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
1115 warning(existingElement.label,
1116 MessageKind.EXISTING_LABEL, [labelName]);
1117 }
1118 }
1119
1120 StatementElement statementElement =
1121 new StatementElement(switchCase,
1122 statementScope.nestingLevel,
1123 enclosingElement);
1124 mapping[switchCase] = statementElement;
1125
1126 LabelElement label =
1127 new LabelElement(labelIdentifier, labelName,
ahe 2012/03/13 10:17:15 I don't understand the mental model for this. The
Lasse Reichstein Nielsen 2012/03/13 12:09:38 Are you referring to enclosingElement? I have assu
1128 statementElement, enclosingElement);
1129 mapping[labelIdentifier] = label;
1130 continueLabels[labelName] = label;
1131 }
1132 cases = cases.tail;
1133 if (switchCase.defaultKeyword !== null && !cases.isEmpty()) {
1134 error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
1135 }
1136 }
1137 statementScope.enterSwitch(breakElement, continueLabels);
1056 node.cases.accept(this); 1138 node.cases.accept(this);
1057 statementScope.exitLoop(); 1139 statementScope.exitSwitch();
1140
1141 // Clean-up unused labels
1142 continueLabels.forEach((String key, LabelElement label) {
ahe 2012/03/13 10:17:15 Wouldn't it better to set a bit on the label?
Lasse Reichstein Nielsen 2012/03/13 12:09:38 The bit is set. This is pure cleanup. We know that
1143 StatementElement statementElement = label.target;
1144 SwitchCase switchCase = statementElement.statement;
1145 if (!label.isContinueTarget) {
1146 mapping.remove(switchCase);
1147 mapping.remove(label.label);
1148 }
1149 });
1058 } 1150 }
1059 1151
1060 visitSwitchCase(SwitchCase node) { 1152 visitSwitchCase(SwitchCase node) {
1061 // TODO(ahe): What about the label? 1153 // The label was handled in [visitSwitchStatement(SwitchStatement)].
1062 node.expression.accept(this); 1154 node.expressions.accept(this);
1063 visitIn(node.statements, new BlockScope(context)); 1155 visitIn(node.statements, new BlockScope(context));
1064 } 1156 }
1065 1157
1066 visitDefaultCase(DefaultCase node) {
1067 // TODO(ahe): What about the label?
1068 visitIn(node.statements, new BlockScope(context));
1069 }
1070
1071 visitTryStatement(TryStatement node) { 1158 visitTryStatement(TryStatement node) {
1072 visit(node.tryBlock); 1159 visit(node.tryBlock);
1073 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) { 1160 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) {
1074 // TODO(ngeoffray): The precise location is 1161 // TODO(ngeoffray): The precise location is
1075 // node.getEndtoken.next. Adjust when issue #1581 is fixed. 1162 // node.getEndtoken.next. Adjust when issue #1581 is fixed.
1076 error(node, MessageKind.NO_CATCH_NOR_FINALLY); 1163 error(node, MessageKind.NO_CATCH_NOR_FINALLY);
1077 } 1164 }
1078 visit(node.catchBlocks); 1165 visit(node.catchBlocks);
1079 visit(node.finallyBlock); 1166 visit(node.finallyBlock);
1080 } 1167 }
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after
1558 class TopScope extends Scope { 1645 class TopScope extends Scope {
1559 LibraryElement get library() => element; 1646 LibraryElement get library() => element;
1560 1647
1561 TopScope(LibraryElement library) : super(null, library); 1648 TopScope(LibraryElement library) : super(null, library);
1562 Element lookup(SourceString name) => library.find(name); 1649 Element lookup(SourceString name) => library.find(name);
1563 1650
1564 Element add(Element element) { 1651 Element add(Element element) {
1565 throw "Cannot add an element in the top scope"; 1652 throw "Cannot add an element in the top scope";
1566 } 1653 }
1567 } 1654 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698