Quellcode durchsuchen

fix type guard semantic: pointer type is checked for pointer variable and record type for record variable.

Vladislav Folts vor 12 Jahren
Ursprung
Commit
1a582a573c

+ 33 - 19
src/context.js

@@ -82,6 +82,8 @@ function promoteExpressionType(context, left, right){
 function checkTypeCast(from, to, msg){
     if (from instanceof Type.Pointer)
         from = from.baseType();
+    if (to instanceof Type.Pointer)
+        to = to.baseType();
 
     var t = to.baseType();
     while (t && t != from)
@@ -332,18 +334,24 @@ exports.Designator = ChainedContext.extend({
         this.__info = new Type.Variable(this.__currentType, false, false);
     },
     handleTypeCast: function(type){
-        if (!(type instanceof Type.Record))
-            throw new Errors.Error(
-                "invalid type cast: RECORD type expected as an argument of type guard, got '"
-              + type.description() + "'");
+        if (this.__currentType instanceof Type.Record){
+            if (!(type instanceof Type.Record))
+                throw new Errors.Error(
+                    "invalid type cast: RECORD type expected as an argument of RECORD type guard, got '"
+                  + type.description() + "'");
+        }
+        else if (this.__currentType instanceof Type.Pointer)
+            if (!(type instanceof Type.Pointer))
+                throw new Errors.Error(
+                    "invalid type cast: POINTER type expected as an argument of POINTER type guard, got '"
+                  + type.description() + "'");
 
         checkTypeCast(this.__currentType, type, "invalid type cast");
 
-        var code = this.rtl().typeGuard(this.__code.result(), type.name());
+        var castName = (type instanceof Type.Pointer ? type.baseType() : type).cons();
+        var code = this.rtl().typeGuard(this.__code.result(), castName);
         this.__code = new Code.SimpleGenerator(code);
 
-        if (this.__currentType instanceof Type.Pointer)
-            type = new Type.Pointer(this.genTypeName(), type);
         this.__currentType = type;
     },
     __denote: function(id){
@@ -555,7 +563,6 @@ exports.PointerDecl = ChainedContext.extend({
     init: function PointerDecl(context){
         ChainedContext.prototype.init.call(this, context);
         this.__base = undefined;
-        this.__name = this.parent().genTypeName();
    } ,
     setType: function(type){
         if (!(type instanceof Type.ForwardRecord) && !(type instanceof Type.Record))
@@ -579,13 +586,15 @@ exports.PointerDecl = ChainedContext.extend({
             scope
             );
     },
-    genTypeName: function(){
-        return this.__name + "$base";
-    },
+    isAnonymousDeclaration: function(){return true;},
     exportField: function(field){this.parent().exportField(field);},
     endParse: function(){
-        var type = new Type.Pointer(this.__name, this.__base);
-        this.parent().setType(type);
+        var parent = this.parent();
+        var name = parent.isAnonymousDeclaration() 
+            ? undefined
+            : parent.genTypeName();
+        var type = new Type.Pointer(name, this.__base);
+        parent.setType(type);
     }
 });
 
@@ -614,6 +623,7 @@ exports.ArrayDecl = ChainedContext.extend({
 
         this.__type = type;
     },
+    isAnonymousDeclaration: function(){return true;},
     endParse: function(){this.parent().setType(this.__type);}
 });
 
@@ -1379,6 +1389,7 @@ exports.VariableDeclaration = ChainedContext.extend({
     },
     setType: function(type){this.__type = type;},
     typeName: function(){return undefined;},
+    isAnonymousDeclaration: function(){return true;},
     endParse: function(){
         var v = new Type.Variable(this.__type);
         var idents = this.__idents;
@@ -1411,6 +1422,7 @@ exports.FieldListDeclaration = ChainedContext.extend({
         checkIfFieldCanBeExported(name, this.__idents, "field");
     },
     setType: function(type) {this.__type = type;},
+    isAnonymousDeclaration: function(){return true;},
     endParse: function(){
         var idents = this.__idents;
         var parent = this.parent();
@@ -1520,11 +1532,12 @@ function isTypeRecursive(type, base){
 exports.RecordDecl = ChainedContext.extend({
     init: function RecordDeclContext(context){
         ChainedContext.prototype.init.call(this, context);
-        var id = this.genTypeName();
-        this.__type = new Type.Record(id);
-        this.parent().setType(this.__type);
-        var gen = this.codeGenerator();
-        gen.write("var " + id + " = ");
+        var parent = this.parent();
+        var cons = parent.genTypeName();
+        var name = parent.isAnonymousDeclaration() ? undefined : cons;
+        this.__type = new Type.Record(name, cons);
+        parent.setType(this.__type);
+        parent.codeGenerator().write("var " + cons + " = ");
     },
     addField: function(field, type){
         if (isTypeRecursive(type, this.__type))
@@ -1546,7 +1559,7 @@ exports.RecordDecl = ChainedContext.extend({
         var gen = this.codeGenerator();
         gen.write((baseType ? baseType.name() : this.rtl().baseClass()) + ".extend(");
         gen.openScope();
-        gen.write("init: function " + type.name() + "()");
+        gen.write("init: function " + this.__type.cons() + "()");
         gen.openScope();
         if (baseType)
             gen.write(baseType.name() + ".prototype.init.call(this);\n");
@@ -1578,6 +1591,7 @@ exports.TypeDeclaration = ChainedContext.extend({
     },
     typeName: function(){return this.__id.id();},
     genTypeName: function(){return this.__id.id();},
+    isAnonymousDeclaration: function(){return false;},
     type: function(){return this.parent().type();},
     exportField: function(name){
         checkIfFieldCanBeExported(name, [this.__id], "record");

+ 3 - 1
src/procedure.js

@@ -309,7 +309,9 @@ exports.predefined = [
                 this.__baseType = type.baseType();
                 return new CheckArgumentResult(type, false);
             },
-            epilog: function(){return " = new " + this.__baseType.name() + "()";}
+            epilog: function(){
+                return " = new " + this.__baseType.cons() + "()";
+            }
         });
 
         var name = "NEW";

+ 7 - 11
src/type.js

@@ -71,10 +71,7 @@ exports.Pointer = BasicType.extend({
         this.__base = base;
     },
     description: function(){
-        var name = this.name();
-        if (name.indexOf("$") != -1)
-            return "POINTER TO " + this.baseType().description();
-        return name;
+        return this.name() || "POINTER TO " + this.baseType().description();
     },
     baseType: function(){
         if (this.__base instanceof exports.ForwardRecord)
@@ -92,11 +89,13 @@ exports.ForwardRecord = Type.extend({
 });
 
 exports.Record = BasicType.extend({
-    init: function RecordType(name){
-        BasicType.prototype.init.call(this, name, "new " + name + "()");
+    init: function RecordType(name, cons){
+        BasicType.prototype.init.call(this, name, "new " + cons + "()");
+        this.__cons = cons;        
         this.__fields = {};
         this.__base = undefined;
     },
+    cons: function(){return this.__cons;},
     addField: function(field, type){
         var name = field.id();
         if (this.__fields.hasOwnProperty(name))
@@ -115,10 +114,7 @@ exports.Record = BasicType.extend({
     baseType: function() {return this.__base;},
     setBaseType: function(type) {this.__base = type;},
     description: function(){
-        var name = this.name();
-        if (name.indexOf("$") != -1)
-            return "anonymous RECORD";
-        return name;
+        return this.name() || "anonymous RECORD";
     }
 });
 
@@ -168,7 +164,7 @@ var ExportedVariable = Variable.extend({
     init: function ExportedVariable(variable){
         Variable.prototype.init.call(this, variable.type(), variable.isVar(), true);
     },
-    idType: function(){return "imported variable";},
+    idType: function(){return "imported variable";}
 });
 
 exports.Procedure = BasicType.extend({

+ 20 - 0
test/expected/cast.js

@@ -36,13 +36,33 @@ var Derived2 = Derived1.extend({
 		this.field2 = 0;
 	}
 });
+var PAnonymousDerived = Base.extend({
+	init: function PAnonymousDerived(){
+		Base.prototype.init.call(this);
+		this.field3 = 0;
+	}
+});
 var pb = null;
 var pd1 = null;
 var pd2 = null;
+var pad = null;
+
+function p(b/*Base*/, d1/*Derived1*/){
+	RTL$.typeGuard(b, Derived1).field1 = 0;
+	RTL$.typeGuard(b, Derived2).field2 = 1;
+	RTL$.typeGuard(d1, Derived2).field2 = 2;
+}
 pd2 = new Derived2();
 pb = pd2;
 pd1 = pd2;
 RTL$.typeGuard(pb, Derived1).field1 = 0;
 RTL$.typeGuard(pb, Derived2).field2 = 1;
 RTL$.typeGuard(pd1, Derived2).field2 = 2;
+RTL$.typeGuard(pb, Derived1).field1 = 0;
+RTL$.typeGuard(pb, Derived2).field2 = 1;
+RTL$.typeGuard(pd1, Derived2).field2 = 2;
+pad = new PAnonymousDerived();
+pb = pad;
+RTL$.typeGuard(pb, PAnonymousDerived).field3 = 3;
+p(pd2, pd2);
 }();

+ 3 - 3
test/expected/modules.js

@@ -21,8 +21,8 @@ var RTL$ = {
 var m1 = function (){
 var ci = 123;
 var i = 0;
-var anonymous$1$base = RTL$.extend({
-	init: function anonymous$1$base(){
+var anonymous$1 = RTL$.extend({
+	init: function anonymous$1(){
 		this.i = 0;
 	}
 });
@@ -30,7 +30,7 @@ var pr = null;
 
 function p(){
 }
-pr = new anonymous$1$base();
+pr = new anonymous$1();
 return {
 	ci: ci,
 	i: function(){return i;},

+ 6 - 6
test/expected/new.js

@@ -20,19 +20,19 @@ var T1 = RTL$.extend({
 		this.field1 = 0;
 	}
 });
-var anonymous$1$base = RTL$.extend({
-	init: function anonymous$1$base(){
+var anonymous$1 = RTL$.extend({
+	init: function anonymous$1(){
 	}
 });
 var p = null;
 var p1 = null;
-var anonymous$3 = RTL$.extend({
-	init: function anonymous$3(){
+var anonymous$2 = RTL$.extend({
+	init: function anonymous$2(){
 		this.p = null;
 	}
 });
-var r = new anonymous$3();
-p = new anonymous$1$base();
+var r = new anonymous$2();
+p = new anonymous$1();
 p1 = new T1();
 r.p = new T1();
 }();

+ 2 - 2
test/expected/nil.js

@@ -15,8 +15,8 @@ var RTL$ = {
     }
 };
 var m = function (){
-var anonymous$1$base = RTL$.extend({
-	init: function anonymous$1$base(){
+var anonymous$1 = RTL$.extend({
+	init: function anonymous$1(){
 	}
 });
 var p = null;

+ 14 - 0
test/expected/pointer.js

@@ -21,8 +21,22 @@ var T = RTL$.extend({
 		this.i = 0;
 	}
 });
+var T2 = RTL$.extend({
+	init: function T2(){
+		this.p = null;
+	}
+});
 var r = new T();
+var r2 = null;
+var anonymous$1 = RTL$.extend({
+	init: function anonymous$1(){
+	}
+});
+var pAnonymous = null;
 r.p = new T();
 r.p.p = new T();
 r.p.i = 123;
+r2 = new T2();
+r2.p = new T();
+pAnonymous = new anonymous$1();
 }();

+ 30 - 3
test/input/cast.ob

@@ -3,16 +3,43 @@ MODULE m;
 TYPE
 	Base = RECORD END;
 	Derived1 = RECORD(Base) field1: INTEGER END;
+	PDerived1 = POINTER TO Derived1;
 	Derived2 = RECORD(Derived1) field2: INTEGER END;
+	PDerived2 = POINTER TO Derived2;
+
+    PAnonymousDerived = POINTER TO RECORD(Base) field3: INTEGER END;
+
+    (*PForward1 = POINTER TO Forward;
+    PForward2 = POINTER TO Forward;
+    Forward = RECORD END;*)
 VAR
 	pb: POINTER TO Base;
 	pd1: POINTER TO Derived1;
 	pd2: POINTER TO Derived2;
+    pad: PAnonymousDerived;
+
+PROCEDURE p(b: Base; d1: Derived1);
+BEGIN
+    b(Derived1).field1 := 0;
+    b(Derived2).field2 := 1;
+    d1(Derived2).field2 := 2;
+END p;
+
 BEGIN 
 	NEW(pd2);
 	pb := pd2;
 	pd1 := pd2;
-    pb(Derived1).field1 := 0;
-    pb(Derived2).field2 := 1;
-    pd1(Derived2).field2 := 2
+    pb(PDerived1).field1 := 0;
+    pb(PDerived2).field2 := 1;
+    pd1(PDerived2).field2 := 2;
+
+    pb^(Derived1).field1 := 0;
+    pb^(Derived2).field2 := 1;
+    pd1^(Derived2).field2 := 2;
+
+    NEW(pad);
+    pb := pad;
+    pb(PAnonymousDerived).field3 := 3;    
+
+    p(pd2^, pd2^);
 END m.

+ 9 - 0
test/input/pointer.ob

@@ -1,11 +1,20 @@
 MODULE m;
 TYPE
 	T = RECORD p: POINTER TO T; i: INTEGER END;
+	T2 = POINTER TO RECORD p: POINTER TO T(*2*) END;
 VAR
 	r: T;
+	r2: T2;
+	pAnonymous: POINTER TO RECORD END;
 
 BEGIN
 	NEW(r.p);
     NEW(r.p.p);
     r.p.i := 123;
+
+	NEW(r2);
+	NEW(r2.p);
+	(*r2.p := r2;*)
+
+	NEW(pAnonymous);
 END m.

+ 6 - 7
test/test_unit.js

@@ -362,17 +362,16 @@ var testSuite = {
     ),
 "POINTER cast": testWithContext(
     context(Grammar.expression,
-            "TYPE Base = RECORD END; Derived = RECORD (Base) END; PDerived = POINTER TO Derived;"
+            "TYPE Base = RECORD END; PBase = POINTER TO Base; Derived = RECORD (Base) END; PDerived = POINTER TO Derived;"
             + "VAR p1, p2: POINTER TO RECORD END; pBase: POINTER TO Base; pDerived: POINTER TO Derived; i: INTEGER;"),
-    pass("pBase(Derived)"),
-    fail(["pDerived(Derived)",
+    pass("pBase(PDerived)",
+         "pBase^(Derived)"),
+    fail(["pDerived(PDerived)",
           "invalid type cast: 'Derived' is not an extension of 'Derived'"],
-         ["p1(Base)", 
+         ["p1(PBase)", 
           "invalid type cast: 'Base' is not an extension of 'anonymous RECORD'"],
          ["p1(INTEGER)", 
-          "invalid type cast: RECORD type expected as an argument of type guard, got 'INTEGER'"],
-         ["p1(PDerived)",
-          "invalid type cast: RECORD type expected as an argument of type guard, got 'PDerived'"],
+          "invalid type cast: POINTER type expected as an argument of POINTER type guard, got 'INTEGER'"],
          ["i(Derived)",
           "invalid type cast: 'Derived' is not an extension of 'INTEGER'"])
     ),