@@ -2810,21 +2810,61 @@ class CodeGenerator extends GeneralizingAstVisitor
2810
2810
// these values are assumed to be non-null (determined by the checker)
2811
2811
// TODO(jmesserly): it would be nice to just inline the method from core,
2812
2812
// instead of special cases here.
2813
- if (op.type == TokenType .TILDE_SLASH ) {
2814
- // `a ~/ b` is equivalent to `(a / b).truncate()`
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 #' ;
2813
+ JS .Expression binary (String code) {
2814
+ return js.call (code, [notNull (left), notNull (right)]);
2815
+ }
2816
+
2817
+ JS .Expression bitwise (String code) {
2818
+ return _coerceBitOperationResultToUnsigned (node, binary (code));
2819
+ }
2820
+
2821
+ switch (op.type) {
2822
+ case TokenType .TILDE_SLASH :
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 #' );
2821
2853
}
2822
- return js.call (code, [notNull (left), notNull (right)]);
2823
2854
}
2824
2855
2825
2856
return _emitSend (left, op.lexeme, [right]);
2826
2857
}
2827
2858
2859
+ /// Bit operations are coerced to values on [0, 2^32). The coercion changes
2860
+ /// the interpretation of the 32-bit value from signed to unsigned. Most
2861
+ /// JavaScript operations interpret their operands as signed and generate
2862
+ /// signed results.
2863
+ JS .Expression _coerceBitOperationResultToUnsigned (
2864
+ Expression node, JS .Expression operation) {
2865
+ return js.call ('# >>> 0' , operation);
2866
+ }
2867
+
2828
2868
/// If the type [t] is [int] or [double] , or a type parameter
2829
2869
/// bounded by [int] , [double] or [num] returns [num] .
2830
2870
/// Otherwise returns [t] .
@@ -3001,9 +3041,17 @@ class CodeGenerator extends GeneralizingAstVisitor
3001
3041
3002
3042
var dispatchType = getStaticType (expr);
3003
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
3051
if (! isNullable (expr)) {
3005
3052
return js.call ('$op #' , _visit (expr));
3006
- } else if (op.lexeme == '++' || op.lexeme == '--' ) {
3053
+ }
3054
+ if (op.lexeme == '++' || op.lexeme == '--' ) {
3007
3055
// We need a null check, so the increment must be expanded out.
3008
3056
var vars = < JS .MetaLetVariable , JS .Expression > {};
3009
3057
var x = _bindLeftHandSide (vars, expr, context: expr);
@@ -3014,9 +3062,8 @@ class CodeGenerator extends GeneralizingAstVisitor
3014
3062
..staticType = getStaticType (expr);
3015
3063
3016
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
3069
if (op.lexeme == '++' || op.lexeme == '--' ) {
0 commit comments