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

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 963343002: implement private members, fixes #74 (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: rebase Created 5 years, 9 months 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library ddc.src.codegen.js_codegen; 5 library ddc.src.codegen.js_codegen;
6 6
7 import 'dart:io' show Directory, File; 7 import 'dart:io' show Directory, File;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
(...skipping 28 matching lines...) Expand all
39 SimpleIdentifier _cascadeTarget; 39 SimpleIdentifier _cascadeTarget;
40 /// The variable for the current catch clause 40 /// The variable for the current catch clause
41 String _catchParameter; 41 String _catchParameter;
42 42
43 ClassDeclaration currentClass; 43 ClassDeclaration currentClass;
44 ConstantEvaluator _constEvaluator; 44 ConstantEvaluator _constEvaluator;
45 45
46 final _exports = <String>[]; 46 final _exports = <String>[];
47 final _lazyFields = <VariableDeclaration>[]; 47 final _lazyFields = <VariableDeclaration>[];
48 final _properties = <FunctionDeclaration>[]; 48 final _properties = <FunctionDeclaration>[];
49 final _privateNames = new Set<String>();
49 50
50 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules) 51 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules)
51 : libraryInfo = libraryInfo, 52 : libraryInfo = libraryInfo,
52 rules = rules; 53 rules = rules;
53 54
54 Element get currentLibrary => libraryInfo.library; 55 Element get currentLibrary => libraryInfo.library;
55 56
56 JS.Block generateLibrary( 57 JS.Block generateLibrary(
57 Iterable<CompilationUnit> units, CheckerReporter reporter) { 58 Iterable<CompilationUnit> units, CheckerReporter reporter) {
58 var body = <JS.Statement>[]; 59 var body = <JS.Statement>[];
(...skipping 11 matching lines...) Expand all
70 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); 71 if (_exports.isNotEmpty) body.add(js.comment('Exports:'));
71 72
72 // TODO(jmesserly): make these immutable in JS? 73 // TODO(jmesserly): make these immutable in JS?
73 for (var name in _exports) { 74 for (var name in _exports) {
74 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); 75 body.add(js.statement('$_EXPORTS.# = #;', [name, name]));
75 } 76 }
76 77
77 var name = jsLibraryName(libraryInfo.library); 78 var name = jsLibraryName(libraryInfo.library);
78 return new JS.Block([ 79 return new JS.Block([
79 js.statement('var #;', name), 80 js.statement('var #;', name),
80 js.statement(''' 81 js.statement("(function($_EXPORTS){'use strict'; #; #;})(# || (# = {}));",
81 (function ($_EXPORTS) { 82 [_privateNames.map(_initPrivateSymbol), body, name, name])
82 'use strict';
83 #;
84 })(# || (# = {}));
85 ''', [body, name, name])
86 ]); 83 ]);
87 } 84 }
88 85
86 JS.Statement _initPrivateSymbol(String name) =>
87 js.statement('let # = Symbol(#);', [name, js.string(name, "'")]);
88
89 @override 89 @override
90 JS.Statement visitCompilationUnit(CompilationUnit node) { 90 JS.Statement visitCompilationUnit(CompilationUnit node) {
91 // TODO(jmesserly): scriptTag, directives. 91 // TODO(jmesserly): scriptTag, directives.
92 var body = <JS.Statement>[]; 92 var body = <JS.Statement>[];
93 for (var child in node.declarations) { 93 for (var child in node.declarations) {
94 // Attempt to group adjacent fields/properties. 94 // Attempt to group adjacent fields/properties.
95 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); 95 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body);
96 if (child is! FunctionDeclaration) _flushLibraryProperties(body); 96 if (child is! FunctionDeclaration) _flushLibraryProperties(body);
97 97
98 var code = _visit(child); 98 var code = _visit(child);
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 return new JS.Block(body)..sourceInformation = node; 395 return new JS.Block(body)..sourceInformation = node;
396 } 396 }
397 397
398 @override 398 @override
399 JS.Statement visitRedirectingConstructorInvocation( 399 JS.Statement visitRedirectingConstructorInvocation(
400 RedirectingConstructorInvocation node) { 400 RedirectingConstructorInvocation node) {
401 ClassDeclaration classDecl = node.parent.parent; 401 ClassDeclaration classDecl = node.parent.parent;
402 var className = classDecl.name.name; 402 var className = classDecl.name.name;
403 403
404 var name = _constructorName(className, node.constructorName); 404 var name = _constructorName(className, node.constructorName);
405 return js.statement('this.#(#);', [name, _visit(node.argumentList)]); 405 return js.statement(
406 'this.#(#);', [_jsMemberName(name), _visit(node.argumentList)]);
406 } 407 }
407 408
408 JS.Statement _superConstructorCall(ClassDeclaration clazz, 409 JS.Statement _superConstructorCall(ClassDeclaration clazz,
409 [SuperConstructorInvocation node]) { 410 [SuperConstructorInvocation node]) {
410 var superCtorName = node != null ? node.constructorName : null; 411 var superCtorName = node != null ? node.constructorName : null;
411 412
412 var element = clazz.element; 413 var element = clazz.element;
413 if (superCtorName == null && 414 if (superCtorName == null &&
414 (element.type.isObject || element.supertype.isObject)) { 415 (element.type.isObject || element.supertype.isObject)) {
415 return null; 416 return null;
(...skipping 29 matching lines...) Expand all
445 } 446 }
446 } 447 }
447 } 448 }
448 449
449 // Initialize fields from `this.fieldName` parameters. 450 // Initialize fields from `this.fieldName` parameters.
450 if (parameters != null) { 451 if (parameters != null) {
451 for (var p in parameters.parameters) { 452 for (var p in parameters.parameters) {
452 if (p is DefaultFormalParameter) p = p.parameter; 453 if (p is DefaultFormalParameter) p = p.parameter;
453 if (p is FieldFormalParameter) { 454 if (p is FieldFormalParameter) {
454 var name = p.identifier.name; 455 var name = p.identifier.name;
455 body.add(js.statement('this.# = #;', [name, name])); 456 body.add(
457 js.statement('this.# = #;', [_jsMemberName(name), _visit(p)]));
456 unsetFields.remove(name); 458 unsetFields.remove(name);
457 } 459 }
458 } 460 }
459 } 461 }
460 462
461 // Run constructor field initializers such as `: foo = bar.baz` 463 // Run constructor field initializers such as `: foo = bar.baz`
462 if (initializers != null) { 464 if (initializers != null) {
463 for (var init in initializers) { 465 for (var init in initializers) {
464 if (init is ConstructorFieldInitializer) { 466 if (init is ConstructorFieldInitializer) {
465 body.add(js.statement( 467 body.add(js.statement(
466 '# = #;', [_visit(init.fieldName), _visit(init.expression)])); 468 '# = #;', [_visit(init.fieldName), _visit(init.expression)]));
467 unsetFields.remove(init.fieldName.name); 469 unsetFields.remove(init.fieldName.name);
468 } 470 }
469 } 471 }
470 } 472 }
471 473
472 // Initialize all remaining fields 474 // Initialize all remaining fields
473 unsetFields.forEach((name, field) { 475 unsetFields.forEach((name, field) {
474 JS.Expression value; 476 JS.Expression value;
475 if (field.initializer != null) { 477 if (field.initializer != null) {
476 value = _visit(field.initializer); 478 value = _visit(field.initializer);
477 } else { 479 } else {
478 var type = rules.elementType(field.element); 480 var type = rules.elementType(field.element);
479 if (rules.maybeNonNullableType(type)) { 481 if (rules.maybeNonNullableType(type)) {
480 value = js.call('dart.as(null, #)', _emitTypeName(type)); 482 value = js.call('dart.as(null, #)', _emitTypeName(type));
481 } else { 483 } else {
482 value = new JS.LiteralNull(); 484 value = new JS.LiteralNull();
483 } 485 }
484 } 486 }
485 body.add(js.statement('this.# = #;', [name, value])); 487 body.add(js.statement('this.# = #;', [_jsMemberName(name), value]));
486 }); 488 });
487 489
488 return _statement(body); 490 return _statement(body);
489 } 491 }
490 492
491 FormalParameterList _parametersOf(node) { 493 FormalParameterList _parametersOf(node) {
492 // Note: ConstructorDeclaration is intentionally skipped here so we can 494 // Note: ConstructorDeclaration is intentionally skipped here so we can
493 // emit the argument initializers in a different place. 495 // emit the argument initializers in a different place.
494 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we 496 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we
495 // could handle argument initializers more consistently in a separate 497 // could handle argument initializers more consistently in a separate
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 545
544 @override 546 @override
545 JS.Method visitMethodDeclaration(MethodDeclaration node) { 547 JS.Method visitMethodDeclaration(MethodDeclaration node) {
546 if (node.isAbstract || _externalOrNative(node)) { 548 if (node.isAbstract || _externalOrNative(node)) {
547 return null; 549 return null;
548 } 550 }
549 551
550 var params = _visit(node.parameters); 552 var params = _visit(node.parameters);
551 if (params == null) params = []; 553 if (params == null) params = [];
552 554
553 return new JS.Method(new JS.PropertyName(_jsMethodName(node.name.name)), 555 return new JS.Method(
554 new JS.Fun(params, _visit(node.body)), 556 _jsMemberName(node.name.name), new JS.Fun(params, _visit(node.body)),
555 isGetter: node.isGetter, 557 isGetter: node.isGetter,
556 isSetter: node.isSetter, 558 isSetter: node.isSetter,
557 isStatic: node.isStatic); 559 isStatic: node.isStatic);
558 } 560 }
559 561
560 @override 562 @override
561 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { 563 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) {
562 assert(node.parent is CompilationUnit); 564 assert(node.parent is CompilationUnit);
563 565
564 if (_externalOrNative(node)) return null; 566 if (_externalOrNative(node)) return null;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 var e = node.staticElement; 638 var e = node.staticElement;
637 if (e == null) { 639 if (e == null) {
638 return js.commentExpression( 640 return js.commentExpression(
639 'Unimplemented unknown name', new JS.VariableUse(node.name)); 641 'Unimplemented unknown name', new JS.VariableUse(node.name));
640 } 642 }
641 var name = node.name; 643 var name = node.name;
642 if (e.enclosingElement is CompilationUnitElement && 644 if (e.enclosingElement is CompilationUnitElement &&
643 (e.library != libraryInfo.library || _needsModuleGetter(e))) { 645 (e.library != libraryInfo.library || _needsModuleGetter(e))) {
644 return js.call('#.#', [_libraryName(e.library), name]); 646 return js.call('#.#', [_libraryName(e.library), name]);
645 } else if (currentClass != null && _needsImplicitThis(e)) { 647 } else if (currentClass != null && _needsImplicitThis(e)) {
646 return js.call('this.#', name); 648 return js.call('this.#', _jsMemberName(name));
649 } else if (e is ParameterElement && e.isInitializingFormal) {
650 name = _fieldParameterName(name);
647 } 651 }
648 return new JS.VariableUse(name); 652 return new JS.VariableUse(name);
649 } 653 }
650 654
651 JS.Expression _emitTypeName(DartType type) { 655 JS.Expression _emitTypeName(DartType type) {
652 var name = type.name; 656 var name = type.name;
653 var lib = type.element.library; 657 var lib = type.element.library;
654 if (name == '') { 658 if (name == '') {
655 // TODO(jmesserly): remove when we're using coercion reifier. 659 // TODO(jmesserly): remove when we're using coercion reifier.
656 return _unimplementedCall('Unimplemented type $type'); 660 return _unimplementedCall('Unimplemented type $type');
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 } 847 }
844 848
845 @override 849 @override
846 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) { 850 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) {
847 var result = <JS.Parameter>[]; 851 var result = <JS.Parameter>[];
848 for (FormalParameter param in node.parameters) { 852 for (FormalParameter param in node.parameters) {
849 if (param.kind == ParameterKind.NAMED) { 853 if (param.kind == ParameterKind.NAMED) {
850 result.add(new JS.Parameter(_jsNamedParameterName)); 854 result.add(new JS.Parameter(_jsNamedParameterName));
851 break; 855 break;
852 } 856 }
853 result.add(new JS.Parameter(param.identifier.name)); 857 result.add(_visit(param));
854 } 858 }
855 return result; 859 return result;
856 } 860 }
857 861
858 @override 862 @override
859 JS.Statement visitExpressionStatement(ExpressionStatement node) => 863 JS.Statement visitExpressionStatement(ExpressionStatement node) =>
860 _expressionStatement(_visit(node.expression)); 864 _expressionStatement(_visit(node.expression));
861 865
862 // Some expressions may choose to generate themselves as JS statements 866 // Some expressions may choose to generate themselves as JS statements
863 // if their parent is in a statement context. 867 // if their parent is in a statement context.
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
1206 } 1210 }
1207 return false; 1211 return false;
1208 } 1212 }
1209 1213
1210 @override 1214 @override
1211 visitParenthesizedExpression(ParenthesizedExpression node) => 1215 visitParenthesizedExpression(ParenthesizedExpression node) =>
1212 // The printer handles precedence so we don't need to. 1216 // The printer handles precedence so we don't need to.
1213 _visit(node.expression); 1217 _visit(node.expression);
1214 1218
1215 @override 1219 @override
1216 visitSimpleFormalParameter(SimpleFormalParameter node) => 1220 visitFormalParameter(FormalParameter node) =>
1217 _visit(node.identifier); 1221 new JS.Parameter(node.identifier.name);
1218 1222
1219 @override 1223 @override
1220 visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) => 1224 visitFieldFormalParameter(FieldFormalParameter node) =>
1221 _visit(node.identifier); 1225 new JS.Parameter(_fieldParameterName(node.identifier.name));
1226
1227 /// Rename private names so they don't shadow the private field symbol.
1228 // TODO(jmesserly): replace this ad-hoc rename with a general strategy.
1229 _fieldParameterName(name) => name.startsWith('_') ? '\$$name' : name;
1222 1230
1223 @override 1231 @override
1224 JS.This visitThisExpression(ThisExpression node) => new JS.This(); 1232 JS.This visitThisExpression(ThisExpression node) => new JS.This();
1225 1233
1226 @override 1234 @override
1227 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); 1235 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super();
1228 1236
1229 @override 1237 @override
1230 visitPrefixedIdentifier(PrefixedIdentifier node) { 1238 visitPrefixedIdentifier(PrefixedIdentifier node) {
1231 if (node.prefix.staticElement is PrefixElement) { 1239 if (node.prefix.staticElement is PrefixElement) {
1232 return _visit(node.identifier); 1240 return _visit(node.identifier);
1233 } else { 1241 } else {
1234 return _visitGet(node.prefix, node.identifier); 1242 return _visitGet(node.prefix, node.identifier);
1235 } 1243 }
1236 } 1244 }
1237 1245
1238 @override 1246 @override
1239 visitPropertyAccess(PropertyAccess node) => 1247 visitPropertyAccess(PropertyAccess node) =>
1240 _visitGet(_getTarget(node), node.propertyName); 1248 _visitGet(_getTarget(node), node.propertyName);
1241 1249
1242 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 1250 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
1243 _visitGet(Expression target, SimpleIdentifier name) { 1251 _visitGet(Expression target, SimpleIdentifier name) {
1244 if (rules.isDynamicTarget(target)) { 1252 if (rules.isDynamicTarget(target)) {
1245 return js.call( 1253 return js.call(
1246 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]); 1254 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]);
1247 } else { 1255 } else {
1248 return js.call('#.#', [_visit(target), name.name]); 1256 return js.call('#.#', [_visit(target), _jsMemberName(name.name)]);
1249 } 1257 }
1250 } 1258 }
1251 1259
1252 @override 1260 @override
1253 visitIndexExpression(IndexExpression node) { 1261 visitIndexExpression(IndexExpression node) {
1254 var target = _getTarget(node); 1262 var target = _getTarget(node);
1255 var code; 1263 var code;
1256 if (rules.isDynamicTarget(target)) { 1264 if (rules.isDynamicTarget(target)) {
1257 code = 'dart.dindex(#, #)'; 1265 code = 'dart.dindex(#, #)';
1258 } else { 1266 } else {
(...skipping 23 matching lines...) Expand all
1282 visitThrowExpression(ThrowExpression node) { 1290 visitThrowExpression(ThrowExpression node) {
1283 var expr = _visit(node.expression); 1291 var expr = _visit(node.expression);
1284 if (node.parent is ExpressionStatement) { 1292 if (node.parent is ExpressionStatement) {
1285 return js.statement('throw #;', expr); 1293 return js.statement('throw #;', expr);
1286 } else { 1294 } else {
1287 return js.call('dart.throw_(#)', expr); 1295 return js.call('dart.throw_(#)', expr);
1288 } 1296 }
1289 } 1297 }
1290 1298
1291 @override 1299 @override
1292 visitRethrowExpression(RethrowExpression node){ 1300 visitRethrowExpression(RethrowExpression node) {
1293 if (node.parent is ExpressionStatement) { 1301 if (node.parent is ExpressionStatement) {
1294 return js.statement('throw #;', _catchParameter); 1302 return js.statement('throw #;', _catchParameter);
1295 } else { 1303 } else {
1296 return js.call('dart.throw_(#)', _catchParameter); 1304 return js.call('dart.throw_(#)', _catchParameter);
1297 } 1305 }
1298 } 1306 }
1299 1307
1300 @override 1308 @override
1301 JS.If visitIfStatement(IfStatement node) { 1309 JS.If visitIfStatement(IfStatement node) {
1302 return new JS.If(_visit(node.condition), _visit(node.thenStatement), 1310 return new JS.If(_visit(node.condition), _visit(node.thenStatement),
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
1604 var jsExpr = _visit(node); 1612 var jsExpr = _visit(node);
1605 if (result == null) { 1613 if (result == null) {
1606 result = jsExpr; 1614 result = jsExpr;
1607 } else { 1615 } else {
1608 result = new JS.Binary(operator, result, jsExpr); 1616 result = new JS.Binary(operator, result, jsExpr);
1609 } 1617 }
1610 } 1618 }
1611 return result; 1619 return result;
1612 } 1620 }
1613 1621
1614 /// The following names are allowed for user-defined operators: 1622 /// This handles member renaming for private names and operators.
1623 ///
1624 /// Private names are generated using ES6 symbols:
1625 ///
1626 /// // At the top of the module:
1627 /// let _x = Symbol('_x');
1628 /// let _y = Symbol('_y');
1629 /// ...
1630 ///
1631 /// class Point {
1632 /// Point(x, y) {
1633 /// this[_x] = x;
1634 /// this[_y] = y;
1635 /// }
1636 /// get x() { return this[_x]; }
1637 /// get y() { return this[_y]; }
1638 /// }
1639 ///
1640 /// For user-defined operators the following names are allowed:
1615 /// 1641 ///
1616 /// <, >, <=, >=, ==, -, +, /, ˜/, *, %, |, ˆ, &, <<, >>, []=, [], ˜ 1642 /// <, >, <=, >=, ==, -, +, /, ˜/, *, %, |, ˆ, &, <<, >>, []=, [], ˜
1617 /// 1643 ///
1618 /// For the indexing operators, we use `get` and `set` instead: 1644 /// They generate code like:
1645 ///
1646 /// x['+'](y)
1647 ///
1648 /// There are three exceptions: [], []= and unary -.
1649 /// The indexing operators we use `get` and `set` instead:
1619 /// 1650 ///
1620 /// x.get('hi') 1651 /// x.get('hi')
1621 /// x.set('hi', 123) 1652 /// x.set('hi', 123)
1622 /// 1653 ///
1623 /// This follows the same pattern as EcmaScript 6 Map: 1654 /// This follows the same pattern as EcmaScript 6 Map:
1624 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> 1655 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map>
1625 /// 1656 ///
1626 /// For all others we use the operator name: 1657 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed
1627 /// 1658 /// for this transformation to happen, otherwise binary minus is assumed.
1628 /// x['+'](y)
1629 /// 1659 ///
1630 /// Equality is a bit special, it is generated via the Dart `equals` runtime 1660 /// Equality is a bit special, it is generated via the Dart `equals` runtime
1631 /// helper, that checks for null. The user defined method is called '=='. 1661 /// helper, that checks for null. The user defined method is called '=='.
1632 String _jsMethodName(String name) { 1662 ///
1633 if (name == '[]') return 'get'; 1663 JS.Expression _jsMemberName(String name, {bool unary: false}) {
1634 if (name == '[]=') return 'set'; 1664 if (name.startsWith('_')) {
1635 return name; 1665 _privateNames.add(name);
1666 return new JS.VariableUse(name);
1667 }
1668 if (name == '[]') {
1669 name = 'get';
1670 } else if (name == '[]=') {
1671 name = 'set';
1672 } else if (unary && name == '-') {
1673 name = 'unary-';
1674 }
1675 return new JS.PropertyName(name);
1636 } 1676 }
1637 1677
1638 bool _externalOrNative(node) => 1678 bool _externalOrNative(node) =>
1639 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 1679 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
1640 1680
1641 FunctionBody _functionBody(node) => 1681 FunctionBody _functionBody(node) =>
1642 node is FunctionDeclaration ? node.functionExpression.body : node.body; 1682 node is FunctionDeclaration ? node.functionExpression.body : node.body;
1643 1683
1644 /// Choose a canonical name from the library element. 1684 /// Choose a canonical name from the library element.
1645 /// This never uses the library's name (the identifier in the `library` 1685 /// This never uses the library's name (the identifier in the `library`
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
1852 1892
1853 // TODO(jmesserly): in many cases marking the end will be unncessary. 1893 // TODO(jmesserly): in many cases marking the end will be unncessary.
1854 printer.mark(_location(node.end)); 1894 printer.mark(_location(node.end));
1855 } 1895 }
1856 1896
1857 String _getIdentifier(AstNode node) { 1897 String _getIdentifier(AstNode node) {
1858 if (node is SimpleIdentifier) return node.name; 1898 if (node is SimpleIdentifier) return node.name;
1859 return null; 1899 return null;
1860 } 1900 }
1861 } 1901 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/js/printer.dart » ('j') | test/codegen/expect/_isolate_helper/_isolate_helper.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698