浏览代码

type promotion fo temporary values in expressions - first approach

Vladislav Folts 11 年之前
父节点
当前提交
d3701f7581
共有 7 个文件被更改,包括 75 次插入11 次删除
  1. 1 0
      src/context.js
  2. 51 1
      src/eberon/eberon_context.js
  3. 3 2
      src/eberon/eberon_grammar.js
  4. 3 3
      src/grammar.js
  5. 1 2
      src/ob/Operator.ob
  6. 3 2
      src/oberon/oberon_grammar.js
  7. 13 1
      test/test_unit_eberon.js

+ 1 - 0
src/context.js

@@ -960,6 +960,7 @@ function relationOp(leftType, rightType, literal, ops, context){
             break;
         case "IN":
             o = op.setHasBit;
+            break;
         }
     if (mismatch)
         throwOperatorTypeMismatch(literal, mismatch, type);

+ 51 - 1
src/eberon/eberon_context.js

@@ -110,6 +110,18 @@ var ResultVariable = Type.Variable.extend({
     idType: function(){return "procedure call " + (this.type() ? "result" : "statement");}
 });
 
+var TempVariable = Type.Variable.extend({
+    init: function TempVariable(type){
+        this.__originalType = type;
+        this.__type = 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;}
+});
+
 var IdentdefInfo = Context.IdentdefInfo.extend({
     init: function(id, exported, ro){
         Context.IdentdefInfo.prototype.init.call(this, id, exported);
@@ -205,7 +217,7 @@ var TemplValueInit = Context.Chained.extend({
         gen.write("var " + this.__id + " = ");
     },
     handleExpression: function(e){
-        var v = Type.makeVariable(e.type(), true);
+        var v = new TempVariable(e.type());
         this.__symbol = Symbol.makeSymbol(this.__id, v);
     },
     endParse: function(){
@@ -564,6 +576,26 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
     }
 });
 
+var Term = Context.Term.extend({
+    init: function EberonContext$Term(context){
+        Context.Term.prototype.init.call(this, context);
+    },
+    handleMessage: function(msg){
+        if (msg instanceof PromoteTypeMsg){
+            var promoted = msg.info;
+            promoted.promoteType(msg.type);
+            this.__promoted = promoted;
+            return undefined;
+        }
+        return Context.Term.prototype.handleMessage.call(this, msg);
+    },
+    endParse: function(){
+        if (this.__promoted)
+            this.__promoted.resetPromotion();
+        return Context.Term.prototype.endParse.call(this);
+    }
+});
+
 var AddOperator = Context.AddOperator.extend({
     init: function EberonContext$AddOperator(context){
         Context.AddOperator.prototype.init.call(this, context);
@@ -576,6 +608,11 @@ var AddOperator = Context.AddOperator.extend({
     _expectPlusOperator: function(){return "numeric type or SET or STRING";}
 });
 
+function PromoteTypeMsg(info, type){
+    this.info = info;
+    this.type = type;
+}
+
 var RelationOps = Context.RelationOps.extend({
     init: function EberonContext$RelationOps(){
         Context.RelationOps.prototype.init.call(this);
@@ -609,6 +646,18 @@ var RelationOps = Context.RelationOps.extend({
         return type == EberonString.string() 
             ? eOp.greaterEqualStr
             : Context.RelationOps.prototype.greaterEq.call(this, type);
+    },
+    is: function(type, context){
+        var impl = Context.RelationOps.prototype.is.call(this, type, context);
+        return function(left, right){
+            var d = left.designator();
+            if (d){
+                var v = d.info();
+                if (v instanceof TempVariable)
+                    context.handleMessage(new PromoteTypeMsg(v, type));
+            }
+            return impl(left, right);
+        };
     }
 });
 
@@ -721,6 +770,7 @@ exports.ProcOrMethodDecl = ProcOrMethodDecl;
 exports.RecordDecl = RecordDecl;
 exports.Repeat = Repeat;
 exports.TemplValueInit = TemplValueInit;
+exports.Term = Term;
 exports.TypeDeclaration = TypeDeclaration;
 exports.VariableDeclaration = VariableDeclaration;
 exports.While = While;

+ 3 - 2
src/eberon/eberon_grammar.js

@@ -77,8 +77,9 @@ exports.language = {
             typeDeclaration:    EbContext.TypeDeclaration,
             recordDecl:         EbContext.RecordDecl,
             variableDeclaration: EbContext.VariableDeclaration,
-            addOperator:        EbContext.AddOperator,
-            expression:         EbContext.Expression,
+            Term:               EbContext.Term,
+            AddOperator:        EbContext.AddOperator,
+            Expression:         EbContext.Expression,
             For:                EbContext.For,
             While:              EbContext.While,
             If:                 EbContext.If,

+ 3 - 3
src/grammar.js

@@ -88,9 +88,9 @@ var factor = context(
      )
     , Context.Factor);
 
-var addOperator = context(or("+", "-", "OR"), contexts.addOperator);
+var addOperator = context(or("+", "-", "OR"), contexts.AddOperator);
 var mulOperator = context(or("*", "/", "DIV", "MOD", "&"), Context.MulOperator);
-var term = context(and(factor, repeat(and(mulOperator, factor))), Context.Term);
+var term = context(and(factor, repeat(and(mulOperator, factor))), contexts.Term);
 var simpleExpression = context(
         and(optional(or("+", "-"))
           , term
@@ -98,7 +98,7 @@ var simpleExpression = context(
       , Context.SimpleExpression);
 var relation = or("=", "#", "<=", "<", ">=", ">", "IN", "IS");
 var expression = context(and(simpleExpression, optional(and(relation, simpleExpression)))
-                       , contexts.expression);
+                       , contexts.Expression);
 var constExpression = expression;
 
 var element = context(and(expression, optional(and("..", expression))), Context.SetElement);

+ 1 - 2
src/ob/Operator.ob

@@ -236,13 +236,12 @@ END binaryPred;
 PROCEDURE unary(e: Code.PExpression; op: UnaryOp; code: STRING): Code.PExpression;
 VAR
     value: Code.PConst;
-    resultCode: STRING;
 BEGIN
     value := e.constValue();
     IF value # NIL THEN
         value := op(value);
     END;
-    resultCode := code 
+    resultCode <- code 
                 + Code.adjustPrecedence(Code.derefExpression(e), Precedence.unary);
     RETURN Code.makeExpression(resultCode, e.type(), NIL, value)
 END unary;

+ 3 - 2
src/oberon/oberon_grammar.js

@@ -64,8 +64,9 @@ exports.language = {
             typeDeclaration:    Context.TypeDeclaration,
             recordDecl:         ObContext.RecordDecl,
             variableDeclaration: ObContext.VariableDeclaration,
-            addOperator:        Context.AddOperator,
-            expression:         Context.Expression,
+            Term:               Context.Term,
+            AddOperator:        Context.AddOperator,
+            Expression:         Context.Expression,
             For:                Context.For,
             While:              Context.While,
             If:                 Context.If,

+ 13 - 1
test/test_unit_eberon.js

@@ -387,8 +387,20 @@ exports.suite = {
         context(grammar.declarationSequence,
                 ""),
         pass(),
-        fail(["PROCEDURE p(); BEGIN v <- 0; v := 0; END p;", "cannot assign to read-only variable"]
+        fail(["PROCEDURE p(); BEGIN v <- 0; v := 0; END p;", 
+              "cannot assign to temporary variable"]
             )
+        ),
+    "type promotion": testWithContext(
+        context(grammar.declarationSequence,
+                "TYPE Base = RECORD END;"
+                + "Derived = RECORD (Base) flag: BOOLEAN END;"
+                + "PDerived = POINTER TO Derived;"
+                + "VAR pBase: POINTER TO Base;"
+               ),
+        pass("PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & 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"])
         )
     }
 };