浏览代码

temporary values in progress

Vladislav Folts 11 年之前
父节点
当前提交
9b639a281f

+ 27 - 0
src/eberon/eberon_context.js

@@ -188,6 +188,32 @@ var Designator = Context.Designator.extend({
     }
 });
 
+var TemplValueInit = Context.Chained.extend({
+    init: function EberonContext$TemplValueInit(context){
+        Context.Chained.prototype.init.call(this, context);
+        this.__id = undefined;
+        this.__symbol = undefined;
+    },
+    handleIdent: function(id){
+        this.__id = id;
+    },
+    handleLiteral: function(){
+        var gen = this.codeGenerator();
+        gen.write("var " + this.__id + " = ");
+    },
+    handleExpression: function(e){
+        var v = Type.makeVariable(e.type(), true);
+        this.__symbol = Symbol.makeSymbol(this.__id, v);
+    },
+    endParse: function(){
+        if (!this.__symbol)
+            return false;
+
+        this.currentScope().addSymbol(this.__symbol);
+        return true;
+    }
+});
+
 var ExpressionProcedureCall = Context.Chained.extend({
     init: function EberonContext$init(context){
         Context.Chained.prototype.init.call(this, context);
@@ -606,5 +632,6 @@ exports.AssignmentOrProcedureCall = AssignmentOrProcedureCall;
 exports.ProcOrMethodId = ProcOrMethodId;
 exports.ProcOrMethodDecl = ProcOrMethodDecl;
 exports.RecordDecl = RecordDecl;
+exports.TemplValueInit = TemplValueInit;
 exports.TypeDeclaration = TypeDeclaration;
 exports.VariableDeclaration = VariableDeclaration;

+ 9 - 6
src/eberon/eberon_grammar.js

@@ -12,6 +12,7 @@ var context = Parser.context;
 var optional = Parser.optional;
 var or = Parser.or;
 var repeat = Parser.repeat;
+var required = Parser.required;
 
 function makeProcedureHeading(ident, identdef, formalParameters){
     return and("PROCEDURE",
@@ -20,22 +21,24 @@ function makeProcedureHeading(ident, identdef, formalParameters){
                );
 }
 
-function makeAssignmentOrProcedureCall(designator, assignment){
-    return context(and(designator, optional(assignment)),
-                   EbContext.AssignmentOrProcedureCall);
+function makeAssignmentOrProcedureCall(ident, designator, assignment, expression){
+    return or(
+        context(and(ident, "<-", required(expression, "initialization expression expected")), EbContext.TemplValueInit),
+        context(and(designator, optional(assignment)), EbContext.AssignmentOrProcedureCall)
+        );
 }
 
 function makeIdentdef(ident){
     return context(and(ident, optional(or("*", "-"))), EbContext.Identdef);
 }
 
-function makeDesignator(qualident, selector, actualParameters){
+function makeDesignator(ident, qualident, selector, actualParameters){
     var designator = context(
         and(or("SELF", "SUPER", qualident), repeat(or(selector, actualParameters))), EbContext.Designator);
     return { 
         factor: context(designator, EbContext.ExpressionProcedureCall),
-        assignmentOrProcedureCall: function(assignment){
-            return makeAssignmentOrProcedureCall(designator, assignment);
+        assignmentOrProcedureCall: function(assignment, expression){
+            return makeAssignmentOrProcedureCall(ident, designator, assignment, expression);
         }
     };
 }

+ 2 - 1
src/grammar.js

@@ -53,6 +53,7 @@ var selector = or(and(point, ident)
                 , context(and("(", qualident, ")"), Context.TypeCast)
                 );
 var designator = makeDesignator(
+        ident,
         qualident, 
         selector,
         // break recursive declaration of actualParameters
@@ -111,7 +112,7 @@ var assignment = and(context(or(":=", "="), Context.CheckAssignment),
                      required(expression, "expression expected"));
 
 var statement = optional(or(
-                   emit(designator.assignmentOrProcedureCall(assignment), Context.emitEndStatement)
+                   emit(designator.assignmentOrProcedureCall(assignment, expression), Context.emitEndStatement)
                    // break recursive declaration of ifStatement/caseStatement/whileStatement/repeatStatement
                  , function(stream, context){return ifStatement(stream, context);}
                  , function(stream, context){return caseStatement(stream, context);}

+ 1 - 1
src/oberon/oberon_grammar.js

@@ -31,7 +31,7 @@ function makeIdentdef(ident){
     return context(and(ident, optional("*")), Context.Identdef);
 }
 
-function makeDesignator(qualident, selector, actualParameters){
+function makeDesignator(ident, qualident, selector, actualParameters){
     var designator = context(and(qualident, repeat(selector)), Context.Designator);
     return { 
         factor: context(and(designator, optional(actualParameters)), ObContext.ExpressionProcedureCall),

+ 51 - 0
test/expected/eberon/temporary_value.js

@@ -0,0 +1,51 @@
+var RTL$ = {
+    extend: function extend(methods){
+        function Type(){
+            for(var m in methods)
+                this[m] = methods[m];
+        }
+        Type.prototype = this.prototype;
+
+        var result = methods.init;
+        result.prototype = new Type(); // inherit this.prototype
+        result.prototype.constructor = result; // to see constructor name in diagnostic
+        
+        result.extend = extend;
+        return result;
+    }
+};
+var m = function (){
+var T = RTL$.extend({
+	init: function T(){
+	}
+});
+var r = new T();
+var i = 0;
+
+function p(){
+	return false;
+}
+
+function void$(){
+}
+
+function valueArgs(r/*T*/, i/*INTEGER*/){
+	var v1 = r;
+	var v2 = i;
+}
+
+function varArgs(r/*VAR T*/, i/*VAR INTEGER*/){
+	var v1 = r;
+	var v2 = i;
+}
+var v1 = 0;
+var v2 = 1.23;
+var v3 = "abc";
+var v4 = true;
+var v5 = i;
+var v6 = i + i | 0;
+var v7 = p();
+var v8 = void$;
+var do$ = 0;
+var tempRecord = r;
+}();

+ 42 - 0
test/input/eberon/temporary_value.ob

@@ -0,0 +1,42 @@
+MODULE m;
+
+TYPE
+    T = RECORD
+    END;
+
+VAR 
+    r: T;
+    i: INTEGER;
+
+PROCEDURE p(): BOOLEAN; 
+    RETURN FALSE
+END p;
+
+PROCEDURE void();
+END void;
+
+PROCEDURE valueArgs(r: T; i: INTEGER);
+BEGIN
+    v1 <- r;
+    v2 <- i;
+END valueArgs;
+
+PROCEDURE varArgs(VAR r: T; VAR i: INTEGER);
+BEGIN
+    v1 <- r;
+    v2 <- i;
+END varArgs;
+
+BEGIN
+    v1 <- 0;
+    v2 <- 1.23;
+    v3 <- "abc";
+    v4 <- TRUE;
+    v5 <- i;
+    v6 <- i + i;
+    v7 <- p();
+    v8 <- void;
+    do <- {};
+
+    tempRecord <- r;
+END m.

+ 1 - 0
test/test.js

@@ -73,6 +73,7 @@ function run(tests){
         console.log("All OK!");
     else
         console.log(stat.failCount + " test(s) failed");
+    return !stat.failCount;
 }
 
 exports.run = run;

+ 10 - 8
test/test_compile.js

@@ -155,13 +155,15 @@ function main(){
         };
     }
 
-    Test.run({"common": {"oberon": makeCommonTests(oberon, "oberon"),
-                         "eberon": makeCommonTests(eberon, "eberon")
-                        },
-              "eberon": {"expect OK": makeTests(expectOk, eberonDirs, eberon),
-                         "run": makeTests(run, eberonRunDirs, eberon)
-                        }
-             });
+    var result =
+        Test.run({"common": {"oberon": makeCommonTests(oberon, "oberon"),
+                             "eberon": makeCommonTests(eberon, "eberon")
+                            },
+                  "eberon": {"expect OK": makeTests(expectOk, eberonDirs, eberon),
+                             "run": makeTests(run, eberonRunDirs, eberon)
+                            }
+                 });
+    return result ? 0 : -1;
 }
 
-main();
+process.exit(main());

+ 3 - 1
test/test_unit.js

@@ -1428,7 +1428,7 @@ return {
     };
 }
 
-Test.run({
+var result = Test.run({
     "common": {
         "oberon": makeSuiteForGrammar(oberon),
         "eberon": makeSuiteForGrammar(eberon)
@@ -1436,3 +1436,5 @@ Test.run({
     "eberon": TestUnitEberon.suite,
     "oberon": TestUnitOberon.suite
 });
+if (typeof process != "undefined")
+    process.exit(result ? 0 : -1);

+ 40 - 1
test/test_unit_eberon.js

@@ -338,5 +338,44 @@ exports.suite = {
          ["int()()", "PROCEDURE expected, got 'INTEGER'"],
          ["returnProc()", "procedure returning a result cannot be used as a statement"] // call is not applied implicitly to result
         )
-    )
+    ),
+"temporary values": {
+    "initialization": testWithContext(
+        context(grammar.statement,
+                "VAR i: INTEGER;"
+                + "PROCEDURE p(): BOOLEAN; RETURN FALSE END p;"
+                + "PROCEDURE void(); END void;"
+               ),
+        pass("v <- 0",
+             "v <- 1.23",
+             "v <- \"abc\"",
+             "v <- TRUE",
+             "v <- i",
+             "v <- i + i",
+             "v <- p()",
+             "v <- void" // procedure type
+            ),
+        fail(["v <-", "initialization expression expected"],
+             ["v <- void()", "procedure returning no result cannot be used in an expression"])
+        ),
+    "scope": testWithContext(
+        context(grammar.declarationSequence,
+                "VAR i: INTEGER;"),
+        pass("PROCEDURE p(); BEGIN v1 <- 0; v2 <-0; END p;",
+             "PROCEDURE p(); BEGIN i <- 0; END p;",
+             "PROCEDURE p(); BEGIN WHILE FALSE DO v <- 0; END; WHILE FALSE DO v <- 0; END; END p;"
+             ),
+        fail(["PROCEDURE p(); BEGIN v <- 0; v <-0; END p;", "'v' already declared"],
+             ["PROCEDURE p(); VAR v: INTEGER; BEGIN v <- 0; END p;", "'v' already declared"],
+             ["PROCEDURE p(); BEGIN v <- 0; WHILE FALSE DO v <- 0; END; END p;", "'v' already declared"]
+            )
+        ),
+    "read-only": testWithContext(
+        context(grammar.declarationSequence,
+                ""),
+        pass(),
+        fail(["PROCEDURE p(); BEGIN v <- 0; v := 0; END p;", "cannot assign to read-only variable"]
+            )
+        )
+    }
 };