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

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

Issue 1393683003: more housecleaning: helpers on rules (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: rebase Created 5 years, 2 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
« no previous file with comments | « lib/src/checker/rules.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 final _temps = new HashMap<Element, JS.TemporaryId>(); 84 final _temps = new HashMap<Element, JS.TemporaryId>();
85 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); 85 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>();
86 86
87 /// The name for the library's exports inside itself. 87 /// The name for the library's exports inside itself.
88 /// `exports` was chosen as the most similar to ES module patterns. 88 /// `exports` was chosen as the most similar to ES module patterns.
89 final _dartxVar = new JS.Identifier('dartx'); 89 final _dartxVar = new JS.Identifier('dartx');
90 final _exportsVar = new JS.TemporaryId('exports'); 90 final _exportsVar = new JS.TemporaryId('exports');
91 final _runtimeLibVar = new JS.Identifier('dart'); 91 final _runtimeLibVar = new JS.Identifier('dart');
92 final _namedArgTemp = new JS.TemporaryId('opts'); 92 final _namedArgTemp = new JS.TemporaryId('opts');
93 93
94 final TypeProvider _types;
95
94 ConstFieldVisitor _constField; 96 ConstFieldVisitor _constField;
95 97
96 ModuleItemLoadOrder _loader; 98 ModuleItemLoadOrder _loader;
97 99
98 /// _interceptors.JSArray<E>, used for List literals. 100 /// _interceptors.JSArray<E>, used for List literals.
99 ClassElement _jsArray; 101 ClassElement _jsArray;
100 102
101 /// The default value of the module object. See [visitLibraryDirective]. 103 /// The default value of the module object. See [visitLibraryDirective].
102 String _jsModuleValue; 104 String _jsModuleValue;
103 105
104 Map<String, DartType> _objectMembers; 106 Map<String, DartType> _objectMembers;
105 107
106 JSCodegenVisitor(AbstractCompiler compiler, this.currentLibrary, 108 JSCodegenVisitor(AbstractCompiler compiler, this.currentLibrary,
107 this._extensionTypes, this._fieldsNeedingStorage) 109 this._extensionTypes, this._fieldsNeedingStorage)
108 : compiler = compiler, 110 : compiler = compiler,
109 options = compiler.options.codegenOptions, 111 options = compiler.options.codegenOptions,
110 rules = compiler.rules { 112 rules = compiler.rules,
113 _types = compiler.context.typeProvider {
111 _loader = new ModuleItemLoadOrder(_emitModuleItem); 114 _loader = new ModuleItemLoadOrder(_emitModuleItem);
112 115
113 var context = compiler.context; 116 var context = compiler.context;
114 var src = context.sourceFactory.forUri('dart:_interceptors'); 117 var src = context.sourceFactory.forUri('dart:_interceptors');
115 var interceptors = context.computeLibraryElement(src); 118 var interceptors = context.computeLibraryElement(src);
116 _jsArray = interceptors.getType('JSArray'); 119 _jsArray = interceptors.getType('JSArray');
117 120
118 _objectMembers = getObjectMemberMap(types); 121 _objectMembers = getObjectMemberMap(types);
119 } 122 }
120 123
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 visitAsExpression(AsExpression node) { 312 visitAsExpression(AsExpression node) {
310 var from = getStaticType(node.expression); 313 var from = getStaticType(node.expression);
311 var to = node.type.type; 314 var to = node.type.type;
312 315
313 var fromExpr = _visit(node.expression); 316 var fromExpr = _visit(node.expression);
314 317
315 // Skip the cast if it's not needed. 318 // Skip the cast if it's not needed.
316 if (rules.isSubTypeOf(from, to)) return fromExpr; 319 if (rules.isSubTypeOf(from, to)) return fromExpr;
317 320
318 // All Dart number types map to a JS double. 321 // All Dart number types map to a JS double.
319 if (rules.isNumberInJS(from) && rules.isNumberInJS(to)) { 322 if (_isNumberInJS(from) && _isNumberInJS(to)) {
320 // Make sure to check when converting to int. 323 // Make sure to check when converting to int.
321 if (!rules.isIntType(from) && rules.isIntType(to)) { 324 if (from != _types.intType && to == _types.intType) {
322 return js.call('dart.asInt(#)', [fromExpr]); 325 return js.call('dart.asInt(#)', [fromExpr]);
323 } 326 }
324 327
325 if (!rules.isNonNullableType(from) && rules.isNonNullableType(to)) { 328 if (!rules.isNonNullableType(from) && rules.isNonNullableType(to)) {
326 // Converting from a nullable number to a non-nullable number 329 // Converting from a nullable number to a non-nullable number
327 // only requires a null check. 330 // only requires a null check.
328 // TODO(jmesserly): a lot of these checks are meaningless, as people use 331 // TODO(jmesserly): a lot of these checks are meaningless, as people use
329 // `num` to mean "any kind of number" rather than "could be null". 332 // `num` to mean "any kind of number" rather than "could be null".
330 // The core libraries especially suffer from this problem, with many of 333 // The core libraries especially suffer from this problem, with many of
331 // the `num` methods returning `num`. 334 // the `num` methods returning `num`.
(...skipping 21 matching lines...) Expand all
353 result = js.call('dart.is(#, #)', [lhs, _emitTypeName(type)]); 356 result = js.call('dart.is(#, #)', [lhs, _emitTypeName(type)]);
354 } 357 }
355 358
356 if (node.notOperator != null) { 359 if (node.notOperator != null) {
357 return js.call('!#', result); 360 return js.call('!#', result);
358 } 361 }
359 return result; 362 return result;
360 } 363 }
361 364
362 String _jsTypeofName(DartType t) { 365 String _jsTypeofName(DartType t) {
363 if (rules.isNumberInJS(t)) return 'number'; 366 if (_isNumberInJS(t)) return 'number';
364 if (rules.isStringType(t)) return 'string'; 367 if (t == _types.stringType) return 'string';
365 if (rules.isBoolType(t)) return 'boolean'; 368 if (t == _types.boolType) return 'boolean';
366 return null; 369 return null;
367 } 370 }
368 371
369 @override 372 @override
370 visitFunctionTypeAlias(FunctionTypeAlias node) { 373 visitFunctionTypeAlias(FunctionTypeAlias node) {
371 var element = node.element; 374 var element = node.element;
372 var type = element.type; 375 var type = element.type;
373 var name = element.name; 376 var name = element.name;
374 377
375 var fnType = annotateTypeDef( 378 var fnType = annotateTypeDef(
(...skipping 1784 matching lines...) Expand 10 before | Expand all | Expand 10 after
2160 var type = constructor.type.type; 2163 var type = constructor.type.type;
2161 return _emitInstanceCreationExpression( 2164 return _emitInstanceCreationExpression(
2162 element, type, name, node.argumentList, node.isConst); 2165 element, type, name, node.argumentList, node.isConst);
2163 } 2166 }
2164 2167
2165 /// True if this type is built-in to JS, and we use the values unwrapped. 2168 /// True if this type is built-in to JS, and we use the values unwrapped.
2166 /// For these types we generate a calling convention via static 2169 /// For these types we generate a calling convention via static
2167 /// "extension methods". This allows types to be extended without adding 2170 /// "extension methods". This allows types to be extended without adding
2168 /// extensions directly on the prototype. 2171 /// extensions directly on the prototype.
2169 bool _isJSBuiltinType(DartType t) => 2172 bool _isJSBuiltinType(DartType t) =>
2170 typeIsPrimitiveInJS(t) || rules.isStringType(t); 2173 typeIsPrimitiveInJS(t) || t == _types.stringType;
2171 2174
2172 bool typeIsPrimitiveInJS(DartType t) => 2175 bool typeIsPrimitiveInJS(DartType t) =>
2173 rules.isNumberInJS(t) || rules.isBoolType(t); 2176 _isNumberInJS(t) || t == _types.boolType;
2174 2177
2175 bool typeIsNonNullablePrimitiveInJS(DartType t) => 2178 bool typeIsNonNullablePrimitiveInJS(DartType t) =>
2176 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t); 2179 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t);
2177 2180
2178 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => 2181 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) =>
2179 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); 2182 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT);
2180 2183
2181 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); 2184 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t);
2182 2185
2183 bool _isNonNullableExpression(Expression expr) { 2186 bool _isNonNullableExpression(Expression expr) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
2287 2290
2288 var vars = <String, JS.Expression>{}; 2291 var vars = <String, JS.Expression>{};
2289 // Desugar `l ?? r` as `l != null ? l : r` 2292 // Desugar `l ?? r` as `l != null ? l : r`
2290 var l = _visit(_bindValue(vars, 'l', left, context: left)); 2293 var l = _visit(_bindValue(vars, 'l', left, context: left));
2291 return new JS.MetaLet(vars, [ 2294 return new JS.MetaLet(vars, [
2292 js.call('# != null ? # : #', [l, l, _visit(right)]) 2295 js.call('# != null ? # : #', [l, l, _visit(right)])
2293 ]); 2296 ]);
2294 } 2297 }
2295 2298
2296 if (binaryOperationIsPrimitive(leftType, rightType) || 2299 if (binaryOperationIsPrimitive(leftType, rightType) ||
2297 rules.isStringType(leftType) && op.type == TokenType.PLUS) { 2300 leftType == _types.stringType && op.type == TokenType.PLUS) {
2298 // special cases where we inline the operation 2301 // special cases where we inline the operation
2299 // these values are assumed to be non-null (determined by the checker) 2302 // these values are assumed to be non-null (determined by the checker)
2300 // TODO(jmesserly): it would be nice to just inline the method from core, 2303 // TODO(jmesserly): it would be nice to just inline the method from core,
2301 // instead of special cases here. 2304 // instead of special cases here.
2302 if (op.type == TokenType.TILDE_SLASH) { 2305 if (op.type == TokenType.TILDE_SLASH) {
2303 // `a ~/ b` is equivalent to `(a / b).truncate()` 2306 // `a ~/ b` is equivalent to `(a / b).truncate()`
2304 var div = AstBuilder.binaryExpression(left, '/', right) 2307 var div = AstBuilder.binaryExpression(left, '/', right)
2305 ..staticType = node.staticType; 2308 ..staticType = node.staticType;
2306 return _emitSend(div, 'truncate', []); 2309 return _emitSend(div, 'truncate', []);
2307 } else { 2310 } else {
(...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after
3245 3248
3246 JS.Node annotateVariable(JS.Node node, VariableElement e) => 3249 JS.Node annotateVariable(JS.Node node, VariableElement e) =>
3247 options.closure && e != null 3250 options.closure && e != null
3248 ? node.withClosureAnnotation(closureAnnotationForVariable(e)) 3251 ? node.withClosureAnnotation(closureAnnotationForVariable(e))
3249 : node; 3252 : node;
3250 3253
3251 JS.Node annotateTypeDef(JS.Node node, FunctionTypeAliasElement e) => 3254 JS.Node annotateTypeDef(JS.Node node, FunctionTypeAliasElement e) =>
3252 options.closure && e != null 3255 options.closure && e != null
3253 ? node.withClosureAnnotation(closureAnnotationForTypeDef(e)) 3256 ? node.withClosureAnnotation(closureAnnotationForTypeDef(e))
3254 : node; 3257 : node;
3258
3259 /// Returns true if this is any kind of object represented by `Number` in JS.
3260 ///
3261 /// In practice, this is 4 types: num, int, double, and JSNumber.
3262 ///
3263 /// JSNumber is the type that actually "implements" all numbers, hence it's
3264 /// a subtype of int and double (and num). It's in our "dart:_interceptors".
3265 bool _isNumberInJS(DartType t) => rules.isSubTypeOf(t, _types.numType);
3255 } 3266 }
3256 3267
3257 class JSGenerator extends CodeGenerator { 3268 class JSGenerator extends CodeGenerator {
3258 final _extensionTypes = new HashSet<ClassElement>(); 3269 final _extensionTypes = new HashSet<ClassElement>();
3259 3270
3260 JSGenerator(AbstractCompiler compiler) : super(compiler) { 3271 JSGenerator(AbstractCompiler compiler) : super(compiler) {
3261 // TODO(jacobr): determine the the set of types with extension methods from 3272 // TODO(jacobr): determine the the set of types with extension methods from
3262 // the annotations rather than hard coding the list once the analyzer 3273 // the annotations rather than hard coding the list once the analyzer
3263 // supports summaries. 3274 // supports summaries.
3264 var context = compiler.context; 3275 var context = compiler.context;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
3322 3333
3323 /// A special kind of element created by the compiler, signifying a temporary 3334 /// A special kind of element created by the compiler, signifying a temporary
3324 /// variable. These objects use instance equality, and should be shared 3335 /// variable. These objects use instance equality, and should be shared
3325 /// everywhere in the tree where they are treated as the same variable. 3336 /// everywhere in the tree where they are treated as the same variable.
3326 class TemporaryVariableElement extends LocalVariableElementImpl { 3337 class TemporaryVariableElement extends LocalVariableElementImpl {
3327 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3338 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3328 3339
3329 int get hashCode => identityHashCode(this); 3340 int get hashCode => identityHashCode(this);
3330 bool operator ==(Object other) => identical(this, other); 3341 bool operator ==(Object other) => identical(this, other);
3331 } 3342 }
OLDNEW
« no previous file with comments | « lib/src/checker/rules.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698