Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 var key = "${field.declaringType.jsname}.${field.jsname}"; | 137 var key = "${field.declaringType.jsname}.${field.jsname}"; |
| 138 var ret = globals[key]; | 138 var ret = globals[key]; |
| 139 if (ret === null) { | 139 if (ret === null) { |
| 140 ret = new GlobalValue(exp.type, exp.code, field.isFinal, field, null, | 140 ret = new GlobalValue(exp.type, exp.code, field.isFinal, field, null, |
| 141 exp, exp.span, dependencies); | 141 exp, exp.span, dependencies); |
| 142 globals[key] = ret; | 142 globals[key] = ret; |
| 143 } | 143 } |
| 144 return ret; | 144 return ret; |
| 145 } | 145 } |
| 146 | 146 |
| 147 GlobalValue globalForConst(EvaluatedValue exp, List<Value> dependencies) { | 147 GlobalValue globalForConst(Value exp, List<Value> dependencies) { |
| 148 // Include type name to ensure unique constants - this matches | 148 // Include type name to ensure unique constants - this matches |
| 149 // the code above that includes the type name for static fields. | 149 // the code above that includes the type name for static fields. |
| 150 var key = exp.type.jsname + ':' + exp.code; | 150 var key = exp.type.jsname + ':' + exp.code; |
| 151 var ret = globals[key]; | 151 var ret = globals[key]; |
| 152 if (ret === null) { | 152 if (ret === null) { |
| 153 var name = "const\$${globals.length}"; | 153 // another egregious hack!!! |
| 154 var ns = globals.length.toString(); | |
| 155 while (ns.length < 4) ns = '0' + ns; | |
| 156 var name = "const\$${ns}"; | |
| 154 ret = new GlobalValue(exp.type, name, true, null, name, exp, | 157 ret = new GlobalValue(exp.type, name, true, null, name, exp, |
| 155 exp.span, dependencies); | 158 exp.span, dependencies); |
| 156 globals[key] = ret; | 159 globals[key] = ret; |
| 157 } | 160 } |
| 158 assert(ret.type == exp.type); | 161 assert(ret.type == exp.type); |
| 159 return ret; | 162 return ret; |
| 160 } | 163 } |
| 161 | 164 |
| 162 writeTypes(Library lib) { | 165 writeTypes(Library lib) { |
| 163 if (lib.isWritten) return; | 166 if (lib.isWritten) return; |
| (...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 922 | 925 |
| 923 void freeTemp(Value value) { | 926 void freeTemp(Value value) { |
| 924 if (_usedTemps.remove(value.code)) { | 927 if (_usedTemps.remove(value.code)) { |
| 925 _freeTemps.add(value.code); | 928 _freeTemps.add(value.code); |
| 926 } else { | 929 } else { |
| 927 world.internalError( | 930 world.internalError( |
| 928 'tried to free unused value or non-temp "${value.code}"'); | 931 'tried to free unused value or non-temp "${value.code}"'); |
| 929 } | 932 } |
| 930 } | 933 } |
| 931 | 934 |
| 935 /* | |
| 936 run1(Value thisValue, Arguments args) { | |
| 937 // Use some sort of key to do a lookup | |
| 938 | |
| 939 | |
| 940 }*/ | |
| 941 | |
| 932 run() { | 942 run() { |
| 933 if (method.isGenerated) return; | 943 if (method.isGenerated) return; |
| 934 | 944 |
| 935 // This avoids any attempts to infer across recursion. | 945 // This avoids any attempts to infer across recursion. |
| 936 method.isGenerated = true; | 946 method.isGenerated = true; |
| 937 method.generator = this; | 947 method.generator = this; |
| 938 | 948 |
| 939 writeBody(); | 949 // Create most generic possible call for this method. |
| 950 var thisObject; | |
| 951 if (method.isConstructor) { | |
| 952 thisObject = new ObjectValue(false, method.declaringType, method.span); | |
| 953 thisObject.initFields(); | |
| 954 } else { | |
| 955 thisObject = new Value(method.declaringType, 'this', null); | |
| 956 } | |
| 957 var values = []; | |
| 958 for (var p in method.parameters) { | |
| 959 values.add(new Value(p.type, p.name, null)); | |
| 960 } | |
| 961 var args = new Arguments(null, values); | |
| 962 | |
| 963 evalBody(thisObject, args); | |
| 940 | 964 |
| 941 if (method.definition.nativeBody != null) { | 965 if (method.definition.nativeBody != null) { |
| 942 // Throw away the code--it was just used for tree shaking purposes. | 966 // Throw away the code--it was just used for tree shaking purposes. |
| 943 writer = new CodeWriter(); | 967 writer = new CodeWriter(); |
| 944 if (method.definition.nativeBody == '') { | 968 if (method.definition.nativeBody == '') { |
| 945 method.generator = null; | 969 method.generator = null; |
| 946 } else { | 970 } else { |
| 947 _paramCode = map(method.parameters, (p) => p.name); | 971 _paramCode = map(method.parameters, (p) => p.name); |
| 948 writer.write(method.definition.nativeBody); | 972 writer.write(method.definition.nativeBody); |
| 949 } | 973 } |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1080 } | 1104 } |
| 1081 | 1105 |
| 1082 optNames.addAll(optValues); | 1106 optNames.addAll(optValues); |
| 1083 var optional = "['" + Strings.join(optNames, "', '") + "']"; | 1107 var optional = "['" + Strings.join(optNames, "', '") + "']"; |
| 1084 defWriter.writeln('${start}${meth.jsname}.\$optional = $optional'); | 1108 defWriter.writeln('${start}${meth.jsname}.\$optional = $optional'); |
| 1085 } | 1109 } |
| 1086 } | 1110 } |
| 1087 } | 1111 } |
| 1088 } | 1112 } |
| 1089 | 1113 |
| 1090 writeBody() { | 1114 _initField(ObjectValue newObject, String name, Value value, SourceSpan span) { |
| 1091 var initializers = null; | 1115 var field = method.declaringType.getMember(name); |
| 1092 var initializedFields = null; // to check that final fields are initialized | 1116 if (field == null) { |
| 1093 var allMembers = null; | 1117 world.error('bad initializer - no matching field', span); |
| 1094 if (method.isConstructor) { | 1118 } |
| 1095 initializers = []; | 1119 if (!field.isField) { |
| 1096 initializedFields = new Set(); | 1120 world.error('"this.${name}" does not refer to a field', span); |
| 1097 allMembers = world.gen._orderValues(method.declaringType.getAllMembers()); | 1121 } |
| 1098 for (var f in allMembers) { | 1122 return newObject.setField(field, value, duringInit: true); |
| 1099 if (f.isField && !f.isStatic) { | 1123 } |
| 1100 var cv = f.computeValue(); | 1124 |
| 1101 if (cv != null) { | 1125 evalBody(Value newObject, Arguments args) { |
| 1102 initializers.add('this.${f.jsname} = ${cv.code}'); | 1126 bool fieldsSet = false; |
| 1103 initializedFields.add(f.name); | 1127 if (method.isNative && method.isConstructor && newObject is ObjectValue) { |
| 1104 } | 1128 newObject.dynamic.seenNativeInitializer = true; |
|
Jennifer Messerly
2012/01/09 20:45:35
I see you've embraced the Dart "cast" syntax ;)
| |
| 1129 } | |
| 1130 // Collects parameters for writing signature in the future. | |
| 1131 _paramCode = []; | |
| 1132 for (int i = 0; i < method.parameters.length; i++) { | |
| 1133 var p = method.parameters[i]; | |
| 1134 Value currentArg = null; | |
| 1135 // TODO(jimhug): bareCount is O(N) | |
|
Jennifer Messerly
2012/01/09 20:45:35
It gets cached though. So it's amortized O(1)
jimhug
2012/01/09 21:12:17
I'd missed that! Thanks, I'll remove the comment.
| |
| 1136 if (i < args.bareCount) { | |
| 1137 currentArg = args.values[i]; | |
| 1138 } else { | |
| 1139 // Handle named or missing arguments | |
| 1140 currentArg = args.getValue(p.name); | |
| 1141 if (currentArg === null) { | |
| 1142 // Ensure default value for param has been generated | |
| 1143 p.genValue(method, method.generator); | |
| 1144 currentArg = p.value; | |
| 1145 } | |
| 1146 } | |
| 1147 | |
| 1148 if (p.isInitializer) { | |
| 1149 _paramCode.add(p.name); | |
| 1150 fieldsSet = true; | |
| 1151 _initField(newObject, p.name, currentArg, p.definition.span); | |
| 1152 } else { | |
| 1153 var paramValue = _scope.declareParameter(p); | |
| 1154 _paramCode.add(paramValue.code); | |
| 1155 if (newObject != null && newObject.isConst) { | |
| 1156 _scope._vars[p.name] = currentArg; | |
| 1105 } | 1157 } |
| 1106 } | 1158 } |
| 1107 } | 1159 } |
| 1108 | 1160 |
| 1109 // Collects parameters for writing signature in the future. | 1161 var initializerCall = null; |
| 1110 _paramCode = []; | 1162 final declaredInitializers = method.definition.initializers; |
| 1111 for (var p in method.parameters) { | 1163 if (declaredInitializers != null) { |
| 1112 if (initializers != null && p.isInitializer) { | 1164 for (var init in declaredInitializers) { |
| 1113 var field = method.declaringType.getMember(p.name); | 1165 if (init is CallExpression) { |
| 1114 if (field == null) { | 1166 if (initializerCall != null) { |
| 1115 world.error('bad this parameter - no matching field', | 1167 world.error('only one initializer redirecting call is allowed', |
| 1116 p.definition.span); | 1168 init.span); |
| 1169 } | |
| 1170 initializerCall = init; | |
| 1171 } else if (init is BinaryExpression | |
| 1172 && TokenKind.kindFromAssign(init.op.kind) == 0) { | |
| 1173 var left = init.x; | |
| 1174 if (!(left is DotExpression && left.self is ThisExpression | |
| 1175 || left is VarExpression)) { | |
| 1176 world.error('invalid left side of initializer', left.span); | |
| 1177 continue; | |
| 1178 } | |
| 1179 // TODO(jmesserly): eval right side of initializers in static | |
| 1180 // context, so "this." is not in scope | |
| 1181 var initValue = visitValue(init.y); | |
| 1182 fieldsSet = true; | |
| 1183 _initField(newObject, left.name.name, initValue, left.span); | |
| 1184 } else { | |
| 1185 world.error('invalid initializer', init.span); | |
| 1117 } | 1186 } |
| 1118 if (!field.isField) { | |
| 1119 world.error('"this.${p.name}" does not refer to a field', | |
| 1120 p.definition.span); | |
| 1121 } | |
| 1122 var paramValue = new Value(field.returnType, p.name, | |
| 1123 p.definition.span, false); | |
| 1124 _paramCode.add(paramValue.code); | |
| 1125 | |
| 1126 initializers.add('this.${field.jsname} = ${paramValue.code};'); | |
| 1127 initializedFields.add(p.name); | |
| 1128 } else { | |
| 1129 var paramValue = _scope.declareParameter(p); | |
| 1130 _paramCode.add(paramValue.code); | |
| 1131 } | 1187 } |
| 1132 } | 1188 } |
| 1133 | 1189 |
| 1134 var body = method.definition.body; | |
| 1135 | |
| 1136 if (body == null && !method.isConstructor && !method.isNative) { | |
| 1137 world.error('unexpected empty body for ${method.name}', | |
| 1138 method.definition.span); | |
| 1139 } | |
| 1140 | |
| 1141 var initializerCall = null; | |
| 1142 final declaredInitializers = method.definition.initializers; | |
| 1143 if (initializers != null) { | |
| 1144 for (var i in initializers) { | |
| 1145 writer.writeln(i); | |
| 1146 } | |
| 1147 if (declaredInitializers != null) { | |
| 1148 for (var init in declaredInitializers) { | |
| 1149 // TODO(jmesserly): eval right side of initializers in static context, | |
| 1150 // so "this." is not in scope | |
| 1151 // TODO(jmesserly): this has diverged from code in member.dart, | |
| 1152 // _invokeConstConstructor. Need to unify these paths. | |
| 1153 // TODO(jimhug): Lot's of correctness to verify here. | |
| 1154 if (init is CallExpression) { | |
| 1155 if (initializerCall != null) { | |
| 1156 world.error('only one initializer redirecting call is allowed', | |
| 1157 init.span); | |
| 1158 } | |
| 1159 initializerCall = init; | |
| 1160 } else if (init is BinaryExpression | |
| 1161 && TokenKind.kindFromAssign(init.op.kind) == 0) { | |
| 1162 | |
| 1163 var left = init.x; | |
| 1164 if (!(left is DotExpression && left.self is ThisExpression | |
| 1165 || left is VarExpression)) { | |
| 1166 world.error('invalid left side of initializer', left.span); | |
| 1167 continue; | |
| 1168 } | |
| 1169 | |
| 1170 var f = method.declaringType.getMember(left.name.name); | |
| 1171 if (f == null) { | |
| 1172 world.error('bad initializer - no matching field', left.span); | |
| 1173 continue; | |
| 1174 } else if (!f.isField) { | |
| 1175 world.error('"${left.name.name}" does not refer to a field', | |
| 1176 left.span); | |
| 1177 continue; | |
| 1178 } | |
| 1179 | |
| 1180 initializedFields.add(f.name); | |
| 1181 writer.writeln('this.${f.jsname} = ${visitValue(init.y).code};'); | |
| 1182 } else { | |
| 1183 world.error('invalid initializer', init.span); | |
| 1184 } | |
| 1185 } | |
| 1186 } | |
| 1187 writer.comment('// Initializers done'); | |
| 1188 } | |
| 1189 | |
| 1190 if (method.isConstructor && initializerCall == null && !method.isNative) { | 1190 if (method.isConstructor && initializerCall == null && !method.isNative) { |
| 1191 var parentType = method.declaringType.parent; | 1191 var parentType = method.declaringType.parent; |
| 1192 if (parentType != null && !parentType.isObject) { | 1192 if (parentType != null && !parentType.isObject) { |
| 1193 // TODO(jmesserly): we could omit this if all supertypes are using | 1193 // TODO(jmesserly): we could omit this if all supertypes are using |
| 1194 // default constructors. | 1194 // default constructors. |
| 1195 initializerCall = new CallExpression( | 1195 initializerCall = new CallExpression( |
| 1196 new SuperExpression(method.span), [], method.span); | 1196 new SuperExpression(method.span), [], method.span); |
| 1197 } | 1197 } |
| 1198 } | 1198 } |
| 1199 | 1199 |
| 1200 if (initializerCall != null) { | 1200 if (method.isConstructor && newObject is ObjectValue) { |
| 1201 var target = _writeInitializerCall(initializerCall); | 1201 var fields = newObject.dynamic.fields; |
| 1202 if (!target.isSuper) { | 1202 for (var field in fields.getKeys()) { |
| 1203 // when calling another constructor on the same class | 1203 var value = fields[field]; |
| 1204 // no other initialization is allowed | 1204 if (value !== null) { |
| 1205 if (initializers.length > 0) { | 1205 writer.writeln('this.${field.jsname} = ${value.code};'); |
| 1206 for (var p in method.parameters) { | |
| 1207 if (p.isInitializer) { | |
| 1208 world.error( | |
| 1209 'no initialization allowed on redirecting constructors', | |
| 1210 p.definition.span); | |
| 1211 break; | |
| 1212 } | |
| 1213 } | |
| 1214 } | |
| 1215 if (declaredInitializers != null && declaredInitializers.length > 1) { | |
| 1216 var init = declaredInitializers[0] == initializerCall | |
| 1217 ? declaredInitializers[1] : declaredInitializers[0]; | |
| 1218 world.error( | |
| 1219 'no initialization allowed on redirecting constructors', | |
| 1220 init.span); | |
| 1221 } | |
| 1222 initializedFields = null; | |
| 1223 } | |
| 1224 } | |
| 1225 | |
| 1226 // check that initialization was correct | |
| 1227 if (initializedFields != null) { | |
| 1228 for (var member in allMembers) { | |
| 1229 if (member.isField && member.isFinal && !member.isStatic | |
| 1230 && !method.isNative && !initializedFields.contains(member.name)) { | |
| 1231 world.error('Field "${member.name}" is final and was not initialized', | |
| 1232 method.definition.span); | |
| 1233 } | 1206 } |
| 1234 } | 1207 } |
| 1235 } | 1208 } |
| 1236 | 1209 |
| 1237 visitStatementsInBlock(body); | 1210 // TODO(jimhug): Doing this call last does not match spec. |
| 1211 if (initializerCall != null) { | |
| 1212 evalInitializerCall(newObject, initializerCall, fieldsSet); | |
| 1213 } | |
| 1214 | |
| 1215 if (method.isConstructor && newObject !== null && newObject.isConst) { | |
| 1216 newObject.validateInitialized(method.span); | |
| 1217 } else if (method.isConstructor) { | |
| 1218 var fields = newObject.dynamic.fields; | |
| 1219 for (var field in fields.getKeys()) { | |
| 1220 var value = fields[field]; | |
| 1221 if (value === null && field.isFinal && | |
| 1222 field.declaringType == method.declaringType && | |
| 1223 !newObject.dynamic.seenNativeInitializer) { | |
| 1224 world.error('uninitialized final field "${field.name}"', | |
| 1225 field.span, method.span); | |
| 1226 } | |
| 1227 } | |
| 1228 } | |
| 1229 | |
| 1230 var body = method.definition.body; | |
| 1231 | |
| 1232 if (body === null) { | |
| 1233 // TODO(jimhug): Move check into resolve on method. | |
| 1234 if (!method.isConstructor && !method.isNative) { | |
| 1235 world.error('unexpected empty body for ${method.name}', | |
| 1236 method.definition.span); | |
| 1237 } | |
| 1238 } else { | |
| 1239 visitStatementsInBlock(body); | |
| 1240 } | |
| 1238 } | 1241 } |
| 1239 | 1242 |
| 1240 /** | 1243 evalInitializerCall(ObjectValue newObject, CallExpression node, |
| 1241 * Calls another constructor (super, super.name, this, this.name). Returns | 1244 [bool fieldsSet = false]) { |
| 1242 * the value of the target expression. | |
| 1243 */ | |
| 1244 Value _writeInitializerCall(CallExpression node) { | |
| 1245 String contructorName = ''; | 1245 String contructorName = ''; |
| 1246 var targetExp = node.target; | 1246 var targetExp = node.target; |
| 1247 if (targetExp is DotExpression) { | 1247 if (targetExp is DotExpression) { |
| 1248 DotExpression dot = targetExp; | 1248 DotExpression dot = targetExp; |
| 1249 targetExp = dot.self; | 1249 targetExp = dot.self; |
| 1250 contructorName = dot.name.name; | 1250 contructorName = dot.name.name; |
| 1251 } | 1251 } |
| 1252 | 1252 |
| 1253 Type targetType = null; | |
| 1253 var target = null; | 1254 var target = null; |
| 1254 if (targetExp is SuperExpression) { | 1255 if (targetExp is SuperExpression) { |
| 1256 targetType = method.declaringType.parent; | |
| 1255 target = _makeSuperValue(targetExp); | 1257 target = _makeSuperValue(targetExp); |
| 1256 } else if (targetExp is ThisExpression) { | 1258 } else if (targetExp is ThisExpression) { |
| 1259 targetType = method.declaringType; | |
| 1257 target = _makeThisValue(targetExp); | 1260 target = _makeThisValue(targetExp); |
| 1261 if (fieldsSet) { | |
| 1262 world.error('no initialization allowed with redirecting constructor', | |
| 1263 node.span); | |
| 1264 } | |
| 1258 } else { | 1265 } else { |
| 1259 world.error('bad call in initializers', node.span); | 1266 world.error('bad call in initializers', node.span); |
| 1260 } | 1267 } |
| 1261 target.allowDynamic = false; | 1268 target.allowDynamic = false; |
| 1262 | 1269 |
| 1263 var m = target.type.getConstructor(contructorName); | 1270 |
| 1271 var m = targetType.getConstructor(contructorName); | |
| 1264 if (m == null) { | 1272 if (m == null) { |
| 1265 world.error('no matching constructor for ${target.type.name}', node.span); | 1273 world.error('no matching constructor for ${targetType.name}', node.span); |
| 1266 } | 1274 } |
| 1267 | 1275 |
| 1276 // TODO(jimhug): Replace with more generic recursion detection | |
| 1268 method.initDelegate = m; | 1277 method.initDelegate = m; |
| 1269 // check no cycles in in initialization: | 1278 // check no cycles in in initialization: |
| 1270 var other = m; | 1279 var other = m; |
| 1271 while (other != null) { | 1280 while (other != null) { |
| 1272 if (other == method) { | 1281 if (other == method) { |
| 1273 world.error('initialization cycle', node.span); | 1282 world.error('initialization cycle', node.span); |
| 1274 break; | 1283 break; |
| 1275 } | 1284 } |
| 1276 other = other.initDelegate; | 1285 other = other.initDelegate; |
| 1277 } | 1286 } |
| 1278 | 1287 |
| 1279 // move this all to happen when new first constuctor is walked. | 1288 var newArgs = _makeArgs(node.arguments); |
| 1289 // ???? wacky stuff ???? | |
| 1280 world.gen.genMethod(m); | 1290 world.gen.genMethod(m); |
| 1281 var value = m.invoke(this, node, target, _makeArgs(node.arguments)); | 1291 |
| 1282 if (target.type != world.objectType) { | 1292 m._evalConstConstructor(newObject, newArgs); |
| 1283 // No need to actually call Object's empty super constructor. | 1293 |
| 1284 writer.writeln('${value.code};'); | 1294 if (!newObject.isConst) { |
| 1295 var value = m.invoke(this, node, target, newArgs); | |
| 1296 if (target.type != world.objectType) { | |
| 1297 // No need to actually call Object's empty super constructor. | |
| 1298 writer.writeln('${value.code};'); | |
| 1299 } | |
| 1285 } | 1300 } |
| 1286 return target; | |
| 1287 } | 1301 } |
| 1288 | 1302 |
| 1289 _makeArgs(List<ArgumentNode> arguments) { | 1303 _makeArgs(List<ArgumentNode> arguments) { |
| 1290 var args = []; | 1304 var args = []; |
| 1291 bool seenLabel = false; | 1305 bool seenLabel = false; |
| 1292 for (var arg in arguments) { | 1306 for (var arg in arguments) { |
| 1293 if (arg.label != null) { | 1307 if (arg.label != null) { |
| 1294 seenLabel = true; | 1308 seenLabel = true; |
| 1295 } else if (seenLabel) { | 1309 } else if (seenLabel) { |
| 1296 // TODO(jimhug): Move this into parser? | 1310 // TODO(jimhug): Move this into parser? |
| (...skipping 881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2178 var kind = (TokenKind.INCR == node.op.kind ? | 2192 var kind = (TokenKind.INCR == node.op.kind ? |
| 2179 TokenKind.ADD : TokenKind.SUB); | 2193 TokenKind.ADD : TokenKind.SUB); |
| 2180 // TODO(jimhug): Shouldn't need a full-expression here. | 2194 // TODO(jimhug): Shouldn't need a full-expression here. |
| 2181 var operand = new LiteralExpression(Value.fromInt(1, node.span), | 2195 var operand = new LiteralExpression(Value.fromInt(1, node.span), |
| 2182 node.span); | 2196 node.span); |
| 2183 | 2197 |
| 2184 var assignValue = _visitAssign(kind, node.self, operand, node, null); | 2198 var assignValue = _visitAssign(kind, node.self, operand, node, null); |
| 2185 return new Value(assignValue.type, '(${assignValue.code})', | 2199 return new Value(assignValue.type, '(${assignValue.code})', |
| 2186 node.span); | 2200 node.span); |
| 2187 } | 2201 } |
| 2188 case TokenKind.NOT: | |
| 2189 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | |
| 2190 if (value.type.isBool && value.isConst) { | |
| 2191 var newVal = !value.actualValue; | |
| 2192 return Value.fromBool(newVal, node.span); | |
| 2193 } else { | |
| 2194 var newVal = value.convertTo(this, world.nonNullBool); | |
| 2195 return new Value(newVal.type, '!${newVal.code}', node.span); | |
| 2196 } | |
| 2197 | |
| 2198 case TokenKind.ADD: | |
| 2199 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | |
| 2200 return value.convertTo(this, world.numType); | |
| 2201 | |
| 2202 case TokenKind.SUB: | |
| 2203 case TokenKind.BIT_NOT: | |
| 2204 if (node.op.kind == TokenKind.BIT_NOT) { | |
| 2205 return value.invoke(this, ':bit_not', node, Arguments.EMPTY); | |
| 2206 } else if (node.op.kind == TokenKind.SUB) { | |
| 2207 return value.invoke(this, ':negate', node, Arguments.EMPTY); | |
| 2208 } else { | |
| 2209 world.internalError('unimplemented: unary ${node.op}', | |
| 2210 node.span); | |
| 2211 } | |
| 2212 default: | |
| 2213 world.internalError('unimplemented: ${node.op}', node.span); | |
| 2214 } | 2202 } |
| 2203 return value.unop(node.op.kind, this, node); | |
|
Jennifer Messerly
2012/01/09 20:45:35
so nice
| |
| 2215 } | 2204 } |
| 2216 | 2205 |
| 2217 visitDeclaredIdentifier(DeclaredIdentifier node) { | 2206 visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 2218 world.error('Expected expression', node.span); | 2207 world.error('Expected expression', node.span); |
| 2219 } | 2208 } |
| 2220 | 2209 |
| 2221 visitAwaitExpression(AwaitExpression node) { | 2210 visitAwaitExpression(AwaitExpression node) { |
| 2222 world.internalError( | 2211 world.internalError( |
| 2223 'Await expressions should have been eliminated before code generation', | 2212 'Await expressions should have been eliminated before code generation', |
| 2224 node.span); | 2213 node.span); |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2609 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); | 2598 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); |
| 2610 } | 2599 } |
| 2611 for (int i = bareCount; i < length; i++) { | 2600 for (int i = bareCount; i < length; i++) { |
| 2612 var name = getName(i); | 2601 var name = getName(i); |
| 2613 if (name == null) name = '\$$i'; | 2602 if (name == null) name = '\$$i'; |
| 2614 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); | 2603 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); |
| 2615 } | 2604 } |
| 2616 return new Arguments(nodes, result); | 2605 return new Arguments(nodes, result); |
| 2617 } | 2606 } |
| 2618 } | 2607 } |
| OLD | NEW |