Explorar o código

code.js -> Code.ob
symbol.js -> Symbols.ob
Fix incorrect code generation for ~(object IS Type) - Issue #46.

Vladislav Folts %!s(int64=11) %!d(string=hai) anos
pai
achega
1d6154f38e

+ 3 - 3
src/cast.js

@@ -1,5 +1,5 @@
 "use strict";
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Type = require("js/Types.js");
 var ArrayType = Type.Array;
 var PointerType = Type.Pointer;
@@ -78,14 +78,14 @@ function implicitCast(from, to, ops){
 
     if (from == basicTypes.integer && to == basicTypes.uint8)
         return function(context, e){
-            return ops.setIntersection(e, new Code.Expression("0xFF", basicTypes.integer, undefined, 0xFF));
+            return ops.setIntersection(e, Code.makeExpression("0xFF", basicTypes.integer, null, 0xFF));
         };
 
     if (from instanceof Type.String){
         if (to === basicTypes.ch){
             var v;
             if (Type.stringAsChar(from, {set: function(value){v = value;}}))
-                return function(){return new Code.Expression(v, to);};
+                return function(){return Code.makeExpression(v, to);};
         }
         else if (to instanceof Type.Array && Type.arrayElementsType(to) == basicTypes.ch)
             return doNoting;

+ 0 - 149
src/code.js

@@ -1,149 +0,0 @@
-"use strict";
-
-var Class = require("rtl.js").Class;
-var Type = require("js/Types.js");
-
-var NullCodeGenerator = Class.extend({
-	init: function NullCodeGenerator(){},
-	write: function(){},
-    openScope: function(){},
-    closeScope: function(){},
-    getResult: function(){}
-});
-
-exports.Generator = Class.extend({
-	init: function CodeGenerator(){
-		this.__result = "";
-		this.__indent = "";
-	},
-	write: function(s){
-		this.__result += s.replace(/\n/g, "\n" + this.__indent);
-	},
-	openScope: function(){
-		this.__indent += "\t";
-		this.__result += "{\n" + this.__indent;
-	},
-	closeScope: function(ending){
-		this.__indent = this.__indent.substr(1);
-		this.__result = this.__result.substr(0, this.__result.length - 1) + "}";
-		if (ending)
-			this.write(ending);
-		else
-			this.write("\n");
-	},
-	getResult: function(){return this.__result;}
-});
-
-exports.SimpleGenerator = Class.extend({
-	init: function SimpleCodeGenerator(code){this.__result = code ? code : "";},
-	write: function(s){this.__result += s;},
-	result: function(){return this.__result;}
-});
-
-var Expression = Class.extend({
-	init: function Expression(code, type, designator, constValue, maxPrecedence){
-        this.__code = code;
-        this.__type = type;
-        this.__designator = designator;
-        this.__constValue = constValue;
-        this.__maxPrecedence = maxPrecedence;
-    },
-    code: function(){return this.__code;},
-    lval: function(){return this.__designator ? this.__designator.lval() : this.__code;},
-    type: function(){return this.__type;},
-    designator: function(){return this.__designator;},
-    constValue: function(){return this.__constValue;},
-    maxPrecedence: function(){return this.__maxPrecedence;},
-    isTerm: function(){return !this.__designator && this.__maxPrecedence === undefined;},
-    deref: function(){
-        if (!this.__designator)
-            return this;
-        if (this.__type instanceof Type.Array || this.__type instanceof Type.Record)
-            return this;
-        var info = this.__designator.info();
-        if (!(info instanceof Type.VariableRef))
-            return this;
-        return new Expression(this.__code + ".get()", this.__type);
-    },
-    ref: function(){
-        if (!this.__designator)
-            return this;
-        
-        var info = this.__designator.info();
-        if (info instanceof Type.VariableRef)
-            return this;
-
-        return new Expression(this.__designator.refCode(), this.__type);
-    }
-});
-
-function adjustPrecedence(e, precedence){
-    var code = e.code();
-    if (e.maxPrecedence() > precedence)
-        code = "(" + code + ")";
-    return code;
-}
-
-function genExport(symbol){
-    if (symbol.isVariable())
-        return "function(){return " + symbol.id() + ";}";
-    if (symbol.isType()){
-        var type = symbol.info().type();
-        if (!(type instanceof Type.Record 
-              || (type instanceof Type.Pointer && !Type.typeName(Type.pointerBase(type)))))
-            return undefined;
-    }
-    return symbol.id();
-}
-
-var ModuleGenerator = Class.extend({
-    init: function Code$ModuleGenerator(name, imports){
-        this.__name = name;
-        this.__imports = imports;
-    },
-    prolog: function(){
-        var result = "";            
-        var modules = this.__imports;
-        for(var name in modules){
-            var alias = modules[name];
-            if (result.length)
-                result += ", ";
-            result += alias;
-        }
-        return "var " + this.__name + " = function " + "(" + result + "){\n";
-    },
-    epilog: function(exports){
-        var result = "";
-        for(var access in exports){
-            var e = exports[access];
-            var code = genExport(e);
-            if (code){
-                if (result.length)
-                    result += ",\n";
-                result += "\t" + e.id() + ": " + code;
-            }
-        }
-        if (result.length)
-            result = "return {\n" + result + "\n}\n";
-        
-        result += "}(";
-
-        var modules = this.__imports;
-        var importList = "";
-        for(var name in modules){
-            if (importList.length)
-                importList += ", ";
-            importList += name;
-        }
-        result += importList;
-        result += ");\n";
-
-        return result;
-    }
-});
-
-exports.nullGenerator = new NullCodeGenerator();
-exports.Expression = Expression;
-exports.adjustPrecedence = adjustPrecedence;
-exports.genExport = genExport;
-exports.ModuleGenerator = ModuleGenerator;

+ 49 - 38
src/context.js

@@ -1,7 +1,7 @@
 "use strict";
 
 var Cast = require("cast.js");
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var Module = require("module.js");
 var op = require("operator.js");
@@ -9,10 +9,11 @@ var Parser = require("parser.js");
 var Procedure = require("procedure.js");
 var Class = require("rtl.js").Class;
 var Scope = require("scope.js");
-var Symbol = require("symbol.js");
+var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
 var basicTypes = Type.basic();
+var nullCodeGenerator = Code.nullGenerator();
 
 function getSymbolAndScope(context, id){
     var s = context.findSymbol(id);
@@ -64,7 +65,7 @@ function promoteTypeInExpression(e, type){
     if (type == basicTypes.ch && fromType instanceof Type.String){
         var v;
         if (Type.stringAsChar(fromType, {set: function(value){v = value;}}))
-            return new Code.Expression(v, type);
+            return Code.makeExpression(v, type);
     }
     return e;
 }
@@ -204,7 +205,7 @@ exports.BaseType = ChainedContext.extend({
         this.parent().setBaseType(unwrapType(s.symbol().info()));
     }
 });
-
+/*
 var DesignatorInfo = Class.extend({
     init: function(code, lval, refCode, type, info, scope){
         this.__code = code;
@@ -221,7 +222,7 @@ var DesignatorInfo = Class.extend({
     info: function(){return this.__info;},
     scope: function(){return this.__scope;}
 });
-
+*/
 exports.QualifiedIdentificator = ChainedContext.extend({
     init: function QualifiedIdentificator(context){
         ChainedContext.prototype.init.call(this, context);
@@ -292,12 +293,14 @@ exports.Designator = ChainedContext.extend({
         this.__scope = found.scope();
         var s = found.symbol();
         var info = s.info();
-        if (info instanceof Type.Type || s.isType() || s.isProcedure())
+        if (info instanceof Type.Type || s.isType())
             this.__currentType = info;
         else if (s.isConst())
             this.__currentType = Type.constType(info);
         else if (s.isVariable())
             this.__currentType = Type.variableType(info);
+        else if (s.isProcedure())
+            this.__currentType = Type.procedureType(info);
         this.__info = info;
         this.__code += code;
     },
@@ -344,7 +347,7 @@ exports.Designator = ChainedContext.extend({
     handleLiteral: function(s){
         if (s == "]" || s == ","){
             this.__handleIndexExpression();
-            var indexCode = this.__indexExpression.deref().code();
+            var indexCode = Code.derefExpression(this.__indexExpression).code();
             this.__propCode = indexCode;
             var code = this.__derefCode + "[" + indexCode + "]";
             if (this.__currentType == basicTypes.ch){
@@ -412,7 +415,7 @@ exports.Designator = ChainedContext.extend({
         var self = this;
         var refCode = function(code){return self.__makeRefCode(code);};
         this.parent().setDesignator(
-            new DesignatorInfo(code, this.__lval ? this.__lval : code, refCode, this.__currentType, this.__info, this.__scope));
+            Code.makeDesignator(code, this.__lval ? this.__lval : code, refCode, this.__currentType, this.__info, this.__scope));
     },
     __makeRefCode: function(code){
         if (   this.__currentType instanceof Type.Array
@@ -550,7 +553,9 @@ exports.ProcDecl = ChainedContext.extend({
     _prolog: function(){return "\nfunction " + this.__id.id() + "(";},
     typeName: function(){return undefined;},
     setType: function(type){
-        var procSymbol = new Symbol.Symbol(this.__id.id(), type);
+        var procSymbol = Symbol.makeSymbol(
+            this.__id.id(), 
+            Type.makeProcedure(type));
         this.__outerScope.addSymbol(procSymbol, this.__id.exported());
         this.__type = type;
     },
@@ -560,7 +565,7 @@ exports.ProcDecl = ChainedContext.extend({
         var readOnly = !arg.isVar && (arg.type instanceof Type.Array);
         var v = arg.isVar ? Type.makeVariableRef(arg.type)
                           : Type.makeVariable(arg.type, readOnly);
-        var s = new Symbol.Symbol(name, v);
+        var s = Symbol.makeSymbol(name, v);
         this.currentScope().addSymbol(s);
 
         var code = this.codeGenerator();
@@ -614,11 +619,11 @@ exports.Return = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         this.__expr = undefined;
     },
-    codeGenerator: function(){return Code.nullGenerator;},
+    codeGenerator: function(){return nullCodeGenerator;},
     handleExpression: function(e){this.__expr = e;},
     endParse: function(){
         var parent = this.parent();
-        parent.codeGenerator().write("return " + this.__expr.deref().code() + ";\n");
+        parent.codeGenerator().write("return " + Code.derefExpression(this.__expr).code() + ";\n");
         parent.handleReturn(this.__expr.type());
     }
 });
@@ -684,8 +689,8 @@ exports.PointerDecl = ChainedContext.extend({
         scope.addUnresolved(id);
         var resolve = function(){return getSymbol(parent, id).info().type();};
 
-        return new Symbol.Found(
-            new Symbol.Symbol(id, Type.makeForwardTypeId(resolve)),
+        return Symbol.makeFound(
+            Symbol.makeSymbol(id, Type.makeForwardTypeId(resolve)),
             scope
             );
     },
@@ -731,7 +736,7 @@ exports.ArrayDimensions = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         this.__dimensions = [];
     },
-    codeGenerator: function(){return Code.nullGenerator;},
+    codeGenerator: function(){return nullCodeGenerator;},
     handleExpression: function(e){
         var type = e.type();
         if (type !== basicTypes.integer)
@@ -940,7 +945,7 @@ exports.Term = ChainedContext.extend({
         if (info instanceof Type.Const)
             value = Type.constValue(info);
         this.handleExpression(
-            new Code.Expression(d.code(), d.type(), d, value));
+            Code.makeExpression(d.code(), d.type(), d, value));
     },
     handleLogicalNot: function(){
         this.__logicalNot = !this.__logicalNot;
@@ -948,7 +953,7 @@ exports.Term = ChainedContext.extend({
     },
     handleOperator: function(o){this.__operator = o;},
     handleConst: function(type, value, code){
-        this.handleExpression(new Code.Expression(
+        this.handleExpression(Code.makeExpression(
             code, type, undefined, value));
     },
     handleFactor: function(e){
@@ -1022,7 +1027,7 @@ exports.Set = ChainedContext.extend({
             var code = this.rtl().makeSet(this.__expr);
             if (this.__value)
                 code += " | " + this.__value;
-            var e = new Code.Expression(code, basicTypes.set);
+            var e = Code.makeExpression(code, basicTypes.set);
             parent.handleFactor(e);
         }
     }
@@ -1035,7 +1040,7 @@ exports.SetElement = ChainedContext.extend({
         this.__fromValue = undefined;
         this.__to = undefined;
         this.__toValue = undefined;
-        this.__expr = new Code.SimpleGenerator();
+        this.__expr = Code.makeSimpleGenerator();
     },
     codeGenerator: function(){return this.__expr;},
     handleExpression: function(e){
@@ -1044,7 +1049,7 @@ exports.SetElement = ChainedContext.extend({
             {
             this.__from = this.__expr.result();
             this.__fromValue = value;
-            this.__expr = new Code.SimpleGenerator();
+            this.__expr = Code.makeSimpleGenerator();
             }
         else{
             this.__to = this.__expr.result();
@@ -1123,6 +1128,7 @@ exports.Expression = ChainedContext.extend({
         var rightExpression = e;
         var rightType = rightExpression.type();
         var rightCode = rightExpression.code();
+        var resultExpression;
         var code;
 
         if (this.__relation == "IN"){
@@ -1145,8 +1151,10 @@ exports.Expression = ChainedContext.extend({
                 throw new Errors.Error("POINTER to type expected after 'IS'");
 
             checkTypeCast(leftType, rightType, "invalid type test");
-
-            code = leftCode + " instanceof " + castCode(rightType, this);
+            //rightExpression = , rightType);
+            resultExpression = op.is(leftExpression, Code.makeExpression(castCode(rightType, this)));
+            code = resultExpression.code();
+            //code = leftCode + " instanceof " + castCode(rightType, this);
         }
         else {
             leftExpression = promoteTypeInExpression(leftExpression, rightType);
@@ -1164,12 +1172,14 @@ exports.Expression = ChainedContext.extend({
             value = oResult.constValue();
         }
 
-        this.__expression = new Code.Expression(code, basicTypes.bool, undefined, value);
+        this.__expression = resultExpression 
+                          ? resultExpression
+                          : Code.makeExpression(code, basicTypes.bool, undefined, value);
     },
     handleLiteral: function(relation){
         this.__relation = relation;
     },
-    codeGenerator: function(){return Code.nullGenerator;},
+    codeGenerator: function(){return nullCodeGenerator;},
     endParse: function(){
         var parent = this.parent();
         parent.codeGenerator().write(this.__expression.code());
@@ -1310,7 +1320,7 @@ exports.CaseRange = ChainedContext.extend({
         this.__from = undefined;
         this.__to = undefined;
     },
-    codeGenerator: function(){return Code.nullGenerator;}, // suppress any output
+    codeGenerator: function(){return nullCodeGenerator;}, // suppress any output
     handleLabel: function(type, v){
         this.parent().handleLabelType(type);
         if (this.__from === undefined )
@@ -1386,7 +1396,7 @@ exports.For = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         this.__var = undefined;
         this.__initExprParsed = false;
-        this.__toExpr = new Code.SimpleGenerator();
+        this.__toExpr = Code.makeSimpleGenerator();
         this.__toParsed = false;
         this.__by_parsed = false;
         this.__by = undefined;
@@ -1428,7 +1438,7 @@ exports.For = ChainedContext.extend({
         if (this.__initExprParsed && !this.__toParsed)
             return this.__toExpr;
         if (this.__toParsed && !this.__by_parsed)
-            return Code.nullGenerator; // suppress output for BY expression
+            return nullCodeGenerator; // suppress output for BY expression
         
         return this.parent().codeGenerator();
     },
@@ -1466,9 +1476,9 @@ exports.Assignment = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         this.__left = undefined;
     },
-    codeGenerator: function(){return Code.nullGenerator;},
+    codeGenerator: function(){return nullCodeGenerator;},
     setDesignator: function(d){
-        this.__left = new Code.Expression(d.code(), d.type(), d);
+        this.__left = Code.makeExpression(d.code(), d.type(), d);
     },
     handleExpression: function(e){
         this.parent().codeGenerator().write(op.assign(this.__left, e, this));
@@ -1495,7 +1505,7 @@ exports.ConstDecl = ChainedContext.extend({
     },
     endParse: function(){
         var c = Type.makeConst(this.__type, this.__value);
-        this.currentScope().addSymbol(new Symbol.Symbol(this.__id.id(), c), this.__id.exported());
+        this.currentScope().addSymbol(Symbol.makeSymbol(this.__id.id(), c), this.__id.exported());
         this.codeGenerator().write(";\n");
     }
 });
@@ -1534,7 +1544,7 @@ exports.VariableDeclaration = HandleSymbolAsType.extend({
             var varName = id.id();
             if (id.exported())
                 this.checkExport(varName);
-            this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
+            this.currentScope().addSymbol(Symbol.makeSymbol(varName, v), id.exported());
             var t = Type.variableType(v);
             gen.write("var " + varName + " = " + t.initializer(this) + ";");
         }
@@ -1581,7 +1591,7 @@ var ProcedureCall = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         this.__type = undefined;
         this.__procCall = undefined;
-        this.__code = new Code.SimpleGenerator();
+        this.__code = Code.makeSimpleGenerator();
     },
     setDesignator: function(d){
         var type = d.type();
@@ -1634,9 +1644,10 @@ exports.ExpressionProcedureCall = ProcedureCall.extend({
         else{
             var d = this.__designator;
             var info = d.info();
-            if (info instanceof Type.Procedure){
-                if (info instanceof Procedure.Std)
-                    throw new Errors.Error(info.description() + " cannot be referenced");
+            if (info instanceof Type.ProcedureId){
+                var proc = Type.procedureType(info);
+                if (proc instanceof Procedure.Std)
+                    throw new Errors.Error(proc.description() + " cannot be referenced");
                 var scope = d.scope();
                 if (scope && scope.id() == "procedure")
                     throw new Errors.Error("local procedure '" + d.code() + "' cannot be referenced");
@@ -1723,7 +1734,7 @@ exports.TypeDeclaration = ChainedContext.extend({
     },
     handleIdentdef: function(id){
         var typeId = Type.makeLazyTypeId();
-        var symbol = new Symbol.Symbol(id.id(), typeId);
+        var symbol = Symbol.makeSymbol(id.id(), typeId);
         this.currentScope().addSymbol(symbol, id.exported());
         if (!id.exported())
             this.currentScope().addFinalizer(function(){typeId.strip();});
@@ -1855,7 +1866,7 @@ var ModuleImport = ChainedContext.extend({
             if (!module)
                 unresolved.push(moduleName);
             else
-                modules.push(new Symbol.Symbol(alias, module));
+                modules.push(Symbol.makeSymbol(alias, module));
         }
         if (unresolved.length)
             throw new Errors.Error("module(s) not found: " + unresolved.join(", "));
@@ -1906,7 +1917,7 @@ exports.Context = Class.extend({
             var s = scope.findSymbol(ident);
 
             if (s)
-                return new Symbol.Found(s, scope);
+                return Symbol.makeFound(s, scope);
         }
         return undefined;
     },

+ 7 - 5
src/eberon/eberon_context.js

@@ -3,7 +3,7 @@
 var Cast = require("cast.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
-var Symbol = require("symbol.js");
+var Symbol = require("js/Symbols.js");
 var Procedure = require("procedure.js");
 var Type = require("js/Types.js");
 
@@ -96,10 +96,10 @@ var Designator = Context.Designator.extend({
     },
     handleLiteral: function(s){
         if (s == "SELF")
-            this.handleSymbol(new Symbol.Found(this.handleMessage(getMethodSelf)), "this");
+            this.handleSymbol(Symbol.makeFound(this.handleMessage(getMethodSelf)), "this");
         else if (s == "SUPER"){
             var ms = this.handleMessage(getMethodSuper);
-            this.handleSymbol(new Symbol.Found(ms.symbol), ms.code);
+            this.handleSymbol(Symbol.makeFound(ms.symbol), ms.code);
         }
         else
             Context.Designator.prototype.handleLiteral.call(this, s);
@@ -282,7 +282,7 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
             var id = msg.id;
             var type = msg.type;
             if (type){
-                this.__selfSymbol = new Symbol.Symbol("SELF", type);
+                this.__selfSymbol = Symbol.makeSymbol("SELF", type);
                 this.__methodId = id;
                 this.__boundType = type;
             }
@@ -351,7 +351,9 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
         var id = this.__methodId.id();
         baseType.requireMethodDefinition(id);
         return {
-            symbol: new Symbol.Symbol("method", new MethodType(this.__methodType.procType(), superMethodCallGenerator)),
+            symbol: Symbol.makeSymbol(
+                "method",  
+                Type.makeProcedure(new MethodType(this.__methodType.procType(), superMethodCallGenerator))),
             code: Type.typeName(baseType) + ".prototype." + id + ".call"
         };
     }

+ 336 - 0
src/js/Code.js

@@ -0,0 +1,336 @@
+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 Types = require("js/Types.js");
+var kTab = "\t";
+var kNoPrecedence = 0;
+var IGenerator = RTL$.extend({
+	init: function IGenerator(){
+	}
+});
+var NullGenerator = IGenerator.extend({
+	init: function NullGenerator(){
+		IGenerator.prototype.init.call(this);
+	}
+});
+var SimpleGenerator = NullGenerator.extend({
+	init: function SimpleGenerator(){
+		NullGenerator.prototype.init.call(this);
+		this.mResult = null;
+	}
+});
+var Generator = SimpleGenerator.extend({
+	init: function Generator(){
+		SimpleGenerator.prototype.init.call(this);
+		this.indent = 0;
+	}
+});
+var Designator = RTL$.extend({
+	init: function Designator(){
+		this.mCode = null;
+		this.mLval = null;
+		this.mRefCode = null;
+		this.mType = null;
+		this.mInfo = null;
+		this.mScope = null;
+	}
+});
+var Expression = RTL$.extend({
+	init: function Expression(){
+		this.mCode = null;
+		this.mType = null;
+		this.mDesignator = null;
+		this.mConstValue = undefined;
+		this.mMaxPrecedence = 0;
+	}
+});
+var ModuleGenerator = RTL$.extend({
+	init: function ModuleGenerator(){
+		this.name = null;
+		this.imports = null;
+	}
+});
+var Closure = Object.Type.extend({
+	init: function Closure(){
+		Object.Type.prototype.init.call(this);
+		this.result = null;
+	}
+});
+var nullGenerator = new NullGenerator();
+var undefined = undefined;
+NullGenerator.prototype.write = function(s/*Type*/){
+}
+NullGenerator.prototype.openScope = function(){
+}
+NullGenerator.prototype.closeScope = function(ending/*Type*/){
+}
+NullGenerator.prototype.result = function(){
+	return null;
+}
+SimpleGenerator.prototype.write = function(s/*Type*/){
+	this.mResult = JsString.concat(this.mResult, s);
+}
+SimpleGenerator.prototype.result = function(){
+	return this.mResult;
+}
+
+function putIndent(s/*Type*/, indent/*INTEGER*/){
+	var i = 0;
+	for (i = 0; i <= indent - 1 | 0; ++i){
+		s = JsString.appendChar(s, 9);
+	}
+	return s;
+}
+Generator.prototype.write = function(s/*Type*/){
+	var pos = 0;
+	var index = 0;
+	index = JsString.indexOf(s, 10);
+	while (true){
+		if (index != -1){
+			++index;
+			this.mResult = JsString.concat(this.mResult, JsString.substr(s, pos, index - pos | 0));
+			this.mResult = putIndent(this.mResult, this.indent);
+			pos = index;
+			index = JsString.indexOfFrom(s, 10, pos);
+		} else break;
+	}
+	this.mResult = JsString.concat(this.mResult, JsString.substr(s, pos, JsString.len(s) - pos | 0));
+}
+Generator.prototype.openScope = function(){
+	++this.indent;
+	this.mResult = JsString.appendChar(this.mResult, 123);
+	this.mResult = JsString.appendChar(this.mResult, 10);
+	this.mResult = putIndent(this.mResult, this.indent);
+}
+Generator.prototype.closeScope = function(ending/*Type*/){
+	--this.indent;
+	this.mResult = JsString.substr(this.mResult, 0, JsString.len(this.mResult) - 1 | 0);
+	this.mResult = JsString.appendChar(this.mResult, 125);
+	if (ending != null){
+		this.write(ending);
+	}
+	else {
+		this.mResult = JsString.appendChar(this.mResult, 10);
+		this.mResult = putIndent(this.mResult, this.indent);
+	}
+}
+Expression.prototype.code = function(){
+	return this.mCode;
+}
+Expression.prototype.lval = function(){
+	var result = null;
+	if (this.mDesignator != null){
+		result = this.mDesignator.mLval;
+	}
+	else {
+		result = this.mCode;
+	}
+	return result;
+}
+Expression.prototype.type = function(){
+	return this.mType;
+}
+Expression.prototype.designator = function(){
+	return this.mDesignator;
+}
+Expression.prototype.constValue = function(){
+	return this.mConstValue;
+}
+Expression.prototype.maxPrecedence = function(){
+	return this.mMaxPrecedence;
+}
+Expression.prototype.isTerm = function(){
+	return this.mDesignator == null && this.mMaxPrecedence == kNoPrecedence;
+}
+
+function makeExpressionWithPrecedence(code/*Type*/, type/*PType*/, designator/*PDesigantor*/, constValue/*JS.var*/, maxPrecedence/*INTEGER*/){
+	var result = null;
+	result = new Expression();
+	result.mCode = code;
+	result.mType = type;
+	result.mDesignator = designator;
+	result.mConstValue = constValue;
+	result.mMaxPrecedence = maxPrecedence;
+	return result;
+}
+
+function makeExpression(code/*Type*/, type/*PType*/, designator/*PDesigantor*/, constValue/*JS.var*/){
+	return makeExpressionWithPrecedence(code, type, designator, constValue, kNoPrecedence);
+}
+Designator.prototype.code = function(){
+	return this.mCode;
+}
+Designator.prototype.lval = function(){
+	return this.mLval;
+}
+Designator.prototype.refCode = function(){
+	return this.mRefCode;
+}
+Designator.prototype.type = function(){
+	return this.mType;
+}
+Designator.prototype.info = function(){
+	return this.mInfo;
+}
+Designator.prototype.scope = function(){
+	return this.mScope;
+}
+
+function makeDesignator(code/*Type*/, lval/*Type*/, refCode/*RefCodeProc*/, type/*PType*/, info/*PId*/, scope/*PScope*/){
+	var result = null;
+	result = new Designator();
+	result.mCode = code;
+	result.mLval = lval;
+	result.mRefCode = refCode;
+	result.mType = type;
+	result.mInfo = info;
+	result.mScope = scope;
+	return result;
+}
+
+function derefExpression(e/*PExpression*/){
+	var result = null;
+	if (e.mDesignator == null || (e.mType instanceof Types.Array || e.mType instanceof Types.Record) || !(e.mDesignator.mInfo instanceof Types.VariableRef)){
+		result = e;
+	}
+	else {
+		result = makeExpression(JsString.concat(e.mCode, JsString.make(".get()")), e.mType, null, undefined);
+	}
+	return result;
+}
+
+function refExpression(e/*PExpression*/){
+	var result = null;
+	if (e.mDesignator == null || e.mDesignator.mInfo instanceof Types.VariableRef){
+		result = e;
+	}
+	else {
+		result = makeExpression(e.mDesignator.mRefCode(e.mDesignator.mCode), e.mType, null, undefined);
+	}
+	return result;
+}
+
+function adjustPrecedence(e/*Expression*/, precedence/*INTEGER*/){
+	var result = null;
+	result = e.mCode;
+	if (e.mMaxPrecedence > precedence){
+		result = JsString.concat(JsString.concat(JsString.make("("), result), JsString.make(")"));
+	}
+	return result;
+}
+
+function isPointerShouldBeExported(type/*Pointer*/){
+	var r = null;
+	r = Types.pointerBase(type);
+	return Types.typeName(r) == null;
+}
+
+function typeShouldBeExported(typeId/*PId*/){
+	var type = null;
+	type = RTL$.typeGuard(typeId, Types.TypeId).type();
+	return type instanceof Types.Record || type instanceof Types.Pointer && isPointerShouldBeExported(RTL$.typeGuard(type, Types.Pointer));
+}
+
+function genExport(s/*Symbol*/){
+	var result = null;
+	if (s.isVariable()){
+		result = JsString.concat(JsString.concat(JsString.make("function(){return "), s.id()), JsString.make(";}"));
+	}
+	else if (!s.isType() || typeShouldBeExported(s.info())){
+		result = s.id();
+	}
+	return result;
+}
+
+function genCommaList(name/*Type*/, closure/*Closure*/){
+	if (JsString.len(closure.result) != 0){
+		closure.result = JsString.concat(closure.result, JsString.make(", "));
+	}
+	closure.result = JsString.concat(closure.result, name);
+}
+
+function genAliasesAdaptor(key/*Type*/, value/*Type*/, closure/*VAR Type*/){
+	genCommaList(value, RTL$.typeGuard(closure, Closure));
+}
+ModuleGenerator.prototype.prolog = function(){
+	var closure = new Closure();
+	closure.result = JsString.makeEmpty();
+	JsMap.forEachString(this.imports, genAliasesAdaptor, closure);
+	return JsString.appendChar(JsString.concat(JsString.concat(JsString.concat(JsString.concat(JsString.make("var "), this.name), JsString.make(" = function (")), closure.result), JsString.make("){")), 10);
+}
+
+function genExports(s/*Symbol*/, closure/*Closure*/){
+	var code = null;
+	code = genExport(s);
+	if (code != null){
+		if (JsString.len(closure.result) != 0){
+			closure.result = JsString.appendChar(JsString.appendChar(closure.result, 44), 10);
+		}
+		closure.result = JsString.concat(JsString.concat(JsString.concat(JsString.appendChar(closure.result, 9), s.id()), JsString.make(": ")), code);
+	}
+}
+
+function genExportsAdaptor(key/*Type*/, value/*PType*/, closure/*VAR Type*/){
+	genExports(RTL$.typeGuard(value, Symbols.Symbol), RTL$.typeGuard(closure, Closure));
+}
+
+function genImportListAdaptor(key/*Type*/, value/*Type*/, closure/*VAR Type*/){
+	genCommaList(key, RTL$.typeGuard(closure, Closure));
+}
+ModuleGenerator.prototype.epilog = function(exports/*Type*/){
+	var result = null;
+	var closure = new Closure();
+	closure.result = JsString.makeEmpty();
+	JsMap.forEach(exports, genExportsAdaptor, closure);
+	result = closure.result;
+	if (JsString.len(result) != 0){
+		result = JsString.appendChar(JsString.appendChar(JsString.appendChar(JsString.concat(JsString.appendChar(JsString.make("return {"), 10), result), 10), 125), 10);
+	}
+	result = JsString.concat(result, JsString.make("}("));
+	closure.result = JsString.makeEmpty();
+	JsMap.forEachString(this.imports, genImportListAdaptor, closure);
+	result = JsString.appendChar(JsString.concat(JsString.concat(result, closure.result), JsString.make(");")), 10);
+	return result;
+}
+
+function initSimpleGenerator(g/*SimpleGenerator*/){
+	g.mResult = JsString.makeEmpty();
+}
+
+function makeSimpleGenerator(){
+	var result = null;
+	result = new SimpleGenerator();
+	initSimpleGenerator(result);
+	return result;
+}
+
+function makeGenerator(){
+	var result = null;
+	result = new Generator();
+	initSimpleGenerator(result);
+	return result;
+}
+
+function makeModuleGenerator(name/*Type*/, imports/*Strings*/){
+	var result = null;
+	result = new ModuleGenerator();
+	result.name = name;
+	result.imports = imports;
+	return result;
+}
+exports.nullGenerator = function(){return nullGenerator;};
+exports.makeExpressionWithPrecedence = makeExpressionWithPrecedence;
+exports.makeExpression = makeExpression;
+exports.makeDesignator = makeDesignator;
+exports.derefExpression = derefExpression;
+exports.refExpression = refExpression;
+exports.adjustPrecedence = adjustPrecedence;
+exports.genExport = genExport;
+exports.makeSimpleGenerator = makeSimpleGenerator;
+exports.makeGenerator = makeGenerator;
+exports.makeModuleGenerator = makeModuleGenerator;

+ 15 - 0
src/js/JsMap.js

@@ -6,6 +6,10 @@ var Type = RTL$.extend({
 	init: function Type(){
 	}
 });
+var Strings = RTL$.extend({
+	init: function Strings(){
+	}
+});
 
 function make(){
 	var result = null;
@@ -32,9 +36,20 @@ function put(m/*Type*/, s/*Type*/, o/*PType*/){
 function erase(m/*Type*/, s/*Type*/){
 	delete m[s];
 }
+
+function forEach(m/*Type*/, p/*forEachProc*/, closure/*VAR Type*/){
+	for(var key in m){p(key, m[key], closure)};
+}
+
+function forEachString(m/*Strings*/, p/*forEachStringProc*/, closure/*VAR Type*/){
+	for(var key in m){p(key, m[key], closure)};
+}
 exports.Type = Type;
+exports.Strings = Strings;
 exports.make = make;
 exports.has = has;
 exports.find = find;
 exports.put = put;
 exports.erase = erase;
+exports.forEach = forEach;
+exports.forEachString = forEachString;

+ 7 - 0
src/js/JsString.js

@@ -15,6 +15,12 @@ function make(s/*ARRAY OF CHAR*/){
 	return result;
 }
 
+function makeEmpty(){
+	var result = null;
+	result = '';
+	return result;
+}
+
 function fromInt(i/*INTEGER*/){
 	var result = null;
 	result = '' + i;
@@ -65,6 +71,7 @@ function concat(self/*Type*/, add/*Type*/){
 }
 exports.Type = Type;
 exports.make = make;
+exports.makeEmpty = makeEmpty;
 exports.fromInt = fromInt;
 exports.len = len;
 exports.at = at;

+ 2 - 0
src/js/Stream.js

@@ -1,5 +1,6 @@
 var RTL$ = require("rtl.js");
 var JsString = require("js/JsString.js");
+var kCR = "\n";
 var Type = RTL$.extend({
 	init: function Type(){
 		this.s = null;
@@ -80,6 +81,7 @@ function lineNumber(self/*Type*/){
 	}
 	return line + 1 | 0;
 }
+exports.kCR = kCR;
 exports.Type = Type;
 exports.make = make;
 exports.eof = eof;

+ 65 - 0
src/js/Symbols.js

@@ -0,0 +1,65 @@
+var RTL$ = require("rtl.js");
+var Context = require("js/Context.js");
+var JsString = require("js/JsString.js");
+var Object = require("js/Object.js");
+var Types = require("js/Types.js");
+var Symbol = Object.Type.extend({
+	init: function Symbol(){
+		Object.Type.prototype.init.call(this);
+		this.mId = null;
+		this.mInfo = null;
+	}
+});
+var FoundSymbol = RTL$.extend({
+	init: function FoundSymbol(){
+		this.mSymbol = null;
+		this.mScope = null;
+	}
+});
+Symbol.prototype.id = function(){
+	return this.mId;
+}
+Symbol.prototype.info = function(){
+	return this.mInfo;
+}
+Symbol.prototype.isModule = function(){
+	return this.mInfo instanceof Types.Module;
+}
+Symbol.prototype.isVariable = function(){
+	return this.mInfo instanceof Types.Variable;
+}
+Symbol.prototype.isConst = function(){
+	return this.mInfo instanceof Types.Const;
+}
+Symbol.prototype.isType = function(){
+	return this.mInfo instanceof Types.TypeId;
+}
+Symbol.prototype.isProcedure = function(){
+	return this.mInfo instanceof Types.ProcedureId;
+}
+FoundSymbol.prototype.scope = function(){
+	return this.mScope;
+}
+FoundSymbol.prototype.symbol = function(){
+	return this.mSymbol;
+}
+
+function makeSymbol(id/*Type*/, info/*PId*/){
+	var result = null;
+	result = new Symbol();
+	result.mId = id;
+	result.mInfo = info;
+	return result;
+}
+
+function makeFound(s/*PSymbol*/, scope/*PScope*/){
+	var result = null;
+	result = new FoundSymbol();
+	result.mSymbol = s;
+	result.mScope = scope;
+	return result;
+}
+exports.Symbol = Symbol;
+exports.FoundSymbol = FoundSymbol;
+exports.makeSymbol = makeSymbol;
+exports.makeFound = makeFound;

+ 27 - 17
src/js/Types.js

@@ -12,13 +12,14 @@ var Id = Object.Type.extend({
 		Object.Type.prototype.init.call(this);
 	}
 });
-var Type = Id.extend({
+var Type = Object.Type.extend({
 	init: function Type(){
-		Id.prototype.init.call(this);
+		Object.Type.prototype.init.call(this);
 	}
 });
-var TypeId = RTL$.extend({
+var TypeId = Id.extend({
 	init: function TypeId(){
+		Id.prototype.init.call(this);
 		this.mType = null;
 	}
 });
@@ -57,6 +58,12 @@ var ExportedVariable = Variable.extend({
 		Variable.prototype.init.call(this);
 	}
 });
+var ProcedureId = Id.extend({
+	init: function ProcedureId(){
+		Id.prototype.init.call(this);
+		this.type = null;
+	}
+});
 var String = Type.extend({
 	init: function String(){
 		Type.prototype.init.call(this);
@@ -206,12 +213,9 @@ function defineTypeId(tId/*VAR LazyTypeId*/, t/*PType*/){
 function typeName(type/*NamedType*/){
 	return type.name;
 }
-Procedure.prototype.idType = function(){
+ProcedureId.prototype.idType = function(){
 	return JsString.make("procedure");
 }
-String.prototype.idType = function(){
-	return JsString.make("string");
-}
 String.prototype.description = function(){
 	var prefix = null;
 	if (JsString.len(this.s) == 1){
@@ -265,13 +269,17 @@ function variableType(v/*Variable*/){
 	return v.type;
 }
 
+function procedureType(p/*ProcedureId*/){
+	return p.type;
+}
+
 function isVariableReadOnly(v/*Variable*/){
 	return v.readOnly;
 }
 ExportedVariable.prototype.idType = function(){
 	return JsString.make("imported variable");
 }
-BasicType.prototype.idType = function(){
+TypeId.prototype.idType = function(){
 	return JsString.make("type");
 }
 BasicType.prototype.description = function(){
@@ -307,9 +315,6 @@ function makeBasic(name/*ARRAY OF CHAR*/, initializer/*ARRAY OF CHAR*/){
 	result.mInitializer = JsString.make(initializer);
 	return result;
 }
-Record.prototype.idType = function(){
-	return JsString.make("record");
-}
 Record.prototype.description = function(){
 	var result = null;
 	if (this.name != null){
@@ -362,9 +367,6 @@ function recordConstructor(r/*Record*/){
 function recordOwnFields(r/*Record*/){
 	return r.fields;
 }
-Pointer.prototype.idType = function(){
-	return JsString.make("pointer");
-}
 
 function pointerBase(p/*Pointer*/){
 	var result = null;
@@ -386,9 +388,6 @@ Pointer.prototype.description = function(){
 Pointer.prototype.initializer = function(cx/*Type*/){
 	return JsString.make("null");
 }
-Array.prototype.idType = function(){
-	return JsString.make("array");
-}
 
 function foldArrayDimensions(a/*Array*/, sizes/*VAR Type*/, of/*VAR Type*/){
 	if (a.len != openArrayLength && a.elementsType instanceof Array){
@@ -521,6 +520,13 @@ function makeExportedVariable(v/*Variable*/){
 	return result;
 }
 
+function makeProcedure(type/*PType*/){
+	var result = null;
+	result = new ProcedureId();
+	result.type = type;
+	return result;
+}
+
 function initProcedure(p/*Procedure*/, name/*Type*/){
 	p.name = name;
 }
@@ -540,12 +546,14 @@ JsArray.add(numeric, basic.uint8);
 JsArray.add(numeric, basic.real);
 nil = new Nil();
 exports.openArrayLength = openArrayLength;
+exports.Id = Id;
 exports.Type = Type;
 exports.TypeId = TypeId;
 exports.ForwardTypeId = ForwardTypeId;
 exports.Const = Const;
 exports.Variable = Variable;
 exports.VariableRef = VariableRef;
+exports.ProcedureId = ProcedureId;
 exports.String = String;
 exports.Array = Array;
 exports.Pointer = Pointer;
@@ -566,6 +574,7 @@ exports.stringAsChar = stringAsChar;
 exports.constType = constType;
 exports.constValue = constValue;
 exports.variableType = variableType;
+exports.procedureType = procedureType;
 exports.isVariableReadOnly = isVariableReadOnly;
 exports.isInt = isInt;
 exports.intsDescription = intsDescription;
@@ -589,5 +598,6 @@ exports.makeConst = makeConst;
 exports.makeVariable = makeVariable;
 exports.makeVariableRef = makeVariableRef;
 exports.makeExportedVariable = makeExportedVariable;
+exports.makeProcedure = makeProcedure;
 exports.initProcedure = initProcedure;
 exports.initModule = initModule;

+ 7 - 7
src/module.js

@@ -1,9 +1,9 @@
 "use strict";
 
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var Procedure = require("procedure.js");
-var Symbol = require("symbol.js");
+var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
 var AnyTypeProc = Type.Procedure.extend({
@@ -54,7 +54,7 @@ var doProcSymbol = (function(){
         epilog: function(){return "";},
         writeArgumentCode: function(){},
         callExpression: function(){
-            return new Code.Expression(this.__code);
+            return Code.makeExpression(this.__code);
         }
     });
 
@@ -72,11 +72,11 @@ var doProcSymbol = (function(){
         }
         });
 
-    return new Symbol.Symbol(doProcId, new ProcType());
+    return Symbol.makeSymbol(doProcId, new ProcType());
 })();
 
 var varTypeSymbol = function(){
-    return new Symbol.Symbol(varTypeId, Type.makeTypeId(any));
+    return Symbol.makeSymbol(varTypeId, Type.makeTypeId(any));
 }();
 
 var JSModule = Type.Module.extend({
@@ -85,10 +85,10 @@ var JSModule = Type.Module.extend({
         Type.initModule(this, "this");
     },
     findSymbol: function(id){
-        return new Symbol.Found(
+        return Symbol.makeFound(
             id == doProcId ? doProcSymbol
           : id == varTypeId ? varTypeSymbol
-          : new Symbol.Symbol(id, any));
+          : Symbol.makeSymbol(id, any));
     }
 });
 

+ 2 - 2
src/nodejs.js

@@ -1,7 +1,7 @@
 "use strict";
 
 var Class = require("rtl.js").Class;
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Context = require("context.js");
 var oc = require("oc.js");
 var RTL = require("rtl_code.js").RTL;
@@ -71,7 +71,7 @@ function compile(sources, grammar, handleErrors, outDir, importDir){
             },
             grammar,
             function(moduleResolver){return new Context.Context(
-                new Code.Generator(),
+                Code.makeGenerator(),
                 moduleCode,
                 rtl,
                 moduleResolver);},

+ 449 - 6
src/ob/Code.ob

@@ -1,13 +1,456 @@
 MODULE Code;
-IMPORT Types;
+IMPORT JS, JsMap, JsString, Context, Object, Stream, Symbols, Types;
+
+CONST
+    kTab = 09X;
+    kNoPrecedence = 0;
+
 TYPE
-    Generator = RECORD
-        PROCEDURE write();
-        PROCEDURE getResult();
+    IGenerator = RECORD
+        PROCEDURE write(s: JsString.Type);
         PROCEDURE openScope();
-        PROCEDURE closeScope()
+        PROCEDURE closeScope(ending: JsString.Type);
+        PROCEDURE result(): JsString.Type
+    END;
+
+    PIGenerator = POINTER TO IGenerator;
+
+    NullGenerator = RECORD(IGenerator)
+    END;
+
+    SimpleGenerator = RECORD(NullGenerator)
+        mResult: JsString.Type
+    END;
+
+    Generator = RECORD(SimpleGenerator)
+        indent: INTEGER
+    END;
+
+    RefCodeProc = PROCEDURE(s: JsString.Type): JsString.Type;
+
+    Designator = RECORD
+        PROCEDURE code(): JsString.Type;
+        PROCEDURE lval(): JsString.Type;
+        PROCEDURE refCode(): RefCodeProc;
+        PROCEDURE type(): Types.PType;
+        PROCEDURE info(): Types.PId;
+        PROCEDURE scope(): Context.PScope;
+
+        mCode: JsString.Type;
+        mLval: JsString.Type;
+        mRefCode: RefCodeProc;
+        mType: Types.PType;
+        mInfo: Types.PId;
+        mScope: Context.PScope
+    END;
+
+    PDesigantor = POINTER TO Designator;
+
+    PExpression = POINTER TO Expression;
+
+    Expression = RECORD
+        PROCEDURE code(): JsString.Type;
+        PROCEDURE lval(): JsString.Type;
+        PROCEDURE type(): Types.PType;
+        PROCEDURE designator(): PDesigantor;
+        PROCEDURE constValue(): JS.var;
+        PROCEDURE maxPrecedence(): INTEGER;
+        PROCEDURE isTerm(): BOOLEAN;
+
+        mCode: JsString.Type;
+        mType: Types.PType;
+        mDesignator: PDesigantor;
+        mConstValue: JS.var;
+        mMaxPrecedence: INTEGER
+    END;
+
+    ModuleGenerator = RECORD
+        PROCEDURE prolog(): JsString.Type;
+        PROCEDURE epilog(exports: JsMap.Type): JsString.Type;
+
+        name: JsString.Type;
+        imports: JsMap.Strings
+    END;
+
+    PModuleGenerator = POINTER TO ModuleGenerator;
+
+    Closure = RECORD(Object.Type)
+        result: JsString.Type
+    END;
+
+VAR
+    nullGenerator*: NullGenerator;
+    undefined: JS.var;
+
+PROCEDURE NullGenerator.write(s: JsString.Type);
+END NullGenerator.write;
+
+PROCEDURE NullGenerator.openScope();
+END NullGenerator.openScope;
+
+PROCEDURE NullGenerator.closeScope(ending: JsString.Type);
+END NullGenerator.closeScope;
+
+PROCEDURE NullGenerator.result(): JsString.Type;
+    RETURN NIL
+END NullGenerator.result;
+
+PROCEDURE SimpleGenerator.write(s: JsString.Type);
+BEGIN
+    SELF.mResult := JsString.concat(SELF.mResult, s);
+END SimpleGenerator.write;
+
+PROCEDURE SimpleGenerator.result(): JsString.Type;
+    RETURN SELF.mResult
+END SimpleGenerator.result;
+
+PROCEDURE putIndent(s: JsString.Type; indent: INTEGER): JsString.Type;
+VAR
+    i: INTEGER;
+BEGIN
+    FOR i := 0 TO indent - 1 DO
+        s := JsString.appendChar(s, kTab);
+    END;
+    RETURN s
+END putIndent;
+
+PROCEDURE Generator.write(s: JsString.Type);
+VAR
+    pos: INTEGER;
+    index: INTEGER;
+BEGIN
+    index := JsString.indexOf(s, Stream.kCR);
+    WHILE index # -1 DO
+        INC(index);
+        SELF.mResult := JsString.concat(SELF.mResult, JsString.substr(s, pos, index - pos));
+        SELF.mResult := putIndent(SELF.mResult, SELF.indent);
+        pos := index;
+        index := JsString.indexOfFrom(s, Stream.kCR, pos);
+    END;
+    SELF.mResult := JsString.concat(SELF.mResult, 
+                                    JsString.substr(s, pos, JsString.len(s) - pos));
+END Generator.write;
+
+PROCEDURE Generator.openScope();
+BEGIN
+    INC(SELF.indent);
+    SELF.mResult := JsString.appendChar(SELF.mResult, "{");
+    SELF.mResult := JsString.appendChar(SELF.mResult, Stream.kCR);
+    SELF.mResult := putIndent(SELF.mResult, SELF.indent);
+END Generator.openScope;
+
+PROCEDURE Generator.closeScope(ending: JsString.Type);
+BEGIN
+    DEC(SELF.indent);
+    SELF.mResult := JsString.substr(SELF.mResult, 0, JsString.len(SELF.mResult) - 1);
+    SELF.mResult := JsString.appendChar(SELF.mResult, "}");
+    IF ending # NIL THEN
+        SELF.write(ending);
+    ELSE
+        SELF.mResult := JsString.appendChar(SELF.mResult, Stream.kCR);
+        SELF.mResult := putIndent(SELF.mResult, SELF.indent);
+    END;
+END Generator.closeScope;
+
+PROCEDURE Expression.code(): JsString.Type;
+    RETURN SELF.mCode
+END Expression.code;
+
+PROCEDURE Expression.lval(): JsString.Type;
+VAR
+    result: JsString.Type;
+BEGIN
+    IF SELF.mDesignator # NIL THEN
+        result := SELF.mDesignator.mLval;
+    ELSE
+        result := SELF.mCode;
+    END;
+    RETURN result
+END Expression.lval;
+
+PROCEDURE Expression.type(): Types.PType;
+    RETURN SELF.mType
+END Expression.type;
+
+PROCEDURE Expression.designator(): PDesigantor;
+    RETURN SELF.mDesignator
+END Expression.designator;
+
+PROCEDURE Expression.constValue(): JS.var;
+    RETURN SELF.mConstValue
+END Expression.constValue;
+
+PROCEDURE Expression.maxPrecedence(): INTEGER;
+    RETURN SELF.mMaxPrecedence
+END Expression.maxPrecedence;
+
+PROCEDURE Expression.isTerm(): BOOLEAN;
+    RETURN (SELF.mDesignator = NIL) & (SELF.mMaxPrecedence = kNoPrecedence)
+END Expression.isTerm;
+
+PROCEDURE makeExpressionWithPrecedence*(
+    code: JsString.Type; 
+    type: Types.PType; 
+    designator: PDesigantor; 
+    constValue: JS.var; 
+    maxPrecedence: INTEGER): PExpression;
+VAR
+    result: PExpression;
+BEGIN
+    NEW(result);
+    result.mCode := code;
+    result.mType := type;
+    result.mDesignator := designator;
+    result.mConstValue := constValue;
+    result.mMaxPrecedence := maxPrecedence;
+    RETURN result
+END makeExpressionWithPrecedence;
+
+PROCEDURE makeExpression*(
+    code: JsString.Type; 
+    type: Types.PType; 
+    designator: PDesigantor; 
+    constValue: JS.var)
+    : PExpression;
+    RETURN makeExpressionWithPrecedence(code, type, designator, constValue, kNoPrecedence)
+END makeExpression;
+
+PROCEDURE Designator.code(): JsString.Type;
+    RETURN SELF.mCode
+END Designator.code;
+
+PROCEDURE Designator.lval(): JsString.Type;
+    RETURN SELF.mLval
+END Designator.lval;
+
+PROCEDURE Designator.refCode(): RefCodeProc;
+    RETURN SELF.mRefCode
+END Designator.refCode;
+
+PROCEDURE Designator.type(): Types.PType;
+    RETURN SELF.mType
+END Designator.type;
+
+PROCEDURE Designator.info(): Types.PId;
+    RETURN SELF.mInfo
+END Designator.info;
+
+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;
+VAR
+    result: PDesigantor;
+BEGIN
+    NEW(result);
+    result.mCode := code;
+    result.mLval := lval;
+    result.mRefCode := refCode;
+    result.mType := type;
+    result.mInfo := info;
+    result.mScope := scope;
+    RETURN result
+END makeDesignator;
+
+PROCEDURE derefExpression*(e: PExpression): PExpression;
+VAR
+    result: PExpression;
+BEGIN
+    IF     (e.mDesignator = NIL)
+        OR ((e.mType IS Types.PArray) OR (e.mType IS Types.PRecord)) 
+        OR ~(e.mDesignator.mInfo IS Types.PVariableRef) THEN
+        result := e;
+    ELSE
+        result := makeExpression(JsString.concat(e.mCode, JsString.make(".get()")),
+                                 e.mType,
+                                 NIL,
+                                 undefined);
+    END;
+    RETURN result
+END derefExpression;
+
+PROCEDURE refExpression*(e: PExpression): PExpression;
+VAR
+    result: PExpression;
+BEGIN
+    IF     (e.mDesignator = NIL) 
+        OR (e.mDesignator.mInfo IS Types.PVariableRef) THEN
+        result := e;
+    ELSE
+        result := makeExpression(e.mDesignator.mRefCode(e.mDesignator.mCode),
+                                 e.mType,
+                                 NIL,
+                                 undefined);
     END;
+    RETURN result
+END refExpression;
 
-    NullGenerator = RECORD(Generator)
+PROCEDURE adjustPrecedence*(e: Expression; precedence: INTEGER): JsString.Type;
+VAR
+    result: JsString.Type;
+BEGIN
+    result := e.mCode;
+    IF e.mMaxPrecedence > precedence THEN
+        result := JsString.concat(JsString.concat(
+            JsString.make("("), 
+            result), 
+            JsString.make(")"));
     END;
+    RETURN result
+END adjustPrecedence;
+
+PROCEDURE isPointerShouldBeExported(type: Types.Pointer): BOOLEAN;
+VAR
+    r: Types.PRecord;
+BEGIN
+    r := Types.pointerBase(type);
+    RETURN Types.typeName(r^) = NIL
+END isPointerShouldBeExported;
+
+PROCEDURE typeShouldBeExported(typeId: Types.PId): BOOLEAN;
+VAR
+    type: Types.PType;
+BEGIN
+    type := typeId(Types.PTypeId).type();
+    RETURN (type IS Types.PRecord)
+        OR ((type IS Types.PPointer) 
+            & isPointerShouldBeExported(type^(Types.Pointer)))
+END typeShouldBeExported;
+
+PROCEDURE genExport*(s: Symbols.Symbol): JsString.Type;
+VAR
+    result: JsString.Type;
+BEGIN
+    IF s.isVariable() THEN
+        result := JsString.concat(JsString.concat(
+            JsString.make("function(){return "),
+            s.id()),
+            JsString.make(";}"));
+    ELSIF ~s.isType() OR typeShouldBeExported(s.info()) THEN
+        result := s.id();
+    END;
+    RETURN result
+END genExport;
+
+PROCEDURE genCommaList(name: JsString.Type; closure: Closure);
+BEGIN
+    IF JsString.len(closure.result) # 0 THEN
+        closure.result := JsString.concat(closure.result, JsString.make(", "));
+    END;
+    closure.result := JsString.concat(closure.result, name);
+END genCommaList;
+
+PROCEDURE genAliasesAdaptor(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
+BEGIN
+    genCommaList(value, closure(Closure));
+END genAliasesAdaptor;
+
+PROCEDURE ModuleGenerator.prolog(): JsString.Type;
+VAR
+    closure: Closure;
+BEGIN
+    closure.result := JsString.makeEmpty();
+    JsMap.forEachString(SELF.imports, genAliasesAdaptor, closure);
+    RETURN JsString.appendChar(JsString.concat(JsString.concat(JsString.concat(JsString.concat(
+        JsString.make("var "),
+        SELF.name),
+        JsString.make(" = function (")),
+        closure.result),
+        JsString.make("){")),
+        Stream.kCR)
+END ModuleGenerator.prolog;
+
+PROCEDURE genExports(s: Symbols.Symbol; closure: Closure);
+VAR
+    code: JsString.Type;
+BEGIN
+    code := genExport(s);
+    IF code # NIL THEN
+        IF JsString.len(closure.result) # 0 THEN
+            closure.result := JsString.appendChar(JsString.appendChar(
+                closure.result,
+                ","),
+                Stream.kCR);
+        END;
+        closure.result := JsString.concat(JsString.concat(JsString.concat(JsString.appendChar(
+            closure.result, 
+            kTab),
+            s.id()),
+            JsString.make(": ")),
+            code);
+    END;
+END genExports;
+
+PROCEDURE genExportsAdaptor(key: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+BEGIN
+    genExports(value^(Symbols.Symbol), closure(Closure));
+END genExportsAdaptor;
+
+PROCEDURE genImportListAdaptor(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
+BEGIN
+    genCommaList(key, closure(Closure));
+END genImportListAdaptor;
+
+PROCEDURE ModuleGenerator.epilog(exports: JsMap.Type): JsString.Type;
+VAR
+    result: JsString.Type;
+    closure: Closure;
+BEGIN
+    closure.result := JsString.makeEmpty();
+    JsMap.forEach(exports, genExportsAdaptor, closure);
+    result := closure.result;
+    IF JsString.len(result) # 0 THEN
+        result := JsString.appendChar(JsString.appendChar(JsString.appendChar(JsString.concat(JsString.appendChar(
+            JsString.make("return {"),
+            Stream.kCR),
+            result),
+            Stream.kCR),
+            "}"),
+            Stream.kCR);
+    END;
+    result := JsString.concat(result, JsString.make("}("));
+
+    closure.result := JsString.makeEmpty();
+    JsMap.forEachString(SELF.imports, genImportListAdaptor, closure);
+    result := JsString.appendChar(JsString.concat(JsString.concat(
+        result, 
+        closure.result), 
+        JsString.make(");")), 
+        Stream.kCR);
+    RETURN result
+END ModuleGenerator.epilog;
+
+PROCEDURE initSimpleGenerator(g: SimpleGenerator);
+BEGIN
+    g.mResult := JsString.makeEmpty();
+END initSimpleGenerator;
+
+PROCEDURE makeSimpleGenerator*(): PIGenerator;
+VAR
+    result: POINTER TO SimpleGenerator;
+BEGIN
+    NEW(result);
+    initSimpleGenerator(result^);
+    RETURN result
+END makeSimpleGenerator;
+
+PROCEDURE makeGenerator*(): PIGenerator;
+VAR
+    result: POINTER TO Generator;
+BEGIN
+    NEW(result);
+    initSimpleGenerator(result^);
+    RETURN result
+END makeGenerator;
+
+PROCEDURE makeModuleGenerator*(name: JsString.Type; imports: JsMap.Strings): PModuleGenerator;
+VAR
+    result: PModuleGenerator;
+BEGIN
+    NEW(result);
+    result.name := name;
+    result.imports := imports;
+    RETURN result
+END makeModuleGenerator;
 END Code.

+ 14 - 0
src/ob/JsMap.ob

@@ -2,6 +2,10 @@ MODULE JsMap;
 IMPORT JS, JsString, Object;
 TYPE
     Type* = POINTER TO RECORD END;
+    forEachProc = PROCEDURE(key: JsString.Type; value: Object.PType; VAR closure: Object.Type);
+    
+    Strings* = POINTER TO RECORD END;
+    forEachStringProc = PROCEDURE(key: JsString.Type; value: JsString.Type; VAR closure: Object.Type);
 
 PROCEDURE make*(): Type;
 VAR
@@ -37,4 +41,14 @@ BEGIN
     JS.do("delete m[s]");
 END erase;
 
+PROCEDURE forEach*(m: Type; p: forEachProc; VAR closure: Object.Type);
+BEGIN
+    JS.do("for(var key in m){p(key, m[key], closure)}");
+END forEach;
+
+PROCEDURE forEachString*(m: Strings; p: forEachStringProc; VAR closure: Object.Type);
+BEGIN
+    JS.do("for(var key in m){p(key, m[key], closure)}");
+END forEachString;
+
 END JsMap.

+ 8 - 0
src/ob/JsString.ob

@@ -16,6 +16,14 @@ BEGIN
     RETURN result
 END make;
 
+PROCEDURE makeEmpty*(): Type;
+VAR 
+    result: Type;
+BEGIN
+    JS.do("result = ''");
+    RETURN result
+END makeEmpty;
+
 PROCEDURE fromInt*(i: INTEGER): Type;
 VAR 
     result: Type;

+ 5 - 2
src/ob/Stream.ob

@@ -1,6 +1,9 @@
 MODULE Stream;
 IMPORT JsString;
 
+CONST
+    kCR* = 0AX;
+
 TYPE
     Type* = POINTER TO RECORD
         s: JsString.Type;
@@ -79,10 +82,10 @@ VAR
     line: INTEGER;
     lastPos: INTEGER;
 BEGIN
-    lastPos := JsString.indexOf(self.s, 0AX);
+    lastPos := JsString.indexOf(self.s, kCR);
     WHILE (lastPos # -1) & (lastPos < self.pos) DO
         INC(line);
-        lastPos := JsString.indexOfFrom(self.s, 0AX, lastPos + 1);
+        lastPos := JsString.indexOfFrom(self.s, kCR, lastPos + 1);
     END;
     RETURN line + 1
 END lineNumber;

+ 85 - 0
src/ob/Symbols.ob

@@ -0,0 +1,85 @@
+MODULE Symbols;
+IMPORT Context, JsString, Object, Types;
+TYPE
+    Symbol* = RECORD(Object.Type)
+        PROCEDURE id*(): JsString.Type;
+        PROCEDURE info*(): Types.PId;
+        PROCEDURE isModule*(): BOOLEAN;
+        PROCEDURE isVariable*(): BOOLEAN;
+        PROCEDURE isConst*(): BOOLEAN;
+        PROCEDURE isType*(): BOOLEAN;
+        PROCEDURE isProcedure*(): BOOLEAN;
+
+        mId: JsString.Type;
+        mInfo: Types.PId
+    END;
+
+    PSymbol* = POINTER TO Symbol;
+
+    FoundSymbol* = RECORD
+        PROCEDURE symbol(): PSymbol;
+        PROCEDURE scope(): Context.PScope;
+
+        mSymbol: PSymbol;
+        mScope: Context.PScope
+    END;
+
+    PFoundSymbol = POINTER TO FoundSymbol;
+
+PROCEDURE Symbol.id(): JsString.Type;
+    RETURN SELF.mId
+END Symbol.id;
+
+PROCEDURE Symbol.info(): Types.PId;
+    RETURN SELF.mInfo
+END Symbol.info;
+
+PROCEDURE Symbol.isModule(): BOOLEAN;
+    RETURN SELF.mInfo IS Types.PModule
+END Symbol.isModule;
+
+PROCEDURE Symbol.isVariable(): BOOLEAN;
+    RETURN SELF.mInfo IS Types.PVariable
+END Symbol.isVariable;
+
+PROCEDURE Symbol.isConst(): BOOLEAN;
+    RETURN SELF.mInfo IS Types.PConst
+END Symbol.isConst;
+
+PROCEDURE Symbol.isType(): BOOLEAN;
+    RETURN SELF.mInfo IS Types.PTypeId
+END Symbol.isType;
+
+PROCEDURE Symbol.isProcedure(): BOOLEAN;
+    RETURN SELF.mInfo IS Types.PProcedureId
+END Symbol.isProcedure;
+
+PROCEDURE FoundSymbol.scope(): Context.PScope;
+    RETURN SELF.mScope
+END FoundSymbol.scope;
+
+PROCEDURE FoundSymbol.symbol(): PSymbol;
+    RETURN SELF.mSymbol
+END FoundSymbol.symbol;
+
+PROCEDURE makeSymbol*(id: JsString.Type; info: Types.PId): PSymbol;
+VAR
+    result: PSymbol;
+BEGIN
+    NEW(result);
+    result.mId := id;
+    result.mInfo := info;
+    RETURN result
+END makeSymbol;
+
+PROCEDURE makeFound*(s: PSymbol; scope: Context.PScope): PFoundSymbol;
+VAR
+    result: PFoundSymbol;
+BEGIN
+    NEW(result);
+    result.mSymbol := s;
+    result.mScope := scope;
+    RETURN result
+END makeFound;
+
+END Symbols.

+ 49 - 26
src/ob/Types.ob

@@ -5,26 +5,26 @@ CONST
     openArrayLength* = 0;
 
 TYPE
-    Id = RECORD (Object.Type)
+    Id* = RECORD(Object.Type)
         PROCEDURE idType(): JsString.Type
     END;
 
-    PId = POINTER TO Id;
+    PId* = POINTER TO Id;
     
-    Type* = RECORD(Id)
+    Type* = RECORD(Object.Type)
         PROCEDURE description(): JsString.Type;
         PROCEDURE initializer(cx: Context.Type): JsString.Type
     END;
-    PType = POINTER TO Type;
+    PType* = POINTER TO Type;
     
-    TypeId* = RECORD
-        PROCEDURE type(): PType;
+    TypeId* = RECORD(Id)
+        PROCEDURE type*(): PType;
         PROCEDURE description(): JsString.Type;
         PROCEDURE strip();
 
         mType: PType
     END;
-    PTypeId = POINTER TO TypeId;
+    PTypeId* = POINTER TO TypeId;
 
     ResolveTypeCallback = PROCEDURE(): PType;
 
@@ -44,25 +44,31 @@ TYPE
         value: JS.var
     END;
 
-    PConst = POINTER TO Const;
+    PConst* = POINTER TO Const;
 
     Variable* = RECORD(Id)
         type: PType;
         readOnly: BOOLEAN
     END;
 
-    PVariable = POINTER TO Variable;
+    PVariable* = POINTER TO Variable;
 
     VariableRef* = RECORD(Variable)
     END;
 
-    PVariableRef = POINTER TO VariableRef;
+    PVariableRef* = POINTER TO VariableRef;
 
     ExportedVariable = RECORD(Variable)
     END;
 
     PExportedVariable = POINTER TO ExportedVariable;
 
+    ProcedureId* = RECORD(Id)
+        type: PType
+    END;
+
+    PProcedureId* = POINTER TO ProcedureId;
+
     String* = RECORD(Type)
         s: JsString.Type
     END;
@@ -79,20 +85,20 @@ TYPE
         len: INTEGER
     END;
 
-    PArray = POINTER TO Array;
+    PArray* = POINTER TO Array;
 
-    PRecord = POINTER TO Record;
+    PRecord* = POINTER TO Record;
 
     Pointer* = RECORD(NamedType)
         base: PTypeId
     END;
 
-    PPointer = POINTER TO Pointer;
+    PPointer* = POINTER TO Pointer;
 
     Procedure* = RECORD(NamedType)
     END;
 
-    PProcedure = POINTER TO Procedure;
+    PProcedure* = POINTER TO Procedure;
 
     BasicType = RECORD(NamedType)
         mInitializer: JsString.Type
@@ -128,7 +134,7 @@ TYPE
         name: JsString.Type
     END;
 
-    PModule = POINTER TO Module;
+    PModule* = POINTER TO Module;
 
 VAR
     basic*: RECORD
@@ -223,14 +229,14 @@ PROCEDURE typeName*(type: NamedType): JsString.Type;
     RETURN type.name
 END typeName;
 
-PROCEDURE Procedure.idType(): JsString.Type;
+PROCEDURE ProcedureId.idType(): JsString.Type;
     RETURN JsString.make("procedure")
-END Procedure.idType;
-
+END ProcedureId.idType;
+(*
 PROCEDURE String.idType(): JsString.Type;
     RETURN JsString.make("string")
 END String.idType;
-
+*)
 PROCEDURE String.description(): JsString.Type;
 VAR
     prefix: JsString.Type;
@@ -290,6 +296,10 @@ PROCEDURE variableType*(v: Variable): PType;
     RETURN v.type
 END variableType;
 
+PROCEDURE procedureType*(p: ProcedureId): PType;
+    RETURN p.type
+END procedureType;
+
 PROCEDURE isVariableReadOnly*(v: Variable): BOOLEAN;
     RETURN v.readOnly
 END isVariableReadOnly;
@@ -297,10 +307,14 @@ END isVariableReadOnly;
 PROCEDURE ExportedVariable.idType(): JsString.Type;
     RETURN JsString.make("imported variable")
 END ExportedVariable.idType;
-
+(*
 PROCEDURE BasicType.idType(): JsString.Type;
     RETURN JsString.make("type")
 END BasicType.idType;
+*)
+PROCEDURE TypeId.idType(): JsString.Type;
+    RETURN JsString.make("type")
+END TypeId.idType;
 
 PROCEDURE BasicType.description(): JsString.Type;
     RETURN SELF.name
@@ -344,11 +358,11 @@ BEGIN
     result.mInitializer := JsString.make(initializer);
     RETURN result
 END makeBasic;
-
+(*
 PROCEDURE Record.idType(): JsString.Type;
     RETURN JsString.make("record")
 END Record.idType;
-
+*)
 PROCEDURE Record.description(): JsString.Type;
 VAR
     result: JsString.Type;
@@ -419,11 +433,11 @@ END recordConstructor;
 PROCEDURE recordOwnFields*(r: Record): JsMap.Type;
     RETURN r.fields
 END recordOwnFields;
-
+(*
 PROCEDURE Pointer.idType(): JsString.Type;
     RETURN JsString.make("pointer")
 END Pointer.idType;
-
+*)
 PROCEDURE pointerBase*(p: Pointer): PRecord;
 VAR
     result: PType;
@@ -449,11 +463,11 @@ END Pointer.description;
 PROCEDURE Pointer.initializer(cx: Context.Type): JsString.Type;
     RETURN JsString.make("null")
 END Pointer.initializer;
-
+(*
 PROCEDURE Array.idType(): JsString.Type;
     RETURN JsString.make("array")
 END Array.idType;
-
+*)
 PROCEDURE foldArrayDimensions(a: Array; VAR sizes, of: JsString.Type);
 BEGIN  
     IF (a.len # openArrayLength) & (a.elementsType IS PArray) THEN
@@ -623,6 +637,15 @@ BEGIN
     RETURN result
 END makeExportedVariable;
 
+PROCEDURE makeProcedure*(type: PType): PProcedureId;
+VAR
+    result: PProcedureId;
+BEGIN
+    NEW(result);
+    result.type := type;
+    RETURN result
+END makeProcedure;
+
 PROCEDURE initProcedure*(p: Procedure; name: JsString.Type);
 BEGIN
     p.name := name;

+ 4 - 4
src/oc.js

@@ -1,7 +1,7 @@
 "use strict";
 
 var Class = require("rtl.js").Class;
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var Lexer = require("js/Lexer.js");
@@ -38,7 +38,7 @@ function compileModule(grammar, stream, context, handleErrors){
     var scope = context.currentScope();
     return new CompiledModule(
             scope.module(),
-            context.codeGenerator().getResult(),
+            context.codeGenerator().result(),
             scope.exports());
 }
 
@@ -107,11 +107,11 @@ function compileModules(names, moduleReader, grammar, contextFactory, handleErro
 function compile(text, grammar, handleErrors){
     var result = "";
     var rtl = new RTL();
-    var moduleCode = function(name, imports){return new Code.ModuleGenerator(name, imports);};
+    var moduleCode = function(name, imports){return Code.makeModuleGenerator(name, imports);};
     var resolver = makeResolver(
             grammar,
             function(moduleResolver){
-                return new Context.Context(new Code.Generator(),
+                return new Context.Context(Code.makeGenerator(),
                                            moduleCode,
                                            rtl,
                                            moduleResolver);

+ 16 - 14
src/operator.js

@@ -1,7 +1,7 @@
 "use strict";
 
 var Cast = require("cast.js");
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var Type = require("js/Types.js");
 
@@ -23,21 +23,21 @@ var precedence = {
     assignment: 17
 };
 
-function makeBinary(op, code, precedence, resultPrecedence){
+function makeBinary(op, code, precedence, resultPrecedence, resultType){
     return function(left, right, context){
         var leftValue = left.constValue();
         var rightValue = right.constValue();
         var value = (leftValue !== undefined && rightValue !== undefined)
             ? op(leftValue, rightValue) : undefined;
 
-        var leftCode = Code.adjustPrecedence(left.deref(), precedence);
+        var leftCode = Code.adjustPrecedence(Code.derefExpression(left), precedence);
 
         // right code needs parentheses even if it has the same percedence
-        var rightCode = Code.adjustPrecedence(right.deref(), precedence - 1);
+        var rightCode = Code.adjustPrecedence(Code.derefExpression(right), precedence - 1);
         var expCode = (typeof code == "function")
                     ? code(leftCode, rightCode, context)
                     : leftCode + code + rightCode;
-        return new Code.Expression(expCode, left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
+        return Code.makeExpressionWithPrecedence(expCode, resultType ? resultType : left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
     };
 }
 
@@ -47,8 +47,8 @@ function makeUnary(op, code){
         var value = e.constValue();
         if (value !== undefined)
             value = op(value, type) ;
-        var expCode = code + Code.adjustPrecedence(e.deref(), precedence.unary);
-        return new Code.Expression(expCode, type, undefined, value);
+        var expCode = code + Code.adjustPrecedence(Code.derefExpression(e), precedence.unary);
+        return Code.makeExpression(expCode, type, undefined, value);
     };
 }
 
@@ -65,7 +65,7 @@ function castToStr(e, context){
 
 function makeStrCmp(op){
     return function(left, right, context){
-        return new Code.Expression(
+        return Code.makeExpression(
             context.rtl().strCmp(castToStr(left, context),
                                  castToStr(right, context))
                 + op + "0",
@@ -75,13 +75,14 @@ function makeStrCmp(op){
 }
 
 function pow2(e){
-    return new Code.Expression("Math.pow(2, " + e.deref().code() + ")",
+    return Code.makeExpression("Math.pow(2, " + Code.derefExpression(e).code() + ")",
                                basicTypes.real);
 }
 
 function log2(e){
-    return new Code.Expression("(Math.log(" + e.deref().code() + ") / Math.LN2) | 0",
-                               basicTypes.integer, undefined, undefined, precedence.bitOr);
+    return Code.makeExpressionWithPrecedence(
+        "(Math.log(" + Code.derefExpression(e).code() + ") / Math.LN2) | 0",
+        basicTypes.integer, undefined, undefined, precedence.bitOr);
 }
 
 function assign(left, right, context){
@@ -123,7 +124,7 @@ function assign(left, right, context){
     if (isArray || rightType instanceof Type.Record)
         return context.rtl().copy(rightCode, leftCode);
 
-    var castCode = castOperation(context, right.deref()).code();
+    var castCode = castOperation(context, Code.derefExpression(right)).code();
     rightCode = castCode ? castCode : rightCode;
     return leftCode + (info instanceof Type.VariableRef 
                       ? ".set(" + rightCode + ")"
@@ -135,7 +136,7 @@ function makeInplace(code, altOp){
         var info = left.designator().info();
         if (info instanceof Type.VariableRef)
             return assign(left, altOp(left, right));
-        return left.code() + code + right.deref().code();
+        return left.code() + code + Code.derefExpression(right).code();
     };
 }
 
@@ -143,7 +144,7 @@ function promoteToWideIfNeeded(op){
     return function(){
         var result = op.apply(this, arguments);
         if (result.type() == basicTypes.uint8)
-            result = new Code.Expression(
+            result = Code.makeExpressionWithPrecedence(
                 result.code(),
                 basicTypes.integer,
                 result.designator(),
@@ -189,6 +190,7 @@ var operators = {
     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),

+ 33 - 27
src/procedure.js

@@ -2,11 +2,11 @@
 
 var Cast = require("cast.js");
 var Class = require("rtl.js").Class;
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Errors = require("js/Errors.js");
 var op = require("operator.js");
 var precedence = require("operator.js").precedence;
-var Symbol = require("symbol.js");
+var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
 var basicTypes = Type.basic();
@@ -35,7 +35,7 @@ var ProcCallGenerator = Class.extend({
         this.__id = id;
         this.__type = type;
         this.__argumentsCount = 0;
-        this.__code = new Code.SimpleGenerator();
+        this.__code = Code.makeSimpleGenerator();
         this.writeCode(this.prolog());
     },
     //id: function(){return this.__id;},
@@ -57,7 +57,7 @@ var ProcCallGenerator = Class.extend({
         this.writeArgumentCode(e, pos, isVarArg, convert);
     },
     writeArgumentCode: function(e, pos, isVar, convert){
-        e = isVar ? e.ref() : e.deref();
+        e = (isVar ? Code.refExpression : Code.derefExpression)(e);
         var code = (convert ? convert(this.__context, e) : e).code();
         var prefix = pos ? ", " : "";
         this.writeCode(prefix + code);
@@ -69,7 +69,7 @@ var ProcCallGenerator = Class.extend({
     },
     callExpression: function(){
         this.writeCode(this.epilog());
-        return new Code.Expression(this.__code.result(),
+        return Code.makeExpression(this.__code.result(),
                                    this.resultType());
     },
     resultType: function(){return this.__type ? this.__type.result() : undefined;},
@@ -188,10 +188,14 @@ var TwoArgToOperatorProcCallGenerator = ExpCallGenerator.extend({
     },
     callExpression: function(){
         var args = this.args();
-        return new Code.Expression(this.__operator(args[0], args[1]));
+        return Code.makeExpression(this.__operator(args[0], args[1]));
     }
 });
 
+function makeProcSymbol(name, proc){
+    return Symbol.makeSymbol(name, Type.makeProcedure(proc));
+}
+
 function setBitImpl(name, bitOp){
     var args = [new Arg(basicTypes.set, true),
                 new Arg(basicTypes.integer, false)];
@@ -199,7 +203,7 @@ function setBitImpl(name, bitOp){
         var value = y.constValue();
         var valueCode;
         if (value === undefined)
-            valueCode = op.lsl(new Code.Expression("1"), y).code();
+            valueCode = op.lsl(Code.makeExpression("1"), y).code();
         else {
             if (value < 0 || value > 31)
                 throw new Errors.Error("value (0..31) expected as a second argument of " + name + ", got " + value);
@@ -217,7 +221,7 @@ function setBitImpl(name, bitOp){
             return new TwoArgToOperatorProcCallGenerator(
                 context, id, type, operator);
             });
-    var symbol = new Symbol.Symbol(name, proc);
+    var symbol = makeProcSymbol(name, proc);
     return symbol;
 }
 
@@ -254,7 +258,7 @@ function incImpl(name, unary, op){
             return new CallGenerator(
                 context, id, type, operator);
             });
-    var symbol = new Symbol.Symbol(name, proc);
+    var symbol = makeProcSymbol(name, proc);
     return symbol;
 }
 
@@ -278,7 +282,7 @@ function bitShiftImpl(name, op){
         function(context, id, type){
             return new CallGenerator(context, id, type);
         });
-    var symbol = new Symbol.Symbol(name, proc);
+    var symbol = makeProcSymbol(name, proc);
     return symbol;
 }
 
@@ -323,7 +327,7 @@ exports.predefined = [
             function(context, id, type){
                 return new NewProcCallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol(name, type);
+        var symbol = makeProcSymbol(name, type);
         return symbol;
     }(),
     function(){
@@ -352,7 +356,7 @@ exports.predefined = [
             function(context, id, type){
                 return new LenProcCallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol(name, type);
+        var symbol = makeProcSymbol(name, type);
         return symbol;
     }(),
     function(){
@@ -363,7 +367,8 @@ exports.predefined = [
             callExpression: function(){
                 var e = this.args()[0];
                 var code = Code.adjustPrecedence(e, precedence.bitAnd);
-                return new Code.Expression(code + " & 1", basicTypes.bool, undefined, e.constValue(), precedence.bitAnd);
+                return Code.makeExpressionWithPrecedence(
+                    code + " & 1", basicTypes.bool, undefined, e.constValue(), precedence.bitAnd);
             }
         });
         var name = "ODD";
@@ -375,7 +380,7 @@ exports.predefined = [
             function(context, id, type){
                 return new CallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol(name, type);
+        var symbol = makeProcSymbol(name, type);
         return symbol;
     }(),
     function(){
@@ -394,7 +399,7 @@ exports.predefined = [
             function(context, id, type){
                 return new AssertProcCallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol("ASSERT", proc);
+        var symbol = makeProcSymbol("ASSERT", proc);
         return symbol;
     }(),
     setBitImpl("INCL", function(x, y){return x + " |= " + y;}),
@@ -426,7 +431,7 @@ exports.predefined = [
             function(context, id, type){
                 return new CallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol("ABS", proc);
+        var symbol = makeProcSymbol("ABS", proc);
         return symbol;
     }(),
     function(){
@@ -444,7 +449,7 @@ exports.predefined = [
             function(context, id, type){
                 return new CallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol("FLOOR", proc);
+        var symbol = makeProcSymbol("FLOOR", proc);
         return symbol;
     }(),
     function(){
@@ -454,7 +459,8 @@ exports.predefined = [
             },
             callExpression: function(){
                 var e = this.args()[0];
-                return new Code.Expression(e.code(), basicTypes.real, undefined, e.constValue(), e.maxPrecedence());
+                return Code.makeExpressionWithPrecedence(
+                    e.code(), basicTypes.real, undefined, e.constValue(), e.maxPrecedence());
             }
         });
         var args = [new Arg(basicTypes.integer, false)];
@@ -465,7 +471,7 @@ exports.predefined = [
             function(context, id, type){
                 return new CallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol("FLT", proc);
+        var symbol = makeProcSymbol("FLT", proc);
         return symbol;
     }(),
     bitShiftImpl("LSL", op.lsl),
@@ -482,20 +488,20 @@ exports.predefined = [
             checkArgument: function(pos, e){
                 var type = e.type();
                 if (type == basicTypes.ch || type == basicTypes.set)
-                    this.__callExpression = new Code.Expression(
+                    this.__callExpression = Code.makeExpression(
                         e.code(), basicTypes.integer, undefined, e.constValue());
                 else if (type == basicTypes.bool){
                     var code = Code.adjustPrecedence(e, precedence.conditional) + " ? 1 : 0";
                     var value = e.constValue();
                     if (value !== undefined)
                         value = value ? 1 : 0;
-                    this.__callExpression = new Code.Expression(
+                    this.__callExpression = Code.makeExpressionWithPrecedence(
                         code, basicTypes.integer, undefined, value, precedence.conditional);
                 }
                 else if (type instanceof Type.String){
                     var ch;
                     if (Type.stringAsChar(type, {set: function(v){ch = v;}}))
-                        this.__callExpression = new Code.Expression(
+                        this.__callExpression = Code.makeExpression(
                             "" + ch, basicTypes.integer);
                 }
                 
@@ -517,7 +523,7 @@ exports.predefined = [
             function(context, id, type){
                 return new CallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol(name, type);
+        var symbol = makeProcSymbol(name, type);
         return symbol;
     }(),
     function(){
@@ -526,7 +532,7 @@ exports.predefined = [
                 ExpCallGenerator.prototype.init.call(this, context, id, type);
             },
             callExpression: function(){
-                return new Code.Expression(this.args()[0].code(), basicTypes.ch);
+                return Code.makeExpression(this.args()[0].code(), basicTypes.ch);
             }
         });
         var name = "CHR";
@@ -537,7 +543,7 @@ exports.predefined = [
             function(context, id, type){
                 return new CallGenerator(context, id, type);
             });
-        var symbol = new Symbol.Symbol(name, type);
+        var symbol = makeProcSymbol(name, type);
         return symbol;
     }(),
     function(){
@@ -555,7 +561,7 @@ exports.predefined = [
                 return new TwoArgToOperatorProcCallGenerator(
                     context, id, type, operator);
                 });
-        var symbol = new Symbol.Symbol(name, proc);
+        var symbol = makeProcSymbol(name, proc);
         return symbol;
     }(),
     function(){
@@ -575,7 +581,7 @@ exports.predefined = [
                 return new TwoArgToOperatorProcCallGenerator(
                     context, id, type, operator);
                 });
-        var symbol = new Symbol.Symbol(name, proc);
+        var symbol = makeProcSymbol(name, proc);
         return symbol;
     }()
     ];

+ 17 - 2
src/rtl.js

@@ -27,8 +27,23 @@ Class.extend = function extend(methods){
 var impl = {
     extend: Class.extend,
     typeGuard: function(from, to){
-        if (!(from instanceof to))
-            throw new Error("typeguard assertion failed");
+        if (!(from instanceof to)){
+            var fromStr;
+            var toStr;
+            if (!from)
+                fromStr = "" + fromStr;
+            else if (from.constructor && from.constructor.name)
+                fromStr = "" + from.constructor.name;
+            if (!to)
+                toStr = "" + to;
+            else if (to.constructor && to.constructor.name)
+                toStr = "" + to.constructor.name;
+            
+            var msg = "typeguard assertion failed";
+            if (fromStr || toStr)               
+                msg += ": '" + fromStr + "' is not an extension of '" + toStr + "'";
+            throw new Error(msg);
+        }
         return from;
     },
     makeArray: function(/*dimensions, initializer*/){

+ 5 - 5
src/scope.js

@@ -3,7 +3,7 @@
 var Class = require("rtl.js").Class;
 var Errors = require("js/Errors.js");
 var Procedure = require("procedure.js");
-var Symbol = require("symbol.js");
+var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
 var stdSymbols = function(){
@@ -12,7 +12,7 @@ var stdSymbols = function(){
     for(var t in basicTypes){
         var type = basicTypes[t];
         var name = Type.typeName(type);
-        symbols[name] = new Symbol.Symbol(name, Type.makeTypeId(type));
+        symbols[name] = Symbol.makeSymbol(name, Type.makeTypeId(type));
     }
     
     var predefined = Procedure.predefined;
@@ -89,7 +89,7 @@ var CompiledModule = Type.Module.extend({
         for(var id in exports){
             var symbol = exports[id];
             if (symbol.isVariable())
-                symbol = new Symbol.Symbol(
+                symbol = Symbol.makeSymbol(
                     id,
                     Type.makeExportedVariable(symbol.info()));
             this.__exports[id] = symbol;
@@ -99,7 +99,7 @@ var CompiledModule = Type.Module.extend({
         var s = this.__exports[id];
         if (!s)
             return undefined;
-        return new Symbol.Found(s);
+        return Symbol.makeFound(s);
     }
 });
 
@@ -108,7 +108,7 @@ var Module = Scope.extend({
         Scope.prototype.init.call(this, "module");
         this.__name = name;
         this.__exports = {};
-        this.__symbol = new Symbol.Symbol(name, new CompiledModule(name));
+        this.__symbol = Symbol.makeSymbol(name, new CompiledModule(name));
         this.addSymbol(this.__symbol);
     },
     module: function(){return this.__symbol;},

+ 0 - 31
src/symbol.js

@@ -1,31 +0,0 @@
-"use strict";
-
-var Class = require("rtl.js").Class;
-var Errors = require("js/Errors.js");
-var Type = require("js/Types.js");
-
-var Symbol = Class.extend({
-	init: function Symbol(id, info){
-		this.__id = id;
-		this.__info = info;
-	},
-	id: function(){return this.__id;},
-	info: function(){return this.__info;},
-	isModule: function(){return this.__info instanceof Type.Module;},
-	isVariable: function(){return this.__info instanceof Type.Variable;},
-	isConst: function(){return this.__info instanceof Type.Const;},
-	isType: function(){return this.__info instanceof Type.TypeId;},
-	isProcedure: function(){return this.__info instanceof Type.Procedure;}
-});
-
-var FoundSymbol = Class.extend({
-    init: function(symbol, scope){
-        this.__symbol = symbol;
-        this.__scope = scope;
-    },
-    symbol: function(){return this.__symbol;},
-    scope: function(){return this.__scope;}
-});
-
-exports.Symbol = Symbol;
-exports.Found = FoundSymbol;

+ 17 - 2
test/expected/cast.js

@@ -14,8 +14,23 @@ var RTL$ = {
         return result;
     },
     typeGuard: function (from, to){
-        if (!(from instanceof to))
-            throw new Error("typeguard assertion failed");
+        if (!(from instanceof to)){
+            var fromStr;
+            var toStr;
+            if (!from)
+                fromStr = "" + fromStr;
+            else if (from.constructor && from.constructor.name)
+                fromStr = "" + from.constructor.name;
+            if (!to)
+                toStr = "" + to;
+            else if (to.constructor && to.constructor.name)
+                toStr = "" + to.constructor.name;
+            
+            var msg = "typeguard assertion failed";
+            if (fromStr || toStr)               
+                msg += ": '" + fromStr + "' is not an extension of '" + toStr + "'";
+            throw new Error(msg);
+        }
         return from;
     }
 };

+ 1 - 0
test/expected/is.js

@@ -42,4 +42,5 @@ b = pb instanceof Derived1;
 b = pb instanceof Derived1;
 b = pb instanceof Derived2;
 b = pd1 instanceof Derived2;
+b = !(pb instanceof Derived1);
 }();

+ 17 - 2
test/expected/modules.js

@@ -14,8 +14,23 @@ var RTL$ = {
         return result;
     },
     typeGuard: function (from, to){
-        if (!(from instanceof to))
-            throw new Error("typeguard assertion failed");
+        if (!(from instanceof to)){
+            var fromStr;
+            var toStr;
+            if (!from)
+                fromStr = "" + fromStr;
+            else if (from.constructor && from.constructor.name)
+                fromStr = "" + from.constructor.name;
+            if (!to)
+                toStr = "" + to;
+            else if (to.constructor && to.constructor.name)
+                toStr = "" + to.constructor.name;
+            
+            var msg = "typeguard assertion failed";
+            if (fromStr || toStr)               
+                msg += ": '" + fromStr + "' is not an extension of '" + toStr + "'";
+            throw new Error(msg);
+        }
         return from;
     },
     makeRef: function (obj, prop){

+ 4 - 1
test/input/is.ob

@@ -17,5 +17,8 @@ BEGIN
     b := pb^ IS Derived1;
     b := pb IS PDerived1;
     b := pb^ IS Derived2;
-    b := pd1^ IS Derived2
+    b := pd1^ IS Derived2;
+
+    (* check operator precedence*)
+    b := ~(pb IS PDerived1);
 END m.

+ 3 - 3
test/test_unit_common.js

@@ -1,7 +1,7 @@
 "use strict";
 
 var Class = require("rtl.js").Class;
-var Code = require("code.js");
+var Code = require("js/Code.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var oc = require("oc.js");
@@ -30,12 +30,12 @@ var TestContext = Context.Context.extend({
     init: function TestContext(){
         Context.Context.prototype.init.call(
                 this,
-                Code.nullGenerator,
+                Code.nullGenerator(),
                 function(){return new TestModuleGenerator();},
                 new RTL());
         this.pushScope(new Scope.Module("test"));
     },
-    qualifyScope: function(){return "";},
+    qualifyScope: function(){return "";}
 });
 
 function makeContext(){return new TestContext();}