2
0
Эх сурвалжийг харах

operator.js -> Operator.ob

Vladislav Folts 11 жил өмнө
parent
commit
f9f7f870d9

+ 38 - 24
src/context.js

@@ -4,7 +4,7 @@ var Cast = require("js/Cast.js");
 var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var Module = require("module.js");
-var op = require("operator.js");
+var op = require("js/Operator.js");
 var Parser = require("parser.js");
 var Procedure = require("procedure.js");
 var Class = require("rtl.js").Class;
@@ -16,6 +16,8 @@ var basicTypes = Type.basic();
 var nullCodeGenerator = Code.nullGenerator();
 var nilType = Type.nil();
 
+var castOperations = op.castOperations();
+
 function getSymbolAndScope(context, id){
     var s = context.findSymbol(id);
     if (!s)
@@ -55,7 +57,7 @@ function checkTypeMatch(from, to){
 }
 
 function checkImplicitCast(from, to){
-    var result = Cast.implicit(from, to, op);
+    var result = Cast.implicit(from, to, castOperations);
     if (!result)
         throwTypeMismatch(from, to);
     return result.make.bind(result);
@@ -77,7 +79,7 @@ function promoteExpressionType(context, left, right){
         return;
 
     var leftType = left.type();
-    if (rightType === undefined)
+    if (!rightType)
         return;
 
     checkImplicitCast(rightType, leftType);
@@ -129,7 +131,7 @@ exports.Integer = ChainedContext.extend({
     toInt: function(s){return parseInt(this.__result, 10);},
     endParse: function(){
         var n = this.toInt();
-        this.parent().handleConst(basicTypes.integer, Code.makeNumberConst(n), n.toString());
+        this.parent().handleConst(basicTypes.integer, Code.makeIntConst(n), n.toString());
     }
 });
 
@@ -154,7 +156,7 @@ exports.Real = ChainedContext.extend({
     },
     endParse: function(){
         var n = Number(this.__result);
-        this.parent().handleConst(basicTypes.real, Code.makeNumberConst(n), n.toString());
+        this.parent().handleConst(basicTypes.real, Code.makeRealConst(n), n.toString());
     }
 });
 
@@ -320,7 +322,7 @@ exports.Designator = ChainedContext.extend({
             throw new Errors.Error("ARRAY expected, got '" + type.description() + "'");
         var value = e.constValue();
         var arrayLen = Type.arrayLength(type);
-        if (value !== undefined && arrayLen != Type.openArrayLength && value.value >= arrayLen)
+        if (value && arrayLen != Type.openArrayLength && value.value >= arrayLen)
             throw new Errors.Error("index out of bounds: maximum possible index is "
                                  + (Type.arrayLength(type) - 1)
                                  + ", got " + value.value );
@@ -584,7 +586,7 @@ exports.ProcDecl = ChainedContext.extend({
         var result = this.__type.result();
         if (!result)
             throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
-        if (!Cast.implicit(type, result, op))
+        if (!Cast.implicit(type, result, castOperations))
             throw new Errors.Error(
                 "RETURN '" + result.description() + "' expected, got '"
                 + type.description() + "'");
@@ -818,26 +820,36 @@ function relationOp(leftType, rightType, literal){
     var type = useTypeInRelation(leftType, rightType);
     switch (literal){
         case "=":
-            o = Type.isString(type) ? op.equalStr : op.equal;
+            o = Type.isString(type) ? op.equalStr 
+              : Type.isInt(type)    ? op.equalInt 
+                                    : op.equalReal;
             check = equalOpTypeCheck;
             break;
         case "#":
-            o = Type.isString(type) ? op.notEqualStr : op.notEqual;
+            o = Type.isString(type) ? op.notEqualStr 
+              : Type.isInt(type)    ? op.notEqualInt
+                                    : op.notEqualReal;
             check = equalOpTypeCheck;
             break;
         case "<":
-            o = Type.isString(type) ? op.lessStr : op.less;
+            o = Type.isString(type) ? op.lessStr 
+              : Type.isInt(type)    ? op.lessInt
+                                    : op.lessReal;
             check = orderOpTypeCheck;
             break;
         case ">":
-            o = Type.isString(type) ? op.greaterStr : op.greater;
+            o = Type.isString(type) ? op.greaterStr 
+              : Type.isInt(type)    ? op.greaterInt
+                                    : op.greaterReal;
             check = orderOpTypeCheck;
             break;
         case "<=":
             if (type == basicTypes.set)
                 o = op.setInclL;
             else {
-                o = Type.isString(type) ? op.eqLessStr : op.eqLess;
+                o = Type.isString(type) ? op.eqLessStr 
+                  : Type.isInt(type)    ? op.eqLessInt
+                                        : op.eqLessReal;
                 check = orderOpTypeCheck;
             }
             break;
@@ -845,7 +857,9 @@ function relationOp(leftType, rightType, literal){
             if (type == basicTypes.set)
                 o = op.setInclR;
             else {
-                o = Type.isString(type) ? op.eqGreaterStr : op.eqGreater;
+                o = Type.isString(type) ? op.eqGreaterStr 
+                  : Type.isInt(type)    ? op.eqGreaterInt
+                                        : op.eqGreaterReal;
                 check = orderOpTypeCheck;
             }
             break;
@@ -865,10 +879,10 @@ exports.AddOperator = ChainedContext.extend({
         var o;
         if (s == "+")
             o = (type == basicTypes.set) ? op.setUnion
-                                         : assertNumericOp(type, s, op.add, op.addInt);
+                                         : assertNumericOp(type, s, op.addReal, op.addInt);
         else if (s == "-")
             o = (type == basicTypes.set) ? op.setDiff
-                                         : assertNumericOp(type, s, op.sub, op.subInt);
+                                         : assertNumericOp(type, s, op.subReal, op.subInt);
         else if (s == "OR"){
             if (type != basicTypes.bool)
                 throw new Errors.Error("BOOLEAN expected as operand of 'OR', got '"
@@ -890,14 +904,14 @@ exports.MulOperator = ChainedContext.extend({
         var o;
         if (s == "*")
             o = (type == basicTypes.set) ? op.setIntersection
-                                         : assertNumericOp(type, s, op.mul, op.mulInt);
+                                         : assertNumericOp(type, s, op.mulReal, op.mulInt);
         else if (s == "/"){
             if (type == basicTypes.set)
                 o = op.setSymmetricDiff;
             else if (Type.isInt(type))
                 throw new Errors.Error("operator DIV expected for integer division");
             else
-                o = assertNumericOp(type, s, op.div);
+                o = assertNumericOp(type, s, op.divReal);
         }
         else if (s == "DIV")
             o = assertIntOp(type, s, op.divInt);
@@ -970,9 +984,9 @@ exports.Factor = ChainedContext.extend({
         if (s == "NIL")
             parent.handleConst(nilType, undefined, "null");
         else if (s == "TRUE")
-            parent.handleConst(basicTypes.bool, Code.makeNumberConst(true), "true");
+            parent.handleConst(basicTypes.bool, Code.makeIntConst(true), "true");
         else if (s == "FALSE")
-            parent.handleConst(basicTypes.bool, Code.makeNumberConst(false), "false");
+            parent.handleConst(basicTypes.bool, Code.makeIntConst(false), "false");
         else if (s == "~")
             parent.handleLogicalNot();
     },
@@ -987,7 +1001,7 @@ exports.Set = ChainedContext.extend({
         this.__expr = "";
     },
     handleElement: function(from, fromValue, to, toValue){
-        if (fromValue !== undefined && (!to || toValue !== undefined)){
+        if (fromValue && (!to || toValue)){
             if (to)
                 for(var i = fromValue.value; i <= toValue.value; ++i)
                     this.__value |= 1 << i;
@@ -1006,7 +1020,7 @@ exports.Set = ChainedContext.extend({
     endParse: function(){
         var parent = this.parent();
         if (!this.__expr.length)
-            parent.handleConst(basicTypes.set, Code.makeNumberConst(this.__value), this.__value.toString());
+            parent.handleConst(basicTypes.set, Code.makeSetConst(this.__value), this.__value.toString());
         else{
             var code = this.rtl().makeSet(this.__expr);
             if (this.__value)
@@ -1067,7 +1081,7 @@ exports.SimpleExpression = ChainedContext.extend({
         switch(this.__unaryOperator){
             case "-":
                 o = (type == basicTypes.set) ? op.setComplement
-                                             : assertNumericOp(type, this.__unaryOperator, op.negate);
+                                             : assertNumericOp(type, this.__unaryOperator, op.negateReal, op.negateInt);
                 break;
             case "+":
                 o = assertNumericOp(type, this.__unaryOperator, op.unaryPlus);
@@ -1317,7 +1331,7 @@ exports.CaseRange = ChainedContext.extend({
             if (!Type.stringAsChar(type, {set: function(v){value = v;}}))
                 throw new Errors.Error("single-character string expected");
             type = basicTypes.ch;
-            value = Code.makeNumberConst(value);
+            value = Code.makeIntConst(value);
         }
         this.handleLabel(type, value);
     },
@@ -1483,7 +1497,7 @@ exports.ConstDecl = ChainedContext.extend({
     },
     handleExpression: function(e){
         var value = e.constValue();
-        if (value === undefined)
+        if (!value)
             throw new Errors.Error("constant expression expected");
         this.__type = e.type();
         this.__value = value;

+ 2 - 0
src/js/Cast.js

@@ -164,6 +164,8 @@ function implicit(from/*PType*/, to/*PType*/, ops/*Operations*/){
 }
 areTypesExactlyMatch = areTypesExactlyMatchImpl;
 doNothing = new CastOpDoNothing();
+exports.CastOp = CastOp;
+exports.Operations = Operations;
 exports.findPointerBaseType = findPointerBaseType;
 exports.areTypesMatch = areTypesMatch;
 exports.areProceduresMatch = areProceduresMatch;

+ 45 - 13
src/js/Code.js

@@ -1,14 +1,13 @@
 var RTL$ = require("rtl.js");
-var JS = GLOBAL;
 var JsMap = require("js/JsMap.js");
 var JsString = require("js/JsString.js");
 var Context = require("js/Context.js");
 var Object = require("js/Object.js");
 var Stream = require("js/Stream.js");
 var Symbols = require("js/Symbols.js");
+var Precedence = require("js/CodePrecedence.js");
 var Types = require("js/Types.js");
 var kTab = "\t";
-var kNoPrecedence = 0;
 var IGenerator = RTL$.extend({
 	init: function IGenerator(){
 	}
@@ -44,8 +43,20 @@ var Const = RTL$.extend({
 	init: function Const(){
 	}
 });
-var NumberConst = Const.extend({
-	init: function NumberConst(){
+var IntConst = Const.extend({
+	init: function IntConst(){
+		Const.prototype.init.call(this);
+		this.value = 0;
+	}
+});
+var RealConst = Const.extend({
+	init: function RealConst(){
+		Const.prototype.init.call(this);
+		this.value = 0;
+	}
+});
+var SetConst = Const.extend({
+	init: function SetConst(){
 		Const.prototype.init.call(this);
 		this.value = 0;
 	}
@@ -160,16 +171,30 @@ Expression.prototype.maxPrecedence = function(){
 	return this.mMaxPrecedence;
 }
 Expression.prototype.isTerm = function(){
-	return this.mDesignator == null && this.mMaxPrecedence == kNoPrecedence;
+	return this.mDesignator == null && this.mMaxPrecedence == Precedence.none;
+}
+
+function makeIntConst(n/*INTEGER*/){
+	var result = null;
+	result = new IntConst();
+	result.value = n;
+	return result;
 }
 
-function makeNumberConst(n/*REAL*/){
+function makeRealConst(n/*REAL*/){
 	var result = null;
-	result = new NumberConst();
+	result = new RealConst();
 	result.value = n;
 	return result;
 }
 
+function makeSetConst(s/*SET*/){
+	var result = null;
+	result = new SetConst();
+	result.value = s;
+	return result;
+}
+
 function makeStringConst(s/*Type*/){
 	var result = null;
 	result = new StringConst();
@@ -177,7 +202,7 @@ function makeStringConst(s/*Type*/){
 	return result;
 }
 
-function makeExpressionWithPrecedence(code/*Type*/, type/*PType*/, designator/*PDesigantor*/, constValue/*PConst*/, maxPrecedence/*INTEGER*/){
+function makeExpressionWithPrecedence(code/*Type*/, type/*PType*/, designator/*PDesignator*/, constValue/*PConst*/, maxPrecedence/*INTEGER*/){
 	var result = null;
 	result = new Expression();
 	result.mCode = code;
@@ -188,8 +213,8 @@ function makeExpressionWithPrecedence(code/*Type*/, type/*PType*/, designator/*P
 	return result;
 }
 
-function makeExpression(code/*Type*/, type/*PType*/, designator/*PDesigantor*/, constValue/*PConst*/){
-	return makeExpressionWithPrecedence(code, type, designator, constValue, kNoPrecedence);
+function makeExpression(code/*Type*/, type/*PType*/, designator/*PDesignator*/, constValue/*PConst*/){
+	return makeExpressionWithPrecedence(code, type, designator, constValue, Precedence.none);
 }
 
 function makeSimpleExpression(code/*Type*/, type/*PType*/){
@@ -248,10 +273,10 @@ function refExpression(e/*PExpression*/){
 	return result;
 }
 
-function adjustPrecedence(e/*Expression*/, precedence/*INTEGER*/){
+function adjustPrecedence(e/*PExpression*/, precedence/*INTEGER*/){
 	var result = null;
 	result = e.mCode;
-	if (e.mMaxPrecedence > precedence){
+	if (precedence != Precedence.none && e.mMaxPrecedence > precedence){
 		result = JsString.concat(JsString.concat(JsString.make("("), result), JsString.make(")"));
 	}
 	return result;
@@ -356,9 +381,16 @@ function makeModuleGenerator(name/*Type*/, imports/*Strings*/){
 	result.imports = imports;
 	return result;
 }
+exports.Designator = Designator;
+exports.Const = Const;
+exports.IntConst = IntConst;
+exports.RealConst = RealConst;
+exports.SetConst = SetConst;
 exports.Expression = Expression;
 exports.nullGenerator = function(){return nullGenerator;};
-exports.makeNumberConst = makeNumberConst;
+exports.makeIntConst = makeIntConst;
+exports.makeRealConst = makeRealConst;
+exports.makeSetConst = makeSetConst;
 exports.makeStringConst = makeStringConst;
 exports.makeExpressionWithPrecedence = makeExpressionWithPrecedence;
 exports.makeExpression = makeExpression;

+ 28 - 0
src/js/CodePrecedence.js

@@ -0,0 +1,28 @@
+var none = 0;
+var unary = 4;
+var mulDivMod = 5;
+var addSub = 6;
+var shift = 7;
+var relational = 8;
+var equal = 9;
+var bitAnd = 10;
+var bitXor = 11;
+var bitOr = 12;
+var and = 13;
+var or = 14;
+var conditional = 15;
+var assignment = 17;
+exports.none = none;
+exports.unary = unary;
+exports.mulDivMod = mulDivMod;
+exports.addSub = addSub;
+exports.shift = shift;
+exports.relational = relational;
+exports.equal = equal;
+exports.bitAnd = bitAnd;
+exports.bitXor = bitXor;
+exports.bitOr = bitOr;
+exports.and = and;
+exports.or = or;
+exports.conditional = conditional;
+exports.assignment = assignment;

+ 11 - 0
src/js/Context.js

@@ -5,6 +5,15 @@ var Scope = RTL$.extend({
 	init: function Scope(){
 	}
 });
+var Rtl = RTL$.extend({
+	init: function Rtl(){
+		this.copy = null;
+		this.strCmp = null;
+		this.assignArrayFromString = null;
+		this.setInclL = null;
+		this.setInclR = null;
+	}
+});
 var Type = RTL$.extend({
 	init: function Type(){
 		this.handleChar = null;
@@ -13,7 +22,9 @@ var Type = RTL$.extend({
 		this.handleIdent = null;
 		this.isLexem = null;
 		this.qualifyScope = null;
+		this.rtl = null;
 	}
 });
 exports.Scope = Scope;
+exports.Rtl = Rtl;
 exports.Type = Type;

+ 648 - 0
src/js/Operator.js

@@ -0,0 +1,648 @@
+var RTL$ = require("rtl.js");
+var Cast = require("js/Cast.js");
+var Code = require("js/Code.js");
+var Context = require("js/Context.js");
+var Errors = require("js/Errors.js");
+var JsString = require("js/JsString.js");
+var Precedence = require("js/CodePrecedence.js");
+var Types = require("js/Types.js");
+var CodeMaker = RTL$.extend({
+	init: function CodeMaker(){
+	}
+});
+var SimpleCodeMaker = CodeMaker.extend({
+	init: function SimpleCodeMaker(){
+		CodeMaker.prototype.init.call(this);
+		this.code = null;
+	}
+});
+var IntCodeMaker = SimpleCodeMaker.extend({
+	init: function IntCodeMaker(){
+		SimpleCodeMaker.prototype.init.call(this);
+	}
+});
+var PredCodeMaker = CodeMaker.extend({
+	init: function PredCodeMaker(){
+		CodeMaker.prototype.init.call(this);
+		this.pred = null;
+	}
+});
+var CastToUint8 = Cast.CastOp.extend({
+	init: function CastToUint8(){
+		Cast.CastOp.prototype.init.call(this);
+	}
+});
+var openArrayChar = null;
+var castOperations = new Cast.Operations();
+var castToUint8 = null;
+
+function binary(left/*PExpression*/, right/*PExpression*/, context/*Type*/, op/*BinaryOp*/, code/*PCodeMaker*/, precedence/*INTEGER*/, optResultType/*PType*/, optResultPrecedence/*INTEGER*/){
+	var result = null;
+	var leftValue = null;var rightValue = null;var resultValue = null;
+	var leftCode = null;var rightCode = null;var resultCode = null;
+	var resultType = null;
+	var resultPrecedence = 0;
+	var rightExpDeref = null;
+	leftValue = left.constValue();
+	rightValue = right.constValue();
+	if (leftValue != null && rightValue != null){
+		resultValue = op(leftValue, rightValue);
+	}
+	leftCode = Code.adjustPrecedence(Code.derefExpression(left), precedence);
+	rightExpDeref = Code.derefExpression(right);
+	if (precedence != Precedence.none){
+		rightCode = Code.adjustPrecedence(rightExpDeref, precedence - 1 | 0);
+	}
+	else {
+		rightCode = rightExpDeref.code();
+	}
+	resultCode = code.make(leftCode, rightCode, context);
+	if (optResultType != null){
+		resultType = optResultType;
+	}
+	else {
+		resultType = left.type();
+	}
+	if (optResultPrecedence != Precedence.none){
+		resultPrecedence = optResultPrecedence;
+	}
+	else {
+		resultPrecedence = precedence;
+	}
+	return Code.makeExpressionWithPrecedence(resultCode, resultType, null, resultValue, resultPrecedence);
+}
+SimpleCodeMaker.prototype.make = function(left/*Type*/, right/*Type*/, c/*Type*/){
+	return JsString.concat(JsString.concat(left, this.code), right);
+}
+IntCodeMaker.prototype.make = function(left/*Type*/, right/*Type*/, c/*Type*/){
+	return JsString.concat(SimpleCodeMaker.prototype.make.call(this, left, right, c), JsString.make(" | 0"));
+}
+PredCodeMaker.prototype.make = function(left/*Type*/, right/*Type*/, c/*Type*/){
+	return this.pred(left, right, c);
+}
+
+function makeSimpleCodeMaker(code/*ARRAY OF CHAR*/){
+	var result = null;
+	result = new SimpleCodeMaker();
+	result.code = JsString.make(code);
+	return result;
+}
+
+function makeIntCodeMaker(code/*ARRAY OF CHAR*/){
+	var result = null;
+	result = new IntCodeMaker();
+	result.code = JsString.make(code);
+	return result;
+}
+
+function makePredCodeMaker(pred/*CodePredicate*/){
+	var result = null;
+	result = new PredCodeMaker();
+	result.pred = pred;
+	return result;
+}
+
+function binaryWithCodeEx(left/*PExpression*/, right/*PExpression*/, context/*Type*/, op/*BinaryOp*/, code/*ARRAY OF CHAR*/, precedence/*INTEGER*/, optResultType/*PType*/, optResultPrecedence/*INTEGER*/){
+	return binary(left, right, context, op, makeSimpleCodeMaker(code), precedence, optResultType, optResultPrecedence);
+}
+
+function binaryWithCode(left/*PExpression*/, right/*PExpression*/, c/*Type*/, op/*BinaryOp*/, code/*ARRAY OF CHAR*/, precedence/*INTEGER*/){
+	return binaryWithCodeEx(left, right, c, op, code, precedence, null, Precedence.none);
+}
+
+function promoteToWideIfNeeded(e/*PExpression*/){
+	var result = null;
+	if (e.type() != Types.basic().uint8){
+		result = e;
+	}
+	else {
+		result = Code.makeExpressionWithPrecedence(e.code(), Types.basic().integer, e.designator(), e.constValue(), e.maxPrecedence());
+	}
+	return result;
+}
+
+function binaryInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/, op/*BinaryOp*/, code/*ARRAY OF CHAR*/, precedence/*INTEGER*/){
+	return promoteToWideIfNeeded(binary(left, right, c, op, makeIntCodeMaker(code), precedence, null, Precedence.bitOr));
+}
+
+function binaryPred(left/*PExpression*/, right/*PExpression*/, c/*Type*/, op/*BinaryOp*/, pred/*CodePredicate*/){
+	return binary(left, right, c, op, makePredCodeMaker(pred), Precedence.none, null, Precedence.none);
+}
+
+function unary(e/*PExpression*/, op/*UnaryOp*/, code/*ARRAY OF CHAR*/){
+	var value = null;
+	var resultCode = null;
+	value = e.constValue();
+	if (value != null){
+		value = op(value);
+	}
+	resultCode = JsString.concat(JsString.make(code), Code.adjustPrecedence(Code.derefExpression(e), Precedence.unary));
+	return Code.makeExpression(resultCode, e.type(), null, value);
+}
+
+function castToStr(e/*PExpression*/, context/*Type*/){
+	var resultExpression = null;
+	var op = null;
+	op = Cast.implicit(e.type(), openArrayChar, castOperations);
+	resultExpression = op.make(context, e);
+	return resultExpression.code();
+}
+
+function opAddReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeRealConst(RTL$.typeGuard(left, Code.RealConst).value + RTL$.typeGuard(right, Code.RealConst).value);
+}
+
+function opAddInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value + RTL$.typeGuard(right, Code.IntConst).value | 0);
+}
+
+function opSubReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeRealConst(RTL$.typeGuard(left, Code.RealConst).value - RTL$.typeGuard(right, Code.RealConst).value);
+}
+
+function opSubInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value - RTL$.typeGuard(right, Code.IntConst).value | 0);
+}
+
+function opMulReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeRealConst(RTL$.typeGuard(left, Code.RealConst).value * RTL$.typeGuard(right, Code.RealConst).value);
+}
+
+function opMulInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value * RTL$.typeGuard(right, Code.IntConst).value | 0);
+}
+
+function opDivReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeRealConst(RTL$.typeGuard(left, Code.RealConst).value / RTL$.typeGuard(right, Code.RealConst).value);
+}
+
+function opDivInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value / RTL$.typeGuard(right, Code.IntConst).value | 0);
+}
+
+function opMod(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value % RTL$.typeGuard(right, Code.IntConst).value);
+}
+
+function opSetUnion(left/*PConst*/, right/*PConst*/){
+	return Code.makeSetConst(RTL$.typeGuard(left, Code.SetConst).value | RTL$.typeGuard(right, Code.SetConst).value);
+}
+
+function opSetDiff(left/*PConst*/, right/*PConst*/){
+	return Code.makeSetConst(RTL$.typeGuard(left, Code.SetConst).value & ~RTL$.typeGuard(right, Code.SetConst).value);
+}
+
+function opSetIntersection(left/*PConst*/, right/*PConst*/){
+	return Code.makeSetConst(RTL$.typeGuard(left, Code.SetConst).value & RTL$.typeGuard(right, Code.SetConst).value);
+}
+
+function opSetSymmetricDiff(left/*PConst*/, right/*PConst*/){
+	return Code.makeSetConst(RTL$.typeGuard(left, Code.SetConst).value ^ RTL$.typeGuard(right, Code.SetConst).value);
+}
+
+function opSetInclL(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.setInclL(RTL$.typeGuard(left, Code.SetConst).value, RTL$.typeGuard(right, Code.SetConst).value) ? 1 : 0);
+}
+
+function opSetInclR(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.setInclR(RTL$.typeGuard(left, Code.SetConst).value, RTL$.typeGuard(right, Code.SetConst).value) ? 1 : 0);
+}
+
+function opOr(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value != 0 || RTL$.typeGuard(right, Code.IntConst).value != 0 ? 1 : 0);
+}
+
+function opAnd(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value != 0 && RTL$.typeGuard(right, Code.IntConst).value != 0 ? 1 : 0);
+}
+
+function opEqualInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value == RTL$.typeGuard(right, Code.IntConst).value ? 1 : 0);
+}
+
+function opEqualReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.RealConst).value == RTL$.typeGuard(right, Code.RealConst).value ? 1 : 0);
+}
+
+function opNotEqualInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value != RTL$.typeGuard(right, Code.IntConst).value ? 1 : 0);
+}
+
+function opNotEqualReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.RealConst).value != RTL$.typeGuard(right, Code.RealConst).value ? 1 : 0);
+}
+
+function opLessInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value < RTL$.typeGuard(right, Code.IntConst).value ? 1 : 0);
+}
+
+function opLessReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.RealConst).value < RTL$.typeGuard(right, Code.RealConst).value ? 1 : 0);
+}
+
+function opGreaterInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value > RTL$.typeGuard(right, Code.IntConst).value ? 1 : 0);
+}
+
+function opGreaterReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.RealConst).value > RTL$.typeGuard(right, Code.RealConst).value ? 1 : 0);
+}
+
+function opEqLessInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value <= RTL$.typeGuard(right, Code.IntConst).value ? 1 : 0);
+}
+
+function opEqLessReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.RealConst).value <= RTL$.typeGuard(right, Code.RealConst).value ? 1 : 0);
+}
+
+function opEqGreaterInt(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value >= RTL$.typeGuard(right, Code.IntConst).value ? 1 : 0);
+}
+
+function opEqGreaterReal(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.RealConst).value >= RTL$.typeGuard(right, Code.RealConst).value ? 1 : 0);
+}
+
+function opNot(x/*PConst*/){
+	return Code.makeIntConst(!RTL$.typeGuard(x, Code.IntConst).value != 0 ? 1 : 0);
+}
+
+function opNegateInt(x/*PConst*/){
+	return Code.makeIntConst(-RTL$.typeGuard(x, Code.IntConst).value);
+}
+
+function opNegateReal(x/*PConst*/){
+	return Code.makeRealConst(-RTL$.typeGuard(x, Code.RealConst).value);
+}
+
+function opUnaryPlus(x/*PConst*/){
+	return x;
+}
+
+function opSetComplement(x/*PConst*/){
+	return Code.makeSetConst(~RTL$.typeGuard(x, Code.SetConst).value);
+}
+
+function opLsl(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value << RTL$.typeGuard(right, Code.IntConst).value);
+}
+
+function opAsr(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value >> RTL$.typeGuard(right, Code.IntConst).value);
+}
+
+function opRor(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value >>> RTL$.typeGuard(right, Code.IntConst).value);
+}
+
+function codeSetInclL(left/*Type*/, right/*Type*/, c/*Type*/){
+	var rtl = null;
+	rtl = c.rtl();
+	return rtl.setInclL(left, right);
+}
+
+function codeSetInclR(left/*Type*/, right/*Type*/, c/*Type*/){
+	var rtl = null;
+	rtl = c.rtl();
+	return rtl.setInclR(left, right);
+}
+
+function strCmp(op/*ARRAY OF CHAR*/, left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	var rtl = null;
+	rtl = c.rtl();
+	return Code.makeSimpleExpression(JsString.concat(JsString.concat(rtl.strCmp(castToStr(left, c), castToStr(right, c)), JsString.make(op)), JsString.make("0")), Types.basic().bool);
+}
+
+function assign(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	var designator = null;
+	var info = null;
+	var leftCode = null;var rightCode = null;
+	var leftType = null;var rightType = null;
+	var isArray = false;
+	var castOperation = null;
+	var rtl = null;
+	var castExp = null;
+	var result = null;
+	
+	function assignArrayFromString(a/*Array*/, s/*String*/){
+		var rtl = null;
+		if (Types.arrayLength(a) == Types.openArrayLength){
+			Errors.raise(JsString.concat(JsString.make("string cannot be assigned to open "), a.description()));
+		}
+		else if (Types.stringLen(s) > Types.arrayLength(a)){
+			Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.fromInt(Types.arrayLength(a)), JsString.make("-character ARRAY is too small for ")), JsString.fromInt(Types.stringLen(s))), JsString.make("-character string")));
+		}
+		rtl = c.rtl();
+		return rtl.assignArrayFromString(leftCode, rightCode);
+	}
+	designator = left.designator();
+	info = designator.info();
+	if (!(info instanceof Types.Variable) || Types.isVariableReadOnly(RTL$.typeGuard(info, Types.Variable))){
+		Errors.raise(JsString.concat(JsString.make("cannot assign to "), info.idType()));
+	}
+	leftCode = left.lval();
+	rightCode = right.code();
+	leftType = left.type();
+	rightType = right.type();
+	isArray = leftType instanceof Types.Array;
+	if (isArray && Types.arrayElementsType(RTL$.typeGuard(leftType, Types.Array)) == Types.basic().ch && rightType instanceof Types.String){
+		result = assignArrayFromString(RTL$.typeGuard(leftType, Types.Array), RTL$.typeGuard(rightType, Types.String));
+	}
+	else {
+		castOperation = Cast.implicit(rightType, leftType, castOperations);
+		if (castOperation == null){
+			Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.make("type mismatch: '"), leftCode), JsString.make("' is '")), leftType.description()), JsString.make("' and cannot be assigned to '")), rightType.description()), JsString.make("' expression")));
+		}
+		if (isArray && rightType instanceof Types.Array && Types.arrayLength(RTL$.typeGuard(leftType, Types.Array)) == Types.openArrayLength){
+			Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.make("'"), leftCode), JsString.make("' is open '")), leftType.description()), JsString.make("' and cannot be assigned")));
+		}
+		if (isArray || rightType instanceof Types.Record){
+			rtl = c.rtl();
+			result = rtl.copy(rightCode, leftCode);
+		}
+		else {
+			castExp = castOperation.make(c, Code.derefExpression(right));
+			rightCode = castExp.code();
+			if (info instanceof Types.VariableRef){
+				rightCode = JsString.concat(JsString.concat(JsString.make(".set("), rightCode), JsString.make(")"));
+			}
+			else {
+				rightCode = JsString.concat(JsString.make(" = "), rightCode);
+			}
+			result = JsString.concat(leftCode, rightCode);
+		}
+	}
+	return result;
+}
+
+function inplace(left/*PExpression*/, right/*PExpression*/, c/*Type*/, code/*ARRAY OF CHAR*/, altOp/*BinaryProc*/){
+	var designator = null;
+	var rightExp = null;
+	var result = null;
+	designator = left.designator();
+	if (designator.info() instanceof Types.VariableRef){
+		result = assign(left, altOp(left, right, c), c);
+	}
+	else {
+		rightExp = Code.derefExpression(right);
+		result = JsString.concat(JsString.concat(left.code(), JsString.make(code)), rightExp.code());
+	}
+	return result;
+}
+
+function addReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opAddReal, " + ", Precedence.addSub);
+}
+
+function addInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryInt(left, right, c, opAddInt, " + ", Precedence.addSub);
+}
+
+function subReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opSubReal, " - ", Precedence.addSub);
+}
+
+function subInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryInt(left, right, c, opSubInt, " - ", Precedence.addSub);
+}
+
+function mulReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opMulReal, " * ", Precedence.mulDivMod);
+}
+
+function mulInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryInt(left, right, c, opMulInt, " * ", Precedence.mulDivMod);
+}
+
+function divReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opDivReal, " / ", Precedence.mulDivMod);
+}
+
+function divInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryInt(left, right, c, opDivInt, " / ", Precedence.mulDivMod);
+}
+
+function mod(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opMod, " % ", Precedence.mulDivMod);
+}
+
+function setUnion(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opSetUnion, " | ", Precedence.bitOr);
+}
+
+function setDiff(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opSetDiff, " & ~", Precedence.bitAnd);
+}
+
+function setIntersection(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opSetIntersection, " & ", Precedence.bitAnd);
+}
+
+function setSymmetricDiff(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opSetSymmetricDiff, " ^ ", Precedence.bitXor);
+}
+
+function setInclL(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryPred(left, right, c, opSetInclL, codeSetInclL);
+}
+
+function setInclR(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryPred(left, right, c, opSetInclR, codeSetInclR);
+}
+
+function or(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opOr, " || ", Precedence.or);
+}
+
+function and(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opAnd, " && ", Precedence.and);
+}
+
+function equalInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opEqualInt, " == ", Precedence.equal);
+}
+
+function equalReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opEqualReal, " == ", Precedence.equal);
+}
+
+function equalStr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return strCmp(" == ", left, right, c);
+}
+
+function notEqualInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opNotEqualInt, " != ", Precedence.equal);
+}
+
+function notEqualReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opNotEqualReal, " != ", Precedence.equal);
+}
+
+function notEqualStr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return strCmp(" != ", left, right, c);
+}
+
+function is(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCodeEx(left, right, c, null, " instanceof ", Precedence.relational, Types.basic().bool, Precedence.none);
+}
+
+function lessInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opLessInt, " < ", Precedence.relational);
+}
+
+function lessReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opLessReal, " < ", Precedence.relational);
+}
+
+function lessStr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return strCmp(" < ", left, right, c);
+}
+
+function greaterInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opGreaterInt, " > ", Precedence.relational);
+}
+
+function greaterReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opGreaterReal, " > ", Precedence.relational);
+}
+
+function greaterStr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return strCmp(" > ", left, right, c);
+}
+
+function eqLessInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opEqLessInt, " <= ", Precedence.relational);
+}
+
+function eqLessReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opEqLessReal, " <= ", Precedence.relational);
+}
+
+function eqLessStr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return strCmp(" <= ", left, right, c);
+}
+
+function eqGreaterInt(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opEqGreaterInt, " >= ", Precedence.relational);
+}
+
+function eqGreaterReal(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opEqGreaterReal, " >= ", Precedence.relational);
+}
+
+function eqGreaterStr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return strCmp(" >= ", left, right, c);
+}
+
+function not(x/*PExpression*/, c/*Type*/){
+	return unary(x, opNot, "!");
+}
+
+function negateInt(x/*PExpression*/, c/*Type*/){
+	return promoteToWideIfNeeded(unary(x, opNegateInt, "-"));
+}
+
+function negateReal(x/*PExpression*/, c/*Type*/){
+	return promoteToWideIfNeeded(unary(x, opNegateReal, "-"));
+}
+
+function unaryPlus(x/*PExpression*/, c/*Type*/){
+	return unary(x, opUnaryPlus, "");
+}
+
+function setComplement(x/*PExpression*/, c/*Type*/){
+	return unary(x, opSetComplement, "~");
+}
+
+function lsl(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opLsl, " << ", Precedence.shift);
+}
+
+function asr(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opAsr, " >> ", Precedence.shift);
+}
+
+function ror(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return binaryWithCode(left, right, c, opRor, " >>> ", Precedence.shift);
+}
+
+function mulInplace(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return inplace(left, right, c, " *= ", mulReal);
+}
+
+function divInplace(left/*PExpression*/, right/*PExpression*/, c/*Type*/){
+	return inplace(left, right, c, " /= ", divReal);
+}
+
+function pow2(e/*PExpression*/){
+	var derefExp = null;
+	derefExp = Code.derefExpression(e);
+	return Code.makeSimpleExpression(JsString.concat(JsString.concat(JsString.make("Math.pow(2, "), derefExp.code()), JsString.make(")")), Types.basic().real);
+}
+
+function log2(e/*PExpression*/){
+	var derefExp = null;
+	derefExp = Code.derefExpression(e);
+	return Code.makeExpressionWithPrecedence(JsString.concat(JsString.concat(JsString.make("(Math.log("), derefExp.code()), JsString.make(") / Math.LN2) | 0")), Types.basic().integer, null, null, Precedence.bitOr);
+}
+
+function opCastToUint8(left/*PConst*/, right/*PConst*/){
+	return Code.makeIntConst(RTL$.typeGuard(left, Code.IntConst).value * RTL$.typeGuard(right, Code.IntConst).value | 0);
+}
+CastToUint8.prototype.make = function(context/*Type*/, e/*PExpression*/){
+	return binaryWithCode(e, Code.makeExpression(JsString.make("0xFF"), Types.basic().integer, null, Code.makeIntConst(255)), context, opCastToUint8, " & ", Precedence.bitAnd);
+}
+openArrayChar = Types.makeArray(null, null, Types.basic().ch, Types.openArrayLength);
+castToUint8 = new CastToUint8();
+castOperations.castToUint8 = castToUint8;
+exports.castOperations = function(){return castOperations;};
+exports.assign = assign;
+exports.addReal = addReal;
+exports.addInt = addInt;
+exports.subReal = subReal;
+exports.subInt = subInt;
+exports.mulReal = mulReal;
+exports.mulInt = mulInt;
+exports.divReal = divReal;
+exports.divInt = divInt;
+exports.mod = mod;
+exports.setUnion = setUnion;
+exports.setDiff = setDiff;
+exports.setIntersection = setIntersection;
+exports.setSymmetricDiff = setSymmetricDiff;
+exports.setInclL = setInclL;
+exports.setInclR = setInclR;
+exports.or = or;
+exports.and = and;
+exports.equalInt = equalInt;
+exports.equalReal = equalReal;
+exports.equalStr = equalStr;
+exports.notEqualInt = notEqualInt;
+exports.notEqualReal = notEqualReal;
+exports.notEqualStr = notEqualStr;
+exports.is = is;
+exports.lessInt = lessInt;
+exports.lessReal = lessReal;
+exports.lessStr = lessStr;
+exports.greaterInt = greaterInt;
+exports.greaterReal = greaterReal;
+exports.greaterStr = greaterStr;
+exports.eqLessInt = eqLessInt;
+exports.eqLessReal = eqLessReal;
+exports.eqLessStr = eqLessStr;
+exports.eqGreaterInt = eqGreaterInt;
+exports.eqGreaterReal = eqGreaterReal;
+exports.eqGreaterStr = eqGreaterStr;
+exports.not = not;
+exports.negateInt = negateInt;
+exports.negateReal = negateReal;
+exports.unaryPlus = unaryPlus;
+exports.setComplement = setComplement;
+exports.lsl = lsl;
+exports.asr = asr;
+exports.ror = ror;
+exports.mulInplace = mulInplace;
+exports.divInplace = divInplace;
+exports.pow2 = pow2;
+exports.log2 = log2;

+ 5 - 5
src/ob/Cast.ob

@@ -2,11 +2,11 @@ MODULE Cast;
 IMPORT Code, Context, JsArray, JsString, Object, Types;
 
 TYPE
-    CastOp = RECORD
-        PROCEDURE make(c: Context.Type; e: Code.PExpression): Code.PExpression
+    CastOp* = RECORD
+        PROCEDURE make*(c: Context.Type; e: Code.PExpression): Code.PExpression
     END;
 
-    PCastOp = POINTER TO CastOp;
+    PCastOp* = POINTER TO CastOp;
 
     CastOpDoNothing = RECORD (CastOp)
     END;
@@ -15,8 +15,8 @@ TYPE
         c: CHAR
     END;
 
-    Operations = RECORD
-        castToUint8: PCastOp
+    Operations* = RECORD
+        castToUint8*: PCastOp
     END;
 
 VAR

+ 53 - 28
src/ob/Code.ob

@@ -1,9 +1,8 @@
 MODULE Code;
-IMPORT JsMap, JsString, Context, Object, Stream, Symbols, Types;
+IMPORT JsMap, JsString, Context, Object, Stream, Symbols, Precedence := CodePrecedence, Types;
 
 CONST
     kTab = 09X;
-    kNoPrecedence = 0;
 
 TYPE
     IGenerator = RECORD
@@ -28,12 +27,12 @@ TYPE
 
     RefCodeProc = PROCEDURE(s: JsString.Type): JsString.Type;
 
-    Designator = RECORD
+    Designator* = RECORD
         PROCEDURE code(): JsString.Type;
         PROCEDURE lval(): JsString.Type;
         PROCEDURE refCode(): RefCodeProc;
         PROCEDURE type(): Types.PType;
-        PROCEDURE info(): Types.PId;
+        PROCEDURE info*(): Types.PId;
         PROCEDURE scope(): Context.PScope;
 
         mCode: JsString.Type;
@@ -44,14 +43,22 @@ TYPE
         mScope: Context.PScope
     END;
 
-    PDesigantor = POINTER TO Designator;
+    PDesignator* = POINTER TO Designator;
 
-    Const = RECORD
+    Const* = RECORD
     END;
-    PConst = POINTER TO Const;
+    PConst* = POINTER TO Const;
 
-    NumberConst = RECORD (Const)
-        value: REAL
+    IntConst* = RECORD (Const)
+        value*: INTEGER
+    END;
+
+    RealConst* = RECORD (Const)
+        value*: REAL
+    END;
+
+    SetConst* = RECORD (Const)
+        value*: SET
     END;
 
     StringConst = RECORD (Const)
@@ -59,17 +66,17 @@ TYPE
     END;
 
     Expression* = RECORD
-        PROCEDURE code(): JsString.Type;
-        PROCEDURE lval(): JsString.Type;
-        PROCEDURE type(): Types.PType;
-        PROCEDURE designator(): PDesigantor;
-        PROCEDURE constValue(): PConst;
-        PROCEDURE maxPrecedence(): INTEGER;
+        PROCEDURE code*(): JsString.Type;
+        PROCEDURE lval*(): JsString.Type;
+        PROCEDURE type*(): Types.PType;
+        PROCEDURE designator*(): PDesignator;
+        PROCEDURE constValue*(): PConst;
+        PROCEDURE maxPrecedence*(): INTEGER;
         PROCEDURE isTerm(): BOOLEAN;
 
         mCode: JsString.Type;
         mType: Types.PType;
-        mDesignator: PDesigantor;
+        mDesignator: PDesignator;
         mConstValue: PConst;
         mMaxPrecedence: INTEGER
     END;
@@ -183,7 +190,7 @@ PROCEDURE Expression.type(): Types.PType;
     RETURN SELF.mType
 END Expression.type;
 
-PROCEDURE Expression.designator(): PDesigantor;
+PROCEDURE Expression.designator(): PDesignator;
     RETURN SELF.mDesignator
 END Expression.designator;
 
@@ -196,17 +203,35 @@ PROCEDURE Expression.maxPrecedence(): INTEGER;
 END Expression.maxPrecedence;
 
 PROCEDURE Expression.isTerm(): BOOLEAN;
-    RETURN (SELF.mDesignator = NIL) & (SELF.mMaxPrecedence = kNoPrecedence)
+    RETURN (SELF.mDesignator = NIL) & (SELF.mMaxPrecedence = Precedence.none)
 END Expression.isTerm;
 
-PROCEDURE makeNumberConst*(n: REAL): PConst;
+PROCEDURE makeIntConst*(n: INTEGER): PConst;
 VAR
-    result: POINTER TO NumberConst;
+    result: POINTER TO IntConst;
 BEGIN
     NEW(result);
     result.value := n;
     RETURN result
-END makeNumberConst;
+END makeIntConst;
+
+PROCEDURE makeRealConst*(n: REAL): PConst;
+VAR
+    result: POINTER TO RealConst;
+BEGIN
+    NEW(result);
+    result.value := n;
+    RETURN result
+END makeRealConst;
+
+PROCEDURE makeSetConst*(s: SET): PConst;
+VAR
+    result: POINTER TO SetConst;
+BEGIN
+    NEW(result);
+    result.value := s;
+    RETURN result
+END makeSetConst;
 
 PROCEDURE makeStringConst*(s: JsString.Type): PConst;
 VAR
@@ -220,7 +245,7 @@ END makeStringConst;
 PROCEDURE makeExpressionWithPrecedence*(
     code: JsString.Type; 
     type: Types.PType; 
-    designator: PDesigantor; 
+    designator: PDesignator; 
     constValue: PConst; 
     maxPrecedence: INTEGER): PExpression;
 VAR
@@ -238,10 +263,10 @@ END makeExpressionWithPrecedence;
 PROCEDURE makeExpression*(
     code: JsString.Type; 
     type: Types.PType; 
-    designator: PDesigantor; 
+    designator: PDesignator; 
     constValue: PConst)
     : PExpression;
-    RETURN makeExpressionWithPrecedence(code, type, designator, constValue, kNoPrecedence)
+    RETURN makeExpressionWithPrecedence(code, type, designator, constValue, Precedence.none)
 END makeExpression;
 
 PROCEDURE makeSimpleExpression*(
@@ -275,9 +300,9 @@ PROCEDURE Designator.scope(): Context.PScope;
     RETURN SELF.mScope
 END Designator.scope;
 
-PROCEDURE makeDesignator*(code: JsString.Type; lval: JsString.Type; refCode: RefCodeProc; type: Types.PType; info: Types.PId; scope: Context.PScope): PDesigantor;
+PROCEDURE makeDesignator*(code: JsString.Type; lval: JsString.Type; refCode: RefCodeProc; type: Types.PType; info: Types.PId; scope: Context.PScope): PDesignator;
 VAR
-    result: PDesigantor;
+    result: PDesignator;
 BEGIN
     NEW(result);
     result.mCode := code;
@@ -318,12 +343,12 @@ BEGIN
     RETURN result
 END refExpression;
 
-PROCEDURE adjustPrecedence*(e: Expression; precedence: INTEGER): JsString.Type;
+PROCEDURE adjustPrecedence*(e: PExpression; precedence: INTEGER): JsString.Type;
 VAR
     result: JsString.Type;
 BEGIN
     result := e.mCode;
-    IF e.mMaxPrecedence > precedence THEN
+    IF (precedence # Precedence.none) & (e.mMaxPrecedence > precedence) THEN
         result := JsString.concat(JsString.concat(
             JsString.make("("), 
             result), 

+ 19 - 0
src/ob/CodePrecedence.ob

@@ -0,0 +1,19 @@
+MODULE CodePrecedence;
+CONST
+    none* = 0;
+
+    unary*      = 4;
+    mulDivMod*  = 5;
+    addSub*     = 6;
+    shift*      = 7;
+    relational* = 8;
+    equal*      = 9;
+    bitAnd*     = 10;
+    bitXor*     = 11;
+    bitOr*      = 12;
+    and*        = 13;
+    or*         = 14;
+    conditional* = 15;
+    assignment* = 17;
+
+END CodePrecedence.

+ 11 - 1
src/ob/Context.ob

@@ -8,13 +8,23 @@ TYPE
     END;
     PScope* = POINTER TO Scope;
 
+    Rtl* = RECORD
+        copy*: PROCEDURE(s1, s2: JsString.Type): JsString.Type;
+        strCmp*: PROCEDURE(s1, s2: JsString.Type): JsString.Type;
+        assignArrayFromString*: PROCEDURE(s1, s2: JsString.Type): JsString.Type;
+        setInclL*: PROCEDURE(l, r: JsString.Type): JsString.Type;
+        setInclR*: PROCEDURE(l, r: JsString.Type): JsString.Type
+    END;
+    PRtl* = POINTER TO Rtl;
+
     Type* = RECORD
         handleChar*:    PROCEDURE(c: CHAR);
         handleLiteral*: PROCEDURE(s: JsString.Type): BOOLEAN;
         handleString*:  PROCEDURE(s: JsString.Type);
         handleIdent*:   PROCEDURE(s: JsString.Type);
         isLexem*:       PROCEDURE(): BOOLEAN;
-        qualifyScope*:  PROCEDURE(scope: PScope): JsString.Type
+        qualifyScope*:  PROCEDURE(scope: PScope): JsString.Type;
+        rtl*:           PROCEDURE(): PRtl
     END;
 
 END Context.

+ 798 - 0
src/ob/Operator.ob

@@ -0,0 +1,798 @@
+MODULE Operator;
+IMPORT Cast, Code, Context, Errors, JsString, Precedence := CodePrecedence, Types;
+TYPE
+    BinaryProc = PROCEDURE(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+
+    BinaryOp = PROCEDURE(left, right: Code.PConst): Code.PConst;
+    CodePredicate = PROCEDURE(left, right: JsString.Type; c: Context.Type): JsString.Type;
+
+    UnaryOp = PROCEDURE(value: Code.PConst): Code.PConst;
+
+    CodeMaker = RECORD
+        PROCEDURE make(left, right: JsString.Type; c: Context.Type): JsString.Type
+    END;
+    PCodeMaker = POINTER TO CodeMaker;
+
+    SimpleCodeMaker = RECORD (CodeMaker)
+        code: JsString.Type
+    END;
+
+    IntCodeMaker = RECORD (SimpleCodeMaker)
+    END;
+
+    PredCodeMaker = RECORD (CodeMaker)
+        pred: CodePredicate
+    END;
+
+    CastToUint8 = RECORD (Cast.CastOp)
+    END;
+
+VAR
+    openArrayChar: Types.PType;
+    castOperations*: Cast.Operations;
+    castToUint8: POINTER TO CastToUint8;
+
+PROCEDURE binary(
+    left, right: Code.PExpression; 
+    context: Context.Type;
+    op: BinaryOp;
+    code: PCodeMaker;
+    precedence: INTEGER;
+    optResultType: Types.PType;
+    optResultPrecedence: INTEGER
+    ): Code.PExpression;
+VAR
+    result: Code.PExpression;
+    leftValue, rightValue, resultValue: Code.PConst;
+    leftCode, rightCode, resultCode: JsString.Type;
+    resultType: Types.PType;
+    resultPrecedence: INTEGER;
+    rightExpDeref: Code.PExpression;
+BEGIN
+    leftValue := left.constValue();
+    rightValue := right.constValue();
+    IF (leftValue # NIL) & (rightValue # NIL) THEN
+        resultValue := op(leftValue, rightValue);
+    END;
+
+    leftCode := Code.adjustPrecedence(Code.derefExpression(left), precedence);
+
+    (* right code needs parentheses even if it has the same percedence *)
+    rightExpDeref := Code.derefExpression(right);
+    IF precedence # Precedence.none THEN
+        rightCode := Code.adjustPrecedence(rightExpDeref, precedence - 1);
+    ELSE
+        rightCode := rightExpDeref.code();
+    END;
+
+    resultCode := code.make(leftCode, rightCode, context);
+
+    IF optResultType # NIL THEN
+        resultType := optResultType;
+    ELSE
+        resultType := left.type();
+    END;
+
+    IF optResultPrecedence # Precedence.none THEN
+        resultPrecedence := optResultPrecedence;
+    ELSE
+        resultPrecedence := precedence;
+    END;
+    RETURN Code.makeExpressionWithPrecedence(resultCode, resultType, NIL, resultValue, resultPrecedence)
+END binary;
+
+PROCEDURE SimpleCodeMaker.make(left, right: JsString.Type; c: Context.Type): JsString.Type;
+    RETURN JsString.concat(JsString.concat(
+        left, 
+        SELF.code), 
+        right)
+END SimpleCodeMaker.make;
+
+PROCEDURE IntCodeMaker.make(left, right: JsString.Type; c: Context.Type): JsString.Type;
+BEGIN
+    RETURN JsString.concat(SUPER(left, right, c), JsString.make(" | 0"))
+END IntCodeMaker.make;
+
+PROCEDURE PredCodeMaker.make(left, right: JsString.Type; c: Context.Type): JsString.Type;
+BEGIN
+    RETURN SELF.pred(left, right, c)
+END PredCodeMaker.make;
+
+PROCEDURE makeSimpleCodeMaker(code: ARRAY OF CHAR): PCodeMaker;
+VAR
+    result: POINTER TO SimpleCodeMaker;
+BEGIN
+    NEW(result);
+    result.code := JsString.make(code);
+    RETURN result
+END makeSimpleCodeMaker;
+
+PROCEDURE makeIntCodeMaker(code: ARRAY OF CHAR): PCodeMaker;
+VAR
+    result: POINTER TO IntCodeMaker;
+BEGIN
+    NEW(result);
+    result.code := JsString.make(code);
+    RETURN result
+END makeIntCodeMaker;
+
+PROCEDURE makePredCodeMaker(pred: CodePredicate): PCodeMaker;
+VAR
+    result: POINTER TO PredCodeMaker;
+BEGIN
+    NEW(result);
+    result.pred := pred;
+    RETURN result
+END makePredCodeMaker;
+
+PROCEDURE binaryWithCodeEx(
+    left, right: Code.PExpression; 
+    context: Context.Type;
+    op: BinaryOp;
+    code: ARRAY OF CHAR;
+    precedence: INTEGER;
+    optResultType: Types.PType;
+    optResultPrecedence: INTEGER
+    ): Code.PExpression;
+    RETURN binary(
+        left, 
+        right, 
+        context, 
+        op, 
+        makeSimpleCodeMaker(code), 
+        precedence, 
+        optResultType, 
+        optResultPrecedence)
+END binaryWithCodeEx;
+
+PROCEDURE binaryWithCode(
+    left, right: Code.PExpression; 
+    c: Context.Type;
+    op: BinaryOp;
+    code: ARRAY OF CHAR;
+    precedence: INTEGER
+    ): Code.PExpression;
+    RETURN binaryWithCodeEx(left, right, c, op, code, precedence, NIL, Precedence.none)
+END binaryWithCode;
+
+PROCEDURE promoteToWideIfNeeded(e: Code.PExpression): Code.PExpression;
+VAR
+    result: Code.PExpression;
+BEGIN
+    IF e.type() # Types.basic.uint8 THEN
+        result := e;
+    ELSE
+        result := Code.makeExpressionWithPrecedence(
+                e.code(),
+                Types.basic.integer,
+                e.designator(),
+                e.constValue(),
+                e.maxPrecedence());
+    END;
+    RETURN result
+END promoteToWideIfNeeded;
+
+PROCEDURE binaryInt(
+    left, right: Code.PExpression; 
+    c: Context.Type;
+    op: BinaryOp;
+    code: ARRAY OF CHAR;
+    precedence: INTEGER
+    ): Code.PExpression;
+    RETURN promoteToWideIfNeeded(binary(
+        left, 
+        right, 
+        c, 
+        op, 
+        makeIntCodeMaker(code), 
+        precedence, 
+        NIL, 
+        Precedence.bitOr (* see IntCodeMaker.make *)
+        ))
+END binaryInt;
+
+PROCEDURE binaryPred(
+    left, right: Code.PExpression; 
+    c: Context.Type;
+    op: BinaryOp;
+    pred: CodePredicate
+    ): Code.PExpression;
+    RETURN binary(
+        left, 
+        right, 
+        c, 
+        op, 
+        makePredCodeMaker(pred), 
+        Precedence.none, 
+        NIL, 
+        Precedence.none
+        )
+END binaryPred;
+
+PROCEDURE unary(e: Code.PExpression; op: UnaryOp; code: ARRAY OF CHAR): Code.PExpression;
+VAR
+    value: Code.PConst;
+    resultCode: JsString.Type;
+BEGIN
+    value := e.constValue();
+    IF value # NIL THEN
+        value := op(value);
+    END;
+    resultCode := JsString.concat(
+        JsString.make(code), 
+        Code.adjustPrecedence(Code.derefExpression(e), Precedence.unary));
+    RETURN Code.makeExpression(resultCode, e.type(), NIL, value)
+END unary;
+
+PROCEDURE castToStr(e: Code.PExpression; context: Context.Type): JsString.Type;
+VAR
+    resultExpression: Code.PExpression;
+    op: Cast.PCastOp;
+BEGIN
+    op := Cast.implicit(e.type(), openArrayChar, castOperations);
+    resultExpression := op.make(context, e)
+    RETURN resultExpression.code()
+END castToStr;
+
+PROCEDURE opAddReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeRealConst(left^(Code.RealConst).value 
+                            + right^(Code.RealConst).value)
+END opAddReal;
+
+PROCEDURE opAddInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(left^(Code.IntConst).value 
+                           + right^(Code.IntConst).value)
+END opAddInt;
+
+PROCEDURE opSubReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeRealConst(left^(Code.RealConst).value 
+                            - right^(Code.RealConst).value)
+END opSubReal;
+
+PROCEDURE opSubInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(left^(Code.IntConst).value 
+                           - right^(Code.IntConst).value)
+END opSubInt;
+
+PROCEDURE opMulReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeRealConst(left^(Code.RealConst).value 
+                            * right^(Code.RealConst).value)
+END opMulReal;
+
+PROCEDURE opMulInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(left^(Code.IntConst).value 
+                           * right^(Code.IntConst).value)
+END opMulInt;
+
+PROCEDURE opDivReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeRealConst(left^(Code.RealConst).value 
+                            / right^(Code.RealConst).value)
+END opDivReal;
+
+PROCEDURE opDivInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(left^(Code.IntConst).value 
+                         DIV right^(Code.IntConst).value)
+END opDivInt;
+
+PROCEDURE opMod(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(left^(Code.IntConst).value 
+                         MOD right^(Code.IntConst).value)
+END opMod;
+
+PROCEDURE opSetUnion(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeSetConst(left^(Code.SetConst).value 
+                           + right^(Code.SetConst).value)
+END opSetUnion;
+
+PROCEDURE opSetDiff(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeSetConst(left^(Code.SetConst).value 
+                           - right^(Code.SetConst).value)
+END opSetDiff;
+
+PROCEDURE opSetIntersection(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeSetConst(left^(Code.SetConst).value 
+                           * right^(Code.SetConst).value)
+END opSetIntersection;
+
+PROCEDURE opSetSymmetricDiff(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeSetConst(left^(Code.SetConst).value 
+                           / right^(Code.SetConst).value)
+END opSetSymmetricDiff;
+
+PROCEDURE opSetInclL(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.SetConst).value 
+                              <= right^(Code.SetConst).value))
+END opSetInclL;
+
+PROCEDURE opSetInclR(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.SetConst).value 
+                              >= right^(Code.SetConst).value))
+END opSetInclR;
+
+PROCEDURE opOr(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD((left^(Code.IntConst).value # 0)
+                              OR (right^(Code.IntConst).value # 0)))
+END opOr;
+
+PROCEDURE opAnd(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD((left^(Code.IntConst).value # 0)
+                               & (right^(Code.IntConst).value # 0)))
+END opAnd;
+
+PROCEDURE opEqualInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.IntConst).value
+                               = right^(Code.IntConst).value))
+END opEqualInt;
+
+PROCEDURE opEqualReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.RealConst).value
+                               = right^(Code.RealConst).value))
+END opEqualReal;
+
+PROCEDURE opNotEqualInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.IntConst).value
+                               # right^(Code.IntConst).value))
+END opNotEqualInt;
+
+PROCEDURE opNotEqualReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.RealConst).value
+                               # right^(Code.RealConst).value))
+END opNotEqualReal;
+
+PROCEDURE opLessInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.IntConst).value
+                               < right^(Code.IntConst).value))
+END opLessInt;
+
+PROCEDURE opLessReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.RealConst).value
+                               < right^(Code.RealConst).value))
+END opLessReal;
+
+PROCEDURE opGreaterInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.IntConst).value
+                               > right^(Code.IntConst).value))
+END opGreaterInt;
+
+PROCEDURE opGreaterReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.RealConst).value
+                               > right^(Code.RealConst).value))
+END opGreaterReal;
+
+PROCEDURE opEqLessInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.IntConst).value
+                              <= right^(Code.IntConst).value))
+END opEqLessInt;
+
+PROCEDURE opEqLessReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.RealConst).value
+                              <= right^(Code.RealConst).value))
+END opEqLessReal;
+
+PROCEDURE opEqGreaterInt(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.IntConst).value
+                              >= right^(Code.IntConst).value))
+END opEqGreaterInt;
+
+PROCEDURE opEqGreaterReal(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(left^(Code.RealConst).value
+                              >= right^(Code.RealConst).value))
+END opEqGreaterReal;
+
+PROCEDURE opNot(x: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ORD(~(x^(Code.IntConst).value # 0)))
+END opNot;
+
+PROCEDURE opNegateInt(x: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(-x^(Code.IntConst).value)
+END opNegateInt;
+
+PROCEDURE opNegateReal(x: Code.PConst): Code.PConst;
+    RETURN Code.makeRealConst(-x^(Code.RealConst).value)
+END opNegateReal;
+
+PROCEDURE opUnaryPlus(x: Code.PConst): Code.PConst;
+    RETURN x
+END opUnaryPlus;
+
+PROCEDURE opSetComplement(x: Code.PConst): Code.PConst;
+    RETURN Code.makeSetConst(-x^(Code.SetConst).value)
+END opSetComplement;
+
+PROCEDURE opLsl(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(LSL(left^(Code.IntConst).value,
+                                 right^(Code.IntConst).value))
+END opLsl;
+
+PROCEDURE opAsr(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ASR(left^(Code.IntConst).value,
+                                 right^(Code.IntConst).value))
+END opAsr;
+
+PROCEDURE opRor(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(ROR(left^(Code.IntConst).value,
+                                 right^(Code.IntConst).value))
+END opRor;
+
+PROCEDURE codeSetInclL(left, right: JsString.Type; c: Context.Type): JsString.Type;
+VAR
+    rtl: Context.PRtl;
+BEGIN
+    rtl := c.rtl();
+    RETURN rtl.setInclL(left, right)
+END codeSetInclL;
+
+PROCEDURE codeSetInclR(left, right: JsString.Type; c: Context.Type): JsString.Type;
+VAR
+    rtl: Context.PRtl;
+BEGIN
+    rtl := c.rtl();
+    RETURN rtl.setInclR(left, right)
+END codeSetInclR;
+
+PROCEDURE strCmp(op: ARRAY OF CHAR; left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+VAR
+    rtl: Context.PRtl;
+BEGIN   
+    rtl := c.rtl();
+    RETURN Code.makeSimpleExpression(
+            JsString.concat(JsString.concat(
+                rtl.strCmp(castToStr(left, c), castToStr(right, c)),
+                JsString.make(op)), 
+                JsString.make("0")),
+            Types.basic.bool)
+END strCmp;
+
+PROCEDURE assign*(left, right: Code.PExpression; c: Context.Type): JsString.Type;
+VAR
+    designator: Code.PDesignator;
+    info: Types.PId;
+    leftCode, rightCode: JsString.Type;
+    leftType, rightType: Types.PType;
+    isArray: BOOLEAN;
+    castOperation: Cast.PCastOp;
+    rtl: Context.PRtl;
+    castExp: Code.PExpression;
+    result: JsString.Type;
+
+    PROCEDURE assignArrayFromString(a: Types.Array; s: Types.String): JsString.Type;
+    VAR
+        rtl: Context.PRtl;
+    BEGIN
+        IF Types.arrayLength(a) = Types.openArrayLength THEN
+            Errors.raise(JsString.concat(JsString.make("string cannot be assigned to open "),
+                                         a.description()));
+        ELSIF Types.stringLen(s) > Types.arrayLength(a) THEN
+            Errors.raise(JsString.concat(JsString.concat(JsString.concat(
+                JsString.fromInt(Types.arrayLength(a)), 
+                JsString.make("-character ARRAY is too small for ")),
+                JsString.fromInt(Types.stringLen(s))), 
+                JsString.make("-character string")));
+        END;
+        rtl := c.rtl();
+        RETURN rtl.assignArrayFromString(leftCode, rightCode)
+    END assignArrayFromString;
+BEGIN
+    designator := left.designator();
+    info := designator.info();
+    IF ~(info IS Types.PVariable) 
+        OR Types.isVariableReadOnly(info(Types.PVariable)^) THEN
+        Errors.raise(JsString.concat(JsString.make("cannot assign to "), info.idType()));
+    END; 
+
+    leftCode := left.lval();
+    rightCode := right.code();
+    leftType := left.type();
+    rightType := right.type();
+
+    isArray := leftType IS Types.PArray;
+    IF isArray
+        & (Types.arrayElementsType(leftType(Types.PArray)^) = Types.basic.ch)
+        & (rightType IS Types.PString) THEN
+        result := assignArrayFromString(leftType(Types.PArray)^, rightType(Types.PString)^);
+    ELSE
+        castOperation := Cast.implicit(rightType, leftType, castOperations);
+        IF castOperation = NIL THEN
+            Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
+                JsString.make("type mismatch: '"), 
+                leftCode),
+                JsString.make("' is '")),
+                leftType.description()),
+                JsString.make("' and cannot be assigned to '")),
+                rightType.description()),
+                JsString.make("' expression")));
+        END;
+        IF isArray & (rightType IS Types.PArray) 
+            & (Types.arrayLength(leftType(Types.PArray)^) = Types.openArrayLength) THEN
+            Errors.raise(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
+                JsString.make("'"),
+                leftCode),
+                JsString.make("' is open '")),
+                leftType.description()),
+                JsString.make("' and cannot be assigned")));
+        END;
+        IF isArray OR (rightType IS Types.PRecord) THEN
+            rtl := c.rtl();
+            result := rtl.copy(rightCode, leftCode);
+        ELSE
+            castExp := castOperation.make(c, Code.derefExpression(right));
+            rightCode := castExp.code();
+            IF info IS Types.PVariableRef THEN
+                rightCode := JsString.concat(JsString.concat(
+                    JsString.make(".set("), 
+                    rightCode), 
+                    JsString.make(")"));
+            ELSE
+                rightCode := JsString.concat(JsString.make(" = "), rightCode);
+            END;
+            result := JsString.concat(leftCode, rightCode);
+        END;
+    END;
+    RETURN result
+END assign;
+    
+PROCEDURE inplace(left, right: Code.PExpression; c: Context.Type; code: ARRAY OF CHAR; altOp: BinaryProc): JsString.Type;
+VAR
+    designator: Code.PDesignator;
+    rightExp: Code.PExpression;
+    result: JsString.Type;
+BEGIN
+    designator := left.designator();
+    IF designator.info() IS Types.PVariableRef THEN
+        result := assign(left, altOp(left, right, c), c);
+    ELSE
+        rightExp := Code.derefExpression(right);
+        result := JsString.concat(JsString.concat(
+            left.code(), 
+            JsString.make(code)), 
+            rightExp.code());
+    END;
+    RETURN result
+END inplace;
+
+PROCEDURE addReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opAddReal, " + ", Precedence.addSub)
+END addReal;
+
+PROCEDURE addInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryInt(left, right, c, opAddInt, " + ", Precedence.addSub)
+END addInt;
+
+PROCEDURE subReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opSubReal, " - ", Precedence.addSub)
+END subReal;
+
+PROCEDURE subInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryInt(left, right, c, opSubInt, " - ", Precedence.addSub)
+END subInt;
+
+PROCEDURE mulReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opMulReal, " * ", Precedence.mulDivMod)
+END mulReal;
+
+PROCEDURE mulInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryInt(left, right, c, opMulInt, " * ", Precedence.mulDivMod)
+END mulInt;
+
+PROCEDURE divReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opDivReal, " / ", Precedence.mulDivMod)
+END divReal;
+
+PROCEDURE divInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryInt(left, right, c, opDivInt, " / ", Precedence.mulDivMod)
+END divInt;
+
+PROCEDURE mod*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opMod, " % ", Precedence.mulDivMod)
+END mod;
+
+PROCEDURE setUnion*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opSetUnion, " | ", Precedence.bitOr)
+END setUnion;
+
+PROCEDURE setDiff*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opSetDiff, " & ~", Precedence.bitAnd)
+END setDiff;
+
+PROCEDURE setIntersection*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opSetIntersection, " & ", Precedence.bitAnd)
+END setIntersection;
+
+PROCEDURE setSymmetricDiff*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opSetSymmetricDiff, " ^ ", Precedence.bitXor)
+END setSymmetricDiff;
+
+PROCEDURE setInclL*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryPred(left, right, c, opSetInclL, codeSetInclL)
+END setInclL;
+
+PROCEDURE setInclR*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryPred(left, right, c, opSetInclR, codeSetInclR)
+END setInclR;
+
+PROCEDURE or*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opOr, " || ", Precedence.or)
+END or;
+
+PROCEDURE and*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opAnd, " && ", Precedence.and)
+END and;
+
+PROCEDURE equalInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opEqualInt, " == ", Precedence.equal)
+END equalInt;
+
+PROCEDURE equalReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opEqualReal, " == ", Precedence.equal)
+END equalReal;
+
+PROCEDURE equalStr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN strCmp(" == ", left, right, c)
+END equalStr;
+
+PROCEDURE notEqualInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opNotEqualInt, " != ", Precedence.equal)
+END notEqualInt;
+
+PROCEDURE notEqualReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opNotEqualReal, " != ", Precedence.equal)
+END notEqualReal;
+
+PROCEDURE notEqualStr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN strCmp(" != ", left, right, c)
+END notEqualStr;
+
+PROCEDURE is*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCodeEx(
+        left, 
+        right, 
+        c, 
+        NIL, 
+        " instanceof ", 
+        Precedence.relational, 
+        Types.basic.bool,
+        Precedence.none
+        )
+END is;
+
+PROCEDURE lessInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opLessInt, " < ", Precedence.relational)
+END lessInt;
+
+PROCEDURE lessReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opLessReal, " < ", Precedence.relational)
+END lessReal;
+
+PROCEDURE lessStr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN strCmp(" < ", left, right, c)
+END lessStr;
+
+PROCEDURE greaterInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opGreaterInt, " > ", Precedence.relational)
+END greaterInt;
+
+PROCEDURE greaterReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opGreaterReal, " > ", Precedence.relational)
+END greaterReal;
+
+PROCEDURE greaterStr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN strCmp(" > ", left, right, c)
+END greaterStr;
+
+PROCEDURE eqLessInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opEqLessInt, " <= ", Precedence.relational)
+END eqLessInt;
+
+PROCEDURE eqLessReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opEqLessReal, " <= ", Precedence.relational)
+END eqLessReal;
+
+PROCEDURE eqLessStr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN strCmp(" <= ", left, right, c)
+END eqLessStr;
+
+PROCEDURE eqGreaterInt*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opEqGreaterInt, " >= ", Precedence.relational)
+END eqGreaterInt;
+
+PROCEDURE eqGreaterReal*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opEqGreaterReal, " >= ", Precedence.relational)
+END eqGreaterReal;
+
+PROCEDURE eqGreaterStr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN strCmp(" >= ", left, right, c)
+END eqGreaterStr;
+
+PROCEDURE not*(x: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN unary(x, opNot, "!")
+END not;
+
+PROCEDURE negateInt*(x: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN promoteToWideIfNeeded(unary(x, opNegateInt, "-"))
+END negateInt;
+
+PROCEDURE negateReal*(x: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN promoteToWideIfNeeded(unary(x, opNegateReal, "-"))
+END negateReal;
+
+PROCEDURE unaryPlus*(x: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN unary(x, opUnaryPlus, "")
+END unaryPlus;
+
+PROCEDURE setComplement*(x: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN unary(x, opSetComplement, "~")
+END setComplement;
+
+PROCEDURE lsl*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opLsl, " << ", Precedence.shift)
+END lsl;
+
+PROCEDURE asr*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opAsr, " >> ", Precedence.shift)
+END asr;
+
+PROCEDURE ror*(left, right: Code.PExpression; c: Context.Type): Code.PExpression;
+    RETURN binaryWithCode(left, right, c, opRor, " >>> ", Precedence.shift)
+END ror;
+
+PROCEDURE mulInplace*(left, right: Code.PExpression; c: Context.Type): JsString.Type;
+    RETURN inplace(left, right, c, " *= ", mulReal)
+END mulInplace;
+
+PROCEDURE divInplace*(left, right: Code.PExpression; c: Context.Type): JsString.Type;
+    RETURN inplace(left, right, c, " /= ", divReal)
+END divInplace;
+
+PROCEDURE pow2*(e: Code.PExpression): Code.PExpression;
+VAR
+    derefExp: Code.PExpression;
+BEGIN
+    derefExp := Code.derefExpression(e);
+    RETURN Code.makeSimpleExpression(
+            JsString.concat(JsString.concat(
+                JsString.make("Math.pow(2, "),
+                derefExp.code()),
+                JsString.make(")")),
+            Types.basic.real)
+END pow2;
+
+PROCEDURE log2*(e: Code.PExpression): Code.PExpression;
+VAR
+    derefExp: Code.PExpression;
+BEGIN
+    derefExp := Code.derefExpression(e);
+    RETURN Code.makeExpressionWithPrecedence(
+            JsString.concat(JsString.concat(
+                JsString.make("(Math.log("),
+                derefExp.code()),
+                JsString.make(") / Math.LN2) | 0")),
+            Types.basic.integer,
+            NIL,
+            NIL,
+            Precedence.bitOr)
+END log2;
+
+PROCEDURE opCastToUint8(left, right: Code.PConst): Code.PConst;
+    RETURN Code.makeIntConst(left^(Code.IntConst).value 
+                           * right^(Code.IntConst).value)
+END opCastToUint8;
+
+PROCEDURE CastToUint8.make(context: Context.Type; e: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(
+        e, 
+        Code.makeExpression(JsString.make("0xFF"), 
+                            Types.basic.integer, 
+                            NIL, 
+                            Code.makeIntConst(0FFH)), 
+        context, 
+        opCastToUint8, 
+        " & ", 
+        Precedence.bitAnd)
+END CastToUint8.make;
+
+BEGIN
+    openArrayChar := Types.makeArray(NIL, NIL, Types.basic.ch, Types.openArrayLength);
+
+    NEW(castToUint8);
+    castOperations.castToUint8 := castToUint8;
+END Operator.

+ 2 - 2
src/ob/Types.ob

@@ -6,13 +6,13 @@ CONST
 
 TYPE
     Id* = RECORD(Object.Type)
-        PROCEDURE idType(): JsString.Type
+        PROCEDURE idType*(): JsString.Type
     END;
 
     PId* = POINTER TO Id;
     
     Type* = RECORD(Object.Type)
-        PROCEDURE description(): JsString.Type
+        PROCEDURE description*(): JsString.Type
     END;
     PType* = POINTER TO Type;
 

+ 0 - 230
src/operator.js

@@ -1,230 +0,0 @@
-"use strict";
-
-var Cast = require("js/Cast.js");
-var Code = require("js/Code.js");
-var Errors = require("js/Errors.js");
-var Type = require("js/Types.js");
-
-var basicTypes = Type.basic();
-
-var precedence = {
-    unary: 4,
-    mulDivMod: 5,
-    addSub: 6,
-    shift: 7,
-    relational: 8,
-    equal: 9,
-    bitAnd: 10,
-    bitXor: 11,
-    bitOr: 12,
-    and: 13,
-    or: 14,
-    conditional: 15,
-    assignment: 17
-};
-
-function makeBinary(op, code, precedence, resultPrecedence, resultType){
-    return function(left, right, context){
-        var leftValue = left.constValue();
-        var rightValue = right.constValue();
-        var value = (leftValue && rightValue)
-            ? Code.makeNumberConst(op(leftValue.value, rightValue.value)) : undefined;
-
-        var leftCode = Code.adjustPrecedence(Code.derefExpression(left), precedence);
-
-        // right code needs parentheses even if it has the same percedence
-        var rightCode = Code.adjustPrecedence(Code.derefExpression(right), precedence - 1);
-        var expCode = (typeof code == "function")
-                    ? code(leftCode, rightCode, context)
-                    : leftCode + code + rightCode;
-        return Code.makeExpressionWithPrecedence(expCode, resultType ? resultType : left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
-    };
-}
-
-function makeUnary(op, code){
-    return function(e){
-        var type = e.type();
-        var value = e.constValue();
-        if (value)
-            value = Code.makeNumberConst(op(value.value, type));
-        var expCode = code + Code.adjustPrecedence(Code.derefExpression(e), precedence.unary);
-        return Code.makeExpression(expCode, type, undefined, value);
-    };
-}
-
-var mul = makeBinary(function(x, y){return x * y;}, " * ", precedence.mulDivMod);
-var div = makeBinary(function(x, y){return x / y;}, " / ", precedence.mulDivMod);
-
-var openArrayChar = Type.makeArray(undefined, undefined, basicTypes.ch, 0);
-
-function castToStr(e, context){
-    var type = e.type();
-    var opCast = Cast.implicit(type, openArrayChar);
-    return opCast.make(context, e).code();
-}
-
-var castToUint8 = {
-    make: function (context, e){
-        return exports.setIntersection(e, Code.makeExpression("0xFF", basicTypes.integer, null, 0xFF));
-    }
-};
-
-function makeStrCmp(op){
-    return function(left, right, context){
-        return Code.makeExpression(
-            context.rtl().strCmp(castToStr(left, context),
-                                 castToStr(right, context))
-                + op + "0",
-            basicTypes.bool
-        );
-    };
-}
-
-function pow2(e){
-    return Code.makeExpression("Math.pow(2, " + Code.derefExpression(e).code() + ")",
-                               basicTypes.real);
-}
-
-function log2(e){
-    return Code.makeExpressionWithPrecedence(
-        "(Math.log(" + Code.derefExpression(e).code() + ") / Math.LN2) | 0",
-        basicTypes.integer, undefined, undefined, precedence.bitOr);
-}
-
-function assign(left, right, context){
-    var info = left.designator().info();
-    if (!(info instanceof Type.Variable) || Type.isVariableReadOnly(info))
-        throw new Errors.Error("cannot assign to " + info.idType());
-
-    var leftCode = left.lval();
-    var leftType = left.type();
-    var rightCode = right.code();
-    var rightType = right.type();
-
-    var isArray = leftType instanceof Type.Array;
-    if (isArray
-        && Type.arrayElementsType(leftType) == basicTypes.ch
-        && rightType instanceof Type.String){
-        if (Type.arrayLength(leftType) == Type.openArrayLength)
-            throw new Errors.Error("string cannot be assigned to open " + leftType.description());
-        if (Type.stringLen(rightType) > Type.arrayLength(leftType))
-            throw new Errors.Error(
-                Type.arrayLength(leftType) + "-character ARRAY is too small for "
-                + Type.stringLen(rightType) + "-character string");
-        return context.rtl().assignArrayFromString(leftCode, rightCode);
-    }
-
-    var castOperation = Cast.implicit(rightType, leftType, exports);
-    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 (Type.arrayLength(leftType) == Type.openArrayLength)
-            throw new Errors.Error("'" + leftCode
-                                 + "' is open '" + leftType.description()
-                                 + "' and cannot be assigned");
-    }
-    
-    if (isArray || rightType instanceof Type.Record)
-        return context.rtl().copy(rightCode, leftCode);
-
-    var castCode = castOperation.make(context, Code.derefExpression(right)).code();
-    rightCode = castCode ? castCode : rightCode;
-    return leftCode + (info instanceof Type.VariableRef 
-                      ? ".set(" + rightCode + ")"
-                      : " = " + rightCode);
-}
-
-function makeInplace(code, altOp){
-    return function(left, right){
-        var info = left.designator().info();
-        if (info instanceof Type.VariableRef)
-            return assign(left, altOp(left, right));
-        return left.code() + code + Code.derefExpression(right).code();
-    };
-}
-
-function promoteToWideIfNeeded(op){
-    return function(){
-        var result = op.apply(this, arguments);
-        if (result.type() == basicTypes.uint8)
-            result = Code.makeExpressionWithPrecedence(
-                result.code(),
-                basicTypes.integer,
-                result.designator(),
-                result.constValue(),
-                result.maxPrecedence());
-        return result;
-    };
-}
-
-function makeBinaryInt(op, code, prec){
-    return promoteToWideIfNeeded(makeBinary(
-            function(x, y){return op(x, y) | 0;},
-            function(x, y){return x + code + y + " | 0";},
-            prec,
-            precedence.bitOr));
-}
-
-var operators = {
-    add:    makeBinary(   function(x, y){return x + y;}, " + ", precedence.addSub),
-    addInt: makeBinaryInt(function(x, y){return x + y;}, " + ", precedence.addSub),
-    sub:    makeBinary(   function(x, y){return x - y;}, " - ", precedence.addSub),
-    subInt: makeBinaryInt(function(x, y){return x - y;}, " - ", precedence.addSub),
-    mul:    mul,
-    mulInt: makeBinaryInt(function(x, y){return x * y;}, " * ", precedence.mulDivMod),
-    div:    div,
-    divInt: makeBinaryInt(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),
-    equalStr:   makeStrCmp(" == "),
-    notEqual:   makeBinary(function(x, y){return x != y;}, " != ", precedence.equal),
-    notEqualStr: makeStrCmp(" != "),
-    is:         makeBinary(undefined, " instanceof ", precedence.relational, undefined, basicTypes.bool),
-    less:       makeBinary(function(x, y){return x < y;}, " < ", precedence.relational),
-    lessStr:    makeStrCmp(" < "),
-    greater:    makeBinary(function(x, y){return x > y;}, " > ", precedence.relational),
-    greaterStr: makeStrCmp(" > "),
-    eqLess:     makeBinary(function(x, y){return x <= y;}, " <= ", precedence.relational),
-    eqLessStr:  makeStrCmp(" <= "),
-    eqGreater:  makeBinary(function(x, y){return x >= y;}, " >= ", precedence.relational),
-    eqGreaterStr: makeStrCmp(" >= "),
-
-    not:        makeUnary(function(x){return !x;}, "!"),
-    negate:     promoteToWideIfNeeded(makeUnary(function(x){return -x;}, "-")),
-    unaryPlus:  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),
-
-    assign:     assign,
-    mulInplace: makeInplace(" *= ", mul),
-    divInplace: makeInplace(" /= ", div),
-    
-    pow2:       pow2,
-    log2:       log2,
-
-    castToUint8: castToUint8
-};
-
-for(var p in operators)
-    exports[p] = operators[p];
-exports.precedence = precedence;

+ 13 - 7
src/procedure.js

@@ -4,8 +4,8 @@ var Cast = require("js/Cast.js");
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
-var op = require("operator.js");
-var precedence = require("operator.js").precedence;
+var op = require("js/Operator.js");
+var precedence = require("js/CodePrecedence.js");
 var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
@@ -80,7 +80,7 @@ var ProcCallGenerator = Class.extend({
         var expectType = arg.type; // can be undefined for predefined functions (like NEW), dont check it in this case
         if (expectType){
             var type = e.type();
-            castOperation = Cast.implicit(type, expectType, op);
+            castOperation = Cast.implicit(type, expectType, op.castOperations());
             if (!castOperation)
                 throw new Errors.Error(
                       "type mismatch for argument " + (pos + 1) + ": '" + type.description()
@@ -229,7 +229,7 @@ function incImpl(name, unary, op){
 
         var value = y.constValue();
         var valueCode;
-        if (value === undefined)
+        if (!value)
             valueCode = y.code();
         else {
             var comment = y.isTerm() ? "" : "/*" + y.code() + "*/";
@@ -454,8 +454,14 @@ exports.predefined = [
             },
             callExpression: function(){
                 var e = this.args()[0];
+                var value = e.constValue();
                 return Code.makeExpressionWithPrecedence(
-                    e.code(), basicTypes.real, undefined, e.constValue(), e.maxPrecedence());
+                    e.code(), 
+                    basicTypes.real, 
+                    undefined, 
+                    value ? Code.makeRealConst(value.value) : value, 
+                    e.maxPrecedence()
+                    );
             }
         });
         var args = [makeArg(basicTypes.integer, false)];
@@ -488,8 +494,8 @@ exports.predefined = [
                 else if (type == basicTypes.bool){
                     var code = Code.adjustPrecedence(e, precedence.conditional) + " ? 1 : 0";
                     var value = e.constValue();
-                    if (value !== undefined)
-                        value = Code.makeNumberConst(value.value ? 1 : 0);
+                    if (value)
+                        value = Code.makeIntConst(value.value ? 1 : 0);
                     this.__callExpression = Code.makeExpressionWithPrecedence(
                         code, basicTypes.integer, undefined, value, precedence.conditional);
                 }

+ 2 - 2
src/rtl.js

@@ -36,8 +36,8 @@ var impl = {
             else
                 fromStr = "" + from;
             
-            if (to && to.constructor && to.constructor.name)
-                toStr = "" + to.constructor.name;
+            if (to.name)
+                toStr = "" + to.name;
             else
                 toStr = "" + to;
             

+ 2 - 2
test/expected/cast.js

@@ -23,8 +23,8 @@ var RTL$ = {
             else
                 fromStr = "" + from;
             
-            if (to && to.constructor && to.constructor.name)
-                toStr = "" + to.constructor.name;
+            if (to.name)
+                toStr = "" + to.name;
             else
                 toStr = "" + to;
             

+ 2 - 2
test/expected/modules.js

@@ -23,8 +23,8 @@ var RTL$ = {
             else
                 fromStr = "" + from;
             
-            if (to && to.constructor && to.constructor.name)
-                toStr = "" + to.constructor.name;
+            if (to.name)
+                toStr = "" + to.name;
             else
                 toStr = "" + to;
             

+ 2 - 0
test/test_unit.js

@@ -404,6 +404,8 @@ return {
     context(grammar.statement, "VAR ch: CHAR; i: INTEGER; b: BOOLEAN;"),
     pass("i := ORD(ch)",
          "i := ORD(TRUE)",
+         "i := ORD(b)",
+         "i := ORD(b = FALSE)",
          "i := ORD({1})",
          "i := ORD(\"a\")",
          "b := ORD(22X) = 022H"),