浏览代码

negate type promotion in conditions + fixes

Vladislav Folts 11 年之前
父节点
当前提交
7b8f86ea06
共有 6 个文件被更改,包括 99 次插入33 次删除
  1. 二进制
      bin/compiled.zip
  2. 75 31
      src/eberon/eberon_context.js
  3. 1 0
      src/eberon/eberon_grammar.js
  4. 1 1
      src/grammar.js
  5. 1 0
      src/oberon/oberon_grammar.js
  6. 21 1
      test/test_unit_eberon.js

二进制
bin/compiled.zip


+ 75 - 31
src/eberon/eberon_context.js

@@ -115,12 +115,20 @@ var TempVariable = Type.Variable.extend({
     init: function TempVariable(type){
         this.__originalType = type;
         this.__type = type;
+        this.__negate = false;
+    },
+    type: function(){
+        return this.__negate ? this.__originalType : this.__type;
     },
-    type: function(){return this.__type;},
     isReadOnly: function(){return true;},
     idType: function(){return "temporary variable";},
-    promoteType: function(t){this.__type = t;},
-    resetPromotion: function(){this.__type = this.__originalType;}
+    promoteType: function(t){
+        this.__type = t;
+    },
+    negateType: function(){this.__negate = !this.__negate;},
+    resetPromotion: function(){
+        this.__type = this.__originalType;
+    }
 });
 
 var IdentdefInfo = Context.IdentdefInfo.extend({
@@ -175,9 +183,6 @@ var Designator = Context.Designator.extend({
         if (msg == Context.endCallMsg)
             return this.__endCall();
         
-        // this is function call and it breaks type promotion
-        if (msg instanceof PromoteTypeMsg)
-            return undefined;
         return Context.Designator.prototype.handleMessage.call(this, msg);
     },
     handleExpression: function(e){
@@ -237,6 +242,7 @@ var TemplValueInit = Context.Chained.extend({
 var ExpressionProcedureCall = Context.Chained.extend({
     init: function EberonContext$init(context){
         Context.Chained.prototype.init.call(this, context);
+        this.__typePromotion = new TypePromotionHandler();
     },
     setDesignator: function(d){
         var info = d.info();
@@ -245,6 +251,15 @@ var ExpressionProcedureCall = Context.Chained.extend({
             parent.handleExpression(info.expression());
         else
             parent.setDesignator(d);
+    },
+    handleMessage: function(msg){
+        if (this.__typePromotion.handleMessage(msg))
+            return;
+
+        return Context.Chained.prototype.handleMessage.call(this, msg);
+    },
+    endParse: function(){
+        this.__typePromotion.reset();
     }
 });
 
@@ -530,6 +545,7 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
             return undefined;
         }
 
+        // reset type promotion made in separate statement
         if (msg instanceof TransferPromotedTypesMsg){
             var types = msg.types;
             for(var i = 0; i < types.length; ++i)
@@ -591,31 +607,26 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
     }
 });
 
-var Term = Context.Term.extend({
-    init: function EberonContext$Term(context){
-        Context.Term.prototype.init.call(this, context);
-        this.__promote = undefined;
-        this.__promotedTypes = [];
+var Factor = Context.Factor.extend({
+    init: function EberonContext$Factor(context){
+        Context.Factor.prototype.init.call(this, context);
+        this.__typePromotion = new TypePromotionHandler();
+        this.__negate = false;
     },
     handleMessage: function(msg){
-        if (msg instanceof PromoteTypeMsg){
-            this.__promote = msg;
+        if (this.__typePromotion.handleMessage(msg))
             return;
-        }
-        return Context.Term.prototype.handleMessage.call(this, msg);
+        return Context.Factor.prototype.handleMessage.call(this, msg);
     },
-    handleLogicalAnd: function(){
-        if (this.__promote){
-            var promoted = this.__promote.info;
-            promoted.promoteType(this.__promote.type);
-            this.__promotedTypes.push(promoted);
-            this.__promote = undefined;
-        }
+    handleLiteral: function(s){
+        if (s == "~")
+            this.__negate = !this.__negate;
+        Context.Factor.prototype.handleLiteral.call(this, s);
     },
     endParse: function(){
-        if (this.__promotedTypes.length)
-            this.handleMessage(new TransferPromotedTypesMsg(this.__promotedTypes));
-        return Context.Term.prototype.endParse.call(this);
+        if (this.__negate)
+            this.__typePromotion.negate();
+        this.__typePromotion.transferTo(this.parent());
     }
 });
 
@@ -628,7 +639,10 @@ var AddOperator = Context.AddOperator.extend({
             return eOp.addStr;
         return Context.AddOperator.prototype._matchPlusOperator.call(this, type);
     },
-    _expectPlusOperator: function(){return "numeric type or SET or STRING";}
+    _expectPlusOperator: function(){return "numeric type or SET or STRING";},
+    endParse: function(){
+        this.handleMessage(resetTypePromotionMsg);
+    }
 });
 
 var MulOperator = Context.MulOperator.extend({
@@ -636,8 +650,8 @@ var MulOperator = Context.MulOperator.extend({
         Context.MulOperator.prototype.init.call(this, context);
     },
     handleLiteral: function(s){
-        if (s == "&")
-            this.parent().handleLogicalAnd();
+        if (s != "&")
+            this.handleMessage(resetTypePromotionMsg);
         return Context.MulOperator.prototype.handleLiteral.call(this, s);
     }
 });
@@ -647,6 +661,8 @@ function PromoteTypeMsg(info, type){
     this.type = type;
 }
 
+function resetTypePromotionMsg(){}
+
 function TransferPromotedTypesMsg(types){
     this.types = types;
 }
@@ -704,6 +720,21 @@ var relationOps = new RelationOps();
 var Expression = Context.Expression.extend({
     init: function EberonContext$Expression(context){
         Context.Expression.prototype.init.call(this, context, relationOps);
+        this.__typePromotion = new TypePromotionHandler();
+    },
+    handleMessage: function(msg){
+        if (this.__typePromotion.handleMessage(msg))
+            return;
+
+        return Context.Expression.prototype.handleMessage.call(this, msg);
+    },
+    handleLiteral: function(s){
+        this.__typePromotion.reset();
+        Context.Expression.prototype.handleLiteral.call(this, s);
+    },
+    endParse: function(){
+        this.__typePromotion.transferTo(this.parent());
+        return Context.Expression.prototype.endParse.call(this);
     }
 });
 
@@ -733,16 +764,28 @@ var TypePromotionHandler = Class.extend({
             return true;
         }
         if (msg instanceof TransferPromotedTypesMsg){
-            this.__promotedTypes = msg.types;
+            Array.prototype.push.apply(this.__promotedTypes, msg.types);
+            return true;
+        }
+        if (msg == resetTypePromotionMsg){
+            this.reset();
             return true;
         }
     return false;
     },
+    negate: function(){
+        for(var i = 0; i < this.__promotedTypes.length; ++i)
+            this.__promotedTypes[i].negateType();
+    },
     reset: function(){
         for(var i = 0; i < this.__promotedTypes.length; ++i)
             this.__promotedTypes[i].resetPromotion();
         this.__promotedTypes = [];
     },
+    transferTo: function(context){
+        if (this.__promotedTypes.length)
+            context.handleMessage(new TransferPromotedTypesMsg(this.__promotedTypes));
+    }
 });
 
 var If = Context.If.extend({
@@ -761,7 +804,7 @@ var If = Context.If.extend({
     handleLiteral: function(s){
         Context.If.prototype.handleLiteral.call(this, s);
         if (s == "ELSIF" || s == "ELSE"){
-            this.__typePromotion.reset();
+            this.__typePromotion.negate();
             this.__newScope();
         }
     },
@@ -838,12 +881,13 @@ exports.If = If;
 exports.MethodHeading = MethodHeading;
 exports.MulOperator = MulOperator;
 exports.AssignmentOrProcedureCall = AssignmentOrProcedureCall;
+exports.Factor = Factor;
 exports.ProcOrMethodId = ProcOrMethodId;
 exports.ProcOrMethodDecl = ProcOrMethodDecl;
 exports.RecordDecl = RecordDecl;
 exports.Repeat = Repeat;
 exports.TemplValueInit = TemplValueInit;
-exports.Term = Term;
+exports.Term = Context.Term;
 exports.TypeDeclaration = TypeDeclaration;
 exports.VariableDeclaration = VariableDeclaration;
 exports.While = While;

+ 1 - 0
src/eberon/eberon_grammar.js

@@ -77,6 +77,7 @@ exports.language = {
             typeDeclaration:    EbContext.TypeDeclaration,
             recordDecl:         EbContext.RecordDecl,
             variableDeclaration: EbContext.VariableDeclaration,
+            Factor:             EbContext.Factor,
             Term:               EbContext.Term,
             AddOperator:        EbContext.AddOperator,
             MulOperator:        EbContext.MulOperator,

+ 1 - 1
src/grammar.js

@@ -86,7 +86,7 @@ var factor = context(
      , and("~", function(stream, context){
                     return factor(stream, context);}) // break recursive declaration of factor
      )
-    , Context.Factor);
+    , contexts.Factor);
 
 var addOperator = context(or("+", "-", "OR"), contexts.AddOperator);
 var mulOperator = context(or("*", "/", "DIV", "MOD", "&"), contexts.MulOperator);

+ 1 - 0
src/oberon/oberon_grammar.js

@@ -64,6 +64,7 @@ exports.language = {
             typeDeclaration:    Context.TypeDeclaration,
             recordDecl:         ObContext.RecordDecl,
             variableDeclaration: ObContext.VariableDeclaration,
+            Factor:             Context.Factor,
             Term:               Context.Term,
             AddOperator:        Context.AddOperator,
             MulOperator:        Context.MulOperator,

+ 21 - 1
test/test_unit_eberon.js

@@ -402,13 +402,19 @@ exports.suite = {
         pass("PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & b.flag); END p;",
              "PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & bVar & b.flag); END p;",
              "PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & (bVar OR b.flag)); END p;",
-             "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & (b2 IS PDerived) & b1.flag & b2.flag); END p;"
+             "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & (b2 IS PDerived) & b1.flag & b2.flag); END p;",
+             "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & proc(TRUE) & b1.flag); END p;",
+             "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & ~proc(TRUE) & b1.flag); END p;",
+             "PROCEDURE p(); BEGIN b <- pBase; ASSERT(~(~(b IS PDerived)) & b.flag); END p;",
+             "PROCEDURE p(); BEGIN b <- pBase; ASSERT(~~(b IS PDerived) & b.flag); END p;"
              //TODO: "PROCEDURE p(); BEGIN b <- pBase; ASSERT(((b IS PDerived) = TRUE) & b.flag); END p;",
              ),
         fail(["PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) OR b.flag); END p;",
               "type 'Base' has no 'flag' field"],
              ["PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) OR bVar & b.flag); END p;",
               "type 'Base' has no 'flag' field"],
+             ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(~(b IS PDerived) & b.flag); END p;",
+              "type 'Base' has no 'flag' field"],
              ["PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT(((b1 IS PDerived) & (b2 IS PDerived) OR bVar) & b1.flag); END p;",
               "type 'Base' has no 'flag' field"],
              ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(proc(b IS PDerived) & proc(b.flag)); END p;",
@@ -418,6 +424,8 @@ exports.suite = {
              ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(((b IS PDerived) = FALSE) & b.flag); END p;",
               "type 'Base' has no 'flag' field"],
              ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(b IS PDerived); ASSERT(b.flag); END p;",
+              "type 'Base' has no 'flag' field"],
+             ["PROCEDURE p(); BEGIN b <- pBase; bVar := b IS PDerived; ASSERT(b.flag); END p;",
               "type 'Base' has no 'flag' field"]
              )
         ),
@@ -442,6 +450,18 @@ exports.suite = {
              ["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN ELSIF TRUE THEN b.flag := FALSE; END; END p;",
               "type 'Base' has no 'flag' field"]
              )
+        ),
+    "negate type promotion in condition": testWithContext(
+        context(grammar.declarationSequence,
+                "TYPE Base = RECORD END;"
+                + "Derived = RECORD (Base) flag: BOOLEAN END;"
+                + "PDerived = POINTER TO Derived;"
+                + "VAR pBase: POINTER TO Base; bVar: BOOLEAN;"
+                + "PROCEDURE proc(b: BOOLEAN): BOOLEAN; RETURN b END proc;"
+               ),
+        pass("PROCEDURE p(); BEGIN b <- pBase; IF ~(b IS PDerived) THEN ELSE b.flag := FALSE; END; END p;"
+             ),
+        fail()
         )
     }
 };