فهرست منبع

Check if SELF(POINTER) was used and forbid to use variables of these types.

Vladislav Folts 11 سال پیش
والد
کامیت
ffcf6f652d
9فایلهای تغییر یافته به همراه67 افزوده شده و 23 حذف شده
  1. BIN
      bin/compiled.zip
  2. 32 4
      src/eberon/eberon_context.js
  3. 1 1
      src/ob/Module.ob
  4. 1 1
      src/ob/Procedure.ob
  5. 1 4
      src/ob/Scope.ob
  6. 6 6
      src/ob/Types.ob
  7. 3 2
      test/expected/eberon/method.js
  8. 3 2
      test/input/eberon/method.ob
  9. 20 3
      test/test_unit_eberon.js

BIN
bin/compiled.zip


+ 32 - 4
src/eberon/eberon_context.js

@@ -104,6 +104,7 @@ var MethodHeading = Context.Chained.extend({
 });
 
 function getMethodSelf(){}
+function getSelfAsPointerMsg(){}
 function getMethodSuper(){}
 
 var MethodVariable = Type.Variable.extend({
@@ -233,7 +234,7 @@ var Designator = Context.Designator.extend({
             this._advance(type, type, "this");
         } 
         else if (s == "POINTER"){
-            var typeId = Type.makeTypeId(this.__currentType);
+            var typeId = Type.makeTypeId(this.handleMessage(getSelfAsPointerMsg));
             var pointerType = Type.makePointer("", typeId);
             var info = Type.makeVariable(pointerType, true);
             this._advance(pointerType, info, "this");
@@ -374,14 +375,23 @@ var RecordType = Type.Record.extend({
         this.__definedMethods = [];
         this.__abstractMethods = [];
         this.__instantiated = false;
+        this.__createByNewOnly = false;
+        this.__declaredAsVariable = false;
         this.__lazyDefinitions = {};
         this.__nonExportedMethods = [];
     },
-    initializer: function(context){
-        if (this.__finalized)
+    initializer: function(context, forNew){
+        if (this.__finalized){
             this.__ensureNonAbstract();
-        else
+            if (!forNew)
+                this.__ensureVariableCanBeDeclared();
+        }
+        else {
             this.__instantiated = true;
+            if (!forNew)
+                this.__declaredAsVariable = true;
+        }
+
         return Type.Record.prototype.initializer.call(this, context);
     },
     findSymbol: function(id){
@@ -446,6 +456,7 @@ var RecordType = Type.Record.extend({
                 ids.push(id);
             }
     },
+    requireNewOnly: function(){this.__createByNewOnly = true;},
     abstractMethods: function(){return this.__abstractMethods;},
     __collectAbstractMethods: function(){
         var selfMethods = Object.keys(this.__declaredMethods);
@@ -463,6 +474,8 @@ var RecordType = Type.Record.extend({
         this.__collectAbstractMethods();
         if (this.__instantiated)
             this.__ensureNonAbstract();
+        if (this.__declaredAsVariable)
+            this.__ensureVariableCanBeDeclared();
         this.__ensureMethodDefinitions(this.__lazyDefinitions);
 
         for(var i = 0; i < this.__nonExportedMethods.length; ++i)
@@ -509,6 +522,17 @@ var RecordType = Type.Record.extend({
             baseType = Type.recordBase(baseType);
         }
     },
+    __ensureVariableCanBeDeclared: function(){
+        var type = this;
+        while (type){
+            if (type.__createByNewOnly)
+                throw new Errors.Error(
+                    "cannot declare a variable of type '" 
+                  + Type.typeName(type) + "' (and derived types) "
+                  + "because SELF(POINTER) was used in its method(s)");
+            type = Type.recordBase(type);
+        }
+    },
     __hasMethodDeclaration: function(id){
         var type = this;
         var result;
@@ -598,6 +622,10 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
                 throw new Errors.Error("SELF can be used only in methods");
             return this.__boundType;
         }
+        if (msg == getSelfAsPointerMsg){
+            this.__boundType.requireNewOnly();
+            return this.__boundType;
+        }
 
         if (msg == getMethodSuper)
             return this.__handleSuperCall();

+ 1 - 1
src/ob/Module.ob

@@ -30,7 +30,7 @@ PROCEDURE AnyType.description(): STRING;
     RETURN "JS.var"
 END AnyType.description;
 
-PROCEDURE AnyType.initializer(cx: Context.Type): STRING;
+PROCEDURE AnyType.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
     RETURN "undefined"
 END AnyType.initializer;
 

+ 1 - 1
src/ob/Procedure.ob

@@ -385,7 +385,7 @@ PROCEDURE makeNew(): Symbols.PSymbol;
             Errors.raise("non-exported RECORD type cannot be used in NEW");
         END;
         RETURN Code.makeSimpleExpression(
-                arg.code() + " = " + baseType.initializer(cx),
+                arg.code() + " = " + baseType.initializer(cx, TRUE),
                 NIL)
     END CallImpl.make;
 BEGIN

+ 1 - 4
src/ob/Scope.ob

@@ -1,7 +1,6 @@
 MODULE Scope;
 IMPORT 
     Errors, 
-    JS,
     JsArray, 
     JsMap, 
     Object, 
@@ -185,14 +184,12 @@ PROCEDURE Type.findSymbol(id: STRING): Symbols.PFoundSymbol;
 VAR
     result: Object.PType;
     found: Symbols.PFoundSymbol;
-    pSelf: PType;
 BEGIN
     IF ~JsMap.find(SELF.symbols, id, result) THEN
         void <- JsMap.find(SELF.stdSymbols, id, result);
     END;
     IF result # NIL THEN
-        JS.do("pSelf = this");
-        found := Symbols.makeFound(result(Symbols.PSymbol), pSelf)
+        found := Symbols.makeFound(result(Symbols.PSymbol), SELF(POINTER))
     END;
     RETURN found
 END Type.findSymbol;

+ 6 - 6
src/ob/Types.ob

@@ -17,7 +17,7 @@ TYPE
     PType* = POINTER TO Type;
 
     StorageType* = RECORD(Type)    
-        PROCEDURE initializer*(cx: Context.Type): STRING
+        PROCEDURE initializer*(cx: Context.Type; forNew: BOOLEAN): STRING
     END;
 
     TypeId* = RECORD(Id)
@@ -339,7 +339,7 @@ PROCEDURE BasicType.description(): STRING;
     RETURN SELF.name
 END BasicType.description;
 
-PROCEDURE BasicType.initializer(cx: Context.Type): STRING;
+PROCEDURE BasicType.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
     RETURN SELF.mInitializer
 END BasicType.initializer;
 
@@ -386,7 +386,7 @@ BEGIN
     RETURN result
 END Record.description;
 
-PROCEDURE Record.initializer(cx: Context.Type): STRING;
+PROCEDURE Record.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
     RETURN "new " + cx.qualifyScope(SELF.scope) + SELF.cons + "()"
 END Record.initializer;
 
@@ -457,7 +457,7 @@ BEGIN
     RETURN result
 END Pointer.description;
 
-PROCEDURE Pointer.initializer(cx: Context.Type): STRING;
+PROCEDURE Pointer.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
     RETURN "null"
 END Pointer.initializer;
 
@@ -491,7 +491,7 @@ BEGIN
     RETURN result
 END Array.description;
 
-PROCEDURE Array.initializer(cx: Context.Type): STRING;
+PROCEDURE Array.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
     RETURN SELF.mInitializer
 END Array.initializer;
 
@@ -503,7 +503,7 @@ PROCEDURE arrayLength*(a: Array): INTEGER;
     RETURN a.len
 END arrayLength;
 
-PROCEDURE Procedure.initializer(cx: Context.Type): STRING;
+PROCEDURE Procedure.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
     RETURN "null"
 END Procedure.initializer;
 

+ 3 - 2
test/expected/eberon/method.js

@@ -25,7 +25,7 @@ var D = T.extend({
 		T.prototype.init.call(this);
 	}
 });
-var d = new D();
+var dp = null;
 T.prototype.p = function(){
 	this.i = 123;
 }
@@ -54,5 +54,6 @@ D.prototype.p = function(){
 D.prototype.p2 = function(i/*INTEGER*/){
 	return T.prototype.p2.call(this, i);
 }
-d.p();
+dp = new D();
+dp.p();
 }();

+ 3 - 2
test/input/eberon/method.ob

@@ -9,7 +9,7 @@ TYPE
     PT = POINTER TO T;
     D = RECORD(T) END;
 VAR
-    d: D;
+    dp: POINTER TO D;
 
 PROCEDURE T.p();
 BEGIN
@@ -49,5 +49,6 @@ PROCEDURE D.p2(i: INTEGER): INTEGER;
 END D.p2;
 
 BEGIN
-    d.p();
+    NEW(dp);
+    dp.p();
 END m.

+ 20 - 3
test/test_unit_eberon.js

@@ -157,15 +157,32 @@ exports.suite = {
     ),
 "SELF as pointer": testWithContext(
     context(grammar.declarationSequence, 
-            "TYPE T = RECORD PROCEDURE method() END; PT = POINTER TO T;"
+            "TYPE T = RECORD PROCEDURE method() END;"
+            + "PT = POINTER TO T;"
             + "VAR pVar: PT;"
             + "PROCEDURE refProc(VAR p: PT); END refProc;"
             ),
-    pass("PROCEDURE T.method(); BEGIN pVar := SELF(POINTER) END T.method;"),
+    pass("PROCEDURE T.method(); BEGIN pVar := SELF(POINTER) END T.method;",
+         "PROCEDURE p();"
+          + "TYPE Derived = RECORD(T) END; VAR pd: POINTER TO Derived;"
+          + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN NEW(pd); pVar := SELF(POINTER); END Derived.method;"
+          + "END p;"),
     fail(["PROCEDURE T.method(); BEGIN refProc(SELF(POINTER)) END T.method;", 
           "read-only variable cannot be used as VAR parameter"],
          ["PROCEDURE T.method(); BEGIN SELF(POINTER) := pVar; END T.method;", 
-          "cannot assign to read-only variable"])
+          "cannot assign to read-only variable"],
+         ["PROCEDURE p();"
+          + "TYPE Derived = RECORD(T) END; VAR d: Derived;"
+          + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN pVar := SELF(POINTER); END Derived.method;"
+          + "END p;",
+          "cannot declare a variable of type 'Derived' (and derived types) because SELF(POINTER) was used in its method(s)"],
+         ["PROCEDURE p();"
+          + "TYPE Derived = RECORD(T) END; Derived2 = RECORD(Derived) END;"
+          + "VAR d: Derived2;"
+          + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN pVar := SELF(POINTER); END Derived.method;"
+          + "END p;",
+          "cannot declare a variable of type 'Derived' (and derived types) because SELF(POINTER) was used in its method(s)"]
+         )
     ),
 "method call": testWithContext(
     context(grammar.expression,