Browse Source

all predefined functions are implemented.

Vladislav Folts 12 years ago
parent
commit
12c2ec0dc9

+ 35 - 10
src/operator.js

@@ -50,10 +50,23 @@ function makeUnary(op, code){
     };
 }
 
+var mul = makeBinary(function(x, y){return x * y;}, " * ", precedence.mulDivMod);
+var divFloat = makeBinary(function(x, y){return x / y;}, " / ", precedence.mulDivMod);
+
+function pow2(e){
+    return new Code.Expression("Math.pow(2, " + e.deref().code() + ")",
+                               Type.basic.real);
+}
+
+function log2(e){
+    return new Code.Expression("(Math.log(" + e.deref().code() + ") / Math.LN2) | 0",
+                               Type.basic.int, undefined, undefined, precedence.bitOr);
+}
+
 function assign(left, right, context){
-    var d_info = left.designator().info();
-    if (!(d_info instanceof Type.Variable) || d_info.isReadOnly())
-        throw new Errors.Error("cannot assign to " + d_info.idType());
+    var info = left.designator().info();
+    if (!(info instanceof Type.Variable) || info.isReadOnly())
+        throw new Errors.Error("cannot assign to " + info.idType());
 
     var leftCode = left.code();
     var leftType = left.type();
@@ -99,22 +112,29 @@ function assign(left, right, context){
 
     var castCode = castOperation(context, right.deref()).code();
     rightCode = castCode ? castCode : rightCode;
-    return leftCode
-         + (left.designator().info().isVar()
-            ? ".set(" + rightCode + ")"
-            : " = " + rightCode);
+    return leftCode + (info.isVar() ? ".set(" + rightCode + ")"
+                                    : " = " + rightCode);
+}
+
+function makeInplace(code, altOp){
+    return function(left, right){
+        var info = left.designator().info();
+        if (info.isVar())
+            return assign(left, altOp(left, right));
+        return left.code() + code + right.deref().code();
+    };
 }
 
 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),
+    mul: mul,
     div: makeBinary(
             function(x, y){return (x / y) | 0;},
             function(x, y){return x + " / " + y + " | 0";},
             precedence.mulDivMod,
             precedence.bitOr),
-    divFloat:   makeBinary(function(x, y){return x / y;}, " / ", precedence.mulDivMod),
+    divFloat:   divFloat,
     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),
@@ -146,7 +166,12 @@ var operators = {
     asr:        makeBinary(function(x, y){return x >> y;}, " >> ", precedence.shift),
     ror:        makeBinary(function(x, y){return x >>> y;}, " >>> ", precedence.shift),
 
-    assign:     assign
+    assign:     assign,
+    mulInplace: makeInplace(" *= ", mul),
+    divInplace: makeInplace(" /= ", divFloat),
+    
+    pow2:       pow2,
+    log2:       log2
 };
 
 for(var p in operators)

+ 39 - 5
src/procedure.js

@@ -449,7 +449,7 @@ exports.predefined = [
             },
             callExpression: function(){
                 var e = this.args()[0];
-                return new Code.Expression(e.code(), Type.basic.real, undefined, e.constValue());
+                return new Code.Expression(e.code(), Type.basic.real, undefined, e.constValue(), e.maxPrecedence());
             }
         });
         var args = [new Arg(Type.basic.int, false)];
@@ -539,10 +539,6 @@ exports.predefined = [
             init: function CopyProcCallGenerator(context, id, type){
                 ExpCallGenerator.prototype.init.call(this, context, id, type);
             },
-            checkArgument: function(pos, e){
-                //this.__callExpression = new Code.Expression(e.code(), Type.basic.char);
-                return ExpCallGenerator.prototype.checkArgument.call(this, pos, e);
-            },
             callExpression: function(){
                 var args = this.args();
                 return new Code.Expression(op.assign(args[1], args[0], this.context()));
@@ -559,6 +555,44 @@ exports.predefined = [
             });
         var symbol = new Type.Symbol(name, type);
         return symbol;
+    }(),
+    function(){
+        var args = [new Arg(Type.basic.real, true),
+                    new Arg(Type.basic.int, false)];
+        function operator(x, y){
+            return op.mulInplace(x, op.pow2(y));
+        }
+        var name = "PACK";
+        var proc = new ProcType(
+            "predefined procedure " + name,
+            args,
+            undefined,
+            function(context, id, type){
+                return new TwoArgToOperatorProcCallGenerator(
+                    context, id, type, operator);
+                });
+        var symbol = new Type.Symbol(name, proc);
+        return symbol;
+    }(),
+    function(){
+        var args = [new Arg(Type.basic.real, true),
+                    new Arg(Type.basic.int, true)];
+        function operator(x, y){
+            return op.assign(y, op.log2(x)) +
+                   "; " +
+                   op.divInplace(x, op.pow2(y));
+        }
+        var name = "UNPACK";
+        var proc = new ProcType(
+            "predefined procedure " + name,
+            args,
+            undefined,
+            function(context, id, type){
+                return new TwoArgToOperatorProcCallGenerator(
+                    context, id, type, operator);
+                });
+        var symbol = new Type.Symbol(name, proc);
+        return symbol;
     }()
     ];
 

+ 1 - 0
test/expected/flt.js

@@ -1,4 +1,5 @@
 var m = function (){
 var r = 0;
 r = 123;
+r = 1.23 * (1 + 2);
 }();

+ 11 - 0
test/expected/pack_unpack.js

@@ -0,0 +1,11 @@
+var m = function (){
+var i = 0;
+var r = 0;
+
+function p(r/*VAR REAL*/, i/*VAR INTEGER*/){
+	r.set(r.get() * Math.pow(2, i.get()));
+	i.set((Math.log(r.get()) / Math.LN2) | 0); r.set(r.get() / Math.pow(2, i.get()));
+}
+r *= Math.pow(2, i);
+i = (Math.log(r) / Math.LN2) | 0; r /= Math.pow(2, i);
+}();

+ 1 - 0
test/input/flt.ob

@@ -4,4 +4,5 @@ VAR r: REAL;
 
 BEGIN
     r := FLT(123);
+    r := 1.23 * FLT(1 + 2);
 END m.

+ 14 - 0
test/input/pack_unpack.ob

@@ -0,0 +1,14 @@
+MODULE m;
+
+VAR i: INTEGER; r: REAL;
+
+PROCEDURE p(VAR r: REAL; VAR i: INTEGER);
+BEGIN
+    PACK(r, i);
+    UNPACK(r, i);
+END p;
+
+BEGIN
+    PACK(r, i);
+    UNPACK(r, i);
+END m.

+ 15 - 0
test/input/run/pack_unpack.ob

@@ -0,0 +1,15 @@
+MODULE m;
+
+VAR i: INTEGER; r: REAL;
+
+BEGIN
+    r := 1.23;
+    i := 7;
+    PACK(r, i);
+    ASSERT(r = 1.23 * FLT(LSL(1, i)));
+
+    i := 0;
+    UNPACK(r, i);
+    ASSERT(r = 1.23);
+    ASSERT(i = 7);
+END m.

+ 14 - 0
test/test_unit.js

@@ -508,6 +508,20 @@ identifier: function(){
          ["COPY(ac3, ac4)", "array size mismatch: 'ac4' has size 4 and cannot be copied to the array with size 3"]
          )
 ),
+"PACK": testWithContext(
+    context(Grammar.statement, "VAR r: REAL; i: INTEGER;"),
+    pass("PACK(r, i)",
+         "PACK(r, 3)"),
+    fail(["PACK(r, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"])
+),
+"UNPACK": testWithContext(
+    context(Grammar.statement, "VAR r: REAL; i: INTEGER;"),
+    pass("UNPACK(r, i)"),
+    fail(["UNPACK(r, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
+         ["UNPACK(r, 3)", "expression cannot be used as VAR parameter"],
+         ["UNPACK(123.456, i)", "expression cannot be used as VAR parameter"]
+         )
+),
 "assignment statement": function(){
     var test = setupWithContext(
           Grammar.statement