Vladislav Folts пре 12 година
родитељ
комит
bf13043b14
6 измењених фајлова са 215 додато и 170 уклоњено
  1. 4 69
      src/context.js
  2. 61 1
      src/operator.js
  3. 80 99
      src/procedure.js
  4. 46 0
      test/expected/copy.js
  5. 13 0
      test/input/copy.ob
  6. 11 1
      test/test_unit.js

+ 4 - 69
src/context.js

@@ -1257,79 +1257,14 @@ exports.emitForBegin = function(context){context.handleBegin();};
 exports.Assignment = ChainedContext.extend({
 exports.Assignment = ChainedContext.extend({
     init: function AssignmentContext(context){
     init: function AssignmentContext(context){
         ChainedContext.prototype.init.bind(this)(context);
         ChainedContext.prototype.init.bind(this)(context);
-        this.__designator = undefined;
-        this.__leftCode = undefined;
-        this.__rightCode = undefined;
-        this.__resultCode = undefined;
-        this.__type = undefined;
-        this.__code = new Code.SimpleGenerator();
+        this.__left = undefined;
     },
     },
-    codeGenerator: function(){return this.__code;},
+    codeGenerator: function(){/*throw new Error("Test");*/ return Code.nullGenerator;},
     setDesignator: function(d){
     setDesignator: function(d){
-        this.__designator = d;
-    },
-    handleLiteral: function(){
-        var d = this.__designator;
-        var d_info = d.info();
-        if (!(d_info instanceof Type.Variable) || d_info.isReadOnly())
-            throw new Errors.Error("cannot assign to " + d_info.idType());
-        this.__leftCode = d.code();
-        this.__code = new Code.SimpleGenerator();
-        this.__type = d.type();
+        this.__left = new Code.Expression(d.code(), d.type(), d);
     },
     },
     handleExpression: function(e){
     handleExpression: function(e){
-        var type = e.type();
-        var isArray = this.__type instanceof Type.Array;
-        if (isArray
-            && this.__type.elementsType() == basicTypes.char
-            && type instanceof Type.String){
-            if (this.__type.length() === undefined)
-                throw new Errors.Error("string cannot be assigned to open " + this.__type.description());
-            if (type.length() > this.__type.length())
-                throw new Errors.Error(
-                    this.__type.length() + "-character ARRAY is too small for "
-                    + type.length() + "-character string");
-            this.__resultCode = this.rtl().assignArrayFromString(this.__leftCode, this.__code.result());
-            return;
-        }
-
-        var castOperation = Cast.implicit(type, this.__type);
-        if (!castOperation)
-            throw new Errors.Error("type mismatch: '" + this.__leftCode
-                                 + "' is '" + this.__type.description()
-                                 + "' and cannot be assigned to '" + type.description() + "' expression");
-
-        if (isArray && type instanceof Type.Array)
-            if (this.__type.length() === undefined)
-                throw new Errors.Error("'" + this.__leftCode
-                                     + "' is open '" + this.__type.description()
-                                     + "' and cannot be assigned");
-            else if (type.length() === undefined)
-                throw new Errors.Error("'" + this.__leftCode
-                                     + "' cannot be assigned to open '"
-                                     + this.__type.description() + "'");
-            else if (this.__type.length() != type.length())
-                throw new Errors.Error("array size mismatch: '" + this.__leftCode
-                                     + "' has size " + this.__type.length()
-                                     + " and cannot be assigned to the array with size " + type.length());
-        
-        if (isArray || type instanceof Type.Record){
-            this.__resultCode = this.rtl().copy(this.__code.result(), this.__leftCode);
-            return;
-        }
-
-        var castCode = castOperation(this, e.deref()).code();
-        this.__rightCode = castCode ? castCode : this.__code.result();
-    },
-    endParse: function(){
-        var code = this.__resultCode;
-        if (!code)
-            code = this.__leftCode
-                 + (this.__designator.info().isVar()
-                    ? ".set(" + this.__rightCode + ")"
-                    : " = " + this.__rightCode);
-
-        this.parent().codeGenerator().write(code);
+        this.parent().codeGenerator().write(op.assign(this.__left, e, this));
     }
     }
 });
 });
 
 

+ 61 - 1
src/operator.js

@@ -1,6 +1,9 @@
 "use strict";
 "use strict";
 
 
+var Cast = require("cast.js");
 var Code = require("code.js");
 var Code = require("code.js");
+var Errors = require("errors.js");
+var Type = require("type.js");
 
 
 var precedence = {
 var precedence = {
     unary: 4,
     unary: 4,
@@ -47,6 +50,61 @@ function makeUnary(op, code){
     };
     };
 }
 }
 
 
+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 leftCode = left.code();
+    var leftType = left.type();
+    var rightCode = right.code();
+    var rightType = right.type();
+
+    var isArray = leftType instanceof Type.Array;
+    if (isArray
+        && leftType.elementsType() == Type.basic.char
+        && rightType instanceof Type.String){
+        if (leftType.length() === undefined)
+            throw new Errors.Error("string cannot be assigned to open " + leftType.description());
+        if (rightType.length() > leftType.length())
+            throw new Errors.Error(
+                leftType.length() + "-character ARRAY is too small for "
+                + rightType.length() + "-character string");
+        return context.rtl().assignArrayFromString(leftCode, rightCode);
+    }
+
+    var castOperation = Cast.implicit(rightType, leftType);
+    if (!castOperation)
+        throw new Errors.Error("type mismatch: '" + leftCode
+                             + "' is '" + leftType.description()
+                             + "' and cannot be assigned to '" + rightType.description() + "' expression");
+
+    if (isArray && rightType instanceof Type.Array)
+        if (leftType.length() === undefined)
+            throw new Errors.Error("'" + leftCode
+                                 + "' is open '" + leftType.description()
+                                 + "' and cannot be assigned");
+        else if (rightType.length() === undefined)
+            throw new Errors.Error("'" + leftCode
+                                 + "' cannot be assigned to open '"
+                                 + rightType.description() + "'");
+        else if (leftType.length() != rightType.length())
+            throw new Errors.Error("array size mismatch: '" + leftCode
+                                 + "' has size " + leftType.length()
+                                 + " and cannot be copied to the array with size "
+                                 + rightType.length());
+    
+    if (isArray || rightType instanceof Type.Record)
+        return context.rtl().copy(rightCode, leftCode);
+
+    var castCode = castOperation(context, right.deref()).code();
+    rightCode = castCode ? castCode : rightCode;
+    return leftCode
+         + (left.designator().info().isVar()
+            ? ".set(" + rightCode + ")"
+            : " = " + rightCode);
+}
+
 var operators = {
 var operators = {
     add: makeBinary(function(x, y){return x + y;}, " + ", precedence.addSub),
     add: makeBinary(function(x, y){return x + y;}, " + ", precedence.addSub),
     sub: makeBinary(function(x, y){return x - y;}, " - ", precedence.addSub),
     sub: makeBinary(function(x, y){return x - y;}, " - ", precedence.addSub),
@@ -86,7 +144,9 @@ var operators = {
 
 
     lsl:        makeBinary(function(x, y){return x << y;}, " << ", precedence.shift),
     lsl:        makeBinary(function(x, y){return x << y;}, " << ", precedence.shift),
     asr:        makeBinary(function(x, y){return x >> y;}, " >> ", precedence.shift),
     asr:        makeBinary(function(x, y){return x >> y;}, " >> ", precedence.shift),
-    ror:        makeBinary(function(x, y){return x >>> y;}, " >>> ", precedence.shift)
+    ror:        makeBinary(function(x, y){return x >>> y;}, " >>> ", precedence.shift),
+
+    assign:     assign
 };
 };
 
 
 for(var p in operators)
 for(var p in operators)

+ 80 - 99
src/procedure.js

@@ -155,25 +155,29 @@ var ProcType = Type.Procedure.extend({
     }
     }
 });
 });
 
 
-var TwoArgToOperatorProcCallGenerator = ProcCallGenerator.extend({
-    init: function TwoArgToOperatorProcCallGenerator(context, id, type, operator){
+var ExpCallGenerator = ProcCallGenerator.extend({
+    init: function ExpCallGenerator(context, id, type){
         ProcCallGenerator.prototype.init.call(this, context, id, type);
         ProcCallGenerator.prototype.init.call(this, context, id, type);
-        this.__operator = operator;
-        this.__firstArgument = undefined;
-        this.__secondArgument = undefined;
-    },
-    prolog: function(id){return "";},
-    handleArgument: function(e){
-        if (!this.__firstArgument)
-            this.__firstArgument = e;
-        else
-            this.__secondArgument = e;
-        ProcCallGenerator.prototype.handleArgument.call(this, e);
+        this.__args = [];
     },
     },
+    prolog: function(){return "";},
+    epilog: function(){return "";},
     writeArgumentCode: function(){},
     writeArgumentCode: function(){},
-    epilog: function(type){return "";},
-    end: function(){
-        return this.__operator(this.__firstArgument, this.__secondArgument);
+    checkArgument: function(pos, e){
+        this.__args.push(e);
+        return ProcCallGenerator.prototype.checkArgument.call(this, pos, e);
+    },
+    args: function(){return this.__args;}
+});
+
+var TwoArgToOperatorProcCallGenerator = ExpCallGenerator.extend({
+    init: function TwoArgToOperatorProcCallGenerator(context, id, type, operator){
+        ExpCallGenerator.prototype.init.call(this, context, id, type);
+        this.__operator = operator;
+    },
+    callExpression: function(){
+        var args = this.args();
+        return new Code.Expression(this.__operator(args[0], args[1]));
     }
     }
 });
 });
 
 
@@ -187,10 +191,7 @@ function setBitImpl(name, op){
         var comment = "bit: " + (y.isTerm() ? value : Code.adjustPrecedence(y, precedence.shift));
         var comment = "bit: " + (y.isTerm() ? value : Code.adjustPrecedence(y, precedence.shift));
         value = 1 << value;
         value = 1 << value;
         var valueCode = value + "/*" + comment + "*/";
         var valueCode = value + "/*" + comment + "*/";
-        var code = op(Code.adjustPrecedence(x, precedence.assignment),
-                      valueCode);
-        return new Code.Expression(
-            code, undefined, undefined, undefined, precedence.assignment);
+        return op(Code.adjustPrecedence(x, precedence.assignment), valueCode);
     }
     }
     var proc = new ProcType(
     var proc = new ProcType(
         "predefined procedure " + name,
         "predefined procedure " + name,
@@ -207,44 +208,22 @@ function setBitImpl(name, op){
 function incImpl(name, unary, op){
 function incImpl(name, unary, op){
     var args = [new Arg(Type.basic.int, true), new Arg(Type.basic.int, false)];
     var args = [new Arg(Type.basic.int, true), new Arg(Type.basic.int, false)];
     function operator(x, y){
     function operator(x, y){
-        if (!y){
-            code = unary + x.code();
-            return new Code.Expression(
-                code, undefined, undefined, undefined, precedence.prefix);
-        }
-        else {
-            var value = y.constValue();
-            if (value === undefined)
-                throw new Errors.Error("constant expected as second argument of " + name);
-            var comment = y.isTerm() ? "" : "/*" + y.code() + "*/";
-            var valueCode = value + comment;
-            var code = op(x.code(), valueCode);
-            return new Code.Expression(
-                code, undefined, undefined, undefined, precedence.assignment);
-        }
+        if (!y)
+            return unary + x.code();
+
+        var value = y.constValue();
+        if (value === undefined)
+            throw new Errors.Error("constant expected as second argument of " + name);
+        var comment = y.isTerm() ? "" : "/*" + y.code() + "*/";
+        var valueCode = value + comment;
+        return op(x.code(), valueCode);
     }
     }
-    var CallGenerator = ProcCallGenerator.extend({
-        init: function IncProcCallGenerator(context, id, type, operator){
-            ProcCallGenerator.prototype.init.call(this, context, id, type);
-            this.__operator = operator;
-            this.__firstArgument = undefined;
-            this.__secondArgument = undefined;
+    var CallGenerator = TwoArgToOperatorProcCallGenerator.extend({
+        init: function IncDecProcCallGenerator(context, id, type, operator){
+            TwoArgToOperatorProcCallGenerator.prototype.init.call(this, context, id, type, operator);
         },
         },
-        prolog: function(id){return "";},
-        handleArgument: function(e){
-            if (!this.__firstArgument)
-                this.__firstArgument = e;
-            else
-                this.__secondArgument = e;
-            ProcCallGenerator.prototype.handleArgument.call(this, e);
-        },
-        writeArgumentCode: function(){},
         checkArgumentsCount: function(count){
         checkArgumentsCount: function(count){
             checkVariableArgumentsCount(1, 2, count);
             checkVariableArgumentsCount(1, 2, count);
-        },
-        epilog: function(type){return "";},
-        callExpression: function(){
-            return operator(this.__firstArgument, this.__secondArgument);
         }
         }
     });
     });
     var proc = new ProcType(
     var proc = new ProcType(
@@ -260,19 +239,13 @@ function incImpl(name, unary, op){
 }
 }
 
 
 function bitShiftImpl(name, op){
 function bitShiftImpl(name, op){
-    var CallGenerator = ProcCallGenerator.extend({
-        init: function SgiftProcCallGenerator(context, id, type){
-            ProcCallGenerator.prototype.init.call(this, context, id, type);
-            this.__args = [];
-        },
-        prolog: function(){return "";},
-        epilog: function(){return "";},
-        checkArgument: function(pos, e){
-            this.__args.push(e);
-            return ProcCallGenerator.prototype.checkArgument.call(this, pos, e);
+    var CallGenerator = ExpCallGenerator.extend({
+        init: function ShiftProcCallGenerator(context, id, type){
+            ExpCallGenerator.prototype.init.call(this, context, id, type);
         },
         },
         callExpression: function(){
         callExpression: function(){
-            return op(this.__args[0], this.__args[1]);
+            var args = this.args();
+            return op(args[0], args[1]);
         }
         }
     });
     });
     var args = [new Arg(Type.basic.int, false),
     var args = [new Arg(Type.basic.int, false),
@@ -290,19 +263,11 @@ function bitShiftImpl(name, op){
 }
 }
 
 
 function longShort(name){
 function longShort(name){
-    var CallGenerator = ProcCallGenerator.extend({
-        init: function FloorProcCallGenerator(context, id, type){
-            ProcCallGenerator.prototype.init.call(this, context, id, type);
-            this.__callExpression = undefined;
-        },
-        prolog: function(){return "";},
-        epilog: function(){return "";},
-        checkArgument: function(pos, e){
-            var result = ProcCallGenerator.prototype.checkArgument.call(this, pos, e);
-            this.__callExpression = e;
-            return result;
+    var CallGenerator = ExpCallGenerator.extend({
+        init: function LongShortCallGenerator(context, id, type){
+            ExpCallGenerator.prototype.init.call(this, context, id, type);
         },
         },
-        callExpression: function(){return this.__callExpression;}
+        callExpression: function(){return this.args()[0];}
     });
     });
     var args = [new Arg(Type.basic.real, false)];
     var args = [new Arg(Type.basic.real, false)];
     var proc = new ProcType(
     var proc = new ProcType(
@@ -478,19 +443,14 @@ exports.predefined = [
         return symbol;
         return symbol;
     }(),
     }(),
     function(){
     function(){
-        var CallGenerator = ProcCallGenerator.extend({
-            init: function FloorProcCallGenerator(context, id, type){
-                ProcCallGenerator.prototype.init.call(this, context, id, type);
-                this.__callExpression = undefined;
+        var CallGenerator = ExpCallGenerator.extend({
+            init: function FltProcCallGenerator(context, id, type){
+                ExpCallGenerator.prototype.init.call(this, context, id, type);
             },
             },
-            prolog: function(){return "";},
-            epilog: function(){return "";},
-            checkArgument: function(pos, e){
-                var result = ProcCallGenerator.prototype.checkArgument.call(this, pos, e);
-                this.__callExpression = new Code.Expression(e.code(), Type.basic.real, undefined, e.constValue());
-                return result;
-            },
-            callExpression: function(){return this.__callExpression;}
+            callExpression: function(){
+                var e = this.args()[0];
+                return new Code.Expression(e.code(), Type.basic.real, undefined, e.constValue());
+            }
         });
         });
         var args = [new Arg(Type.basic.int, false)];
         var args = [new Arg(Type.basic.int, false)];
         var proc = new ProcType(
         var proc = new ProcType(
@@ -555,18 +515,13 @@ exports.predefined = [
         return symbol;
         return symbol;
     }(),
     }(),
     function(){
     function(){
-        var CallGenerator = ProcCallGenerator.extend({
+        var CallGenerator = ExpCallGenerator.extend({
             init: function ChrProcCallGenerator(context, id, type){
             init: function ChrProcCallGenerator(context, id, type){
-                ProcCallGenerator.prototype.init.call(this, context, id, type);
-                this.__callExpression = undefined;
-            },
-            prolog: function(){return "";},
-            epilog: function(){return "";},
-            checkArgument: function(pos, e){
-                this.__callExpression = new Code.Expression(e.code(), Type.basic.char);
-                return ProcCallGenerator.prototype.checkArgument.call(this, pos, e);
+                ExpCallGenerator.prototype.init.call(this, context, id, type);
             },
             },
-            callExpression: function(){return this.__callExpression;}
+            callExpression: function(){
+                return new Code.Expression(this.args()[0].code(), Type.basic.char);
+            }
         });
         });
         var name = "CHR";
         var name = "CHR";
         var type = new ProcType(
         var type = new ProcType(
@@ -578,6 +533,32 @@ exports.predefined = [
             });
             });
         var symbol = new Type.Symbol(name, type);
         var symbol = new Type.Symbol(name, type);
         return symbol;
         return symbol;
+    }(),
+    function(){
+        var CallGenerator = ExpCallGenerator.extend({
+            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()));
+            }
+        });
+        var name = "COPY";
+        var type = new ProcType(
+            "predefined procedure " + name,
+            [new Arg(undefined, false),
+             new Arg(new Type.Array("ARRAY OF CHAR", undefined, Type.basic.char), true)],
+            undefined,
+            function(context, id, type){
+                return new CallGenerator(context, id, type);
+            });
+        var symbol = new Type.Symbol(name, type);
+        return symbol;
     }()
     }()
     ];
     ];
 
 

+ 46 - 0
test/expected/copy.js

@@ -0,0 +1,46 @@
+var RTL$ = {
+    makeArray: function (/*dimensions, initializer*/){
+        var forward = Array.prototype.slice.call(arguments);
+        var result = new Array(forward.shift());
+        var i;
+        if (forward.length == 1){
+            var init = forward[0];
+            if (typeof init == "function")
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init();
+            else
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init;
+        }
+        else
+            for(i = 0; i < result.length; ++i)
+                result[i] = this.makeArray.apply(this, forward);
+        return result;
+    },
+    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;
+    },
+    copy: function (from, to){
+        for(var prop in to){
+            if (to.hasOwnProperty(prop)){
+                var v = from[prop];
+                if (v !== null && typeof v == "object")
+                    this.copy(v, to[prop]);
+                else
+                    to[prop] = v;
+            }
+        }
+    }
+};
+var m = function (){
+var s1 = "\"";
+var s2 = "ABC";
+var ac3 = RTL$.makeArray(3, 0);
+RTL$.assignArrayFromString(ac3, s1);
+RTL$.assignArrayFromString(ac3, s2);
+RTL$.copy(ac3, ac3);
+}();

+ 13 - 0
test/input/copy.ob

@@ -0,0 +1,13 @@
+MODULE m;
+
+CONST
+	s1 = 22X;
+	s2 = "ABC";
+VAR
+	ac3: ARRAY 3 OF CHAR;
+
+BEGIN
+    COPY(s1, ac3);
+    COPY(s2, ac3);
+    COPY(ac3, ac3);
+END m.

+ 11 - 1
test/test_unit.js

@@ -498,6 +498,16 @@ identifier: function(){
          ["DEC(i, 1, 2)", "at most 2 arguments expected, got 3"]
          ["DEC(i, 1, 2)", "at most 2 arguments expected, got 3"]
          )
          )
 ),
 ),
+"COPY": testWithContext(
+    context(Grammar.statement, "VAR ac3: ARRAY 3 OF CHAR; ac4: ARRAY 4 OF CHAR;"),
+    pass("COPY(\"abc\", ac3)",
+         "COPY(ac3, ac3)"
+        ),
+    fail(["COPY(ac3, \"abc\")", "expression cannot be used as VAR parameter"],
+         ["COPY(\"abcd\", ac3)", "3-character ARRAY is too small for 4-character string"],
+         ["COPY(ac3, ac4)", "array size mismatch: 'ac4' has size 4 and cannot be copied to the array with size 3"]
+         )
+),
 "assignment statement": function(){
 "assignment statement": function(){
     var test = setupWithContext(
     var test = setupWithContext(
           Grammar.statement
           Grammar.statement
@@ -998,7 +1008,7 @@ procedure: function(){
     test.expectError("intArray := charArray"
     test.expectError("intArray := charArray"
                    , "type mismatch: 'intArray' is 'ARRAY OF INTEGER' and cannot be assigned to 'ARRAY OF CHAR' expression");
                    , "type mismatch: 'intArray' is 'ARRAY OF INTEGER' and cannot be assigned to 'ARRAY OF CHAR' expression");
     test.expectError("intArray2 := intArray3"
     test.expectError("intArray2 := intArray3"
-                   , "array size mismatch: 'intArray2' has size 10 and cannot be assigned to the array with size 5");
+                   , "array size mismatch: 'intArray2' has size 10 and cannot be copied to the array with size 5");
     test.expectError("intArray3 := charArray"
     test.expectError("intArray3 := charArray"
                    , "type mismatch: 'intArray3' is 'ARRAY OF INTEGER' and cannot be assigned to 'ARRAY OF CHAR' expression");
                    , "type mismatch: 'intArray3' is 'ARRAY OF INTEGER' and cannot be assigned to 'ARRAY OF CHAR' expression");
 },
 },