Bläddra i källkod

generate code for constructor fields initializtion list

Vladislav Folts 10 år sedan
förälder
incheckning
7111fbe582

BIN
bin/compiled.zip


+ 4 - 16
src/context.js

@@ -291,18 +291,6 @@ function castCode(type, context){
     return context.qualifyScope(Type.recordScope(baseType)) + Type.recordConstructor(baseType);
 }
 
-function mangleField(id, type){
-    if (Type.isScalar(type) 
-        || (type instanceof Type.Array 
-            && Type.isScalar(Type.arrayBaseElementsType(type)))){
-        if (id == "constructor" || id == "prototype")
-            return id + "$";
-        return id;
-    }
-
-    return "$" + id;
-}
-
 exports.Designator = ChainedContext.extend({
     init: function Context$Designator(context){
         ChainedContext.prototype.init.call(this, context);
@@ -351,7 +339,7 @@ exports.Designator = ChainedContext.extend({
         this.__derefCode = this.__code;
         var codeId = this.__currentType instanceof Type.Procedure 
                  ? this.__currentType.designatorCode(id)
-                 : mangleField(id, this.__currentType);
+                 : Type.mangleField(id, this.__currentType);
         this.__propCode = "\"" + codeId + "\"";
         this.__info = field.asVar(isReadOnly, this);
         this.__code += "." + codeId;
@@ -1760,7 +1748,7 @@ exports.RecordDecl = ChainedContext.extend({
         gen.write("function " + this.__cons + "()");
         gen.openScope();
         gen.write(this._generateBaseConstructorCallCode() 
-                + this._generateFieldsInitializationCode());
+                + this.__generateFieldsInitializationCode());
         gen.closeScope("");
         return gen.result();
     },
@@ -1772,12 +1760,12 @@ exports.RecordDecl = ChainedContext.extend({
             result += qualifiedBase + ".call(this);\n";
         return result;
     },
-    _generateFieldsInitializationCode: function(){
+    __generateFieldsInitializationCode: function(){
         var result = "";
         var ownFields = Type.recordOwnFields(this.__type);
         for(var f in ownFields){
             var fieldType = ownFields[f].type();
-            result += "this." + mangleField(f, fieldType) + " = " + fieldType.initializer(this, false, "") + ";\n";
+            result += "this." + Type.mangleField(f, fieldType) + " = " + fieldType.initializer(this, false, "") + ";\n";
         }
         return result;
     },

+ 27 - 2
src/eberon/EberonConstructor.ob

@@ -9,6 +9,10 @@ TYPE
     BaseConstructorCall = RECORD(ConstructorCall)
     END;
 
+    RecordInitCall = RECORD(ConstructorCall)
+        field: STRING;
+    END;
+
     NonRecordInitCall = RECORD(Procedure.CallGenerator)
         cx: LanguageContext.PType;
         type: Types.PType;
@@ -36,6 +40,17 @@ BEGIN
     RETURN Code.makeSimpleExpression(code, NIL);
 END;
 
+PROCEDURE fieldInitLval(field: STRING; type: Types.PType): STRING;
+    RETURN "this." + Types.mangleField(field, type);
+END;
+
+PROCEDURE RecordInitCall.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+BEGIN
+    e <- SUPER(args, cx);
+    t <- e.type();
+    RETURN Code.makeSimpleExpression(fieldInitLval(SELF.field, t) + " = " + e.code(), t);
+END;
+
 PROCEDURE makeCallGenerator(
     type: EberonRecord.PRecord; 
     cx: LanguageContext.PType;
@@ -62,7 +77,8 @@ BEGIN
     END;
 
     variable <- Types.makeVariable(SELF.type, FALSE);
-    designator <- Code.makeDesignator(SELF.field, SELF.field, NIL, SELF.type, variable, NIL);
+    lval <- fieldInitLval(SELF.field, SELF.type);
+    designator <- Code.makeDesignator(SELF.field, lval, NIL, SELF.type, variable, NIL);
     left <- Code.makeExpression(SELF.field, SELF.type, designator, NIL);
     SELF.code := Operator.assign(left, e, SELF.cx^);    
 END;
@@ -94,6 +110,15 @@ PROCEDURE makeFieldInitCall*(
 VAR
     result: Procedure.PCallGenerator;
 
+    PROCEDURE initRecord(type: EberonRecord.PRecord): Procedure.PCallGenerator;
+    VAR
+        call: POINTER TO RecordInitCall;
+    BEGIN
+        NEW(call);
+        call.field := field;
+        RETURN makeCallGenerator(type, cx, call);
+    END;
+
     PROCEDURE initNonRecord(): Procedure.PCallGenerator;
     VAR
         result: POINTER TO NonRecordInitCall;
@@ -106,7 +131,7 @@ VAR
     END;
 BEGIN
     IF type IS EberonRecord.PRecord THEN
-        result := makeConstructorCall(type, cx);
+        result := initRecord(type);
     ELSE
         result := initNonRecord();
     END;

+ 39 - 5
src/eberon/EberonRecord.ob

@@ -1,6 +1,6 @@
 MODULE EberonRecord;
 IMPORT 
-    Cast, Context, EberonContext, EberonTypes, Errors, JS, JsMap, ScopeBase, Object, String, Types;
+    Cast, Context, EberonContext, EberonTypes, Errors, JS, JsMap, ScopeBase, Object, Stream, String, Types;
 TYPE
     Record* = RECORD(Types.Record)
         PROCEDURE declareConstructor(type: Types.PDefinedProcedure);
@@ -10,7 +10,7 @@ TYPE
         PROCEDURE requireNewOnly();
         PROCEDURE setBaseConstructorCallCode(code: STRING);
         PROCEDURE setFieldInitializationCode(field: STRING; code: STRING);
-        PROCEDURE setRecordInitializationCode(baseConstructorCallCode, fieldsInitializationCode, inheritanceCode: STRING);
+        PROCEDURE setRecordInitializationCode(baseConstructorCallCode, inheritanceCode: STRING);
 
         customConstructor-: Types.PDefinedProcedure;
         customConstructorDefined: BOOLEAN;
@@ -24,7 +24,7 @@ TYPE
         declaredAsVariable: BOOLEAN;
         lazyDefinitions: JsMap.Type;
         nonExportedMethods: ARRAY * OF STRING;
-        inheritanceCode-, baseConstructorCallCode-, fieldsInitializationCode-: STRING;
+        inheritanceCode-, baseConstructorCallCode-: STRING;
         fieldsInit: JsMap.Strings;
         fieldsInitOrder: ARRAY * OF STRING;
         lastFieldInit: INTEGER;
@@ -53,6 +53,12 @@ TYPE
         base: PRecord;
     END;
 
+    GenFieldInitCodeClosure = RECORD(Object.Type)
+        cx: Context.PType;
+        record: PRecord;
+        code: STRING;
+    END;
+
 PROCEDURE cannotInstantiateErrMsg(r: Types.Record): STRING;
     RETURN "cannot instantiate '" 
          + r.name 
@@ -331,10 +337,9 @@ BEGIN
     JsMap.putString(SELF.fieldsInit, field, code);
 END;
 
-PROCEDURE Record.setRecordInitializationCode(baseConstructorCallCode, fieldsInitializationCode, inheritanceCode: STRING);
+PROCEDURE Record.setRecordInitializationCode(baseConstructorCallCode, inheritanceCode: STRING);
 BEGIN
     SELF.baseConstructorCallCode := baseConstructorCallCode;
-    SELF.fieldsInitializationCode := fieldsInitializationCode;
     SELF.inheritanceCode := inheritanceCode;
 END;
 
@@ -435,6 +440,35 @@ BEGIN
     RETURN result;
 END;
 
+PROCEDURE genFieldInitCode(key: STRING; value: Object.PType; VAR closure: Object.Type);
+    PROCEDURE do(f: Types.PField; VAR closure: GenFieldInitCodeClosure);
+    VAR
+        code: STRING;
+        result: STRING;
+    BEGIN
+        type <- f.type()(Types.PStorageType);
+        IF JsMap.findString(closure.record.fieldsInit, key, code) THEN
+            result := code;
+        ELSE
+            result := "this." + Types.mangleField(key, type) 
+                    + " = " + type.initializer(closure.cx^, FALSE, "");
+        END;
+        closure.code := closure.code + result + ";" + Stream.kCR;
+    END;
+BEGIN
+    do(value(Types.PField), closure(GenFieldInitCodeClosure));
+END;
+
+PROCEDURE fieldsInitializationCode*(r: PRecord; cx: Context.PType): STRING;
+VAR
+    closure: GenFieldInitCodeClosure;
+BEGIN
+    closure.cx := cx;
+    closure.record := r;
+    JsMap.forEach(Types.recordOwnFields(r^), genFieldInitCode, closure);
+    RETURN closure.code;
+END;
+
 PROCEDURE makeRecordField*(identdef: Context.PIdentdefInfo; type: Types.PType; record: PRecord): Types.PRecordField;
 VAR
     result: POINTER TO RecordField;

+ 1 - 2
src/eberon/eberon_context.js

@@ -434,7 +434,6 @@ var RecordDecl = Context.RecordDecl.extend({
         else
             type.setRecordInitializationCode(
                 this._generateBaseConstructorCallCode(),
-                this._generateFieldsInitializationCode(), 
                 this._generateInheritance());
     }
 });
@@ -575,7 +574,7 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
         if (this.__isConstructor)
             this.codeGenerator().write(
                 this.__boundType.baseConstructorCallCode
-              + this.__boundType.fieldsInitializationCode);
+              + EberonRecord.fieldsInitializationCode(this.__boundType, this));
     },
     _makeArgumentVariable: function(arg){
         if (!arg.isVar)

+ 8 - 0
src/ob/JsMap.ob

@@ -40,6 +40,14 @@ BEGIN
     RETURN result
 END find;
 
+PROCEDURE findString*(m: Strings; s: STRING; VAR r: STRING): BOOLEAN;
+VAR
+    result: BOOLEAN;
+BEGIN
+    JS.do("if (m.hasOwnProperty(s)){result = true; r.set(m[s]);}");
+    RETURN result
+END;
+
 PROCEDURE put*(m: Type; s: STRING; o: Object.PType);
 BEGIN
     JS.do("m[s] = o");

+ 1 - 1
src/ob/Operator.ob

@@ -510,7 +510,7 @@ BEGIN
     ELSE
         IF cx.types.implicitCast(rightType, leftType, FALSE, castOperations, castOperation)
             # Cast.errNo THEN;
-            Errors.raise("type mismatch: '" + leftCode + "' is '" + leftType.description()
+            Errors.raise("type mismatch: '" + left.code() + "' is '" + leftType.description()
                          + "' and cannot be assigned to '" + rightType.description() + "' expression");
         END;
         IF (leftType IS Types.POpenArray) & (rightType IS Types.PArray) THEN

+ 16 - 0
src/ob/Types.ob

@@ -17,6 +17,7 @@ TYPE
     StorageType* = RECORD(Type)    
         PROCEDURE initializer*(cx: Context.Type; forNew: BOOLEAN; code: STRING): STRING
     END;
+    PStorageType* = POINTER TO StorageType;
 
     TypeId* = RECORD(Id)
         PROCEDURE type*(): PType;
@@ -821,6 +822,21 @@ BEGIN
     RETURN result;
 END;
 
+PROCEDURE mangleField*(id: STRING; type: PType): STRING;
+BEGIN
+    result <- id;
+    IF isScalar(type^) 
+        OR ((type IS PArray)
+            & isScalar(arrayBaseElementsType(type^)^)) THEN
+        IF (id = "constructor") OR (id = "prototype") THEN
+            result := result + "$";
+        END;
+    ELSE
+        result := "$" + result;
+    END;
+    RETURN result;
+END;
+
 BEGIN
     basic.bool := makeBasic("BOOLEAN", "false");
     basic.ch := makeBasic("CHAR", "0");

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

@@ -7,6 +7,22 @@ var RTL$ = {
     }
 };
 var m = function (){
+function MixAutoAndManualInitFields(){
+	this.iAuto = 0;
+	this.iManual = 123;
+	this.$rAuto = new T();
+	this.$rManual = new RecordWithParamConstructor(345);
+	this.setManual = 8;
+	this.stringAuto = '';
+}
+function UsingSelfInFieldsInit(){
+	this.i1 = 123;
+	this.i2 = this.i1;
+}
+function FieldInitAndBody(){
+	this.i = 1;
+	this.i = 2;
+}
 function T(){
 }
 function Derived(){
@@ -29,6 +45,16 @@ function DerivedRecordWithParamConstructor(){
 	RecordWithParamConstructor.call(this, 123);
 }
 RTL$.extend(DerivedRecordWithParamConstructor, RecordWithParamConstructor);
+function InitializeField(){
+	this.i = 123;
+}
+function InitializeRecordField(){
+	this.$r = new RecordWithParamConstructor(123);
+}
+function InitializeMangledField(){
+	this.constructor$ = 123;
+	this.prototype$ = true;
+}
 passAsArgument(new T());
 var r = new T();
 var i = new RecordWithField().i;

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

@@ -26,6 +26,64 @@ TYPE
         PROCEDURE DerivedRecordWithParamConstructor();
     END;
 
+    InitializeField = RECORD
+        PROCEDURE InitializeField();
+
+        i: INTEGER;
+    END;
+
+    InitializeRecordField = RECORD
+        PROCEDURE InitializeRecordField();
+
+        r: RecordWithParamConstructor;
+    END;
+
+    InitializeMangledField = RECORD
+        PROCEDURE InitializeMangledField();
+
+        constructor: INTEGER;
+        prototype: BOOLEAN;
+    END;
+
+    MixAutoAndManualInitFields = RECORD
+        PROCEDURE MixAutoAndManualInitFields();
+
+        iAuto, iManual: INTEGER;
+        rAuto: T;
+        rManual: RecordWithParamConstructor;
+        setManual: SET;
+        stringAuto: STRING;
+    END;
+
+    UsingSelfInFieldsInit = RECORD
+        PROCEDURE UsingSelfInFieldsInit();
+
+        i1, i2: INTEGER;
+    END;
+
+    FieldInitAndBody = RECORD
+        PROCEDURE FieldInitAndBody();
+
+        i: INTEGER;
+    END;
+
+PROCEDURE MixAutoAndManualInitFields.MixAutoAndManualInitFields()
+    | iManual(123),
+      rManual(345),
+      setManual({3});
+END;
+
+PROCEDURE UsingSelfInFieldsInit.UsingSelfInFieldsInit()
+    | i1(123),
+      i2(SELF.i1);
+END;
+
+PROCEDURE FieldInitAndBody.FieldInitAndBody()
+    | i(1);
+BEGIN
+    SELF.i := 2;
+END;
+
 PROCEDURE T.T();
 END;
 
@@ -48,6 +106,19 @@ PROCEDURE DerivedRecordWithParamConstructor.DerivedRecordWithParamConstructor()
     | SUPER(123);
 END;
 
+PROCEDURE InitializeField.InitializeField()
+    | i(123);
+END;
+
+PROCEDURE InitializeRecordField.InitializeRecordField()
+    | r(123);
+END;
+
+PROCEDURE InitializeMangledField.InitializeMangledField()
+    | constructor(123),
+      prototype(TRUE);
+END;
+
 BEGIN
     passAsArgument(T());
     r <- T();