Kaynağa Gözat

fix copy/clone for MAP OF RECORD

Vladislav Folts 10 yıl önce
ebeveyn
işleme
00a17481bb
45 değiştirilmiş dosya ile 376 ekleme ve 1176 silme
  1. BIN
      bin/compiled.zip
  2. 2 2
      src/context.js
  3. 12 14
      src/eberon/EberonCast.ob
  4. 2 2
      src/eberon/EberonConstructor.ob
  5. 3 3
      src/eberon/EberonDynamicArray.ob
  6. 30 18
      src/eberon/EberonOperator.ob
  7. 0 2
      src/eberon/EberonRtl.ob
  8. 5 3
      src/eberon/eberon_context.js
  9. 1 0
      src/eberon/eberon_grammar.js
  10. 47 18
      src/eberon/eberon_rtl.js
  11. 16 24
      src/ob/Cast.ob
  12. 18 3
      src/ob/LanguageContext.ob
  13. 111 119
      src/ob/Operator.ob
  14. 19 22
      src/ob/Procedure.ob
  15. 1 0
      src/oberon/oberon_grammar.js
  16. 4 4
      src/rtl.js
  17. 1 73
      test/expected/array.js
  18. 1 6
      test/expected/assert.js
  19. 1 44
      test/expected/blur.js
  20. 1 32
      test/expected/cast.js
  21. 1 6
      test/expected/chr.js
  22. 1 8
      test/expected/eberon/constructor.js
  23. 1 6
      test/expected/eberon/designator.js
  24. 1 77
      test/expected/eberon/dynamic_array.js
  25. 1 12
      test/expected/eberon/generic_message_bus.js
  26. 1 83
      test/expected/eberon/in_place_variables.js
  27. 24 153
      test/expected/eberon/map.js
  28. 1 8
      test/expected/eberon/method.js
  29. 1 8
      test/expected/eberon/modules.js
  30. 1 6
      test/expected/eberon/string.js
  31. 1 20
      test/expected/export.js
  32. 1 8
      test/expected/is.js
  33. 1 66
      test/expected/len.js
  34. 1 54
      test/expected/modules.js
  35. 1 6
      test/expected/odd.js
  36. 1 6
      test/expected/ord.js
  37. 1 24
      test/expected/parentheses.js
  38. 1 8
      test/expected/proc.js
  39. 1 87
      test/expected/record.js
  40. 1 50
      test/expected/set.js
  41. 1 64
      test/expected/string.js
  42. 1 24
      test/expected/var_parameter.js
  43. 18 0
      test/input/eberon/map.ob
  44. 25 3
      test/input/eberon/run/map.ob
  45. 13 0
      test/test_compile.js

BIN
bin/compiled.zip


+ 2 - 2
src/context.js

@@ -641,7 +641,7 @@ exports.ProcDecl = ChainedContext.extend({
                 "RETURN '" + result.description() + "' expected, got '"
                 + type.description() + "'");
 
-        this.codeGenerator().write("return " + op.clone(language.rtl, e) + ";\n");
+        this.codeGenerator().write("return " + op.clone(language, e) + ";\n");
 
         this.__returnParsed = true;
     },
@@ -1256,7 +1256,7 @@ exports.Expression = ChainedContext.extend({
         rightExpression = promoteTypeInExpression(rightExpression, leftExpression.type());
 
         var o = this._relationOperation(leftExpression.type(), rightExpression.type(), this.__relation);
-        this.__expression = o(leftExpression, rightExpression, this.language().rtl);
+        this.__expression = o(leftExpression, rightExpression, this.language());
     },
     _relationOperation: function(left, right, relation){
         return relationOp(left, right, relation, this.__relOps, this);

+ 12 - 14
src/eberon/EberonCast.ob

@@ -1,18 +1,18 @@
 MODULE EberonCast;
-IMPORT Cast, Code, Context, EberonMap, EberonRtl, EberonString, EberonDynamicArray, OberonRtl, Types;
+IMPORT Cast, Code, Context, EberonMap, EberonRtl, EberonString, EberonOperator, EberonDynamicArray, LanguageContext, OberonRtl, Types;
 TYPE
     CastOpToDynamicArray = RECORD (Cast.CastOpArray)
     END;
 
-    CastOpToMap = RECORD (Cast.CastOp)
+    CastOpToMap = RECORD (LanguageContext.CastOp)
     END;
 
 VAR
     castOpToDynamicArray: POINTER TO CastOpToDynamicArray;
     castOpToMap: POINTER TO CastOpToMap;
 
-PROCEDURE CastOpToDynamicArray.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
-    RETURN Code.makeSimpleExpression(Cast.cloneArray(e.type()(Types.PArray), e.code(), rtl^), NIL)
+PROCEDURE CastOpToDynamicArray.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
+    RETURN Code.makeSimpleExpression(Cast.cloneArray(e.type()(Types.PArray), e.code(), cx), NIL)
 END;
 
 PROCEDURE copyArray(t: Types.PArray; leftCode, rightCode: STRING; rtl: OberonRtl.Type): STRING;
@@ -22,27 +22,25 @@ BEGIN
     IF t.elementsType.isScalar() THEN
         result := "Array.prototype.splice.apply(" + leftCode + ", [0, Number.MAX_VALUE].concat(" + rightCode + "))";
     ELSE
-        result := rtl.copy(rightCode, leftCode, Types.generateTypeInfo(t));
+        result := rtl.copy(rightCode, leftCode, EberonOperator.generateTypeInfo(t));
     END;
     RETURN result
 END;
 
-PROCEDURE CastOpToDynamicArray.assign(cx: Context.Type; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpToDynamicArray.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
     RETURN copyArray(left.type()(Types.PArray), left.code(), right.code(), cx.rtl^)
 END;
 
-PROCEDURE CastOpToMap.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastOpToMap.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
     RETURN e;
 END;
 
-PROCEDURE CastOpToMap.assign(cx: Context.Type; left, right: Code.PExpression): STRING;
-    (* TODO: support non-scalar MAPs *)
-    RETURN cx.rtl(EberonRtl.PType).copyMapOfScalars(right.code(), left.code());
+PROCEDURE CastOpToMap.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+    RETURN cx.rtl.copy(right.code(), left.code(), EberonOperator.generateTypeInfo(left.type()));
 END;
 
-PROCEDURE CastOpToMap.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
-    (* TODO: support non-scalar MAPs *)
-    RETURN rtl(EberonRtl.PType).cloneMapOfScalars(e.code());
+PROCEDURE CastOpToMap.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
+    RETURN cx.rtl.clone(e.code(), EberonOperator.generateTypeInfo(e.type()), "undefined");
 END;
 
 PROCEDURE isOpenCharArray(type: Types.PType): BOOLEAN;
@@ -63,7 +61,7 @@ BEGIN
     RETURN result
 END dynamicArrayElementsMatch;
 
-PROCEDURE implicit*(from, to: Types.PType; toVar: BOOLEAN; ops: Cast.Operations; VAR op: Cast.PCastOp): INTEGER;
+PROCEDURE implicit*(from, to: Types.PType; toVar: BOOLEAN; ops: Cast.Operations; VAR op: LanguageContext.PCastOp): INTEGER;
 VAR
     result: INTEGER;
 BEGIN

+ 2 - 2
src/eberon/EberonConstructor.ob

@@ -75,7 +75,7 @@ END;
 
 PROCEDURE NonRecordInitCall.handleArgument(e: Code.PExpression);
 VAR
-    op: Cast.PCastOp;
+    op: LanguageContext.PCastOp;
 BEGIN
     IF LEN(SELF.code) # 0 THEN
         raiseSingleArgumentException(SELF);
@@ -87,7 +87,7 @@ BEGIN
                          + "' and cannot be initialized using '" + e.type().description() + "' expression");
     END;
     lval <- fieldInitLval(SELF.field);
-    SELF.code := lval + " = " + op.clone(SELF.cx.rtl, e);
+    SELF.code := lval + " = " + op.clone(SELF.cx, e);
 END;
         
 PROCEDURE NonRecordInitCall.end(): Code.PExpression;

+ 3 - 3
src/eberon/EberonDynamicArray.ob

@@ -1,5 +1,5 @@
 MODULE EberonDynamicArray;
-IMPORT Cast, Code, Context, EberonArray, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Types;
+IMPORT Cast, Code, Context, EberonArray, EberonOperator, EberonRecord, EberonTypes, Errors, LanguageContext, Procedure, Types;
 CONST
     methodNameAdd = "add";
     methodNameClear = "clear";
@@ -121,9 +121,9 @@ BEGIN
     
     t <- e.type();
     IF t IS Types.PArray THEN
-        SELF.code := Cast.cloneArray(t, SELF.code, SELF.cx.rtl^);
+        SELF.code := Cast.cloneArray(t, SELF.code, SELF.cx);
     ELSIF t IS Types.PRecord THEN
-        SELF.code := SELF.cx.rtl.clone(SELF.code, Types.generateTypeInfo(t), Types.recordConstructor(SELF.cx^, t^));
+        SELF.code := SELF.cx.rtl.clone(SELF.code, EberonOperator.generateTypeInfo(t), Types.recordConstructor(SELF.cx^, t^));
     END;
 END AddCallGenerator.handleArgument;
 

+ 30 - 18
src/eberon/EberonOperator.ob

@@ -1,5 +1,5 @@
 MODULE EberonOperator;
-IMPORT Cast, Code, CodePrecedence, Context, OberonRtl, Operator, Types;
+IMPORT Cast, Code, CodePrecedence, EberonMap, LanguageContext, OberonRtl, Operator, Types;
 TYPE
     CastOpRecord = RECORD(Cast.CastOpRecord)
     END;
@@ -41,32 +41,32 @@ PROCEDURE opGraterEqualStr(left, right: Code.PConst): Code.PConst;
                               >= right^(Code.StringConst).value))
 END opGraterEqualStr;
 
-PROCEDURE addStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.binaryWithCode(left, right, rtl, opAddStr, " + ", CodePrecedence.addSub)
+PROCEDURE addStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.binaryWithCode(left, right, opAddStr, " + ", CodePrecedence.addSub)
 END addStr;
 
-PROCEDURE equalStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.equal(left, right, rtl, opEqualStr, " == ")
+PROCEDURE equalStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.equal(left, right, opEqualStr, " == ")
 END equalStr;
 
-PROCEDURE notEqualStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.equal(left, right, rtl, opNotEqualStr, " != ")
+PROCEDURE notEqualStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.equal(left, right, opNotEqualStr, " != ")
 END notEqualStr;
 
-PROCEDURE lessStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.relational(left, right, rtl, opLessStr, " < ")
+PROCEDURE lessStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.relational(left, right, opLessStr, " < ")
 END lessStr;
 
-PROCEDURE greaterStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.relational(left, right, rtl, opGreaterStr, " > ")
+PROCEDURE greaterStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.relational(left, right, opGreaterStr, " > ")
 END greaterStr;
 
-PROCEDURE lessEqualStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.relational(left, right, rtl, opLessEqualStr, " <= ")
+PROCEDURE lessEqualStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.relational(left, right, opLessEqualStr, " <= ")
 END lessEqualStr;
 
-PROCEDURE greaterEqualStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN Operator.relational(left, right, rtl, opGraterEqualStr, " >= ")
+PROCEDURE greaterEqualStr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN Operator.relational(left, right, opGraterEqualStr, " >= ")
 END greaterEqualStr;
 
 PROCEDURE inMap*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
@@ -74,7 +74,19 @@ PROCEDURE inMap*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExp
                                      Types.basic.bool);
 END;
 
-PROCEDURE CastOpRecord.assign(cx: Context.Type; left, right: Code.PExpression): STRING;
+PROCEDURE generateTypeInfo*(type: Types.PType): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF type IS EberonMap.PType THEN
+        result := "{map: " + generateTypeInfo(type.valueType) + "}";
+    ELSE
+        result := Types.generateTypeInfo(type);
+    END;
+    RETURN result;
+END;
+
+PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
 VAR
     result: STRING;
 BEGIN
@@ -87,8 +99,8 @@ BEGIN
             result := leftLval + " = " + right.code();
         ELSE
             result := leftLval + " = " + cx.rtl.clone(right.code(), 
-                                                      Types.generateTypeInfo(left.type()), 
-                                                      Types.recordConstructor(cx, left.type()(Types.PRecord)^));
+                                                      generateTypeInfo(left.type()), 
+                                                      Types.recordConstructor(cx^, left.type()(Types.PRecord)^));
         END;
     ELSE
         result := SUPER(cx, left, right);

+ 0 - 2
src/eberon/EberonRtl.ob

@@ -3,8 +3,6 @@ IMPORT OberonRtl;
 TYPE
     Type* = RECORD(OberonRtl.Type)
         clearMap*: PROCEDURE(s: STRING): STRING;
-        cloneMapOfScalars*: PROCEDURE(s: STRING): STRING;
-        copyMapOfScalars*: PROCEDURE(from, to: STRING): STRING;
     END;
     PType* = POINTER TO Type;
 

+ 5 - 3
src/eberon/eberon_context.js

@@ -359,8 +359,10 @@ var InPlaceVariableInit = Context.Chained.extend({
         this._symbol = new Symbol.Symbol(this.__id, v);
         if (type instanceof Type.Record){
             EberonRecord.ensureCanBeInstantiated(this, type, EberonRecord.instantiateForCopy);
-            if (e.designator())
-                this._code += this.language().rtl.clone(e.code(), Type.generateTypeInfo(type));
+            if (e.designator()){
+                var l = this.language();
+                this._code += l.rtl.clone(e.code(), l.types.typeInfo(type));
+            }
             else // do not clone if it is temporary, e.g. constructor call
                 this._code += e.code();
         }
@@ -371,7 +373,7 @@ var InPlaceVariableInit = Context.Chained.extend({
             var language = this.language();
             var cloneOp;
             language.types.implicitCast(type, type, false, {set: function(v){cloneOp = v;}, get:function(){return cloneOp;}});
-            this._code += cloneOp.clone(language.rtl, e);
+            this._code += cloneOp.clone(language, e);
         }
     },
     _onParsed: function(){

+ 1 - 0
src/eberon/eberon_grammar.js

@@ -165,6 +165,7 @@ exports.language = {
         implicitCast: function(from, to, toVar, op){
             return Cast.implicit(from, to, toVar, EbOperator.castOperations(), op);
         },
+        typeInfo: function(type){return EbOperator.generateTypeInfo(type);},
         StaticArray: EbArray.StaticArray,
         OpenArray: EbArray.OpenArray
     },

+ 47 - 18
src/eberon/eberon_rtl.js

@@ -2,7 +2,14 @@
 
 var oberon_rtl = require("rtl.js");
 
-var methods = {
+function extendMap(base, ext){
+    var result = {};
+    oberon_rtl.applyMap(base, result);
+    oberon_rtl.applyMap(ext, result);
+    return result;
+}
+
+var methods = extendMap(oberon_rtl.rtl.methods, {
     getMappedValue: function(map, key){
         if (!map.hasOwnProperty(key))
             throw new Error("invalid key: " + key);
@@ -12,25 +19,47 @@ var methods = {
         for(var p in map)
             delete map[p];
     },
-    cloneMapOfScalars: function(from){
-        var result = {};
-        this.copyMapOfScalars(from, result);
-        return result;
+    cloneMapOfScalars: function(map){ // support old code
+        return this.clone(map, {map: null});
     },
-    copyMapOfScalars: function(from, to){
-        this.clearMap(to);
-        for(var k in from)
-            to[k] = from[k];
-    }
-};
-oberon_rtl.extendMap(oberon_rtl.rtl.methods, methods);
-oberon_rtl.extendMap(methods, exports);
+    clone: function(from, type, recordCons){
+        var m = type.map;
+        if (m !== undefined){
+            var result = {};
+            this.__copyMap(from, result, m);
+            return result;
+        }
+        return this.__inheritedClone(from, type, recordCons);
+    },
+    copy: function(from, to, type){
+        var m = type.map;
+        if (m !== undefined){
+            this.clearMap(to);
+            this.__copyMap(from, to, m);
+        }
+        else
+            this.__inheritedCopy(from, to, type);
+    },
+    __copyMap: function(from, to, type){
+        var k;
+        if (type === null)
+            // shallow copy
+            for(k in from)
+                to[k] = from[k];
+        else
+            // deep copy
+            for(k in from)
+                to[k] = this.clone(from[k], type);
+    },
+    __inheritedClone: oberon_rtl.rtl.methods.clone,
+    __inheritedCopy: oberon_rtl.rtl.methods.copy
+});
+oberon_rtl.applyMap(methods, exports);
 
-var dependencies = { 
-        "copyMapOfScalars": ["clearMap"],
-        "cloneMapOfScalars": ["copyMapOfScalars"]
-    };
-oberon_rtl.extendMap(oberon_rtl.rtl.dependencies, dependencies);
+var dependencies = extendMap(oberon_rtl.rtl.dependencies, { 
+        "clone": oberon_rtl.rtl.dependencies.clone.concat(["__copyMap", "__inheritedClone"]),
+        "copy": oberon_rtl.rtl.dependencies.copy.concat(["clearMap", "__copyMap", "__inheritedCopy"])
+    });
 
 exports.rtl = {
     dependencies: dependencies,

+ 16 - 24
src/ob/Cast.ob

@@ -1,19 +1,12 @@
 MODULE Cast;
-IMPORT Code, Context, OberonRtl, String, Types;
+IMPORT Code, LanguageContext, OberonRtl, String, Types;
 CONST
     errNo* = 0;
     err* = 1;
     errVarParameter* = 2;
 TYPE
-    CastOp* = RECORD
-        PROCEDURE make*(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
-        PROCEDURE assign*(cx: Context.Type; left, right: Code.PExpression): STRING;
-        PROCEDURE clone*(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
-    END;
-
-    PCastOp* = POINTER TO CastOp;
 
-    CastOpDoNothing* = RECORD (CastOp)
+    CastOpDoNothing* = RECORD (LanguageContext.CastOp)
     END;
 
     CastOpArray* = RECORD (CastOpDoNothing)
@@ -26,8 +19,7 @@ TYPE
     END;
 
     Operations* = RECORD
-        castToRecord*: PCastOp;
-        castToUint8*: PCastOp
+        castToRecord*, castToUint8*: LanguageContext.PCastOp;
     END;
 
 VAR
@@ -118,7 +110,7 @@ BEGIN
     RETURN result
 END areTypesExactlyMatchImpl;
 
-PROCEDURE CastOpDoNothing.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastOpDoNothing.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
     RETURN e
 END;
 
@@ -132,11 +124,11 @@ PROCEDURE assignByReference*(left, right: Code.PExpression): STRING;
     RETURN left.code() + ".set(" + Code.derefExpression(right).code() + ")";
 END;
 
-PROCEDURE CastOpDoNothing.assign(cx: Context.Type; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpDoNothing.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
 VAR
     result: STRING;
 BEGIN
-    rightConverted <- SELF.make(cx.rtl, right);
+    rightConverted <- SELF.make(cx, right);
     IF passedByReference(left) THEN
         result := assignByReference(left, rightConverted);
     ELSE
@@ -145,35 +137,35 @@ BEGIN
     RETURN result;
 END;
 
-PROCEDURE CastOpDoNothing.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
+PROCEDURE CastOpDoNothing.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
     RETURN Code.derefExpression(e).code();
 END;
 
-PROCEDURE cloneArray*(t: Types.PArray; code: STRING; rtl: OberonRtl.Type): STRING;
+PROCEDURE cloneArray*(t: Types.PArray; code: STRING; cx: LanguageContext.PType): STRING;
 VAR
     result: STRING;
 BEGIN
     IF Types.arrayElementsType(t^).isScalar() THEN
         result := code + ".slice()";
     ELSE
-        result := rtl.clone(code, Types.generateTypeInfo(t), "undefined");
+        result := cx.rtl.clone(code, cx.types.typeInfo(t), "undefined");
     END;
     RETURN result
 END;
 
-PROCEDURE CastOpArray.assign(cx: Context.Type; left, right: Code.PExpression): STRING;
-    RETURN left.code() + " = " + cloneArray(right.type()(Types.PArray), right.code(), cx.rtl^)
+PROCEDURE CastOpArray.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
+    RETURN left.code() + " = " + cloneArray(right.type()(Types.PArray), right.code(), cx)
 END;
 
-PROCEDURE CastOpArray.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
-    RETURN cloneArray(e.type()(Types.PArray), e.code(), rtl^);
+PROCEDURE CastOpArray.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
+    RETURN cloneArray(e.type()(Types.PArray), e.code(), cx);
 END;
 
-PROCEDURE CastOpRecord.assign(cx: Context.Type; left, right: Code.PExpression): STRING;
+PROCEDURE CastOpRecord.assign(cx: LanguageContext.PType; left, right: Code.PExpression): STRING;
     RETURN cx.rtl.copy(right.code(), left.lval(), Types.generateTypeInfo(left.type()));
 END;
 
-PROCEDURE CastOpStrToChar.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastOpStrToChar.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
 BEGIN
     s <- e.type()(Types.PString);
     ASSERT(LEN(s.s) = 1);
@@ -182,7 +174,7 @@ BEGIN
     RETURN Code.makeSimpleExpression(code, Types.basic.ch)
 END CastOpStrToChar.make;
 
-PROCEDURE implicit*(from, to: Types.PType; toVar: BOOLEAN; ops: Operations; VAR op: PCastOp): INTEGER;
+PROCEDURE implicit*(from, to: Types.PType; toVar: BOOLEAN; ops: Operations; VAR op: LanguageContext.PCastOp): INTEGER;
 VAR
     ignore: BOOLEAN;
 BEGIN

+ 18 - 3
src/ob/LanguageContext.ob

@@ -1,10 +1,25 @@
 MODULE LanguageContext;
-IMPORT Context, Language;
+IMPORT Code, Context, 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;
+    END;
+
+    PCastOp* = POINTER TO CastOp;
+
+    Types* = RECORD         
+        PROCEDURE implicitCast*(from, to: T.PType; toVar: BOOLEAN; VAR op: PCastOp): INTEGER;
+        PROCEDURE typeInfo*(type: T.PType): STRING;
+    END;
+    PTypes* = POINTER TO Types;
+
     Type* = RECORD(Context.Type)
-        types*: Language.PTypes
+        types*: PTypes;
     END;
-    PType* = POINTER TO Type;
 
 END LanguageContext.

+ 111 - 119
src/ob/Operator.ob

@@ -3,14 +3,13 @@ IMPORT
     Cast, 
     Code, 
     Errors, 
-    Language, 
     LanguageContext, 
     OberonRtl, 
     Precedence := CodePrecedence,
     String,
     Types;
 TYPE
-    BinaryProc* = PROCEDURE(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+    BinaryProc* = PROCEDURE(left, right: Code.PExpression): Code.PExpression;
 
     BinaryOp = PROCEDURE(left, right: Code.PConst): Code.PConst;
     CodePredicate = PROCEDURE(left, right: STRING; rtl: OberonRtl.PType): STRING;
@@ -117,7 +116,6 @@ END;
 
 PROCEDURE binaryWithCodeEx(
     left, right: Code.PExpression; 
-    rtl: OberonRtl.PType;
     op: BinaryOp;
     code: STRING;
     precedence: INTEGER;
@@ -127,41 +125,38 @@ PROCEDURE binaryWithCodeEx(
     RETURN binary(
         left, 
         right, 
-        rtl, 
+        NIL, 
         op, 
         NEW SimpleCodeMaker(code), 
         precedence, 
         optResultType, 
         optResultPrecedence)
-END binaryWithCodeEx;
+END;
 
 PROCEDURE binaryWithCode*(
     left, right: Code.PExpression; 
-    rtl: OberonRtl.PType;
     op: BinaryOp;
     code: STRING;
     precedence: INTEGER
     ): Code.PExpression;
-    RETURN binaryWithCodeEx(left, right, rtl, op, code, precedence, NIL, Precedence.none)
+    RETURN binaryWithCodeEx(left, right, op, code, precedence, NIL, Precedence.none)
 END binaryWithCode;
 
 PROCEDURE relational*(
     left, right: Code.PExpression; 
-    rtl: OberonRtl.PType;
     op: BinaryOp;
     code: STRING
     ): Code.PExpression;
-    RETURN binaryWithCodeEx(left, right, rtl, op, code, Precedence.relational, Types.basic.bool, Precedence.none)
-END relational;
+    RETURN binaryWithCodeEx(left, right, op, code, Precedence.relational, Types.basic.bool, Precedence.none)
+END;
 
 PROCEDURE equal*(
     left, right: Code.PExpression; 
-    rtl: OberonRtl.PType;
     op: BinaryOp;
     code: STRING
     ): Code.PExpression;
-    RETURN binaryWithCodeEx(left, right, rtl, op, code, Precedence.equal, Types.basic.bool, Precedence.none)
-END equal;
+    RETURN binaryWithCodeEx(left, right, op, code, Precedence.equal, Types.basic.bool, Precedence.none)
+END;
 
 PROCEDURE promoteToWideIfNeeded(e: Code.PExpression): Code.PExpression;
 VAR
@@ -182,7 +177,6 @@ END promoteToWideIfNeeded;
 
 PROCEDURE binaryInt(
     left, right: Code.PExpression; 
-    rtl: OberonRtl.PType;
     op: BinaryOp;
     code: STRING;
     precedence: INTEGER
@@ -190,7 +184,7 @@ PROCEDURE binaryInt(
     RETURN promoteToWideIfNeeded(binary(
         left, 
         right, 
-        rtl, 
+        NIL, 
         op, 
         NEW IntCodeMaker(code), 
         precedence, 
@@ -230,15 +224,15 @@ BEGIN
     RETURN Code.makeExpression(resultCode, e.type(), NIL, value)
 END unary;
 
-PROCEDURE castToStr(e: Code.PExpression; rtl: OberonRtl.PType): STRING;
+PROCEDURE castToStr(e: Code.PExpression; cx: LanguageContext.PType): STRING;
 VAR
     resultExpression: Code.PExpression;
-    op: Cast.PCastOp;
+    op: LanguageContext.PCastOp;
     ignored: INTEGER;
 BEGIN
     ignored := Cast.implicit(e.type(), openArrayChar, FALSE, castOperations, op);
     IF op # NIL THEN
-        resultExpression := op.make(rtl, e)
+        resultExpression := op.make(cx, e)
     ELSE
         resultExpression := e;
     END;
@@ -444,20 +438,19 @@ PROCEDURE codeSetInclR(left, right: STRING; rtl: OberonRtl.PType): STRING;
     RETURN rtl.setInclR(left, right)
 END codeSetInclR;
 
-PROCEDURE strCmp(op: STRING; left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-BEGIN   
+PROCEDURE strCmp(op: STRING; left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     RETURN Code.makeSimpleExpression(
-            rtl.strCmp(castToStr(left, rtl), castToStr(right, rtl)) + op + "0",
+            cx.rtl.strCmp(castToStr(left, cx), castToStr(right, cx)) + op + "0",
             Types.basic.bool)
-END strCmp;
+END;
 
-PROCEDURE assign*(left, right: Code.PExpression; cx: LanguageContext.Type): STRING;
+PROCEDURE assign*(left, right: Code.PExpression; cx: LanguageContext.PType): STRING;
 VAR
     designator: Code.PDesignator;
     info: Types.PId;
     leftCode, rightCode: STRING;
     isArray: BOOLEAN;
-    castOperation: Cast.PCastOp;
+    castOperation: LanguageContext.PCastOp;
     ignored: BOOLEAN;
     result: STRING;
 
@@ -506,7 +499,7 @@ BEGIN
     RETURN result
 END assign;
     
-PROCEDURE inplace(left, right: Code.PExpression; cx: LanguageContext.Type; code: STRING; altOp: BinaryProc): STRING;
+PROCEDURE inplace(left, right: Code.PExpression; cx: LanguageContext.PType; code: STRING; altOp: BinaryProc): STRING;
 VAR
     designator: Code.PDesignator;
     rightExp: Code.PExpression;
@@ -515,7 +508,7 @@ BEGIN
     designator := left.designator();
     info <- designator.info();
     IF (info IS Types.PVariable) & info.isReference() THEN
-        result := assign(left, altOp(left, right, cx.rtl), cx);
+        result := assign(left, altOp(left, right), cx);
     ELSE
         rightExp := Code.derefExpression(right);
         result := left.code() + code + rightExp.code();
@@ -523,56 +516,56 @@ BEGIN
     RETURN result
 END inplace;
 
-PROCEDURE addReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opAddReal, " + ", Precedence.addSub)
+PROCEDURE addReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opAddReal, " + ", Precedence.addSub)
 END addReal;
 
-PROCEDURE addInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryInt(left, right, rtl, opAddInt, " + ", Precedence.addSub)
+PROCEDURE addInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryInt(left, right, opAddInt, " + ", Precedence.addSub)
 END addInt;
 
-PROCEDURE subReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opSubReal, " - ", Precedence.addSub)
+PROCEDURE subReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opSubReal, " - ", Precedence.addSub)
 END subReal;
 
-PROCEDURE subInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryInt(left, right, rtl, opSubInt, " - ", Precedence.addSub)
+PROCEDURE subInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryInt(left, right, opSubInt, " - ", Precedence.addSub)
 END subInt;
 
-PROCEDURE mulReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opMulReal, " * ", Precedence.mulDivMod)
+PROCEDURE mulReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opMulReal, " * ", Precedence.mulDivMod)
 END mulReal;
 
-PROCEDURE mulInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryInt(left, right, rtl, opMulInt, " * ", Precedence.mulDivMod)
+PROCEDURE mulInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryInt(left, right, opMulInt, " * ", Precedence.mulDivMod)
 END mulInt;
 
-PROCEDURE divReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opDivReal, " / ", Precedence.mulDivMod)
+PROCEDURE divReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opDivReal, " / ", Precedence.mulDivMod)
 END divReal;
 
-PROCEDURE divInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryInt(left, right, rtl, opDivInt, " / ", Precedence.mulDivMod)
+PROCEDURE divInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryInt(left, right, opDivInt, " / ", Precedence.mulDivMod)
 END divInt;
 
-PROCEDURE mod*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opMod, " % ", Precedence.mulDivMod)
+PROCEDURE mod*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opMod, " % ", Precedence.mulDivMod)
 END mod;
 
-PROCEDURE setUnion*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opSetUnion, " | ", Precedence.bitOr)
+PROCEDURE setUnion*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opSetUnion, " | ", Precedence.bitOr)
 END setUnion;
 
-PROCEDURE setDiff*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opSetDiff, " & ~", Precedence.bitAnd)
+PROCEDURE setDiff*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opSetDiff, " & ~", Precedence.bitAnd)
 END setDiff;
 
-PROCEDURE setIntersection*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opSetIntersection, " & ", Precedence.bitAnd)
+PROCEDURE setIntersection*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opSetIntersection, " & ", Precedence.bitAnd)
 END setIntersection;
 
-PROCEDURE setSymmetricDiff*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opSetSymmetricDiff, " ^ ", Precedence.bitXor)
+PROCEDURE setSymmetricDiff*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opSetSymmetricDiff, " ^ ", Precedence.bitXor)
 END setSymmetricDiff;
 
 PROCEDURE setHasBit*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
@@ -585,143 +578,143 @@ PROCEDURE setHasBit*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.
             Precedence.bitAnd)
 END setHasBit;
 
-PROCEDURE setInclL*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryPred(left, right, rtl, opSetInclL, codeSetInclL)
+PROCEDURE setInclL*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN binaryPred(left, right, cx.rtl, opSetInclL, codeSetInclL)
 END setInclL;
 
-PROCEDURE setInclR*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryPred(left, right, rtl, opSetInclR, codeSetInclR)
+PROCEDURE setInclR*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN binaryPred(left, right, cx.rtl, opSetInclR, codeSetInclR)
 END setInclR;
 
-PROCEDURE or*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opOr, " || ", Precedence.or)
+PROCEDURE or*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opOr, " || ", Precedence.or)
 END or;
 
-PROCEDURE and*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opAnd, " && ", Precedence.and)
+PROCEDURE and*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opAnd, " && ", Precedence.and)
 END and;
 
-PROCEDURE equalInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN equal(left, right, rtl, opEqualInt, " == ")
+PROCEDURE equalInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN equal(left, right, opEqualInt, " == ")
 END equalInt;
 
-PROCEDURE equalReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN equal(left, right, rtl, opEqualReal, " == ")
+PROCEDURE equalReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN equal(left, right, opEqualReal, " == ")
 END equalReal;
 
-PROCEDURE equalSet*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN equal(left, right, rtl, opEqualSet, " == ")
+PROCEDURE equalSet*(left, right: Code.PExpression): Code.PExpression;
+    RETURN equal(left, right, opEqualSet, " == ")
 END equalSet;
 
-PROCEDURE equalStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN strCmp(" == ", left, right, rtl)
+PROCEDURE equalStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN strCmp(" == ", left, right, cx)
 END equalStr;
 
-PROCEDURE notEqualInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN equal(left, right, rtl, opNotEqualInt, " != ")
+PROCEDURE notEqualInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN equal(left, right, opNotEqualInt, " != ")
 END notEqualInt;
 
-PROCEDURE notEqualReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN equal(left, right, rtl, opNotEqualReal, " != ")
+PROCEDURE notEqualReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN equal(left, right, opNotEqualReal, " != ")
 END notEqualReal;
 
-PROCEDURE notEqualSet*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN equal(left, right, rtl, opNotEqualSet, " != ")
+PROCEDURE notEqualSet*(left, right: Code.PExpression): Code.PExpression;
+    RETURN equal(left, right, opNotEqualSet, " != ")
 END notEqualSet;
 
-PROCEDURE notEqualStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN strCmp(" != ", left, right, rtl)
+PROCEDURE notEqualStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN strCmp(" != ", left, right, cx)
 END notEqualStr;
 
-PROCEDURE is*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, NIL, " instanceof ")
+PROCEDURE is*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, NIL, " instanceof ")
 END is;
 
-PROCEDURE lessInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opLessInt, " < ")
+PROCEDURE lessInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opLessInt, " < ")
 END lessInt;
 
-PROCEDURE lessReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opLessReal, " < ")
+PROCEDURE lessReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opLessReal, " < ")
 END lessReal;
 
-PROCEDURE lessStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN strCmp(" < ", left, right, rtl)
+PROCEDURE lessStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN strCmp(" < ", left, right, cx)
 END lessStr;
 
-PROCEDURE greaterInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opGreaterInt, " > ")
+PROCEDURE greaterInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opGreaterInt, " > ")
 END greaterInt;
 
-PROCEDURE greaterReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opGreaterReal, " > ")
+PROCEDURE greaterReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opGreaterReal, " > ")
 END greaterReal;
 
-PROCEDURE greaterStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN strCmp(" > ", left, right, rtl)
+PROCEDURE greaterStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN strCmp(" > ", left, right, cx)
 END greaterStr;
 
-PROCEDURE eqLessInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opEqLessInt, " <= ")
+PROCEDURE eqLessInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opEqLessInt, " <= ")
 END eqLessInt;
 
-PROCEDURE eqLessReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opEqLessReal, " <= ")
+PROCEDURE eqLessReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opEqLessReal, " <= ")
 END eqLessReal;
 
-PROCEDURE eqLessStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN strCmp(" <= ", left, right, rtl)
+PROCEDURE eqLessStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN strCmp(" <= ", left, right, cx)
 END eqLessStr;
 
-PROCEDURE eqGreaterInt*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opEqGreaterInt, " >= ")
+PROCEDURE eqGreaterInt*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opEqGreaterInt, " >= ")
 END eqGreaterInt;
 
-PROCEDURE eqGreaterReal*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN relational(left, right, rtl, opEqGreaterReal, " >= ")
+PROCEDURE eqGreaterReal*(left, right: Code.PExpression): Code.PExpression;
+    RETURN relational(left, right, opEqGreaterReal, " >= ")
 END eqGreaterReal;
 
-PROCEDURE eqGreaterStr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN strCmp(" >= ", left, right, rtl)
+PROCEDURE eqGreaterStr*(left, right: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+    RETURN strCmp(" >= ", left, right, cx)
 END eqGreaterStr;
 
-PROCEDURE not*(x: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+PROCEDURE not*(x: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     RETURN unary(x, opNot, "!")
 END not;
 
-PROCEDURE negateInt*(x: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+PROCEDURE negateInt*(x: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     RETURN promoteToWideIfNeeded(unary(x, opNegateInt, "-"))
 END negateInt;
 
-PROCEDURE negateReal*(x: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+PROCEDURE negateReal*(x: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     RETURN promoteToWideIfNeeded(unary(x, opNegateReal, "-"))
 END negateReal;
 
-PROCEDURE unaryPlus*(x: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+PROCEDURE unaryPlus*(x: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     RETURN unary(x, opUnaryPlus, "")
 END unaryPlus;
 
-PROCEDURE setComplement*(x: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+PROCEDURE setComplement*(x: Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     RETURN unary(x, opSetComplement, "~")
 END setComplement;
 
-PROCEDURE lsl*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opLsl, " << ", Precedence.shift)
+PROCEDURE lsl*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opLsl, " << ", Precedence.shift)
 END lsl;
 
-PROCEDURE asr*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opAsr, " >> ", Precedence.shift)
+PROCEDURE asr*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opAsr, " >> ", Precedence.shift)
 END asr;
 
-PROCEDURE ror*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
-    RETURN binaryWithCode(left, right, rtl, opRor, " >>> ", Precedence.shift)
+PROCEDURE ror*(left, right: Code.PExpression): Code.PExpression;
+    RETURN binaryWithCode(left, right, opRor, " >>> ", Precedence.shift)
 END ror;
 
-PROCEDURE mulInplace*(left, right: Code.PExpression; cx: LanguageContext.Type): STRING;
+PROCEDURE mulInplace*(left, right: Code.PExpression; cx: LanguageContext.PType): STRING;
     RETURN inplace(left, right, cx, " *= ", mulReal)
 END mulInplace;
 
-PROCEDURE divInplace*(left, right: Code.PExpression; cx: LanguageContext.Type): STRING;
+PROCEDURE divInplace*(left, right: Code.PExpression; cx: LanguageContext.PType): STRING;
     RETURN inplace(left, right, cx, " /= ", divReal)
 END divInplace;
 
@@ -752,21 +745,20 @@ PROCEDURE opCastToUint8(left, right: Code.PConst): Code.PConst;
                            * right^(Code.IntConst).value)
 END opCastToUint8;
 
-PROCEDURE CastToUint8.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
+PROCEDURE CastToUint8.make(cx: LanguageContext.PType; e: Code.PExpression): Code.PExpression;
     RETURN binaryWithCode(
         e, 
         Code.makeExpression("0xFF", 
                             Types.basic.integer, 
                             NIL, 
                             Code.makeIntConst(0FFH)), 
-        rtl, 
         opCastToUint8, 
         " & ", 
         Precedence.bitAnd)
 END;
 
-PROCEDURE CastToUint8.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
-    RETURN SELF.make(rtl, e).code();
+PROCEDURE CastToUint8.clone(cx: LanguageContext.PType; e: Code.PExpression): STRING;
+    RETURN SELF.make(cx, e).code();
 END;
 
 BEGIN

+ 19 - 22
src/ob/Procedure.ob

@@ -4,7 +4,6 @@ IMPORT
     Code, 
     Context, 
     Errors, 
-    Language,
     LanguageContext,
     OberonRtl,
     Object, 
@@ -61,7 +60,7 @@ TYPE
     ArgumentsCode* = RECORD
         PROCEDURE write*(actual: Code.PExpression; 
                          expected: Types.PProcedureArgument; 
-                         cast: Cast.PCastOp
+                         cast: LanguageContext.PCastOp
                          );
         PROCEDURE result*(): STRING
     END;
@@ -69,10 +68,9 @@ TYPE
 
     GenArgCode = RECORD(ArgumentsCode)
         code: STRING;
-        cx: Context.PType
+        cx: LanguageContext.PType
     END;
 
-    BinaryOp = PROCEDURE(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
     BinaryOpStr = PROCEDURE (x, y: STRING): STRING;
 VAR
     predefined*: ARRAY * OF Symbols.PSymbol;
@@ -82,13 +80,13 @@ PROCEDURE checkArgument*(
     expected: Types.PProcedureArgument; 
     pos: INTEGER;
     code: PArgumentsCode;
-    types: Language.PTypes
+    types: LanguageContext.PTypes
     );
 VAR
     actualType, expectType: Types.PType;
     designator: Code.PDesignator;
     info: Types.PId;
-    result: Cast.PCastOp;
+    result: LanguageContext.PCastOp;
     castErr: INTEGER;
 BEGIN
     expectType := expected.type; (* can be NIL for predefined functions (like NEW), dont check it in this case *)
@@ -128,7 +126,7 @@ PROCEDURE checkArgumentsType(
     actual: ARRAY OF Code.PExpression;
     expected: ARRAY OF Types.PProcedureArgument; 
     code: PArgumentsCode;
-    types: Language.PTypes
+    types: LanguageContext.PTypes
     );
 BEGIN
     FOR i <- 0 TO LEN(actual) - 1 DO
@@ -149,14 +147,14 @@ PROCEDURE processArguments*(
     actual: ARRAY OF Code.PExpression;
     expected: ARRAY OF Types.PProcedureArgument; 
     code: PArgumentsCode;
-    types: Language.PTypes
+    types: LanguageContext.PTypes
     );
 BEGIN
     checkArgumentsCount(LEN(actual), LEN(expected));
     checkArgumentsType(actual, expected, code, types);
 END processArguments;
 
-PROCEDURE checkArguments(actual: ARRAY OF Code.PExpression; expected: ARRAY OF Types.PProcedureArgument; types: Language.PTypes);
+PROCEDURE checkArguments(actual: ARRAY OF Code.PExpression; expected: ARRAY OF Types.PProcedureArgument; types: LanguageContext.PTypes);
 BEGIN
     processArguments(actual, expected, NIL, types);
 END checkArguments;
@@ -185,7 +183,7 @@ BEGIN
     RETURN result
 END;
 
-PROCEDURE GenArgCode.write(actual: Code.PExpression; expected: Types.PProcedureArgument; cast: Cast.PCastOp);
+PROCEDURE GenArgCode.write(actual: Code.PExpression; expected: Types.PProcedureArgument; cast: LanguageContext.PCastOp);
 VAR
     e: Code.PExpression;
     coercedArg: Code.PExpression;
@@ -199,7 +197,7 @@ BEGIN
         SELF.code := SELF.code + ", ";
     END;
     IF cast # NIL THEN
-        e := cast.make(SELF.cx.rtl, coercedArg);
+        e := cast.make(SELF.cx, coercedArg);
     ELSE
         e := coercedArg;
     END;
@@ -238,7 +236,7 @@ BEGIN
     RETURN makeCallGenerator(call, cx)
 END makeProcCallGeneratorWithCustomArgs;
 
-PROCEDURE makeArgumentsCode*(cx: Context.PType): PArgumentsCode;
+PROCEDURE makeArgumentsCode*(cx: LanguageContext.PType): PArgumentsCode;
 BEGIN
     result <- NEW GenArgCode();
     result.cx := cx;
@@ -291,7 +289,7 @@ END hasVarArgumnetWithCustomType;
 PROCEDURE checkSingleArgument*(
     actual: ARRAY OF Code.PExpression; 
     call: StdCall; 
-    types: Language.PTypes; 
+    types: LanguageContext.PTypes; 
     code: PArgumentsCode
     ): Code.PExpression;
 BEGIN
@@ -441,8 +439,7 @@ PROCEDURE setBitImpl(name: STRING; bitOp: BinaryOpStr): Symbols.PSymbol;
                     Types.basic.integer,
                     NIL,
                     Code.makeIntConst(1)), 
-                y,
-                cx.rtl);
+                y);
             valueCode := valueCodeExp.code();
         ELSE
             yValue := value^(Code.IntConst).value;
@@ -510,7 +507,7 @@ PROCEDURE incImpl(name: STRING; unary: STRING; incOp: BinaryOpStr; incRefOp: Ope
             ELSE
                 y := args[1];
             END;
-            addExp <- SELF.incRefOp(x, y, cx.rtl);
+            addExp <- SELF.incRefOp(x, y);
             code := Cast.assignByReference(x, addExp);
         ELSIF LEN(args) = 1 THEN
             code := SELF.unary + x.code();
@@ -628,18 +625,18 @@ BEGIN
     RETURN makeSymbol(NEW Std("FLT", call))
 END makeFlt;
 
-PROCEDURE bitShiftImpl(name: STRING; op: BinaryOp): Symbols.PSymbol;
+PROCEDURE bitShiftImpl(name: STRING; op: Operator.BinaryProc): Symbols.PSymbol;
     TYPE
         CallImpl = RECORD(StdCall)
             name: STRING;
-            op: BinaryOp
+            op: Operator.BinaryProc
         END;
 
     PROCEDURE CallImpl.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
     BEGIN
         checkArguments(args, SELF.args, cx.types);
         ASSERT(LEN(args) = 2);
-        RETURN SELF.op(args[0], args[1], cx.rtl)
+        RETURN SELF.op(args[0], args[1])
     END CallImpl.make;
 BEGIN
     call <- NEW CallImpl();
@@ -732,7 +729,7 @@ PROCEDURE makePack(): Symbols.PSymbol;
         x := args[0];
         y := args[1];
         RETURN Code.makeSimpleExpression(
-            Operator.mulInplace(x, Operator.pow2(y), cx^),
+            Operator.mulInplace(x, Operator.pow2(y), cx),
             NIL)
     END CallImpl.make;
 BEGIN
@@ -755,9 +752,9 @@ PROCEDURE makeUnpk(): Symbols.PSymbol;
         x := args[0];
         y := args[1];
         RETURN Code.makeSimpleExpression(
-                Operator.assign(y, Operator.log2(x), cx^) 
+                Operator.assign(y, Operator.log2(x), cx) 
                 + "; "
-                + Operator.divInplace(x, Operator.pow2(y), cx^),
+                + Operator.divInplace(x, Operator.pow2(y), cx),
             NIL)
     END CallImpl.make;
 BEGIN

+ 1 - 0
src/oberon/oberon_grammar.js

@@ -132,6 +132,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);},
         StaticArray: Types.StaticArray,
         OpenArray: Types.OpenArray
     },

+ 4 - 4
src/rtl.js

@@ -8,7 +8,7 @@ if (typeof Uint16Array == "undefined"){
     };
 }
 
-function extendMap(from, to){
+function applyMap(from, to){
     for(var p in from)
         to[p] = from[p];
 }
@@ -16,7 +16,7 @@ function extendMap(from, to){
 function Class(){}
 Class.extend = function extend(methods){
         function Type(){
-            extendMap(methods, this);
+            applyMap(methods, this);
         }
         Type.prototype = this.prototype;
 
@@ -239,5 +239,5 @@ exports.rtl = {
     methods: methods,
     nodejsModule: "rtl.js"
 };
-exports.extendMap = extendMap;
-extendMap(methods, exports);
+exports.applyMap = applyMap;
+applyMap(methods, exports);

+ 1 - 73
test/expected/array.js

@@ -1,76 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    clone: function (from, type, recordCons){
-        var result;
-        var r = type.record;
-        if (r){
-            var Ctr = recordCons || from.constructor;
-            result = new Ctr();
-            this.copy(from, result, type);
-            return result;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow clone
-                return from.slice();
-
-            // deep clone
-            var length = from.length;
-            result = new Array(length);
-            for(var i = 0; i < length; ++i)
-                result[i] = this.clone(from[i], a);
-            return result;
-        }
-    },
-    copy: function (from, to, type){
-        var r = type.record;
-        if (r){
-            for(var f in r){
-                var fieldType = r[f];
-                if (fieldType){
-                    // temporary support for mangled fields
-                    var mangled = "$" + f;
-                    if (!from.hasOwnProperty(mangled))
-                        mangled = f;
-                    this.copy(from[mangled], to[mangled], fieldType);
-                }
-                else
-                    to[f] = from[f];
-            }
-            return;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow copy
-                Array.prototype.splice.apply(to, [0, to.length].concat(from));
-            else {
-                // deep copy
-                to.splice(0, to.length);
-                for(var i = 0; i < from.length; ++i)
-                    to.push(this.clone(from[i], a));
-            }
-        }
-    }
-};
+<rtl code>
 var m = function (){
 var arraySize = 10;
 var a1 = RTL$.makeArray(10, 0);var a11 = RTL$.makeArray(10, 0);

+ 1 - 6
test/expected/assert.js

@@ -1,9 +1,4 @@
-var RTL$ = {
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 RTL$.assert(true);
 }();

+ 1 - 44
test/expected/blur.js

@@ -1,47 +1,4 @@
-var RTL$ = {
-    makeCharArray: function (/*dimensions*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var length = forward.pop();
-
-        if (!forward.length)
-            return this.__makeCharArray(length);
-
-        function makeArray(){
-            var forward = Array.prototype.slice.call(arguments);
-            var result = new Array(forward.shift());
-            var i;
-            if (forward.length == 1){
-                var init = forward[0];
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            }
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = makeArray.apply(undefined, forward);
-            return result;
-        }
-
-        forward.push(this.__makeCharArray.bind(this, length));
-        return makeArray.apply(undefined, forward);
-    },
-    __makeCharArray: function (length){
-        var result = new Uint16Array(length);
-        this.__setupCharArrayMethods(result);
-        return result;
-    },
-    __setupCharArrayMethods: function (a){
-        var rtl = this;
-        a.charCodeAt = function(i){return this[i];};
-        a.slice = function(){
-            var result = Array.prototype.slice.apply(this, arguments);
-            rtl.__setupCharArrayMethods(result);
-            return result;
-        };
-        a.toString = function(){
-            return String.fromCharCode.apply(this, this);
-        };
-    }
-};
+<rtl code>
 var Blur = function (){
 var W = 640;
 var W1 = 640 - 3 | 0;

+ 1 - 32
test/expected/cast.js

@@ -1,35 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    },
-    typeGuard: function (from, to){
-        if (!from)
-            return from;
-        if (!(from instanceof to)){
-            var fromStr;
-            var toStr;
-            
-            if (from && from.constructor && from.constructor.name)
-                fromStr = "" + from.constructor.name;
-            else
-                fromStr = "" + from;
-            
-            if (to.name)
-                toStr = "" + to.name;
-            else
-                toStr = "" + to;
-            
-            var msg = "typeguard assertion failed";
-            if (fromStr || toStr)               
-                msg += ": '" + fromStr + "' is not an extension of '" + toStr + "'";
-            throw new Error(msg);
-        }
-        return from;
-    }
-};
+<rtl code>
 var m = function (){
 function Base(){
 }

+ 1 - 6
test/expected/chr.js

@@ -1,9 +1,4 @@
-var RTL$ = {
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 var ch = 0;
 var i = 0;

+ 1 - 8
test/expected/eberon/constructor.js

@@ -1,11 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    }
-};
+<rtl code>
 var m = function (){
 RTL$.extend(Derived, T);
 RTL$.extend(RecordWithFieldDerived, T);

+ 1 - 6
test/expected/eberon/designator.js

@@ -1,9 +1,4 @@
-var RTL$ = {
-    makeRef: function (obj, prop){
-        return {set: function(v){ obj[prop] = v; },
-                get: function(){ return obj[prop]; }};
-    }
-};
+<rtl code>
 var m = function (){
 function TP(){
 	this.i = 0;

+ 1 - 77
test/expected/eberon/dynamic_array.js

@@ -1,80 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    copy: function (from, to, type){
-        var r = type.record;
-        if (r){
-            for(var f in r){
-                var fieldType = r[f];
-                if (fieldType){
-                    // temporary support for mangled fields
-                    var mangled = "$" + f;
-                    if (!from.hasOwnProperty(mangled))
-                        mangled = f;
-                    this.copy(from[mangled], to[mangled], fieldType);
-                }
-                else
-                    to[f] = from[f];
-            }
-            return;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow copy
-                Array.prototype.splice.apply(to, [0, to.length].concat(from));
-            else {
-                // deep copy
-                to.splice(0, to.length);
-                for(var i = 0; i < from.length; ++i)
-                    to.push(this.clone(from[i], a));
-            }
-        }
-    },
-    clone: function (from, type, recordCons){
-        var result;
-        var r = type.record;
-        if (r){
-            var Ctr = recordCons || from.constructor;
-            result = new Ctr();
-            this.copy(from, result, type);
-            return result;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow clone
-                return from.slice();
-
-            // deep clone
-            var length = from.length;
-            result = new Array(length);
-            for(var i = 0; i < length; ++i)
-                result[i] = this.clone(from[i], a);
-            return result;
-        }
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 function T(){
 	this.a = [];

+ 1 - 12
test/expected/eberon/generic_message_bus.js

@@ -1,15 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 function Message(){
 }

+ 1 - 83
test/expected/eberon/in_place_variables.js

@@ -1,86 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    },
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    clone: function (from, type, recordCons){
-        var result;
-        var r = type.record;
-        if (r){
-            var Ctr = recordCons || from.constructor;
-            result = new Ctr();
-            this.copy(from, result, type);
-            return result;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow clone
-                return from.slice();
-
-            // deep clone
-            var length = from.length;
-            result = new Array(length);
-            for(var i = 0; i < length; ++i)
-                result[i] = this.clone(from[i], a);
-            return result;
-        }
-    },
-    copy: function (from, to, type){
-        var r = type.record;
-        if (r){
-            for(var f in r){
-                var fieldType = r[f];
-                if (fieldType){
-                    // temporary support for mangled fields
-                    var mangled = "$" + f;
-                    if (!from.hasOwnProperty(mangled))
-                        mangled = f;
-                    this.copy(from[mangled], to[mangled], fieldType);
-                }
-                else
-                    to[f] = from[f];
-            }
-            return;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow copy
-                Array.prototype.splice.apply(to, [0, to.length].concat(from));
-            else {
-                // deep copy
-                to.splice(0, to.length);
-                for(var i = 0; i < from.length; ++i)
-                    to.push(this.clone(from[i], a));
-            }
-        }
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 function Base(){
 }

+ 24 - 153
test/expected/eberon/map.js

@@ -1,147 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    cloneMapOfScalars: function (from){
-        var result = {};
-        this.copyMapOfScalars(from, result);
-        return result;
-    },
-    copyMapOfScalars: function (from, to){
-        this.clearMap(to);
-        for(var k in from)
-            to[k] = from[k];
-    },
-    clearMap: function (map){
-        for(var p in map)
-            delete map[p];
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    },
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    },
-    makeCharArray: function (/*dimensions*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var length = forward.pop();
-
-        if (!forward.length)
-            return this.__makeCharArray(length);
-
-        function makeArray(){
-            var forward = Array.prototype.slice.call(arguments);
-            var result = new Array(forward.shift());
-            var i;
-            if (forward.length == 1){
-                var init = forward[0];
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            }
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = makeArray.apply(undefined, forward);
-            return result;
-        }
-
-        forward.push(this.__makeCharArray.bind(this, length));
-        return makeArray.apply(undefined, forward);
-    },
-    __makeCharArray: function (length){
-        var result = new Uint16Array(length);
-        this.__setupCharArrayMethods(result);
-        return result;
-    },
-    __setupCharArrayMethods: function (a){
-        var rtl = this;
-        a.charCodeAt = function(i){return this[i];};
-        a.slice = function(){
-            var result = Array.prototype.slice.apply(this, arguments);
-            rtl.__setupCharArrayMethods(result);
-            return result;
-        };
-        a.toString = function(){
-            return String.fromCharCode.apply(this, this);
-        };
-    },
-    getMappedValue: function (map, key){
-        if (!map.hasOwnProperty(key))
-            throw new Error("invalid key: " + key);
-        return map[key];
-    },
-    clone: function (from, type, recordCons){
-        var result;
-        var r = type.record;
-        if (r){
-            var Ctr = recordCons || from.constructor;
-            result = new Ctr();
-            this.copy(from, result, type);
-            return result;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow clone
-                return from.slice();
-
-            // deep clone
-            var length = from.length;
-            result = new Array(length);
-            for(var i = 0; i < length; ++i)
-                result[i] = this.clone(from[i], a);
-            return result;
-        }
-    },
-    copy: function (from, to, type){
-        var r = type.record;
-        if (r){
-            for(var f in r){
-                var fieldType = r[f];
-                if (fieldType){
-                    // temporary support for mangled fields
-                    var mangled = "$" + f;
-                    if (!from.hasOwnProperty(mangled))
-                        mangled = f;
-                    this.copy(from[mangled], to[mangled], fieldType);
-                }
-                else
-                    to[f] = from[f];
-            }
-            return;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow copy
-                Array.prototype.splice.apply(to, [0, to.length].concat(from));
-            else {
-                // deep copy
-                to.splice(0, to.length);
-                for(var i = 0; i < from.length; ++i)
-                    to.push(this.clone(from[i], a));
-            }
-        }
-    }
-};
+<rtl code>
 var test = function (){
 var m = {};
 function anonymous$1(){
@@ -150,7 +7,7 @@ function anonymous$1(){
 var r = new anonymous$1();
 var a = RTL$.makeArray(1, {});
 function RecordWithMapInitializedInConstructor(m/*MAP OF INTEGER*/){
-	this.m = RTL$.cloneMapOfScalars(m);
+	this.m = RTL$.clone(m, {map: null}, undefined);
 }
 
 function ForEach(){
@@ -165,7 +22,7 @@ function ForEach(){
 
 function makeMap(){
 	var m = {};
-	return RTL$.cloneMapOfScalars(m);
+	return RTL$.clone(m, {map: null}, undefined);
 }
 
 function ForEachWithExpression(){
@@ -269,20 +126,34 @@ function clear(){
 
 function returnLocalMap(){
 	var result = {};
-	return RTL$.cloneMapOfScalars(result);
+	return RTL$.clone(result, {map: null}, undefined);
 }
 
 function returnNonLocalMap(m/*MAP OF INTEGER*/){
-	return RTL$.cloneMapOfScalars(m);
+	return RTL$.clone(m, {map: null}, undefined);
 }
 
 function assign(a/*MAP OF INTEGER*/){
 	var v = {};
-	RTL$.copyMapOfScalars(a, v);
-	var v2 = RTL$.cloneMapOfScalars(a);
-	var v3 = RTL$.cloneMapOfScalars(v2);
-	var v4 = RTL$.cloneMapOfScalars(returnLocalMap());
-	var v5 = RTL$.cloneMapOfScalars(returnNonLocalMap(v));
+	RTL$.copy(a, v, {map: null});
+	var v2 = RTL$.clone(a, {map: null}, undefined);
+	var v3 = RTL$.clone(v2, {map: null}, undefined);
+	var v4 = RTL$.clone(returnLocalMap(), {map: null}, undefined);
+	var v5 = RTL$.clone(returnNonLocalMap(v), {map: null}, undefined);
+}
+
+function copyMapOfRecord(){
+	function T(){
+	}
+	var r1 = {};var r2 = {};
+	RTL$.copy(r2, r1, {map: {record: {}}});
+}
+
+function cloneMapOfRecord(){
+	function T(){
+	}
+	var r1 = {};
+	var r2 = RTL$.clone(r1, {map: {record: {}}}, undefined);
 }
 
 function passByRef(m/*VAR MAP OF INTEGER*/){

+ 1 - 8
test/expected/eberon/method.js

@@ -1,11 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    }
-};
+<rtl code>
 var m = function (){
 function T(){
 	this.i = 0;

+ 1 - 8
test/expected/eberon/modules.js

@@ -1,11 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    }
-};
+<rtl code>
 var m1 = function (){
 function Base(){
 }

+ 1 - 6
test/expected/eberon/string.js

@@ -1,9 +1,4 @@
-var RTL$ = {
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 var cs1 = "abc" + "cde";
 var cs2 = "\"" + "\"";

+ 1 - 20
test/expected/export.js

@@ -1,23 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    }
-};
+<rtl code>
 var m = function (){
 var ci = 123;
 function T1(){

+ 1 - 8
test/expected/is.js

@@ -1,11 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    }
-};
+<rtl code>
 var m = function (){
 function Base(){
 }

+ 1 - 66
test/expected/len.js

@@ -1,69 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    makeCharArray: function (/*dimensions*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var length = forward.pop();
-
-        if (!forward.length)
-            return this.__makeCharArray(length);
-
-        function makeArray(){
-            var forward = Array.prototype.slice.call(arguments);
-            var result = new Array(forward.shift());
-            var i;
-            if (forward.length == 1){
-                var init = forward[0];
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            }
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = makeArray.apply(undefined, forward);
-            return result;
-        }
-
-        forward.push(this.__makeCharArray.bind(this, length));
-        return makeArray.apply(undefined, forward);
-    },
-    __makeCharArray: function (length){
-        var result = new Uint16Array(length);
-        this.__setupCharArrayMethods(result);
-        return result;
-    },
-    __setupCharArrayMethods: function (a){
-        var rtl = this;
-        a.charCodeAt = function(i){return this[i];};
-        a.slice = function(){
-            var result = Array.prototype.slice.apply(this, arguments);
-            rtl.__setupCharArrayMethods(result);
-            return result;
-        };
-        a.toString = function(){
-            return String.fromCharCode.apply(this, this);
-        };
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 var s1 = "\"";
 var a1 = RTL$.makeArray(10, 0);

+ 1 - 54
test/expected/modules.js

@@ -1,57 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    },
-    typeGuard: function (from, to){
-        if (!from)
-            return from;
-        if (!(from instanceof to)){
-            var fromStr;
-            var toStr;
-            
-            if (from && from.constructor && from.constructor.name)
-                fromStr = "" + from.constructor.name;
-            else
-                fromStr = "" + from;
-            
-            if (to.name)
-                toStr = "" + to.name;
-            else
-                toStr = "" + to;
-            
-            var msg = "typeguard assertion failed";
-            if (fromStr || toStr)               
-                msg += ": '" + fromStr + "' is not an extension of '" + toStr + "'";
-            throw new Error(msg);
-        }
-        return from;
-    },
-    makeRef: function (obj, prop){
-        return {set: function(v){ obj[prop] = v; },
-                get: function(){ return obj[prop]; }};
-    },
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    }
-};
+<rtl code>
 var m1 = function (){
 var ci = 123;
 function Base(){

+ 1 - 6
test/expected/odd.js

@@ -1,9 +1,4 @@
-var RTL$ = {
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 var i = 0;
 RTL$.assert(1 & 1);

+ 1 - 6
test/expected/ord.js

@@ -1,9 +1,4 @@
-var RTL$ = {
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 var ch = 0;
 var set = 0;

+ 1 - 24
test/expected/parentheses.js

@@ -1,27 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 var ch = 0;
 var i = 0;

+ 1 - 8
test/expected/proc.js

@@ -1,11 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    }
-};
+<rtl code>
 var m = function (){
 var i = 0;
 var byte = 0;

+ 1 - 87
test/expected/record.js

@@ -1,90 +1,4 @@
-var RTL$ = {
-    extend: function (cons, base){
-        function Type(){}
-        Type.prototype = base.prototype;
-        cons.prototype = new Type();
-        cons.prototype.constructor = cons;
-    },
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    copy: function (from, to, type){
-        var r = type.record;
-        if (r){
-            for(var f in r){
-                var fieldType = r[f];
-                if (fieldType){
-                    // temporary support for mangled fields
-                    var mangled = "$" + f;
-                    if (!from.hasOwnProperty(mangled))
-                        mangled = f;
-                    this.copy(from[mangled], to[mangled], fieldType);
-                }
-                else
-                    to[f] = from[f];
-            }
-            return;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow copy
-                Array.prototype.splice.apply(to, [0, to.length].concat(from));
-            else {
-                // deep copy
-                to.splice(0, to.length);
-                for(var i = 0; i < from.length; ++i)
-                    to.push(this.clone(from[i], a));
-            }
-        }
-    },
-    clone: function (from, type, recordCons){
-        var result;
-        var r = type.record;
-        if (r){
-            var Ctr = recordCons || from.constructor;
-            result = new Ctr();
-            this.copy(from, result, type);
-            return result;
-        }
-        var a = type.array;
-        if (a !== undefined ){
-            if (a === null)
-                // shallow clone
-                return from.slice();
-
-            // deep clone
-            var length = from.length;
-            result = new Array(length);
-            for(var i = 0; i < length; ++i)
-                result[i] = this.clone(from[i], a);
-            return result;
-        }
-    },
-    makeRef: function (obj, prop){
-        return {set: function(v){ obj[prop] = v; },
-                get: function(){ return obj[prop]; }};
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    }
-};
+<rtl code>
 var m = function (){
 function Base1(){
 }

+ 1 - 50
test/expected/set.js

@@ -1,53 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    makeSet: function (/*...*/){
-        var result = 0;
-        
-        function checkBit(b){
-            if (b < 0 || b > 31)
-                throw new Error("integers between 0 and 31 expected, got " + b);
-        }
-
-        function setBit(b){
-            checkBit(b);
-            result |= 1 << b;
-        }
-        
-        for(var i = 0; i < arguments.length; ++i){
-            var b = arguments[i];
-            if (b instanceof Array){
-                var from = b[0];
-                var to = b[1];
-                if (from < to)
-                    throw new Error("invalid SET diapason: " + from + ".." + to);
-                for(var bi = from; bi <= to; ++bi)
-                    setBit(bi);
-            }
-            else
-                setBit(b);
-        }
-        return result;
-    },
-    setInclL: function (l, r){return (l & r) == l;},
-    setInclR: function (l, r){return (l & r) == r;}
-};
+<rtl code>
 var m = function (){
 var ci = 3;
 var cb = true;

+ 1 - 64
test/expected/string.js

@@ -1,67 +1,4 @@
-var RTL$ = {
-    makeCharArray: function (/*dimensions*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var length = forward.pop();
-
-        if (!forward.length)
-            return this.__makeCharArray(length);
-
-        function makeArray(){
-            var forward = Array.prototype.slice.call(arguments);
-            var result = new Array(forward.shift());
-            var i;
-            if (forward.length == 1){
-                var init = forward[0];
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            }
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = makeArray.apply(undefined, forward);
-            return result;
-        }
-
-        forward.push(this.__makeCharArray.bind(this, length));
-        return makeArray.apply(undefined, forward);
-    },
-    __makeCharArray: function (length){
-        var result = new Uint16Array(length);
-        this.__setupCharArrayMethods(result);
-        return result;
-    },
-    __setupCharArrayMethods: function (a){
-        var rtl = this;
-        a.charCodeAt = function(i){return this[i];};
-        a.slice = function(){
-            var result = Array.prototype.slice.apply(this, arguments);
-            rtl.__setupCharArrayMethods(result);
-            return result;
-        };
-        a.toString = function(){
-            return String.fromCharCode.apply(this, this);
-        };
-    },
-    assignArrayFromString: function (a, s){
-        var i;
-        for(i = 0; i < s.length; ++i)
-            a[i] = s.charCodeAt(i);
-        for(i = s.length; i < a.length; ++i)
-            a[i] = 0;
-    },
-    assert: function (condition){
-        if (!condition)
-            throw new Error("assertion failed");
-    },
-    strCmp: function (s1, s2){
-        var cmp = 0;
-        var i = 0;
-        while (!cmp && i < s1.length && i < s2.length){
-            cmp = s1.charCodeAt(i) - s2.charCodeAt(i);
-            ++i;
-        }
-        return cmp ? cmp : s1.length - s2.length;
-    }
-};
+<rtl code>
 var m = function (){
 var s1 = "\"";
 var s2 = "ABC";

+ 1 - 24
test/expected/var_parameter.js

@@ -1,27 +1,4 @@
-var RTL$ = {
-    makeArray: function (/*dimensions, initializer*/){
-        var forward = Array.prototype.slice.call(arguments);
-        var result = new Array(forward.shift());
-        var i;
-        if (forward.length == 1){
-            var init = forward[0];
-            if (typeof init == "function")
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init();
-            else
-                for(i = 0; i < result.length; ++i)
-                    result[i] = init;
-        }
-        else
-            for(i = 0; i < result.length; ++i)
-                result[i] = this.makeArray.apply(this, forward);
-        return result;
-    },
-    makeRef: function (obj, prop){
-        return {set: function(v){ obj[prop] = v; },
-                get: function(){ return obj[prop]; }};
-    }
-};
+<rtl code>
 var m = function (){
 function R(){
 	this.i = 0;

+ 18 - 0
test/input/eberon/map.ob

@@ -157,6 +157,24 @@ BEGIN
     v5 <- returnNonLocalMap(v);
 END;
 
+PROCEDURE copyMapOfRecord();
+TYPE
+    T = RECORD END;
+VAR
+    r1, r2: MAP OF T;
+BEGIN
+    r1 := r2;
+END;
+
+PROCEDURE cloneMapOfRecord();
+TYPE
+    T = RECORD END;
+VAR
+    r1: MAP OF T;
+BEGIN
+    r2 <- r1;
+END;
+
 PROCEDURE passByRef(VAR m: MapOfInteger);
 BEGIN
     m["abc"] := 123;

+ 25 - 3
test/input/eberon/run/map.ob

@@ -80,14 +80,36 @@ BEGIN
     ASSERT(m2["a"] = 1);
     m2["a"] := 2;
     ASSERT(m1["a"] = 1);
-(*
+
     mr1["a"] := T();
     mr1["a"].i := 1;
     mr2 := mr1;
     ASSERT(mr2["a"].i = 1);
     mr1["a"].i := 2;
-    ASSERT(mr1["a"].i = 1);
-    *)
+    ASSERT(mr2["a"].i = 1);
+END;
+
+PROCEDURE testClone();
+TYPE
+    T = RECORD
+        i: INTEGER;
+    END;
+VAR
+    m1: MAP OF INTEGER;
+    mr1: MAP OF T;
+BEGIN
+    m1["a"] := 1;
+    m2 <- m1;
+    ASSERT(m2["a"] = 1);
+    m2["a"] := 2;
+    ASSERT(m1["a"] = 1);
+
+    mr1["a"] := T();
+    mr1["a"].i := 1;
+    mr2 <- mr1;
+    ASSERT(mr2["a"].i = 1);
+    mr1["a"].i := 2;
+    ASSERT(mr2["a"].i = 1);
 END;
 
 BEGIN

+ 13 - 0
test/test_compile.js

@@ -13,7 +13,20 @@ function normalizeLineEndings(text){
                .replace(/\s+$/,''); // ending spaces
 }
 
+function filterOutRtlCode(text){
+    var prefix = "var RTL$ = {";
+    if (text.substr(0, prefix.length) != prefix)
+        return text;
+    
+    var suffix = "\n};";
+    var end = text.indexOf(suffix);
+    if (end == -1)
+        return text;
+    return "<rtl code>" + text.substr(end + suffix.length);
+}
+
 function compareResults(result, name, dirs){
+    result = filterOutRtlCode(result);
     fs.writeFileSync(path.join(dirs.output, name), result);
     var expected = fs.readFileSync(path.join(dirs.expected, name), "utf8");
     if (normalizeLineEndings(result) != normalizeLineEndings(expected))