Ver código fonte

js -> eberon transition

Vladislav Folts 10 anos atrás
pai
commit
88705c68b7

BIN
bin/compiled.zip


+ 51 - 135
src/context.js

@@ -6,16 +6,21 @@ var CodeGenerator = require("js/CodeGenerator.js");
 var ConstValue = require("js/ConstValue.js");
 var ContextExpression = require("js/ContextExpression.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
+var Designator = require("js/Designator.js");
 var Errors = require("js/Errors.js");
+var Expression = require("js/Expression.js");
 var Module = require("js/Module.js");
 var op = require("js/Operator.js");
 var ObContext = require("js/Context.js");
 var Parser = require("parser.js");
 var Procedure = require("js/Procedure.js");
+var Record = require("js/Record.js");
 var Class = require("rtl.js").Class;
 var Scope = require("js/Scope.js");
 var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
+var TypeId = require("js/TypeId.js");
+var Variable = require("js/Variable.js");
 
 var basicTypes = Type.basic();
 var nullCodeGenerator = CodeGenerator.nullGenerator();
@@ -36,7 +41,7 @@ exports.BaseType = ChainedContext.extend({
     },
     handleQIdent: function(q){
         var s = ContextHierarchy.getQIdSymbolAndScope(this.root(), q);
-        this.parent().setBaseType(ContextHierarchy.unwrapType(s.symbol().info()));
+        this.parent().setBaseType(ContextExpression.unwrapType(s.symbol().info()));
     }
 });
 
@@ -74,7 +79,7 @@ exports.QualifiedIdentificator = ChainedContext.extend({
         this.__code = id + ".";
     },
     endParse: function(){
-        var code = this.__code ? this.__code + Type.mangleJSProperty(this.__id) : this.__id;
+        var code = this.__code ? this.__code + Record.mangleJSProperty(this.__id) : this.__id;
         this.parent().handleQIdent({
             module: this.__module,
             id: this.__id,
@@ -99,11 +104,6 @@ exports.Identdef = ChainedContext.extend({
     }
 });
 
-function castCode(type, context){
-    var baseType = type instanceof Type.Pointer ? Type.pointerBase(type) : type;
-    return Type.recordConstructor(context, baseType);
-}
-
 function makeContext(context){
     var l = context.root().language();
     return {
@@ -152,7 +152,7 @@ exports.Designator = ChainedContext.extend({
         var t = this.__currentType;
         var isReadOnly = this.__info instanceof Type.Variable 
                       && this.__info.isReadOnly();
-        if (t instanceof Type.Pointer){
+        if (t instanceof Record.Pointer){
             this.__handleDeref();
             isReadOnly = false;
         }
@@ -170,13 +170,13 @@ exports.Designator = ChainedContext.extend({
     _currentInfo: function(){return this.__info;},
     _discardCode: function(){this.__code = "";},
     _makeDerefVar: function(info){
-        return new Type.DerefVariable(this.__currentType, this.__code);
+        return new Variable.DerefVariable(this.__currentType, this.__code);
     },
     handleExpression: function(e){this.__indexExpression = e;},
     __handleIndexExpression: function(){
         var e = this.__indexExpression;
         this._checkIndexType(e.type());
-        var index = this._indexSequence(this.__info, this.__derefCode, Code.derefExpression(e).code());
+        var index = this._indexSequence(this.__info, this.__derefCode, Expression.deref(e).code());
         this._checkIndexValue(index, e.constValue());  
         return index;
     },
@@ -228,14 +228,14 @@ exports.Designator = ChainedContext.extend({
 
         return { length: length,
                  type: indexType,
-                 info: new Type.PropertyVariable(indexType, leadCode, indexCode, info instanceof Type.Const || info.isReadOnly(), this.root().language().rtl),
+                 info: new Variable.PropertyVariable(indexType, leadCode, indexCode, info instanceof Type.Const || info.isReadOnly(), this.root().language().rtl),
                  code: code,
                  lval: lval,
                  asProperty: indexCode
                };
     },
     _stringIndexCode: function(){
-        return this.__derefCode + ".charCodeAt(" + Code.derefExpression(this.__indexExpression).code() + ")";
+        return this.__derefCode + ".charCodeAt(" + Expression.deref(this.__indexExpression).code() + ")";
     },
     handleLiteral: function(s){
         if (s == "]" || s == ","){
@@ -253,18 +253,18 @@ exports.Designator = ChainedContext.extend({
         }
     },
     __handleDeref: function(){
-        if (!(this.__currentType instanceof Type.Pointer))
+        if (!(this.__currentType instanceof Record.Pointer))
             throw new Errors.Error("POINTER TO type expected, got '"
                                  + this.__currentType.description() + "'");
-        this.__currentType = Type.pointerBase(this.__currentType);
-        if (this.__currentType instanceof Type.NonExportedRecord)
+        this.__currentType = Record.pointerBase(this.__currentType);
+        if (this.__currentType instanceof Record.NonExported)
             throw new Errors.Error("POINTER TO non-exported RECORD type cannot be dereferenced");
         this.__lval = undefined;
     },
     handleTypeCast: function(type){
-        ContextHierarchy.checkTypeCast(this.__info, this.__currentType, type, "type cast");
+        ContextExpression.checkTypeCast(this.__info, this.__currentType, type, "type cast");
 
-        var code = this.root().language().rtl.typeGuard(this.__code, castCode(type, this));
+        var code = this.root().language().rtl.typeGuard(this.__code, ContextExpression.castCode(type, this));
         this.__code = code;
 
         this.__currentType = type;
@@ -272,7 +272,7 @@ exports.Designator = ChainedContext.extend({
     endParse: function(){
         var code = this.__code;
         this.parent().attributes.designator =
-            new Code.Designator(code, this.__lval ? this.__lval : code, this.__currentType, this.__info, this.__scope);
+            new Designator.Type(code, this.__lval ? this.__lval : code, this.__currentType, this.__info, this.__scope);
     }
 });
 
@@ -291,7 +291,7 @@ var HandleSymbolAsType = ChainedContext.extend({
     },
     handleQIdent: function(q){
         var s = ContextHierarchy.getQIdSymbolAndScope(this.root(), q);
-        this.setType(ContextHierarchy.unwrapType(s.symbol().info()));
+        this.setType(ContextExpression.unwrapType(s.symbol().info()));
     }
 });
 
@@ -349,7 +349,7 @@ exports.FormalParameters = ChainedContext.extend({
     },
     handleQIdent: function(q){
         var s = ContextHierarchy.getQIdSymbolAndScope(this.root(), q);
-        var resultType = ContextHierarchy.unwrapType(s.symbol().info());
+        var resultType = ContextExpression.unwrapType(s.symbol().info());
         this._checkResultType(resultType);
         this.__result = resultType;
     },
@@ -435,7 +435,7 @@ exports.ProcDecl = ChainedContext.extend({
         code.write(name + "/*" + arg.description() + "*/");
     },
     _makeArgumentVariable: function(arg, name){
-        return new Type.ArgumentVariable(name, arg.type, arg.isVar);
+        return new Variable.ArgumentVariable(name, arg.type, arg.isVar);
     },
     handleMessage: function(msg){
         if (msg == endParametersMsg){
@@ -524,11 +524,11 @@ exports.PointerDecl = ChainedContext.extend({
         
         var info = s ? s.symbol().info()
                      : this.parent().handleMessage(new ForwardTypeMsg(id));
-        var typeId = ContextHierarchy.unwrapTypeId(info);
+        var typeId = ContextExpression.unwrapTypeId(info);
         this.__setTypeId(typeId);
     },
     __setTypeId: function(typeId){
-        if (!(typeId instanceof Type.ForwardTypeId)){
+        if (!(typeId instanceof TypeId.Forward)){
             var type = typeId.type();
             if (!(type instanceof Type.Record))
                 throw new Errors.Error(
@@ -539,12 +539,12 @@ exports.PointerDecl = ChainedContext.extend({
         var name = parent.isAnonymousDeclaration() 
             ? ""
             : parent.genTypeName();
-        var pointerType = new Type.Pointer(name, typeId);
+        var pointerType = new Record.Pointer(name, typeId);
         parent.setType(pointerType);
     },
     setType: function(type){
-        var typeId = new Type.TypeId(type);
-        this.root().currentScope().addFinalizer(function(){typeId.strip();});
+        var typeId = new TypeId.Type(type);
+        this.root().currentScope().addFinalizer(function(){Record.stripTypeId(typeId);});
         this.__setTypeId(typeId);
     },
     isAnonymousDeclaration: function(){return true;},
@@ -614,102 +614,18 @@ exports.ArrayDimensions = ChainedContext.extend({
     }
 });
 
-function useIntOrderOp(t){
-    return Type.isInt(t) || t == basicTypes.ch;
-}
-
-function useIntEqOp(t){
-    return Type.isInt(t)
-        || t == basicTypes.bool
-        || t == basicTypes.ch
-        || t instanceof Type.Pointer
-        || t instanceof Type.Procedure
-        || t == nilType;
-}
-
-var RelationOps = Class.extend({
-    init: function RelationOps(){
-    },
-    eq: function(type){
-        return useIntEqOp(type)         ? op.equalInt 
-             : Type.isString(type)      ? op.equalStr
-             : type == basicTypes.real  ? op.equalReal
-             : type == basicTypes.set   ? op.equalSet
-                                        : undefined;
-    },
-    notEq: function(type){
-        return useIntEqOp(type)         ? op.notEqualInt 
-             : Type.isString(type)      ? op.notEqualStr
-             : type == basicTypes.real  ? op.notEqualReal
-             : type == basicTypes.set   ? op.notEqualSet
-                                        : undefined;
-    },
-    less: function(type){
-        return useIntOrderOp(type) ?    op.lessInt
-             : Type.isString(type)      ? op.lessStr 
-             : type == basicTypes.real  ? op.lessReal
-                                        : undefined;
-    },
-    greater: function(type){
-        return useIntOrderOp(type) ?    op.greaterInt
-             : Type.isString(type)      ? op.greaterStr 
-             : type == basicTypes.real  ? op.greaterReal
-                                        : undefined;
-    },
-    lessEq: function(type){
-        return useIntOrderOp(type) ?    op.eqLessInt
-             : Type.isString(type)      ? op.eqLessStr 
-             : type == basicTypes.real  ? op.eqLessReal
-             : type == basicTypes.set   ? op.setInclL
-                                        : undefined;
-    },
-    greaterEq: function(type){
-        return useIntOrderOp(type)      ? op.eqGreaterInt
-             : Type.isString(type)      ? op.eqGreaterStr 
-             : type == basicTypes.real  ? op.eqGreaterReal
-             : type == basicTypes.set   ? op.setInclR
-                                        : undefined;
-    },
-    is: function(type, context){
-        return function(left, right){
-                var d = left.designator();
-                ContextHierarchy.checkTypeCast(d ? d.info() : undefined, left.type(), type, "type test");
-                return op.is(left, Code.makeExpression(castCode(type, context)));
-            };
-    },
-    eqExpect: function(){return "numeric type or SET or BOOLEAN or CHAR or character array or POINTER or PROCEDURE";},
-    strongRelExpect: function(){return "numeric type or CHAR or character array";},
-    relExpect: function(){return "numeric type or SET or CHAR or character array";},
-    coalesceType: function(leftType, rightType){
-        if (leftType instanceof Type.Pointer && rightType instanceof Type.Pointer){
-            var type = Cast.findPointerBaseType(leftType, rightType);
-            if (!type)
-                type = Cast.findPointerBaseType(rightType, leftType);
-            if (type)
-                return type;
-        }
-
-        // special case for strings
-        var isStrings = Type.isString(leftType) && Type.isString(rightType);
-        if (!isStrings)
-            ContextHierarchy.checkTypeMatch(rightType, leftType);
-
-        return leftType;
-    }
-});
-
-var relationOps = new RelationOps();
+var relationOps = new ContextExpression.RelationOps();
 
 function checkSetHasBit(leftType, rightType, context){
     if (!Type.isInt(leftType))
         throw new Errors.Error(
             Type.intsDescription() + " expected as an element of SET, got '" + Type.typeName(leftType) + "'");
-    ContextHierarchy.checkImplicitCast(context.root(), rightType, basicTypes.set);
+    ContextExpression.checkImplicitCast(context.root(), rightType, basicTypes.set);
 }
 
 function relationOp(leftType, rightType, literal, ops, context){
     var type = 
-          literal == "IS" ? ContextHierarchy.unwrapType(rightType)
+          literal == "IS" ? ContextExpression.unwrapType(rightType)
         : literal == "IN" ? checkSetHasBit(leftType, rightType, context)
                           : ops.coalesceType(leftType, rightType);
     var o;
@@ -812,7 +728,7 @@ function designatorAsExpression(d){
     var value;
     if (info instanceof Type.Const)
         value = info.value;
-    return Code.makeExpression(d.code(), d.type(), d, value);
+    return Expression.make(d.code(), d.type(), d, value);
 }
 
 exports.Set = ChainedContext.extend({
@@ -846,7 +762,7 @@ exports.Set = ChainedContext.extend({
             var code = this.root().language().rtl.makeSet(this.__expr);
             if (this.__value)
                 code += " | " + this.__value;
-            var e = Code.makeExpression(code, basicTypes.set);
+            var e = Expression.make(code, basicTypes.set);
             parent.handleExpression(e);
         }
     }
@@ -895,11 +811,12 @@ exports.Expression = ChainedContext.extend({
 
         var leftExpression = this.__expression;
         var rightExpression = e;
-        leftExpression = ContextHierarchy.promoteTypeInExpression(leftExpression, rightExpression.type());
-        rightExpression = ContextHierarchy.promoteTypeInExpression(rightExpression, leftExpression.type());
+        leftExpression = ContextExpression.promoteTypeInExpression(leftExpression, rightExpression.type());
+        rightExpression = ContextExpression.promoteTypeInExpression(rightExpression, leftExpression.type());
 
         var o = this._relationOperation(leftExpression.type(), rightExpression.type(), this.__relation);
-        this.__expression = o(leftExpression, rightExpression, this.root().language());
+        var language = this.root().language();
+        this.__expression = o(leftExpression, rightExpression, language);
     },
     _relationOperation: function(left, right, relation){
         return relationOp(left, right, relation, this.__relOps, this);
@@ -1291,7 +1208,7 @@ exports.VariableDeclaration = HandleSymbolAsType.extend({
             if (id.exported())
                 this.checkExport(varName);
 
-            var v = new Type.DeclaredVariable(varName, this.__type);
+            var v = new Variable.DeclaredVariable(varName, this.__type);
             this.root().currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
             gen.write("var " + varName + " = " + this._initCode() + ";");
         }
@@ -1357,9 +1274,9 @@ function isTypeRecursive(type, base){
     if (type == base)
         return true;
     if (type instanceof Type.Record){
-        if (isTypeRecursive(Type.recordBase(type), base))
+        if (isTypeRecursive(type.base, base))
             return true;
-        var fields = Type.recordOwnFields(type);
+        var fields = type.fields;
         for(var fieldName in fields){
             if (isTypeRecursive(fields[fieldName].type(), base))
                 return true;
@@ -1417,35 +1334,35 @@ exports.RecordDecl = ChainedContext.extend({
         return gen.result();
     },
     _qualifiedBaseConstructor: function(){
-        var baseType = Type.recordBase(this.__type);
+        var baseType = this.__type.base;
         if (!baseType)
             return "";
-        return this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType);
+        return this.qualifyScope(baseType.scope) + Type.typeName(baseType);
     },
     _generateBaseConstructorCallCode: function(){
-        var baseType = Type.recordBase(this.__type);
-        var qualifiedBase = baseType ? this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType) : undefined; 
+        var baseType = this.__type.base;
+        var qualifiedBase = baseType ? this.qualifyScope(baseType.scope) + Type.typeName(baseType) : undefined; 
         var result = this._qualifiedBaseConstructor();
         return result ? result + ".call(this);\n" : "";
     },
     __generateFieldsInitializationCode: function(){
         var result = "";
-        var ownFields = Type.recordOwnFields(this.__type);
+        var ownFields = this.__type.fields;
         for(var f in ownFields){
             var fieldType = ownFields[f].type();
-            result += "this." + Type.mangleField(f) + " = " + fieldType.initializer(this) + ";\n";
+            result += "this." + Record.mangleField(f) + " = " + fieldType.initializer(this) + ";\n";
         }
         return result;
     },
     _generateInheritance: function(){
-        var base = Type.recordBase(this.__type);
+        var base = this.__type.base;
         if (!base)
             return "";
-        var qualifiedBase = this.qualifyScope(Type.recordScope(base)) + Type.typeName(base); 
+        var qualifiedBase = this.qualifyScope(base.scope) + Type.typeName(base); 
         return this.root().language().rtl.extend(this.__cons, qualifiedBase) + ";\n";
     },
     _makeField: function(field, type){
-        return new Type.RecordField(field, type);
+        return new Record.Field(field, type);
     }
 });
 
@@ -1456,17 +1373,17 @@ exports.TypeDeclaration = ChainedContext.extend({
         this.__symbol = undefined;
     },
     handleIdentdef: function(id){
-        var typeId = new Type.LazyTypeId();
+        var typeId = new TypeId.Lazy();
         var symbol = new Symbol.Symbol(id.id(), typeId);
         var scope = this.root().currentScope();
         scope.addSymbol(symbol, id.exported());
         if (!id.exported())
-            scope.addFinalizer(function(){typeId.strip();});
+            scope.addFinalizer(function(){Record.stripTypeId(typeId);});
         this.__id = id;
         this.__symbol = symbol;
     },
     setType: function(type){
-        Type.defineTypeId(this.__symbol.info(), type);
+        TypeId.define(this.__symbol.info(), type);
         Scope.resolve(this.root().currentScope(), this.__symbol);
     },
     typeName: function(){return this.__id.id();},
@@ -1491,7 +1408,7 @@ exports.TypeSection = ChainedContext.extend({
                 return ContextHierarchy.getSymbol(this.root(), msg.id).info().type();
             }.bind(this);
 
-            return new Type.ForwardTypeId(resolve);
+            return new TypeId.Forward(resolve);
         }
         return ChainedContext.prototype.handleMessage.call(this, msg);
     },
@@ -1654,6 +1571,5 @@ exports.Chained = ChainedContext;
 exports.designatorAsExpression = designatorAsExpression;
 exports.endParametersMsg = endParametersMsg;
 exports.makeProcCall = makeProcCall;
-exports.RelationOps = RelationOps;
 exports.HandleSymbolAsType = HandleSymbolAsType;
 exports.makeContext = makeContext;

+ 3 - 3
src/eberon/EberonArray.ob

@@ -1,5 +1,5 @@
 MODULE EberonArray;
-IMPORT Code, EberonTypes, Errors, LanguageContext, Procedure, Types;
+IMPORT EberonTypes, Errors, Expression, LanguageContext, Procedure, Types;
 CONST
     methodNameIndexOf = "indexOf";
 TYPE
@@ -39,11 +39,11 @@ BEGIN
     RETURN Procedure.makeCallGenerator(call, cx)
 END MethodIndexOf.callGenerator;
 
-PROCEDURE MethodCallIndexOf.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE MethodCallIndexOf.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     argCode <- Procedure.makeArgumentsCode(cx);
     argType <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode).type();
-    RETURN Code.makeSimpleExpression("(" + argCode.result() + ")", Types.basic.integer)
+    RETURN Expression.makeSimple("(" + argCode.result() + ")", Types.basic.integer)
 END MethodCallIndexOf.make;
 
 PROCEDURE denoteMethod*(id: STRING; elementsType: Types.PType): Types.PField;

+ 10 - 7
src/eberon/EberonCast.ob

@@ -1,5 +1,8 @@
 MODULE EberonCast;
-IMPORT Cast, Code, Context, EberonMap, EberonString, EberonOperator, EberonDynamicArray, LanguageContext, OberonRtl, Types;
+IMPORT 
+    Cast, Code, Context, 
+    EberonMap, EberonString, EberonOperator, EberonDynamicArray, Expression, 
+    LanguageContext, OberonRtl, Types;
 TYPE
     CastOpToDynamicArray = RECORD (Cast.CastOpArray)
     END;
@@ -11,8 +14,8 @@ VAR
     castOpToDynamicArray: POINTER TO CastOpToDynamicArray;
     castOpToMap: POINTER TO CastOpToMap;
 
-PROCEDURE CastOpToDynamicArray.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
-    RETURN Code.makeSimpleExpression(Cast.cloneArray(e.type()(Types.PArray), e.code(), cx), NIL)
+PROCEDURE CastOpToDynamicArray.make(cx: LanguageContext.PType; e: Expression.PType): Expression.PType;
+    RETURN Expression.makeSimple(Cast.cloneArray(e.type()(Types.PArray), e.code(), cx), NIL)
 END;
 
 PROCEDURE copyArray(t: Types.PArray; leftCode, rightCode: STRING; rtl: OberonRtl.Type): STRING;
@@ -27,19 +30,19 @@ BEGIN
     RETURN result
 END;
 
-PROCEDURE CastOpToDynamicArray.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpToDynamicArray.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
     RETURN copyArray(left.type()(Types.PArray), left.code(), right.code(), cx.rtl^)
 END;
 
-PROCEDURE CastOpToMap.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastOpToMap.make(cx: LanguageContext.PType; e: Expression.PType): Expression.PType;
     RETURN e;
 END;
 
-PROCEDURE CastOpToMap.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpToMap.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
     RETURN cx.rtl.copy(right.code(), left.code(), EberonOperator.generateTypeInfo(left.type()));
 END;
 
-PROCEDURE CastOpToMap.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
+PROCEDURE CastOpToMap.clone(cx: LanguageContext.PType; e: Expression.PType): STRING;
     RETURN cx.rtl.clone(e.code(), EberonOperator.generateTypeInfo(e.type()), "undefined");
 END;
 

+ 17 - 15
src/eberon/EberonConstructor.ob

@@ -1,5 +1,7 @@
 MODULE EberonConstructor;
-IMPORT Cast, Code, EberonCast, EberonRecord, Errors, LanguageContext, Procedure, Stream, Types;
+IMPORT 
+    Cast, EberonCast, EberonRecord, Errors, Expression, 
+    LanguageContext, Procedure, Record, Stream, TypeId, Types;
 TYPE
     ConstructorCall = RECORD(Procedure.StdCall)
         recordType: EberonRecord.PRecord;
@@ -21,35 +23,35 @@ TYPE
         code: STRING;
     END;
 
-PROCEDURE checkArgs(call: ConstructorCall; args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): STRING;
+PROCEDURE checkArgs(call: ConstructorCall; args: ARRAY OF Expression.PType; cx: LanguageContext.PType): STRING;
 BEGIN
     argCode <- Procedure.makeArgumentsCode(cx);
     Procedure.processArguments(args, call.args, argCode, cx.types);
     RETURN argCode.result();
 END;
 
-PROCEDURE ConstructorCall.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE ConstructorCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     argCode <- checkArgs(SELF, args, cx);
-    RETURN Code.makeSimpleExpression(Types.recordInitializer(cx^, SELF.recordType^, argCode), SELF.resultType);
+    RETURN Expression.makeSimple(Record.initializer(cx^, SELF.recordType^, argCode), SELF.resultType);
 END;
 
-PROCEDURE BaseConstructorCall.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE BaseConstructorCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     argCode <- checkArgs(SELF, args, cx);
-    code <- Types.recordConstructor(cx^, SELF.recordType^) + ".call(this, " + argCode + ");" + Stream.kCR;
-    RETURN Code.makeSimpleExpression(code, NIL);
+    code <- Record.constructor(cx^, SELF.recordType^) + ".call(this, " + argCode + ");" + Stream.kCR;
+    RETURN Expression.makeSimple(code, NIL);
 END;
 
 PROCEDURE fieldInitLval(field: STRING): STRING;
-    RETURN "this." + Types.mangleField(field);
+    RETURN "this." + Record.mangleField(field);
 END;
 
-PROCEDURE RecordInitCall.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE RecordInitCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     e <- SUPER(args, cx);
     t <- e.type()(Types.PStorageType);
-    RETURN Code.makeSimpleExpression(fieldInitLval(SELF.field) + " = " + e.code(), t);
+    RETURN Expression.makeSimple(fieldInitLval(SELF.field) + " = " + e.code(), t);
 END;
 
 PROCEDURE makeCallGenerator(
@@ -73,7 +75,7 @@ BEGIN
     Errors.raise("single argument expected to initialize field '" + c.field + "'");
 END;
 
-PROCEDURE NonRecordInitCall.handleArgument(e: Code.PExpression);
+PROCEDURE NonRecordInitCall.handleArgument(e: Expression.PType);
 VAR
     op: LanguageContext.PCastOp;
 BEGIN
@@ -90,16 +92,16 @@ BEGIN
     SELF.code := lval + " = " + op.clone(SELF.cx, e);
 END;
         
-PROCEDURE NonRecordInitCall.end(): Code.PExpression;
+PROCEDURE NonRecordInitCall.end(): Expression.PType;
 BEGIN
     IF LEN(SELF.code) = 0 THEN
         raiseSingleArgumentException(SELF);
     END;
-    RETURN Code.makeSimpleExpression(SELF.code, NIL);
+    RETURN Expression.makeSimple(SELF.code, NIL);
 END;
 
 PROCEDURE makeConstructorCall*(
-    typeId: Types.PTypeId;
+    typeId: TypeId.PType;
     cx: LanguageContext.PType;
     forNew: BOOLEAN
     ): Procedure.PCallGenerator;
@@ -115,7 +117,7 @@ BEGIN
     
     EberonRecord.ensureCanBeInstantiated(cx^, recordType, instType);
     IF forNew THEN
-        resultType := NEW Types.Pointer("", typeId);
+        resultType := NEW Record.Pointer("", typeId);
     END;
     RETURN makeCallGenerator(recordType, resultType, cx, call);
 END;

+ 13 - 10
src/eberon/EberonDynamicArray.ob

@@ -1,5 +1,8 @@
 MODULE EberonDynamicArray;
-IMPORT Cast, Code, ConstValue, Context, EberonArray, EberonOperator, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Types;
+IMPORT 
+    Cast, Code, ConstValue, Context, 
+    EberonArray, EberonOperator, EberonRecord, EberonTypes, Errors, Expression, 
+    LanguageContext, Procedure, Record, Types;
 CONST
     methodNameAdd = "add";
     methodNameClear = "clear";
@@ -104,7 +107,7 @@ BEGIN
     RETURN result
 END;
 
-PROCEDURE AddCallGenerator.handleArgument(e: Code.PExpression);
+PROCEDURE AddCallGenerator.handleArgument(e: Expression.PType);
 BEGIN
     IF SELF.code # "" THEN
         Errors.raise("method 'add' expects one argument, got many");
@@ -122,17 +125,17 @@ BEGIN
     t <- e.type();
     IF t IS Types.PArray THEN
         SELF.code := Cast.cloneArray(t, SELF.code, SELF.cx);
-    ELSIF t IS Types.PRecord THEN
-        SELF.code := SELF.cx.rtl.clone(SELF.code, EberonOperator.generateTypeInfo(t), Types.recordConstructor(SELF.cx^, t^));
+    ELSIF t IS Record.PType THEN
+        SELF.code := SELF.cx.rtl.clone(SELF.code, EberonOperator.generateTypeInfo(t), Record.constructor(SELF.cx^, t^));
     END;
 END AddCallGenerator.handleArgument;
 
-PROCEDURE AddCallGenerator.end(): Code.PExpression;
+PROCEDURE AddCallGenerator.end(): Expression.PType;
 BEGIN
     IF SELF.code = "" THEN
         Errors.raise("method 'add' expects one argument, got nothing");
     END;
-    RETURN Code.makeSimpleExpression(
+    RETURN Expression.makeSimple(
             "(" + SELF.code + ")",
             NIL)
 END AddCallGenerator.end;
@@ -173,13 +176,13 @@ PROCEDURE MethodRemoveField.MethodRemoveField()
     | SUPER(NEW MethodRemove(methodNameRemove, NIL));
 END;
 
-PROCEDURE MethodCallClear.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE MethodCallClear.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     Procedure.processArguments(args, SELF.args, NIL, cx.types);
-    RETURN Code.makeSimpleExpression("(0, Number.MAX_VALUE)", NIL)
+    RETURN Expression.makeSimple("(0, Number.MAX_VALUE)", NIL)
 END MethodCallClear.make;
 
-PROCEDURE MethodCallRemove.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE MethodCallRemove.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     argCode <- Procedure.makeArgumentsCode(cx);
     arg <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode);
@@ -187,7 +190,7 @@ BEGIN
     IF (value # NIL) & (value^ IS ConstValue.Int) THEN
         Code.checkIndex(value.value);
     END;
-    RETURN Code.makeSimpleExpression("(" + argCode.result() + ", 1)", NIL)
+    RETURN Expression.makeSimple("(" + argCode.result() + ", 1)", NIL)
 END MethodCallRemove.make;
 
 PROCEDURE MethodClear.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;

+ 6 - 5
src/eberon/EberonMap.ob

@@ -1,5 +1,6 @@
 MODULE EberonMap;
-IMPORT Code, Context, EberonRtl, EberonString, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Types;
+IMPORT 
+    Context, EberonRtl, Expression, EberonString, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Record, Types;
 CONST
     removeMethodName = "remove";
     clearMethodName = "clear";
@@ -76,17 +77,17 @@ PROCEDURE Type.isScalar(): BOOLEAN;
     RETURN FALSE;
 END;
 
-PROCEDURE MethodCallRemove.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE MethodCallRemove.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     argCode <- Procedure.makeArgumentsCode(cx);
     arg <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode);
-    RETURN Code.makeSimpleExpression("[" + argCode.result() + "]", NIL)
+    RETURN Expression.makeSimple("[" + argCode.result() + "]", NIL)
 END;        
 
-PROCEDURE MethodCallClear.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE MethodCallClear.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     Procedure.checkArgumentsCount(LEN(args), 0);
-    RETURN Code.makeSimpleExpression("", NIL);
+    RETURN Expression.makeSimple("", NIL);
 END;
 
 PROCEDURE MapMethod.description(): STRING;

+ 14 - 14
src/eberon/EberonOperator.ob

@@ -1,5 +1,5 @@
 MODULE EberonOperator;
-IMPORT Cast, Code, CodePrecedence, ConstValue, EberonMap, LanguageContext, OberonRtl, Operator, Types;
+IMPORT Cast, CodePrecedence, ConstValue, EberonMap, Expression, LanguageContext, OberonRtl, Operator, Record, Types;
 TYPE
     CastOpRecord = RECORD(Cast.CastOpRecord)
     END;
@@ -41,37 +41,37 @@ PROCEDURE opGraterEqualStr(left, right: ConstValue.PType): ConstValue.PType;
                                >= right^(ConstValue.String).value))
 END opGraterEqualStr;
 
-PROCEDURE addStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE addStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.binaryWithCode(left, right, opAddStr, " + ", CodePrecedence.addSub)
 END addStr;
 
-PROCEDURE equalStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE equalStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.equal(left, right, opEqualStr, Operator.equalCode)
 END equalStr;
 
-PROCEDURE notEqualStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE notEqualStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.equal(left, right, opNotEqualStr, Operator.notEqualCode)
 END notEqualStr;
 
-PROCEDURE lessStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE lessStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.relational(left, right, opLessStr, " < ")
 END lessStr;
 
-PROCEDURE greaterStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE greaterStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.relational(left, right, opGreaterStr, " > ")
 END greaterStr;
 
-PROCEDURE lessEqualStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE lessEqualStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.relational(left, right, opLessEqualStr, " <= ")
 END lessEqualStr;
 
-PROCEDURE greaterEqualStr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE greaterEqualStr*(left, right: Expression.PType): Expression.PType;
     RETURN Operator.relational(left, right, opGraterEqualStr, " >= ")
 END greaterEqualStr;
 
-PROCEDURE inMap*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Code.makeSimpleExpression("Object.prototype.hasOwnProperty.call(" + right.code() + ", " + left.code() + ")",
-                                     Types.basic.bool);
+PROCEDURE inMap*(left, right: Expression.PType; rtl: OberonRtl.PType): Expression.PType;
+    RETURN Expression.makeSimple("Object.prototype.hasOwnProperty.call(" + right.code() + ", " + left.code() + ")",
+                                 Types.basic.bool);
 END;
 
 PROCEDURE generateTypeInfo*(type: Types.PType): STRING;
@@ -81,12 +81,12 @@ BEGIN
     IF type IS EberonMap.PType THEN
         result := "{map: " + generateTypeInfo(type.valueType) + "}";
     ELSE
-        result := Types.generateTypeInfo(type);
+        result := Record.generateTypeInfo(type);
     END;
     RETURN result;
 END;
 
-PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
 VAR
     result: STRING;
 BEGIN
@@ -100,7 +100,7 @@ BEGIN
         ELSE
             result := leftLval + " = " + cx.rtl.clone(right.code(), 
                                                       generateTypeInfo(left.type()), 
-                                                      Types.recordConstructor(cx^, left.type()(Types.PRecord)^));
+                                                      Record.constructor(cx^, left.type()(Record.PType)^));
         END;
     ELSE
         result := SUPER(cx, left, right);

+ 14 - 14
src/eberon/EberonRecord.ob

@@ -1,6 +1,6 @@
 MODULE EberonRecord;
 IMPORT 
-    Cast, Context, EberonContext, EberonTypes, Errors, JS, Object, Scope, ScopeBase, Stream, String, Types;
+    Cast, Chars, Context, EberonContext, EberonTypes, Errors, JS, Object, Base := Record, Scope, ScopeBase, String, Types;
 CONST
     instantiateForVar* = 0;    
     instantiateForNew* = 1;    
@@ -13,7 +13,7 @@ TYPE
     MapOfMethodIds = MAP OF PMethodIds;
     MapOfFields = MAP OF Types.PField;
 
-    Record* = RECORD(Types.Record)
+    Record* = RECORD(Base.Type)
         PROCEDURE Record(name: STRING; cons: STRING; scope: ScopeBase.PType);
 
         PROCEDURE declareConstructor(type: Types.PDefinedProcedure; exported: BOOLEAN);
@@ -45,15 +45,15 @@ TYPE
     END;
     PRecord* = POINTER TO Record;
 
-    RecordField* = RECORD(Types.RecordField)
-        PROCEDURE RecordField*(identdef: Context.PIdentdefInfo; type: Types.PStorageType; record: PRecord);
+    Field* = RECORD(Base.Field)
+        PROCEDURE Field*(identdef: Context.PIdentdefInfo; type: Types.PStorageType; record: PRecord);
 
         record: PRecord;
     END;
 
-    RecordFieldAsMethod = RECORD(Types.RecordField)
+    FieldAsMethod = RECORD(Base.Field)
     END;
-    PRecordFieldAsMethod = POINTER TO RecordFieldAsMethod;
+    PFieldAsMethod = POINTER TO FieldAsMethod;
 
 PROCEDURE assertNotReadOnly*(isReadObly: BOOLEAN; method: STRING; class: STRING);
 BEGIN
@@ -202,7 +202,7 @@ BEGIN
     END;
 END;
 
-PROCEDURE RecordFieldAsMethod.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
+PROCEDURE FieldAsMethod.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
     RETURN NEW EberonTypes.MethodVariable(SELF.type()); 
 END;
 
@@ -230,7 +230,7 @@ PROCEDURE canBeCreatedInContext(cx: Context.Type; r: Record): BOOLEAN;
         OR canBeCreatedInAnotherModule(r);
 END;
 
-PROCEDURE Record.setBase(type: Types.PRecord);
+PROCEDURE Record.setBase(type: Base.PType);
 BEGIN
     IF (type.scope # SELF.scope) & (SELF.scope^ IS Scope.Module) 
         & ~canBeCreatedInAnotherModule(type(PRecord)^) THEN
@@ -323,7 +323,7 @@ BEGIN
                    + "method already was declared in the base record (but was not exported)");
     END;
 
-    SELF.declaredMethods[id] := NEW RecordFieldAsMethod(methodId, type);
+    SELF.declaredMethods[id] := NEW FieldAsMethod(methodId, type);
     IF ~methodId.exported() THEN
         SELF.nonExportedMethods.add(id);
     END;
@@ -492,10 +492,10 @@ BEGIN
     SUPER();
 END;
 
-PROCEDURE RecordField.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
+PROCEDURE Field.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
 BEGIN
     actualReadOnly <- isReadOnly;
-    IF ~actualReadOnly & (LEN(cx.qualifyScope(Types.recordScope(SELF.record^))) # 0) THEN
+    IF ~actualReadOnly & (LEN(cx.qualifyScope(SELF.record.scope)) # 0) THEN
         actualReadOnly := SELF.identdef()(EberonContext.PIdentdefInfo).isReadOnly();
     END;
     RETURN SUPER(leadCode, actualReadOnly, cx); 
@@ -516,15 +516,15 @@ BEGIN
         IF key IN r.fieldsInit THEN
             code := r.fieldsInit[key];
         ELSE
-            code := "this." + Types.mangleField(key) 
+            code := "this." + Base.mangleField(key) 
                     + " = " + type.initializer(cx^);
         END;
-        result := result + code + ";" + Stream.kCR;
+        result := result + code + ";" + Chars.ln;
     END;
     RETURN result;
 END;
 
-PROCEDURE RecordField.RecordField(identdef: Context.PIdentdefInfo; type: Types.PStorageType; record: PRecord)
+PROCEDURE Field.Field(identdef: Context.PIdentdefInfo; type: Types.PStorageType; record: PRecord)
     | SUPER(identdef, type),
       record(record);
 END;

+ 2 - 2
src/eberon/EberonTypes.ob

@@ -1,5 +1,5 @@
 MODULE EberonTypes;
-IMPORT Context, LanguageContext, Procedure, Types;
+IMPORT Context, LanguageContext, Procedure, Record, Types;
 
 TYPE
     CallGenerator = PROCEDURE(cx: LanguageContext.PType; type: Types.DefinedProcedure): Procedure.PCallGenerator;
@@ -73,7 +73,7 @@ PROCEDURE MethodField.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.T
 END;
 
 PROCEDURE MethodField.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
-    RETURN NEW Types.FieldCode(leadCode + "." + Types.mangleField(SELF.method.name), "", "");
+    RETURN NEW Types.FieldCode(leadCode + "." + Record.mangleField(SELF.method.name), "", "");
 END;
 
 END EberonTypes.

+ 33 - 29
src/eberon/eberon_context.js

@@ -16,12 +16,16 @@ var EberonScope = require("js/EberonScope.js");
 var EberonString = require("js/EberonString.js");
 var EberonTypes = require("js/EberonTypes.js");
 var Errors = require("js/Errors.js");
+var Expression = require("js/Expression.js");
 var op = require("js/Operator.js");
 var eOp = require("js/EberonOperator.js");
 var Symbol = require("js/Symbols.js");
 var Procedure = require("js/Procedure.js");
+var Record = require("js/Record.js");
 var Type = require("js/Types.js");
+var TypeId = require("js/TypeId.js");
 var TypePromotion = require("eberon/eberon_type_promotion.js");
+var Variable = require("js/Variable.js");
 
 /*
 function log(s){
@@ -31,7 +35,7 @@ function log(s){
 
 function superMethodCallGenerator(context, type){
     var args = Procedure.makeArgumentsCode(context);
-    args.write(Code.makeExpression("this"));
+    args.write(Expression.make("this"));
     return Procedure.makeProcCallGeneratorWithCustomArgs(context, type, args);
 }
 
@@ -49,7 +53,7 @@ var ProcOrMethodId = Context.Chained.extend({
     handleIdent: function(id){this.__maybeTypeId = id;},
     handleLiteral: function(s){
         var ss = ContextHierarchy.getSymbolAndScope(this.root(), this.__maybeTypeId);
-        var type = ContextHierarchy.unwrapType(ss.symbol().info());
+        var type = ContextExpression.unwrapType(ss.symbol().info());
         if (!(type instanceof Type.Record))
             throw new Errors.Error(
                   "RECORD type expected in method declaration, got '"
@@ -292,12 +296,12 @@ var Designator = Context.Designator.extend({
     handleLiteral: function(s){
         if (s == "SELF"){
             var type = this.handleMessage(getMethodSelf);
-            var info = new Type.DeclaredVariable("this", type);
+            var info = new Variable.DeclaredVariable("this", type);
             this._advance(type, info, "this");
         } 
         else if (s == "POINTER"){
-            var typeId = new Type.TypeId(this.handleMessage(getSelfAsPointerMsg));
-            var pointerType = new Type.Pointer("", typeId);
+            var typeId = new TypeId.Type(this.handleMessage(getSelfAsPointerMsg));
+            var pointerType = new Record.Pointer("", typeId);
             this._advance(pointerType, new SelfAsPointer(), "");
         }
         else if (s == "SUPER"){
@@ -309,7 +313,7 @@ var Designator = Context.Designator.extend({
     },
     __beginCall: function(){
         var type = this._currentType();
-        if (type instanceof Type.TypeId && type.type() instanceof Type.Record){
+        if (type instanceof TypeId.Type && type.type() instanceof Type.Record){
             this.__procCall = makeContextCall(
                 this, 
                 function(cx){ return EberonConstructor.makeConstructorCall(type, cx, false); }
@@ -337,7 +341,7 @@ var OperatorNew = Context.Chained.extend({
         var s = found.symbol();
         var info = s.info();
 
-        if (!(info instanceof Type.TypeId))
+        if (!(info instanceof TypeId.Type))
             throw new Errors.Error("record type is expected in operator NEW, got '" + info.idType() + "'");
 
         var type = info.type();
@@ -441,7 +445,7 @@ var ExpressionProcedureCall = Context.Chained.extend({
         var e;
         if (info instanceof ResultVariable){
             e = info.expression();
-            e = new Code.Expression(d.code(), d.type(), undefined, e.constValue(), e.maxPrecedence());
+            e = new Expression.Type(d.code(), d.type(), undefined, e.constValue(), e.maxPrecedence());
         }
         else
             e = Context.designatorAsExpression(d);
@@ -464,7 +468,7 @@ var AssignmentOrProcedureCall = Context.Chained.extend({
         var type = d.type();
         var code;
         if (this.__right){
-            var left = Code.makeExpression(d.code(), type, d);
+            var left = Expression.make(d.code(), type, d);
             code = op.assign(left, this.__right, Context.makeContext(this));
         }
         else if (!(d.info() instanceof ResultVariable)){
@@ -553,10 +557,10 @@ var RecordDecl = Context.RecordDecl.extend({
         return Context.RecordDecl.prototype.handleMessage.call(this, msg);
     },
     _makeField: function(field, type){
-        return new EberonRecord.RecordField(field, type, this.__type);
+        return new EberonRecord.Field(field, type, this.__type);
     },
     _generateBaseConstructorCallCode: function(){
-        var base = Type.recordBase(this.type());
+        var base = this.type().base;
         if (!base)
             return "";
         var baseConstructor = EberonRecord.constructor$(base);
@@ -642,7 +646,7 @@ var BaseInit = Context.Chained.extend({
                 this,
                 function(cx){ 
                     return EberonConstructor.makeBaseConstructorCall(
-                        Type.recordBase(this.type()), 
+                        this.type().base, 
                         cx);
                     }.bind(this)
                 );
@@ -768,7 +772,7 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
             if (this.__isConstructor){
                 this.__boundType.defineConstructor(this.__methodType.procType());
 
-                var base = Type.recordBase(this.__boundType);
+                var base = this.__boundType.base;
                 var baseConstructor = base && EberonRecord.constructor$(base);
                 if (!this.__baseConstructorWasCalled && baseConstructor && baseConstructor.args().length)
                     throw new Errors.Error("base record constructor has parameters but was not called (use '| SUPER' to pass parameters to base constructor)");
@@ -783,7 +787,7 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
         if (!this.__methodId)
             throw new Errors.Error("SUPER can be used only in methods");
 
-        var baseType = Type.recordBase(this.__boundType);
+        var baseType = this.__boundType.base;
         if (!baseType)
             throw new Errors.Error(
                   "'" + Type.typeName(this.__boundType)
@@ -796,12 +800,12 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
         return {
             info: this.__isConstructor ? undefined
                                        : new Type.ProcedureId(new EberonTypes.MethodType(id, this.__methodType.procType(), superMethodCallGenerator)),
-            code: this.qualifyScope(Type.recordScope(baseType))
+            code: this.qualifyScope(baseType.scope)
                 + Type.typeName(baseType) + ".prototype." + id + ".call"
         };
     },
     __handleFieldInit: function(id){
-        var fields = Type.recordOwnFields(this.__boundType);
+        var fields = this.__boundType.fields;
         if (!fields.hasOwnProperty(id))
             throw new Errors.Error("'" + id + "' is not record '" + Type.typeName(this.__boundType) + "' own field");
         
@@ -864,42 +868,42 @@ function TransferPromotedTypesMsg(promotion){
     this.promotion = promotion;
 }
 
-var RelationOps = Context.RelationOps.extend({
+var RelationOps = Class.extend.call(ContextExpression.RelationOps, {
     init: function EberonContext$RelationOps(){
-        Context.RelationOps.prototype.init.call(this);
+        ContextExpression.RelationOps.call(this);
     },
     eq: function(type){
         return type == EberonString.string() 
             ? eOp.equalStr
-            : Context.RelationOps.prototype.eq.call(this, type);
+            : ContextExpression.RelationOps.prototype.eq.call(this, type);
     },
     notEq: function(type){
         return type == EberonString.string() 
             ? eOp.notEqualStr
-            : Context.RelationOps.prototype.notEq.call(this, type);
+            : ContextExpression.RelationOps.prototype.notEq.call(this, type);
     },
     less: function(type){
         return type == EberonString.string() 
             ? eOp.lessStr
-            : Context.RelationOps.prototype.less.call(this, type);
+            : ContextExpression.RelationOps.prototype.less.call(this, type);
     },
     greater: function(type){
         return type == EberonString.string() 
             ? eOp.greaterStr
-            : Context.RelationOps.prototype.greater.call(this, type);
+            : ContextExpression.RelationOps.prototype.greater.call(this, type);
     },
     lessEq: function(type){
         return type == EberonString.string() 
             ? eOp.lessEqualStr
-            : Context.RelationOps.prototype.lessEq.call(this, type);
+            : ContextExpression.RelationOps.prototype.lessEq.call(this, type);
     },
     greaterEq: function(type){
         return type == EberonString.string() 
             ? eOp.greaterEqualStr
-            : Context.RelationOps.prototype.greaterEq.call(this, type);
+            : ContextExpression.RelationOps.prototype.greaterEq.call(this, type);
     },
     is: function(type, context){
-        var impl = Context.RelationOps.prototype.is.call(this, type, context);
+        var impl = ContextExpression.RelationOps.prototype.is.call(this, type, context);
         return function(left, right){
             var d = left.designator();
             if (d){
@@ -914,7 +918,7 @@ var RelationOps = Context.RelationOps.extend({
         if ((leftType == EberonString.string() && rightType instanceof Type.String)
             || (rightType == EberonString.string() && leftType instanceof Type.String))
             return EberonString.string();
-        return Context.RelationOps.prototype.coalesceType.call(this, leftType, rightType);
+        return ContextExpression.RelationOps.prototype.coalesceType.call(this, leftType, rightType);
     }
 });
 
@@ -1014,7 +1018,7 @@ var SimpleExpression = Class.extend.call(ContextExpression.SimpleExpression, {
 
 var relationOps = new RelationOps();
 
-var Expression = Context.Expression.extend({
+var ExpressionContext = Context.Expression.extend({
     init: function EberonContext$Expression(context){
         Context.Expression.prototype.init.call(this, context, relationOps);
         this.__typePromotion = undefined;
@@ -1229,7 +1233,7 @@ var MapDecl = Context.Chained.extend({
     },
     handleQIdent: function(q){
         var s = ContextHierarchy.getQIdSymbolAndScope(this.root(), q);
-        var type = ContextHierarchy.unwrapType(s.symbol().info());
+        var type = ContextExpression.unwrapType(s.symbol().info());
         this.setType(type);
     },
     // anonymous types can be used in map declaration
@@ -1402,7 +1406,7 @@ exports.BaseInit = BaseInit;
 exports.CaseLabel = CaseLabel;
 exports.ConstDecl = ConstDecl;
 exports.Designator = Designator;
-exports.Expression = Expression;
+exports.Expression = ExpressionContext;
 exports.ExpressionProcedureCall = ExpressionProcedureCall;
 exports.For = For;
 exports.ForEach = ForEach;

+ 2 - 2
src/nodejs.js

@@ -5,7 +5,7 @@ var Code = require("js/Code.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
 var oc = require("oc.js");
 var makeRTL = require("rtl_code.js").makeRTL;
-var Type = require("js/Types.js");
+var Record = require("js/Record.js");
 
 var fs = require("fs");
 var path = require("path");
@@ -35,7 +35,7 @@ var ModuleGenerator = Class.extend({
             var e = exports[access];
             var code = Code.genExport(e);
             if (code){
-                var id = Type.mangleJSProperty(e.id());
+                var id = Record.mangleJSProperty(e.id());
                 result += "exports." + id + " = " + code + ";\n";
             }
         }

+ 31 - 30
src/ob/Cast.ob

@@ -1,5 +1,6 @@
 MODULE Cast;
-IMPORT Code, LanguageContext, OberonRtl, String, Types;
+IMPORT 
+    Expression, LanguageContext, OberonRtl, Record, String, TypeId, Types;
 CONST
     errNo* = 0;
     err* = 1;
@@ -30,28 +31,28 @@ VAR
     castOpStrToChar: POINTER TO CastOpStrToChar;
     castOpArray: POINTER TO CastOpArray;
 
-PROCEDURE findBaseType(base: Types.PRecord; type: Types.PRecord): Types.PRecord;
+PROCEDURE findBaseType(base: Record.PType; type: Record.PType): Record.PType;
 BEGIN
     result <- type;
     WHILE (result # NIL) & (result # base) DO
-        result := Types.recordBase(result^);
+        result := result.base;
     END;
     RETURN result
 END findBaseType;
 
-PROCEDURE findPointerBaseType*(base: Types.PPointer; type: Types.Pointer): Types.PPointer;
+PROCEDURE findPointerBaseType*(base: Record.PPointer; type: Record.Pointer): Record.PPointer;
 VAR
-    result: Types.PPointer;
+    result: Record.PPointer;
 BEGIN
-    IF findBaseType(Types.pointerBase(base^), Types.pointerBase(type)) # NIL THEN
+    IF findBaseType(Record.pointerBase(base^), Record.pointerBase(type)) # NIL THEN
         result := base;
     END;
     RETURN result
-END findPointerBaseType;
+END;
 
 PROCEDURE matchesToNIL(VAR t: Types.Type): BOOLEAN;
-    RETURN (t IS Types.Pointer) OR (t IS Types.Procedure)
-END matchesToNIL;
+    RETURN (t IS Record.Pointer) OR (t IS Types.Procedure)
+END;
 
 PROCEDURE areTypesMatch*(t1: Types.PType; t2: Types.PType): BOOLEAN;
     RETURN areTypesExactlyMatch(t1, t2)
@@ -101,30 +102,30 @@ BEGIN
         result := (t1.length() = t2.length()) 
                 & (areTypesMatch(Types.arrayElementsType(t1^), 
                                  Types.arrayElementsType(t2^)));
-    ELSIF (t1 IS Types.PPointer) & (t2 IS Types.PPointer) THEN
-        result := areTypesMatch(Types.pointerBase(t1^), 
-                                Types.pointerBase(t2^));
+    ELSIF (t1 IS Record.PPointer) & (t2 IS Record.PPointer) THEN
+        result := areTypesMatch(Record.pointerBase(t1^), 
+                                Record.pointerBase(t2^));
     ELSIF (t1 IS Types.PDefinedProcedure) & (t2 IS Types.PDefinedProcedure) THEN
         result := areProceduresMatch(t1, t2);
     END;
     RETURN result
 END areTypesExactlyMatchImpl;
 
-PROCEDURE CastOpDoNothing.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastOpDoNothing.make(cx: LanguageContext.PType; e: Expression.PType): Expression.PType;
     RETURN e
 END;
 
-PROCEDURE passedByReference*(e: Code.PExpression): BOOLEAN;
+PROCEDURE passedByReference*(e: Expression.PType): BOOLEAN;
 BEGIN
     info <- e.designator().info();
     RETURN (info IS Types.PVariable) & info.isReference();
 END;
 
-PROCEDURE assignByReference*(left, right: Code.PExpression): STRING;
-    RETURN left.code() + ".set(" + Code.derefExpression(right).code() + ")";
+PROCEDURE assignByReference*(left, right: Expression.PType): STRING;
+    RETURN left.code() + ".set(" + Expression.deref(right).code() + ")";
 END;
 
-PROCEDURE CastOpDoNothing.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpDoNothing.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
 VAR
     result: STRING;
 BEGIN
@@ -132,13 +133,13 @@ BEGIN
     IF passedByReference(left) THEN
         result := assignByReference(left, rightConverted);
     ELSE
-        result := left.lval() + " = " + Code.derefExpression(rightConverted).code();
+        result := left.lval() + " = " + Expression.deref(rightConverted).code();
     END;
     RETURN result;
 END;
 
-PROCEDURE CastOpDoNothing.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
-    RETURN Code.derefExpression(e).code();
+PROCEDURE CastOpDoNothing.clone(cx: LanguageContext.PType; e: Expression.PType): STRING;
+    RETURN Expression.deref(e).code();
 END;
 
 PROCEDURE cloneArray*(t: Types.PArray; code: STRING; cx: LanguageContext.PType): STRING;
@@ -153,26 +154,26 @@ BEGIN
     RETURN result
 END;
 
-PROCEDURE CastOpArray.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpArray.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
     RETURN left.code() + " = " + cloneArray(right.type()(Types.PArray), right.code(), cx)
 END;
 
-PROCEDURE CastOpArray.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
+PROCEDURE CastOpArray.clone(cx: LanguageContext.PType; e: Expression.PType): STRING;
     RETURN cloneArray(e.type()(Types.PArray), e.code(), cx);
 END;
 
-PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
-    RETURN cx.rtl.copy(right.code(), left.lval(), Types.generateTypeInfo(left.type()));
+PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Expression.PType): STRING;
+    RETURN cx.rtl.copy(right.code(), left.lval(), Record.generateTypeInfo(left.type()));
 END;
 
-PROCEDURE CastOpStrToChar.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastOpStrToChar.make(cx: LanguageContext.PType; e: Expression.PType): Expression.PType;
 BEGIN
     s <- e.type()(Types.PString);
     ASSERT(LEN(s.s) = 1);
     c <- s.s[0];
     code <- String.fromInt(ORD(c))
-    RETURN Code.makeSimpleExpression(code, Types.basic.ch)
-END CastOpStrToChar.make;
+    RETURN Expression.makeSimple(code, Types.basic.ch)
+END;
 
 PROCEDURE implicit*(from, to: Types.PType; toVar: BOOLEAN; ops: Operations; VAR op: LanguageContext.PCastOp): INTEGER;
 VAR
@@ -181,7 +182,7 @@ BEGIN
     result <- err;
     op := NIL;
     IF from = to THEN
-        IF from IS Types.PRecord THEN
+        IF from IS Record.PType THEN
             op := ops.castToRecord;
         ELSIF from IS Types.PArray THEN
             op := castOpArray;
@@ -219,7 +220,7 @@ BEGIN
                                Types.arrayElementsType(to^)) THEN
             op := castOpArray;
             result := errNo;
-    ELSIF (from IS Types.PPointer) & (to IS Types.PPointer) THEN
+    ELSIF (from IS Record.PPointer) & (to IS Record.PPointer) THEN
         IF ~toVar THEN
             IF findPointerBaseType(to, from^) # NIL THEN
                 result := errNo;
@@ -229,7 +230,7 @@ BEGIN
         ELSE
             result := errVarParameter;
         END;
-    ELSIF (from IS Types.PRecord) & (to IS Types.PRecord) THEN
+    ELSIF (from IS Record.PType) & (to IS Record.PType) THEN
         IF findBaseType(to, from) # NIL THEN
             op := ops.castToRecord;
             result := errNo;

+ 18 - 167
src/ob/Code.ob

@@ -2,59 +2,20 @@ MODULE Code;
 IMPORT 
     CodeGenerator,
     ConstValue,
+    Designator,
     Errors,
+    Expression,
     Object, 
     Stream, 
     ScopeBase, 
     Symbols, 
     Precedence := CodePrecedence, 
-    String, 
+    Record,
+    String,
+    TypeId, 
     Types;
 
 TYPE
-    Designator* = RECORD
-        PROCEDURE Designator*(code: STRING; lval: STRING; type: Types.PType; info: Types.PId; scope: ScopeBase.PType);
-
-        PROCEDURE code*(): STRING;
-        PROCEDURE lval(): STRING;
-        PROCEDURE type*(): Types.PType;
-        PROCEDURE info*(): Types.PId;
-        PROCEDURE scope(): ScopeBase.PType;
-
-        mCode: STRING;
-        mLval: STRING;
-        mType: Types.PType;
-        mInfo: Types.PId;
-        mScope: ScopeBase.PType
-    END;
-
-    PDesignator* = POINTER TO Designator;
-
-    Expression* = RECORD(Object.Type)
-        PROCEDURE Expression*(
-            code: STRING; 
-            type: Types.PType; 
-            designator: PDesignator; 
-            constValue: ConstValue.PType; 
-            maxPrecedence: INTEGER);
-
-        PROCEDURE code*(): STRING;
-        PROCEDURE lval*(): STRING;
-        PROCEDURE type*(): Types.PType;
-        PROCEDURE designator*(): PDesignator;
-        PROCEDURE constValue*(): ConstValue.PType;
-        PROCEDURE maxPrecedence*(): INTEGER;
-        PROCEDURE isTerm*(): BOOLEAN;
-
-        mCode: STRING;
-        mType: Types.PType;
-        mDesignator: PDesignator;
-        mConstValue: ConstValue.PType;
-        mMaxPrecedence: INTEGER
-    END;
-
-    PExpression* = POINTER TO Expression;
-
     StringsMap = MAP OF STRING;
 
     ModuleGenerator* = RECORD
@@ -69,150 +30,40 @@ TYPE
 
     PModuleGenerator* = POINTER TO ModuleGenerator;
 
-PROCEDURE Expression.code(): STRING;
-    RETURN SELF.mCode
-END Expression.code;
-
-PROCEDURE Expression.lval(): STRING;
-VAR
-    result: STRING;
-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(): PDesignator;
-    RETURN SELF.mDesignator
-END Expression.designator;
-
-PROCEDURE Expression.constValue(): ConstValue.PType;
-    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 = Precedence.none)
-END Expression.isTerm;
-
-PROCEDURE Expression.Expression(
-    code: STRING; 
-    type: Types.PType; 
-    designator: PDesignator; 
-    constValue: ConstValue.PType; 
-    maxPrecedence: INTEGER)
-  | mCode(code),
-    mType(type),
-    mDesignator(designator),
-    mConstValue(constValue),
-    mMaxPrecedence(maxPrecedence);
-END;
-
-PROCEDURE makeExpression*(
-    code: STRING; 
-    type: Types.PType; 
-    designator: PDesignator; 
-    constValue: ConstValue.PType)
-    : PExpression;
-    RETURN NEW Expression(code, type, designator, constValue, Precedence.none)
-END makeExpression;
-
-PROCEDURE makeSimpleExpression*(
-    code: STRING; 
-    type: Types.PType)
-    : PExpression;
-    RETURN makeExpression(code, type, NIL, NIL)
-END makeSimpleExpression;
-
-PROCEDURE Designator.code(): STRING;
-    RETURN SELF.mCode
-END Designator.code;
-
-PROCEDURE Designator.lval(): STRING;
-    RETURN SELF.mLval
-END Designator.lval;
-
-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(): ScopeBase.PType;
-    RETURN SELF.mScope
-END Designator.scope;
-
-PROCEDURE Designator.Designator(code: STRING; lval: STRING; type: Types.PType; info: Types.PId; scope: ScopeBase.PType)
-  | mCode(code),
-    mLval(lval),
-    mType(type),
-    mInfo(info),
-    mScope(scope);
-END;
-
-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.PVariable) 
-                & e.mDesignator.mInfo(Types.PVariable).isReference()) THEN
-        result := e;
-    ELSE
-        result := makeSimpleExpression(e.mCode + ".get()", e.mType);
-    END;
-    RETURN result
-END derefExpression;
-
-PROCEDURE adjustPrecedence*(e: PExpression; precedence: INTEGER): STRING;
+PROCEDURE adjustPrecedence*(e: Expression.PType; precedence: INTEGER): STRING;
 VAR
     result: STRING;
 BEGIN
-    result := e.mCode;
-    IF (precedence # Precedence.none) & (e.mMaxPrecedence > precedence) THEN
+    result := e.code();
+    IF (precedence # Precedence.none) & (e.maxPrecedence() > precedence) THEN
         result := "(" + result + ")";
     END;
     RETURN result
 END adjustPrecedence;
 
-PROCEDURE isPointerShouldBeExported(type: Types.Pointer): STRING;
+PROCEDURE isPointerShouldBeExported(type: Record.Pointer): STRING;
 VAR
-    r: Types.PRecord;
     result: STRING;
 BEGIN
-    r := Types.pointerBase(type);
+    r <- Record.pointerBase(type);
     IF LEN(Types.typeName(r^)) = 0 THEN
         result := r.cons;
     END;
     RETURN result
-END isPointerShouldBeExported;
+END;
 
-PROCEDURE typeShouldBeExported(typeId: Types.PId; defaultId: STRING): STRING;
+PROCEDURE typeShouldBeExported(typeId: TypeId.PType; defaultId: STRING): STRING;
 VAR
     result: STRING;
-    type: Types.PType;
 BEGIN
-    type := typeId(Types.PTypeId).type();
-    IF type IS Types.PRecord THEN
+    type <- typeId.type();
+    IF type IS Record.PType THEN
         result := defaultId;
-    ELSIF type IS Types.PPointer THEN
-        result := isPointerShouldBeExported(type^(Types.Pointer));
+    ELSIF type IS Record.PPointer THEN
+        result := isPointerShouldBeExported(type^);
     END;
     RETURN result
-END typeShouldBeExported;
+END;
 
 PROCEDURE genExport*(s: Symbols.Symbol): STRING;
 VAR
@@ -223,7 +74,7 @@ BEGIN
     ELSIF ~s.isType() THEN
         result := s.id();
     ELSE
-        result := typeShouldBeExported(s.info(), s.id())
+        result := typeShouldBeExported(s.info()(TypeId.PType), s.id())
     END;
     RETURN result
 END;

+ 2 - 4
src/ob/Context.ob

@@ -1,10 +1,8 @@
 MODULE Context;
-IMPORT OberonRtl, Object, ScopeBase;
+IMPORT OberonRtl, ScopeBase;
 TYPE
     Type* = RECORD
-        handleLiteral*: PROCEDURE(s: STRING);
-        handleIdent*:   PROCEDURE(s: STRING);
-        qualifyScope*:  PROCEDURE(scope: ScopeBase.PType): STRING;
+        PROCEDURE qualifyScope*(scope: ScopeBase.PType): STRING;
         
         rtl*: OberonRtl.PType;
     END;

+ 331 - 21
src/ob/ContextExpression.ob

@@ -1,33 +1,50 @@
 MODULE ContextExpression;
 IMPORT 
-    Chars, Code, ConstValue, ContextHierarchy, Errors, Operator, String, Types;
+    Cast, Chars, ConstValue, Context, ContextHierarchy, Errors, Expression, JS, LanguageContext, Operator, Record, String, TypeId, Types;
 TYPE
     ExpressionHandler = RECORD(ContextHierarchy.Node)
-        PROCEDURE handleExpression(e: Code.PExpression);
+        PROCEDURE handleExpression(e: Expression.PType);
 
-        expression: Code.PExpression;
+        expression: Expression.PType;
     END;
 
-    BinaryOperator = PROCEDURE(l, r: Code.PExpression): Code.PExpression;
+    BinaryOperator = PROCEDURE(l, r: Expression.PType): Expression.PType;
+    BinaryOperatorCx = PROCEDURE(l, r: Expression.PType; cx: LanguageContext.PType): Expression.PType;
 
-    Expression = RECORD(ContextHierarchy.Node)
-        PROCEDURE handleSimpleExpression(e: Code.PExpression);
+    RelationOps* = RECORD
+        PROCEDURE eq(type: Types.PType): BinaryOperatorCx;
+        PROCEDURE notEq(type: Types.PType): BinaryOperatorCx;
+        PROCEDURE less(type: Types.PType): BinaryOperatorCx;
+        PROCEDURE greater(type: Types.PType): BinaryOperatorCx;
+        PROCEDURE lessEq(type: Types.PType): BinaryOperatorCx;
+        PROCEDURE greaterEq(type: Types.PType): BinaryOperatorCx;
+        PROCEDURE is(type: Types.PType; cx: Context.Type): BinaryOperatorCx;
+
+        PROCEDURE eqExpect(): STRING;
+        PROCEDURE strongRelExpect(): STRING;
+        PROCEDURE relExpect(): STRING;
+
+        PROCEDURE coalesceType(leftType, rightType: Types.PType): Types.PType;
+    END;
+
+    ExpressionNode = RECORD(ContextHierarchy.Node)
+        PROCEDURE handleSimpleExpression(e: Expression.PType);
     END;
-    PExpression = POINTER TO Expression;
+    PExpressionNode = POINTER TO ExpressionNode;
 
     SimpleExpression* = RECORD(ContextHierarchy.Node)
-        PROCEDURE SimpleExpression(parent: PExpression);
+        PROCEDURE SimpleExpression(parent: PExpressionNode);
 
-        PROCEDURE handleTerm(e: Code.PExpression);
+        PROCEDURE handleTerm(e: Expression.PType);
         PROCEDURE type(): Types.PType;
         PROCEDURE setType(type: Types.PType);
         PROCEDURE handleOperator(op: BinaryOperator);
 
-        parentExpression: PExpression;  
+        parentExpression: PExpressionNode;  
         mType: Types.PType;
         unaryOperator: STRING;
         binaryOperator: BinaryOperator;
-        expression: Code.PExpression;
+        expression: Expression.PType;
     END;
     PSimpleExpression = POINTER TO SimpleExpression;
 
@@ -143,14 +160,307 @@ BEGIN
     RETURN op;
 END;
 
-PROCEDURE SimpleExpression.SimpleExpression(parent: PExpression)
+PROCEDURE useIntOrderOp(t: Types.PType): BOOLEAN;
+    RETURN Types.isInt(t) OR (t = Types.basic.ch);
+END;
+
+PROCEDURE useIntEqOp(t: Types.PType): BOOLEAN;
+    RETURN Types.isInt(t)
+        OR (t = Types.basic.bool)
+        OR (t = Types.basic.ch)
+        OR (t IS Record.PPointer)
+        OR (t IS Types.PProcedure)
+        OR (t = Types.nil);
+END;
+
+PROCEDURE unwrapTypeId*(id: Types.PId): TypeId.PType;
+VAR
+    result: TypeId.PType;
+BEGIN
+    IF ~(id IS TypeId.PType) THEN
+        Errors.raise("type name expected");
+    ELSE
+        result := id;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE unwrapType*(id: Types.PId): Types.PType;
+    RETURN unwrapTypeId(id).type();
+END;
+
+PROCEDURE throwTypeMismatch(from, to: Types.PType);
+VAR
+    fromDescription: STRING;
+BEGIN
+    IF from # NIL THEN
+        fromDescription := "'" + from.description() + "'";
+    ELSE
+        fromDescription := "no type (proper procedure call)";
+    END;
+    Errors.raise("type mismatch: expected '" + to.description() 
+               + "', got " + fromDescription);
+END;
+
+PROCEDURE checkTypeMatch(from, to: Types.PType);
+BEGIN
+    IF ~Cast.areTypesMatch(from, to) THEN
+        throwTypeMismatch(from, to);
+    END;
+END;
+
+PROCEDURE checkImplicitCast*(cx: ContextHierarchy.Root; from, to: Types.PType);
+VAR
+    op: LanguageContext.PCastOp;
+BEGIN
+    IF cx.language().types.implicitCast(from, to, FALSE, op) # Cast.errNo THEN
+        throwTypeMismatch(from, to);
+    END;
+END;
+
+PROCEDURE promoteExpressionType(cx: ContextHierarchy.Root; left, right: Expression.PType);
+BEGIN
+    IF left # NIL THEN
+        rightType <- right.type();
+        leftType <- left.type();
+        IF (leftType # NIL) & (rightType # NIL) THEN
+            checkImplicitCast(cx, rightType, leftType);
+        END;
+    END;
+END;
+
+PROCEDURE promoteTypeInExpression*(e: Expression.PType; type: Types.PType): Expression.PType;
+VAR
+    v: CHAR;
+    result: Expression.PType;
+BEGIN
+    fromType <- e.type();
+    IF (type = Types.basic.ch) & (fromType IS Types.PString) & Types.stringAsChar(fromType^, v) THEN
+        result := Expression.makeSimple(String.fromInt(ORD(v)), type);
+    ELSE
+        result := e;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE checkTypeCast*(fromInfo: Types.PVariable; fromType, toType: Types.PType; msg: STRING);
+VAR
+    PROCEDURE checkCommonBase(from, to: Record.PType; prefix: STRING);
+    BEGIN
+        t <- to.base;
+        WHILE (t # NIL) & (t # from) DO
+            t := t.base;
+        END;
+        IF t = NIL THEN
+            Errors.raise(prefix + ": '" + to.description()
+                       + "' is not an extension of '" + from.description() + "'");
+        END;
+    END;
+
+BEGIN
+    prefix <- "invalid " + msg;
+
+    pointerExpected <- fromType IS Record.PPointer;
+    IF ~pointerExpected & ~(fromType IS Record.PType) THEN
+        Errors.raise(
+            prefix + ": POINTER to type or RECORD expected, got '"
+            + fromType.description() + "'");
+    END;
+
+    IF ~pointerExpected THEN
+        IF ~fromInfo.isReference() THEN
+            Errors.raise(
+                prefix + ": a value variable cannot be used");
+        ELSIF ~(toType IS Record.PType) THEN
+            Errors.raise(
+                prefix + ": RECORD type expected as an argument of RECORD " + msg + ", got '"
+              + toType.description() + "'");
+        END;
+    ELSIF ~(toType IS Record.PPointer) THEN
+        Errors.raise(
+            prefix + ": POINTER type expected as an argument of POINTER " + msg + ", got '"
+          + toType.description() + "'");
+    END;
+
+    IF pointerExpected THEN
+        checkCommonBase(Record.pointerBase(fromType(Record.PPointer)^), 
+                        Record.pointerBase(toType(Record.PPointer)^), 
+                        prefix);
+    ELSE
+        checkCommonBase(fromType(Record.PType), 
+                        toType(Record.PType), 
+                        prefix);
+    END;
+END checkTypeCast;
+
+PROCEDURE RelationOps.eq(type: Types.PType): BinaryOperatorCx;
+VAR
+    result: BinaryOperatorCx;
+BEGIN
+    IF useIntEqOp(type) THEN
+        result := Operator.equalInt;
+    ELSIF Types.isString(type) THEN
+        result := Operator.equalStr;
+    ELSIF type = Types.basic.real THEN
+        result := Operator.equalReal;
+    ELSIF type = Types.basic.set THEN
+        result := Operator.equalSet;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE RelationOps.notEq(type: Types.PType): BinaryOperatorCx;
+VAR
+    result: BinaryOperatorCx;
+BEGIN
+    IF useIntEqOp(type) THEN
+        result := Operator.notEqualInt;
+    ELSIF Types.isString(type) THEN
+        result := Operator.notEqualStr;
+    ELSIF type = Types.basic.real THEN
+        result := Operator.notEqualReal;
+    ELSIF type = Types.basic.set THEN
+        result := Operator.notEqualSet;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE RelationOps.less(type: Types.PType): BinaryOperatorCx;
+VAR
+    result: BinaryOperatorCx;
+BEGIN
+    IF useIntOrderOp(type) THEN
+        result := Operator.lessInt;
+    ELSIF Types.isString(type) THEN
+        result := Operator.lessStr;
+    ELSIF type = Types.basic.real THEN
+        result := Operator.lessReal;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE RelationOps.greater(type: Types.PType): BinaryOperatorCx;
+VAR
+    result: BinaryOperatorCx;
+BEGIN
+    IF useIntOrderOp(type) THEN
+        result := Operator.greaterInt;
+    ELSIF Types.isString(type) THEN
+        result := Operator.greaterStr;
+    ELSIF type = Types.basic.real THEN
+        result := Operator.greaterReal;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE RelationOps.lessEq(type: Types.PType): BinaryOperatorCx;
+VAR
+    result: BinaryOperatorCx;
+BEGIN
+    IF useIntOrderOp(type) THEN
+        result := Operator.eqLessInt;
+    ELSIF Types.isString(type) THEN
+        result := Operator.eqLessStr;
+    ELSIF type = Types.basic.real THEN
+        result := Operator.eqLessReal;
+    ELSIF type = Types.basic.set THEN
+        result := Operator.setInclL;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE RelationOps.greaterEq(type: Types.PType): BinaryOperatorCx;
+VAR
+    result: BinaryOperatorCx;
+BEGIN
+    IF useIntOrderOp(type) THEN
+        result := Operator.eqGreaterInt;
+    ELSIF Types.isString(type) THEN
+        result := Operator.eqGreaterStr;
+    ELSIF type = Types.basic.real THEN
+        result := Operator.eqGreaterReal;
+    ELSIF type = Types.basic.set THEN
+        result := Operator.setInclR;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE castCode*(type: Types.PType; cx: Context.Type): STRING;
+BEGIN
+    baseType <- type;
+    IF type IS Record.PPointer THEN
+        baseType := Record.pointerBase(type^);
+    END;
+    RETURN Record.constructor(cx, baseType(Record.PType)^);
+END;
+
+PROCEDURE RelationOps.is(type: Types.PType; cx: Context.Type): BinaryOperatorCx;
+VAR
+    r: BinaryOperatorCx;
+
+    PROCEDURE is(left, right: Expression.PType; unused: LanguageContext.PType): Expression.PType;
+    VAR
+        leftVar: Types.PVariable;
+    BEGIN
+        d <- left.designator();
+        IF d # NIL THEN
+            info <- d.info();
+            IF info IS Types.PVariable THEN
+                leftVar := info;
+            END;
+        END;
+        rightType <- right.designator().info()(TypeId.PType).type();
+        checkTypeCast(leftVar, left.type(), rightType, "type test");
+        RETURN Operator.is(left, Expression.makeSimple(castCode(rightType, cx), NIL));
+    END;
+
+BEGIN    
+    JS.do("r = is"); (*allow closure*)
+    RETURN r;
+END;
+
+PROCEDURE RelationOps.eqExpect(): STRING;
+    RETURN "numeric type or SET or BOOLEAN or CHAR or character array or POINTER or PROCEDURE";
+END;
+
+PROCEDURE RelationOps.strongRelExpect(): STRING;
+    RETURN "numeric type or CHAR or character array";
+END;
+
+PROCEDURE RelationOps.relExpect(): STRING;
+    RETURN "numeric type or SET or CHAR or character array";
+END;
+
+PROCEDURE RelationOps.coalesceType(leftType, rightType: Types.PType): Types.PType;
+VAR
+    result: Types.PType;
+BEGIN
+    IF (leftType IS Record.PPointer) & (rightType IS Record.PPointer) THEN
+        result := Cast.findPointerBaseType(leftType, rightType^);
+        IF result = NIL THEN
+            result := Cast.findPointerBaseType(rightType, leftType^);
+        END;
+    END;
+
+    IF result = NIL THEN
+        (*special case for strings*)
+        isStrings <- Types.isString(leftType) & Types.isString(rightType);
+        IF ~isStrings THEN
+            checkTypeMatch(rightType, leftType);
+        END;
+        result := leftType;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE SimpleExpression.SimpleExpression(parent: PExpressionNode)
     | SUPER(parent),
       parentExpression(parent);
 END;
 
-PROCEDURE SimpleExpression.handleTerm(e: Code.PExpression);
+PROCEDURE SimpleExpression.handleTerm(e: Expression.PType);
 VAR
-    o: PROCEDURE(e: Code.PExpression): Code.PExpression;
+    o: PROCEDURE(e: Expression.PType): Expression.PType;
 BEGIN
     type <- e.type();
     SELF.setType(type);
@@ -194,7 +504,7 @@ BEGIN
     IF (type = NIL) OR (SELF.mType = NIL) THEN
         SELF.mType := type;
     ELSE
-        ContextHierarchy.checkImplicitCast(SELF.root()^, type, SELF.mType);
+        checkImplicitCast(SELF.root()^, type, SELF.mType);
     END;
 END;
 
@@ -215,7 +525,7 @@ END;
 
 PROCEDURE Factor.handleConst(type: Types.PType; value: ConstValue.PType; code: STRING);
 BEGIN
-    SELF.expression := Code.makeExpression(code, type, NIL, value);
+    SELF.expression := Expression.make(code, type, NIL, value);
 END;
 
 PROCEDURE Factor.handleLiteral(s: STRING);
@@ -236,7 +546,7 @@ BEGIN
     SELF.logicalNot := TRUE;
 END;
 
-PROCEDURE Factor.handleExpression(e: Code.PExpression);
+PROCEDURE Factor.handleExpression(e: Expression.PType);
 BEGIN
     SELF.expression := e;
 END;
@@ -244,7 +554,7 @@ END;
 PROCEDURE Factor.endParse();
 BEGIN
     IF SELF.logicalNot THEN
-        ContextHierarchy.checkTypeMatch(SELF.expression.type(), Types.basic.bool);
+        checkTypeMatch(SELF.expression.type(), Types.basic.bool);
         SELF.expression := Operator.not(SELF.expression);
     END;
     SELF.factorParent.handleExpression(SELF.expression);
@@ -273,9 +583,9 @@ BEGIN
     SELF.operator := op;
 END;
 
-PROCEDURE Term.handleExpression(e: Code.PExpression);
+PROCEDURE Term.handleExpression(e: Expression.PType);
 BEGIN
-    ContextHierarchy.promoteExpressionType(SELF.root()^, SELF.expression, e);
+    promoteExpressionType(SELF.root()^, SELF.expression, e);
     IF SELF.operator = NIL THEN
         SELF.expression := e;
     ELSIF SELF.expression # NIL THEN
@@ -296,7 +606,7 @@ BEGIN
         IF info IS Types.PConst THEN
             const := info.value;
         END;
-        e := Code.makeExpression(d.code(), d.type(), d, const);
+        e := Expression.make(d.code(), d.type(), d, const);
     END;
     SELF.simpleExpression.handleTerm(e);
 END;

+ 10 - 126
src/ob/ContextHierarchy.ob

@@ -1,5 +1,6 @@
 MODULE ContextHierarchy;
-IMPORT Cast, Code, CodeGenerator, Errors, LanguageContext, Module, Scope, Symbols, String, Types;
+IMPORT 
+    CodeGenerator, Context, Designator, Errors, LanguageContext, Module, Scope, ScopeBase, Symbols, String, Types;
 TYPE
     PRoot = POINTER TO Root;
     PNode = POINTER TO Node;
@@ -17,18 +18,18 @@ TYPE
     END;
 
     Attributes* = RECORD
-        designator*: Code.PDesignator;
+        designator*: Designator.PType;
     END;
 
-    Node* = RECORD
+    Node* = RECORD(Context.Type)
         PROCEDURE Node*(parent: PNode);
 
         PROCEDURE root*(): PRoot;
         PROCEDURE parent*(): PNode;
         PROCEDURE handleMessage(VAR msg: Message): PMessageResult;
         PROCEDURE codeGenerator(): CodeGenerator.PIGenerator;
-        PROCEDURE qualifyScope(scope: Scope.PType): STRING;
         PROCEDURE handleLiteral*(s: STRING);
+        PROCEDURE handleIdent*(s: STRING);
         PROCEDURE genTypeName(): STRING;
         PROCEDURE endParse*();
 
@@ -39,7 +40,7 @@ TYPE
     Root* = RECORD(Node)
         PROCEDURE Root(language: LanguageContext.PType);
 
-        PROCEDURE language(): LanguageContext.PType;
+        PROCEDURE language*(): LanguageContext.PType;
 
         PROCEDURE findSymbol(ident: STRING): Symbols.PFoundSymbol;
         PROCEDURE findModule(name: STRING): Types.PModule;
@@ -77,13 +78,16 @@ PROCEDURE Node.codeGenerator(): CodeGenerator.PIGenerator;
     RETURN SELF.mParent.codeGenerator();
 END;
 
-PROCEDURE Node.qualifyScope(scope: Scope.PType): STRING;
+PROCEDURE Node.qualifyScope(scope: ScopeBase.PType): STRING;
     RETURN SELF.mParent.qualifyScope(scope);
 END;
 
 PROCEDURE Node.handleLiteral(s: STRING);
 END;
 
+PROCEDURE Node.handleIdent(s: STRING);
+END;
+
 PROCEDURE Node.genTypeName(): STRING;
     RETURN SELF.mParent.genTypeName();
 END;
@@ -186,124 +190,4 @@ PROCEDURE getSymbol*(cx: Root; id: STRING): Symbols.PSymbol;
     RETURN getSymbolAndScope(cx, id).symbol();
 END;
 
-PROCEDURE unwrapTypeId*(id: Types.PId): Types.PTypeId;
-VAR
-    result: Types.PTypeId;
-BEGIN
-    IF ~(id IS Types.PTypeId) THEN
-        Errors.raise("type name expected");
-    ELSE
-        result := id;
-    END;
-    RETURN result;
-END;
-
-PROCEDURE unwrapType*(id: Types.PId): Types.PType;
-    RETURN unwrapTypeId(id).type();
-END;
-
-PROCEDURE throwTypeMismatch(from, to: Types.PType);
-VAR
-    fromDescription: STRING;
-BEGIN
-    IF from # NIL THEN
-        fromDescription := "'" + from.description() + "'";
-    ELSE
-        fromDescription := "no type (proper procedure call)";
-    END;
-    Errors.raise("type mismatch: expected '" + to.description() 
-               + "', got " + fromDescription);
-END;
-
-PROCEDURE checkTypeMatch*(from, to: Types.PType);
-BEGIN
-    IF ~Cast.areTypesMatch(from, to) THEN
-        throwTypeMismatch(from, to);
-    END;
-END;
-
-PROCEDURE checkImplicitCast*(cx: Root; from, to: Types.PType);
-VAR
-    op: LanguageContext.PCastOp;
-BEGIN
-    IF cx.language().types.implicitCast(from, to, FALSE, op) # Cast.errNo THEN
-        throwTypeMismatch(from, to);
-    END;
-END;
-
-PROCEDURE promoteTypeInExpression*(e: Code.PExpression; type: Types.PType): Code.PExpression;
-VAR
-    v: CHAR;
-    result: Code.PExpression;
-BEGIN
-    fromType <- e.type();
-    IF (type = Types.basic.ch) & (fromType IS Types.PString) & Types.stringAsChar(fromType^, v) THEN
-        result := Code.makeSimpleExpression(String.fromInt(ORD(v)), type);
-    ELSE
-        result := e;
-    END;
-    RETURN result;
-END;
-
-PROCEDURE promoteExpressionType*(cx: Root; left, right: Code.PExpression);
-BEGIN
-    IF left # NIL THEN
-        rightType <- right.type();
-        leftType <- left.type();
-        IF (leftType # NIL) & (rightType # NIL) THEN
-            checkImplicitCast(cx, rightType, leftType);
-        END;
-    END;
-END;
-
-PROCEDURE checkTypeCast*(fromInfo: Types.Variable; fromType, toType: Types.PType; msg: STRING);
-VAR
-    PROCEDURE checkCommonBase(from, to: Types.PRecord; prefix: STRING);
-    BEGIN
-        t <- to.base;
-        WHILE (t # NIL) & (t # from) DO
-            t := t.base;
-        END;
-        IF t = NIL THEN
-            Errors.raise(prefix + ": '" + to.description()
-                       + "' is not an extension of '" + from.description() + "'");
-        END;
-    END;
-
-BEGIN
-    prefix <- "invalid " + msg;
-
-    pointerExpected <- fromType IS Types.PPointer;
-    IF ~pointerExpected & ~(fromType IS Types.PRecord) THEN
-        Errors.raise(
-            prefix + ": POINTER to type or RECORD expected, got '"
-            + fromType.description() + "'");
-    END;
-
-    IF ~pointerExpected THEN
-        IF ~fromInfo.isReference() THEN
-            Errors.raise(
-                prefix + ": a value variable cannot be used");
-        ELSIF ~(toType IS Types.PRecord) THEN
-            Errors.raise(
-                prefix + ": RECORD type expected as an argument of RECORD " + msg + ", got '"
-              + toType.description() + "'");
-        END;
-    ELSIF ~(toType IS Types.PPointer) THEN
-        Errors.raise(
-            prefix + ": POINTER type expected as an argument of POINTER " + msg + ", got '"
-          + toType.description() + "'");
-    END;
-
-    IF pointerExpected THEN
-        checkCommonBase(Types.pointerBase(fromType(Types.PPointer)^), 
-                        Types.pointerBase(toType(Types.PPointer)^), 
-                        prefix);
-    ELSE
-        checkCommonBase(fromType(Types.PRecord), 
-                        toType(Types.PRecord), 
-                        prefix);
-    END;
-END checkTypeCast;
-
 END ContextHierarchy.

+ 51 - 0
src/ob/Designator.ob

@@ -0,0 +1,51 @@
+MODULE Designator;
+IMPORT
+    ScopeBase, Types;
+TYPE
+    Type* = RECORD
+        PROCEDURE Type*(code: STRING; lval: STRING; type: Types.PType; info: Types.PId; scope: ScopeBase.PType);
+
+        PROCEDURE code*(): STRING;
+        PROCEDURE lval*(): STRING;
+        PROCEDURE type*(): Types.PType;
+        PROCEDURE info*(): Types.PId;
+        PROCEDURE scope(): ScopeBase.PType;
+
+        mCode: STRING;
+        mLval: STRING;
+        mType: Types.PType;
+        mInfo: Types.PId;
+        mScope: ScopeBase.PType
+    END;
+
+    PType* = POINTER TO Type;
+
+PROCEDURE Type.code(): STRING;
+    RETURN SELF.mCode
+END;
+
+PROCEDURE Type.lval(): STRING;
+    RETURN SELF.mLval
+END;
+
+PROCEDURE Type.type(): Types.PType;
+    RETURN SELF.mType
+END;
+
+PROCEDURE Type.info(): Types.PId;
+    RETURN SELF.mInfo
+END;
+
+PROCEDURE Type.scope(): ScopeBase.PType;
+    RETURN SELF.mScope
+END;
+
+PROCEDURE Type.Type(code: STRING; lval: STRING; type: Types.PType; info: Types.PId; scope: ScopeBase.PType)
+  | mCode(code),
+    mLval(lval),
+    mType(type),
+    mInfo(info),
+    mScope(scope);
+END;
+
+END Designator.

+ 108 - 0
src/ob/Expression.ob

@@ -0,0 +1,108 @@
+MODULE Expression;
+IMPORT
+    ConstValue, Designator, Precedence := CodePrecedence, Types;
+TYPE
+    Type* = RECORD
+        PROCEDURE Type*(
+            code: STRING; 
+            type: Types.PType; 
+            designator: Designator.PType; 
+            constValue: ConstValue.PType; 
+            maxPrecedence: INTEGER);
+
+        PROCEDURE code*(): STRING;
+        PROCEDURE lval*(): STRING;
+        PROCEDURE type*(): Types.PType;
+        PROCEDURE designator*(): Designator.PType;
+        PROCEDURE constValue*(): ConstValue.PType;
+        PROCEDURE maxPrecedence*(): INTEGER;
+        PROCEDURE isTerm*(): BOOLEAN;
+
+        mCode: STRING;
+        mType: Types.PType;
+        mDesignator: Designator.PType;
+        mConstValue: ConstValue.PType;
+        mMaxPrecedence: INTEGER
+    END;
+
+    PType* = POINTER TO Type;
+
+PROCEDURE Type.code(): STRING;
+    RETURN SELF.mCode
+END;
+
+PROCEDURE Type.lval(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF SELF.mDesignator # NIL THEN
+        result := SELF.mDesignator.lval();
+    ELSE
+        result := SELF.mCode;
+    END;
+    RETURN result
+END;
+
+PROCEDURE Type.type(): Types.PType;
+    RETURN SELF.mType
+END;
+
+PROCEDURE Type.designator(): Designator.PType;
+    RETURN SELF.mDesignator
+END;
+
+PROCEDURE Type.constValue(): ConstValue.PType;
+    RETURN SELF.mConstValue
+END;
+
+PROCEDURE Type.maxPrecedence(): INTEGER;
+    RETURN SELF.mMaxPrecedence
+END;
+
+PROCEDURE Type.isTerm(): BOOLEAN;
+    RETURN (SELF.mDesignator = NIL) & (SELF.mMaxPrecedence = Precedence.none)
+END;
+
+PROCEDURE Type.Type(
+    code: STRING; 
+    type: Types.PType; 
+    designator: Designator.PType; 
+    constValue: ConstValue.PType; 
+    maxPrecedence: INTEGER)
+  | mCode(code),
+    mType(type),
+    mDesignator(designator),
+    mConstValue(constValue),
+    mMaxPrecedence(maxPrecedence);
+END;
+
+PROCEDURE make*(
+    code: STRING; 
+    type: Types.PType; 
+    designator: Designator.PType; 
+    constValue: ConstValue.PType)
+    : PType;
+    RETURN NEW Type(code, type, designator, constValue, Precedence.none)
+END;
+
+PROCEDURE makeSimple*(code: STRING; type: Types.PType): PType;
+    RETURN make(code, type, NIL, NIL)
+END;
+
+PROCEDURE deref*(e: PType): PType;
+BEGIN
+    result <- e;
+    designator <- e.mDesignator;
+    type <- e.mType;
+    IF    (designator # NIL)
+      & ~((type IS Types.PArray) OR (type IS Types.PRecord)) THEN
+        
+        info <- designator.info();
+        IF ((info IS Types.PVariable) & info.isReference()) THEN
+            result := makeSimple(e.code() + ".get()", type);
+        END;
+    END;
+    RETURN result
+END;
+
+END Expression.

+ 4 - 4
src/ob/LanguageContext.ob

@@ -1,13 +1,13 @@
 MODULE LanguageContext;
-IMPORT Code, Context, CodeGenerator, T := Types;
+IMPORT Context, CodeGenerator, Expression, T := Types;
 
 TYPE
     PType* = POINTER TO Type;
 
     CastOp* = RECORD
-        PROCEDURE make*(cx: PType; e: Code.PExpression): Code.PExpression;
-        PROCEDURE assign*(cx: PType; left, right: Code.PExpression): STRING;
-        PROCEDURE clone*(cx: PType; e: Code.PExpression): STRING;
+        PROCEDURE make*(cx: PType; e: Expression.PType): Expression.PType;
+        PROCEDURE assign*(cx: PType; left, right: Expression.PType): STRING;
+        PROCEDURE clone*(cx: PType; e: Expression.PType): STRING;
     END;
 
     PCastOp* = POINTER TO CastOp;

+ 7 - 7
src/ob/Lexer.ob

@@ -1,6 +1,6 @@
 MODULE Lexer;
-IMPORT Chars, Context, ContextExpression, ContextHierarchy, Errors, Stream, String;
-
+IMPORT 
+    Chars, ContextExpression, ContextHierarchy, Errors, Stream, String;
 CONST
     doubleQuote = Chars.doubleQuote;
     commentBegin = "(*";
@@ -185,7 +185,7 @@ PROCEDURE isHexDigit(c: CHAR): BOOLEAN;
     RETURN isDigit(c) OR ((c >= "A") & (c <= "F"));
 END;
 
-PROCEDURE point*(VAR stream: Stream.Type; context: Context.Type): BOOLEAN;
+PROCEDURE point*(VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
 VAR result: BOOLEAN;
 BEGIN
     IF    ~Stream.eof(stream)
@@ -270,7 +270,7 @@ BEGIN
     RETURN i = LEN(s)
 END isReservedWord;
 
-PROCEDURE ident*(VAR stream: Stream.Type; context: Context.Type; reservedWords: STRING): BOOLEAN;
+PROCEDURE ident*(VAR stream: Stream.Type; context: ContextHierarchy.Node; reservedWords: STRING): BOOLEAN;
 VAR
     result: BOOLEAN;
     c: CHAR;
@@ -301,7 +301,7 @@ BEGIN
     RETURN result
 END ident;
 
-PROCEDURE skipComment(VAR stream: Stream.Type; context: Context.Type): BOOLEAN;
+PROCEDURE skipComment(VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
 VAR
     result: BOOLEAN;
 BEGIN
@@ -329,7 +329,7 @@ PROCEDURE readSpaces(c: CHAR): BOOLEAN;
         OR (c = 0DX)
 END readSpaces;
 
-PROCEDURE skipSpaces*(VAR stream: Stream.Type; context: Context.Type);
+PROCEDURE skipSpaces*(VAR stream: Stream.Type; context: ContextHierarchy.Node);
 BEGIN
     WHILE Stream.read(stream, readSpaces)
         & skipComment(stream, context) DO 
@@ -340,7 +340,7 @@ PROCEDURE Literal.Literal(s: STRING)
     | s(s);
 END;
 
-PROCEDURE literal*(l: Literal; VAR stream: Stream.Type; context: Context.Type): BOOLEAN;
+PROCEDURE literal*(l: Literal; VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
 VAR
     result: BOOLEAN;
 BEGIN

+ 9 - 8
src/ob/Module.ob

@@ -1,5 +1,6 @@
 MODULE Module;
-IMPORT Code, Context, Errors, LanguageContext, Procedure, Symbols, Types;
+IMPORT 
+    Context, Errors, Expression, LanguageContext, Procedure, Symbols, TypeId, Types;
 TYPE
     Type* = RECORD(Types.Module)
         PROCEDURE findSymbol*(id: STRING): Symbols.PFoundSymbol
@@ -86,13 +87,13 @@ PROCEDURE AnyTypeProc.callGenerator(cx: LanguageContext.PType): Procedure.PCallG
     RETURN makeCallGenerator(cx)
 END AnyTypeProc.callGenerator;
 
-PROCEDURE AnyProcCall.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE AnyProcCall.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 BEGIN
     argCode <- Procedure.makeArgumentsCode(cx);
     FOR i <- 0 TO LEN(args) - 1 DO
         argCode.write(args[i], NIL, NIL);
     END;
-    RETURN Code.makeSimpleExpression("(" + argCode.result() + ")", any)
+    RETURN Expression.makeSimple("(" + argCode.result() + ")", any)
 END AnyProcCall.make;
 
 PROCEDURE JS.findSymbol(id: STRING): Symbols.PFoundSymbol;
@@ -110,7 +111,7 @@ BEGIN
 END JS.findSymbol;
 
 PROCEDURE makeVarTypeSymbol(): Symbols.PSymbol;
-    RETURN NEW Symbols.Symbol(varTypeId, NEW Types.TypeId(any))
+    RETURN NEW Symbols.Symbol(varTypeId, NEW TypeId.Type(any))
 END makeVarTypeSymbol;
 
 PROCEDURE makeDoProcSymbol(): Symbols.PSymbol;
@@ -122,9 +123,9 @@ TYPE
 VAR
     description: STRING;
 
-    PROCEDURE Call.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE Call.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
         type: Types.PType;
     BEGIN
         arg := Procedure.checkSingleArgument(args, SELF, cx.types, NIL);
@@ -133,7 +134,7 @@ VAR
             Errors.raise("string is expected as an argument of "
                        + description + ", got " + type.description());
         END;
-        RETURN Code.makeSimpleExpression(Types.stringValue(type(Types.PString)^), NIL)
+        RETURN Expression.makeSimple(Types.stringValue(type(Types.PString)^), NIL)
     END Call.make;
 
     PROCEDURE Proc.description(): STRING;
@@ -152,7 +153,7 @@ PROCEDURE makeJS*(): PType;
 END;
 
 PROCEDURE AnyType.AnyType()
-    | asVar(NEW Types.TypeId(SELF(POINTER)));
+    | asVar(NEW TypeId.Type(SELF(POINTER)));
 END;
 
 PROCEDURE AnyField.AnyField(id: STRING)

+ 108 - 106
src/ob/Operator.ob

@@ -3,7 +3,9 @@ IMPORT
     Cast, 
     Code,
     ConstValue, 
+    Designator,
     Errors, 
+    Expression,
     LanguageContext, 
     OberonRtl, 
     Precedence := CodePrecedence,
@@ -13,7 +15,7 @@ CONST
     equalCode* = " == ";
     notEqualCode* = " != ";
 TYPE
-    BinaryProc* = PROCEDURE(left, right: Code.PExpression): Code.PExpression;
+    BinaryProc* = PROCEDURE(left, right: Expression.PType): Expression.PType;
 
     BinaryOp = PROCEDURE(left, right: ConstValue.PType): ConstValue.PType;
     CodePredicate = PROCEDURE(left, right: STRING; rtl: OberonRtl.PType): STRING;
@@ -47,21 +49,21 @@ VAR
     castOperations*: Cast.Operations;
 
 PROCEDURE binary(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     rtl: OberonRtl.PType;
     op: BinaryOp;
     code: PCodeMaker;
     precedence: INTEGER;
     optResultType: Types.PType;
     optResultPrecedence: INTEGER
-    ): Code.PExpression;
+    ): Expression.PType;
 VAR
-    result: Code.PExpression;
+    result: Expression.PType;
     leftValue, rightValue, resultValue: ConstValue.PType;
     leftCode, rightCode, resultCode: STRING;
     resultType: Types.PType;
     resultPrecedence: INTEGER;
-    rightExpDeref: Code.PExpression;
+    rightExpDeref: Expression.PType;
 BEGIN
     leftValue := left.constValue();
     rightValue := right.constValue();
@@ -69,10 +71,10 @@ BEGIN
         resultValue := op(leftValue, rightValue);
     END;
 
-    leftCode := Code.adjustPrecedence(Code.derefExpression(left), precedence);
+    leftCode := Code.adjustPrecedence(Expression.deref(left), precedence);
 
     (* right code needs parentheses even if it has the same percedence *)
-    rightExpDeref := Code.derefExpression(right);
+    rightExpDeref := Expression.deref(right);
     IF precedence # Precedence.none THEN
         rightCode := Code.adjustPrecedence(rightExpDeref, precedence - 1);
     ELSE
@@ -92,7 +94,7 @@ BEGIN
     ELSE
         resultPrecedence := precedence;
     END;
-    RETURN NEW Code.Expression(resultCode, resultType, NIL, resultValue, resultPrecedence)
+    RETURN NEW Expression.Type(resultCode, resultType, NIL, resultValue, resultPrecedence)
 END binary;
 
 PROCEDURE SimpleCodeMaker.make(left, right: STRING; rtl: OberonRtl.PType): STRING;
@@ -118,13 +120,13 @@ PROCEDURE PredCodeMaker.PredCodeMaker(pred: CodePredicate)
 END;
 
 PROCEDURE binaryWithCodeEx(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     op: BinaryOp;
     code: STRING;
     precedence: INTEGER;
     optResultType: Types.PType;
     optResultPrecedence: INTEGER
-    ): Code.PExpression;
+    ): Expression.PType;
     RETURN binary(
         left, 
         right, 
@@ -137,38 +139,38 @@ PROCEDURE binaryWithCodeEx(
 END;
 
 PROCEDURE binaryWithCode*(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     op: BinaryOp;
     code: STRING;
     precedence: INTEGER
-    ): Code.PExpression;
+    ): Expression.PType;
     RETURN binaryWithCodeEx(left, right, op, code, precedence, NIL, Precedence.none)
 END binaryWithCode;
 
 PROCEDURE relational*(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     op: BinaryOp;
     code: STRING
-    ): Code.PExpression;
+    ): Expression.PType;
     RETURN binaryWithCodeEx(left, right, op, code, Precedence.relational, Types.basic.bool, Precedence.none)
 END;
 
 PROCEDURE equal*(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     op: BinaryOp;
     code: STRING
-    ): Code.PExpression;
+    ): Expression.PType;
     RETURN binaryWithCodeEx(left, right, op, code, Precedence.equal, Types.basic.bool, Precedence.none)
 END;
 
-PROCEDURE promoteToWideIfNeeded(e: Code.PExpression): Code.PExpression;
+PROCEDURE promoteToWideIfNeeded(e: Expression.PType): Expression.PType;
 VAR
-    result: Code.PExpression;
+    result: Expression.PType;
 BEGIN
     IF e.type() # Types.basic.uint8 THEN
         result := e;
     ELSE
-        result := NEW Code.Expression(
+        result := NEW Expression.Type(
                 e.code(),
                 Types.basic.integer,
                 e.designator(),
@@ -179,11 +181,11 @@ BEGIN
 END promoteToWideIfNeeded;
 
 PROCEDURE binaryInt(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     op: BinaryOp;
     code: STRING;
     precedence: INTEGER
-    ): Code.PExpression;
+    ): Expression.PType;
     RETURN promoteToWideIfNeeded(binary(
         left, 
         right, 
@@ -197,11 +199,11 @@ PROCEDURE binaryInt(
 END binaryInt;
 
 PROCEDURE binaryPred(
-    left, right: Code.PExpression; 
+    left, right: Expression.PType; 
     rtl: OberonRtl.PType;
     op: BinaryOp;
     pred: CodePredicate
-    ): Code.PExpression;
+    ): Expression.PType;
     RETURN binary(
         left, 
         right, 
@@ -214,7 +216,7 @@ PROCEDURE binaryPred(
         )
 END binaryPred;
 
-PROCEDURE unary(e: Code.PExpression; op: UnaryOp; code: STRING): Code.PExpression;
+PROCEDURE unary(e: Expression.PType; op: UnaryOp; code: STRING): Expression.PType;
 VAR
     value: ConstValue.PType;
 BEGIN
@@ -223,13 +225,13 @@ BEGIN
         value := op(value);
     END;
     resultCode <- code 
-                + Code.adjustPrecedence(Code.derefExpression(e), Precedence.unary);
-    RETURN NEW Code.Expression(resultCode, e.type(), NIL, value, Precedence.unary)
+                + Code.adjustPrecedence(Expression.deref(e), Precedence.unary);
+    RETURN NEW Expression.Type(resultCode, e.type(), NIL, value, Precedence.unary)
 END;
 
-PROCEDURE castToStr(e: Code.PExpression; cx: LanguageContext.PType): STRING;
+PROCEDURE castToStr(e: Expression.PType; cx: LanguageContext.PType): STRING;
 VAR
-    resultExpression: Code.PExpression;
+    resultExpression: Expression.PType;
     op: LanguageContext.PCastOp;
     ignored: INTEGER;
 BEGIN
@@ -441,15 +443,15 @@ PROCEDURE codeSetInclR(left, right: STRING; rtl: OberonRtl.PType): STRING;
     RETURN rtl.setInclR(left, right)
 END codeSetInclR;
 
-PROCEDURE strCmp(op: STRING; left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
-    RETURN Code.makeSimpleExpression(
+PROCEDURE strCmp(op: STRING; left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
+    RETURN Expression.makeSimple(
             cx.rtl.strCmp(castToStr(left, cx), castToStr(right, cx)) + op + "0",
             Types.basic.bool)
 END;
 
-PROCEDURE assign*(left, right: Code.PExpression; cx: LanguageContext.PType): STRING;
+PROCEDURE assign*(left, right: Expression.PType; cx: LanguageContext.PType): STRING;
 VAR
-    designator: Code.PDesignator;
+    designator: Designator.PType;
     leftCode, rightCode: STRING;
     isArray: BOOLEAN;
     castOperation: LanguageContext.PCastOp;
@@ -500,10 +502,10 @@ BEGIN
     RETURN result
 END assign;
     
-PROCEDURE inplace(left, right: Code.PExpression; cx: LanguageContext.PType; code: STRING; altOp: BinaryProc): STRING;
+PROCEDURE inplace(left, right: Expression.PType; cx: LanguageContext.PType; code: STRING; altOp: BinaryProc): STRING;
 VAR
-    designator: Code.PDesignator;
-    rightExp: Code.PExpression;
+    designator: Designator.PType;
+    rightExp: Expression.PType;
     result: STRING;
 BEGIN
     designator := left.designator();
@@ -511,241 +513,241 @@ BEGIN
     IF (info IS Types.PVariable) & info.isReference() THEN
         result := assign(left, altOp(left, right), cx);
     ELSE
-        rightExp := Code.derefExpression(right);
+        rightExp := Expression.deref(right);
         result := left.code() + code + rightExp.code();
     END;
     RETURN result
 END inplace;
 
-PROCEDURE addReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE addReal*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opAddReal, " + ", Precedence.addSub)
 END addReal;
 
-PROCEDURE addInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE addInt*(left, right: Expression.PType): Expression.PType;
     RETURN binaryInt(left, right, opAddInt, " + ", Precedence.addSub)
 END addInt;
 
-PROCEDURE subReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE subReal*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opSubReal, " - ", Precedence.addSub)
 END subReal;
 
-PROCEDURE subInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE subInt*(left, right: Expression.PType): Expression.PType;
     RETURN binaryInt(left, right, opSubInt, " - ", Precedence.addSub)
 END subInt;
 
-PROCEDURE mulReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE mulReal*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opMulReal, " * ", Precedence.mulDivMod)
 END mulReal;
 
-PROCEDURE mulInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE mulInt*(left, right: Expression.PType): Expression.PType;
     RETURN binaryInt(left, right, opMulInt, " * ", Precedence.mulDivMod)
 END mulInt;
 
-PROCEDURE divReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE divReal*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opDivReal, " / ", Precedence.mulDivMod)
 END divReal;
 
-PROCEDURE divInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE divInt*(left, right: Expression.PType): Expression.PType;
     RETURN binaryInt(left, right, opDivInt, " / ", Precedence.mulDivMod)
 END divInt;
 
-PROCEDURE mod*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE mod*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opMod, " % ", Precedence.mulDivMod)
 END mod;
 
-PROCEDURE setUnion*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE setUnion*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opSetUnion, " | ", Precedence.bitOr)
 END setUnion;
 
-PROCEDURE setDiff*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE setDiff*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opSetDiff, " & ~", Precedence.bitAnd)
 END setDiff;
 
-PROCEDURE setIntersection*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE setIntersection*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opSetIntersection, " & ", Precedence.bitAnd)
 END setIntersection;
 
-PROCEDURE setSymmetricDiff*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE setSymmetricDiff*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opSetSymmetricDiff, " ^ ", Precedence.bitXor)
 END setSymmetricDiff;
 
-PROCEDURE setHasBit*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN NEW Code.Expression(
-            "1 << " + Code.adjustPrecedence(Code.derefExpression(left), Precedence.shift) 
-            + " & " + Code.adjustPrecedence(Code.derefExpression(right), Precedence.bitAnd),
+PROCEDURE setHasBit*(left, right: Expression.PType; rtl: OberonRtl.PType): Expression.PType;
+    RETURN NEW Expression.Type(
+            "1 << " + Code.adjustPrecedence(Expression.deref(left), Precedence.shift) 
+            + " & " + Code.adjustPrecedence(Expression.deref(right), Precedence.bitAnd),
             Types.basic.bool,
             NIL,
             NIL,
             Precedence.bitAnd)
 END setHasBit;
 
-PROCEDURE setInclL*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE setInclL*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN binaryPred(left, right, cx.rtl, opSetInclL, codeSetInclL)
 END setInclL;
 
-PROCEDURE setInclR*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE setInclR*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN binaryPred(left, right, cx.rtl, opSetInclR, codeSetInclR)
 END setInclR;
 
-PROCEDURE or*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE or*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opOr, " || ", Precedence.or)
 END or;
 
-PROCEDURE and*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE and*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opAnd, " && ", Precedence.and)
 END and;
 
-PROCEDURE equalInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE equalInt*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN equal(left, right, opEqualInt, equalCode)
 END equalInt;
 
-PROCEDURE equalReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE equalReal*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN equal(left, right, opEqualReal, equalCode)
 END equalReal;
 
-PROCEDURE equalSet*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE equalSet*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN equal(left, right, opEqualSet, equalCode)
 END equalSet;
 
-PROCEDURE equalStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE equalStr*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN strCmp(equalCode, left, right, cx)
 END equalStr;
 
-PROCEDURE notEqualInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE notEqualInt*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN equal(left, right, opNotEqualInt, notEqualCode)
 END notEqualInt;
 
-PROCEDURE notEqualReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE notEqualReal*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN equal(left, right, opNotEqualReal, notEqualCode)
 END notEqualReal;
 
-PROCEDURE notEqualSet*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE notEqualSet*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN equal(left, right, opNotEqualSet, notEqualCode)
 END notEqualSet;
 
-PROCEDURE notEqualStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE notEqualStr*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN strCmp(notEqualCode, left, right, cx)
 END notEqualStr;
 
-PROCEDURE is*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE is*(left, right: Expression.PType): Expression.PType;
     RETURN relational(left, right, NIL, " instanceof ")
 END is;
 
-PROCEDURE lessInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE lessInt*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opLessInt, " < ")
 END lessInt;
 
-PROCEDURE lessReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE lessReal*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opLessReal, " < ")
 END lessReal;
 
-PROCEDURE lessStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE lessStr*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN strCmp(" < ", left, right, cx)
 END lessStr;
 
-PROCEDURE greaterInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE greaterInt*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opGreaterInt, " > ")
 END greaterInt;
 
-PROCEDURE greaterReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE greaterReal*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opGreaterReal, " > ")
 END greaterReal;
 
-PROCEDURE greaterStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE greaterStr*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN strCmp(" > ", left, right, cx)
 END greaterStr;
 
-PROCEDURE eqLessInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE eqLessInt*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opEqLessInt, " <= ")
 END eqLessInt;
 
-PROCEDURE eqLessReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE eqLessReal*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opEqLessReal, " <= ")
 END eqLessReal;
 
-PROCEDURE eqLessStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE eqLessStr*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN strCmp(" <= ", left, right, cx)
 END eqLessStr;
 
-PROCEDURE eqGreaterInt*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE eqGreaterInt*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opEqGreaterInt, " >= ")
 END eqGreaterInt;
 
-PROCEDURE eqGreaterReal*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE eqGreaterReal*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN relational(left, right, opEqGreaterReal, " >= ")
 END eqGreaterReal;
 
-PROCEDURE eqGreaterStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE eqGreaterStr*(left, right: Expression.PType; cx: LanguageContext.PType): Expression.PType;
     RETURN strCmp(" >= ", left, right, cx)
 END eqGreaterStr;
 
-PROCEDURE not*(x: Code.PExpression): Code.PExpression;
+PROCEDURE not*(x: Expression.PType): Expression.PType;
     RETURN unary(x, opNot, "!")
 END not;
 
-PROCEDURE negateInt*(x: Code.PExpression): Code.PExpression;
+PROCEDURE negateInt*(x: Expression.PType): Expression.PType;
 VAR
-    result: Code.PExpression;
+    result: Expression.PType;
 BEGIN
     overflowCheck <- TRUE;
     c <- x.constValue();
     IF c # NIL THEN
         value <- -c^(ConstValue.Int).value;
-        result := NEW Code.Expression(String.fromInt(value), Types.basic.integer, NIL, NEW ConstValue.Int(value), Precedence.unary);
+        result := NEW Expression.Type(String.fromInt(value), Types.basic.integer, NIL, NEW ConstValue.Int(value), Precedence.unary);
     ELSE
         result := promoteToWideIfNeeded(unary(x, opNegateInt, "-"));
-        result := NEW Code.Expression(result.code() + " | 0", result.type(), result.designator(), result.constValue(), Precedence.bitOr);
+        result := NEW Expression.Type(result.code() + " | 0", result.type(), result.designator(), result.constValue(), Precedence.bitOr);
     END;
     RETURN result;
 END;
 
-PROCEDURE negateReal*(x: Code.PExpression): Code.PExpression;
+PROCEDURE negateReal*(x: Expression.PType): Expression.PType;
     RETURN promoteToWideIfNeeded(unary(x, opNegateReal, "-"))
 END negateReal;
 
-PROCEDURE unaryPlus*(x: Code.PExpression): Code.PExpression;
+PROCEDURE unaryPlus*(x: Expression.PType): Expression.PType;
     RETURN unary(x, opUnaryPlus, "")
 END unaryPlus;
 
-PROCEDURE setComplement*(x: Code.PExpression): Code.PExpression;
+PROCEDURE setComplement*(x: Expression.PType): Expression.PType;
     RETURN unary(x, opSetComplement, "~")
 END setComplement;
 
-PROCEDURE lsl*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE lsl*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opLsl, " << ", Precedence.shift)
 END lsl;
 
-PROCEDURE asr*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE asr*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opAsr, " >> ", Precedence.shift)
 END asr;
 
-PROCEDURE ror*(left, right: Code.PExpression): Code.PExpression;
+PROCEDURE ror*(left, right: Expression.PType): Expression.PType;
     RETURN binaryWithCode(left, right, opRor, " >>> ", Precedence.shift)
 END ror;
 
-PROCEDURE mulInplace*(left, right: Code.PExpression; cx: LanguageContext.PType): STRING;
+PROCEDURE mulInplace*(left, right: Expression.PType; cx: LanguageContext.PType): STRING;
     RETURN inplace(left, right, cx, " *= ", mulReal)
 END mulInplace;
 
-PROCEDURE divInplace*(left, right: Code.PExpression; cx: LanguageContext.PType): STRING;
+PROCEDURE divInplace*(left, right: Expression.PType; cx: LanguageContext.PType): STRING;
     RETURN inplace(left, right, cx, " /= ", divReal)
 END divInplace;
 
-PROCEDURE pow2*(e: Code.PExpression): Code.PExpression;
+PROCEDURE pow2*(e: Expression.PType): Expression.PType;
 VAR
-    derefExp: Code.PExpression;
+    derefExp: Expression.PType;
 BEGIN
-    derefExp := Code.derefExpression(e);
-    RETURN Code.makeSimpleExpression("Math.pow(2, " + derefExp.code() + ")",
-                                     Types.basic.real)
+    derefExp := Expression.deref(e);
+    RETURN Expression.makeSimple("Math.pow(2, " + derefExp.code() + ")",
+                                 Types.basic.real)
 END pow2;
 
-PROCEDURE log2*(e: Code.PExpression): Code.PExpression;
+PROCEDURE log2*(e: Expression.PType): Expression.PType;
 VAR
-    derefExp: Code.PExpression;
+    derefExp: Expression.PType;
 BEGIN
-    derefExp := Code.derefExpression(e);
-    RETURN NEW Code.Expression(
+    derefExp := Expression.deref(e);
+    RETURN NEW Expression.Type(
             "(Math.log(" + derefExp.code() + ") / Math.LN2) | 0",
             Types.basic.integer,
             NIL,
@@ -758,19 +760,19 @@ PROCEDURE opCastToUint8(left, right: ConstValue.PType): ConstValue.PType;
                             * right^(ConstValue.Int).value)
 END opCastToUint8;
 
-PROCEDURE CastToUint8.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastToUint8.make(cx: LanguageContext.PType; e: Expression.PType): Expression.PType;
     RETURN binaryWithCode(
         e, 
-        Code.makeExpression("0xFF", 
-                            Types.basic.integer, 
-                            NIL, 
-                            NEW ConstValue.Int(0FFH)), 
+        Expression.make("0xFF", 
+                        Types.basic.integer, 
+                        NIL, 
+                        NEW ConstValue.Int(0FFH)), 
         opCastToUint8, 
         " & ", 
         Precedence.bitAnd)
 END;
 
-PROCEDURE CastToUint8.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
+PROCEDURE CastToUint8.clone(cx: LanguageContext.PType; e: Expression.PType): STRING;
     RETURN SELF.make(cx, e).code();
 END;
 

+ 76 - 72
src/ob/Procedure.ob

@@ -4,18 +4,22 @@ IMPORT
     Code, 
     Context, 
     ConstValue,
+    Designator,
     Errors, 
+    Expression,
     LanguageContext,
     OberonRtl,
     Object, 
     Operator, 
     Precedence := CodePrecedence, 
+    Record,
     String,
     Symbols, 
+    TypeId,
     Types;
 TYPE
     Call* = RECORD
-        PROCEDURE make*(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression
+        PROCEDURE make*(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType
     END;
     PCall = POINTER TO Call;
 
@@ -30,13 +34,13 @@ TYPE
     END;
 
     CallGenerator* = RECORD
-        PROCEDURE handleArgument*(e: Code.PExpression);
-        PROCEDURE end*(): Code.PExpression;
+        PROCEDURE handleArgument*(e: Expression.PType);
+        PROCEDURE end*(): Expression.PType;
     END;
     PCallGenerator* = POINTER TO CallGenerator;
 
     CallGeneratorImpl = RECORD(CallGenerator)
-        args: ARRAY * OF Code.PExpression;
+        args: ARRAY * OF Expression.PType;
         cx: LanguageContext.PType;
         call: PCall
     END;
@@ -59,7 +63,7 @@ TYPE
     END;
 
     ArgumentsCode* = RECORD
-        PROCEDURE write*(actual: Code.PExpression; 
+        PROCEDURE write*(actual: Expression.PType; 
                          expected: Types.PProcedureArgument; 
                          cast: LanguageContext.PCastOp
                          );
@@ -77,7 +81,7 @@ VAR
     predefined*: ARRAY * OF Symbols.PSymbol;
 
 PROCEDURE checkArgument*(
-    actual: Code.PExpression; 
+    actual: Expression.PType; 
     expected: Types.PProcedureArgument; 
     pos: INTEGER;
     code: PArgumentsCode;
@@ -85,7 +89,7 @@ PROCEDURE checkArgument*(
     );
 VAR
     actualType, expectType: Types.PType;
-    designator: Code.PDesignator;
+    designator: Designator.PType;
     result: LanguageContext.PCastOp;
     castErr: INTEGER;
 BEGIN
@@ -119,7 +123,7 @@ BEGIN
 END checkArgument;
 
 PROCEDURE checkArgumentsType(
-    actual: ARRAY OF Code.PExpression;
+    actual: ARRAY OF Expression.PType;
     expected: ARRAY OF Types.PProcedureArgument; 
     code: PArgumentsCode;
     types: LanguageContext.PTypes
@@ -140,7 +144,7 @@ BEGIN
 END checkArgumentsCount;
 
 PROCEDURE processArguments*(
-    actual: ARRAY OF Code.PExpression;
+    actual: ARRAY OF Expression.PType;
     expected: ARRAY OF Types.PProcedureArgument; 
     code: PArgumentsCode;
     types: LanguageContext.PTypes
@@ -150,7 +154,7 @@ BEGIN
     checkArgumentsType(actual, expected, code, types);
 END processArguments;
 
-PROCEDURE checkArguments(actual: ARRAY OF Code.PExpression; expected: ARRAY OF Types.PProcedureArgument; types: LanguageContext.PTypes);
+PROCEDURE checkArguments(actual: ARRAY OF Expression.PType; expected: ARRAY OF Types.PProcedureArgument; types: LanguageContext.PTypes);
 BEGIN
     processArguments(actual, expected, NIL, types);
 END checkArguments;
@@ -161,12 +165,12 @@ BEGIN
     SELF.call := call;
 END;
 
-PROCEDURE CallGeneratorImpl.handleArgument(e: Code.PExpression);
+PROCEDURE CallGeneratorImpl.handleArgument(e: Expression.PType);
 BEGIN
     SELF.args.add(e);
 END;
 
-PROCEDURE CallGeneratorImpl.end(): Code.PExpression;
+PROCEDURE CallGeneratorImpl.end(): Expression.PType;
     RETURN SELF.call.make(SELF.args, SELF.cx)
 END;
 
@@ -179,16 +183,16 @@ BEGIN
     RETURN result
 END;
 
-PROCEDURE GenArgCode.write(actual: Code.PExpression; expected: Types.PProcedureArgument; cast: LanguageContext.PCastOp);
+PROCEDURE GenArgCode.write(actual: Expression.PType; expected: Types.PProcedureArgument; cast: LanguageContext.PCastOp);
 VAR
-    e: Code.PExpression;
-    coercedArg: Code.PExpression;
+    e: Expression.PType;
+    coercedArg: Expression.PType;
 BEGIN
     IF (expected # NIL) & expected.isVar THEN
         referenceCode <- actual.designator().info()(Types.PVariable).referenceCode();
-        coercedArg := Code.makeSimpleExpression(referenceCode, actual.type());
+        coercedArg := Expression.makeSimple(referenceCode, actual.type());
     ELSE
-        coercedArg := Code.derefExpression(actual);
+        coercedArg := Expression.deref(actual);
     END;
     IF LEN(SELF.code) # 0 THEN
         SELF.code := SELF.code + ", ";
@@ -217,10 +221,10 @@ TYPE
         argumentsCode: PArgumentsCode
     END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     BEGIN
         processArguments(args, SELF.args, SELF.argumentsCode, cx.types);
-        RETURN Code.makeSimpleExpression(
+        RETURN Expression.makeSimple(
                 "(" + SELF.argumentsCode.result() + ")",
                 SELF.result
                 )
@@ -284,11 +288,11 @@ BEGIN
 END hasVarArgumnetWithCustomType;
 
 PROCEDURE checkSingleArgument*(
-    actual: ARRAY OF Code.PExpression; 
+    actual: ARRAY OF Expression.PType; 
     call: StdCall; 
     types: LanguageContext.PTypes; 
     code: PArgumentsCode
-    ): Code.PExpression;
+    ): Expression.PType;
 BEGIN
     ASSERT(LEN(call.args) = 1);
     processArguments(actual, call.args, code, types);
@@ -301,22 +305,22 @@ PROCEDURE makeNew(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        result: Code.PExpression;
+        result: Expression.PType;
     BEGIN
         arg <- checkSingleArgument(args, SELF, cx.types, NIL);
         argType <- arg.type();
-        IF ~(argType IS Types.PPointer) THEN
+        IF ~(argType IS Record.PPointer) THEN
             Errors.raise("POINTER variable expected, got '" 
                          + argType.description() + "'");
         ELSE
-            baseType <- Types.pointerBase(argType^);
-            IF baseType IS Types.PNonExportedRecord THEN
+            baseType <- Record.pointerBase(argType^);
+            IF baseType IS Record.PNonExported THEN
                 Errors.raise("non-exported RECORD type cannot be used in NEW");
             END;
-            right <- Code.makeSimpleExpression(baseType.codeForNew(cx^), argType);
-            result := Code.makeSimpleExpression(Operator.assign(arg, right, cx), NIL);
+            right <- Expression.makeSimple(baseType.codeForNew(cx^), argType);
+            result := Expression.makeSimple(Operator.assign(arg, right, cx), NIL);
         END;
         RETURN result;
     END;
@@ -330,9 +334,9 @@ PROCEDURE lenArgumentCheck*(argType: Types.PType): BOOLEAN;
     RETURN (argType IS Types.PArray) OR (argType IS Types.PString)
 END lenArgumentCheck;
 
-PROCEDURE CallLen.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+PROCEDURE CallLen.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
 VAR
-    arg: Code.PExpression;
+    arg: Expression.PType;
     argType: Types.PType;
 BEGIN
     arg := checkSingleArgument(args, SELF, cx.types, NIL);
@@ -341,7 +345,7 @@ BEGIN
         Errors.raise("ARRAY or string is expected as an argument of LEN, got '"
                      + argType.description() + "'");
     END;
-    RETURN Code.makeSimpleExpression(
+    RETURN Expression.makeSimple(
         arg.code() + ".length",
         Types.basic.integer)
 END CallLen.make;
@@ -359,9 +363,9 @@ PROCEDURE makeOdd(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
         code: STRING;
         constValue: ConstValue.PType;
     BEGIN
@@ -374,7 +378,7 @@ PROCEDURE makeOdd(): Symbols.PSymbol;
                 ORD(ODD(constValue^(ConstValue.Int).value)));
         END;
 
-        RETURN NEW Code.Expression(
+        RETURN NEW Expression.Type(
             code + " & 1",
             Types.basic.bool,
             NIL,
@@ -392,12 +396,12 @@ PROCEDURE makeAssert(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types, NIL);
-        RETURN Code.makeSimpleExpression(
+        RETURN Expression.makeSimple(
                 cx.rtl.assertId() + "(" + arg.code() + ")",
                 NIL)
     END CallImpl.make;
@@ -414,12 +418,12 @@ PROCEDURE setBitImpl(name: STRING; bitOp: BinaryOpStr): Symbols.PSymbol;
             bitOp: BinaryOpStr
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        x, y: Code.PExpression;
+        x, y: Expression.PType;
         yValue: INTEGER;
         value: ConstValue.PType;
-        valueCodeExp: Code.PExpression;
+        valueCodeExp: Expression.PType;
         valueCode: STRING;
         comment: STRING;
     BEGIN
@@ -430,7 +434,7 @@ PROCEDURE setBitImpl(name: STRING; bitOp: BinaryOpStr): Symbols.PSymbol;
         value := y.constValue();
         IF value = NIL THEN
             valueCodeExp := Operator.lsl(
-                Code.makeExpression(
+                Expression.make(
                     "1", 
                     Types.basic.integer,
                     NIL,
@@ -453,7 +457,7 @@ PROCEDURE setBitImpl(name: STRING; bitOp: BinaryOpStr): Symbols.PSymbol;
             valueCode := String.fromInt(yValue) + "/*" + comment + "*/";
         END;
 
-        RETURN Code.makeSimpleExpression(
+        RETURN Expression.makeSimple(
             SELF.bitOp(Code.adjustPrecedence(x, Precedence.assignment), valueCode),
             NIL)
     END CallImpl.make;
@@ -466,7 +470,7 @@ BEGIN
     RETURN makeSymbol(NEW Std(call.name, call))
 END setBitImpl;
 
-PROCEDURE checkVariableArgumentsCount(min, max: INTEGER; actual: ARRAY OF Code.PExpression);
+PROCEDURE checkVariableArgumentsCount(min, max: INTEGER; actual: ARRAY OF Expression.PType);
 BEGIN
     len <- LEN(actual);
     IF len < min THEN
@@ -487,9 +491,9 @@ PROCEDURE incImpl(name: STRING; unary: STRING; incOp: BinaryOpStr; incRefOp: Ope
             incRefOp: Operator.BinaryProc;
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        x, y: Code.PExpression;
+        x, y: Expression.PType;
         code: STRING;
         value: ConstValue.PType;
         valueCode: STRING;
@@ -499,7 +503,7 @@ PROCEDURE incImpl(name: STRING; unary: STRING; incOp: BinaryOpStr; incRefOp: Ope
         x := args[0];
         IF Cast.passedByReference(x) THEN
             IF LEN(args) = 1 THEN
-                y := Code.makeSimpleExpression("1", NIL);
+                y := Expression.makeSimple("1", NIL);
             ELSE
                 y := args[1];
             END;
@@ -520,7 +524,7 @@ PROCEDURE incImpl(name: STRING; unary: STRING; incOp: BinaryOpStr; incRefOp: Ope
             END;
             code := SELF.incOp(x.code(), valueCode);
         END;
-        RETURN Code.makeSimpleExpression(code, NIL)
+        RETURN Expression.makeSimple(code, NIL)
     END CallImpl.make;
 BEGIN
     call <- NEW CallImpl();
@@ -554,9 +558,9 @@ PROCEDURE makeAbs(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
         argType: Types.PType;
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types, NIL);
@@ -565,7 +569,7 @@ PROCEDURE makeAbs(): Symbols.PSymbol;
             Errors.raise("type mismatch: expected numeric type, got '"
                          + argType.description() + "'");
         END;
-        RETURN Code.makeSimpleExpression("Math.abs(" + arg.code() + ")", argType)
+        RETURN Expression.makeSimple("Math.abs(" + arg.code() + ")", argType)
     END CallImpl.make;
 BEGIN
     call <- NEW CallImpl();
@@ -578,13 +582,13 @@ PROCEDURE makeFloor(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types, NIL);
         code <- Code.adjustPrecedence(arg, Precedence.bitOr) + " | 0";
-        RETURN NEW Code.Expression(
+        RETURN NEW Expression.Type(
             code,
             Types.basic.integer,
             NIL,
@@ -603,9 +607,9 @@ PROCEDURE makeFlt(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
         value: ConstValue.PType;
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types, NIL);
@@ -613,7 +617,7 @@ PROCEDURE makeFlt(): Symbols.PSymbol;
         IF value # NIL THEN
             value := NEW ConstValue.Real(FLT(value^(ConstValue.Int).value));
         END;
-        RETURN NEW Code.Expression(
+        RETURN NEW Expression.Type(
                 arg.code(), 
                 Types.basic.real,
                 NIL,
@@ -633,7 +637,7 @@ PROCEDURE bitShiftImpl(name: STRING; op: Operator.BinaryProc): Symbols.PSymbol;
             op: Operator.BinaryProc
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     BEGIN
         checkArguments(args, SELF.args, cx.types);
         ASSERT(LEN(args) = 2);
@@ -653,14 +657,14 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
         argType: Types.PType;
         value: ConstValue.PType;
         code: STRING;
         ch: CHAR;
-        result: Code.PExpression;
+        result: Expression.PType;
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types, NIL);
         argType := arg.type();
@@ -669,11 +673,11 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
             IF (value # NIL) & (argType = Types.basic.set) THEN
                 value := NEW ConstValue.Int(ORD(value^(ConstValue.Set).value));
             END;
-            result := Code.makeExpression(arg.code(), Types.basic.integer, NIL, value);
+            result := Expression.make(arg.code(), Types.basic.integer, NIL, value);
         ELSIF argType = Types.basic.bool THEN
             code := Code.adjustPrecedence(arg, Precedence.conditional) 
                   + " ? 1 : 0";
-            result := NEW Code.Expression(
+            result := NEW Expression.Type(
                 code, 
                 Types.basic.integer, 
                 NIL, 
@@ -681,7 +685,7 @@ PROCEDURE makeOrd(): Symbols.PSymbol;
                 Precedence.conditional);
         ELSIF (argType IS Types.PString) 
             & (Types.stringAsChar(argType(Types.PString)^, ch)) THEN
-            result := Code.makeExpression(
+            result := Expression.make(
                 String.fromInt(ORD(ch)), 
                 Types.basic.integer,
                 NIL,
@@ -704,12 +708,12 @@ PROCEDURE makeChr(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        arg: Code.PExpression;
+        arg: Expression.PType;
     BEGIN
         arg := checkSingleArgument(args, SELF, cx.types, NIL);
-        RETURN Code.makeSimpleExpression(arg.code(), Types.basic.ch)
+        RETURN Expression.makeSimple(arg.code(), Types.basic.ch)
     END CallImpl.make;
 BEGIN
     call <- NEW CallImpl();
@@ -722,14 +726,14 @@ PROCEDURE makePack(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        x, y: Code.PExpression;
+        x, y: Expression.PType;
     BEGIN
         checkArguments(args, SELF.args, cx.types);
         x := args[0];
         y := args[1];
-        RETURN Code.makeSimpleExpression(
+        RETURN Expression.makeSimple(
             Operator.mulInplace(x, Operator.pow2(y), cx),
             NIL)
     END CallImpl.make;
@@ -745,14 +749,14 @@ PROCEDURE makeUnpk(): Symbols.PSymbol;
         CallImpl = RECORD(StdCall)
         END;
 
-    PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    PROCEDURE CallImpl.make(args: ARRAY OF Expression.PType; cx: LanguageContext.PType): Expression.PType;
     VAR
-        x, y: Code.PExpression;
+        x, y: Expression.PType;
     BEGIN
         checkArguments(args, SELF.args, cx.types);
         x := args[0];
         y := args[1];
-        RETURN Code.makeSimpleExpression(
+        RETURN Expression.makeSimple(
                 Operator.assign(y, Operator.log2(x), cx) 
                 + "; "
                 + Operator.divInplace(x, Operator.pow2(y), cx),

+ 342 - 0
src/ob/Record.ob

@@ -0,0 +1,342 @@
+MODULE Record;
+IMPORT
+    Chars, Context, Errors, OberonRtl, Object, ScopeBase, TypeId, Types;
+TYPE
+    FieldsMap = MAP OF Types.PField;
+
+    PType* = POINTER TO Type;
+    Type* = RECORD(Types.Record)
+        PROCEDURE Type*(name: STRING; cons: STRING; scope: ScopeBase.PType);
+
+        PROCEDURE setBase*(type: PType);
+        PROCEDURE addField*(f: Types.PField);
+        PROCEDURE findSymbol*(id: STRING): Types.PField;
+        PROCEDURE codeForNew*(cx: Context.Type): STRING;
+        PROCEDURE finalize*();
+
+        fields-: FieldsMap;
+        base-:   PType;
+        cons-:   STRING;
+        scope-:  ScopeBase.PType;
+        notExported: ARRAY * OF STRING
+    END;
+
+    NonExported* = RECORD(Type)
+        PROCEDURE NonExported(cons: STRING; scope: ScopeBase.PType; base: PType);
+    END;
+    PNonExported* = POINTER TO NonExported;
+
+    Field* = RECORD(Types.Field)
+        PROCEDURE Field*(identdef: Context.PIdentdefInfo; type: Types.PStorageType);
+
+        PROCEDURE identdef*(): Context.PIdentdefInfo;
+
+        mIdentdef: Context.PIdentdefInfo;
+        mType: Types.PStorageType;
+    END;
+    PField* = POINTER TO Field;
+
+    Pointer* = RECORD(Types.NamedType)
+        PROCEDURE Pointer*(name: STRING; base: TypeId.PType);
+
+        base: TypeId.PType;
+    END;
+
+    PPointer* = POINTER TO Pointer;
+
+    FieldVariable* = RECORD(Types.Variable)
+        PROCEDURE FieldVariable(f: PField; leadCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType);
+
+        field: PField;
+        leadCode: STRING;
+        readOnly: BOOLEAN;
+        rtl: OberonRtl.PType;
+    END;
+
+VAR
+    pGenerateTypeInfo: PROCEDURE(type: Types.PType): STRING;
+
+PROCEDURE finalizeRecord(closure: Object.PType);
+BEGIN
+    closure(PType).finalize();
+END;
+
+PROCEDURE Type.codeForNew(cx: Context.Type): STRING;
+    RETURN SELF.initializer(cx);
+END;
+
+PROCEDURE Type.finalize();
+BEGIN
+    FOR i <- 0 TO LEN(SELF.notExported) - 1 DO
+        SELF.fields.remove(SELF.notExported[i])
+    END;
+    SELF.notExported.clear();
+END Type.finalize;
+
+PROCEDURE Type.isScalar(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE recordOwnFields*(r: Type): FieldsMap;
+    RETURN r.fields;
+END;
+
+PROCEDURE Type.Type(name: STRING; cons: STRING; scope: ScopeBase.PType)
+    | SUPER(name),
+      cons(cons),
+      scope(scope);
+BEGIN
+    scope.addFinalizer(finalizeRecord, SELF(POINTER));
+END;
+
+PROCEDURE NonExported.NonExported(cons: STRING; scope: ScopeBase.PType; base: PType)
+    | SUPER("", cons, scope);
+BEGIN
+    SELF.base := base;
+END;    
+
+PROCEDURE Type.description(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF LEN(SELF.name) # 0 THEN
+        result := SELF.name;
+    ELSE
+        result := "anonymous RECORD";
+    END;
+    RETURN result
+END;
+
+PROCEDURE constructor*(cx: Context.Type; r: Type): STRING;
+    RETURN cx.qualifyScope(r.scope) + r.cons;
+END;
+
+PROCEDURE initializer*(cx: Context.Type; r: Type; args: STRING): STRING;
+    RETURN "new " + constructor(cx, r)  + "(" + args + ")";
+END;
+
+PROCEDURE Type.initializer(cx: Context.Type): STRING;
+    RETURN initializer(cx, SELF, "");
+END;
+
+PROCEDURE Type.addField(f: Types.PField);
+BEGIN
+    IF f.id() IN SELF.fields THEN
+        Errors.raise("duplicated field: '" + f.id() + "'");
+    END;
+    IF (SELF.base # NIL) & (SELF.base.findSymbol(f.id()) # NIL) THEN
+        Errors.raise("base record already has field: '" + f.id() + "'");
+    END;
+    SELF.fields[f.id()] := f;
+    IF ~f.exported() THEN
+        SELF.notExported.add(f.id());
+    END;
+END;
+
+PROCEDURE Type.findSymbol(id: STRING): Types.PField;
+VAR
+    result: Types.PField;
+BEGIN
+    IF id IN SELF.fields THEN
+        result := SELF.fields[id];
+    ELSIF SELF.base # NIL THEN
+        result := SELF.base.findSymbol(id);
+    END;
+    RETURN result;
+END;
+
+PROCEDURE existingField(r: Type; id: STRING; d: Types.NamedType): Types.PField;
+BEGIN
+    result <- r.findSymbol(id);
+    IF result = NIL THEN
+        Errors.raise("type '" + d.description() + "' has no '" + id + "' field");
+    END;
+    RETURN result
+END;
+
+PROCEDURE Type.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
+BEGIN
+    RETURN existingField(SELF, id, SELF)
+END;
+
+PROCEDURE Type.setBase(type: PType);
+BEGIN
+    SELF.base := type;
+END;
+
+PROCEDURE mangleJSProperty*(id: STRING): STRING;
+BEGIN
+    result <- id;
+    IF (id = "constructor") OR (id = "prototype") THEN
+        result := result + "$";
+    END;
+    RETURN result;
+END;
+
+PROCEDURE mangleField*(id: STRING): STRING;
+    RETURN mangleJSProperty(id);
+END;
+
+PROCEDURE dumpFields*(type: PType): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF type.base # NIL THEN
+        result := dumpFields(type.base);
+    END;
+    FOR k, v IN type.fields DO
+        IF LEN(result) # 0 THEN
+            result := result + ", ";
+        END;
+        result := result + mangleField(k) + ": " + pGenerateTypeInfo(v.type());
+    END;
+    RETURN result;
+END;
+
+PROCEDURE generateTypeInfo*(type: Types.PType): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF type IS PType THEN
+        result := "{record: {" + dumpFields(type) + "}}";
+    ELSIF type IS Types.PArray THEN
+        result := "{array: " + generateTypeInfo(type.elementsType) + "}";
+    ELSE
+        result := "null";
+    END;
+    RETURN result;
+END;
+
+PROCEDURE stripTypeId*(VAR id: TypeId.Type);
+BEGIN
+    r <- id.type();
+    IF r IS PType THEN
+        id.reset(NEW NonExported(r.cons, r.scope, r.base));
+    ELSE
+        id.reset(NIL);
+    END;
+END;
+
+PROCEDURE Field.id(): STRING;
+    RETURN SELF.mIdentdef.id();
+END;
+
+PROCEDURE Field.exported(): BOOLEAN;
+    RETURN SELF.mIdentdef.exported();
+END;
+
+PROCEDURE Field.identdef(): Context.PIdentdefInfo;
+    RETURN SELF.mIdentdef;
+END;
+
+PROCEDURE Field.designatorCode(leadCode: STRING; cx: Context.Type): Types.PFieldCode;
+BEGIN
+    codeId <- mangleField(SELF.mIdentdef.id());
+    RETURN NEW Types.FieldCode(
+        leadCode + "." + codeId, 
+        leadCode, 
+        Chars.doubleQuote + codeId + Chars.doubleQuote);
+END;
+
+PROCEDURE Field.type(): Types.PType;
+    RETURN SELF.mType;
+END;
+
+PROCEDURE Field.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): Types.PId;
+    RETURN NEW FieldVariable(SELF(POINTER), leadCode, isReadOnly, cx.rtl);
+END;
+
+PROCEDURE Field.Field(identdef: Context.PIdentdefInfo; type: Types.PStorageType)
+    | mIdentdef(identdef),
+      mType(type);
+END;
+
+PROCEDURE pointerBase*(p: Pointer): PType;
+    RETURN p.base.type()(PType);
+END;
+
+PROCEDURE Pointer.Pointer(name: STRING; base: TypeId.PType)
+    | SUPER(name),
+      base(base);
+END;
+
+PROCEDURE Pointer.description(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF LEN(SELF.name) # 0 THEN
+        result := SELF.name;
+    ELSE
+        result := "POINTER TO " + pointerBase(SELF).description();
+    END;
+    RETURN result
+END;
+
+PROCEDURE Pointer.initializer(cx: Context.Type): STRING;
+    RETURN "null"
+END Pointer.initializer;
+
+PROCEDURE Pointer.denote(id: STRING; isReadObly: BOOLEAN): Types.PField;
+VAR
+    d: POINTER TO Types.NamedType;
+BEGIN
+    base <- pointerBase(SELF);
+    IF (LEN(SELF.name) = 0) OR (LEN(base.name) # 0) THEN
+        d := base;
+    ELSE
+        d := SELF(POINTER);
+    END;
+    RETURN existingField(base^, id, d^)
+END;
+
+PROCEDURE Pointer.isScalar(): BOOLEAN;
+    RETURN TRUE;
+END;
+
+PROCEDURE FieldVariable.FieldVariable(f: PField; leadCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType)
+    | field(f),
+      leadCode(leadCode),
+      readOnly(isReadOnly),
+      rtl(rtl);
+END;
+
+PROCEDURE FieldVariable.idType(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    result := "record's field";
+    IF SELF.readOnly THEN
+        result := "read-only " + result; 
+    END;
+    RETURN result;
+END;
+
+PROCEDURE FieldVariable.type(): Types.PStorageType;
+    RETURN SELF.field.mType;
+END;
+
+PROCEDURE FieldVariable.referenceCode(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    codeId <- mangleField(SELF.field.mIdentdef.id());
+    IF SELF.type().isScalar() THEN
+        result := SELF.rtl.makeRef(SELF.leadCode, 
+                                   Chars.doubleQuote + codeId + Chars.doubleQuote);
+    ELSE
+        result := SELF.leadCode + "." + codeId;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE FieldVariable.isReference(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE FieldVariable.isReadOnly(): BOOLEAN;
+    RETURN SELF.readOnly;
+END;
+
+BEGIN
+    pGenerateTypeInfo := generateTypeInfo;
+END Record.

+ 8 - 5
src/ob/Scope.ob

@@ -3,10 +3,13 @@ IMPORT
     Errors, 
     Object, 
     Procedures := Procedure, 
+    Record,
     ScopeBase,
     String,
     Symbols, 
-    Types;
+    TypeId,
+    Types,
+    Variable;
 TYPE
     Unresolved = ARRAY * OF STRING;
 
@@ -53,7 +56,7 @@ TYPE
 
 PROCEDURE addSymbolForType*(t: Types.PBasicType; VAR result: Symbols.Map);
 BEGIN
-    result[t.name] := NEW Symbols.Symbol(t.name, NEW Types.TypeId(t));
+    result[t.name] := NEW Symbols.Symbol(t.name, NEW TypeId.Type(t));
 END;
 
 PROCEDURE makeStdSymbols*(): Symbols.Map;
@@ -108,8 +111,8 @@ BEGIN
     i := s.unresolved.indexOf(id);
     IF i # -1 THEN
         info := symbol.info();
-        type := info(Types.PTypeId).type();
-        IF (type # NIL) & ~(type IS Types.PRecord) THEN
+        type := info(TypeId.PType).type();
+        IF (type # NIL) & ~(type IS Record.PType) THEN
             Errors.raise(
                 "'" 
                 + id
@@ -213,7 +216,7 @@ BEGIN
         symbol <- k;
         info <- symbol.info();
         IF info IS Types.PVariable THEN
-            symbol := NEW Symbols.Symbol(id, Types.makeExportedVariable(info^));
+            symbol := NEW Symbols.Symbol(id, Variable.makeExportedVariable(info^));
         END;
         m.exports[id] := symbol;
     END;

+ 3 - 3
src/ob/Symbols.ob

@@ -1,5 +1,5 @@
 MODULE Symbols;
-IMPORT Object, ScopeBase, Types;
+IMPORT Object, ScopeBase, Types, TypeId;
 TYPE
     Symbol* = RECORD(Object.Type)
         PROCEDURE Symbol*(id: STRING; info: Types.PId);
@@ -52,8 +52,8 @@ PROCEDURE Symbol.isConst(): BOOLEAN;
 END Symbol.isConst;
 
 PROCEDURE Symbol.isType(): BOOLEAN;
-    RETURN SELF.mInfo IS Types.PTypeId
-END Symbol.isType;
+    RETURN SELF.mInfo IS TypeId.PType;
+END;
 
 PROCEDURE Symbol.isProcedure(): BOOLEAN;
     RETURN SELF.mInfo IS Types.PProcedureId

+ 75 - 0
src/ob/TypeId.ob

@@ -0,0 +1,75 @@
+MODULE TypeId;
+IMPORT
+    Types;
+TYPE
+    PType* = POINTER TO Type;
+    Type* = RECORD(Types.Id)
+        PROCEDURE Type*(type: Types.PType);
+
+        PROCEDURE type*(): Types.PType;
+        PROCEDURE reset*(type: Types.PType);
+        PROCEDURE description(): STRING;
+
+        mType: Types.PType
+    END;
+
+    ResolveTypeCallback = PROCEDURE(): Types.PType;
+
+    Forward* = RECORD(Type)
+        PROCEDURE Forward(resolve: ResolveTypeCallback);
+
+        resolve: ResolveTypeCallback
+    END;
+
+    PForward = POINTER TO Forward;
+
+    Lazy* = RECORD(Type)
+        PROCEDURE Lazy*();
+    END;
+
+    PLazy = POINTER TO Lazy;
+
+PROCEDURE Type.description(): STRING;
+    RETURN "type " + SELF.type().description()
+END;
+
+PROCEDURE Type.type(): Types.PType;
+    RETURN SELF.mType
+END;
+
+PROCEDURE Type.reset(type: Types.PType);
+BEGIN
+    SELF.mType := type;
+END;
+
+PROCEDURE Forward.Forward(resolve: ResolveTypeCallback)
+    | SUPER(NIL),
+      resolve(resolve);
+END;
+
+PROCEDURE Forward.type(): Types.PType;
+BEGIN
+    IF SELF.mType = NIL THEN
+        SELF.mType := SELF.resolve();
+    END;
+    RETURN SELF.mType
+END;
+
+PROCEDURE define*(VAR tId: Lazy; t: Types.PType);
+BEGIN
+    tId.mType := t;
+END;
+
+PROCEDURE Type.idType(): STRING;
+    RETURN "type"
+END Type.idType;
+
+PROCEDURE Type.Type(type: Types.PType)
+    | mType(type);
+END;
+
+PROCEDURE Lazy.Lazy()
+    | SUPER(NIL);
+END;
+
+END TypeId.

+ 6 - 605
src/ob/Types.ob

@@ -1,6 +1,6 @@
 MODULE Types;
 IMPORT
-    Chars, ConstValue, Context, Errors, OberonRtl, Object, ScopeBase, Str := String;
+    Chars, ConstValue, Context, Errors, OberonRtl, Object, Str := String;
 TYPE
     Id* = RECORD(Object.Type)
         PROCEDURE idType*(): STRING
@@ -13,33 +13,6 @@ TYPE
     END;
     PType* = POINTER TO Type;
 
-    TypeId* = RECORD(Id)
-        PROCEDURE TypeId*(type: PType);
-
-        PROCEDURE type*(): PType;
-        PROCEDURE description(): STRING;
-        PROCEDURE strip();
-
-        mType: PType
-    END;
-    PTypeId* = POINTER TO TypeId;
-
-    ResolveTypeCallback = PROCEDURE(): PType;
-
-    ForwardTypeId* = RECORD(TypeId)
-        PROCEDURE ForwardTypeId(resolve: ResolveTypeCallback);
-
-        resolve: ResolveTypeCallback
-    END;
-
-    PForwardTypeId = POINTER TO ForwardTypeId;
-
-    LazyTypeId* = RECORD(TypeId)
-        PROCEDURE LazyTypeId*();
-    END;
-
-    PLazyTypeId = POINTER TO LazyTypeId;
-
     Const* = RECORD(Id)
         PROCEDURE Const*(type: PType; value: ConstValue.PType);
 
@@ -60,54 +33,6 @@ TYPE
 
     PVariable* = POINTER TO Variable;
 
-    TypedVariable = RECORD(Variable)
-        PROCEDURE TypedVariable(type: PStorageType);
-
-        mType: PStorageType;
-    END;
-
-    DeclaredVariable* = RECORD(TypedVariable)
-        PROCEDURE DeclaredVariable(id: STRING; type: PStorageType);
-
-        id: STRING;
-    END;
-
-    ArgumentVariable* = RECORD(DeclaredVariable)
-        PROCEDURE ArgumentVariable(id: STRING; type: PStorageType; var: BOOLEAN);
-
-        var: BOOLEAN;
-    END;
-
-    PRecordField* = POINTER TO RecordField;
-
-    FieldVariable* = RECORD(Variable)
-        PROCEDURE FieldVariable(f: PRecordField; leadCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType);
-
-        field: PRecordField;
-        leadCode: STRING;
-        readOnly: BOOLEAN;
-        rtl: OberonRtl.PType;
-    END;
-
-    PropertyVariable* = RECORD(TypedVariable)
-        PROCEDURE PropertyVariable(type: PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType);
-
-        leadCode, propCode: STRING;
-        readOnly: BOOLEAN;
-        rtl: OberonRtl.PType;
-    END;
-
-    DerefVariable* = RECORD(TypedVariable)
-        PROCEDURE DerefVariable(type: PStorageType; code: STRING);
-
-        code: STRING;
-    END;
-
-    ExportedVariable = RECORD(TypedVariable)
-    END;
-
-    PExportedVariable = POINTER TO ExportedVariable;
-
     ProcedureId* = RECORD(Id)
         PROCEDURE ProcedureId*(type: PType);
 
@@ -140,15 +65,6 @@ TYPE
     END;
     PField* = POINTER TO Field;
 
-    RecordField* = RECORD(Field)
-        PROCEDURE RecordField*(identdef: Context.PIdentdefInfo; type: PStorageType);
-
-        PROCEDURE identdef*(): Context.PIdentdefInfo;
-
-        mIdentdef: Context.PIdentdefInfo;
-        mType: PStorageType;
-    END;
-
     StorageType* = RECORD(Type)    
         PROCEDURE initializer*(cx: Context.Type): STRING;
         PROCEDURE denote*(id: STRING; isReadObly: BOOLEAN): PField;
@@ -156,11 +72,15 @@ TYPE
     END;
 
     NamedType* = RECORD(StorageType)
-        PROCEDURE NamedType(name: STRING);
+        PROCEDURE NamedType*(name: STRING);
 
         name*: STRING
     END;
 
+    Record* = RECORD(NamedType)
+    END;
+    PRecord* = POINTER TO Record;
+
     Array* = RECORD(NamedType)
         PROCEDURE Array*(elementsType: PStorageType);
 
@@ -182,16 +102,6 @@ TYPE
     END;
     PStaticArray* = POINTER TO StaticArray;
 
-    PRecord* = POINTER TO Record;
-
-    Pointer* = RECORD(NamedType)
-        PROCEDURE Pointer*(name: STRING; base: PTypeId);
-
-        base: PTypeId
-    END;
-
-    PPointer* = POINTER TO Pointer;
-
     Procedure* = RECORD(NamedType)
         PROCEDURE designatorCode*(id: STRING): STRING
     END;
@@ -223,29 +133,6 @@ TYPE
 
     PBasicType* = POINTER TO BasicType;
 
-    FieldsMap = MAP OF PField;
-
-    Record* = RECORD(NamedType)
-        PROCEDURE Record*(name: STRING; cons: STRING; scope: ScopeBase.PType);
-
-        PROCEDURE setBase*(type: PRecord);
-        PROCEDURE addField*(f: PField);
-        PROCEDURE findSymbol*(id: STRING): PField;
-        PROCEDURE codeForNew*(cx: Context.Type): STRING;
-        PROCEDURE finalize*();
-
-        fields-: FieldsMap;
-        base-:   PRecord;
-        cons-:   STRING;
-        scope-:  ScopeBase.PType;
-        notExported: ARRAY * OF STRING
-    END;
-    
-    NonExportedRecord* = RECORD(Record)
-        PROCEDURE NonExportedRecord(cons: STRING; scope: ScopeBase.PType; base: PRecord);
-    END;
-    PNonExportedRecord* = POINTER TO NonExportedRecord;
-
     Nil = RECORD(Type)
     END;
 
@@ -267,89 +154,6 @@ VAR
     numeric*: ARRAY * OF PType;
     nil*: POINTER TO Nil;
 
-    pGenerateTypeInfo: PROCEDURE(type: PType): STRING;
-
-PROCEDURE TypeId.description(): STRING;
-VAR
-    t: PType;
-BEGIN
-    t := SELF.type();
-    RETURN "type " + t.description()
-END TypeId.description;
-
-PROCEDURE TypeId.type(): PType;
-    RETURN SELF.mType
-END TypeId.type;
-
-PROCEDURE finalizeRecord(closure: Object.PType);
-BEGIN
-    closure(PRecord).finalize();
-END finalizeRecord;
-
-PROCEDURE Record.codeForNew(cx: Context.Type): STRING;
-    RETURN SELF.initializer(cx);
-END;
-
-PROCEDURE Record.finalize();
-BEGIN
-    FOR i <- 0 TO LEN(SELF.notExported) - 1 DO
-        SELF.fields.remove(SELF.notExported[i])
-    END;
-    SELF.notExported.clear();
-END Record.finalize;
-
-PROCEDURE Record.isScalar(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE recordOwnFields*(r: Record): FieldsMap;
-    RETURN r.fields;
-END;
-
-PROCEDURE Record.Record(name: STRING; cons: STRING; scope: ScopeBase.PType)
-    | SUPER(name),
-      cons(cons),
-      scope(scope);
-BEGIN
-    scope.addFinalizer(finalizeRecord, SELF(POINTER));
-END;
-
-PROCEDURE NonExportedRecord.NonExportedRecord(cons: STRING; scope: ScopeBase.PType; base: PRecord)
-    | SUPER("", cons, scope);
-BEGIN
-    SELF.base := base;
-END;    
-
-PROCEDURE TypeId.strip();
-VAR
-    r: PRecord;
-BEGIN
-    IF SELF.mType IS PRecord THEN
-        r := SELF.mType(PRecord);
-        SELF.mType := NEW NonExportedRecord(r.cons, r.scope, r.base);
-    ELSE
-        SELF.mType := NIL;
-    END;
-END TypeId.strip;
-
-PROCEDURE ForwardTypeId.ForwardTypeId(resolve: ResolveTypeCallback)
-    | SUPER(NIL),
-      resolve(resolve);
-END;
-
-PROCEDURE ForwardTypeId.type(): PType;
-BEGIN
-    IF SELF.mType = NIL THEN
-        SELF.mType := SELF.resolve();
-    END;
-    RETURN SELF.mType
-END ForwardTypeId.type;
-
-PROCEDURE defineTypeId*(VAR tId: LazyTypeId; t: PType);
-BEGIN
-    tId.mType := t;
-END defineTypeId;
-
 PROCEDURE typeName*(type: NamedType): STRING;
     RETURN type.name
 END typeName;
@@ -401,177 +205,10 @@ PROCEDURE Variable.idType(): STRING;
     RETURN "variable"
 END Variable.idType;
 
-PROCEDURE TypedVariable.type(): PStorageType;
-    RETURN SELF.mType
-END;
-
-PROCEDURE DeclaredVariable.referenceCode(): STRING;
-BEGIN
-    result <- SELF.id;
-    IF SELF.mType.isScalar() THEN
-        result := "{set: function($v){" + result + " = $v;}, get: function(){return " + result + ";}}";
-    END;
-    RETURN result;
-END;
-
-PROCEDURE DeclaredVariable.isReference(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE DeclaredVariable.isReadOnly(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE ArgumentVariable.idType(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    result := "formal parameter";
-    IF ~SELF.var THEN
-        result := "non-VAR " + result;
-    END;
-    RETURN result;
-END;
-
-PROCEDURE ArgumentVariable.isReference(): BOOLEAN;
-    RETURN SELF.var;
-END;
-
-PROCEDURE ArgumentVariable.isReadOnly(): BOOLEAN;
-    RETURN ~SELF.var 
-        & ((SELF.mType IS PArray) OR (SELF.mType IS PRecord));
-END;
-
-PROCEDURE ArgumentVariable.referenceCode(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF SELF.var THEN
-        result := SELF.id;
-    ELSE
-        result := SUPER();
-    END;
-    RETURN result;
-END;
-
-PROCEDURE mangleJSProperty*(id: STRING): STRING;
-BEGIN
-    result <- id;
-    IF (id = "constructor") OR (id = "prototype") THEN
-        result := result + "$";
-    END;
-    RETURN result;
-END;
-
-PROCEDURE mangleField*(id: STRING): STRING;
-    RETURN mangleJSProperty(id);
-END;
-
-PROCEDURE FieldVariable.idType(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    result := "record's field";
-    IF SELF.readOnly THEN
-        result := "read-only " + result; 
-    END;
-    RETURN result;
-END;
-
-PROCEDURE FieldVariable.type(): PStorageType;
-    RETURN SELF.field.mType;
-END;
-
-PROCEDURE FieldVariable.referenceCode(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    codeId <- mangleField(SELF.field.mIdentdef.id());
-    IF SELF.type().isScalar() THEN
-        result := SELF.rtl.makeRef(SELF.leadCode, 
-                                   Chars.doubleQuote + codeId + Chars.doubleQuote);
-    ELSE
-        result := SELF.leadCode + "." + codeId;
-    END;
-    RETURN result;
-END;
-
-PROCEDURE FieldVariable.isReference(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE FieldVariable.isReadOnly(): BOOLEAN;
-    RETURN SELF.readOnly;
-END;
-
-PROCEDURE PropertyVariable.idType(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    result := "array's element";
-    IF SELF.readOnly THEN
-        result := "read-only " + result; 
-    END;
-    RETURN result;
-END;
-
-PROCEDURE PropertyVariable.referenceCode(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF SELF.type().isScalar() THEN
-        result := SELF.rtl.makeRef(SELF.leadCode, SELF.propCode);
-    ELSE
-        result := SELF.leadCode + "[" + SELF.propCode + "]";
-    END;
-    RETURN result;
-END;
-
-PROCEDURE PropertyVariable.isReference(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE PropertyVariable.isReadOnly(): BOOLEAN;
-    RETURN SELF.readOnly;
-END;
-
-PROCEDURE DerefVariable.referenceCode(): STRING;
-    RETURN SELF.code;
-END;
-
-PROCEDURE DerefVariable.isReference(): BOOLEAN;
-    RETURN TRUE;
-END;
-
-PROCEDURE DerefVariable.isReadOnly(): BOOLEAN;
-    RETURN FALSE;
-END;
-
 PROCEDURE procedureType*(p: ProcedureId): PType;
     RETURN p.type
 END procedureType;
 
-PROCEDURE ExportedVariable.idType(): STRING;
-    RETURN "imported variable"
-END ExportedVariable.idType;
-
-PROCEDURE ExportedVariable.isReference(): BOOLEAN;
-    RETURN FALSE;
-END;
-
-PROCEDURE ExportedVariable.isReadOnly(): BOOLEAN;
-    RETURN TRUE;
-END;
-
-PROCEDURE ExportedVariable.referenceCode(): STRING;
-BEGIN
-    RETURN "";
-END;
-
-PROCEDURE TypeId.idType(): STRING;
-    RETURN "type"
-END TypeId.idType;
-
 PROCEDURE BasicType.description(): STRING;
     RETURN SELF.name
 END BasicType.description;
@@ -610,126 +247,6 @@ PROCEDURE BasicType.BasicType(name: STRING; initializer: STRING)
       mInitializer(initializer);
 END;
 
-PROCEDURE Record.description(): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF LEN(SELF.name) # 0 THEN
-        result := SELF.name;
-    ELSE
-        result := "anonymous RECORD";
-    END;
-    RETURN result
-END Record.description;
-
-PROCEDURE recordConstructor*(cx: Context.Type; r: Record): STRING;
-    RETURN cx.qualifyScope(r.scope) + r.cons;
-END;
-
-PROCEDURE recordInitializer*(cx: Context.Type; r: Record; args: STRING): STRING;
-    RETURN "new " + recordConstructor(cx, r)  + "(" + args + ")";
-END;
-
-PROCEDURE Record.initializer(cx: Context.Type): STRING;
-    RETURN recordInitializer(cx, SELF, "");
-END;
-
-PROCEDURE Record.addField(f: PField);
-BEGIN
-    IF f.id() IN SELF.fields THEN
-        Errors.raise("duplicated field: '" + f.id() + "'");
-    END;
-    IF (SELF.base # NIL) & (SELF.base.findSymbol(f.id()) # NIL) THEN
-        Errors.raise("base record already has field: '" + f.id() + "'");
-    END;
-    SELF.fields[f.id()] := f;
-    IF ~f.exported() THEN
-        SELF.notExported.add(f.id());
-    END;
-END Record.addField;
-
-PROCEDURE Record.findSymbol(id: STRING): PField;
-VAR
-    result: PField;
-BEGIN
-    IF id IN SELF.fields THEN
-        result := SELF.fields[id];
-    ELSIF SELF.base # NIL THEN
-        result := SELF.base.findSymbol(id);
-    END;
-    RETURN result;
-END;
-
-PROCEDURE existingField(r: Record; id: STRING; d: NamedType): PField;
-BEGIN
-    result <- r.findSymbol(id);
-    IF result = NIL THEN
-        Errors.raise("type '" + d.description() + "' has no '" + id + "' field");
-    END;
-    RETURN result
-END existingField;
-
-PROCEDURE Record.denote(id: STRING; isReadObly: BOOLEAN): PField;
-BEGIN
-    RETURN existingField(SELF, id, SELF)
-END;
-
-PROCEDURE recordBase*(r: Record): PRecord;
-    RETURN r.base
-END recordBase;
-
-PROCEDURE Record.setBase(type: PRecord);
-BEGIN
-    SELF.base := type;
-END;
-
-PROCEDURE recordScope*(r: Record): ScopeBase.PType;
-    RETURN r.scope
-END recordScope;
-
-PROCEDURE pointerBase*(p: Pointer): PRecord;
-VAR
-    result: PType;
-BEGIN
-    result := p.base.type();
-    RETURN result(PRecord)
-END pointerBase;
-
-PROCEDURE Pointer.description(): STRING;
-VAR
-    base: PRecord;
-    result: STRING;
-BEGIN
-    IF LEN(SELF.name) # 0 THEN
-        result := SELF.name;
-    ELSE
-        base := pointerBase(SELF);
-        result := "POINTER TO " + base.description();
-    END;
-    RETURN result
-END Pointer.description;
-
-PROCEDURE Pointer.initializer(cx: Context.Type): STRING;
-    RETURN "null"
-END Pointer.initializer;
-
-PROCEDURE Pointer.denote(id: STRING; isReadObly: BOOLEAN): PField;
-VAR
-    d: POINTER TO NamedType;
-BEGIN
-    base <- pointerBase(SELF);
-    IF (LEN(SELF.name) = 0) OR (LEN(base.name) # 0) THEN
-        d := base;
-    ELSE
-        d := SELF(POINTER);
-    END;
-    RETURN existingField(base^, id, d^)
-END;
-
-PROCEDURE Pointer.isScalar(): BOOLEAN;
-    RETURN TRUE;
-END;
-
 PROCEDURE foldArrayDimensions(VAR a: Array; dimToStr: ArrayDimensionDescriptionCallback; VAR sizes, of: STRING);
 BEGIN  
     elementsType <- a.elementsType;
@@ -835,14 +352,6 @@ PROCEDURE Module.idType(): STRING;
     RETURN "MODULE"
 END Module.idType;
 
-PROCEDURE TypeId.TypeId(type: PType)
-    | mType(type);
-END;
-
-PROCEDURE LazyTypeId.LazyTypeId()
-    | SUPER(NIL);
-END;
-
 PROCEDURE String.String(s: STRING)
     | s(s);
 END;
@@ -866,54 +375,11 @@ PROCEDURE StaticArray.StaticArray(
     len(len);
 END;
 
-PROCEDURE Pointer.Pointer(name: STRING; base: PTypeId)
-    | SUPER(name),
-      base(base);
-END;
-
 PROCEDURE Const.Const(type: PType; value: ConstValue.PType)
     | type(type),
       value(value);
 END;
 
-PROCEDURE TypedVariable.TypedVariable(type: PStorageType)
-    | mType(type);
-END;
-
-PROCEDURE DeclaredVariable.DeclaredVariable(id: STRING; type: PStorageType)
-    | SUPER(type),
-      id(id);
-END;
-
-PROCEDURE ArgumentVariable.ArgumentVariable(id: STRING; type: PStorageType; var: BOOLEAN)
-    | SUPER(id, type),
-      var(var);
-END;
-
-PROCEDURE FieldVariable.FieldVariable(f: PRecordField; leadCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType)
-    | field(f),
-      leadCode(leadCode),
-      readOnly(isReadOnly),
-      rtl(rtl);
-END;
-
-PROCEDURE PropertyVariable.PropertyVariable(type: PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType)
-    | SUPER(type),
-      leadCode(leadCode),
-      propCode(propCode),
-      readOnly(isReadOnly),
-      rtl(rtl);
-END;
-
-PROCEDURE DerefVariable.DerefVariable(type: PStorageType; code: STRING)
-    | SUPER(type),
-      code(code);
-      END;
-
-PROCEDURE makeExportedVariable*(v: Variable): PVariable;
-    RETURN NEW ExportedVariable(v.type());
-END;
-
 PROCEDURE ProcedureId.ProcedureId(type: PType)
     | type(type);
 END;
@@ -926,69 +392,6 @@ PROCEDURE FieldCode.FieldCode(code, derefCode, propCode: STRING)
     | code(code), derefCode(derefCode), propCode(propCode);
 END;
 
-PROCEDURE RecordField.id(): STRING;
-    RETURN SELF.mIdentdef.id();
-END;
-
-PROCEDURE RecordField.exported(): BOOLEAN;
-    RETURN SELF.mIdentdef.exported();
-END;
-
-PROCEDURE RecordField.identdef(): Context.PIdentdefInfo;
-    RETURN SELF.mIdentdef;
-END;
-
-PROCEDURE RecordField.designatorCode(leadCode: STRING; cx: Context.Type): PFieldCode;
-BEGIN
-    codeId <- mangleField(SELF.mIdentdef.id());
-    RETURN NEW FieldCode(leadCode + "." + codeId, 
-                         leadCode, 
-                         Chars.doubleQuote + codeId + Chars.doubleQuote);
-END;
-
-PROCEDURE RecordField.type(): PType;
-    RETURN SELF.mType;
-END;
-
-PROCEDURE RecordField.asVar(leadCode: STRING; isReadOnly: BOOLEAN; cx: Context.Type): PId;
-    RETURN NEW FieldVariable(SELF(POINTER), leadCode, isReadOnly, cx.rtl);
-END;
-
-PROCEDURE RecordField.RecordField(identdef: Context.PIdentdefInfo; type: PStorageType)
-    | mIdentdef(identdef),
-      mType(type);
-END;
-
-PROCEDURE dumpRecordFields*(type: PRecord): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF type.base # NIL THEN
-        result := dumpRecordFields(type.base);
-    END;
-    FOR k, v IN type.fields DO
-        IF LEN(result) # 0 THEN
-            result := result + ", ";
-        END;
-        result := result + mangleField(k) + ": " + pGenerateTypeInfo(v.type());
-    END;
-    RETURN result;
-END;
-
-PROCEDURE generateTypeInfo*(type: PType): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF type IS PRecord THEN
-        result := "{record: {" + dumpRecordFields(type) + "}}";
-    ELSIF type IS PArray THEN
-        result := "{array: " + generateTypeInfo(type.elementsType) + "}";
-    ELSE
-        result := "null";
-    END;
-    RETURN result;
-END;
-
 BEGIN
     basic.bool := NEW BasicType("BOOLEAN", "false");
     basic.ch := NEW BasicType("CHAR", "0");
@@ -1002,6 +405,4 @@ BEGIN
     numeric.add(basic.real);
 
     NEW(nil);
-
-    pGenerateTypeInfo := generateTypeInfo;
 END Types.

+ 191 - 0
src/ob/Variable.ob

@@ -0,0 +1,191 @@
+MODULE Variable;
+IMPORT
+    OberonRtl, Types;
+TYPE
+    TypedVariable = RECORD(Types.Variable)
+        PROCEDURE TypedVariable(type: Types.PStorageType);
+
+        mType: Types.PStorageType;
+    END;
+
+    DeclaredVariable* = RECORD(TypedVariable)
+        PROCEDURE DeclaredVariable*(id: STRING; type: Types.PStorageType);
+
+        id-: STRING;
+    END;
+
+    ArgumentVariable* = RECORD(DeclaredVariable)
+        PROCEDURE ArgumentVariable(id: STRING; type: Types.PStorageType; var: BOOLEAN);
+
+        var: BOOLEAN;
+    END;
+
+    PropertyVariable* = RECORD(TypedVariable)
+        PROCEDURE PropertyVariable(type: Types.PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType);
+
+        leadCode, propCode: STRING;
+        readOnly: BOOLEAN;
+        rtl: OberonRtl.PType;
+    END;
+
+    DerefVariable* = RECORD(TypedVariable)
+        PROCEDURE DerefVariable(type: Types.PStorageType; code: STRING);
+
+        code: STRING;
+    END;
+
+    ExportedVariable = RECORD(TypedVariable)
+    END;
+
+    PExportedVariable = POINTER TO ExportedVariable;
+
+PROCEDURE TypedVariable.type(): Types.PStorageType;
+    RETURN SELF.mType
+END;
+
+PROCEDURE DeclaredVariable.referenceCode(): STRING;
+BEGIN
+    result <- SELF.id;
+    IF SELF.mType.isScalar() THEN
+        result := "{set: function($v){" + result + " = $v;}, get: function(){return " + result + ";}}";
+    END;
+    RETURN result;
+END;
+
+PROCEDURE DeclaredVariable.isReference(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE DeclaredVariable.isReadOnly(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE PropertyVariable.idType(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    result := "array's element";
+    IF SELF.readOnly THEN
+        result := "read-only " + result; 
+    END;
+    RETURN result;
+END;
+
+PROCEDURE PropertyVariable.referenceCode(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF SELF.type().isScalar() THEN
+        result := SELF.rtl.makeRef(SELF.leadCode, SELF.propCode);
+    ELSE
+        result := SELF.leadCode + "[" + SELF.propCode + "]";
+    END;
+    RETURN result;
+END;
+
+PROCEDURE PropertyVariable.isReference(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE PropertyVariable.isReadOnly(): BOOLEAN;
+    RETURN SELF.readOnly;
+END;
+
+PROCEDURE DerefVariable.referenceCode(): STRING;
+    RETURN SELF.code;
+END;
+
+PROCEDURE DerefVariable.isReference(): BOOLEAN;
+    RETURN TRUE;
+END;
+
+PROCEDURE DerefVariable.isReadOnly(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE ExportedVariable.idType(): STRING;
+    RETURN "imported variable"
+END ExportedVariable.idType;
+
+PROCEDURE ExportedVariable.isReference(): BOOLEAN;
+    RETURN FALSE;
+END;
+
+PROCEDURE ExportedVariable.isReadOnly(): BOOLEAN;
+    RETURN TRUE;
+END;
+
+PROCEDURE ExportedVariable.referenceCode(): STRING;
+BEGIN
+    RETURN "";
+END;
+
+PROCEDURE TypedVariable.TypedVariable(type: Types.PStorageType)
+    | mType(type);
+END;
+
+PROCEDURE DeclaredVariable.DeclaredVariable(id: STRING; type: Types.PStorageType)
+    | SUPER(type),
+      id(id);
+END;
+
+PROCEDURE PropertyVariable.PropertyVariable(type: Types.PStorageType; leadCode, propCode: STRING; isReadOnly: BOOLEAN; rtl: OberonRtl.PType)
+    | SUPER(type),
+      leadCode(leadCode),
+      propCode(propCode),
+      readOnly(isReadOnly),
+      rtl(rtl);
+END;
+
+PROCEDURE DerefVariable.DerefVariable(type: Types.PStorageType; code: STRING)
+    | SUPER(type),
+      code(code);
+      END;
+
+PROCEDURE ArgumentVariable.ArgumentVariable(id: STRING; type: Types.PStorageType; var: BOOLEAN)
+    | SUPER(id, type),
+      var(var);
+END;
+
+PROCEDURE ArgumentVariable.idType(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    result := "formal parameter";
+    IF ~SELF.var THEN
+        result := "non-VAR " + result;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE ArgumentVariable.isReference(): BOOLEAN;
+    RETURN SELF.var;
+END;
+
+PROCEDURE ArgumentVariable.isReadOnly(): BOOLEAN;
+BEGIN
+    r <- FALSE;
+    IF ~SELF.var THEN
+        t <- SELF.type(); 
+        r := (t IS Types.PArray) OR (t IS Types.PRecord);
+    END;
+    RETURN r;
+END;
+
+PROCEDURE ArgumentVariable.referenceCode(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF SELF.var THEN
+        result := SELF.id;
+    ELSE
+        result := SUPER();
+    END;
+    RETURN result;
+END;
+
+PROCEDURE makeExportedVariable*(v: Types.Variable): Types.PVariable;
+    RETURN NEW ExportedVariable(v.type());
+END;
+
+END Variable.

+ 5 - 4
src/oberon/oberon_context.js

@@ -1,15 +1,16 @@
 "use strict";
 
-var Code = require("js/Code.js");
 var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
+var Expression = require("js/Expression.js");
 var op = require("js/Operator.js");
+var Record = require("js/Record.js");
 var Type = require("js/Types.js");
 
 var RecordDecl = Context.RecordDecl.extend({
     init: function OberonContext$RecordDecl(context){
-        Context.RecordDecl.prototype.init.call(this, context, Type.Record);
+        Context.RecordDecl.prototype.init.call(this, context, Record.Type);
     }
 });
 
@@ -56,7 +57,7 @@ var ProcedureCall = Context.Chained.extend({
     callExpression: function(){
         if (!this.__callExpression){
             var e = this.procCall().end();
-            this.__callExpression = new Code.Expression(this.__id + e.code(), e.type(), undefined, e.constValue(), e.maxPrecedence());
+            this.__callExpression = new Expression.Type(this.__id + e.code(), e.type(), undefined, e.constValue(), e.maxPrecedence());
         }
         return this.__callExpression;
     }
@@ -101,7 +102,7 @@ var Assignment = Context.Chained.extend({
     codeGenerator: function(){return CodeGenerator.nullGenerator();},
     handleExpression: function(e){
         var d = this.attributes.designator;
-        var left = Code.makeExpression(d.code(), d.type(), d);
+        var left = Expression.make(d.code(), d.type(), d);
         this.parent().codeGenerator().write(op.assign(left, e, this.root().language()));
     }
 });

+ 2 - 1
src/oberon/oberon_grammar.js

@@ -10,6 +10,7 @@ var ObRtl = require("js/OberonRtl.js");
 var ObRtlCode = require("rtl.js");
 var Operator = require("js/Operator.js");
 var Parser = require("parser.js");
+var Record = require("js/Record.js");
 var Symbols = require("js/OberonSymbols.js");
 var Types = require("js/Types.js");
 
@@ -133,7 +134,7 @@ exports.language = {
         implicitCast: function(from, to, toVar, op){
             return Cast.implicit(from, to, toVar, Operator.castOperations(), op);
         },
-        typeInfo: function(type){return Types.generateTypeInfo(type);},
+        typeInfo: function(type){return Record.generateTypeInfo(type);},
         StaticArray: Types.StaticArray,
         OpenArray: Types.OpenArray
     },