| OLD | NEW |
| 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:collection' show HashSet; |
| 7 import 'dart:io' show Directory, File; | 8 import 'dart:io' show Directory, File; |
| 8 | 9 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 11 import 'package:analyzer/src/generated/constant.dart'; | 12 import 'package:analyzer/src/generated/constant.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; | 13 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/scanner.dart' | 14 import 'package:analyzer/src/generated/scanner.dart' |
| 14 show StringToken, Token, TokenType; | 15 show StringToken, Token, TokenType; |
| 15 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; | 16 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; |
| 16 import 'package:source_maps/source_maps.dart' show SourceMapSpan; | 17 import 'package:source_maps/source_maps.dart' show SourceMapSpan; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 39 SimpleIdentifier _cascadeTarget; | 40 SimpleIdentifier _cascadeTarget; |
| 40 /// The variable for the current catch clause | 41 /// The variable for the current catch clause |
| 41 String _catchParameter; | 42 String _catchParameter; |
| 42 | 43 |
| 43 ClassDeclaration currentClass; | 44 ClassDeclaration currentClass; |
| 44 ConstantEvaluator _constEvaluator; | 45 ConstantEvaluator _constEvaluator; |
| 45 | 46 |
| 46 final _exports = <String>[]; | 47 final _exports = <String>[]; |
| 47 final _lazyFields = <VariableDeclaration>[]; | 48 final _lazyFields = <VariableDeclaration>[]; |
| 48 final _properties = <FunctionDeclaration>[]; | 49 final _properties = <FunctionDeclaration>[]; |
| 50 final _privateNames = new HashSet<String>(); |
| 51 final _pendingPrivateNames = <String>[]; |
| 49 | 52 |
| 50 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules) | 53 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules) |
| 51 : libraryInfo = libraryInfo, | 54 : libraryInfo = libraryInfo, |
| 52 rules = rules; | 55 rules = rules; |
| 53 | 56 |
| 54 Element get currentLibrary => libraryInfo.library; | 57 Element get currentLibrary => libraryInfo.library; |
| 55 | 58 |
| 56 JS.Block generateLibrary( | 59 JS.Block generateLibrary( |
| 57 Iterable<CompilationUnit> units, CheckerReporter reporter) { | 60 Iterable<CompilationUnit> units, CheckerReporter reporter) { |
| 58 var body = <JS.Statement>[]; | 61 var body = <JS.Statement>[]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 70 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); | 73 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); |
| 71 | 74 |
| 72 // TODO(jmesserly): make these immutable in JS? | 75 // TODO(jmesserly): make these immutable in JS? |
| 73 for (var name in _exports) { | 76 for (var name in _exports) { |
| 74 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); | 77 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); |
| 75 } | 78 } |
| 76 | 79 |
| 77 var name = jsLibraryName(libraryInfo.library); | 80 var name = jsLibraryName(libraryInfo.library); |
| 78 return new JS.Block([ | 81 return new JS.Block([ |
| 79 js.statement('var #;', name), | 82 js.statement('var #;', name), |
| 80 js.statement(''' | 83 js.statement("(function($_EXPORTS) { 'use strict'; #; })(# || (# = {}));", |
| 81 (function ($_EXPORTS) { | 84 [body, name, name]) |
| 82 'use strict'; | |
| 83 #; | |
| 84 })(# || (# = {})); | |
| 85 ''', [body, name, name]) | |
| 86 ]); | 85 ]); |
| 87 } | 86 } |
| 88 | 87 |
| 88 JS.Statement _initPrivateSymbol(String name) => |
| 89 js.statement('let # = Symbol(#);', [name, js.string(name, "'")]); |
| 90 |
| 89 @override | 91 @override |
| 90 JS.Statement visitCompilationUnit(CompilationUnit node) { | 92 JS.Statement visitCompilationUnit(CompilationUnit node) { |
| 91 // TODO(jmesserly): scriptTag, directives. | 93 // TODO(jmesserly): scriptTag, directives. |
| 92 var body = <JS.Statement>[]; | 94 var body = <JS.Statement>[]; |
| 93 for (var child in node.declarations) { | 95 for (var child in node.declarations) { |
| 94 // Attempt to group adjacent fields/properties. | 96 // Attempt to group adjacent fields/properties. |
| 95 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); | 97 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); |
| 96 if (child is! FunctionDeclaration) _flushLibraryProperties(body); | 98 if (child is! FunctionDeclaration) _flushLibraryProperties(body); |
| 97 | 99 |
| 98 var code = _visit(child); | 100 var code = _visit(child); |
| 99 if (code != null) body.add(code); | 101 |
| 102 if (code != null) { |
| 103 if (_pendingPrivateNames.isNotEmpty) { |
| 104 body.addAll(_pendingPrivateNames.map(_initPrivateSymbol)); |
| 105 _pendingPrivateNames.clear(); |
| 106 } |
| 107 body.add(code); |
| 108 } |
| 100 } | 109 } |
| 110 |
| 101 // Flush any unwritten fields/properties. | 111 // Flush any unwritten fields/properties. |
| 102 _flushLazyFields(body); | 112 _flushLazyFields(body); |
| 103 _flushLibraryProperties(body); | 113 _flushLibraryProperties(body); |
| 114 |
| 115 assert(_pendingPrivateNames.isEmpty); |
| 104 return _statement(body); | 116 return _statement(body); |
| 105 } | 117 } |
| 106 | 118 |
| 107 bool isPublic(String name) => !name.startsWith('_'); | 119 bool isPublic(String name) => !name.startsWith('_'); |
| 108 | 120 |
| 109 /// Conversions that we don't handle end up here. | 121 /// Conversions that we don't handle end up here. |
| 110 @override | 122 @override |
| 111 visitConversion(Conversion node) { | 123 visitConversion(Conversion node) { |
| 112 var from = node.baseType; | 124 var from = node.baseType; |
| 113 var to = node.convertedType; | 125 var to = node.convertedType; |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 return new JS.Block(body)..sourceInformation = node; | 407 return new JS.Block(body)..sourceInformation = node; |
| 396 } | 408 } |
| 397 | 409 |
| 398 @override | 410 @override |
| 399 JS.Statement visitRedirectingConstructorInvocation( | 411 JS.Statement visitRedirectingConstructorInvocation( |
| 400 RedirectingConstructorInvocation node) { | 412 RedirectingConstructorInvocation node) { |
| 401 ClassDeclaration classDecl = node.parent.parent; | 413 ClassDeclaration classDecl = node.parent.parent; |
| 402 var className = classDecl.name.name; | 414 var className = classDecl.name.name; |
| 403 | 415 |
| 404 var name = _constructorName(className, node.constructorName); | 416 var name = _constructorName(className, node.constructorName); |
| 405 return js.statement('this.#(#);', [name, _visit(node.argumentList)]); | 417 return js.statement( |
| 418 'this.#(#);', [_jsMemberName(name), _visit(node.argumentList)]); |
| 406 } | 419 } |
| 407 | 420 |
| 408 JS.Statement _superConstructorCall(ClassDeclaration clazz, | 421 JS.Statement _superConstructorCall(ClassDeclaration clazz, |
| 409 [SuperConstructorInvocation node]) { | 422 [SuperConstructorInvocation node]) { |
| 410 var superCtorName = node != null ? node.constructorName : null; | 423 var superCtorName = node != null ? node.constructorName : null; |
| 411 | 424 |
| 412 var element = clazz.element; | 425 var element = clazz.element; |
| 413 if (superCtorName == null && | 426 if (superCtorName == null && |
| 414 (element.type.isObject || element.supertype.isObject)) { | 427 (element.type.isObject || element.supertype.isObject)) { |
| 415 return null; | 428 return null; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 445 } | 458 } |
| 446 } | 459 } |
| 447 } | 460 } |
| 448 | 461 |
| 449 // Initialize fields from `this.fieldName` parameters. | 462 // Initialize fields from `this.fieldName` parameters. |
| 450 if (parameters != null) { | 463 if (parameters != null) { |
| 451 for (var p in parameters.parameters) { | 464 for (var p in parameters.parameters) { |
| 452 if (p is DefaultFormalParameter) p = p.parameter; | 465 if (p is DefaultFormalParameter) p = p.parameter; |
| 453 if (p is FieldFormalParameter) { | 466 if (p is FieldFormalParameter) { |
| 454 var name = p.identifier.name; | 467 var name = p.identifier.name; |
| 455 body.add(js.statement('this.# = #;', [name, name])); | 468 body.add( |
| 469 js.statement('this.# = #;', [_jsMemberName(name), _visit(p)])); |
| 456 unsetFields.remove(name); | 470 unsetFields.remove(name); |
| 457 } | 471 } |
| 458 } | 472 } |
| 459 } | 473 } |
| 460 | 474 |
| 461 // Run constructor field initializers such as `: foo = bar.baz` | 475 // Run constructor field initializers such as `: foo = bar.baz` |
| 462 if (initializers != null) { | 476 if (initializers != null) { |
| 463 for (var init in initializers) { | 477 for (var init in initializers) { |
| 464 if (init is ConstructorFieldInitializer) { | 478 if (init is ConstructorFieldInitializer) { |
| 465 body.add(js.statement( | 479 body.add(js.statement( |
| 466 '# = #;', [_visit(init.fieldName), _visit(init.expression)])); | 480 '# = #;', [_visit(init.fieldName), _visit(init.expression)])); |
| 467 unsetFields.remove(init.fieldName.name); | 481 unsetFields.remove(init.fieldName.name); |
| 468 } | 482 } |
| 469 } | 483 } |
| 470 } | 484 } |
| 471 | 485 |
| 472 // Initialize all remaining fields | 486 // Initialize all remaining fields |
| 473 unsetFields.forEach((name, field) { | 487 unsetFields.forEach((name, field) { |
| 474 JS.Expression value; | 488 JS.Expression value; |
| 475 if (field.initializer != null) { | 489 if (field.initializer != null) { |
| 476 value = _visit(field.initializer); | 490 value = _visit(field.initializer); |
| 477 } else { | 491 } else { |
| 478 var type = rules.elementType(field.element); | 492 var type = rules.elementType(field.element); |
| 479 if (rules.maybeNonNullableType(type)) { | 493 if (rules.maybeNonNullableType(type)) { |
| 480 value = js.call('dart.as(null, #)', _emitTypeName(type)); | 494 value = js.call('dart.as(null, #)', _emitTypeName(type)); |
| 481 } else { | 495 } else { |
| 482 value = new JS.LiteralNull(); | 496 value = new JS.LiteralNull(); |
| 483 } | 497 } |
| 484 } | 498 } |
| 485 body.add(js.statement('this.# = #;', [name, value])); | 499 body.add(js.statement('this.# = #;', [_jsMemberName(name), value])); |
| 486 }); | 500 }); |
| 487 | 501 |
| 488 return _statement(body); | 502 return _statement(body); |
| 489 } | 503 } |
| 490 | 504 |
| 491 FormalParameterList _parametersOf(node) { | 505 FormalParameterList _parametersOf(node) { |
| 492 // Note: ConstructorDeclaration is intentionally skipped here so we can | 506 // Note: ConstructorDeclaration is intentionally skipped here so we can |
| 493 // emit the argument initializers in a different place. | 507 // emit the argument initializers in a different place. |
| 494 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we | 508 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we |
| 495 // could handle argument initializers more consistently in a separate | 509 // could handle argument initializers more consistently in a separate |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 | 557 |
| 544 @override | 558 @override |
| 545 JS.Method visitMethodDeclaration(MethodDeclaration node) { | 559 JS.Method visitMethodDeclaration(MethodDeclaration node) { |
| 546 if (node.isAbstract || _externalOrNative(node)) { | 560 if (node.isAbstract || _externalOrNative(node)) { |
| 547 return null; | 561 return null; |
| 548 } | 562 } |
| 549 | 563 |
| 550 var params = _visit(node.parameters); | 564 var params = _visit(node.parameters); |
| 551 if (params == null) params = []; | 565 if (params == null) params = []; |
| 552 | 566 |
| 553 return new JS.Method(new JS.PropertyName(_jsMethodName(node.name.name)), | 567 return new JS.Method( |
| 554 new JS.Fun(params, _visit(node.body)), | 568 _jsMemberName(node.name.name), new JS.Fun(params, _visit(node.body)), |
| 555 isGetter: node.isGetter, | 569 isGetter: node.isGetter, |
| 556 isSetter: node.isSetter, | 570 isSetter: node.isSetter, |
| 557 isStatic: node.isStatic); | 571 isStatic: node.isStatic); |
| 558 } | 572 } |
| 559 | 573 |
| 560 @override | 574 @override |
| 561 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { | 575 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 562 assert(node.parent is CompilationUnit); | 576 assert(node.parent is CompilationUnit); |
| 563 | 577 |
| 564 if (_externalOrNative(node)) return null; | 578 if (_externalOrNative(node)) return null; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 var e = node.staticElement; | 650 var e = node.staticElement; |
| 637 if (e == null) { | 651 if (e == null) { |
| 638 return js.commentExpression( | 652 return js.commentExpression( |
| 639 'Unimplemented unknown name', new JS.VariableUse(node.name)); | 653 'Unimplemented unknown name', new JS.VariableUse(node.name)); |
| 640 } | 654 } |
| 641 var name = node.name; | 655 var name = node.name; |
| 642 if (e.enclosingElement is CompilationUnitElement && | 656 if (e.enclosingElement is CompilationUnitElement && |
| 643 (e.library != libraryInfo.library || _needsModuleGetter(e))) { | 657 (e.library != libraryInfo.library || _needsModuleGetter(e))) { |
| 644 return js.call('#.#', [_libraryName(e.library), name]); | 658 return js.call('#.#', [_libraryName(e.library), name]); |
| 645 } else if (currentClass != null && _needsImplicitThis(e)) { | 659 } else if (currentClass != null && _needsImplicitThis(e)) { |
| 646 return js.call('this.#', name); | 660 return js.call('this.#', _jsMemberName(name)); |
| 661 } else if (e is ParameterElement && e.isInitializingFormal) { |
| 662 name = _fieldParameterName(name); |
| 647 } | 663 } |
| 648 return new JS.VariableUse(name); | 664 return new JS.VariableUse(name); |
| 649 } | 665 } |
| 650 | 666 |
| 651 JS.Expression _emitTypeName(DartType type) { | 667 JS.Expression _emitTypeName(DartType type) { |
| 652 var name = type.name; | 668 var name = type.name; |
| 653 var lib = type.element.library; | 669 var lib = type.element.library; |
| 654 if (name == '') { | 670 if (name == '') { |
| 655 // TODO(jmesserly): remove when we're using coercion reifier. | 671 // TODO(jmesserly): remove when we're using coercion reifier. |
| 656 return _unimplementedCall('Unimplemented type $type'); | 672 return _unimplementedCall('Unimplemented type $type'); |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 } | 859 } |
| 844 | 860 |
| 845 @override | 861 @override |
| 846 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) { | 862 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) { |
| 847 var result = <JS.Parameter>[]; | 863 var result = <JS.Parameter>[]; |
| 848 for (FormalParameter param in node.parameters) { | 864 for (FormalParameter param in node.parameters) { |
| 849 if (param.kind == ParameterKind.NAMED) { | 865 if (param.kind == ParameterKind.NAMED) { |
| 850 result.add(new JS.Parameter(_jsNamedParameterName)); | 866 result.add(new JS.Parameter(_jsNamedParameterName)); |
| 851 break; | 867 break; |
| 852 } | 868 } |
| 853 result.add(new JS.Parameter(param.identifier.name)); | 869 result.add(_visit(param)); |
| 854 } | 870 } |
| 855 return result; | 871 return result; |
| 856 } | 872 } |
| 857 | 873 |
| 858 @override | 874 @override |
| 859 JS.Statement visitExpressionStatement(ExpressionStatement node) => | 875 JS.Statement visitExpressionStatement(ExpressionStatement node) => |
| 860 _expressionStatement(_visit(node.expression)); | 876 _expressionStatement(_visit(node.expression)); |
| 861 | 877 |
| 862 // Some expressions may choose to generate themselves as JS statements | 878 // Some expressions may choose to generate themselves as JS statements |
| 863 // if their parent is in a statement context. | 879 // if their parent is in a statement context. |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1206 } | 1222 } |
| 1207 return false; | 1223 return false; |
| 1208 } | 1224 } |
| 1209 | 1225 |
| 1210 @override | 1226 @override |
| 1211 visitParenthesizedExpression(ParenthesizedExpression node) => | 1227 visitParenthesizedExpression(ParenthesizedExpression node) => |
| 1212 // The printer handles precedence so we don't need to. | 1228 // The printer handles precedence so we don't need to. |
| 1213 _visit(node.expression); | 1229 _visit(node.expression); |
| 1214 | 1230 |
| 1215 @override | 1231 @override |
| 1216 visitSimpleFormalParameter(SimpleFormalParameter node) => | 1232 visitFormalParameter(FormalParameter node) => |
| 1217 _visit(node.identifier); | 1233 new JS.Parameter(node.identifier.name); |
| 1218 | 1234 |
| 1219 @override | 1235 @override |
| 1220 visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) => | 1236 visitFieldFormalParameter(FieldFormalParameter node) => |
| 1221 _visit(node.identifier); | 1237 new JS.Parameter(_fieldParameterName(node.identifier.name)); |
| 1238 |
| 1239 /// Rename private names so they don't shadow the private field symbol. |
| 1240 // TODO(jmesserly): replace this ad-hoc rename with a general strategy. |
| 1241 _fieldParameterName(name) => name.startsWith('_') ? '\$$name' : name; |
| 1222 | 1242 |
| 1223 @override | 1243 @override |
| 1224 JS.This visitThisExpression(ThisExpression node) => new JS.This(); | 1244 JS.This visitThisExpression(ThisExpression node) => new JS.This(); |
| 1225 | 1245 |
| 1226 @override | 1246 @override |
| 1227 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); | 1247 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); |
| 1228 | 1248 |
| 1229 @override | 1249 @override |
| 1230 visitPrefixedIdentifier(PrefixedIdentifier node) { | 1250 visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 1231 if (node.prefix.staticElement is PrefixElement) { | 1251 if (node.prefix.staticElement is PrefixElement) { |
| 1232 return _visit(node.identifier); | 1252 return _visit(node.identifier); |
| 1233 } else { | 1253 } else { |
| 1234 return _visitGet(node.prefix, node.identifier); | 1254 return _visitGet(node.prefix, node.identifier); |
| 1235 } | 1255 } |
| 1236 } | 1256 } |
| 1237 | 1257 |
| 1238 @override | 1258 @override |
| 1239 visitPropertyAccess(PropertyAccess node) => | 1259 visitPropertyAccess(PropertyAccess node) => |
| 1240 _visitGet(_getTarget(node), node.propertyName); | 1260 _visitGet(_getTarget(node), node.propertyName); |
| 1241 | 1261 |
| 1242 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 1262 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
| 1243 _visitGet(Expression target, SimpleIdentifier name) { | 1263 _visitGet(Expression target, SimpleIdentifier name) { |
| 1244 if (rules.isDynamicTarget(target)) { | 1264 if (rules.isDynamicTarget(target)) { |
| 1245 return js.call( | 1265 return js.call( |
| 1246 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]); | 1266 'dart.dload(#, #)', [_visit(target), js.string(name.name, "'")]); |
| 1247 } else { | 1267 } else { |
| 1248 return js.call('#.#', [_visit(target), name.name]); | 1268 return js.call('#.#', [_visit(target), _jsMemberName(name.name)]); |
| 1249 } | 1269 } |
| 1250 } | 1270 } |
| 1251 | 1271 |
| 1252 @override | 1272 @override |
| 1253 visitIndexExpression(IndexExpression node) { | 1273 visitIndexExpression(IndexExpression node) { |
| 1254 var target = _getTarget(node); | 1274 var target = _getTarget(node); |
| 1255 var code; | 1275 var code; |
| 1256 if (rules.isDynamicTarget(target)) { | 1276 if (rules.isDynamicTarget(target)) { |
| 1257 code = 'dart.dindex(#, #)'; | 1277 code = 'dart.dindex(#, #)'; |
| 1258 } else { | 1278 } else { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1282 visitThrowExpression(ThrowExpression node) { | 1302 visitThrowExpression(ThrowExpression node) { |
| 1283 var expr = _visit(node.expression); | 1303 var expr = _visit(node.expression); |
| 1284 if (node.parent is ExpressionStatement) { | 1304 if (node.parent is ExpressionStatement) { |
| 1285 return js.statement('throw #;', expr); | 1305 return js.statement('throw #;', expr); |
| 1286 } else { | 1306 } else { |
| 1287 return js.call('dart.throw_(#)', expr); | 1307 return js.call('dart.throw_(#)', expr); |
| 1288 } | 1308 } |
| 1289 } | 1309 } |
| 1290 | 1310 |
| 1291 @override | 1311 @override |
| 1292 visitRethrowExpression(RethrowExpression node){ | 1312 visitRethrowExpression(RethrowExpression node) { |
| 1293 if (node.parent is ExpressionStatement) { | 1313 if (node.parent is ExpressionStatement) { |
| 1294 return js.statement('throw #;', _catchParameter); | 1314 return js.statement('throw #;', _catchParameter); |
| 1295 } else { | 1315 } else { |
| 1296 return js.call('dart.throw_(#)', _catchParameter); | 1316 return js.call('dart.throw_(#)', _catchParameter); |
| 1297 } | 1317 } |
| 1298 } | 1318 } |
| 1299 | 1319 |
| 1300 @override | 1320 @override |
| 1301 JS.If visitIfStatement(IfStatement node) { | 1321 JS.If visitIfStatement(IfStatement node) { |
| 1302 return new JS.If(_visit(node.condition), _visit(node.thenStatement), | 1322 return new JS.If(_visit(node.condition), _visit(node.thenStatement), |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1604 var jsExpr = _visit(node); | 1624 var jsExpr = _visit(node); |
| 1605 if (result == null) { | 1625 if (result == null) { |
| 1606 result = jsExpr; | 1626 result = jsExpr; |
| 1607 } else { | 1627 } else { |
| 1608 result = new JS.Binary(operator, result, jsExpr); | 1628 result = new JS.Binary(operator, result, jsExpr); |
| 1609 } | 1629 } |
| 1610 } | 1630 } |
| 1611 return result; | 1631 return result; |
| 1612 } | 1632 } |
| 1613 | 1633 |
| 1614 /// The following names are allowed for user-defined operators: | 1634 /// This handles member renaming for private names and operators. |
| 1635 /// |
| 1636 /// Private names are generated using ES6 symbols: |
| 1637 /// |
| 1638 /// // At the top of the module: |
| 1639 /// let _x = Symbol('_x'); |
| 1640 /// let _y = Symbol('_y'); |
| 1641 /// ... |
| 1642 /// |
| 1643 /// class Point { |
| 1644 /// Point(x, y) { |
| 1645 /// this[_x] = x; |
| 1646 /// this[_y] = y; |
| 1647 /// } |
| 1648 /// get x() { return this[_x]; } |
| 1649 /// get y() { return this[_y]; } |
| 1650 /// } |
| 1651 /// |
| 1652 /// For user-defined operators the following names are allowed: |
| 1615 /// | 1653 /// |
| 1616 /// <, >, <=, >=, ==, -, +, /, ˜/, *, %, |, ˆ, &, <<, >>, []=, [], ˜ | 1654 /// <, >, <=, >=, ==, -, +, /, ˜/, *, %, |, ˆ, &, <<, >>, []=, [], ˜ |
| 1617 /// | 1655 /// |
| 1618 /// For the indexing operators, we use `get` and `set` instead: | 1656 /// They generate code like: |
| 1657 /// |
| 1658 /// x['+'](y) |
| 1659 /// |
| 1660 /// There are three exceptions: [], []= and unary -. |
| 1661 /// The indexing operators we use `get` and `set` instead: |
| 1619 /// | 1662 /// |
| 1620 /// x.get('hi') | 1663 /// x.get('hi') |
| 1621 /// x.set('hi', 123) | 1664 /// x.set('hi', 123) |
| 1622 /// | 1665 /// |
| 1623 /// This follows the same pattern as EcmaScript 6 Map: | 1666 /// This follows the same pattern as EcmaScript 6 Map: |
| 1624 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/Map> | 1667 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_
Objects/Map> |
| 1625 /// | 1668 /// |
| 1626 /// For all others we use the operator name: | 1669 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed |
| 1627 /// | 1670 /// for this transformation to happen, otherwise binary minus is assumed. |
| 1628 /// x['+'](y) | |
| 1629 /// | 1671 /// |
| 1630 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 1672 /// 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 '=='. | 1673 /// helper, that checks for null. The user defined method is called '=='. |
| 1632 String _jsMethodName(String name) { | 1674 /// |
| 1633 if (name == '[]') return 'get'; | 1675 JS.Expression _jsMemberName(String name, {bool unary: false}) { |
| 1634 if (name == '[]=') return 'set'; | 1676 if (name.startsWith('_')) { |
| 1635 return name; | 1677 if (_privateNames.add(name)) _pendingPrivateNames.add(name); |
| 1678 return new JS.VariableUse(name); |
| 1679 } |
| 1680 if (name == '[]') { |
| 1681 name = 'get'; |
| 1682 } else if (name == '[]=') { |
| 1683 name = 'set'; |
| 1684 } else if (unary && name == '-') { |
| 1685 name = 'unary-'; |
| 1686 } |
| 1687 return new JS.PropertyName(name); |
| 1636 } | 1688 } |
| 1637 | 1689 |
| 1638 bool _externalOrNative(node) => | 1690 bool _externalOrNative(node) => |
| 1639 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 1691 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 1640 | 1692 |
| 1641 FunctionBody _functionBody(node) => | 1693 FunctionBody _functionBody(node) => |
| 1642 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 1694 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| 1643 | 1695 |
| 1644 /// Choose a canonical name from the library element. | 1696 /// Choose a canonical name from the library element. |
| 1645 /// This never uses the library's name (the identifier in the `library` | 1697 /// This never uses the library's name (the identifier in the `library` |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1852 | 1904 |
| 1853 // TODO(jmesserly): in many cases marking the end will be unncessary. | 1905 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 1854 printer.mark(_location(node.end)); | 1906 printer.mark(_location(node.end)); |
| 1855 } | 1907 } |
| 1856 | 1908 |
| 1857 String _getIdentifier(AstNode node) { | 1909 String _getIdentifier(AstNode node) { |
| 1858 if (node is SimpleIdentifier) return node.name; | 1910 if (node is SimpleIdentifier) return node.name; |
| 1859 return null; | 1911 return null; |
| 1860 } | 1912 } |
| 1861 } | 1913 } |
| OLD | NEW |