| 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 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 var filename = basename(file.filename); | 177 var filename = basename(file.filename); |
| 178 writer.comment('// ********** Natives $filename **************'); | 178 writer.comment('// ********** Natives $filename **************'); |
| 179 writer.writeln(file.text); | 179 writer.writeln(file.text); |
| 180 } | 180 } |
| 181 lib.topType.markUsed(); // TODO(jimhug): EGREGIOUS HACK | 181 lib.topType.markUsed(); // TODO(jimhug): EGREGIOUS HACK |
| 182 | 182 |
| 183 for (var type in _orderValues(lib.types)) { | 183 for (var type in _orderValues(lib.types)) { |
| 184 // TODO(jmesserly): we can't accurately track if DOM types are | 184 // TODO(jmesserly): we can't accurately track if DOM types are |
| 185 // created or not, so we need to prepare to handle them. | 185 // created or not, so we need to prepare to handle them. |
| 186 // This should be fixed by tightening up the return types in DOM. | 186 // This should be fixed by tightening up the return types in DOM. |
| 187 if ((type.isUsed || type.library == world.dom | 187 if ((type.isUsed || type.library.isDom |
| 188 || type.isHiddenNativeType) && type.isClass) { | 188 || type.isHiddenNativeType) && type.isClass) { |
| 189 writeType(type); | 189 writeType(type); |
| 190 | 190 |
| 191 if (type.isGeneric) { | 191 if (type.isGeneric) { |
| 192 for (var ct in _orderValues(type._concreteTypes)) { | 192 for (var ct in _orderValues(type._concreteTypes)) { |
| 193 writeType(ct); | 193 writeType(ct); |
| 194 } | 194 } |
| 195 } | 195 } |
| 196 } else if (type.isFunction && type.varStubs.length > 0) { | 196 } else if (type.isFunction && type.varStubs.length > 0) { |
| 197 // Emit stubs on "Function" or hidden types if needed | 197 // Emit stubs on "Function" or hidden types if needed |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 } | 233 } |
| 234 | 234 |
| 235 if (checkType.isChecked) { | 235 if (checkType.isChecked) { |
| 236 String body = 'return this'; | 236 String body = 'return this'; |
| 237 String checkName = 'assert\$${checkType.jsname}'; | 237 String checkName = 'assert\$${checkType.jsname}'; |
| 238 if (!isSubtype) { | 238 if (!isSubtype) { |
| 239 // Get the code to throw a TypeError. | 239 // Get the code to throw a TypeError. |
| 240 // TODO(jmesserly): it'd be nice not to duplicate this code, and instead | 240 // TODO(jmesserly): it'd be nice not to duplicate this code, and instead |
| 241 // be able to refer to the JS function. | 241 // be able to refer to the JS function. |
| 242 body = world.objectType.varStubs[checkName].body; | 242 body = world.objectType.varStubs[checkName].body; |
| 243 } else if (onType.name == 'StringImplementation' || | 243 } else if (onType == world.stringImplType |
| 244 onType.name == 'NumImplementation') { | 244 || onType == world.numImplType) { |
| 245 body = 'return ${onType.nativeType.name}(this)'; | 245 body = 'return ${onType.nativeType.name}(this)'; |
| 246 } | 246 } |
| 247 writer.writeln(_prototypeOf(onType, checkName) + ' = function(){$body};'); | 247 writer.writeln(_prototypeOf(onType, checkName) + ' = function(){$body};'); |
| 248 } | 248 } |
| 249 } | 249 } |
| 250 | 250 |
| 251 writeType(Type type) { | 251 writeType(Type type) { |
| 252 if (type.isWritten) return; | 252 if (type.isWritten) return; |
| 253 | 253 |
| 254 type.isWritten = true; | 254 type.isWritten = true; |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 | 549 |
| 550 _usedDynamicDispatchOnType(Type type) { | 550 _usedDynamicDispatchOnType(Type type) { |
| 551 if (typesWithDynamicDispatch == null) typesWithDynamicDispatch = new Set(); | 551 if (typesWithDynamicDispatch == null) typesWithDynamicDispatch = new Set(); |
| 552 typesWithDynamicDispatch.add(type); | 552 typesWithDynamicDispatch.add(type); |
| 553 } | 553 } |
| 554 | 554 |
| 555 writeDynamicDispatchMetadata() { | 555 writeDynamicDispatchMetadata() { |
| 556 if (typesWithDynamicDispatch == null) return; | 556 if (typesWithDynamicDispatch == null) return; |
| 557 writer.comment('// ${typesWithDynamicDispatch.length} dynamic types.'); | 557 writer.comment('// ${typesWithDynamicDispatch.length} dynamic types.'); |
| 558 | 558 |
| 559 typeTag(type) => type.definition.nativeType.name; | |
| 560 | |
| 561 // Build a pre-order traversal over all the types and their subtypes. | 559 // Build a pre-order traversal over all the types and their subtypes. |
| 562 var seen = new Set(); | 560 var seen = new Set(); |
| 563 var types = []; | 561 var types = []; |
| 564 visit(type) { | 562 visit(type) { |
| 565 if (seen.contains(type)) return; | 563 if (seen.contains(type)) return; |
| 566 seen.add(type); | 564 seen.add(type); |
| 567 for (final subtype in _orderCollectionValues(type.directSubtypes)) { | 565 for (final subtype in _orderCollectionValues(type.directSubtypes)) { |
| 568 visit(subtype); | 566 visit(subtype); |
| 569 } | 567 } |
| 570 types.add(type); | 568 types.add(type); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 593 // Dart objects could be easily excluded, then we might be able to simplify | 591 // Dart objects could be easily excluded, then we might be able to simplify |
| 594 // the test, replacing dozens of HTMLxxxElement types with the regexp | 592 // the test, replacing dozens of HTMLxxxElement types with the regexp |
| 595 // /HTML.*Element/. | 593 // /HTML.*Element/. |
| 596 | 594 |
| 597 var varNames = []; // temporary variables for common substrings. | 595 var varNames = []; // temporary variables for common substrings. |
| 598 var varDefns = {}; // var -> expression | 596 var varDefns = {}; // var -> expression |
| 599 var tagDefns = {}; // tag -> expression (a string or a variable) | 597 var tagDefns = {}; // tag -> expression (a string or a variable) |
| 600 | 598 |
| 601 makeExpression(type) { | 599 makeExpression(type) { |
| 602 var expressions = []; // expression fragments for this set of type keys. | 600 var expressions = []; // expression fragments for this set of type keys. |
| 603 var subtags = [typeTag(type)]; // TODO: Remove if type is abstract. | 601 var subtags = [type.nativeName]; // TODO: Remove if type is abstract. |
| 604 walk(type) { | 602 walk(type) { |
| 605 for (final subtype in _orderCollectionValues(type.directSubtypes)) { | 603 for (final subtype in _orderCollectionValues(type.directSubtypes)) { |
| 606 var tag = typeTag(subtype); | 604 var tag = subtype.nativeName; |
| 607 var existing = tagDefns[tag]; | 605 var existing = tagDefns[tag]; |
| 608 if (existing == null) { | 606 if (existing == null) { |
| 609 subtags.add(tag); | 607 subtags.add(tag); |
| 610 walk(subtype); | 608 walk(subtype); |
| 611 } else { | 609 } else { |
| 612 if (varDefns.containsKey(existing)) { | 610 if (varDefns.containsKey(existing)) { |
| 613 expressions.add(existing); | 611 expressions.add(existing); |
| 614 } else { | 612 } else { |
| 615 var varName = 'v${varNames.length}/*${tag}*/'; | 613 var varName = 'v${varNames.length}/*${tag}*/'; |
| 616 varNames.add(varName); | 614 varNames.add(varName); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 627 var expression; | 625 var expression; |
| 628 if (expressions.length == 1) { | 626 if (expressions.length == 1) { |
| 629 expression = expressions[0]; | 627 expression = expressions[0]; |
| 630 } else { | 628 } else { |
| 631 expression = "[${Strings.join(expressions, ',')}].join('|')"; | 629 expression = "[${Strings.join(expressions, ',')}].join('|')"; |
| 632 } | 630 } |
| 633 return expression; | 631 return expression; |
| 634 } | 632 } |
| 635 | 633 |
| 636 for (final type in dispatchTypes) { | 634 for (final type in dispatchTypes) { |
| 637 tagDefns[typeTag(type)] = makeExpression(type); | 635 tagDefns[type.nativeName] = makeExpression(type); |
| 638 } | 636 } |
| 639 | 637 |
| 640 // Write out a thunk that builds the metadata. | 638 // Write out a thunk that builds the metadata. |
| 641 | 639 |
| 642 if (!tagDefns.isEmpty()) { | 640 if (!tagDefns.isEmpty()) { |
| 643 writer.enterBlock('(function(){'); | 641 writer.enterBlock('(function(){'); |
| 644 | 642 |
| 645 for (final varName in varNames) { | 643 for (final varName in varNames) { |
| 646 writer.writeln('var ${varName} = ${varDefns[varName]};'); | 644 writer.writeln('var ${varName} = ${varDefns[varName]};'); |
| 647 } | 645 } |
| 648 | 646 |
| 649 writer.enterBlock('var table = ['); | 647 writer.enterBlock('var table = ['); |
| 650 writer.comment( | 648 writer.comment( |
| 651 '// [dynamic-dispatch-tag, ' | 649 '// [dynamic-dispatch-tag, ' |
| 652 + 'tags of classes implementing dynamic-dispatch-tag]'); | 650 + 'tags of classes implementing dynamic-dispatch-tag]'); |
| 653 for (final type in dispatchTypes) { | 651 for (final type in dispatchTypes) { |
| 654 writer.writeln("['${typeTag(type)}', ${tagDefns[typeTag(type)]}],"); | 652 writer.writeln("['${type.nativeName}', ${tagDefns[type.nativeName]}],"); |
| 655 } | 653 } |
| 656 writer.exitBlock('];'); | 654 writer.exitBlock('];'); |
| 657 writer.writeln('\$dynamicSetMetadata(table);'); | 655 writer.writeln('\$dynamicSetMetadata(table);'); |
| 658 | 656 |
| 659 writer.exitBlock('})();'); | 657 writer.exitBlock('})();'); |
| 660 } | 658 } |
| 661 } | 659 } |
| 662 | 660 |
| 663 /** Order a list of values in a Map by SourceSpan, then by name. */ | 661 /** Order a list of values in a Map by SourceSpan, then by name. */ |
| 664 List _orderValues(Map map) { | 662 List _orderValues(Map map) { |
| (...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 meth.resolve(); | 1342 meth.resolve(); |
| 1345 return meth; | 1343 return meth; |
| 1346 } | 1344 } |
| 1347 | 1345 |
| 1348 visitBool(Expression node) { | 1346 visitBool(Expression node) { |
| 1349 // Boolean conversions in if/while/do/for/conditions require non-null bool. | 1347 // Boolean conversions in if/while/do/for/conditions require non-null bool. |
| 1350 | 1348 |
| 1351 // TODO(jmesserly): why do we have this rule? It seems inconsistent with | 1349 // TODO(jmesserly): why do we have this rule? It seems inconsistent with |
| 1352 // the rest of the type system, and just causes bogus asserts unless all | 1350 // the rest of the type system, and just causes bogus asserts unless all |
| 1353 // bools are initialized to false. | 1351 // bools are initialized to false. |
| 1354 return visitValue(node).convertTo(this, world.nonNullBool, node); | 1352 return visitValue(node).convertTo(this, world.nonNullBool); |
| 1355 } | 1353 } |
| 1356 | 1354 |
| 1357 visitValue(Expression node) { | 1355 visitValue(Expression node) { |
| 1358 if (node == null) return null; | 1356 if (node == null) return null; |
| 1359 | 1357 |
| 1360 var value = node.visit(this); | 1358 var value = node.visit(this); |
| 1361 value.checkFirstClass(node.span); | 1359 value.checkFirstClass(node.span); |
| 1362 return value; | 1360 return value; |
| 1363 } | 1361 } |
| 1364 | 1362 |
| 1365 /** | 1363 /** |
| 1366 * Visit [node] and ensure statically or with an runtime check that it has the | 1364 * Visit [node] and ensure statically or with an runtime check that it has the |
| 1367 * expected type (if specified). | 1365 * expected type (if specified). |
| 1368 */ | 1366 */ |
| 1369 visitTypedValue(Expression node, Type expectedType) { | 1367 visitTypedValue(Expression node, Type expectedType) { |
| 1370 final val = visitValue(node); | 1368 final val = visitValue(node); |
| 1371 return expectedType == null ? val : val.convertTo(this, expectedType, node); | 1369 return expectedType == null ? val : val.convertTo(this, expectedType); |
| 1372 } | 1370 } |
| 1373 | 1371 |
| 1374 visitVoid(Expression node) { | 1372 visitVoid(Expression node) { |
| 1375 // TODO(jmesserly): should we generalize this? | 1373 // TODO(jmesserly): should we generalize this? |
| 1376 if (node is PostfixExpression) { | 1374 if (node is PostfixExpression) { |
| 1377 var value = visitPostfixExpression(node, isVoid: true); | 1375 var value = visitPostfixExpression(node, isVoid: true); |
| 1378 value.checkFirstClass(node.span); | 1376 value.checkFirstClass(node.span); |
| 1379 return value; | 1377 return value; |
| 1380 } else if (node is BinaryExpression) { | 1378 } else if (node is BinaryExpression) { |
| 1381 var value = visitBinaryExpression(node, isVoid: true); | 1379 var value = visitBinaryExpression(node, isVoid: true); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1422 | 1420 |
| 1423 if (value == null) { | 1421 if (value == null) { |
| 1424 if (_scope.reentrant) { | 1422 if (_scope.reentrant) { |
| 1425 // To preserve block scoping, we need to ensure the variable is | 1423 // To preserve block scoping, we need to ensure the variable is |
| 1426 // reinitialized each time the block is entered. | 1424 // reinitialized each time the block is entered. |
| 1427 writer.write('${val.code} = null'); | 1425 writer.write('${val.code} = null'); |
| 1428 } else { | 1426 } else { |
| 1429 writer.write('${val.code}'); | 1427 writer.write('${val.code}'); |
| 1430 } | 1428 } |
| 1431 } else { | 1429 } else { |
| 1432 value = value.convertTo(this, type, node.values[i]); | 1430 value = value.convertTo(this, type); |
| 1433 writer.write('${val.code} = ${value.code}'); | 1431 writer.write('${val.code} = ${value.code}'); |
| 1434 } | 1432 } |
| 1435 } | 1433 } |
| 1436 writer.writeln(';'); | 1434 writer.writeln(';'); |
| 1437 return false; | 1435 return false; |
| 1438 | 1436 |
| 1439 } | 1437 } |
| 1440 | 1438 |
| 1441 bool visitFunctionDefinition(FunctionDefinition node) { | 1439 bool visitFunctionDefinition(FunctionDefinition node) { |
| 1442 var meth = _makeLambdaMethod(node.name.name, node); | 1440 var meth = _makeLambdaMethod(node.name.name, node); |
| (...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2126 | 2124 |
| 2127 // Otherwise treat it as a field. | 2125 // Otherwise treat it as a field. |
| 2128 // This makes for nicer code in the $op= case | 2126 // This makes for nicer code in the $op= case |
| 2129 } | 2127 } |
| 2130 | 2128 |
| 2131 if (x.isFinal) { | 2129 if (x.isFinal) { |
| 2132 world.error('final variable "${x.code}" is not assignable', | 2130 world.error('final variable "${x.code}" is not assignable', |
| 2133 position.span); | 2131 position.span); |
| 2134 } | 2132 } |
| 2135 | 2133 |
| 2136 y = y.convertTo(this, x.type, yn); | 2134 y = y.convertTo(this, x.type); |
| 2137 | 2135 |
| 2138 if (kind == 0) { | 2136 if (kind == 0) { |
| 2139 x = captureOriginal(x); | 2137 x = captureOriginal(x); |
| 2140 return new Value(y.type, '${x.code} = ${y.code}', position.span); | 2138 return new Value(y.type, '${x.code} = ${y.code}', position.span); |
| 2141 } else if (x.type.isNum && y.type.isNum && (kind != TokenKind.TRUNCDIV)) { | 2139 } else if (x.type.isNum && y.type.isNum && (kind != TokenKind.TRUNCDIV)) { |
| 2142 // Process everything but ~/ , which has no equivalent JS operator | 2140 // Process everything but ~/ , which has no equivalent JS operator |
| 2143 x = captureOriginal(x); | 2141 x = captureOriginal(x); |
| 2144 // Very localized optimization for numbers! | 2142 // Very localized optimization for numbers! |
| 2145 final op = TokenKind.kindToString(kind); | 2143 final op = TokenKind.kindToString(kind); |
| 2146 return new Value(y.type, '${x.code} $op= ${y.code}', position.span); | 2144 return new Value(y.type, '${x.code} $op= ${y.code}', position.span); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2230 var assignValue = _visitAssign(kind, node.self, operand, node, null); | 2228 var assignValue = _visitAssign(kind, node.self, operand, node, null); |
| 2231 return new Value(assignValue.type, '(${assignValue.code})', | 2229 return new Value(assignValue.type, '(${assignValue.code})', |
| 2232 node.span); | 2230 node.span); |
| 2233 } | 2231 } |
| 2234 case TokenKind.NOT: | 2232 case TokenKind.NOT: |
| 2235 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 2233 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 2236 if (value.type.isBool && value.isConst) { | 2234 if (value.type.isBool && value.isConst) { |
| 2237 var newVal = !value.actualValue; | 2235 var newVal = !value.actualValue; |
| 2238 return new EvaluatedValue(value.type, newVal, '${newVal}', node.span); | 2236 return new EvaluatedValue(value.type, newVal, '${newVal}', node.span); |
| 2239 } else { | 2237 } else { |
| 2240 var newVal = value.convertTo(this, world.nonNullBool, node); | 2238 var newVal = value.convertTo(this, world.nonNullBool); |
| 2241 return new Value(newVal.type, '!${newVal.code}', node.span); | 2239 return new Value(newVal.type, '!${newVal.code}', node.span); |
| 2242 } | 2240 } |
| 2243 | 2241 |
| 2244 case TokenKind.ADD: | 2242 case TokenKind.ADD: |
| 2245 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 2243 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 2246 return value.convertTo(this, world.numType, node); | 2244 return value.convertTo(this, world.numType); |
| 2247 | 2245 |
| 2248 case TokenKind.SUB: | 2246 case TokenKind.SUB: |
| 2249 case TokenKind.BIT_NOT: | 2247 case TokenKind.BIT_NOT: |
| 2250 if (node.op.kind == TokenKind.BIT_NOT) { | 2248 if (node.op.kind == TokenKind.BIT_NOT) { |
| 2251 return value.invoke(this, ':bit_not', node, Arguments.EMPTY); | 2249 return value.invoke(this, ':bit_not', node, Arguments.EMPTY); |
| 2252 } else if (node.op.kind == TokenKind.SUB) { | 2250 } else if (node.op.kind == TokenKind.SUB) { |
| 2253 return value.invoke(this, ':negate', node, Arguments.EMPTY); | 2251 return value.invoke(this, ':negate', node, Arguments.EMPTY); |
| 2254 } else { | 2252 } else { |
| 2255 world.internalError('unimplemented: unary ${node.op}', | 2253 world.internalError('unimplemented: unary ${node.op}', |
| 2256 node.span); | 2254 node.span); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2357 world.error('can\'t use const on a non-const constructor', node.span); | 2355 world.error('can\'t use const on a non-const constructor', node.span); |
| 2358 } | 2356 } |
| 2359 for (var arg in node.arguments) { | 2357 for (var arg in node.arguments) { |
| 2360 if (!visitValue(arg.value).isConst) { | 2358 if (!visitValue(arg.value).isConst) { |
| 2361 world.error('const constructor expects const arguments', arg.span); | 2359 world.error('const constructor expects const arguments', arg.span); |
| 2362 } | 2360 } |
| 2363 } | 2361 } |
| 2364 } | 2362 } |
| 2365 | 2363 |
| 2366 // Call the constructor on the type we want to construct. | 2364 // Call the constructor on the type we want to construct. |
| 2367 // NOTE: this is important for correct checking of factories. | 2365 // NOTE: this is important for correct type checking of factories. |
| 2368 // If the user calls "new Interface()" we want the result type to be the | 2366 // If the user calls "new Interface()" we want the result type to be the |
| 2369 // interface, not the class. | 2367 // interface, not the class. |
| 2370 var target = new Value.type(type, typeRef.span); | 2368 var target = new Value.type(type, typeRef.span); |
| 2371 return m.invoke(this, node, target, _makeArgs(node.arguments)); | 2369 return m.invoke(this, node, target, _makeArgs(node.arguments)); |
| 2372 } | 2370 } |
| 2373 | 2371 |
| 2374 visitListExpression(ListExpression node) { | 2372 visitListExpression(ListExpression node) { |
| 2375 // TODO(jimhug): Use node.type or other type inference here. | 2373 // TODO(jimhug): Use node.type or other type inference here. |
| 2376 var argsCode = []; | 2374 var argsCode = []; |
| 2377 var argValues = []; | 2375 var argValues = []; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2391 world.error('const list can only contain const values', item.span); | 2389 world.error('const list can only contain const values', item.span); |
| 2392 argsCode.add(arg.code); | 2390 argsCode.add(arg.code); |
| 2393 } else { | 2391 } else { |
| 2394 argsCode.add(arg.canonicalCode); | 2392 argsCode.add(arg.canonicalCode); |
| 2395 } | 2393 } |
| 2396 } else { | 2394 } else { |
| 2397 argsCode.add(arg.code); | 2395 argsCode.add(arg.code); |
| 2398 } | 2396 } |
| 2399 } | 2397 } |
| 2400 | 2398 |
| 2401 world.coreimpl.types['ListFactory'].markUsed(); | 2399 world.listFactoryType.markUsed(); |
| 2402 | 2400 |
| 2403 final code = '[${Strings.join(argsCode, ", ")}]'; | 2401 final code = '[${Strings.join(argsCode, ", ")}]'; |
| 2404 var value = new Value(world.listType, code, node.span); | 2402 var value = new Value(world.listType, code, node.span); |
| 2405 if (node.isConst) { | 2403 if (node.isConst) { |
| 2406 final immutableList = world.coreimpl.types['ImmutableList']; | 2404 final immutableList = world.immutableListType; |
| 2407 final immutableListCtor = immutableList.getConstructor('from'); | 2405 final immutableListCtor = immutableList.getConstructor('from'); |
| 2408 final result = immutableListCtor.invoke(this, node, | 2406 final result = immutableListCtor.invoke(this, node, |
| 2409 new Value.type(value.type, node.span), new Arguments(null, [value])); | 2407 new Value.type(value.type, node.span), new Arguments(null, [value])); |
| 2410 value = world.gen.globalForConst( | 2408 value = world.gen.globalForConst( |
| 2411 new ConstListValue(immutableList, argValues, 'const $code', | 2409 new ConstListValue(immutableList, argValues, 'const $code', |
| 2412 result.code, node.span), | 2410 result.code, node.span), |
| 2413 argValues); | 2411 argValues); |
| 2414 } | 2412 } |
| 2415 return value; | 2413 return value; |
| 2416 } | 2414 } |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2568 } | 2566 } |
| 2569 // No need to concat empty strings except the first. | 2567 // No need to concat empty strings except the first. |
| 2570 if (items.length == 0 || (code != "''" && code != '""')) { | 2568 if (items.length == 0 || (code != "''" && code != '""')) { |
| 2571 items.add(code); | 2569 items.add(code); |
| 2572 } | 2570 } |
| 2573 } | 2571 } |
| 2574 return new Value(type, '(${Strings.join(items, " + ")})', node.span); | 2572 return new Value(type, '(${Strings.join(items, " + ")})', node.span); |
| 2575 } | 2573 } |
| 2576 | 2574 |
| 2577 if (node.value is num) { | 2575 if (node.value is num) { |
| 2578 world.coreimpl.types['NumImplementation'].markUsed(); | 2576 world.numImplType.markUsed(); |
| 2579 } | 2577 } |
| 2580 | 2578 |
| 2581 var text = node.text; | 2579 var text = node.text; |
| 2582 // TODO(jimhug): Confirm that only strings need possible translation | 2580 // TODO(jimhug): Confirm that only strings need possible translation |
| 2583 if (type.isString) { | 2581 if (type.isString) { |
| 2584 world.coreimpl.types['StringImplementation'].markUsed(); | 2582 world.stringImplType.markUsed(); |
| 2585 | 2583 |
| 2586 if (text.startsWith('@')) { | 2584 if (text.startsWith('@')) { |
| 2587 text = _escapeString(parseStringLiteral(text)); | 2585 text = _escapeString(parseStringLiteral(text)); |
| 2588 text = '"$text"'; | 2586 text = '"$text"'; |
| 2589 } else if (isMultilineString(text)) { | 2587 } else if (isMultilineString(text)) { |
| 2590 // convert multi-line strings into single-line | 2588 // convert multi-line strings into single-line |
| 2591 text = parseStringLiteral(text); | 2589 text = parseStringLiteral(text); |
| 2592 // TODO(jimhug): What about \r? | 2590 // TODO(jimhug): What about \r? |
| 2593 text = text.replaceAll('\n', '\\n'); | 2591 text = text.replaceAll('\n', '\\n'); |
| 2594 text = toDoubleQuote(text); | 2592 text = toDoubleQuote(text); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2718 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); | 2716 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); |
| 2719 } | 2717 } |
| 2720 for (int i = bareCount; i < length; i++) { | 2718 for (int i = bareCount; i < length; i++) { |
| 2721 var name = getName(i); | 2719 var name = getName(i); |
| 2722 if (name == null) name = '\$$i'; | 2720 if (name == null) name = '\$$i'; |
| 2723 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); | 2721 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); |
| 2724 } | 2722 } |
| 2725 return new Arguments(nodes, result); | 2723 return new Arguments(nodes, result); |
| 2726 } | 2724 } |
| 2727 } | 2725 } |
| OLD | NEW |