Sfoglia il codice sorgente

fix relaations and set operations

Vladislav Folts 12 anni fa
parent
commit
5ff81f99ed

+ 5 - 2
src/code.js

@@ -1,3 +1,5 @@
+"use strict";
+
 var Class = require("rtl.js").Class;
 var Type = require("type.js");
 
@@ -70,12 +72,13 @@ var Expression = Class.extend({
     }
 });
 
-exports.adjustPrecedence = function(e, precedence){
+function adjustPrecedence(e, precedence){
     var code = e.code();
     if (e.maxPrecedence() > precedence)
         code = "(" + code + ")";
     return code;
-};
+}
 
 exports.nullGenerator = new NullCodeGenerator();
 exports.Expression = Expression;
+exports.adjustPrecedence = adjustPrecedence;

+ 45 - 22
src/context.js

@@ -1,3 +1,5 @@
+"use strict";
+
 var Cast = require("cast.js");
 var Code = require("code.js");
 var Errors = require("errors.js");
@@ -848,16 +850,35 @@ exports.Expression = ChainedContext.extend({
             checkImplicitCast(rightExpression.type(), leftExpression.type());
         }
 
-        if (this.__relation == "=")
-            code = op.equal(leftExpression, rightExpression).code();
-        else if (this.__relation == "#")
-            code = op.notEqual(leftExpression, rightExpression).code();
-        else if (this.__relation == "<=")
-            code = this.rtl().setInclL(leftCode, rightCode);
-        else if (this.__relation == ">=")
-            code = this.rtl().setInclR(leftCode, rightCode);
+        var o;
+        switch (this.__relation){
+            case "=":
+                o = op.equal;
+                break;
+            case "#":
+                o = op.notEqual;
+                break;
+            case "<":
+                o = op.less;
+                break;
+            case ">":
+                o = op.greater;
+                break;
+            case "<=":
+                o = (leftType == basicTypes.set) ? op.setInclL : op.eqLess;
+                break;
+            case ">=":
+                o = (leftType == basicTypes.set) ? op.setInclR : op.eqGreater;
+                break;
+            }
+        var value;
+        if (o){
+            var oResult = o(leftExpression, rightExpression, this);
+            code = oResult.code();
+            value = oResult.constValue();
+        }
 
-        this.__expression = new Code.Expression(code, basicTypes.bool);
+        this.__expression = new Code.Expression(code, basicTypes.bool, undefined, value);
     },
     handleLiteral: function(relation){
         this.__relation = relation;
@@ -875,30 +896,32 @@ function handleIfExpression(e){
         throw new Errors.Error("'BOOLEAN' expression expected, got '" + type.name() + "'");
 }
 
-function endIfParse(){
-    var gen = this.codeGenerator();
-    gen.write(")");
-    gen.openScope();
-}
+var IfContextBase = ChainedContext.extend({
+    init: function(context){
+        ChainedContext.prototype.init.call(this, context);
+    },
+    endParse: function(){
+        var gen = this.codeGenerator();
+        gen.write(")");
+        gen.openScope();
+    },
+    handleExpression: handleIfExpression
+});
 
-exports.If = ChainedContext.extend({
+exports.If = IfContextBase.extend({
     init: function IfContext(context){
         ChainedContext.prototype.init.bind(this)(context);
         this.codeGenerator().write("if (");
-    },
-    handleExpression: handleIfExpression,
-    endParse: endIfParse
+    }
 });
 
-exports.ElseIf = ChainedContext.extend({
+exports.ElseIf = IfContextBase.extend({
     init: function ElseIfContext(context){
         ChainedContext.prototype.init.bind(this)(context);
         var gen = this.codeGenerator();
         gen.closeScope();
         gen.write("else if (");
-    },
-    handleExpression: handleIfExpression,
-    endParse: endIfParse
+    }
 });
 
 exports.Else = ChainedContext.extend({

+ 21 - 6
src/operator.js

@@ -7,6 +7,7 @@ var precedence = {
     mulDivMod: 5,
     addSub: 6,
     shift: 7,
+    relational: 8,
     equal: 9,
     bitAnd: 10,
     bitXor: 11,
@@ -18,7 +19,7 @@ var precedence = {
 };
 
 function makeBinary(op, code, precedence, resultPrecedence){
-    return function(left, right){
+    return function(left, right, context){
         var leftValue = left.constValue();
         var rightValue = right.constValue();
         var value = (leftValue !== undefined && rightValue !== undefined)
@@ -26,10 +27,10 @@ function makeBinary(op, code, precedence, resultPrecedence){
 
         var leftCode = Code.adjustPrecedence(left.deref(), precedence);
 
-        // right code needs parentheses even if it has the same percedence 
+        // 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)
+                    ? code(leftCode, rightCode, context)
                     : leftCode + code + rightCode;
         return new Code.Expression(expCode, left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
     };
@@ -50,19 +51,33 @@ var operators = {
     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),
+    div: makeBinary(
+            function(x, y){return (x / y) >> 0;},
+            function(x, y){return x + " / " + y + " >> 0";},
+            precedence.mulDivMod,
+            precedence.shift),
     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),
+    setInclL:   makeBinary(
+            function(x, y){return (x & y) == x;},
+            function(x, y, context){return context.rtl().setInclL(x, y);}),
+    setInclR:   makeBinary(
+            function(x, y){return (x & y) == y;},
+            function(x, y, context){return context.rtl().setInclR(x, y);}),
+
     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),
+    less:       makeBinary(function(x, y){return x < y;}, " < ", precedence.relational),
+    greater:    makeBinary(function(x, y){return x > y;}, " > ", precedence.relational),
+    eqLess:     makeBinary(function(x, y){return x <= y;}, " <= ", precedence.relational),
+    eqGreater:  makeBinary(function(x, y){return x >= y;}, " >= ", precedence.relational),
 
     not:        makeUnary(function(x){return !x;}, "!"),
     negate:     makeUnary(function(x){return -x;}, "-"),

+ 5 - 2
src/procedure.js

@@ -326,10 +326,13 @@ exports.predefined = [
             checkArgument: function(pos, e){
                 var type = e.type();
                 if (type == Type.basic.char || type == Type.basic.set)
-                    this.__callExpression = new Code.Expression(e.code(), Type.basic.int);
+                    this.__callExpression = new Code.Expression(e.code(), Type.basic.int, undefined, e.constValue());
                 else if (type == Type.basic.bool){
                     var code = Code.adjustPrecedence(e, precedence.conditional) + " ? 1 : 0";
-                    this.__callExpression = new Code.Expression(code, Type.basic.int, undefined, undefined, precedence.conditional);
+                    var value = e.constValue();
+                    if (value !== undefined)
+                        value = value ? 1 : 0;
+                    this.__callExpression = new Code.Expression(code, Type.basic.int, undefined, value, precedence.conditional);
                 }
                 else if (type instanceof Type.String){
                     var ch = type.asChar();

+ 5 - 3
src/rtl.js

@@ -1,3 +1,5 @@
+"use strict";
+
 function Class(){}
 Class.extend = function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
@@ -67,8 +69,8 @@ var impl = {
         return {set: function(v){ obj[prop] = v; },
                 get: function(){ return obj[prop]; }};
     },
-    setInclL: function(l, r){return l & r == l;},
-    setInclR: function(l, r){return l & r == r;},
+    setInclL: function(l, r){return (l & r) == l;},
+    setInclR: function(l, r){return (l & r) == r;},
     assignArrayFromString: function(a, s){
         var i;
         for(i = 0; i < s.length; ++i)
@@ -124,7 +126,7 @@ exports.RTL = Class.extend({
                 result += ",\n";
             else
                 firstEntry = false;
-            result += "\t" + name + ": " + this.__entries[name].toString();
+            result += "    " + name + ": " + this.__entries[name].toString();
         }
         if (!firstEntry)
             result += "\n};\n";

+ 3 - 3
test/expected/array.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	makeArray: function (/*dimensions, initializer*/){
+    makeArray: function (/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var i;
@@ -17,7 +17,7 @@ var RTL$ = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic
@@ -28,7 +28,7 @@ var RTL$ = {
         result.extend = extend;
         return result;
     },
-	copy: function (from, to){
+    copy: function (from, to){
         for(var prop in to){
             if (to.hasOwnProperty(prop)){
                 var v = from[prop];

+ 1 - 1
test/expected/assert.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 1 - 1
test/expected/blur.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	makeArray: function (/*dimensions, initializer*/){
+    makeArray: function (/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var i;

+ 2 - 2
test/expected/cast.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic
@@ -10,7 +10,7 @@ var RTL$ = {
         result.extend = extend;
         return result;
     },
-	typeGuard: function (from, to){
+    typeGuard: function (from, to){
         if (!(from instanceof to))
             throw new Error("typeguard assertion failed");
         return from;

+ 1 - 1
test/expected/chr.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 1 - 1
test/expected/is.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic

+ 2 - 2
test/expected/len.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	makeArray: function (/*dimensions, initializer*/){
+    makeArray: function (/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var i;
@@ -17,7 +17,7 @@ var RTL$ = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 1 - 1
test/expected/new.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic

+ 1 - 1
test/expected/nil.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic

+ 1 - 1
test/expected/odd.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 1 - 1
test/expected/ord.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 2 - 2
test/expected/parentheses.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	makeArray: function (/*dimensions, initializer*/){
+    makeArray: function (/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var i;
@@ -17,7 +17,7 @@ var RTL$ = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 1 - 1
test/expected/proc.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic

+ 2 - 2
test/expected/record.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic
@@ -10,7 +10,7 @@ var RTL$ = {
         result.extend = extend;
         return result;
     },
-	copy: function (from, to){
+    copy: function (from, to){
         for(var prop in to){
             if (to.hasOwnProperty(prop)){
                 var v = from[prop];

+ 13 - 0
test/expected/relations.js

@@ -0,0 +1,13 @@
+var m = function (){
+var i1 = 0;var i2 = 0;
+var r1 = 0;var r2 = 0;
+var b = false;
+b = i1 == i2;
+b = i1 != i2;
+b = i1 > i2;
+b = i1 < i2;
+b = i1 >= i2;
+b = i1 <= i2;
+if (i1 > i2){
+}
+}();

+ 19 - 3
test/expected/set.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	makeSet: function (/*...*/){
+    makeSet: function (/*...*/){
         var result = 0;
         
         function checkBit(b){
@@ -27,8 +27,8 @@ var RTL$ = {
         }
         return result;
     },
-	setInclL: function (l, r){return l & r == l;},
-	setInclR: function (l, r){return l & r == r;}
+    setInclL: function (l, r){return (l & r) == l;},
+    setInclR: function (l, r){return (l & r) == r;}
 };
 var m = function (){
 var ci = 3;
@@ -40,6 +40,14 @@ var cs5 = ~2;
 var s1 = 0;var s2 = 0;
 var i1 = 0;
 var b = false;
+
+function getSet1(){
+	return 2;
+}
+
+function getSet2(){
+	return 4;
+}
 s1 = 0;
 s1 = 61;
 s1 = 8;
@@ -50,6 +58,14 @@ s2 = RTL$.makeSet(i1) | 4;
 b = 1 << i1 & s1;
 b = RTL$.setInclL(s1, s2);
 b = RTL$.setInclR(s1, s2);
+b = RTL$.setInclL(getSet1(), getSet2());
+b = RTL$.setInclR(getSet1(), getSet2());
+b = RTL$.setInclL(cs1, cs2);
+b = RTL$.setInclR(cs1, cs2);
+b = RTL$.setInclL(cs1 | cs2, cs1 | cs2);
+b = RTL$.setInclR(cs1 | cs2, cs2 | cs1);
+b = RTL$.setInclL(2 | 4, 2 | 4);
+b = RTL$.setInclR(2 | 4, 4 | 2);
 b = s1 == s2;
 b = s1 != s2;
 s1 = s1 | s2;

+ 4 - 4
test/expected/string.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	makeArray: function (/*dimensions, initializer*/){
+    makeArray: function (/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var i;
@@ -17,20 +17,20 @@ var RTL$ = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
-	assignArrayFromString: function (a, s){
+    assignArrayFromString: function (a, s){
         var i;
         for(i = 0; i < s.length; ++i)
             a[i] = s.charCodeAt(i);
         for(i = s.length; i < a.length; ++i)
             a[i] = 0;
     },
-	strToArray: function (s){
+    strToArray: function (s){
         var result = new Array(s.length);
         for(i = 0; i < s.length; ++i)
             result[i] = s.charCodeAt(i);
         return result;
     },
-	assert: function (condition, code){
+    assert: function (condition, code){
         if (!condition)
             throw new Error("assertion failed"
                           + ((code !== undefined) ? " with code " + code : ""));

+ 3 - 3
test/expected/var_parameter.js

@@ -1,5 +1,5 @@
 var RTL$ = {
-	extend: function extend(methods){
+    extend: function extend(methods){
         methods.__proto__ = this.prototype; // make instanceof work
 
         // to see constructor name in diagnostic
@@ -10,7 +10,7 @@ var RTL$ = {
         result.extend = extend;
         return result;
     },
-	makeArray: function (/*dimensions, initializer*/){
+    makeArray: function (/*dimensions, initializer*/){
         var forward = Array.prototype.slice.call(arguments);
         var result = new Array(forward.shift());
         var i;
@@ -28,7 +28,7 @@ var RTL$ = {
                 result[i] = this.makeArray.apply(this, forward);
         return result;
     },
-	makeRef: function (obj, prop){
+    makeRef: function (obj, prop){
         return {set: function(v){ obj[prop] = v; },
                 get: function(){ return obj[prop]; }};
     }

+ 16 - 0
test/input/relations.ob

@@ -0,0 +1,16 @@
+MODULE m;
+
+VAR 
+	i1, i2: INTEGER;
+	r1, r2: REAL;
+	b: BOOLEAN;
+
+BEGIN
+    b := i1 = i2;
+    b := i1 # i2;
+	b := i1 > i2;
+    b := i1 < i2;
+    b := i1 >= i2;
+    b := i1 <= i2;
+    IF i1 > i2 THEN END;
+END m.

+ 6 - 0
test/input/run/relations.ob

@@ -0,0 +1,6 @@
+MODULE test;
+VAR x: INTEGER;
+BEGIN
+    x := 10;
+    ASSERT(x >= 0)
+END test.

+ 7 - 0
test/input/run/set.ob

@@ -0,0 +1,7 @@
+MODULE test;
+VAR s1, s2: SET;
+BEGIN
+    s1 := {0..5};
+    s2 := {0..8};
+    ASSERT(s1 <= s2)
+END test.

+ 16 - 0
test/input/set.ob

@@ -13,6 +13,14 @@ VAR
 	i1: INTEGER;
 	b: BOOLEAN;
 
+PROCEDURE getSet1(): SET;
+	RETURN {1}
+END getSet1;
+
+PROCEDURE getSet2(): SET;
+	RETURN {2}
+END getSet2;
+
 BEGIN
 	s1 := {};
 	s1 := {0, 2..5};
@@ -26,6 +34,14 @@ BEGIN
 	b := i1 IN s1;
 	b := s1 <= s2;
 	b := s1 >= s2;
+	b := getSet1() <= getSet2();
+	b := getSet1() >= getSet2();
+    b := cs1 <= cs2;
+    b := cs1 >= cs2;
+    b := cs1 + cs2 <= cs1 + cs2;
+    b := cs1 + cs2 >= cs2 + cs1;
+    b := {1} + {2} <= {1} + {2};
+    b := {1} + {2} >= {2} + {1};
 	b := s1 = s2;
 	b := s1 # s2;
 

+ 6 - 0
test/test_unit.js

@@ -180,7 +180,10 @@ identifier: function(){
 	test.parse("CONST i = 1 + 2;");
 	test.parse("CONST i = ci + 2;");
 	test.parse("CONST i = ci * 2;");
+	test.parse("CONST i = ORD({0..5});");
+	test.parse("CONST i = ORD({0..5} <= {0..8});");
 	test.parse("CONST b = TRUE;");
+	test.parse("CONST b = {0..5} <= {0..8};");
 	test.parse("CONST c = \"a\";");
 	test.parse("CONST s = \"abc\";");
 	test.parse("CONST s0 = \"\";");
@@ -219,8 +222,10 @@ identifier: function(){
 				   , "'INTEGER' constant expression expected, got 'BOOLEAN'");
 	test.parse("T = ARRAY 1 + 2 OF INTEGER");
 	test.parse("T = ARRAY c1 OF INTEGER");
+	test.parse("T = ARRAY ORD({0..5} <= {0..8}) OF INTEGER");
 	test.expectError("T = ARRAY v1 OF INTEGER", "constant expression expected as ARRAY size");
 	test.expectError("T = ARRAY c1 - 10 OF INTEGER", "array size must be greater than 0, got -5");
+	test.expectError("T = ARRAY ORD({0..5} >= {0..8}) OF INTEGER", "array size must be greater than 0, got 0");
 },
 "multi-dimensional array declaration": function(){
 	var test = setup(Grammar.typeDeclaration);
@@ -581,6 +586,7 @@ identifier: function(){
 	test.parse("b := set1 <= set2");
 	test.parse("b := i1 IN set2");
 	test.parse("b := i1 < i2");
+	test.parse("IF i1 > i2 THEN END");
 	test.parse("b := c1 > c2");
 	test.parse("b := ca1 <= ca2");
 	test.parse("b := r1 >= r2");