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

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 1924413002: Fix modulo and bitwise operators. (Closed) Base URL: https://github.com/dart-lang/dev_compiler@master
Patch Set: Created 4 years, 7 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 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
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
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
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';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698