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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 | 6 |
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
8 import 'package:analyzer/dart/ast/ast.dart'; | 8 import 'package:analyzer/dart/ast/ast.dart'; |
9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
(...skipping 2792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2803 js.call('# != null ? # : #', [l, l, _visit(right)]) | 2803 js.call('# != null ? # : #', [l, l, _visit(right)]) |
2804 ]); | 2804 ]); |
2805 } | 2805 } |
2806 | 2806 |
2807 if (binaryOperationIsPrimitive(leftType, rightType) || | 2807 if (binaryOperationIsPrimitive(leftType, rightType) || |
2808 leftType == types.stringType && op.type == TokenType.PLUS) { | 2808 leftType == types.stringType && op.type == TokenType.PLUS) { |
2809 // special cases where we inline the operation | 2809 // special cases where we inline the operation |
2810 // these values are assumed to be non-null (determined by the checker) | 2810 // these values are assumed to be non-null (determined by the checker) |
2811 // TODO(jmesserly): it would be nice to just inline the method from core, | 2811 // TODO(jmesserly): it would be nice to just inline the method from core, |
2812 // instead of special cases here. | 2812 // instead of special cases here. |
2813 if (op.type == TokenType.TILDE_SLASH) { | 2813 JS.Expression binary(String code) { |
2814 // `a ~/ b` is equivalent to `(a / b).truncate()` | 2814 return js.call(code, [notNull(left), notNull(right)]); |
2815 var div = AstBuilder.binaryExpression(left, '/', right) | |
2816 ..staticType = node.staticType; | |
2817 return _emitSend(div, 'truncate', []); | |
2818 } else { | |
2819 // TODO(vsm): When do Dart ops not map to JS? | |
2820 code = '# $op #'; | |
2821 } | 2815 } |
2822 return js.call(code, [notNull(left), notNull(right)]); | 2816 |
2817 JS.Expression bitwise(String code) { | |
2818 return _coerceBitOperationResultToUnsigned(node, binary(code)); | |
2819 } | |
2820 | |
2821 switch (op.type) { | |
2822 case TokenType.TILDE_SLASH: | |
Jennifer Messerly
2016/04/28 20:08:52
this looks great, love the refactoring!
| |
2823 // `a ~/ b` is equivalent to `(a / b).truncate()` | |
2824 var div = AstBuilder.binaryExpression(left, '/', right) | |
2825 ..staticType = node.staticType; | |
2826 return _emitSend(div, 'truncate', []); | |
2827 | |
2828 case TokenType.PERCENT: | |
2829 // TODO(sra): We can generate `a % b + 0` if both are non-negative | |
2830 // (the `+ 0` is to coerce -0.0 to 0). | |
2831 return _emitSend(left, op.lexeme, [right]); | |
2832 | |
2833 case TokenType.AMPERSAND: | |
2834 return bitwise('# & #'); | |
2835 | |
2836 case TokenType.BAR: | |
2837 return bitwise('# | #'); | |
2838 | |
2839 case TokenType.CARET: | |
2840 return bitwise('# ^ #'); | |
2841 | |
2842 case TokenType.GT_GT: | |
2843 // TODO(sra): Detect when JS shift does the right thing. | |
2844 return _emitSend(left, op.lexeme, [right]); | |
2845 | |
2846 case TokenType.LT_LT: | |
2847 // TODO(sra): Detect when JS shift does the right thing. | |
2848 return _emitSend(left, op.lexeme, [right]); | |
2849 | |
2850 default: | |
2851 // TODO(vsm): When do Dart ops not map to JS? | |
2852 return binary('# $op #'); | |
2853 } | |
2823 } | 2854 } |
2824 | 2855 |
2825 return _emitSend(left, op.lexeme, [right]); | 2856 return _emitSend(left, op.lexeme, [right]); |
2826 } | 2857 } |
2827 | 2858 |
2859 JS.Expression _coerceBitOperationResultToUnsigned( | |
2860 Expression node, JS.Expression operation) { | |
2861 // Bit operations are coerced to values on [0, 2^32). The coercion changes | |
Jennifer Messerly
2016/04/28 20:08:52
move this to be a doc comment?
| |
2862 // the interpretation of the the 32-bit value from signed to unsigned. Most | |
2863 // JavaScript operations interpret their operands as signed and generate | |
2864 // signed results. | |
2865 return js.call('# >>> 0', operation); | |
2866 } | |
2867 | |
2828 /// If the type [t] is [int] or [double], or a type parameter | 2868 /// If the type [t] is [int] or [double], or a type parameter |
2829 /// bounded by [int], [double] or [num] returns [num]. | 2869 /// bounded by [int], [double] or [num] returns [num]. |
2830 /// Otherwise returns [t]. | 2870 /// Otherwise returns [t]. |
2831 DartType _canonicalizeNumTypes(DartType t) { | 2871 DartType _canonicalizeNumTypes(DartType t) { |
2832 var numType = types.numType; | 2872 var numType = types.numType; |
2833 if (rules.isSubtypeOf(t, numType)) return numType; | 2873 if (rules.isSubtypeOf(t, numType)) return numType; |
2834 return t; | 2874 return t; |
2835 } | 2875 } |
2836 | 2876 |
2837 bool _canUsePrimitiveEquality(Expression left, Expression right) { | 2877 bool _canUsePrimitiveEquality(Expression left, Expression right) { |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2994 return new JS.MetaLet(vars, body, statelessResult: true); | 3034 return new JS.MetaLet(vars, body, statelessResult: true); |
2995 } | 3035 } |
2996 | 3036 |
2997 @override | 3037 @override |
2998 JS.Expression visitPrefixExpression(PrefixExpression node) { | 3038 JS.Expression visitPrefixExpression(PrefixExpression node) { |
2999 var op = node.operator; | 3039 var op = node.operator; |
3000 var expr = node.operand; | 3040 var expr = node.operand; |
3001 | 3041 |
3002 var dispatchType = getStaticType(expr); | 3042 var dispatchType = getStaticType(expr); |
3003 if (unaryOperationIsPrimitive(dispatchType)) { | 3043 if (unaryOperationIsPrimitive(dispatchType)) { |
3044 if (op.lexeme == '~') { | |
3045 if (_isNumberInJS(dispatchType)) { | |
3046 JS.Expression jsExpr = js.call('~#', notNull(expr)); | |
3047 return _coerceBitOperationResultToUnsigned(node, jsExpr); | |
3048 } | |
3049 return _emitSend(expr, op.lexeme[0], []); | |
3050 } | |
3004 if (!isNullable(expr)) { | 3051 if (!isNullable(expr)) { |
3005 return js.call('$op#', _visit(expr)); | 3052 return js.call('$op#', _visit(expr)); |
3006 } else if (op.lexeme == '++' || op.lexeme == '--') { | 3053 } |
3054 if (op.lexeme == '++' || op.lexeme == '--') { | |
3007 // We need a null check, so the increment must be expanded out. | 3055 // We need a null check, so the increment must be expanded out. |
3008 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3056 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
3009 var x = _bindLeftHandSide(vars, expr, context: expr); | 3057 var x = _bindLeftHandSide(vars, expr, context: expr); |
3010 | 3058 |
3011 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; | 3059 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; |
3012 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) | 3060 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) |
3013 ..staticElement = node.staticElement | 3061 ..staticElement = node.staticElement |
3014 ..staticType = getStaticType(expr); | 3062 ..staticType = getStaticType(expr); |
3015 | 3063 |
3016 return new JS.MetaLet(vars, [_emitSet(x, increment)]); | 3064 return new JS.MetaLet(vars, [_emitSet(x, increment)]); |
3017 } else { | |
3018 return js.call('$op#', notNull(expr)); | |
3019 } | 3065 } |
3066 return js.call('$op#', notNull(expr)); | |
3020 } | 3067 } |
3021 | 3068 |
3022 if (op.lexeme == '++' || op.lexeme == '--') { | 3069 if (op.lexeme == '++' || op.lexeme == '--') { |
3023 // Increment or decrement requires expansion. | 3070 // Increment or decrement requires expansion. |
3024 // Desugar `++x` as `x = x + 1`, ensuring that if `x` has subexpressions | 3071 // Desugar `++x` as `x = x + 1`, ensuring that if `x` has subexpressions |
3025 // (for example, x is IndexExpression) we evaluate those once. | 3072 // (for example, x is IndexExpression) we evaluate those once. |
3026 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; | 3073 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; |
3027 return _emitOpAssign(expr, one, op.lexeme[0], node.staticElement, | 3074 return _emitOpAssign(expr, one, op.lexeme[0], node.staticElement, |
3028 context: expr); | 3075 context: expr); |
3029 } | 3076 } |
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3890 } | 3937 } |
3891 | 3938 |
3892 bool isLibraryPrefix(Expression node) => | 3939 bool isLibraryPrefix(Expression node) => |
3893 node is SimpleIdentifier && node.staticElement is PrefixElement; | 3940 node is SimpleIdentifier && node.staticElement is PrefixElement; |
3894 | 3941 |
3895 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 3942 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
3896 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 3943 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
3897 | 3944 |
3898 bool _isDartRuntime(LibraryElement l) => | 3945 bool _isDartRuntime(LibraryElement l) => |
3899 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 3946 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |