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 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 final ClassElement _jsArray; | 118 final ClassElement _jsArray; |
119 | 119 |
120 final ClassElement boolClass; | 120 final ClassElement boolClass; |
121 final ClassElement intClass; | 121 final ClassElement intClass; |
122 final ClassElement interceptorClass; | 122 final ClassElement interceptorClass; |
123 final ClassElement nullClass; | 123 final ClassElement nullClass; |
124 final ClassElement numClass; | 124 final ClassElement numClass; |
125 final ClassElement objectClass; | 125 final ClassElement objectClass; |
126 final ClassElement stringClass; | 126 final ClassElement stringClass; |
127 | 127 |
128 ConstFieldVisitor _constField; | 128 ConstFieldVisitor _constants; |
129 | 129 |
130 /// The current function body being compiled. | 130 /// The current function body being compiled. |
131 FunctionBody _currentFunction; | 131 FunctionBody _currentFunction; |
132 | 132 |
133 /// Helper class for emitting elements in the proper order to allow | 133 /// Helper class for emitting elements in the proper order to allow |
134 /// JS to load the module. | 134 /// JS to load the module. |
135 ElementLoader _loader; | 135 ElementLoader _loader; |
136 | 136 |
137 BuildUnit _buildUnit; | 137 BuildUnit _buildUnit; |
138 | 138 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
269 var nodes = new HashMap<Element, AstNode>.identity(); | 269 var nodes = new HashMap<Element, AstNode>.identity(); |
270 var sdkBootstrappingFns = new List<FunctionElement>(); | 270 var sdkBootstrappingFns = new List<FunctionElement>(); |
271 for (var unit in compilationUnits) { | 271 for (var unit in compilationUnits) { |
272 if (_isDartRuntime(unit.element.library)) { | 272 if (_isDartRuntime(unit.element.library)) { |
273 sdkBootstrappingFns.addAll(unit.element.functions); | 273 sdkBootstrappingFns.addAll(unit.element.functions); |
274 } | 274 } |
275 _collectElements(unit, nodes); | 275 _collectElements(unit, nodes); |
276 } | 276 } |
277 _loader = new ElementLoader(nodes); | 277 _loader = new ElementLoader(nodes); |
278 if (compilationUnits.isNotEmpty) { | 278 if (compilationUnits.isNotEmpty) { |
279 _constField = new ConstFieldVisitor(types, | 279 _constants = new ConstFieldVisitor(context, |
280 dummySource: compilationUnits.first.element.source); | 280 dummySource: compilationUnits.first.element.source); |
281 } | 281 } |
282 | 282 |
283 // Add implicit dart:core dependency so it is first. | 283 // Add implicit dart:core dependency so it is first. |
284 emitLibraryName(dartCoreLibrary); | 284 emitLibraryName(dartCoreLibrary); |
285 | 285 |
286 // Emit SDK bootstrapping functions first, if any. | 286 // Emit SDK bootstrapping functions first, if any. |
287 sdkBootstrappingFns.forEach(_emitDeclaration); | 287 sdkBootstrappingFns.forEach(_emitDeclaration); |
288 | 288 |
289 // Visit each compilation unit and emit its code. | 289 // Visit each compilation unit and emit its code. |
(...skipping 1823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2113 [ConstructorDeclaration ctor]) { | 2113 [ConstructorDeclaration ctor]) { |
2114 bool isConst = ctor != null && ctor.constKeyword != null; | 2114 bool isConst = ctor != null && ctor.constKeyword != null; |
2115 if (isConst) _loader.startTopLevel(cls.element); | 2115 if (isConst) _loader.startTopLevel(cls.element); |
2116 | 2116 |
2117 // Run field initializers if they can have side-effects. | 2117 // Run field initializers if they can have side-effects. |
2118 var fields = new Map<FieldElement, JS.Expression>(); | 2118 var fields = new Map<FieldElement, JS.Expression>(); |
2119 var unsetFields = new Map<FieldElement, VariableDeclaration>(); | 2119 var unsetFields = new Map<FieldElement, VariableDeclaration>(); |
2120 for (var declaration in fieldDecls) { | 2120 for (var declaration in fieldDecls) { |
2121 for (var fieldNode in declaration.fields.variables) { | 2121 for (var fieldNode in declaration.fields.variables) { |
2122 var element = fieldNode.element; | 2122 var element = fieldNode.element; |
2123 if (_constField.isFieldInitConstant(fieldNode)) { | 2123 if (_constants.isFieldInitConstant(fieldNode)) { |
2124 unsetFields[element as FieldElement] = fieldNode; | 2124 unsetFields[element as FieldElement] = fieldNode; |
2125 } else { | 2125 } else { |
2126 fields[element as FieldElement] = _visitInitializer(fieldNode); | 2126 fields[element as FieldElement] = _visitInitializer(fieldNode); |
2127 } | 2127 } |
2128 } | 2128 } |
2129 } | 2129 } |
2130 | 2130 |
2131 // Initialize fields from `this.fieldName` parameters. | 2131 // Initialize fields from `this.fieldName` parameters. |
2132 if (ctor != null) { | 2132 if (ctor != null) { |
2133 for (var p in ctor.parameters.parameters) { | 2133 for (var p in ctor.parameters.parameters) { |
(...skipping 1626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3760 JS.Statement _emitConstantStaticField(ClassElement classElem, | 3760 JS.Statement _emitConstantStaticField(ClassElement classElem, |
3761 VariableDeclaration field, Set<FieldElement> staticFieldOverrides) { | 3761 VariableDeclaration field, Set<FieldElement> staticFieldOverrides) { |
3762 PropertyInducingElement element = field.element; | 3762 PropertyInducingElement element = field.element; |
3763 assert(element.isStatic); | 3763 assert(element.isStatic); |
3764 | 3764 |
3765 _loader.startCheckingReferences(); | 3765 _loader.startCheckingReferences(); |
3766 JS.Expression jsInit = _visitInitializer(field); | 3766 JS.Expression jsInit = _visitInitializer(field); |
3767 bool isLoaded = _loader.finishCheckingReferences(); | 3767 bool isLoaded = _loader.finishCheckingReferences(); |
3768 | 3768 |
3769 bool eagerInit = | 3769 bool eagerInit = |
3770 isLoaded && (field.isConst || _constField.isFieldInitConstant(field)); | 3770 isLoaded && (field.isConst || _constants.isFieldInitConstant(field)); |
3771 | 3771 |
3772 var fieldName = field.name.name; | 3772 var fieldName = field.name.name; |
3773 if (eagerInit && | 3773 if (eagerInit && |
3774 !JS.invalidStaticFieldName(fieldName) && | 3774 !JS.invalidStaticFieldName(fieldName) && |
3775 !staticFieldOverrides.contains(element)) { | 3775 !staticFieldOverrides.contains(element)) { |
3776 return annotate( | 3776 return annotate( |
3777 js.statement('#.# = #;', [ | 3777 js.statement('#.# = #;', [ |
3778 _emitTopLevelName(classElem), | 3778 _emitTopLevelName(classElem), |
3779 _emitMemberName(fieldName, isStatic: true), | 3779 _emitMemberName(fieldName, isStatic: true), |
3780 jsInit | 3780 jsInit |
3781 ]), | 3781 ]), |
3782 field, | 3782 field, |
3783 field.element); | 3783 field.element); |
3784 } | 3784 } |
3785 | 3785 |
3786 // This means it should be treated as a lazy field. | 3786 // This means it should be treated as a lazy field. |
3787 // TODO(jmesserly): we're throwing away the initializer expression, | 3787 // TODO(jmesserly): we're throwing away the initializer expression, |
3788 // which will force us to regenerate it. | 3788 // which will force us to regenerate it. |
3789 return null; | 3789 return null; |
3790 } | 3790 } |
3791 | 3791 |
3792 /// Emits a top-level field. | 3792 /// Emits a top-level field. |
3793 JS.ModuleItem _emitTopLevelField(VariableDeclaration field) { | 3793 JS.ModuleItem _emitTopLevelField(VariableDeclaration field) { |
3794 TopLevelVariableElement element = field.element; | 3794 TopLevelVariableElement element = field.element; |
3795 assert(element.isStatic); | 3795 assert(element.isStatic); |
3796 | 3796 |
3797 bool eagerInit; | 3797 bool eagerInit; |
3798 JS.Expression jsInit; | 3798 JS.Expression jsInit; |
3799 if (field.isConst || _constField.isFieldInitConstant(field)) { | 3799 if (field.isConst || _constants.isFieldInitConstant(field)) { |
3800 // If the field is constant, try and generate it at the top level. | 3800 // If the field is constant, try and generate it at the top level. |
3801 _loader.startTopLevel(element); | 3801 _loader.startTopLevel(element); |
3802 jsInit = _visitInitializer(field); | 3802 jsInit = _visitInitializer(field); |
3803 _loader.finishTopLevel(element); | 3803 _loader.finishTopLevel(element); |
3804 eagerInit = _loader.isLoaded(element); | 3804 eagerInit = _loader.isLoaded(element); |
3805 } else { | 3805 } else { |
3806 // TODO(jmesserly): we're visiting the initializer here, and again | 3806 // TODO(jmesserly): we're visiting the initializer here, and again |
3807 // later on when we emit lazy fields. That seems busted. | 3807 // later on when we emit lazy fields. That seems busted. |
3808 jsInit = _visitInitializer(field); | 3808 jsInit = _visitInitializer(field); |
3809 eagerInit = false; | 3809 eagerInit = false; |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3954 assert(args.single is JS.ObjectInitializer); | 3954 assert(args.single is JS.ObjectInitializer); |
3955 return args.single; | 3955 return args.single; |
3956 } | 3956 } |
3957 | 3957 |
3958 @override | 3958 @override |
3959 visitInstanceCreationExpression(InstanceCreationExpression node) { | 3959 visitInstanceCreationExpression(InstanceCreationExpression node) { |
3960 var element = node.staticElement; | 3960 var element = node.staticElement; |
3961 var constructor = node.constructorName; | 3961 var constructor = node.constructorName; |
3962 var name = constructor.name; | 3962 var name = constructor.name; |
3963 var type = constructor.type.type; | 3963 var type = constructor.type.type; |
3964 if (node.isConst && | |
3965 element?.name == 'fromEnvironment' && | |
3966 element.library.isDartCore) { | |
3967 var value = node.accept(_constants.constantVisitor); | |
3968 | |
3969 if (value == null || value.isNull) { | |
3970 return new JS.LiteralNull(); | |
3971 } | |
3972 if (value.isUnknown) { | |
3973 return type == types.boolType | |
3974 ? js.boolean(false) | |
vsm
2016/11/16 19:16:22
Can you add a comment explaining this case? When
Jennifer Messerly
2016/11/16 20:11:48
Sure, as best as I can. Unfortunately behavior of
| |
3975 : new JS.LiteralNull(); | |
3976 } | |
3977 if (value.type == types.boolType) { | |
3978 var boolValue = value.toBoolValue(); | |
3979 return boolValue != null ? js.boolean(boolValue) : new JS.LiteralNull(); | |
3980 } | |
3981 if (value.type == types.intType) { | |
3982 var intValue = value.toIntValue(); | |
3983 return intValue != null ? js.number(intValue) : new JS.LiteralNull(); | |
3984 } | |
3985 if (value.type == types.stringType) { | |
3986 var stringValue = value.toStringValue(); | |
3987 return stringValue != null | |
3988 ? js.escapedString(stringValue) | |
3989 : new JS.LiteralNull(); | |
3990 } | |
3991 throw new StateError('failed to evaluate $node'); | |
3992 } | |
3964 return _emitInstanceCreationExpression( | 3993 return _emitInstanceCreationExpression( |
3965 element, type, name, node.argumentList, node.isConst); | 3994 element, type, name, node.argumentList, node.isConst); |
3966 } | 3995 } |
3967 | 3996 |
3968 /// True if this type is built-in to JS, and we use the values unwrapped. | 3997 /// True if this type is built-in to JS, and we use the values unwrapped. |
3969 /// For these types we generate a calling convention via static | 3998 /// For these types we generate a calling convention via static |
3970 /// "extension methods". This allows types to be extended without adding | 3999 /// "extension methods". This allows types to be extended without adding |
3971 /// extensions directly on the prototype. | 4000 /// extensions directly on the prototype. |
3972 bool isPrimitiveType(DartType t) => | 4001 bool isPrimitiveType(DartType t) => |
3973 typeIsPrimitiveInJS(t) || t == types.stringType; | 4002 typeIsPrimitiveInJS(t) || t == types.stringType; |
(...skipping 1622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5596 var targetIdentifier = target as SimpleIdentifier; | 5625 var targetIdentifier = target as SimpleIdentifier; |
5597 | 5626 |
5598 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5627 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5599 var prefix = targetIdentifier.staticElement as PrefixElement; | 5628 var prefix = targetIdentifier.staticElement as PrefixElement; |
5600 | 5629 |
5601 // The library the prefix is referring to must come from a deferred import. | 5630 // The library the prefix is referring to must come from a deferred import. |
5602 var containingLibrary = (target.root as CompilationUnit).element.library; | 5631 var containingLibrary = (target.root as CompilationUnit).element.library; |
5603 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5632 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5604 return imports.length == 1 && imports[0].isDeferred; | 5633 return imports.length == 1 && imports[0].isDeferred; |
5605 } | 5634 } |
OLD | NEW |