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

Side by Side Diff: frog/gen.dart

Issue 8586020: Treat assignment to final as an error (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: update status Created 9 years, 1 month 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
« no previous file with comments | « frog/frogsh ('k') | frog/tree.dart » ('j') | frog/tree.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** 5 /**
6 * Top level generator object for writing code and keeping track of 6 * Top level generator object for writing code and keeping track of
7 * dependencies. 7 * dependencies.
8 * 8 *
9 * Should have two compilation models, but only one implemented so far. 9 * Should have two compilation models, but only one implemented so far.
10 * 10 *
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 // But probably harmless since we have to pay for the lookup anyway.) 494 // But probably harmless since we have to pay for the lookup anyway.)
495 final type = enclosingMethod.method.declaringType; 495 final type = enclosingMethod.method.declaringType;
496 if (type.library.lookup(name, null) != null) return true; 496 if (type.library.lookup(name, null) != null) return true;
497 497
498 // Nobody else needs this name. It's safe to reuse. 498 // Nobody else needs this name. It's safe to reuse.
499 return false; 499 return false;
500 } 500 }
501 501
502 502
503 Value create(String name, Type type, SourceSpan span, 503 Value create(String name, Type type, SourceSpan span,
504 [bool isParameter = false]) { 504 [bool isFinal = false, bool isParameter = false]) {
505 505
506 var jsName = world.toJsIdentifier(name); 506 var jsName = world.toJsIdentifier(name);
507 if (_vars.containsKey(name)) { 507 if (_vars.containsKey(name)) {
508 world.error('duplicate name "$name"', span); 508 world.error('duplicate name "$name"', span);
509 } 509 }
510 510
511 // Make sure variables don't shadow any names we might need to access. 511 // Make sure variables don't shadow any names we might need to access.
512 if (!isParameter) { 512 if (!isParameter) {
513 int index = 0; 513 int index = 0;
514 while (_isDefinedInParent(jsName)) { 514 while (_isDefinedInParent(jsName)) {
515 jsName = '$name${index++}'; 515 jsName = '$name${index++}';
516 } 516 }
517 } 517 }
518 518
519 var ret = new Value(type, jsName, span, false); 519 var ret = new Value(type, jsName, span, false);
520 ret.isFinal = isFinal;
520 _vars[name] = ret; 521 _vars[name] = ret;
521 return ret; 522 return ret;
522 } 523 }
523 524
524 Value declareParameter(Parameter p) { 525 Value declareParameter(Parameter p) {
525 return create(p.name, p.type, p.definition.span, isParameter:true); 526 return create(p.name, p.type, p.definition.span, isParameter:true);
526 } 527 }
527 528
528 /** Declares a variable in the current scope for this identifier. */ 529 /** Declares a variable in the current scope for this identifier. */
529 Value declare(DeclaredIdentifier id) { 530 Value declare(DeclaredIdentifier id) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 if (enclosingMethod != null) { 576 if (enclosingMethod != null) {
576 _scope = new BlockScope(this, enclosingMethod._scope); 577 _scope = new BlockScope(this, enclosingMethod._scope);
577 captures = new Set(); 578 captures = new Set();
578 } else { 579 } else {
579 _scope = new BlockScope(this, null); 580 _scope = new BlockScope(this, null);
580 } 581 }
581 // For named lambdas, add the name to this scope so we can call it 582 // For named lambdas, add the name to this scope so we can call it
582 // recursively. 583 // recursively.
583 if (enclosingMethod != null && method.name != '') { 584 if (enclosingMethod != null && method.name != '') {
584 MethodMember m = method; // lambdas must be MethodMembers 585 MethodMember m = method; // lambdas must be MethodMembers
585 _scope.create(m.name, m.functionType, m.definition.span); 586 _scope.create(m.name, m.functionType, m.definition.span, isFinal:true);
jimhug 2011/11/17 15:36:15 Nice use for lambdas - I'm a little sad this didn'
586 } 587 }
587 _usedTemps = new Set(); 588 _usedTemps = new Set();
588 _freeTemps = []; 589 _freeTemps = [];
589 } 590 }
590 591
591 Library get library() => method.library; 592 Library get library() => method.library;
592 593
593 // TODO(jimhug): Where does this really belong? 594 // TODO(jimhug): Where does this really belong?
594 MemberSet findMembers(String name) { 595 MemberSet findMembers(String name) {
595 return library._findMembers(name); 596 return library._findMembers(name);
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 var value = visitValue(node.values[i]); 1085 var value = visitValue(node.values[i]);
1085 if (isFinal) { 1086 if (isFinal) {
1086 if (value == null) { 1087 if (value == null) {
1087 world.error('no value specified for final variable', node.span); 1088 world.error('no value specified for final variable', node.span);
1088 } else { 1089 } else {
1089 // TODO(jimhug): Mark inferred types as special for correct errors. 1090 // TODO(jimhug): Mark inferred types as special for correct errors.
1090 if (thisType.isVar) thisType = value.type; 1091 if (thisType.isVar) thisType = value.type;
1091 } 1092 }
1092 } 1093 }
1093 1094
1094 var val = _scope.create(name, thisType, node.names[i].span); 1095 var val = _scope.create(name, thisType, node.names[i].span, isFinal);
1095 1096
1096 if (value == null) { 1097 if (value == null) {
1097 if (_scope.reentrant) { 1098 if (_scope.reentrant) {
1098 // To preserve block scoping, we need to ensure the variable is 1099 // To preserve block scoping, we need to ensure the variable is
1099 // reinitialized each time the block is entered. 1100 // reinitialized each time the block is entered.
1100 writer.write('${val.code} = null'); 1101 writer.write('${val.code} = null');
1101 } else { 1102 } else {
1102 writer.write('${val.code}'); 1103 writer.write('${val.code}');
1103 } 1104 }
1104 } else { 1105 } else {
1105 value = value.convertTo(this, type, node.values[i]); 1106 value = value.convertTo(this, type, node.values[i]);
1106 writer.write('${val.code} = ${value.code}'); 1107 writer.write('${val.code} = ${value.code}');
1107 } 1108 }
1108 } 1109 }
1109 writer.writeln(';'); 1110 writer.writeln(';');
1110 return false; 1111 return false;
1111 1112
1112 } 1113 }
1113 1114
1114 bool visitFunctionDefinition(FunctionDefinition node) { 1115 bool visitFunctionDefinition(FunctionDefinition node) {
1115 var name = world.toJsIdentifier(node.name.name); 1116 var name = world.toJsIdentifier(node.name.name);
1116 1117
1117 var meth = _makeLambdaMethod(name, node); 1118 var meth = _makeLambdaMethod(name, node);
1118 1119
1119 // TODO(jimhug): Pass js name into writeDefinition? 1120 // TODO(jimhug): Pass js name into writeDefinition?
1120 var funcValue = 1121 var funcValue = _scope.create(name, meth.functionType,
1121 _scope.create(name, meth.functionType, method.definition.span); 1122 method.definition.span, isFinal:true);
jimhug 2011/11/17 15:36:15 This one really shocks me that it doesn't trigger
1122 meth.generator.writeDefinition(writer, null); 1123 meth.generator.writeDefinition(writer, null);
1123 return false; 1124 return false;
1124 } 1125 }
1125 1126
1126 /** 1127 /**
1127 * Returns true indicating that normal control-flow is interrupted by 1128 * Returns true indicating that normal control-flow is interrupted by
1128 * this statement. (This could be a return, break, throw, or continue.) 1129 * this statement. (This could be a return, break, throw, or continue.)
1129 */ 1130 */
1130 bool visitReturnStatement(ReturnStatement node) { 1131 bool visitReturnStatement(ReturnStatement node) {
1131 if (node.value == null) { 1132 if (node.value == null) {
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
1253 needsComma = true; 1254 needsComma = true;
1254 } 1255 }
1255 writer.write(') '); 1256 writer.write(') ');
1256 _pushBlock(/*reentrant:*/true); 1257 _pushBlock(/*reentrant:*/true);
1257 node.body.visit(this); 1258 node.body.visit(this);
1258 _popBlock(); 1259 _popBlock();
1259 _popBlock(); 1260 _popBlock();
1260 return false; 1261 return false;
1261 } 1262 }
1262 1263
1264 bool _isFinal(typeRef) {
1265 if (typeRef is GenericTypeReference) {
1266 typeRef = typeRef.baseType;
1267 }
1268 return typeRef != null && typeRef.isFinal;
1269 }
1270
1263 bool visitForInStatement(ForInStatement node) { 1271 bool visitForInStatement(ForInStatement node) {
1264 // TODO(jimhug): visitValue and other cleanups here. 1272 // TODO(jimhug): visitValue and other cleanups here.
1265 var itemType = method.resolveType(node.item.type, false); 1273 var itemType = method.resolveType(node.item.type, false);
1266 var itemName = node.item.name.name; 1274 var itemName = node.item.name.name;
1267 var list = node.list.visit(this); 1275 var list = node.list.visit(this);
1268 _pushBlock(/*reentrant:*/true); 1276 _pushBlock(/*reentrant:*/true);
1269 // TODO(jimhug): Check that itemType matches list members... 1277 // TODO(jimhug): Check that itemType matches list members...
1270 var item = _scope.create(itemName, itemType, node.item.name.span); 1278 bool isFinal = _isFinal(node.item.type);
1279 var item = _scope.create(itemName, itemType, node.item.name.span, isFinal);
1271 Value listVar = list; 1280 Value listVar = list;
1272 if (list.needsTemp) { 1281 if (list.needsTemp) {
1273 listVar = _scope.create('\$list', list.type, null); 1282 listVar = _scope.create('\$list', list.type, null);
1274 writer.writeln('var ${listVar.code} = ${list.code};'); 1283 writer.writeln('var ${listVar.code} = ${list.code};');
1275 } 1284 }
1276 1285
1277 // Special path for list for readability and perf optimization. 1286 // Special path for list for readability and perf optimization.
1278 if (list.type.isList) { 1287 if (list.type.isList) {
1279 var tmpi = _scope.create('\$i', world.numType, null); 1288 var tmpi = _scope.create('\$i', world.numType, null);
1280 writer.enterBlock('for (var ${tmpi.code} = 0;' + 1289 writer.enterBlock('for (var ${tmpi.code} = 0;' +
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
1743 return members._set(this, position, x, y); 1752 return members._set(this, position, x, y);
1744 } else { 1753 } else {
1745 x = members._get(this, position, x); 1754 x = members._get(this, position, x);
1746 } 1755 }
1747 } 1756 }
1748 1757
1749 // Otherwise treat it as a field. 1758 // Otherwise treat it as a field.
1750 // This makes for nicer code in the $op= case 1759 // This makes for nicer code in the $op= case
1751 } 1760 }
1752 1761
1753 // TODO(jimhug): Needs checks for final and other rules to enforce. 1762 if (x.isFinal) {
jimhug 2011/11/17 15:36:15 Yay!
1763 world.error('final variable "${x.code}" is not assignable',
1764 position.span);
1765 }
1766
1754 y = y.convertTo(this, x.type, yn); 1767 y = y.convertTo(this, x.type, yn);
1755 1768
1756 if (kind == 0) { 1769 if (kind == 0) {
1757 x = captureOriginal(x); 1770 x = captureOriginal(x);
1758 return new Value(y.type, '${x.code} = ${y.code}', position.span); 1771 return new Value(y.type, '${x.code} = ${y.code}', position.span);
1759 } else if (x.type.isNum && y.type.isNum && (kind != TokenKind.TRUNCDIV)) { 1772 } else if (x.type.isNum && y.type.isNum && (kind != TokenKind.TRUNCDIV)) {
1760 // Process everything but ~/ , which has no equivalent JS operator 1773 // Process everything but ~/ , which has no equivalent JS operator
1761 x = captureOriginal(x); 1774 x = captureOriginal(x);
1762 // Very localized optimization for numbers! 1775 // Very localized optimization for numbers!
1763 final op = TokenKind.kindToString(kind); 1776 final op = TokenKind.kindToString(kind);
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after
2259 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); 2272 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false));
2260 } 2273 }
2261 for (int i = bareCount; i < length; i++) { 2274 for (int i = bareCount; i < length; i++) {
2262 var name = getName(i); 2275 var name = getName(i);
2263 if (name == null) name = '\$$i'; 2276 if (name == null) name = '\$$i';
2264 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); 2277 result.add(new Value(world.varType, name, null, /*needsTemp:*/false));
2265 } 2278 }
2266 return new Arguments(nodes, result); 2279 return new Arguments(nodes, result);
2267 } 2280 }
2268 } 2281 }
OLDNEW
« no previous file with comments | « frog/frogsh ('k') | frog/tree.dart » ('j') | frog/tree.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698