Sfoglia il codice sorgente

make possible to call constructor in expression

Vladislav Folts 10 anni fa
parent
commit
f7a74c54d3

+ 3 - 0
src/context.js

@@ -362,6 +362,9 @@ exports.Designator = ChainedContext.extend({
         this.__code += "." + codeId;
         this.__scope = undefined;
     },
+    _currentType: function(){return this.__currentType;},
+    _currentInfo: function(){return this.__info;},
+    _discardCode: function(){this.__code = "";},
     _makeDerefVar: function(){
         return Type.makeVariableRef(this.__currentType, false);
     },

+ 24 - 0
src/eberon/EberonConstructor.ob

@@ -0,0 +1,24 @@
+MODULE EberonConstructor;
+IMPORT Code, LanguageContext, Procedure, Types;
+TYPE
+    ConstructorCall = RECORD(Procedure.StdCall)
+        recordType: Types.PRecord;
+    END;
+
+PROCEDURE ConstructorCall.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+BEGIN
+    Procedure.processArguments(args, SELF.args, NIL, NIL);
+    RETURN Code.makeSimpleExpression(SELF.recordType.initializer(cx^, FALSE), SELF.recordType);
+END;
+
+PROCEDURE makeConstructorCall*(type: Types.PRecord; cx: LanguageContext.PType): Procedure.PCallGenerator;
+VAR
+    call: POINTER TO ConstructorCall;
+BEGIN
+    NEW(call);
+    Procedure.initStdCall(call);
+    call.recordType := type; 
+    RETURN Procedure.makeCallGenerator(call, cx)
+END;
+
+END EberonConstructor.

+ 2 - 1
src/eberon/EberonDynamicArray.ob

@@ -198,7 +198,8 @@ BEGIN
     RETURN Procedure.makeCallGenerator(call, cx)
 END MethodClear.callGenerator;
 
-PROCEDURE MethodRemove.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
+PROCEDURE MethodRemove.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator
+;
 VAR
     a: Types.PProcedureArgument;
     call: POINTER TO MethodCallRemove;

+ 22 - 2
src/eberon/eberon_context.js

@@ -5,6 +5,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 EberonConstructor= require("js/EberonConstructor.js");
 var EberonDynamicArray= require("js/EberonDynamicArray.js");
 var EberonScope = require("js/EberonScope.js");
 var EberonString = require("js/EberonString.js");
@@ -188,6 +189,16 @@ var Identdef = Context.Identdef.extend({
     }
 });
 
+function makeConstructorCall(context, type){
+    var l = context.language();
+    var cx = {
+        types: l.types, 
+        rtl: l.rtl, 
+        qualifyScope: context.qualifyScope.bind(context)
+        };
+    return EberonConstructor.makeConstructorCall(type, cx);
+    }
+
 var Designator = Context.Designator.extend({
     init: function EberonContext$Designator(parent){
         Context.Designator.prototype.init.call(this, parent);
@@ -245,7 +256,13 @@ var Designator = Context.Designator.extend({
             Context.Designator.prototype.handleLiteral.call(this, s);
     },
     __beginCall: function(){
-        this.__procCall = Context.makeProcCall(this, this.__currentType, this.__info);
+        var type = this._currentType();
+        if (type instanceof Type.TypeId && type.type() instanceof Type.Record){
+            this.__procCall = makeConstructorCall(this, type.type());
+            this._discardCode();
+        }
+        else
+            this.__procCall = Context.makeProcCall(this, type, this._currentInfo());
     },
     __endCall: function(){
         var e = this.__procCall.end();
@@ -278,7 +295,10 @@ var InPlaceVariableInit = Context.Chained.extend({
         this._symbol = Symbol.makeSymbol(this.__id, v);
         if (type instanceof Type.Record){
             type.initializer(this, false); // checks for abstract etc.
-            this._code += this.language().rtl.cloneRecord(e.code());
+            if (e.designator())
+                this._code += this.language().rtl.cloneRecord(e.code());
+            else // do not clone if it is temporary, e.g. constructor call
+                this._code += e.code();
         }
         else if (type instanceof Type.Array){
             if (type instanceof Type.OpenArray)

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

@@ -20,4 +20,10 @@ function RecordWithFieldDerived(){
 	T.call(this);
 }
 RTL$.extend(RecordWithFieldDerived, T);
+
+function passAsArgument(o/*T*/){
+}
+passAsArgument(new T());
+var r = new T();
+var i = new RecordWithField().i;
 }();

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

@@ -25,4 +25,11 @@ END;
 PROCEDURE RecordWithFieldDerived();
 END;
 
+PROCEDURE passAsArgument(o: T);
+END;
+
+BEGIN
+    passAsArgument(T());
+    r <- T();
+    i <- RecordWithField().i;
 END m.

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

@@ -0,0 +1,14 @@
+MODULE m;
+TYPE
+    T = RECORD
+        i: INTEGER;
+    END;
+
+PROCEDURE T();
+BEGIN
+    SELF.i := 3;
+END;
+
+BEGIN
+    ASSERT(T().i = 3);
+END m.

+ 38 - 16
test/test_unit_eberon.js

@@ -1074,20 +1074,42 @@ exports.suite = {
          "PROCEDURE p(): INTEGER; RETURN 0; END;"
          )
     ),
-"constructor": testWithGrammar(
-    grammar.declarationSequence, 
-    pass("TYPE T = RECORD END; PROCEDURE T(); END;",
-         "TYPE T = RECORD i: INTEGER; END; PROCEDURE T(); BEGIN SELF.i := 0; END;",
-         "TYPE T = RECORD END; PROCEDURE T(); END T;",
-         "TYPE T = RECORD END; PROCEDURE p(); PROCEDURE T(); END; BEGIN T(); END;" /* local procedure name may match type name from outer scope*/
-         ),
-    fail(["TYPE T = RECORD END; PROCEDURE T(); END; PROCEDURE T(); END;", "constructor 'T' already defined"],
-         ["TYPE T = RECORD END; PROCEDURE T(): INTEGER; RETURN 0; END;", "constructor 'T' cannot have result type specified"],
-         ["TYPE T = ARRAY 3 OF INTEGER; PROCEDURE T(); END;", "'T' already declared"],
-         ["TYPE T = RECORD END; PROCEDURE T(); END T.T;", "mismatched method names: expected 'T' at the end (or nothing), got 'T.T'"],
-         ["TYPE T = RECORD END; PROCEDURE T.T(); END;", "'T' has no declaration for method 'T'"],
-         ["TYPE T = RECORD END; PROCEDURE T(); END T2;", "mismatched method names: expected 'T' at the end (or nothing), got 'T2'"],
-         ["TYPE T = RECORD END; PROCEDURE T(); END T.T;", "mismatched method names: expected 'T' at the end (or nothing), got 'T.T'"]
-         )
-    )
+"constructor": {
+    "declaration": testWithGrammar(
+        grammar.declarationSequence, 
+        pass("TYPE T = RECORD END; PROCEDURE T(); END;",
+             "TYPE T = RECORD i: INTEGER; END; PROCEDURE T(); BEGIN SELF.i := 0; END;",
+             "TYPE T = RECORD END; PROCEDURE T(); END T;",
+             "TYPE T = RECORD END; PROCEDURE p(); PROCEDURE T(); END; BEGIN T(); END;" /* local procedure name may match type name from outer scope*/
+             ),
+        fail(["TYPE T = RECORD END; PROCEDURE T(); END; PROCEDURE T(); END;", "constructor 'T' already defined"],
+             ["TYPE T = RECORD END; PROCEDURE T(): INTEGER; RETURN 0; END;", "constructor 'T' cannot have result type specified"],
+             ["TYPE T = ARRAY 3 OF INTEGER; PROCEDURE T(); END;", "'T' already declared"],
+             ["TYPE T = RECORD END; PROCEDURE T(); END T.T;", "mismatched method names: expected 'T' at the end (or nothing), got 'T.T'"],
+             ["TYPE T = RECORD END; PROCEDURE T.T(); END;", "'T' has no declaration for method 'T'"],
+             ["TYPE T = RECORD END; PROCEDURE T(); END T2;", "mismatched method names: expected 'T' at the end (or nothing), got 'T2'"],
+             ["TYPE T = RECORD END; PROCEDURE T(); END T.T;", "mismatched method names: expected 'T' at the end (or nothing), got 'T.T'"]
+             )
+        ),
+    "as expression": testWithContext(
+        context(grammar.expression,
+                "TYPE T = RECORD i: INTEGER; END; PT = POINTER TO T;"
+                + "PROCEDURE byVar(VAR a: T): INTEGER; RETURN 0; END;"
+                + "PROCEDURE byNonVar(a: T): INTEGER; RETURN 0; END;"
+                ),
+        pass("T()",
+             "byNonVar(T())",
+             "T().i"
+             ),
+        fail(["PT()", "PROCEDURE expected, got 'type PT'"],
+             ["byVar(T())", "expression cannot be used as VAR parameter"]
+            )
+        ),
+    "initialize in place variable": testWithContext(
+        context(grammar.statement,
+                "TYPE T = RECORD END;"),
+        pass("r <- T()"),
+        fail()
+        )
+    }
 };