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

Side by Side Diff: frog/member.dart

Issue 8763001: Fix names with '$' to not conflict with operators or internal helpers (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merged again Created 9 years 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/library.dart ('k') | frog/parser.dart » ('j') | no next file with comments »
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 /** A formal parameter to a [Method]. */ 5 /** A formal parameter to a [Method]. */
6 class Parameter { 6 class Parameter {
7 FormalNode definition; 7 FormalNode definition;
8 Member method; 8 Member method;
9 9
10 String name; 10 String name;
(...skipping 18 matching lines...) Expand all
29 } 29 }
30 30
31 if (definition.value != null) { 31 if (definition.value != null) {
32 // To match VM, detect cases where value was not actually specified in 32 // To match VM, detect cases where value was not actually specified in
33 // code and don't signal errors. 33 // code and don't signal errors.
34 // TODO(jimhug): Clean up after issue #352 is resolved. 34 // TODO(jimhug): Clean up after issue #352 is resolved.
35 if (definition.value is NullExpression && 35 if (definition.value is NullExpression &&
36 definition.value.span.start == definition.span.start) { 36 definition.value.span.start == definition.span.start) {
37 return; 37 return;
38 } 38 }
39 if (method.name == '\$call') { 39 if (method.name == ':call') {
40 // TODO(jimhug): Need simpler way to detect "true" function types vs. 40 // TODO(jimhug): Need simpler way to detect "true" function types vs.
41 // regular methods being used as function types for closures. 41 // regular methods being used as function types for closures.
42 if (method.definition.body == null) { 42 if (method.definition.body == null) {
43 world.error('default value not allowed on function type', 43 world.error('default value not allowed on function type',
44 definition.span); 44 definition.span);
45 } 45 }
46 } else if (method.isAbstract) { 46 } else if (method.isAbstract) {
47 world.error('default value not allowed on abstract methods', 47 world.error('default value not allowed on abstract methods',
48 definition.span); 48 definition.span);
49 } 49 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 bool get isProperty() => false; 101 bool get isProperty() => false;
102 bool get isAbstract() => false; 102 bool get isAbstract() => false;
103 103
104 bool get isFinal() => false; 104 bool get isFinal() => false;
105 105
106 // TODO(jmesserly): these only makes sense on methods, but because of 106 // TODO(jmesserly): these only makes sense on methods, but because of
107 // ConcreteMember we need to support them on Member. 107 // ConcreteMember we need to support them on Member.
108 bool get isConst() => false; 108 bool get isConst() => false;
109 bool get isFactory() => false; 109 bool get isFactory() => false;
110 110
111 bool get isOperator() => name.startsWith('\$'); 111 bool get isOperator() => name.startsWith(':');
112 bool get isCallMethod() => name == '\$call'; 112 bool get isCallMethod() => name == ':call';
113 113
114 bool get prefersPropertySyntax() => true; 114 bool get prefersPropertySyntax() => true;
115 bool get requiresFieldSyntax() => false; 115 bool get requiresFieldSyntax() => false;
116 116
117 bool get isNative() => false; 117 bool get isNative() => false;
118 String get constructorName() { 118 String get constructorName() {
119 world.internalError('can not be a constructor', span); 119 world.internalError('can not be a constructor', span);
120 } 120 }
121 121
122 // Don't display an error here; we'll get a better error later. 122 // Don't display an error here; we'll get a better error later.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 // TODO(jmesserly): isDynamic isn't a great name for this, something better? 155 // TODO(jmesserly): isDynamic isn't a great name for this, something better?
156 abstract Value _get(MethodGenerator context, Node node, Value target, 156 abstract Value _get(MethodGenerator context, Node node, Value target,
157 [bool isDynamic]); 157 [bool isDynamic]);
158 158
159 abstract Value _set(MethodGenerator context, Node node, Value target, 159 abstract Value _set(MethodGenerator context, Node node, Value target,
160 Value value, [bool isDynamic]); 160 Value value, [bool isDynamic]);
161 161
162 bool canInvoke(MethodGenerator context, Arguments args) { 162 bool canInvoke(MethodGenerator context, Arguments args) {
163 // No source location needed because canInvoke may not produce errors. 163 // No source location needed because canInvoke may not produce errors.
164 return canGet && 164 return canGet &&
165 new Value(returnType, null, null).canInvoke(context, '\$call', args); 165 new Value(returnType, null, null).canInvoke(context, ':call', args);
166 } 166 }
167 167
168 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, 168 Value invoke(MethodGenerator context, Node node, Value target, Arguments args,
169 [bool isDynamic=false]) { 169 [bool isDynamic=false]) {
170 var newTarget = _get(context, node, target, isDynamic); 170 var newTarget = _get(context, node, target, isDynamic);
171 return newTarget.invoke(context, '\$call', node, args, isDynamic); 171 return newTarget.invoke(context, ':call', node, args, isDynamic);
172 } 172 }
173 173
174 bool override(Member other) { 174 bool override(Member other) {
175 if (isStatic) { 175 if (isStatic) {
176 world.error('static members can not hide parent members', 176 world.error('static members can not hide parent members',
177 span, other.span); 177 span, other.span);
178 return false; 178 return false;
179 } else if (other.isStatic) { 179 } else if (other.isStatic) {
180 world.error('can not override static member', span, other.span); 180 world.error('can not override static member', span, other.span);
181 return false; 181 return false;
(...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 return new Value(inferredResult, 956 return new Value(inferredResult,
957 '${declaringType.jsname}.$jsname($argsString)', node.span); 957 '${declaringType.jsname}.$jsname($argsString)', node.span);
958 } 958 }
959 959
960 var code = '${target.code}.$jsname($argsString)'; 960 var code = '${target.code}.$jsname($argsString)';
961 // optimize expressions which we know statically their value. 961 // optimize expressions which we know statically their value.
962 if (target.isConst) { 962 if (target.isConst) {
963 if (target is GlobalValue) { 963 if (target is GlobalValue) {
964 target = target.dynamic.exp; // TODO: an inline "cast" would be nice. 964 target = target.dynamic.exp; // TODO: an inline "cast" would be nice.
965 } 965 }
966 if (name == 'get\$length') { 966 if (name == 'get:length') {
967 if (target is ConstListValue || target is ConstMapValue) { 967 if (target is ConstListValue || target is ConstMapValue) {
968 code = '${target.dynamic.values.length}'; 968 code = '${target.dynamic.values.length}';
969 } 969 }
970 } else if (name == 'isEmpty') { 970 } else if (name == 'isEmpty') {
971 if (target is ConstListValue || target is ConstMapValue) { 971 if (target is ConstListValue || target is ConstMapValue) {
972 code = '${target.dynamic.values.isEmpty()}'; 972 code = '${target.dynamic.values.isEmpty()}';
973 } 973 }
974 } 974 }
975 } 975 }
976 976
977 // TODO(jmesserly): factor this better 977 // TODO(jmesserly): factor this better
978 if (name == 'get\$typeName' && declaringType.library == world.dom) { 978 if (name == 'get:typeName' && declaringType.library == world.dom) {
979 world.gen.corejs.ensureTypeNameOf(); 979 world.gen.corejs.ensureTypeNameOf();
980 } 980 }
981 981
982 return new Value(inferredResult, code, node.span); 982 return new Value(inferredResult, code, node.span);
983 } 983 }
984 984
985 Value _invokeConstructor(MethodGenerator context, Node node, 985 Value _invokeConstructor(MethodGenerator context, Node node,
986 Value target, Arguments args, argsString) { 986 Value target, Arguments args, argsString) {
987 declaringType.markUsed(); 987 declaringType.markUsed();
988 988
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1113 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, 1113 Value _invokeBuiltin(MethodGenerator context, Node node, Value target,
1114 Arguments args, argsCode, bool isDynamic) { 1114 Arguments args, argsCode, bool isDynamic) {
1115 var allConst = target.isConst && args.values.every((arg) => arg.isConst); 1115 var allConst = target.isConst && args.values.every((arg) => arg.isConst);
1116 1116
1117 // Handle some fast paths for Number, String, List and DOM. 1117 // Handle some fast paths for Number, String, List and DOM.
1118 if (declaringType.isNum) { 1118 if (declaringType.isNum) {
1119 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num. 1119 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num.
1120 // TODO(jimhug): What about null? 1120 // TODO(jimhug): What about null?
1121 if (!allConst) { 1121 if (!allConst) {
1122 var code; 1122 var code;
1123 if (name == '\$negate') { 1123 if (name == ':negate') {
1124 code = '-${target.code}'; 1124 code = '-${target.code}';
1125 } else if (name == '\$bit_not') { 1125 } else if (name == ':bit_not') {
1126 code = '~${target.code}'; 1126 code = '~${target.code}';
1127 } else if (name == '\$truncdiv' || name == '\$mod') { 1127 } else if (name == ':truncdiv' || name == ':mod') {
1128 world.gen.corejs.useOperator(name); 1128 world.gen.corejs.useOperator(name);
1129 code = '$name(${target.code}, ${argsCode[0]})'; 1129 code = '$jsname(${target.code}, ${argsCode[0]})';
1130 } else { 1130 } else {
1131 var op = TokenKind.rawOperatorFromMethod(name); 1131 var op = TokenKind.rawOperatorFromMethod(name);
1132 code = '${target.code} $op ${argsCode[0]}'; 1132 code = '${target.code} $op ${argsCode[0]}';
1133 } 1133 }
1134 1134
1135 return new Value(inferredResult, code, node.span); 1135 return new Value(inferredResult, code, node.span);
1136 } else { 1136 } else {
1137 var value; 1137 var value;
1138 num val0, val1, ival0, ival1; 1138 num val0, val1, ival0, ival1;
1139 val0 = target.dynamic.actualValue; 1139 val0 = target.dynamic.actualValue;
1140 ival0 = val0.toInt(); 1140 ival0 = val0.toInt();
1141 if (args.values.length > 0) { 1141 if (args.values.length > 0) {
1142 val1 = args.values[0].dynamic.actualValue; 1142 val1 = args.values[0].dynamic.actualValue;
1143 ival1 = val1.toInt(); 1143 ival1 = val1.toInt();
1144 } 1144 }
1145 switch (name) { 1145 switch (name) {
1146 case '\$negate': value = -val0; break; 1146 case ':negate': value = -val0; break;
1147 case '\$add': value = val0 + val1; break; 1147 case ':add': value = val0 + val1; break;
1148 case '\$sub': value = val0 - val1; break; 1148 case ':sub': value = val0 - val1; break;
1149 case '\$mul': value = val0 * val1; break; 1149 case ':mul': value = val0 * val1; break;
1150 case '\$div': value = val0 / val1; break; 1150 case ':div': value = val0 / val1; break;
1151 case '\$truncdiv': value = val0 ~/ val1; break; 1151 case ':truncdiv': value = val0 ~/ val1; break;
1152 case '\$mod': value = val0 % val1; break; 1152 case ':mod': value = val0 % val1; break;
1153 case '\$eq': value = val0 == val1; break; 1153 case ':eq': value = val0 == val1; break;
1154 case '\$lt': value = val0 < val1; break; 1154 case ':lt': value = val0 < val1; break;
1155 case '\$gt': value = val0 > val1; break; 1155 case ':gt': value = val0 > val1; break;
1156 case '\$lte': value = val0 <= val1; break; 1156 case ':lte': value = val0 <= val1; break;
1157 case '\$gte': value = val0 >= val1; break; 1157 case ':gte': value = val0 >= val1; break;
1158 case '\$ne': value = val0 != val1; break; 1158 case ':ne': value = val0 != val1; break;
1159 1159
1160 // Note: unfortunatelly bit operations fail on doubles in dartvm 1160 // Note: unfortunatelly bit operations fail on doubles in dartvm
1161 case '\$bit_not': value = (~ival0).toDouble(); break; 1161 case ':bit_not': value = (~ival0).toDouble(); break;
1162 case '\$bit_or': value = (ival0 | ival1).toDouble(); break; 1162 case ':bit_or': value = (ival0 | ival1).toDouble(); break;
1163 case '\$bit_xor': value = (ival0 ^ ival1).toDouble(); break; 1163 case ':bit_xor': value = (ival0 ^ ival1).toDouble(); break;
1164 case '\$bit_and': value = (ival0 & ival1).toDouble(); break; 1164 case ':bit_and': value = (ival0 & ival1).toDouble(); break;
1165 case '\$shl': value = (ival0 << ival1).toDouble(); break; 1165 case ':shl': value = (ival0 << ival1).toDouble(); break;
1166 case '\$sar': value = (ival0 >> ival1).toDouble(); break; 1166 case ':sar': value = (ival0 >> ival1).toDouble(); break;
1167 case '\$shr': value = (ival0 >>> ival1).toDouble(); break; 1167 case ':shr': value = (ival0 >>> ival1).toDouble(); break;
1168 } 1168 }
1169 return new EvaluatedValue(inferredResult, value, "$value", node.span); 1169 return new EvaluatedValue(inferredResult, value, "$value", node.span);
1170 } 1170 }
1171 } else if (declaringType.isString) { 1171 } else if (declaringType.isString) {
1172 if (name == '\$index') { 1172 if (name == ':index') {
1173 // Note: this could technically propagate constness, but that's not 1173 // Note: this could technically propagate constness, but that's not
1174 // specified explicitly and the VM doesn't do that. 1174 // specified explicitly and the VM doesn't do that.
1175 return new Value(declaringType, '${target.code}[${argsCode[0]}]', 1175 return new Value(declaringType, '${target.code}[${argsCode[0]}]',
1176 node.span); 1176 node.span);
1177 } else if (name == '\$add') { 1177 } else if (name == ':add') {
1178 if (allConst) { 1178 if (allConst) {
1179 final value = _normConcat(target, args.values[0]); 1179 final value = _normConcat(target, args.values[0]);
1180 return new EvaluatedValue(world.stringType, value, value, node.span); 1180 return new EvaluatedValue(world.stringType, value, value, node.span);
1181 } 1181 }
1182 1182
1183 // Ensure we generate toString on the right side 1183 // Ensure we generate toString on the right side
1184 return new Value(declaringType, '${target.code} + ${argsCode[0]}', 1184 return new Value(declaringType, '${target.code} + ${argsCode[0]}',
1185 node.span); 1185 node.span);
1186 } 1186 }
1187 } else if (declaringType.isNative) { 1187 } else if (declaringType.isNative) {
1188 if (name == '\$index') { 1188 if (name == ':index') {
1189 // Note: this could technically propagate constness, but that's not 1189 // Note: this could technically propagate constness, but that's not
1190 // specified explicitly and the VM doesn't do that. 1190 // specified explicitly and the VM doesn't do that.
1191 return new Value(returnType, '${target.code}[${argsCode[0]}]', node.span ); 1191 return new Value(returnType, '${target.code}[${argsCode[0]}]', node.span );
1192 } else if (name == '\$setindex') { 1192 } else if (name == ':setindex') {
1193 return new Value(returnType, 1193 return new Value(returnType,
1194 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span); 1194 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span);
1195 } 1195 }
1196 } 1196 }
1197 1197
1198 // TODO(jimhug): Optimize null on lhs as well. 1198 // TODO(jimhug): Optimize null on lhs as well.
1199 if (name == '\$eq' || name == '\$ne') { 1199 if (name == ':eq' || name == ':ne') {
1200 final op = name == '\$eq' ? '==' : '!='; 1200 final op = name == ':eq' ? '==' : '!=';
1201 1201
1202 if (name == '\$ne') { 1202 if (name == ':ne') {
1203 // Ensure == is generated. 1203 // Ensure == is generated.
1204 target.invoke(context, '\$eq', node, args, isDynamic); 1204 target.invoke(context, ':eq', node, args, isDynamic);
1205 } 1205 }
1206 1206
1207 if (allConst) { 1207 if (allConst) {
1208 var val0 = target.dynamic.actualValue; 1208 var val0 = target.dynamic.actualValue;
1209 var val1 = args.values[0].dynamic.actualValue; 1209 var val1 = args.values[0].dynamic.actualValue;
1210 var newVal = name == '\$eq' ? val0 == val1 : val0 != val1; 1210 var newVal = name == ':eq' ? val0 == val1 : val0 != val1;
1211 return new EvaluatedValue(world.nonNullBool, 1211 return new EvaluatedValue(world.nonNullBool,
1212 newVal, "$newVal", node.span); 1212 newVal, "$newVal", node.span);
1213 } 1213 }
1214 // Optimize test when null is on the rhs. 1214 // Optimize test when null is on the rhs.
1215 if (argsCode[0] == 'null') { 1215 if (argsCode[0] == 'null') {
1216 return new Value(inferredResult, '${target.code} $op null', node.span); 1216 return new Value(inferredResult, '${target.code} $op null', node.span);
1217 } else if (target.type.isNum || target.type.isString) { 1217 } else if (target.type.isNum || target.type.isString) {
1218 // TODO(jimhug): Maybe check rhs. 1218 // TODO(jimhug): Maybe check rhs.
1219 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', 1219 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}',
1220 node.span); 1220 node.span);
1221 } 1221 }
1222 world.gen.corejs.useOperator(name); 1222 world.gen.corejs.useOperator(name);
1223 return new Value(inferredResult, '$name(${target.code}, ${argsCode[0]})', 1223 return new Value(inferredResult,
1224 node.span); 1224 '$jsname(${target.code}, ${argsCode[0]})', node.span);
1225 } 1225 }
1226 1226
1227 if (isCallMethod) { 1227 if (isCallMethod) {
1228 declaringType.markUsed(); 1228 declaringType.markUsed();
1229 return new Value(inferredResult, 1229 return new Value(inferredResult,
1230 '${target.code}(${Strings.join(argsCode, ", ")})', node.span); 1230 '${target.code}(${Strings.join(argsCode, ", ")})', node.span);
1231 } 1231 }
1232 1232
1233 if (name == '\$index') { 1233 if (name == ':index') {
1234 world.gen.corejs.useIndex = true; 1234 world.gen.corejs.useIndex = true;
1235 } else if (name == '\$setindex') { 1235 } else if (name == ':setindex') {
1236 world.gen.corejs.useSetIndex = true; 1236 world.gen.corejs.useSetIndex = true;
1237 } 1237 }
1238 1238
1239 // Fall back to normal method invocation. 1239 // Fall back to normal method invocation.
1240 var argsString = Strings.join(argsCode, ', '); 1240 var argsString = Strings.join(argsCode, ', ');
1241 return new Value(inferredResult, '${target.code}.$jsname($argsString)', 1241 return new Value(inferredResult, '${target.code}.$jsname($argsString)',
1242 node.span); 1242 node.span);
1243 } 1243 }
1244 1244
1245 /** 1245 /**
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
1532 // up with a bogus unused temp generated (usually "var $0"). We need a way 1532 // up with a bogus unused temp generated (usually "var $0"). We need a way
1533 // to throw away temps when we throw away the code. 1533 // to throw away temps when we throw away the code.
1534 returnValue = _tryUnion(returnValue, res, node); 1534 returnValue = _tryUnion(returnValue, res, node);
1535 } 1535 }
1536 1536
1537 if (returnValue == null) { 1537 if (returnValue == null) {
1538 return _makeError(node, target, 'method'); 1538 return _makeError(node, target, 'method');
1539 } 1539 }
1540 1540
1541 if (returnValue.code == null) { 1541 if (returnValue.code == null) {
1542 if (name == '\$call') { 1542 if (name == ':call') {
1543 // TODO(jmesserly): reconcile this with similar code in Value 1543 // TODO(jmesserly): reconcile this with similar code in Value
1544 return target._varCall(context, args); 1544 return target._varCall(context, args);
1545 } else if (isOperator) { 1545 } else if (isOperator) {
1546 // TODO(jmesserly): make operators less special. 1546 // TODO(jmesserly): make operators less special.
1547 return target.invokeSpecial(name, args, returnValue.type); 1547 return invokeSpecial(target, args, returnValue.type);
1548 } else { 1548 } else {
1549 return invokeOnVar(context, node, target, args); 1549 return invokeOnVar(context, node, target, args);
1550 } 1550 }
1551 } 1551 }
1552 1552
1553 return returnValue; 1553 return returnValue;
1554 } 1554 }
1555 1555
1556 Value invokeSpecial(Value target, Arguments args, Type returnType) {
1557 assert(name.startsWith(':'));
1558 assert(!args.hasNames);
1559 // TODO(jimhug): We need to do this a little bit more like get and set on
1560 // properties. We should check the set of members for something
1561 // like "requiresNativeIndexer" and "requiresDartIndexer" to
1562 // decide on a strategy.
1563
1564 var argsString = args.getCode();
1565 // Most operator calls need to be emitted as function calls, so we don't
1566 // box numbers accidentally. Indexing is the exception.
1567 if (name == ':index' || name == ':setindex') {
1568 return new Value(returnType, '${target.code}.$jsname($argsString)',
1569 target.span);
1570 } else {
1571 if (argsString.length > 0) argsString = ', $argsString';
1572 world.gen.corejs.useOperator(name);
1573 return new Value(returnType, '$jsname(${target.code}$argsString)',
1574 target.span);
1575 }
1576 }
1577
1556 Value invokeOnVar(MethodGenerator context, Node node, Value target, 1578 Value invokeOnVar(MethodGenerator context, Node node, Value target,
1557 Arguments args) { 1579 Arguments args) {
1558 var member = getVarMember(context, node, args); 1580 var member = getVarMember(context, node, args);
1559 return member.invoke(context, node, target, args); 1581 return member.invoke(context, node, target, args);
1560 } 1582 }
1561 1583
1562 Value _union(Value x, Value y, Node node) { 1584 Value _union(Value x, Value y, Node node) {
1563 var result = _tryUnion(x, y, node); 1585 var result = _tryUnion(x, y, node);
1564 if (result.code == null) { 1586 if (result.code == null) {
1565 world.internalError('mismatched code for $name (${x.code}, ${y.code})', 1587 world.internalError('mismatched code for $name (${x.code}, ${y.code})',
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
1682 } 1704 }
1683 1705
1684 void forEach(void f(Member member)) { 1706 void forEach(void f(Member member)) {
1685 factories.forEach((_, Map constructors) { 1707 factories.forEach((_, Map constructors) {
1686 constructors.forEach((_, Member member) { 1708 constructors.forEach((_, Member member) {
1687 f(member); 1709 f(member);
1688 }); 1710 });
1689 }); 1711 });
1690 } 1712 }
1691 } 1713 }
OLDNEW
« no previous file with comments | « frog/library.dart ('k') | frog/parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698