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 |