فهرست منبع

more operator precedence fixes

Vladislav Folts 12 سال پیش
والد
کامیت
5d6d18d2cc
4فایلهای تغییر یافته به همراه72 افزوده شده و 44 حذف شده
  1. 18 28
      src/context.js
  2. 37 15
      src/operator.js
  3. 8 1
      test/expected/parentheses.js
  4. 9 0
      test/input/parentheses.ob

+ 18 - 28
src/context.js

@@ -574,17 +574,6 @@ exports.ArrayDimensions = ChainedContext.extend({
 	}
 });
 
-function makeUnaryOperator(op, code){
-	return function(e){
-		var type = e.type();
-        var value = e.constValue();
-        if (value !== undefined)
-            value = op(value, type) ;
-        var expCode = ((typeof code == "function") ? code(type) : code) + e.deref().code();
-		return new Code.Expression(expCode, type, undefined, value);
-	};
-}
-
 exports.AddOperator = ChainedContext.extend({
 	init: function AddOperatorContext(context){
 		ChainedContext.prototype.init.bind(this)(context);
@@ -693,8 +682,7 @@ exports.Factor = ChainedContext.extend({
 			parent.handleConst(basicTypes.bool, false, "false");
 		else if (s == "~"){
 			parent.setType(basicTypes.bool);
-			parent.handleOperator(makeUnaryOperator(
-				  function(x){return !x;}, "!"));
+			parent.handleOperator(op.not);
 		}
 	},
 	handleFactor: function(e){this.parent().handleFactor(e);}
@@ -779,24 +767,26 @@ exports.SimpleExpression = ChainedContext.extend({
 		this.__exp = undefined;
 	},
 	handleTerm: function(e){
-		this.setType(e.type());
-		if (this.__unaryOperator){
-			this.__exp = this.__unaryOperator(e);
+        var type = e.type();
+		this.setType(type);
+
+        var o;
+        switch(this.__unaryOperator){
+            case "-":
+                o = (type == basicTypes.set) ? op.setComplement : op.negate;
+                break;
+            case "+":
+                o = op.unaryPlus;
+                break;
+            }
+        if (o){
+			this.__exp = o(e);
 			this.__unaryOperator = undefined;
-		}
+        }
 		else
 			this.__exp = this.__exp ? this.__binaryOperator(this.__exp, e) : e;
 	},
-	handleLiteral: function(s){
-		if (s == "-")
-			this.__unaryOperator = makeUnaryOperator(
-				function(x, type){return type == basicTypes.set ? ~x : -x;},
-				function(type){return type == basicTypes.set ? "~" : "-";}
-				);
-		else if (s == "+")
-			this.__unaryOperator = makeUnaryOperator(
-				function(x){return x;}, "");
-	},
+	handleLiteral: function(s){this.__unaryOperator = s;},
 	type: function(){return this.__type;},
 	setType: function(type){
 		if (type === undefined || this.__type === undefined)
@@ -861,7 +851,7 @@ exports.Expression = ChainedContext.extend({
         if (this.__relation == "=")
             code = op.equal(leftExpression, rightExpression).code();
         else if (this.__relation == "#")
-            code = leftCode + " != " + rightCode;
+            code = op.notEqual(leftExpression, rightExpression).code();
         else if (this.__relation == "<=")
             code = this.rtl().setInclL(leftCode, rightCode);
         else if (this.__relation == ">=")

+ 37 - 15
src/operator.js

@@ -1,6 +1,9 @@
+"use strict";
+
 var Code = require("code.js");
 
 var precedence = {
+    unary: 4,
     mulDivMod: 5,
     addSub: 6,
     shift: 7,
@@ -14,7 +17,7 @@ var precedence = {
     assignment: 17
 };
 
-function make(op, code, precedence, resultPrecedence){
+function makeBinary(op, code, precedence, resultPrecedence){
     return function(left, right){
         var leftValue = left.constValue();
         var rightValue = right.constValue();
@@ -22,7 +25,9 @@ function make(op, code, precedence, resultPrecedence){
             ? op(leftValue, rightValue) : undefined;
 
         var leftCode = Code.adjustPrecedence(left.deref(), precedence);
-        var rightCode = Code.adjustPrecedence(right.deref(), precedence);
+
+        // right code needs parentheses even if it has the same percedence 
+        var rightCode = Code.adjustPrecedence(right.deref(), precedence - 1);
         var expCode = (typeof code == "function")
                     ? code(leftCode, rightCode)
                     : leftCode + code + rightCode;
@@ -30,22 +35,39 @@ function make(op, code, precedence, resultPrecedence){
     };
 }
 
+function makeUnary(op, code){
+    return function(e){
+        var type = e.type();
+        var value = e.constValue();
+        if (value !== undefined)
+            value = op(value, type) ;
+        var expCode = code + Code.adjustPrecedence(e.deref(), precedence.unary);
+        return new Code.Expression(expCode, type, undefined, value);
+    };
+}
+
 var operators = {
-    add: make(function(x, y){return x + y;}, " + ", precedence.addSub),
-    sub: make(function(x, y){return x - y;}, " - ", precedence.addSub),
-    mul: make(function(x, y){return x * y;}, " * ", precedence.mulDivMod),
-    div: make(function(x, y){return (x / y) >> 0;},
+    add: makeBinary(function(x, y){return x + y;}, " + ", precedence.addSub),
+    sub: makeBinary(function(x, y){return x - y;}, " - ", precedence.addSub),
+    mul: makeBinary(function(x, y){return x * y;}, " * ", precedence.mulDivMod),
+    div: makeBinary(function(x, y){return (x / y) >> 0;},
               function(x, y){return x + " / " + y + " >> 0";},
               precedence.mulDivMod, precedence.shift),
-    divFloat: make(function(x, y){return x / y;}, " / ", precedence.mulDivMod),
-    mod: make(function(x, y){return x % y;}, " % ", precedence.mulDivMod),
-    setUnion: make(function(x, y){return x | y;}, " | ", precedence.bitOr),
-    setDiff: make(function(x, y){return x & ~y;}, " & ~", precedence.bitAnd),
-    setIntersection: make(function(x, y){return x & y;}, " & ", precedence.bitAnd),
-    setSymmetricDiff: make(function(x, y){return x ^ y;}, " ^ ", precedence.bitXor),
-    or: make(function(x, y){return x || y;}, " || ", precedence.or),
-    and: make(function(x, y){return x && y;}, " && ", precedence.and),
-    equal: make(function(x, y){return x && y;}, " == ", precedence.equal)
+    divFloat:   makeBinary(function(x, y){return x / y;}, " / ", precedence.mulDivMod),
+    mod:        makeBinary(function(x, y){return x % y;}, " % ", precedence.mulDivMod),
+    setUnion:   makeBinary(function(x, y){return x | y;}, " | ", precedence.bitOr),
+    setDiff:    makeBinary(function(x, y){return x & ~y;}, " & ~", precedence.bitAnd),
+    setIntersection: makeBinary(function(x, y){return x & y;}, " & ", precedence.bitAnd),
+    setSymmetricDiff: makeBinary(function(x, y){return x ^ y;}, " ^ ", precedence.bitXor),
+    or:         makeBinary(function(x, y){return x || y;}, " || ", precedence.or),
+    and:        makeBinary(function(x, y){return x && y;}, " && ", precedence.and),
+    equal:      makeBinary(function(x, y){return x == y;}, " == ", precedence.equal),
+    notEqual:   makeBinary(function(x, y){return x != y;}, " != ", precedence.equal),
+
+    not:        makeUnary(function(x){return !x;}, "!"),
+    negate:     makeUnary(function(x){return -x;}, "-"),
+    unaryPlus:  makeUnary(function(x){return x;}, ""),
+    setComplement: makeUnary(function(x){return ~x;}, "~")
 };
 
 for(var p in operators)

+ 8 - 1
test/expected/parentheses.js

@@ -35,7 +35,7 @@ ch = i;
 i = (ch + i) / 2;
 RTL$.assert(i == 65);
 a[(i - 64) * 3] = i;
-i = i + i - 1;
+i = i + (i - 1);
 i = i - i + 1;
 i = i * i + 1;
 i = i * (i + 1);
@@ -51,10 +51,17 @@ b = b && b || b;
 b = b || b && b;
 b = b == b || b;
 b = b == (b || b);
+b = b != b || b;
+b = b != (b || b);
 s = (s | s) & ~s;
 s = s | s & ~s;
 s = s & s ^ s;
 s = s & (s ^ s);
 s = s & s | s;
 s = s & (s | s);
+i = -(i * 2) + i;
+i = -(i * (2 + i));
+i = -(i % (2 * i));
+i = -i + 2 * i;
+s = ~s & ~~s;
 }();

+ 9 - 0
test/input/parentheses.ob

@@ -33,6 +33,9 @@ BEGIN
     b := (b = b) OR b;
     b := b = (b OR b);
 
+    b := (b # b) OR b;
+    b := b # (b OR b);
+
     s := (s + s) - s;
     s := s + (s - s);
 
@@ -41,4 +44,10 @@ BEGIN
 
     s := s * s + s;
     s := s * (s + s);
+
+    i := -(i * 2) + i;
+    i := -i * (2 + i);
+    i := -i MOD (2 * i);
+    i := -i + (2 * i);
+    s := -s - (-s);
 END m.