2
0
Vladislav Folts 10 жил өмнө
parent
commit
c7175f08ca

BIN
bin/compiled.zip


+ 1 - 0
src/context.js

@@ -2033,6 +2033,7 @@ exports.endCallMsg = endCallMsg;
 exports.Chained = ChainedContext;
 exports.endParametersMsg = endParametersMsg;
 exports.getSymbolAndScope = getSymbolAndScope;
+exports.getQIdSymbolAndScope = getQIdSymbolAndScope;
 exports.makeProcCall = makeProcCall;
 exports.unwrapType = unwrapType;
 exports.RelationOps = RelationOps;

+ 52 - 0
src/eberon/eberon_context.js

@@ -176,6 +176,10 @@ function makeConstructorCall(context, type, call){
     return call(type, cx);
     }
 
+function OperatorNewMsg(e){
+    this.expression = e;
+}
+
 var Designator = Context.Designator.extend({
     init: function EberonContext$Designator(parent){
         Context.Designator.prototype.init.call(this, parent);
@@ -201,6 +205,11 @@ var Designator = Context.Designator.extend({
             return this.__beginCall();
         if (msg == Context.endCallMsg)
             return this.__endCall();
+        if (msg instanceof OperatorNewMsg){
+            var e = msg.expression;
+            this._advance(e.type(), new ResultVariable(e), e.code());
+            return;
+        }
 
         // no type promotion after calling functions
         if (breakTypePromotion(msg))
@@ -248,6 +257,48 @@ var Designator = Context.Designator.extend({
     }
 });
 
+var OperatorNew = Context.Chained.extend({
+    init: function EberonContext$OperatorNew(parent){
+        Context.Chained.prototype.init.call(this, parent);
+        this.__info = undefined;
+        this.__call = undefined;
+    },
+    handleQIdent: function(q){
+        var found = Context.getQIdSymbolAndScope(this, q);
+        var s = found.symbol();
+        var info = s.info();
+
+        if (!(info instanceof Type.TypeId))
+            throw new Errors.Error("record type is expected in operator NEW, got '" + info.idType() + "'");
+
+        var type = info.type();
+        if (!(type instanceof Type.Record))
+            throw new Errors.Error("record type is expected in operator NEW, got '" + type.description() + "'");
+        
+        this.__info = info;        
+    },
+    handleExpression: function(e){
+        this.__call.handleArgument(e);
+    },
+    handleMessage: function(msg){
+        if (msg == Context.beginCallMsg){
+            this.__call = makeConstructorCall(this, this.__info.type(), EberonConstructor.makeConstructorCall);
+            return;
+        }
+        if (msg == Context.endCallMsg)
+            return;
+
+        return Context.Chained.prototype.handleMessage.call(this, msg);
+    },
+    endParse: function(){
+        var callExpression = this.__call.end();
+        var e = Code.makeSimpleExpression(
+              callExpression.code()
+            , Type.makePointer("", this.__info));
+        this.handleMessage(new OperatorNewMsg(e));
+    }
+});
+
 var InPlaceVariableInit = Context.Chained.extend({
     init: function EberonContext$InPlaceVariableInit(context){
         Context.Chained.prototype.init.call(this, context);
@@ -1207,6 +1258,7 @@ exports.Return = Return;
 exports.SimpleExpression = SimpleExpression;
 exports.InPlaceVariableInit = InPlaceVariableInit;
 exports.InPlaceVariableInitFor = InPlaceVariableInitFor;
+exports.OperatorNew = OperatorNew;
 exports.Term = Term;
 exports.TypeDeclaration = TypeDeclaration;
 exports.VariableDeclaration = VariableDeclaration;

+ 3 - 1
src/eberon/eberon_grammar.js

@@ -40,8 +40,10 @@ function makeIdentdef(ident){
 
 function makeDesignator(ident, qualident, selector, actualParameters){
     var self = and("SELF", optional(and("(", "POINTER", ")")));
+    var operatorNew = and("NEW", context(and(qualident, actualParameters), EbContext.OperatorNew));
     var designator = context(
-        and(or(self, "SUPER", qualident), repeat(or(selector, actualParameters))), EbContext.Designator);
+        and(or(self, "SUPER", operatorNew, qualident), 
+            repeat(or(selector, actualParameters))), EbContext.Designator);
     return { 
         factor: context(designator, EbContext.ExpressionProcedureCall),
         assignmentOrProcedureCall: function(assignment, expression){

+ 10 - 6
src/grammar.js

@@ -78,12 +78,16 @@ var string = or(context(Lexer.string, Context.String)
               , context(and(digit, repeat(hexDigit), "X"), Context.Char));
 
 var factor = context(
-    or(string, number, "NIL", "TRUE", "FALSE"
-     , function(stream, context){return set(stream, context);} // break recursive declaration of set
-     , designator.factor
-     , and("(", function(stream, context){return expression(stream, context);}
-         , required(")", "no matched ')'"))
-     , and("~", function(stream, context){
+    or(string, 
+       number, 
+       "NIL", 
+       "TRUE", 
+       "FALSE",
+       function(stream, context){return set(stream, context);}, // break recursive declaration of set
+       designator.factor,
+       and("(", function(stream, context){return expression(stream, context);}
+         , required(")", "no matched ')'")),
+       and("~", function(stream, context){
                     return factor(stream, context);}) // break recursive declaration of factor
      )
     , contexts.Factor);

+ 8 - 0
test/expected/eberon/operator_new.js

@@ -0,0 +1,8 @@
+var m = function (){
+function T(){
+}
+function ConstructorWithParameters(i/*INTEGER*/){
+}
+var t = new T();
+var params = new ConstructorWithParameters(123);
+}();

+ 16 - 0
test/input/eberon/operator_new.ob

@@ -0,0 +1,16 @@
+MODULE m;
+TYPE
+    T = RECORD
+    END;
+
+    ConstructorWithParameters = RECORD
+        PROCEDURE ConstructorWithParameters(i: INTEGER);
+    END;
+
+PROCEDURE ConstructorWithParameters.ConstructorWithParameters(i: INTEGER);
+END;
+
+BEGIN
+    t <- NEW T();
+    params <- NEW ConstructorWithParameters(123);
+END m.

+ 23 - 1
test/test_unit_eberon.js

@@ -1232,5 +1232,27 @@ exports.suite = {
         pass("Derived(123)"),
         fail(["Derived()", "1 argument(s) expected, got 0"])
         )
-    }
+    },
+"operator NEW": testWithContext(
+    context(grammar.expression,
+            "TYPE T = RECORD field: INTEGER; END; Proc = PROCEDURE();"
+            + "ParamCons = RECORD PROCEDURE ParamCons(i: INTEGER); END;"
+            + "Abstract = RECORD PROCEDURE abstract(); END;"
+            + "PROCEDURE ParamCons.ParamCons(i: INTEGER); END;"
+            + "PROCEDURE proc(); END;"
+          ),
+    pass("NEW T()",
+         "NEW ParamCons(123)",
+         "NEW T().field",
+         "NEW T()^"
+         ),
+    fail(["NEW INTEGER()", "record type is expected in operator NEW, got 'INTEGER'"],
+         ["NEW proc()", "record type is expected in operator NEW, got 'procedure'"],
+         ["NEW Proc()", "record type is expected in operator NEW, got 'Proc'"],
+         ["NEW T().unknownField", "type 'T' has no 'unknownField' field"],
+         ["NEW T(123)", "0 argument(s) expected, got 1"],
+         ["NEW Abstract()", "cannot instantiate 'Abstract' because it has abstract method(s): abstract"],
+         ["NEW undeclared()", "undeclared identifier: 'undeclared'"]
+         )
+    )
 };