Răsfoiți Sursa

fix code generation for array initializers

Vladislav Folts 9 ani în urmă
părinte
comite
d75a343ff6

BIN
bin/compiled.zip


+ 70 - 34
src/eberon/EberonContextExpression.ob

@@ -3,7 +3,7 @@ IMPORT
     Cast, CodePrecedence, ConstValue,
     Context, ContextExpression, ContextHierarchy, 
     EberonArray, EberonContextDesignator, 
-    EberonMap, EberonOperator, EberonString, EberonTypePromotion, 
+    EberonMap, EberonOperator, EberonRecord, EberonString, EberonTypePromotion, 
     Errors, Expression, ExpressionTree, LanguageContext,
     JS,
     Object, Record, Types, Variable;
@@ -236,21 +236,79 @@ PROCEDURE RelationExpression.RelationExpression(parent: PExpressionNode)
     | SUPER(parent, parent.currentNode);
 END;
 
-PROCEDURE Array.handleExpression(e: Expression.PType);
+PROCEDURE optimizeRecordRValue(VAR info: Types.Id; l: LanguageContext.Language): STRING;
+VAR
+    result: STRING;
 BEGIN
-    type <- e.type() IS Types.PString ? EberonString.string
-                                      : e.type();
-    IF SELF.type = NIL THEN
-        IF type IS Types.PStorageType THEN
-            SELF.type := type;
+    IF info IS TernaryOperatorResult THEN
+        lTemp <- Expression.isTemporary(info.left^);
+        rTemp <- Expression.isTemporary(info.right^);
+        IF lTemp & rTemp THEN
+            result := ternaryCode(info);
+        ELSIF lTemp THEN
+            result := ternaryCodeImpl(info.condition, 
+                                      info.left.code(), 
+                                      l.rtl.clone(info.right.code(), l.types.typeInfo(info.type()), "undefined"));
+        ELSIF rTemp THEN
+            result := ternaryCodeImpl(info.condition, 
+                                      l.rtl.clone(info.left.code(), l.types.typeInfo(info.type()), "undefined"),
+                                      info.right.code()); 
+        END;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE initFromRValue*(cx: ContextHierarchy.PNode; e: Expression.PType; lval: STRING; VAR resultType: Types.PStorageType): STRING;
+VAR
+    result: STRING;
+    cloneOp: LanguageContext.PCastOp;
+BEGIN
+    type <- e.type();
+    IF type IS Types.PString THEN
+        resultType := EberonString.string;
+    ELSIF type IS Types.PStorageType THEN
+        resultType := type;
+    ELSE
+        Errors.raise("cannot use " + type.description() + " to initialize " + lval);
+    END;
+
+    IF type IS Types.POpenArray THEN
+        Errors.raise("cannot initialize " + lval + " with open array");
+    ELSIF type IS EberonRecord.PRecord THEN
+        EberonRecord.ensureCanBeInstantiated(cx^, type, EberonRecord.instantiateForCopy);
+        IF Expression.isTemporary(e^) THEN
+            result := e.code();
         ELSE
-            Errors.raise("array's element cannot be '" + type.description() + "'");
+            info <- e.info();
+            l <- cx.root().language();
+            code <- optimizeRecordRValue(info^, l^);
+            result := LEN(code) = 0 
+                    ? l.rtl.clone(e.code(), l.types.typeInfo(type), "undefined")
+                    : code;
         END;
-        SELF.code := "[" + e.code();
-    ELSIF SELF.type = type THEN
-        SELF.code := SELF.code + ", " + e.code();
     ELSE
-        Errors.raise("array's elements should have the same type: expected '" + SELF.type.description() + "', got '" + type.description() + "'");
+        IF Expression.isTemporary(e^) & (type IS Types.PArray) THEN
+            result := e.code();
+        ELSE
+            l <- cx.root().language();
+            void <- l.types.implicitCast(type, type, FALSE, cloneOp);
+            result := cloneOp.clone(ContextHierarchy.makeLanguageContext(cx), e);
+        END;
+    END;
+    RETURN result;
+END;
+
+PROCEDURE Array.handleExpression(e: Expression.PType);
+VAR
+    checkType: Types.PStorageType;
+BEGIN
+    IF SELF.type = NIL THEN
+        SELF.code := "[" + initFromRValue(SELF(POINTER), e, "array's element", SELF.type);
+    ELSE
+        SELF.code := SELF.code + ", " + initFromRValue(SELF(POINTER), e, "array's element", checkType);
+        IF SELF.type # checkType THEN
+            Errors.raise("array's elements should have the same type: expected '" + SELF.type.description() + "', got '" + checkType.description() + "'");
+        END;
     END;
     INC(SELF.size);
 END;
@@ -478,28 +536,6 @@ PROCEDURE TernaryOperatorResult.idType(): STRING;
     RETURN "ternary operator result";
 END;
 
-PROCEDURE optimizeRecordRValue*(VAR info: Types.Id; l: LanguageContext.Language): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF info IS TernaryOperatorResult THEN
-        lTemp <- Expression.isTemporary(info.left^);
-        rTemp <- Expression.isTemporary(info.right^);
-        IF lTemp & rTemp THEN
-            result := ternaryCode(info);
-        ELSIF lTemp THEN
-            result := ternaryCodeImpl(info.condition, 
-                                      info.left.code(), 
-                                      l.rtl.clone(info.right.code(), l.types.typeInfo(info.type()), "undefined"));
-        ELSIF rTemp THEN
-            result := ternaryCodeImpl(info.condition, 
-                                      l.rtl.clone(info.left.code(), l.types.typeInfo(info.type()), "undefined"),
-                                      info.right.code()); 
-        END;
-    END;
-    RETURN result;
-END;
-
 BEGIN
     (*resolve recursive calls*)
     setTermTypePromotion := setTermTypePromotionProc;

+ 4 - 33
src/eberon/EberonContextInPlace.ob

@@ -32,40 +32,11 @@ END;
 
 PROCEDURE VariableInit.handleExpression(e: Expression.PType);
 VAR
-    cloneOp: LanguageContext.PCastOp;
+    resultType: Types.PStorageType;
 BEGIN
-    type <- e.type();
-    IF ~(type IS Types.PStorageType) THEN
-        Errors.raise("cannot use " + type.description() + " to initialize variable");
-    ELSIF type IS Types.POpenArray THEN
-        Errors.raise("cannot initialize variable '" + SELF.id + "' with open array");
-    ELSE
-        v <- NEW EberonContextDesignator.TypeNarrowVariable(type, FALSE, FALSE, SELF.id);
-        SELF.symbol := NEW Symbols.Symbol(SELF.id, v);
-
-        IF type IS EberonRecord.PRecord THEN
-            EberonRecord.ensureCanBeInstantiated(SELF, type, EberonRecord.instantiateForCopy);
-            IF Expression.isTemporary(e^) THEN
-                SELF.code := SELF.code + e.code();
-            ELSE
-                info <- e.info();
-                l <- SELF.root().language();
-                code <- EberonContextExpression.optimizeRecordRValue(info^, l^);
-                IF LEN(code) = 0 THEN
-                    code := l.rtl.clone(e.code(), l.types.typeInfo(type), "undefined");
-                END;
-                SELF.code := SELF.code + code;
-            END;
-        ELSE
-            IF Expression.isTemporary(e^) & (type IS Types.PArray) THEN
-                SELF.code := SELF.code + e.code();
-            ELSE
-                l <- SELF.root().language();
-                void <- l.types.implicitCast(type, type, FALSE, cloneOp);
-                SELF.code := SELF.code + cloneOp.clone(ContextHierarchy.makeLanguageContext(SELF(POINTER)), e);
-            END;
-        END;
-    END;
+    SELF.code := SELF.code + EberonContextExpression.initFromRValue(SELF(POINTER), e, "variable '" + SELF.id + "'", resultType);
+    v <- NEW EberonContextDesignator.TypeNarrowVariable(resultType, FALSE, FALSE, SELF.id);
+    SELF.symbol := NEW Symbols.Symbol(SELF.id, v);
 END;
 
 PROCEDURE VariableInit.onParsed();

+ 29 - 0
test/expected/eberon/init_array.js

@@ -5,10 +5,39 @@ var a2 = [1, 2];
 var a3 = [true, false];
 var a4 = [1 + 2 | 0, 3];
 var a5 = ["a", "bc", "def"];
+function T(){
+}
 
 function passArray(a/*ARRAY OF INTEGER*/){
 }
+
+function inPlace(){
+	var a = [1, 2, 3];
+	a[1] = 5;
+}
+
+function copy(){
+	var a = RTL$.makeArray(3, 0);
+	var aDyn = [];
+	a = [1, 2, 3].slice();
+	Array.prototype.splice.apply(aDyn, [0, Number.MAX_VALUE].concat([1, 2, 3, 4, 5]));
+}
+
+function return$(){
+	return [1, 2, 3];
+}
+
+function recordConstructors(){
+	var a = [new T()];
+	var a2 = [new T(), new T()];
+}
+
+function recordVariables(a/*T*/, v/*VAR T*/){
+	var r = new T();
+	var result = [RTL$.clone(a, {record: {}}, undefined), RTL$.clone(v, {record: {}}, undefined), RTL$.clone(r, {record: {}}, undefined)];
+}
 passArray(a1);
+passArray([1, 2, 3]);
 for (var i = 0; i <= a1.length; ++i){
 	RTL$.assert(a1[i] != 0);
 }

+ 37 - 0
test/input/eberon/init_array.ob

@@ -6,12 +6,49 @@ CONST
 	a3 = [TRUE, FALSE];
 	a4 = [1 + 2, 3];
 	a5 = ["a", "bc", "def"];
+TYPE
+	IntDynArray = ARRAY * OF INTEGER;
+
+	T = RECORD END;
 
 PROCEDURE passArray(a: ARRAY OF INTEGER);
 END;
 
+PROCEDURE inPlace();
+BEGIN
+	a <- [1, 2, 3];
+	a[1] := 5;
+END;
+
+PROCEDURE copy();
+VAR
+	a: ARRAY 3 OF INTEGER;
+	aDyn: ARRAY * OF INTEGER;
+BEGIN
+	a := [1, 2, 3];
+	aDyn := [1, 2, 3, 4, 5];
+END;
+
+PROCEDURE return(): IntDynArray;
+	RETURN [1, 2, 3];
+END;
+
+PROCEDURE recordConstructors();
+BEGIN
+	a <- [T()];
+	a2 <- [T(), T()];
+END;
+
+PROCEDURE recordVariables(a: T; VAR v: T);
+VAR
+	r: T;
+BEGIN
+	result <- [a, v, r];
+END;
+
 BEGIN
 	passArray(a1);
+	passArray([1, 2, 3]);
 
 	FOR i <- 0 TO LEN(a1) DO
 		ASSERT(a1[i] # 0);

+ 5 - 5
test/test_unit_eberon.js

@@ -633,14 +633,14 @@ exports.suite = {
              "v <- i + i",
              "v <- \"abc\" + s",
              "v <- s + \"abc\"",
+             "v <- \"abc\"",
+             "v <- \"abc\" + \"def\"",
              "v <- p()",
              "v <- void" // procedure type
             ),
         fail(["v <-", "initialization expression expected"],
              ["v <- void()", "procedure returning no result cannot be used in an expression"],
-             ["v <- NIL", "cannot use NIL to initialize variable"],
-             ["v <- \"abc\"", "cannot use multi-character string to initialize variable"],
-             ["v <- \"abc\" + \"def\"", "cannot use multi-character string to initialize variable"]
+             ["v <- NIL", "cannot use NIL to initialize variable 'v'"]
              )
         ),
     "scope": testWithContext(
@@ -1575,8 +1575,8 @@ exports.suite = {
          ),
     fail(["[]", "not parsed"],
          ["[1, TRUE]", "array's elements should have the same type: expected 'INTEGER', got 'BOOLEAN'"],
-         ["[NIL]", "array's element cannot be 'NIL'"],
-         ["[1, NIL]", "array's elements should have the same type: expected 'INTEGER', got 'NIL'"]
+         ["[NIL]", "cannot use NIL to initialize array's element"],
+         ["[1, NIL]", "cannot use NIL to initialize array's element"]
         )
     ),
 "CONST array": testWithGrammar(