소스 검색

ABS/LSL/ASR/ROR procedures

Vladislav Folts 12 년 전
부모
커밋
68c2ddbdaa
13개의 변경된 파일175개의 추가작업 그리고 5개의 파일을 삭제
  1. 1 1
      src/context.js
  2. 5 1
      src/operator.js
  3. 68 2
      src/procedure.js
  4. 5 1
      src/type.js
  5. 4 0
      test/expected/abs.js
  6. 6 0
      test/expected/asr.js
  7. 6 0
      test/expected/lsl.js
  8. 6 0
      test/expected/ror.js
  9. 7 0
      test/input/abs.ob
  10. 9 0
      test/input/asr.ob
  11. 9 0
      test/input/lsl.ob
  12. 9 0
      test/input/ror.ob
  13. 40 0
      test/test_unit.js

+ 1 - 1
src/context.js

@@ -578,7 +578,7 @@ exports.ArrayDimensions = ChainedContext.extend({
 
 var numericOpTypeCheck = {
     expect: "numeric type",
-    check: function(t){return [basicTypes.int, basicTypes.real].indexOf(t) != -1;}
+    check: function(t){return Type.numeric.indexOf(t) != -1;}
 };
 
 var intOpTypeCheck = {

+ 5 - 1
src/operator.js

@@ -82,7 +82,11 @@ var operators = {
     not:        makeUnary(function(x){return !x;}, "!"),
     negate:     makeUnary(function(x){return -x;}, "-"),
     unaryPlus:  makeUnary(function(x){return x;}, ""),
-    setComplement: makeUnary(function(x){return ~x;}, "~")
+    setComplement: makeUnary(function(x){return ~x;}, "~"),
+
+    lsl:        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)
 };
 
 for(var p in operators)

+ 68 - 2
src/procedure.js

@@ -1,8 +1,10 @@
-//var assert = require("assert").ok;
+"use strict";
+
 var Cast = require("cast.js");
 var Class = require("rtl.js").Class;
 var Code = require("code.js");
 var Errors = require("errors.js");
+var op = require("operator.js");
 var precedence = require("operator.js").precedence;
 var Type = require("type.js");
 
@@ -64,8 +66,9 @@ var ProcCallGenerator = Class.extend({
     callExpression: function(){
 		this.writeCode(this.epilog());
 		return new Code.Expression(this.codeGenerator().result(),
-                                   this.__type ? this.__type.result() : undefined);
+                                   this.resultType());
 	},
+    resultType: function(){return this.__type ? this.__type.result() : undefined;},
 	prolog: function(){return this.__id + "(";},
 	checkArgumentsCount: function(count){
 		var procArgs = this.__type.arguments();
@@ -164,6 +167,37 @@ var TwoArgToOperatorProcCallGenerator = ProcCallGenerator.extend({
 	}
 });
 
+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);
+        },
+        callExpression: function(){
+            return op(this.__args[0], this.__args[1]);
+        }
+    });
+    var args = [new Arg(Type.basic.int, false),
+                new Arg(Type.basic.int, false)
+               ];
+    var proc = new ProcType(
+        "predefined procedure " + name,
+        args,
+        Type.basic.int,
+        function(context, id, type){
+            return new CallGenerator(context, id, type);
+        });
+    var type = new Type.Procedure(proc);
+    var symbol = new Type.Symbol(name, type);
+    return symbol;
+}
+
 exports.predefined = [
 	function(){
 		var NewProcCallGenerator = ProcCallGenerator.extend({
@@ -315,6 +349,38 @@ exports.predefined = [
 		var symbol = new Type.Symbol("EXCL", type);
 		return symbol;
 	}(),
+    function(){
+        var CallGenerator = ProcCallGenerator.extend({
+            init: function AbsProcCallGenerator(context, id, type){
+                ProcCallGenerator.prototype.init.call(this, context, id, type);
+                this.__argType = undefined;
+            },
+            prolog: function(){return "Math.abs(";},
+            checkArgument: function(pos, e){
+                var type = e.type();
+                if (Type.numeric.indexOf(type) == -1)
+                    throw new Errors.Error("type mismatch: expected numeric type, got '" +
+                                           type.description() + "'");
+                this.__argType = type;
+                return ProcCallGenerator.prototype.checkArgument.call(this, pos, e);
+            },
+            resultType: function(){return this.__argType;}
+        });
+        var args = [new Arg(undefined, false)];
+        var proc = new ProcType(
+            "predefined procedure ABS",
+            args,
+            undefined,
+            function(context, id, type){
+                return new CallGenerator(context, id, type);
+            });
+        var type = new Type.Procedure(proc);
+        var symbol = new Type.Symbol("ABS", type);
+        return symbol;
+    }(),
+    bitShiftImpl("LSL", op.lsl),
+    bitShiftImpl("ASR", op.asr),
+    bitShiftImpl("ROR", op.ror),
     function(){
         var CallGenerator = ProcCallGenerator.extend({
             init: function OrdProcCallGenerator(context, id, type){

+ 5 - 1
src/type.js

@@ -1,3 +1,5 @@
+"use strict";
+
 var Class = require("rtl.js").Class;
 var Errors = require("errors.js");
 
@@ -114,13 +116,15 @@ var NilType = Type.extend({
 	description: function(){return "NIL";}
 });
 
-exports.basic = {
+var basic = {
 	bool: new BasicType("BOOLEAN", false),
 	char: new BasicType("CHAR", 0),
 	int: new BasicType("INTEGER", 0),
 	real: new BasicType("REAL", 0),
 	set: new BasicType("SET", 0)
 };
+exports.basic = basic;
+exports.numeric = [basic.int, basic.real];
 
 exports.nil = new NilType();
 

+ 4 - 0
test/expected/abs.js

@@ -0,0 +1,4 @@
+var m = function (){
+var i = 0;
+i = Math.abs(i);
+}();

+ 6 - 0
test/expected/asr.js

@@ -0,0 +1,6 @@
+var m = function (){
+var i = 0;var j = 0;var r = 0;
+i = 1;
+j = 2;
+r = i >> j;
+}();

+ 6 - 0
test/expected/lsl.js

@@ -0,0 +1,6 @@
+var m = function (){
+var i = 0;var j = 0;var r = 0;
+i = 1;
+j = 2;
+r = i << j;
+}();

+ 6 - 0
test/expected/ror.js

@@ -0,0 +1,6 @@
+var m = function (){
+var i = 0;var j = 0;var r = 0;
+i = 1;
+j = 2;
+r = i >>> j;
+}();

+ 7 - 0
test/input/abs.ob

@@ -0,0 +1,7 @@
+MODULE m;
+
+VAR i: INTEGER;
+
+BEGIN
+    i := ABS(i);
+END m.

+ 9 - 0
test/input/asr.ob

@@ -0,0 +1,9 @@
+MODULE m;
+
+VAR i, j, r: INTEGER;
+
+BEGIN
+	i := 1;
+	j := 2;
+    r := ASR(i, j);
+END m.

+ 9 - 0
test/input/lsl.ob

@@ -0,0 +1,9 @@
+MODULE m;
+
+VAR i, j, r: INTEGER;
+
+BEGIN
+	i := 1;
+	j := 2;
+    r := LSL(i, j);
+END m.

+ 9 - 0
test/input/ror.ob

@@ -0,0 +1,9 @@
+MODULE m;
+
+VAR i, j, r: INTEGER;
+
+BEGIN
+	i := 1;
+	j := 2;
+    r := ROR(i, j);
+END m.

+ 40 - 0
test/test_unit.js

@@ -385,6 +385,46 @@ identifier: function(){
     test.expectError("PROCEDURE p(a: ARRAY OF INTEGER): INTEGER; RETURN LEN(a[0]) END p",
                      "type mismatch for argument 1: 'INTEGER' cannot be converted to 'ARRAY OF any type'");
 },
+"ABS": testWithContext(
+    context(Grammar.statement,
+            "VAR i: INTEGER; r: REAL; c: CHAR;"),
+    pass("i := ABS(i)",
+         "r := ABS(r)"),
+    fail(["i := ABS(r)", "type mismatch: 'i' is 'INTEGER' and cannot be assigned to 'REAL' expression"],
+         ["i := ABS(c)", "type mismatch: expected numeric type, got 'CHAR'"],
+         ["i := ABS(i, i)", "1 argument(s) expected, got 2"]
+         )
+    ),
+"LSL": testWithContext(
+    context(Grammar.statement,
+            "VAR i: INTEGER; r: REAL; c: CHAR;"),
+    pass("i := LSL(i, i)"),
+    fail(["i := LSL(i, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
+         ["i := LSL(r, i)", "type mismatch for argument 1: 'REAL' cannot be converted to 'INTEGER'"],
+         ["r := LSL(i, i)", "type mismatch: 'r' is 'REAL' and cannot be assigned to 'INTEGER' expression"],
+         ["i := LSL(i)", "2 argument(s) expected, got 1"]
+         )
+    ),
+"ASR": testWithContext(
+    context(Grammar.statement,
+            "VAR i: INTEGER; r: REAL; c: CHAR;"),
+    pass("i := ASR(i, i)"),
+    fail(["i := ASR(i, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
+         ["i := ASR(r, i)", "type mismatch for argument 1: 'REAL' cannot be converted to 'INTEGER'"],
+         ["r := ASR(i, i)", "type mismatch: 'r' is 'REAL' and cannot be assigned to 'INTEGER' expression"],
+         ["i := ASR(i)", "2 argument(s) expected, got 1"]
+         )
+    ),
+"ROR": testWithContext(
+    context(Grammar.statement,
+            "VAR i: INTEGER; r: REAL; c: CHAR;"),
+    pass("i := ROR(i, i)"),
+    fail(["i := ROR(i, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
+         ["i := ROR(r, i)", "type mismatch for argument 1: 'REAL' cannot be converted to 'INTEGER'"],
+         ["r := ROR(i, i)", "type mismatch: 'r' is 'REAL' and cannot be assigned to 'INTEGER' expression"],
+         ["i := ROR(i)", "2 argument(s) expected, got 1"]
+         )
+    ),
 "ODD": function(){
     var test = setup(Grammar.statement);