Selaa lähdekoodia

Code generation for constructor.

Vladislav Folts 10 vuotta sitten
vanhempi
commit
9bf2b4bfe6

BIN
bin/compiled.zip


+ 21 - 10
src/context.js

@@ -2,6 +2,7 @@
 
 var Cast = require("js/Cast.js");
 var Code = require("js/Code.js");
+var CodeGenerator = require("js/CodeGenerator.js");
 var Errors = require("js/Errors.js");
 var Module = require("js/Module.js");
 var op = require("js/Operator.js");
@@ -13,7 +14,7 @@ var Symbol = require("js/Symbols.js");
 var Type = require("js/Types.js");
 
 var basicTypes = Type.basic();
-var nullCodeGenerator = Code.nullGenerator();
+var nullCodeGenerator = CodeGenerator.nullGenerator();
 var nilType = Type.nil();
 
 var castOperations = op.castOperations();
@@ -1167,7 +1168,7 @@ exports.SetElement = ChainedContext.extend({
         this.__fromValue = undefined;
         this.__to = undefined;
         this.__toValue = undefined;
-        this.__expr = Code.makeSimpleGenerator();
+        this.__expr = CodeGenerator.makeSimpleGenerator();
     },
     codeGenerator: function(){return this.__expr;},
     handleExpression: function(e){
@@ -1176,7 +1177,7 @@ exports.SetElement = ChainedContext.extend({
             {
             this.__from = this.__expr.result();
             this.__fromValue = value;
-            this.__expr = Code.makeSimpleGenerator();
+            this.__expr = CodeGenerator.makeSimpleGenerator();
             }
         else{
             this.__to = this.__expr.result();
@@ -1491,7 +1492,7 @@ exports.For = ChainedContext.extend({
         ChainedContext.prototype.init.call(this, context);
         this.__var = undefined;
         this.__initExprParsed = false;
-        this.__toExpr = Code.makeSimpleGenerator();
+        this.__toExpr = CodeGenerator.makeSimpleGenerator();
         this.__toParsed = false;
         this.__by_parsed = false;
         this.__by = undefined;
@@ -1757,16 +1758,19 @@ exports.RecordDecl = ChainedContext.extend({
             throw new Errors.Error("recursive inheritance: '"
                 + Type.typeName(this.__type) + "'");
 
-        var gen = this.codeGenerator();
-        var qualifiedBase = this.qualifyScope(Type.recordScope(type)) + Type.typeName(type); 
-        gen.write(this.language().rtl.extend(this.__cons, qualifiedBase) + ";\n");
-
         Type.setRecordBase(this.__type, type);
     },
     endParse: function(){
+        var gen = this.codeGenerator();
+        this.codeGenerator().write(
+              this._generateConstructor()
+            + this._generateInheritance()
+            );
+    },
+    _generateConstructor: function(){
         var type = this.__type;
         var baseType = Type.recordBase(type);
-        var gen = this.codeGenerator();
+        var gen = CodeGenerator.makeGenerator();
         var qualifiedBase = baseType ? this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType) : undefined; 
         gen.write("function " + this.__cons + "()");
         gen.openScope();
@@ -1777,8 +1781,15 @@ exports.RecordDecl = ChainedContext.extend({
             var fieldType = ownFields[f].type();
             gen.write("this." + mangleField(f, fieldType) + " = " + fieldType.initializer(this) + ";\n");
         }
-
         gen.closeScope("");
+        return gen.result();
+    },
+    _generateInheritance: function(){
+        var base = Type.recordBase(this.__type);
+        if (!base)
+            return "";
+        var qualifiedBase = this.qualifyScope(Type.recordScope(base)) + Type.typeName(base); 
+        return this.language().rtl.extend(this.__cons, qualifiedBase) + ";\n";
     },
     _makeField: function(field, type){
         return new RecordField(field, type);

+ 26 - 5
src/eberon/eberon_context.js

@@ -3,6 +3,7 @@
 var Cast = require("js/Cast.js");
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
+var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var EberonDynamicArray= require("js/EberonDynamicArray.js");
 var EberonScope = require("js/EberonScope.js");
@@ -260,7 +261,7 @@ var InPlaceVariableInit = Context.Chained.extend({
         this._symbol = undefined;
         this._code = undefined;
     },
-    codeGenerator: function(){return Code.nullGenerator();},
+    codeGenerator: function(){return CodeGenerator.nullGenerator();},
     handleIdent: function(id){
         this.__id = id;
     },
@@ -337,7 +338,7 @@ var AssignmentOrProcedureCall = Context.Chained.extend({
     handleExpression: function(e){
         this.__right = e;
     },
-    codeGenerator: function(){return Code.nullGenerator();},
+    codeGenerator: function(){return CodeGenerator.nullGenerator();},
     endParse: function(){
         var d = this.__left;
         var type = d.type();
@@ -402,6 +403,7 @@ var RecordType = Class.extend.call(Type.Record, {
         this.__declaredAsVariable = false;
         this.__lazyDefinitions = {};
         this.__nonExportedMethods = [];
+        this.__inheritanceCode = undefined;
     },
     initializer: function(context, forNew){
         if (this.__finalized){
@@ -417,6 +419,7 @@ var RecordType = Class.extend.call(Type.Record, {
 
         return Type.Record.prototype.initializer.call(this, context);
     },
+    customConstructor: function(){return this.__customConstructor;},
     findSymbol: function(id){
         var result = this.__hasMethodDeclaration(id);
         if (!result)
@@ -445,12 +448,16 @@ var RecordType = Class.extend.call(Type.Record, {
         if (!methodId.exported())
             this.__nonExportedMethods.push(id);
     },
+    setInheritanceCode: function(code){
+        this.__inheritanceCode = code;
+    },
     defineConstructor: function(type){
         if (this.__customConstructor)
             throw new Errors.Error("constructor '" + Type.typeName(this) + "' already defined");
         if (type.result())
             throw new Errors.Error("constructor '" + Type.typeName(this) + "' cannot have result type specified");
         this.__customConstructor = type;
+        return this.__inheritanceCode;
     },
     defineMethod: function(methodId, type){
         var base = Type.recordBase(this);
@@ -636,6 +643,17 @@ var RecordDecl = Context.RecordDecl.extend({
     },
     _makeField: function(field, type){
         return new RecordField(field, type, this.__type);
+    },
+    endParse: function(){
+        var gen = this.codeGenerator();
+        var pos = gen.makeInsertion();
+        var type = this.type();
+        var inheritanceCode = this._generateInheritance();
+        type.setInheritanceCode(inheritanceCode);
+        this.currentScope().addFinalizer(function(){
+            if (!this.__type.customConstructor())
+                gen.insert(pos, this._generateConstructor() + inheritanceCode);
+        }.bind(this));
     }
 });
 
@@ -701,7 +719,8 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
     },
     _prolog: function(){
         return this.__boundType
-            ? Type.typeName(this.__boundType) + ".prototype." + this.__methodId.id() + " = function("
+            ? this.__isConstructor ? "function " + Type.typeName(this.__boundType) + "("
+                                   : Type.typeName(this.__boundType) + ".prototype." + this.__methodId.id() + " = function("
             : Context.ProcDecl.prototype._prolog.call(this);
     },
     _makeArgumentVariable: function(arg){
@@ -738,6 +757,8 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
             this.__endingId = id;
     },
     endParse: function(){
+        Context.ProcDecl.prototype.endParse.call(this);
+
         if (this.__boundType){
             if (this.__endingId){
                 var expected 
@@ -754,11 +775,11 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
             }
 
             if (this.__isConstructor)
-                this.__boundType.defineConstructor(this.__methodType);
+                this.codeGenerator().write(
+                    this.__boundType.defineConstructor(this.__methodType));
             else
                 this.__boundType.defineMethod(this.__methodId, this.__methodType);
         }
-        Context.ProcDecl.prototype.endParse.call(this);
     },
     __handleSuperCall: function(){
         if (!this.__methodId)

+ 2 - 1
src/nodejs.js

@@ -2,6 +2,7 @@
 
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
+var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var oc = require("oc.js");
 var RTL = require("rtl_code.js").RTL;
@@ -80,7 +81,7 @@ function compile(sources, language, handleErrors, includeDirs, outDir, importDir
             },
             language.grammar,
             function(moduleResolver){return new Context.Context(
-                { codeGenerator: Code.makeGenerator(),
+                { codeGenerator: CodeGenerator.makeGenerator(),
                   moduleGenerator: moduleCode,
                   rtl: rtl,
                   types: language.types,

+ 2 - 108
src/ob/Code.ob

@@ -1,5 +1,6 @@
 MODULE Code;
 IMPORT 
+    CodeGenerator,
     JsMap, 
     Errors,
     Object, 
@@ -9,30 +10,8 @@ IMPORT
     Precedence := CodePrecedence, 
     String, 
     Types;
-CONST
-    kTab = 09X;
 
 TYPE
-    IGenerator = RECORD
-        PROCEDURE write(s: STRING);
-        PROCEDURE openScope();
-        PROCEDURE closeScope(ending: STRING);
-        PROCEDURE result(): STRING
-    END;
-
-    PIGenerator = POINTER TO IGenerator;
-
-    NullGenerator = RECORD(IGenerator)
-    END;
-
-    SimpleGenerator = RECORD(NullGenerator)
-        mResult: STRING
-    END;
-
-    Generator = RECORD(SimpleGenerator)
-        indent: INTEGER
-    END;
-
     RefCodeProc = PROCEDURE(s: STRING): STRING;
 
     Designator* = RECORD
@@ -105,75 +84,6 @@ TYPE
         result: STRING
     END;
 
-VAR
-    nullGenerator*: NullGenerator;
-
-PROCEDURE NullGenerator.write(s: STRING);
-END NullGenerator.write;
-
-PROCEDURE NullGenerator.openScope();
-END NullGenerator.openScope;
-
-PROCEDURE NullGenerator.closeScope(ending: STRING);
-END NullGenerator.closeScope;
-
-PROCEDURE NullGenerator.result(): STRING;
-    RETURN ""
-END NullGenerator.result;
-
-PROCEDURE SimpleGenerator.write(s: STRING);
-BEGIN
-    SELF.mResult := SELF.mResult + s;
-END SimpleGenerator.write;
-
-PROCEDURE SimpleGenerator.result(): STRING;
-    RETURN SELF.mResult
-END SimpleGenerator.result;
-
-PROCEDURE putIndent(s: STRING; indent: INTEGER): STRING;
-BEGIN
-    result <- s;
-    FOR i <- 0 TO indent - 1 DO
-        result := result + kTab;
-    END;
-    RETURN result
-END putIndent;
-
-PROCEDURE Generator.write(s: STRING);
-VAR
-    pos: INTEGER;
-    index: INTEGER;
-BEGIN
-    index := String.indexOf(s, Stream.kCR);
-    WHILE index # -1 DO
-        INC(index);
-        SELF.mResult := SELF.mResult + String.substr(s, pos, index - pos);
-        SELF.mResult := putIndent(SELF.mResult, SELF.indent);
-        pos := index;
-        index := String.indexOfFrom(s, Stream.kCR, pos);
-    END;
-    SELF.mResult := SELF.mResult + String.substr(s, pos, LEN(s) - pos);
-END Generator.write;
-
-PROCEDURE Generator.openScope();
-BEGIN
-    INC(SELF.indent);
-    SELF.mResult := SELF.mResult + "{" + Stream.kCR;
-    SELF.mResult := putIndent(SELF.mResult, SELF.indent);
-END Generator.openScope;
-
-PROCEDURE Generator.closeScope(ending: STRING);
-BEGIN
-    DEC(SELF.indent);
-    SELF.mResult := String.substr(SELF.mResult, 0, LEN(SELF.mResult) - 1) + "}";
-    IF LEN(ending) # 0 THEN
-        SELF.write(ending);
-    ELSE
-        SELF.mResult := SELF.mResult + Stream.kCR;
-        SELF.mResult := putIndent(SELF.mResult, SELF.indent);
-    END;
-END Generator.closeScope;
-
 PROCEDURE Expression.code(): STRING;
     RETURN SELF.mCode
 END Expression.code;
@@ -429,7 +339,7 @@ BEGIN
         IF LEN(closure.result) # 0 THEN
             closure.result := closure.result + "," + Stream.kCR;
         END;
-        closure.result := closure.result + kTab + s.id() + ": " + code;
+        closure.result := closure.result + CodeGenerator.kTab + s.id() + ": " + code;
     END;
 END genExports;
 
@@ -461,22 +371,6 @@ BEGIN
     RETURN result
 END ModuleGenerator.epilog;
 
-PROCEDURE makeSimpleGenerator*(): PIGenerator;
-VAR
-    result: POINTER TO SimpleGenerator;
-BEGIN
-    NEW(result);
-    RETURN result
-END makeSimpleGenerator;
-
-PROCEDURE makeGenerator*(): PIGenerator;
-VAR
-    result: POINTER TO Generator;
-BEGIN
-    NEW(result);
-    RETURN result
-END makeGenerator;
-
 PROCEDURE makeModuleGenerator*(name: STRING; imports: JsMap.Strings): PModuleGenerator;
 VAR
     result: PModuleGenerator;

+ 164 - 0
src/ob/CodeGenerator.ob

@@ -0,0 +1,164 @@
+MODULE CodeGenerator;
+IMPORT
+    Stream, String;
+CONST
+    kTab* = 09X;
+TYPE
+    IGenerator = RECORD
+        PROCEDURE write(s: STRING);
+        PROCEDURE openScope();
+        PROCEDURE closeScope(ending: STRING);
+        PROCEDURE result(): STRING;
+
+        PROCEDURE makeInsertion(): INTEGER;
+        PROCEDURE insert(insertion: INTEGER; code: STRING);
+    END;
+
+    PIGenerator = POINTER TO IGenerator;
+
+    NullGenerator = RECORD(IGenerator)
+    END;
+
+    SimpleGenerator = RECORD(NullGenerator)
+        mResult: STRING
+    END;
+
+    Insertion = RECORD
+        pos: INTEGER;
+        indent: INTEGER;
+        code: STRING;
+    END;
+
+    Generator = RECORD(SimpleGenerator)
+        indent: INTEGER;
+        insertions: ARRAY * OF Insertion;
+    END;
+
+VAR
+    nullGenerator*: NullGenerator;
+
+PROCEDURE NullGenerator.write(s: STRING);
+END NullGenerator.write;
+
+PROCEDURE NullGenerator.openScope();
+END NullGenerator.openScope;
+
+PROCEDURE NullGenerator.closeScope(ending: STRING);
+END NullGenerator.closeScope;
+
+PROCEDURE NullGenerator.makeInsertion(): INTEGER;
+    RETURN 0;
+END;
+
+PROCEDURE NullGenerator.insert(insertion: INTEGER; code: STRING);
+END;
+
+PROCEDURE NullGenerator.result(): STRING;
+    RETURN "";
+END NullGenerator.result;
+
+PROCEDURE SimpleGenerator.write(s: STRING);
+BEGIN
+    SELF.mResult := SELF.mResult + s;
+END SimpleGenerator.write;
+
+PROCEDURE SimpleGenerator.result(): STRING;
+    RETURN SELF.mResult
+END SimpleGenerator.result;
+
+PROCEDURE makeIndent(count: INTEGER): STRING;
+VAR
+    result: STRING;
+BEGIN
+    FOR i <- 0 TO count - 1 DO
+        result := result + kTab;
+    END;
+    RETURN result
+END;
+
+PROCEDURE indentText(s: STRING; indent: INTEGER): STRING;
+VAR
+    result: STRING;
+BEGIN
+    index <- String.indexOf(s, Stream.kCR);
+    pos <- 0;
+    WHILE index # -1 DO
+        INC(index);
+        result := result + String.substr(s, pos, index - pos) + makeIndent(indent);
+        pos := index;
+        index := String.indexOfFrom(s, Stream.kCR, pos);
+    END;
+    RETURN result + String.substr(s, pos, LEN(s) - pos);
+END;
+
+PROCEDURE Generator.write(s: STRING);
+BEGIN
+    SELF.mResult := SELF.mResult + indentText(s, SELF.indent);
+END;
+
+PROCEDURE Generator.openScope();
+BEGIN
+    INC(SELF.indent);
+    SELF.mResult := SELF.mResult + "{" + Stream.kCR + makeIndent(SELF.indent);
+END Generator.openScope;
+
+PROCEDURE Generator.closeScope(ending: STRING);
+BEGIN
+    DEC(SELF.indent);
+    SELF.mResult := String.substr(SELF.mResult, 0, LEN(SELF.mResult) - 1) + "}";
+    IF LEN(ending) # 0 THEN
+        SELF.write(ending);
+    ELSE
+        SELF.mResult := SELF.mResult + Stream.kCR + makeIndent(SELF.indent);
+    END;
+END Generator.closeScope;
+
+PROCEDURE Generator.makeInsertion(): INTEGER;
+VAR
+    insertion: Insertion;
+BEGIN
+    insertion.pos := LEN(SELF.mResult);
+    insertion.indent := SELF.indent;
+    result <- LEN(SELF.insertions);
+    SELF.insertions.add(insertion);
+    RETURN result;
+END;
+
+PROCEDURE Generator.insert(insertion: INTEGER; code: STRING);
+BEGIN
+    SELF.insertions[insertion].code := code;
+END;
+
+PROCEDURE Generator.result(): STRING;
+VAR
+    result: STRING;
+BEGIN
+    pos <- 0;
+    FOR i <- 0 TO LEN(SELF.insertions) - 1 DO
+        nextPos <- SELF.insertions[i].pos;
+        result := result 
+                + String.substr(SELF.mResult, pos, nextPos - pos) 
+                + indentText(SELF.insertions[i].code, SELF.insertions[i].indent);
+        pos := nextPos;
+    END;
+    result := result + String.substr(SELF.mResult, pos, LEN(SELF.mResult) - pos);
+    RETURN result
+END Generator.result;
+
+PROCEDURE makeSimpleGenerator*(): PIGenerator;
+VAR
+    result: POINTER TO SimpleGenerator;
+BEGIN
+    NEW(result);
+    RETURN result
+END makeSimpleGenerator;
+
+PROCEDURE makeGenerator*(): PIGenerator;
+VAR
+    result: POINTER TO Generator;
+BEGIN
+    NEW(result);
+    RETURN result
+END makeGenerator;
+
+END CodeGenerator.

+ 1 - 1
src/ob/Scope.ob

@@ -138,7 +138,7 @@ END unresolved;
 
 PROCEDURE Type.close();
 BEGIN
-    FOR i <- 0 TO LEN(SELF.finalizers) - 1 DO
+    FOR i <- LEN(SELF.finalizers) - 1 TO 0 BY -1 DO
         finalizer <- SELF.finalizers[i];
         finalizer.proc(finalizer.closure);
     END;

+ 3 - 2
src/oberon/oberon_context.js

@@ -1,6 +1,7 @@
 "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 op = require("js/Operator.js");
@@ -29,7 +30,7 @@ var ProcedureCall = Context.Chained.extend({
         this.__type = undefined;
         this.__id = undefined;
         this.__procCall = undefined;
-        this.__code = Code.makeSimpleGenerator();
+        this.__code = CodeGenerator.makeSimpleGenerator();
     },
     setDesignator: function(d){
         this.__type = d.type();
@@ -99,7 +100,7 @@ var Assignment = Context.Chained.extend({
         Context.Chained.prototype.init.call(this, context);
         this.__left = undefined;
     },
-    codeGenerator: function(){return Code.nullGenerator();},
+    codeGenerator: function(){return CodeGenerator.nullGenerator();},
     setDesignator: function(d){
         this.__left = Code.makeExpression(d.code(), d.type(), d);
     },

+ 2 - 1
src/oc.js

@@ -2,6 +2,7 @@
 
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
+var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var Lexer = require("js/Lexer.js");
@@ -128,7 +129,7 @@ function compile(text, language, handleErrors){
             language.grammar,
             function(moduleResolver){
                 return new Context.Context(
-                    { codeGenerator: Code.makeGenerator(),
+                    { codeGenerator: CodeGenerator.makeGenerator(),
                       moduleGenerator: moduleCode,
                       rtl: rtl,
                       types: language.types,

+ 3 - 3
test/expected/cast.js

@@ -33,21 +33,21 @@ var RTL$ = {
 var m = function (){
 function Base(){
 }
-RTL$.extend(Derived1, Base);
 function Derived1(){
 	Base.call(this);
 	this.field1 = 0;
 }
-RTL$.extend(Derived2, Derived1);
+RTL$.extend(Derived1, Base);
 function Derived2(){
 	Derived1.call(this);
 	this.field2 = 0;
 }
-RTL$.extend(PAnonymousDerived, Base);
+RTL$.extend(Derived2, Derived1);
 function PAnonymousDerived(){
 	Base.call(this);
 	this.field3 = 0;
 }
+RTL$.extend(PAnonymousDerived, Base);
 var pb = null;
 var pd1 = null;
 var pd2 = null;

+ 15 - 0
test/expected/eberon/constructor.js

@@ -0,0 +1,15 @@
+var RTL$ = {
+    extend: function (cons, base){
+        function Type(){}
+        Type.prototype = base.prototype;
+        cons.prototype = new Type();
+        cons.prototype.constructor = cons;
+    }
+};
+var m = function (){
+function T(){
+}
+function Derived(){
+}
+RTL$.extend(Derived, T);
+}();

+ 2 - 2
test/expected/eberon/generic_message_bus.js

@@ -13,16 +13,16 @@ var RTL$ = {
 var m = function (){
 function Message(){
 }
-RTL$.extend(Derived1, Message);
 function Derived1(){
 	Message.call(this);
 	this.derivedField1 = false;
 }
-RTL$.extend(Derived2, Message);
+RTL$.extend(Derived1, Message);
 function Derived2(){
 	Message.call(this);
 	this.derivedField2 = false;
 }
+RTL$.extend(Derived2, Message);
 var d1 = new Derived1();
 var d2 = new Derived2();
 

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

@@ -50,11 +50,11 @@ var RTL$ = {
 var m = function (){
 function Base(){
 }
-RTL$.extend(Derived, Base);
 function Derived(){
 	Base.call(this);
 	this.derivedField = 0;
 }
+RTL$.extend(Derived, Base);
 var r = new Derived();
 var pbVar = null;
 var pdVar = null;

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

@@ -10,10 +10,10 @@ var m = function (){
 function T(){
 	this.i = 0;
 }
-RTL$.extend(D, T);
 function D(){
 	T.call(this);
 }
+RTL$.extend(D, T);
 var dp = null;
 T.prototype.p = function(){
 	this.i = 123;

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

@@ -16,10 +16,10 @@ return {
 }
 }();
 var m2 = function (m1){
-RTL$.extend(T, m1.Base);
 function T(){
 	m1.Base.call(this);
 }
+RTL$.extend(T, m1.Base);
 T.prototype.p = function(){
 	m1.Base.prototype.p.call(this);
 }

+ 2 - 2
test/expected/is.js

@@ -9,16 +9,16 @@ var RTL$ = {
 var m = function (){
 function Base(){
 }
-RTL$.extend(Derived1, Base);
 function Derived1(){
 	Base.call(this);
 	this.field1 = 0;
 }
-RTL$.extend(Derived2, Derived1);
+RTL$.extend(Derived1, Base);
 function Derived2(){
 	Derived1.call(this);
 	this.field2 = 0;
 }
+RTL$.extend(Derived2, Derived1);
 var pb = null;
 var pd1 = null;
 var pd2 = null;

+ 1 - 1
test/expected/len.js

@@ -80,4 +80,4 @@ i = p2(a2);
 RTL$.assert(a3.length == 20);
 RTL$.assert(s1.length == 1);
 RTL$.assert("abc".length == 3);
-}();
+}();

+ 4 - 4
test/expected/modules.js

@@ -57,16 +57,16 @@ var ci = 123;
 function Base(){
 	this.i = 0;
 }
-RTL$.extend(T, Base);
 function T(){
 	Base.call(this);
 }
+RTL$.extend(T, Base);
 function TPA(){
 }
-RTL$.extend(TPB, Base);
 function TPB(){
 	Base.call(this);
 }
+RTL$.extend(TPB, Base);
 var i = 0;
 function anonymous$1(){
 	this.i = 0;
@@ -104,11 +104,11 @@ return {
 }
 }();
 var m2 = function (m1){
-RTL$.extend(T, m1.T);
 function T(){
 	m1.T.call(this);
 	this.i2 = 0;
 }
+RTL$.extend(T, m1.T);
 var r = new m1.T();
 var r2 = new T();
 var pb = null;
@@ -134,10 +134,10 @@ p(m1.ci);
 ref(RTL$.makeRef(m1.pr2(), "i"));
 }(m1);
 var m3 = function (m1, m2){
-RTL$.extend(T, m2.T);
 function T(){
 	m2.T.call(this);
 }
+RTL$.extend(T, m2.T);
 var r = new m2.T();
 var r2 = new T();
 var a = RTL$.makeArray(3, function(){return new m2.Base();});

+ 1 - 1
test/expected/nodejs/modules/m1.js

@@ -3,10 +3,10 @@ var ci = 123;
 function Base(){
 	this.i = 0;
 }
-RTL$.extend(T, Base);
 function T(){
 	Base.call(this);
 }
+RTL$.extend(T, Base);
 function TPA(){
 }
 var i = 0;

+ 1 - 1
test/expected/proc.js

@@ -14,11 +14,11 @@ function p1(arg1/*INTEGER*/){
 	function T1(){
 		this.field1 = 0;
 	}
-	RTL$.extend(T2, T1);
 	function T2(){
 		T1.call(this);
 		this.field2 = false;
 	}
+	RTL$.extend(T2, T1);
 	var i = 0;var j = 0;
 	var b = false;
 	var t1 = new T1();

+ 1 - 1
test/expected/record.js

@@ -44,11 +44,11 @@ var RTL$ = {
 var m = function (){
 function Base1(){
 }
-RTL$.extend(T1, Base1);
 function T1(){
 	Base1.call(this);
 	this.i = 0;
 }
+RTL$.extend(T1, Base1);
 function RecordWithInnerRecord(){
 	this.$r = new T1();
 }

+ 15 - 0
test/input/eberon/constructor.ob

@@ -0,0 +1,15 @@
+MODULE m;
+TYPE
+    T = RECORD
+    END;
+
+    Derived = RECORD(T)
+    END;
+
+PROCEDURE T();
+END;
+
+PROCEDURE Derived();
+END;
+
+END m.

+ 35 - 1
test/test_unit.js

@@ -2,6 +2,7 @@
 
 var assert = require("rtl.js").assert;
 var Class = require("rtl.js").Class;
+var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var Grammar = require("grammar.js");
 var Test = require("test.js");
@@ -1431,13 +1432,46 @@ return {
     };
 }
 
+function makeCodeSuite(){
+    return {
+        "insertion": pass(
+            function(){
+                var g = CodeGenerator.makeGenerator();
+                g.write("a");
+                var i = g.makeInsertion();
+                g.write("b");
+                g.insert(i, "c");
+                assert(g.result() == "acb");
+            },
+            function(){
+                var g = CodeGenerator.makeGenerator();
+                g.write("ab");
+                var i1 = g.makeInsertion();
+                var i2 = g.makeInsertion();
+                g.write("cd");
+                g.insert(i1, "123");
+                g.insert(i2, "345");
+                assert(g.result() == "ab123345cd");
+            },
+            function(){
+                var g = CodeGenerator.makeGenerator();
+                g.write("ab");
+                var i = g.makeInsertion();
+                g.write("cd");
+                assert(g.result() == "abcd");
+            }
+        )
+    };
+}
+
 var result = Test.run({
     "common": {
         "oberon": makeSuiteForGrammar(oberon),
         "eberon": makeSuiteForGrammar(eberon)
     },
     "eberon": TestUnitEberon.suite,
-    "oberon": TestUnitOberon.suite
+    "oberon": TestUnitOberon.suite,
+    "code":   makeCodeSuite()
 });
 if (typeof process != "undefined")
     process.exit(result ? 0 : -1);

+ 2 - 1
test/test_unit_common.js

@@ -2,6 +2,7 @@
 
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
+var CodeGenerator = require("js/CodeGenerator.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
 var oc = require("oc.js");
@@ -30,7 +31,7 @@ var TestContext = Context.Context.extend({
     init: function TestContext(language){
         Context.Context.prototype.init.call(
                 this,
-                { codeGenerator: Code.nullGenerator(),
+                { codeGenerator: CodeGenerator.nullGenerator(),
                   moduleGenerator: function(){return new TestModuleGenerator();},
                   rtl: new RTL(),
                   types: language.types,