Browse Source

Support BYTE type.

Vladislav Folts 11 years ago
parent
commit
af14fc0bc7

+ 12 - 2
src/cast.js

@@ -26,6 +26,8 @@ function matchesToNIL(t){
 function areTypesMatch(t1, t2){
 function areTypesMatch(t1, t2){
     if (t1 == t2)
     if (t1 == t2)
         return true;
         return true;
+    if (Type.isInt(t1) && Type.isInt(t2))
+        return true;
     if (t1 instanceof PointerType && t2 instanceof PointerType)
     if (t1 instanceof PointerType && t2 instanceof PointerType)
         return areTypesMatch(t1.baseType(), t2.baseType());
         return areTypesMatch(t1.baseType(), t2.baseType());
     if (t1 instanceof ProcedureType && t2 instanceof ProcedureType)
     if (t1 instanceof ProcedureType && t2 instanceof ProcedureType)
@@ -59,10 +61,18 @@ function areProceduresMatch(p1, p2){
     return areTypesMatch(r1, r2);
     return areTypesMatch(r1, r2);
 }
 }
 
 
-function implicitCast(from, to){
-    if (from === to)
+function implicitCast(from, to, ops){
+    if (from == to)
+        return doNoting;
+
+    if (from == Type.basic.uint8 && to == Type.basic.integer)
         return doNoting;
         return doNoting;
 
 
+    if (from == Type.basic.integer && to == Type.basic.uint8)
+        return function(context, e){
+            return ops.setIntersection(e, new Code.Expression("0xFF", Type.basic.integer, undefined, 0xFF));
+        };
+
     if (from instanceof Type.String){
     if (from instanceof Type.String){
         if (to === Type.basic.ch){
         if (to === Type.basic.ch){
             var v = from.asChar();
             var v = from.asChar();

+ 47 - 44
src/context.js

@@ -54,7 +54,7 @@ function checkTypeMatch(from, to){
 }
 }
 
 
 function checkImplicitCast(from, to){
 function checkImplicitCast(from, to){
-    var result = Cast.implicit(from, to);
+    var result = Cast.implicit(from, to, op);
     if (!result)
     if (!result)
         throwTypeMismatch(from, to);
         throwTypeMismatch(from, to);
     return result;
     return result;
@@ -73,13 +73,13 @@ function promoteTypeInExpression(e, type){
 function promoteExpressionType(context, left, right){
 function promoteExpressionType(context, left, right){
     var rightType = right.type();
     var rightType = right.type();
     if (!left)
     if (!left)
-        return right;
+        return;
 
 
     var leftType = left.type();
     var leftType = left.type();
     if (rightType === undefined)
     if (rightType === undefined)
-        return right;
-    
-    return checkImplicitCast(rightType, leftType)(context, right);
+        return;
+
+    checkImplicitCast(rightType, leftType);
 }
 }
 
 
 function checkTypeCast(from, to, msg){
 function checkTypeCast(from, to, msg){
@@ -313,8 +313,9 @@ exports.Designator = ChainedContext.extend({
     __handleIndexExpression: function(){
     __handleIndexExpression: function(){
         var e = this.__indexExpression;
         var e = this.__indexExpression;
         var expType = e.type();
         var expType = e.type();
-        if (expType != basicTypes.integer)
-            throw new Errors.Error("'INTEGER' expression expected, got '" + expType.description() + "'");
+        if (!Type.isInt(expType))
+            throw new Errors.Error(
+                Type.intsDescription() + " expression expected, got '" + expType.description() + "'");
 
 
         var type = this.__currentType;
         var type = this.__currentType;
         if (!(type instanceof Type.Array))
         if (!(type instanceof Type.Array))
@@ -395,9 +396,9 @@ exports.Designator = ChainedContext.extend({
             new DesignatorInfo(code, refCode, this.__currentType, this.__info, this.__scope));
             new DesignatorInfo(code, refCode, this.__currentType, this.__info, this.__scope));
     },
     },
     __makeRefCode: function(code){
     __makeRefCode: function(code){
-        if ((this.__currentType instanceof Type.Array)
-            || (this.__currentType instanceof Type.Record)
-            || (this.__info instanceof Type.VariableRef))
+        if (   this.__currentType instanceof Type.Array
+            || this.__currentType instanceof Type.Record
+            || this.__info instanceof Type.VariableRef)
             return code;
             return code;
         if (this.__derefCode)
         if (this.__derefCode)
             return this.rtl().makeRef(this.__derefCode, this.__propCode);
             return this.rtl().makeRef(this.__derefCode, this.__propCode);
@@ -560,7 +561,7 @@ exports.ProcDecl = ChainedContext.extend({
         var result = this.__type.result();
         var result = this.__type.result();
         if (!result)
         if (!result)
             throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
             throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
-        if (!Cast.implicit(type, result))
+        if (!Cast.implicit(type, result, op))
             throw new Errors.Error(
             throw new Errors.Error(
                 "RETURN '" + result.description() + "' expected, got '"
                 "RETURN '" + result.description() + "' expected, got '"
                 + type.description() + "'");
                 + type.description() + "'");
@@ -575,22 +576,16 @@ exports.ProcDecl = ChainedContext.extend({
 });
 });
 
 
 exports.Return = ChainedContext.extend({
 exports.Return = ChainedContext.extend({
-    init: function ReturnContext(context){
+    init: function Context$Return(context){
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
-        this.__type = undefined;
-        this.__code = new Code.SimpleGenerator();
-    },
-    codeGenerator: function(){return this.__code;},
-    handleExpression: function(e){
-        this.__type = e.type();
-        var designator = e.designator();
-        if (designator)
-            writeDerefDesignatorCode(designator, this.__code);
+        this.__expr = undefined;
     },
     },
+    codeGenerator: function(){return Code.nullGenerator;},
+    handleExpression: function(e){this.__expr = e;},
     endParse: function(){
     endParse: function(){
         var parent = this.parent();
         var parent = this.parent();
-        parent.codeGenerator().write("return " + this.__code.result() + ";\n");
-        parent.handleReturn(this.__type);
+        parent.codeGenerator().write("return " + this.__expr.deref().code() + ";\n");
+        parent.handleReturn(this.__expr.type());
     }
     }
 });
 });
 
 
@@ -722,14 +717,18 @@ var numericOpTypeCheck = {
 };
 };
 
 
 var intOpTypeCheck = {
 var intOpTypeCheck = {
-    expect: "INTEGER",
-    check: function(t){return t == basicTypes.integer;}
+    expect: Type.intsDescription(),
+    check: Type.isInt
 };
 };
 
 
 var orderOpTypeCheck = {
 var orderOpTypeCheck = {
     expect: "numeric type or CHAR or character array",
     expect: "numeric type or CHAR or character array",
     check: function(t){
     check: function(t){
-        return [basicTypes.integer, basicTypes.real, basicTypes.ch].indexOf(t) != -1
+        return [basicTypes.integer,
+                basicTypes.uint8,
+                basicTypes.real,
+                basicTypes.ch
+               ].indexOf(t) != -1
             || (t instanceof Type.Array && t.elementsType() == basicTypes.ch);
             || (t instanceof Type.Array && t.elementsType() == basicTypes.ch);
     }
     }
 };
 };
@@ -737,7 +736,13 @@ var orderOpTypeCheck = {
 var equalOpTypeCheck = {
 var equalOpTypeCheck = {
     expect: "numeric type or SET or BOOLEAN OR CHAR or character array or POINTER or PROCEDURE",
     expect: "numeric type or SET or BOOLEAN OR CHAR or character array or POINTER or PROCEDURE",
     check: function(t){
     check: function(t){
-        return [basicTypes.integer, basicTypes.real, basicTypes.set, basicTypes.bool, basicTypes.ch].indexOf(t) != -1
+        return [basicTypes.integer,
+                basicTypes.uint8,
+                basicTypes.real,
+                basicTypes.set,
+                basicTypes.bool,
+                basicTypes.ch
+               ].indexOf(t) != -1
             || (t instanceof Type.Array && t.elementsType() == basicTypes.ch)
             || (t instanceof Type.Array && t.elementsType() == basicTypes.ch)
             || t instanceof Type.Pointer
             || t instanceof Type.Pointer
             || t instanceof Type.Procedure
             || t instanceof Type.Procedure
@@ -755,7 +760,7 @@ function assertOpType(type, check, literal){
 
 
 function assertNumericOp(type, literal, op, intOp){
 function assertNumericOp(type, literal, op, intOp){
     assertOpType(type, numericOpTypeCheck, literal);
     assertOpType(type, numericOpTypeCheck, literal);
-    return (intOp && type == basicTypes.integer)
+    return (intOp && Type.isInt(type))
            ? intOp : op;
            ? intOp : op;
 }
 }
 
 
@@ -858,7 +863,7 @@ exports.MulOperator = ChainedContext.extend({
         else if (s == "/"){
         else if (s == "/"){
             if (type == basicTypes.set)
             if (type == basicTypes.set)
                 o = op.setSymmetricDiff;
                 o = op.setSymmetricDiff;
-            else if (type == basicTypes.integer)
+            else if (Type.isInt(type))
                 throw new Errors.Error("operator DIV expected for integer division");
                 throw new Errors.Error("operator DIV expected for integer division");
             else
             else
                 o = assertNumericOp(type, s, op.div);
                 o = assertNumericOp(type, s, op.div);
@@ -879,12 +884,6 @@ exports.MulOperator = ChainedContext.extend({
     }
     }
 });
 });
 
 
-function writeDerefDesignatorCode(designator, code){
-    var info = designator.info();
-    if (info instanceof Type.VariableRef)
-        code.write(".get()");
-}
-
 exports.Term = ChainedContext.extend({
 exports.Term = ChainedContext.extend({
     init: function TermContext(context){
     init: function TermContext(context){
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
@@ -913,7 +912,7 @@ exports.Term = ChainedContext.extend({
     },
     },
     endParse: function(){this.parent().handleTerm(this.__expression);},
     endParse: function(){this.parent().handleTerm(this.__expression);},
     handleExpression: function(e){
     handleExpression: function(e){
-        e = promoteExpressionType(this, this.__expression, e);
+        promoteExpressionType(this, this.__expression, e);
         if (this.__operator)
         if (this.__operator)
             e = this.__expression ? this.__operator(this.__expression, e)
             e = this.__expression ? this.__operator(this.__expression, e)
                                   : this.__operator(e);
                                   : this.__operator(e);
@@ -1077,8 +1076,9 @@ exports.Expression = ChainedContext.extend({
         var code;
         var code;
 
 
         if (this.__relation == "IN"){
         if (this.__relation == "IN"){
-            if (leftType != basicTypes.integer)
-                throw new Errors.Error("'INTEGER' expected as an element of SET, got '" + leftType.name() + "'");
+            if (!Type.isInt(leftType))
+                throw new Errors.Error(
+                    Type.intsDescription() + " expected as an element of SET, got '" + leftType.name() + "'");
             checkImplicitCast(rightType, basicTypes.set);
             checkImplicitCast(rightType, basicTypes.set);
 
 
             code = "1 << " + leftCode + " & " + rightCode;
             code = "1 << " + leftCode + " & " + rightCode;
@@ -1194,8 +1194,9 @@ exports.Case = ChainedContext.extend({
                 type = basicTypes.ch;
                 type = basicTypes.ch;
             }
             }
         }
         }
-        if (type != basicTypes.integer && type != basicTypes.ch)
-            throw new Errors.Error("'INTEGER' or 'CHAR' expected as CASE expression");
+        if (!Type.isInt(type) && type != basicTypes.ch)
+            throw new Errors.Error(
+                Type.intsDescription() + " or 'CHAR' expected as CASE expression");
         this.__type = type;
         this.__type = type;
         gen.write(";\n");
         gen.write(";\n");
     },
     },
@@ -1206,7 +1207,7 @@ exports.Case = ChainedContext.extend({
             this.codeGenerator().write("else ");
             this.codeGenerator().write("else ");
     },
     },
     handleLabelType: function(type){
     handleLabelType: function(type){
-        if (type !== this.__type)
+        if (!Cast.areTypesMatch(type, this.__type))
             throw new Errors.Error(
             throw new Errors.Error(
                 "label must be '" + this.__type.name() + "' (the same as case expression), got '"
                 "label must be '" + this.__type.name() + "' (the same as case expression), got '"
                 + type.name() + "'");
                 + type.name() + "'");
@@ -1342,9 +1343,11 @@ exports.For = ChainedContext.extend({
         var s = getSymbol(this.parent(), id);
         var s = getSymbol(this.parent(), id);
         if (!s.isVariable())
         if (!s.isVariable())
             throw new Errors.Error("'" + s.id() + "' is not a variable");
             throw new Errors.Error("'" + s.id() + "' is not a variable");
-        if (s.info().type() !== basicTypes.integer)
+        var type = s.info().type();
+        if (type !== basicTypes.integer)
             throw new Errors.Error(
             throw new Errors.Error(
-                "'" + s.id() + "' is a 'BOOLEAN' variable, 'FOR' control variable must be 'INTEGER'");
+                  "'" + s.id() + "' is a '" 
+		+ type.description() + "' variable, 'FOR' control variable must be 'INTEGER'");
         this.codeGenerator().write("for (" + id + " = ");
         this.codeGenerator().write("for (" + id + " = ");
         this.__var = id;
         this.__var = id;
     },
     },
@@ -1411,7 +1414,7 @@ exports.Assignment = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         ChainedContext.prototype.init.call(this, context);
         this.__left = undefined;
         this.__left = undefined;
     },
     },
-    codeGenerator: function(){/*throw new Error("Test");*/ return Code.nullGenerator;},
+    codeGenerator: function(){return Code.nullGenerator;},
     setDesignator: function(d){
     setDesignator: function(d){
         this.__left = new Code.Expression(d.code(), d.type(), d);
         this.__left = new Code.Expression(d.code(), d.type(), d);
     },
     },

+ 18 - 4
src/operator.js

@@ -86,7 +86,7 @@ function assign(left, right, context){
         return context.rtl().assignArrayFromString(leftCode, rightCode);
         return context.rtl().assignArrayFromString(leftCode, rightCode);
     }
     }
 
 
-    var castOperation = Cast.implicit(rightType, leftType);
+    var castOperation = Cast.implicit(rightType, leftType, exports);
     if (!castOperation)
     if (!castOperation)
         throw new Errors.Error("type mismatch: '" + leftCode
         throw new Errors.Error("type mismatch: '" + leftCode
                              + "' is '" + leftType.description()
                              + "' is '" + leftType.description()
@@ -118,12 +118,26 @@ function makeInplace(code, altOp){
     };
     };
 }
 }
 
 
+function promoteToWideIfNeeded(op){
+    return function(){
+        var result = op.apply(this, arguments);
+        if (result.type() == Type.basic.uint8)
+            result = new Code.Expression(
+                result.code(),
+                Type.basic.integer,
+                result.designator(),
+                result.constValue(),
+                result.maxPrecedence());
+        return result;
+    };
+}
+
 function makeBinaryInt(op, code, prec){
 function makeBinaryInt(op, code, prec){
-    return makeBinary(
+    return promoteToWideIfNeeded(makeBinary(
             function(x, y){return op(x, y) | 0;},
             function(x, y){return op(x, y) | 0;},
             function(x, y){return x + code + y + " | 0";},
             function(x, y){return x + code + y + " | 0";},
             prec,
             prec,
-            precedence.bitOr);
+            precedence.bitOr));
 }
 }
 
 
 var operators = {
 var operators = {
@@ -158,7 +172,7 @@ var operators = {
     eqGreater:  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;}, "!"),
     not:        makeUnary(function(x){return !x;}, "!"),
-    negate:     makeUnary(function(x){return -x;}, "-"),
+    negate:     promoteToWideIfNeeded(makeUnary(function(x){return -x;}, "-")),
     unaryPlus:  makeUnary(function(x){return x;}, ""),
     unaryPlus:  makeUnary(function(x){return x;}, ""),
     setComplement: makeUnary(function(x){return ~x;}, "~"),
     setComplement: makeUnary(function(x){return ~x;}, "~"),
 
 

+ 8 - 3
src/procedure.js

@@ -84,10 +84,15 @@ var ProcCallGenerator = Class.extend({
         var expectType = arg.type; // can be undefined for predefined functions (like NEW), dont check it in this case
         var expectType = arg.type; // can be undefined for predefined functions (like NEW), dont check it in this case
         if (expectType){
         if (expectType){
             var type = e.type();
             var type = e.type();
-            castOperation = Cast.implicit(type, expectType);
+            castOperation = Cast.implicit(type, expectType, op);
             if (!castOperation)
             if (!castOperation)
-                throw new Errors.Error("type mismatch for argument " + (pos + 1) + ": '" + type.description()
-                                     + "' cannot be converted to '" + expectType.description() + "'");
+                throw new Errors.Error(
+                      "type mismatch for argument " + (pos + 1) + ": '" + type.description()
+                    + "' cannot be converted to '" + expectType.description() + "'");
+            if (arg.isVar && expectType != type && Type.isInt(type))
+                throw new Errors.Error(
+                      "type mismatch for argument " + (pos + 1) + ": cannot pass '" 
+                    + type.description() + "' as VAR parameter of type '" + expectType.description() + "'");
         }
         }
         if (arg.isVar){
         if (arg.isVar){
             var designator = e.designator();
             var designator = e.designator();

+ 6 - 1
src/type.js

@@ -163,11 +163,16 @@ var basic = {
     bool: new BasicType("BOOLEAN", false),
     bool: new BasicType("BOOLEAN", false),
     ch: new BasicType("CHAR", 0),
     ch: new BasicType("CHAR", 0),
     integer: new BasicType("INTEGER", 0),
     integer: new BasicType("INTEGER", 0),
+    uint8: new BasicType("BYTE", 0),
     real: new BasicType("REAL", 0),
     real: new BasicType("REAL", 0),
     set: new BasicType("SET", 0)
     set: new BasicType("SET", 0)
 };
 };
 exports.basic = basic;
 exports.basic = basic;
-exports.numeric = [basic.integer, basic.real];
+exports.numeric = [basic.integer, basic.uint8, basic.real];
+
+exports.isInt = function(type){return type == basic.integer || type == basic.uint8;};
+
+exports.intsDescription = function(){return "'INTEGER' or 'BYTE'";};
 
 
 exports.nil = new NilType();
 exports.nil = new NilType();
 
 

+ 22 - 0
test/expected/arithmetic.js

@@ -2,6 +2,7 @@ var m = function (){
 var c1 = 2147483647 + 1 | 0;
 var c1 = 2147483647 + 1 | 0;
 var c2 = 4294967295 * 2 | 0;
 var c2 = 4294967295 * 2 | 0;
 var i1 = 0;var i2 = 0;
 var i1 = 0;var i2 = 0;
+var b1 = 0;var b2 = 0;
 var r1 = 0;var r2 = 0;
 var r1 = 0;var r2 = 0;
 i1 = 1;
 i1 = 1;
 i2 = 2;
 i2 = 2;
@@ -11,6 +12,27 @@ i1 = i1 * i2 | 0;
 i1 = i1 / i2 | 0;
 i1 = i1 / i2 | 0;
 i1 = i1 % i2;
 i1 = i1 % i2;
 i1 = 1 + (i1 * i2 | 0) | 0;
 i1 = 1 + (i1 * i2 | 0) | 0;
+b1 = 1 & 0xFF;
+b1 = -1 & 0xFF;
+b1 = b2;
+b1 = -b2 & 0xFF;
+b1 = b2;
+b1 = (b1 + b2 | 0) & 0xFF;
+b1 = (b1 - b2 | 0) & 0xFF;
+b1 = (b1 * b2 | 0) & 0xFF;
+b1 = (b1 / b2 | 0) & 0xFF;
+b1 = b1 % b2;
+i1 = b1;
+b1 = i1 & 0xFF;
+i1 = -b1;
+b1 = -i1 & 0xFF;
+i1 = i2 + b1 | 0;
+i1 = b1 - i2 | 0;
+i1 = i2 * b1 | 0;
+i1 = b1 / i2 | 0;
+b1 = i1 % b2 & 0xFF;
+b1 = b1 % i1;
+b1 = i1 % i2 & 0xFF;
 r1 = 1;
 r1 = 1;
 r2 = 2;
 r2 = 2;
 r1 = r1 + r2;
 r1 = r1 + r2;

+ 11 - 0
test/expected/case.js

@@ -4,6 +4,7 @@ var constI = 12;
 var i = 0;
 var i = 0;
 var b1 = false;
 var b1 = false;
 var i1 = 0;
 var i1 = 0;
+var byte = 0;
 var c = 0;
 var c = 0;
 var $c;
 var $c;
 $c = i1;
 $c = i1;
@@ -40,6 +41,16 @@ else if (($c >= 4 && $c <= 5)){
 else if ($c === 6 || ($c >= 7 && $c <= 10)){
 else if ($c === 6 || ($c >= 7 && $c <= 10)){
 	b1 = true;
 	b1 = true;
 }
 }
+$c = byte;
+if ($c === 1){
+	i = 2;
+}
+else if ($c === 257){
+	i = 3;
+}
+else if (($c >= 4 && $c <= 12)){
+	i = 5;
+}
 $c = c;
 $c = c;
 if ($c === 65){
 if ($c === 65){
 	i = 1;
 	i = 1;

+ 29 - 0
test/expected/proc.js

@@ -15,6 +15,8 @@ var RTL$ = {
     }
     }
 };
 };
 var m = function (){
 var m = function (){
+var i = 0;
+var byte = 0;
 
 
 function p1(arg1/*INTEGER*/){
 function p1(arg1/*INTEGER*/){
 	var T1 = RTL$.extend({
 	var T1 = RTL$.extend({
@@ -64,4 +66,31 @@ function emptyBegin(){
 function emptyBeginWithReturn(){
 function emptyBeginWithReturn(){
 	return 0;
 	return 0;
 }
 }
+
+function withByteArgument(b/*BYTE*/){
+}
+
+function withByteResult(){
+	return 0;
+}
+
+function withByteResult2(b/*BYTE*/){
+	return b;
+}
+
+function withByteResult3(b/*VAR BYTE*/){
+	return b.get();
+}
+
+function withByteResult4(){
+	var b = 0;
+	b = 0 & 0xFF;
+	return b;
+}
+byte = withByteResult();
+i = withByteResult();
+withByteArgument(byte);
+byte = withByteResult2(byte);
+byte = withByteResult2(i & 0xFF);
+byte = withByteResult3({set: function($v){byte = $v;}, get: function(){return byte;}});
 }();
 }();

+ 19 - 11
test/expected/var_parameter.js

@@ -40,31 +40,39 @@ var m = function (){
 var R = RTL$.extend({
 var R = RTL$.extend({
 	init: function R(){
 	init: function R(){
 		this.i = 0;
 		this.i = 0;
+		this.byte = 0;
 		this.a = RTL$.makeArray(3, 0);
 		this.a = RTL$.makeArray(3, 0);
 		this.p = null;
 		this.p = null;
 	}
 	}
 });
 });
 var i = 0;
 var i = 0;
+var byte = 0;
 var b = false;
 var b = false;
 var a = RTL$.makeArray(5, 0);
 var a = RTL$.makeArray(5, 0);
+var byteArray = RTL$.makeArray(3, 0);
 
 
-function p1(i1/*VAR INTEGER*/, i2/*VAR INTEGER*/){
+function p1(i1/*VAR INTEGER*/, i2/*VAR INTEGER*/, byte/*VAR BYTE*/){
 	i1.set(1);
 	i1.set(1);
 	i2.set(2);
 	i2.set(2);
+	byte.set(3 & 0xFF);
 }
 }
 
 
-function p2(i/*INTEGER*/, b/*BOOLEAN*/){
+function p2(i/*INTEGER*/, byte/*BYTE*/, b/*BOOLEAN*/){
 }
 }
 
 
 function index(i/*VAR INTEGER*/){
 function index(i/*VAR INTEGER*/){
 	return i.get();
 	return i.get();
 }
 }
 
 
+function indexByte(b/*VAR BYTE*/){
+	return b.get();
+}
+
 function array(a/*VAR ARRAY OF INTEGER*/){
 function array(a/*VAR ARRAY OF INTEGER*/){
 	return a[0];
 	return a[0];
 }
 }
 
 
-function p3(i/*VAR INTEGER*/, b/*VAR BOOLEAN*/){
+function p3(i/*VAR INTEGER*/, byte/*VAR BYTE*/, b/*VAR BOOLEAN*/){
 	var j = 0;
 	var j = 0;
 	var r = new R();
 	var r = new R();
 	var ar = RTL$.makeArray(5, function(){return new R();});
 	var ar = RTL$.makeArray(5, function(){return new R();});
@@ -75,17 +83,17 @@ function p3(i/*VAR INTEGER*/, b/*VAR BOOLEAN*/){
 	j = -i.get();
 	j = -i.get();
 	b.set(!b.get());
 	b.set(!b.get());
 	a[i.get()] = i.get();
 	a[i.get()] = i.get();
-	p1({set: function($v){j = $v;}, get: function(){return j;}}, i);
-	p1(i, {set: function($v){j = $v;}, get: function(){return j;}});
-	p1(i, RTL$.makeRef(a, index(i)));
-	p2(i.get(), b.get());
-	p1(RTL$.makeRef(r, "i"), RTL$.makeRef(ar[index(RTL$.makeRef(r, "i"))], "i"));
+	p1({set: function($v){j = $v;}, get: function(){return j;}}, i, byte);
+	p1(i, {set: function($v){j = $v;}, get: function(){return j;}}, byte);
+	p1(i, RTL$.makeRef(a, index(i)), RTL$.makeRef(byteArray, indexByte(byte)));
+	p2(i.get(), byte.get(), b.get());
+	p1(RTL$.makeRef(r, "i"), RTL$.makeRef(ar[index(RTL$.makeRef(r, "i"))], "i"), RTL$.makeRef(ar[index(RTL$.makeRef(r, "i"))], "byte"));
 	r.p = new R();
 	r.p = new R();
 	ar[j].p = new R();
 	ar[j].p = new R();
-	p1(RTL$.makeRef(r.p, "i"), RTL$.makeRef(ar[j].p, "i"));
-	p2(ar[j].p.i, r.p.i == ar[j].p.i);
+	p1(RTL$.makeRef(r.p, "i"), RTL$.makeRef(ar[j].p, "i"), RTL$.makeRef(ar[j].p, "byte"));
+	p2(ar[j].p.i, ar[j].p.byte, r.p.i == ar[j].p.i);
 	j = array(ai);
 	j = array(ai);
 	j = array(r.a);
 	j = array(r.a);
 }
 }
-p3({set: function($v){i = $v;}, get: function(){return i;}}, {set: function($v){b = $v;}, get: function(){return b;}});
+p3({set: function($v){i = $v;}, get: function(){return i;}}, {set: function($v){byte = $v;}, get: function(){return byte;}}, {set: function($v){b = $v;}, get: function(){return b;}});
 }();
 }();

+ 24 - 0
test/input/arithmetic.ob

@@ -5,6 +5,7 @@ CONST
 	c2 = 0FFFFFFFFH * 2; (* -2 *)
 	c2 = 0FFFFFFFFH * 2; (* -2 *)
 VAR 
 VAR 
 	i1, i2: INTEGER;
 	i1, i2: INTEGER;
+	b1, b2: BYTE;
 	r1, r2: REAL;
 	r1, r2: REAL;
 
 
 BEGIN
 BEGIN
@@ -17,6 +18,29 @@ BEGIN
 	i1 := i1 MOD i2;
 	i1 := i1 MOD i2;
 	i1 := 1 + i1 * i2;
 	i1 := 1 + i1 * i2;
 
 
+	b1 := 1;
+	b1 := -1;
+	b1 := b2;
+	b1 := -b2;
+	b1 := +b2;
+	b1 := b1 + b2;
+	b1 := b1 - b2;
+	b1 := b1 * b2;
+	b1 := b1 DIV b2;
+	b1 := b1 MOD b2;
+
+	i1 := b1;
+	b1 := i1;
+	i1 := -b1;
+	b1 := -i1;
+	i1 := i2 + b1;
+	i1 := b1 - i2;
+	i1 := i2 * b1;
+	i1 := b1 DIV i2;
+	b1 := i1 MOD b2;
+	b1 := b1 MOD i1;
+	b1 := i1 MOD i2;
+
 	r1 := 1.0;
 	r1 := 1.0;
 	r2 := 2.0;
 	r2 := 2.0;
 	r1 := r1 + r2;
 	r1 := r1 + r2;

+ 7 - 0
test/input/case.ob

@@ -7,6 +7,7 @@ CONST
 VAR i: INTEGER;
 VAR i: INTEGER;
 	b1: BOOLEAN;
 	b1: BOOLEAN;
 	i1: INTEGER;
 	i1: INTEGER;
+	byte: BYTE;
 	c: CHAR;
 	c: CHAR;
 
 
 BEGIN    
 BEGIN    
@@ -31,6 +32,12 @@ BEGIN
 		| 6, 7..10: b1 := TRUE
 		| 6, 7..10: b1 := TRUE
 	END;
 	END;
 
 
+	CASE byte OF
+		  1: i := 2
+		| 257: i := 3
+		| 4..constI: i := 5
+	END;
+
 	CASE c OF
 	CASE c OF
 		  "A": i := 1
 		  "A": i := 1
 		| ch1: i := 2
 		| ch1: i := 2

+ 33 - 0
test/input/proc.ob

@@ -4,6 +4,10 @@ TYPE
 	P1 = PROCEDURE(a1: INTEGER);
 	P1 = PROCEDURE(a1: INTEGER);
 	P2 = PROCEDURE(): P2;
 	P2 = PROCEDURE(): P2;
 
 
+VAR
+    i: INTEGER; 
+	byte: BYTE;
+
 PROCEDURE p1(arg1: INTEGER);
 PROCEDURE p1(arg1: INTEGER);
 TYPE
 TYPE
     T1 = RECORD 
     T1 = RECORD 
@@ -47,4 +51,33 @@ BEGIN
 	RETURN 0 
 	RETURN 0 
 END emptyBeginWithReturn;
 END emptyBeginWithReturn;
 
 
+PROCEDURE withByteArgument(b: BYTE);
+END withByteArgument;
+
+PROCEDURE withByteResult(): BYTE;
+	RETURN 0
+END withByteResult;
+
+PROCEDURE withByteResult2(b: BYTE): BYTE;
+	RETURN b
+END withByteResult2;
+
+PROCEDURE withByteResult3(VAR b: BYTE): BYTE;
+	RETURN b
+END withByteResult3;
+
+PROCEDURE withByteResult4(): BYTE;
+VAR b: BYTE;
+BEGIN
+	b := 0;
+	RETURN b
+END withByteResult4;
+
+BEGIN
+	byte := withByteResult();
+	i := withByteResult();
+	withByteArgument(byte);
+	byte := withByteResult2(byte);
+	byte := withByteResult2(i);
+	byte := withByteResult3(byte);
 END m.
 END m.

+ 20 - 13
test/input/var_parameter.ob

@@ -1,30 +1,37 @@
 MODULE m;
 MODULE m;
 
 
-TYPE R = RECORD i: INTEGER; a: ARRAY 3 OF INTEGER; p: POINTER TO R END;
+TYPE R = RECORD i: INTEGER; byte: BYTE; a: ARRAY 3 OF INTEGER; p: POINTER TO R END;
 
 
 VAR 
 VAR 
 	i: INTEGER;
 	i: INTEGER;
+	byte: BYTE;
 	b: BOOLEAN;
 	b: BOOLEAN;
 	a: ARRAY 5 OF INTEGER;
 	a: ARRAY 5 OF INTEGER;
+	byteArray: ARRAY 3 OF BYTE;
 
 
-PROCEDURE p1(VAR i1, i2: INTEGER);
+PROCEDURE p1(VAR i1, i2: INTEGER; VAR byte: BYTE);
 BEGIN
 BEGIN
     i1 := 1;
     i1 := 1;
-	i2 := 2
+	i2 := 2;
+	byte := 3;
 END p1;
 END p1;
 
 
-PROCEDURE p2(i: INTEGER; b: BOOLEAN);
+PROCEDURE p2(i: INTEGER; byte: BYTE; b: BOOLEAN);
 END p2;
 END p2;
 
 
 PROCEDURE index(VAR i: INTEGER): INTEGER;
 PROCEDURE index(VAR i: INTEGER): INTEGER;
 	RETURN i
 	RETURN i
 END index;
 END index;
 
 
+PROCEDURE indexByte(VAR b: BYTE): BYTE;
+	RETURN b
+END indexByte;
+
 PROCEDURE array(VAR a: ARRAY OF INTEGER): INTEGER;
 PROCEDURE array(VAR a: ARRAY OF INTEGER): INTEGER;
 	RETURN a[0]
 	RETURN a[0]
 END array;
 END array;
 
 
-PROCEDURE p3(VAR i: INTEGER; VAR b: BOOLEAN);
+PROCEDURE p3(VAR i: INTEGER; VAR byte: BYTE; VAR b: BOOLEAN);
 VAR j: INTEGER;
 VAR j: INTEGER;
 	r: R;
 	r: R;
 	ar: ARRAY 5 OF R;
 	ar: ARRAY 5 OF R;
@@ -36,23 +43,23 @@ BEGIN
 	j := -i;
 	j := -i;
 	b := ~b;
 	b := ~b;
 	a[i] := i;
 	a[i] := i;
-    p1(j, i);
-	p1(i, j);
-	p1(i, a[index(i)]);
-	p2(i, b);
+    p1(j, i, byte);
+	p1(i, j, byte);
+	p1(i, a[index(i)], byteArray[indexByte(byte)]);
+	p2(i, byte, b);
 
 
-	p1(r.i, ar[index(r.i)].i);
+	p1(r.i, ar[index(r.i)].i, ar[index(r.i)].byte);
 
 
 	NEW(r.p);
 	NEW(r.p);
 	NEW(ar[j].p);
 	NEW(ar[j].p);
-	p1(r.p.i, ar[j].p.i);
-	p2(ar[j].p.i, r.p.i = ar[j].p.i);
+	p1(r.p.i, ar[j].p.i, ar[j].p.byte);
+	p2(ar[j].p.i, ar[j].p.byte, r.p.i = ar[j].p.i);
 
 
 	j := array(ai);
 	j := array(ai);
 	j := array(r.a);
 	j := array(r.a);
 END p3;
 END p3;
 
 
 BEGIN
 BEGIN
-    p3(i, b)
+    p3(i, byte, b)
 
 
 END m.
 END m.

+ 42 - 7
test/test_unit.js

@@ -458,6 +458,36 @@ var testSuite = {
           "invalid type test: 'Base' is not an extension of 'Derived'"],
           "invalid type test: 'Base' is not an extension of 'Derived'"],
          ["pDerived IS INTEGER", "RECORD type expected after 'IS'"])
          ["pDerived IS INTEGER", "RECORD type expected after 'IS'"])
     ),
     ),
+"BYTE": testWithContext(
+    context(Grammar.statement,
+              "VAR b1, b2: BYTE; i: INTEGER; set: SET; a: ARRAY 3 OF BYTE;"
+            + "PROCEDURE varIntParam(VAR i: INTEGER); END varIntParam;"
+            + "PROCEDURE varByteParam(VAR b: BYTE); END varByteParam;"
+            ),
+    pass("b1 := b2",
+         "i := b1",
+         "b2 := i",
+         "a[b1] := i",
+         "ASSERT(i = b1)",
+         "ASSERT(b1 = i)",
+         "ASSERT(i < b1)",
+         "ASSERT(b1 > i)",
+         "ASSERT(b1 IN set)",
+         "i := b1 DIV i",
+         "i := i DIV b1",
+         "b1 := b1 MOD i",
+         "b1 := i MOD b1",
+         "b1 := b1 + i",
+         "b1 := i - b1",
+         "i := b1 * i",
+         "i := -b1",
+         "i := +b1"
+        ),
+    fail(["i := b1 / i", "operator DIV expected for integer division"],
+         ["varIntParam(b1)", "type mismatch for argument 1: cannot pass 'BYTE' as VAR parameter of type 'INTEGER'"],
+         ["varByteParam(i)", "type mismatch for argument 1: cannot pass 'INTEGER' as VAR parameter of type 'BYTE'"]
+        )
+    ),
 "NEW": testWithContext(
 "NEW": testWithContext(
     context(Grammar.statement,
     context(Grammar.statement,
             "TYPE P = POINTER TO RECORD END;"
             "TYPE P = POINTER TO RECORD END;"
@@ -664,9 +694,9 @@ var testSuite = {
     fail(["VAR a: ARRAY 10 OF INTEGER; BEGIN a[0] := TRUE END",
     fail(["VAR a: ARRAY 10 OF INTEGER; BEGIN a[0] := TRUE END",
           "type mismatch: 'a[0]' is 'INTEGER' and cannot be assigned to 'BOOLEAN' expression"],
           "type mismatch: 'a[0]' is 'INTEGER' and cannot be assigned to 'BOOLEAN' expression"],
          ["VAR a: ARRAY 10 OF INTEGER; BEGIN a[TRUE] := 1 END",
          ["VAR a: ARRAY 10 OF INTEGER; BEGIN a[TRUE] := 1 END",
-          "'INTEGER' expression expected, got 'BOOLEAN'"],
+          "'INTEGER' or 'BYTE' expression expected, got 'BOOLEAN'"],
          ["VAR a: ARRAY 10 OF INTEGER; p: POINTER TO RECORD END; BEGIN a[p] := 1 END",
          ["VAR a: ARRAY 10 OF INTEGER; p: POINTER TO RECORD END; BEGIN a[p] := 1 END",
-          "'INTEGER' expression expected, got 'POINTER TO anonymous RECORD'"],
+          "'INTEGER' or 'BYTE' expression expected, got 'POINTER TO anonymous RECORD'"],
          ["VAR i: INTEGER; BEGIN i[0] := 1 END",
          ["VAR i: INTEGER; BEGIN i[0] := 1 END",
           "ARRAY expected, got 'INTEGER'"],
           "ARRAY expected, got 'INTEGER'"],
          ["VAR p: POINTER TO RECORD END; BEGIN p[0] := 1 END",
          ["VAR p: POINTER TO RECORD END; BEGIN p[0] := 1 END",
@@ -743,10 +773,12 @@ var testSuite = {
     ),
     ),
 "CASE statement": testWithContext(
 "CASE statement": testWithContext(
     context(Grammar.statement,
     context(Grammar.statement,
-            "CONST ci = 15; cc = \"A\";   VAR c1: CHAR; b1: BOOLEAN; i1, i2: INTEGER; p: POINTER TO RECORD END;"),
+              "CONST ci = 15; cc = \"A\";"
+            + "VAR c1: CHAR; b1: BOOLEAN; i1, i2: INTEGER; byte: BYTE; p: POINTER TO RECORD END;"),
     pass("CASE i1 OF END",
     pass("CASE i1 OF END",
          "CASE i1 OF 0: b1 := TRUE END",
          "CASE i1 OF 0: b1 := TRUE END",
          "CASE c1 OF \"A\": b1 := TRUE END",
          "CASE c1 OF \"A\": b1 := TRUE END",
+         "CASE byte OF 3: b1 := TRUE END",
          "CASE i1 OF 0: b1 := TRUE | 1: b1 := FALSE END",
          "CASE i1 OF 0: b1 := TRUE | 1: b1 := FALSE END",
          "CASE i1 OF 0, 1: b1 := TRUE END",
          "CASE i1 OF 0, 1: b1 := TRUE END",
          "CASE c1 OF \"A\", \"B\": b1 := TRUE END",
          "CASE c1 OF \"A\", \"B\": b1 := TRUE END",
@@ -759,7 +791,7 @@ var testSuite = {
           "undeclared identifier: 'undefined'"],
           "undeclared identifier: 'undefined'"],
          ["CASE i1 OF i2: b1 := TRUE END",
          ["CASE i1 OF i2: b1 := TRUE END",
           "'i2' is not a constant"],
           "'i2' is not a constant"],
-         ["CASE b1 OF END", "'INTEGER' or 'CHAR' expected as CASE expression"],
+         ["CASE b1 OF END", "'INTEGER' or 'BYTE' or 'CHAR' expected as CASE expression"],
          ["CASE i1 OF \"A\": b1 := TRUE END",
          ["CASE i1 OF \"A\": b1 := TRUE END",
           "label must be 'INTEGER' (the same as case expression), got 'CHAR'"],
           "label must be 'INTEGER' (the same as case expression), got 'CHAR'"],
          ["CASE i1 OF p: b1 := TRUE END",
          ["CASE i1 OF p: b1 := TRUE END",
@@ -786,7 +818,8 @@ var testSuite = {
     ),
     ),
 "FOR statement": testWithContext(
 "FOR statement": testWithContext(
     context(Grammar.statement,
     context(Grammar.statement,
-            "CONST c = 15; VAR b: BOOLEAN; i, n: INTEGER; p: POINTER TO RECORD END;"),
+              "CONST c = 15;"
+            + "VAR b: BOOLEAN; i, n: INTEGER; ch: CHAR; p: POINTER TO RECORD END;"),
     pass("FOR i := 0 TO 10 DO n := 1 END",
     pass("FOR i := 0 TO 10 DO n := 1 END",
          "FOR i := 0 TO 10 BY 5 DO b := TRUE END",
          "FOR i := 0 TO 10 BY 5 DO b := TRUE END",
          "FOR i := 0 TO n DO b := TRUE END",
          "FOR i := 0 TO n DO b := TRUE END",
@@ -795,6 +828,8 @@ var testSuite = {
           "undeclared identifier: 'undefined'"],
           "undeclared identifier: 'undefined'"],
          ["FOR b := TRUE TO 10 DO n := 1 END",
          ["FOR b := TRUE TO 10 DO n := 1 END",
           "'b' is a 'BOOLEAN' variable, 'FOR' control variable must be 'INTEGER'"],
           "'b' is a 'BOOLEAN' variable, 'FOR' control variable must be 'INTEGER'"],
+         ["FOR ch := 'a' TO 10 DO n := 1 END",
+          "'ch' is a 'CHAR' variable, 'FOR' control variable must be 'INTEGER'"],
          ["FOR c := 0 TO 10 DO END", "'c' is not a variable"],
          ["FOR c := 0 TO 10 DO END", "'c' is not a variable"],
          ["FOR i := TRUE TO 10 DO n := 1 END",
          ["FOR i := TRUE TO 10 DO n := 1 END",
           "'INTEGER' expression expected to assign 'i', got 'BOOLEAN'"],
           "'INTEGER' expression expected to assign 'i', got 'BOOLEAN'"],
@@ -839,7 +874,7 @@ var testSuite = {
          "r1 := r1 * r2",
          "r1 := r1 * r2",
          "r1 := r1 / r2"),
          "r1 := r1 / r2"),
     fail(["i1 := i1 / i2", "operator DIV expected for integer division"],
     fail(["i1 := i1 / i2", "operator DIV expected for integer division"],
-         ["r1 := r1 DIV r1", "operator 'DIV' type mismatch: INTEGER expected, got 'REAL'"],
+         ["r1 := r1 DIV r1", "operator 'DIV' type mismatch: 'INTEGER' or 'BYTE' expected, got 'REAL'"],
          ["b1 := b1 + b1", "operator '+' type mismatch: numeric type expected, got 'BOOLEAN'"],
          ["b1 := b1 + b1", "operator '+' type mismatch: numeric type expected, got 'BOOLEAN'"],
          ["c1 := c1 - c1", "operator '-' type mismatch: numeric type expected, got 'CHAR'"],
          ["c1 := c1 - c1", "operator '-' type mismatch: numeric type expected, got 'CHAR'"],
          ["p1 := p1 * p1", "operator '*' type mismatch: numeric type expected, got 'PROCEDURE'"],
          ["p1 := p1 * p1", "operator '*' type mismatch: numeric type expected, got 'PROCEDURE'"],
@@ -874,7 +909,7 @@ var testSuite = {
          "set1 # set2",
          "set1 # set2",
          "i IN set1"),
          "i IN set1"),
     fail(["set1 <= i", "type mismatch: expected 'SET', got 'INTEGER'"],
     fail(["set1 <= i", "type mismatch: expected 'SET', got 'INTEGER'"],
-         ["b IN set1", "'INTEGER' expected as an element of SET, got 'BOOLEAN'"],
+         ["b IN set1", "'INTEGER' or 'BYTE' expected as an element of SET, got 'BOOLEAN'"],
          ["i IN b", "type mismatch: expected 'SET', got 'BOOLEAN'"])
          ["i IN b", "type mismatch: expected 'SET', got 'BOOLEAN'"])
     ),
     ),
 "SET operators": testWithContext(
 "SET operators": testWithContext(