Przeglądaj źródła

constructors are inherited

Vladislav Folts 10 lat temu
rodzic
commit
10e9321074

BIN
bin/compiled.zip


+ 8 - 4
src/context.js

@@ -1752,13 +1752,17 @@ exports.RecordDecl = ChainedContext.extend({
         gen.closeScope("");
         return gen.result();
     },
+    _qualifiedBaseConstructor: function(){
+        var baseType = Type.recordBase(this.__type);
+        if (!baseType)
+            return "";
+        return this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType);
+    },
     _generateBaseConstructorCallCode: function(){
         var baseType = Type.recordBase(this.__type);
         var qualifiedBase = baseType ? this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType) : undefined; 
-        var result = "";
-        if (baseType)
-            result += qualifiedBase + ".call(this);\n";
-        return result;
+        var result = this._qualifiedBaseConstructor();
+        return result ? result + ".call(this);\n" : "";
     },
     __generateFieldsInitializationCode: function(){
         var result = "";

+ 3 - 2
src/eberon/EberonConstructor.ob

@@ -59,8 +59,9 @@ PROCEDURE makeCallGenerator(
 BEGIN
     Procedure.initStdCall(call);
     call.recordType := type; 
-    IF type.customConstructor # NIL THEN
-        call.args := type.customConstructor.args();
+    cons <- EberonRecord.actualConstructor(type^);
+    IF cons # NIL THEN
+        call.args := cons.args();
     END;
     RETURN Procedure.makeCallGenerator(call, cx)
 END;

+ 9 - 0
src/eberon/EberonRecord.ob

@@ -479,4 +479,13 @@ BEGIN
     RETURN result;
 END;
 
+PROCEDURE actualConstructor*(r: Record): Types.PDefinedProcedure;
+BEGIN
+    result <- r.customConstructor;
+    IF (result = NIL) & (r.base # NIL) THEN
+        result := actualConstructor(r.base(PRecord)^);
+    END;
+    RETURN result;
+END;
+
 END EberonRecord.

+ 15 - 6
src/eberon/eberon_context.js

@@ -427,14 +427,22 @@ var RecordDecl = Context.RecordDecl.extend({
     _makeField: function(field, type){
         return EberonRecord.makeRecordField(field, type, this.__type);
     },
+    _generateBaseConstructorCallCode: function(){
+        var actualConstructor = EberonRecord.actualConstructor(this.type());
+        if (!actualConstructor || !actualConstructor.args().length)
+            return Context.RecordDecl.prototype._generateBaseConstructorCallCode.call(this);
+        
+        var result = this._qualifiedBaseConstructor();
+        return result ? result + ".apply(this, arguments);\n" : "";
+    },
     endParse: function(){
         var type = this.type();
         if (!type.customConstructor)
             return Context.RecordDecl.prototype.endParse.call(this);
-        else
-            type.setRecordInitializationCode(
-                this._generateBaseConstructorCallCode(),
-                this._generateInheritance());
+
+        type.setRecordInitializationCode(
+            this._generateBaseConstructorCallCode(),
+            this._generateInheritance());
     }
 });
 
@@ -619,9 +627,10 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
                 this.__boundType.defineConstructor(this.__methodType.procType());
 
                 var base = Type.recordBase(this.__boundType);
-                if (!this.__baseConstructorWasCalled && base && base.customConstructor && base.customConstructor.args().length)
+                var baseConstructor = base && EberonRecord.actualConstructor(base);
+                if (!this.__baseConstructorWasCalled && baseConstructor && baseConstructor.args().length)
                     throw new Errors.Error("base record constructor has parameters but was not called (use '| SUPER' to pass parameters to base constructor)");
-                if (this.__baseConstructorWasCalled && (!base.customConstructor || !base.customConstructor.args().length))
+                if (this.__baseConstructorWasCalled && (!baseConstructor || !baseConstructor.args().length))
                     throw new Errors.Error("base record constructor has no parameters and will be called automatically (do not use '| SUPER' to call base constructor)");
                 
                 var fieldsWereNotInited = [];

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

@@ -7,6 +7,10 @@ var RTL$ = {
     }
 };
 var m = function (){
+function DerivedRecordWithParamConstructorWithoutConstructor(){
+	RecordWithParamConstructor.apply(this, arguments);
+}
+RTL$.extend(DerivedRecordWithParamConstructorWithoutConstructor, RecordWithParamConstructor);
 function MixAutoAndManualInitFields(){
 	this.iAuto = 0;
 	this.iManual = 123;
@@ -59,4 +63,5 @@ passAsArgument(new T());
 var r = new T();
 var i = new RecordWithField().i;
 var rParam = new RecordWithParamConstructor(123);
+var derived = new DerivedRecordWithParamConstructorWithoutConstructor(123);
 }();

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

@@ -26,6 +26,9 @@ TYPE
         PROCEDURE DerivedRecordWithParamConstructor();
     END;
 
+    DerivedRecordWithParamConstructorWithoutConstructor = RECORD(RecordWithParamConstructor)
+    END;
+
     InitializeField = RECORD
         PROCEDURE InitializeField();
 
@@ -125,4 +128,6 @@ BEGIN
     i <- RecordWithField().i;
 
     rParam <- RecordWithParamConstructor(123);
+
+    derived <- DerivedRecordWithParamConstructorWithoutConstructor(123);
 END m.

+ 14 - 0
test/input/eberon/run/constructor.ob

@@ -6,11 +6,25 @@ TYPE
         i: INTEGER;
     END;
 
+    ConstructorWithParam = RECORD
+        PROCEDURE ConstructorWithParam(i: INTEGER);
+
+        i: INTEGER;
+    END;
+
+    Derived = RECORD(ConstructorWithParam)
+    END;
+
 PROCEDURE T.T();
 BEGIN
     SELF.i := 3;
 END;
 
+PROCEDURE ConstructorWithParam.ConstructorWithParam(i: INTEGER)
+    | i(i);
+END;
+
 BEGIN
     ASSERT(T().i = 3);
+    ASSERT(Derived(123).i = 123);
 END m.

+ 9 - 0
test/test_unit_eberon.js

@@ -1211,6 +1211,15 @@ exports.suite = {
         fail(["PROCEDURE T.T() | f2(2), f1(1), f3(3); END;", "field 'f1' must be initialized before 'f2'"],
              ["PROCEDURE T.T() | f1(1), f3(3), f2(2); END;", "field 'f2' must be initialized before 'f3'"]
             )
+        ),
+    "inherit constructor parameters": testWithContext(
+        context(grammar.expression,
+                "TYPE Base = RECORD PROCEDURE Base(i: INTEGER); END;"
+              + "Derived = RECORD(Base) END;"
+              + "PROCEDURE Base.Base(a: INTEGER); END;"
+              ),
+        pass("Derived(123)"),
+        fail(["Derived()", "1 argument(s) expected, got 0"])
         )
     }
 };