Browse Source

In place variable can be used as FOR variable.

Vladislav Folts 11 years ago
parent
commit
6730d7fea3

BIN
bin/compiled.zip


+ 24 - 16
src/context.js

@@ -1489,29 +1489,37 @@ exports.For = ChainedContext.extend({
             throw new Errors.Error(
                   "'" + s.id() + "' is a '" 
 		+ type.description() + "' variable, 'FOR' control variable must be 'INTEGER'");
-        this.codeGenerator().write("for (" + id + " = ");
+        this._handleInitCode(id, "for (" + id + " = ");
+    },
+    _handleInitCode: function(id, code){
         this.__var = id;
+        this.codeGenerator().write(code);
+    },
+    _handleInitExpression: function(type){
+        if (type != basicTypes.integer)
+            throw new Errors.Error(
+                "'INTEGER' expression expected to assign '" + this.__var
+                + "', got '" + type.description() + "'");
+        this.__initExprParsed = true;
     },
     handleExpression: function(e){
         var type = e.type();
-        var value = e.constValue();
-        if (type !== basicTypes.integer)
-            throw new Errors.Error(
-                !this.__initExprParsed
-                    ? "'INTEGER' expression expected to assign '" + this.__var
-                      + "', got '" + type.description() + "'"
-                    : !this.__toParsed
-                    ? "'INTEGER' expression expected as 'TO' parameter, got '" + type.description() + "'"
-                    : "'INTEGER' expression expected as 'BY' parameter, got '" + type.description() + "'"
-                    );
         if (!this.__initExprParsed)
-            this.__initExprParsed = true;
-        else if (!this.__toParsed)
+            this._handleInitExpression(type);
+        else if (!this.__toParsed) {
+            if (type != basicTypes.integer)
+                throw new Errors.Error(
+                    "'INTEGER' expression expected as 'TO' parameter, got '" + type.description() + "'");
             this.__toParsed = true;
-        else if ( value === undefined )
-            throw new Errors.Error("constant expression expected as 'BY' parameter");
-        else
+        }
+        else {
+            if (type != basicTypes.integer)
+                throw new Errors.Error("'INTEGER' expression expected as 'BY' parameter, got '" + type.description() + "'");
+            var value = e.constValue();
+            if ( value === undefined )
+                throw new Errors.Error("constant expression expected as 'BY' parameter");
             this.__by = value.value;
+        }
     },
     codeGenerator: function(){
         if (this.__initExprParsed && !this.__toParsed)

+ 30 - 13
src/eberon/eberon_context.js

@@ -249,45 +249,57 @@ var Designator = Context.Designator.extend({
     }
 });
 
-var TemplValueInit = Context.Chained.extend({
-    init: function EberonContext$TemplValueInit(context){
+var InPlaceVariableInit = Context.Chained.extend({
+    init: function EberonContext$InPlaceVariableInit(context){
         Context.Chained.prototype.init.call(this, context);
         this.__id = undefined;
-        this.__symbol = undefined;
-        this.__code = undefined;
+        this._symbol = undefined;
+        this._code = undefined;
     },
     codeGenerator: function(){return Code.nullGenerator();},
     handleIdent: function(id){
         this.__id = id;
     },
     handleLiteral: function(){
-        this.__code = "var " + this.__id + " = ";
+        this._code = "var " + this.__id + " = ";
     },
     handleExpression: function(e){
         var type = e.type();
         var v = Type.isString(type) ? new InPlaceStringLiteral(type) 
                                     : new TypeNarrowVariable(type, false, false);
-        this.__symbol = Symbol.makeSymbol(this.__id, v);
+        this._symbol = Symbol.makeSymbol(this.__id, v);
         if (type instanceof Type.Record)
-            this.__code += this.language().rtl.clone(e.code());
+            this._code += this.language().rtl.clone(e.code());
         else if (type instanceof Type.Array){
             if (Type.arrayLength(type) == Type.openArrayLength)
                 throw new Errors.Error("cannot initialize variable '" + this.__id + "' with open array");
-            this.__code += this.language().rtl.clone(e.code());
+            this._code += this.language().rtl.clone(e.code());
         }
         else
-            this.__code += Code.derefExpression(e).code();
+            this._code += Code.derefExpression(e).code();
+    },
+    _onParsed: function(){
+        this.parent().codeGenerator().write(this._code);
     },
     endParse: function(){
-        if (!this.__symbol)
+        if (!this._symbol)
             return false;
 
-        this.currentScope().addSymbol(this.__symbol);
-        this.parent().codeGenerator().write(this.__code);
+        this.currentScope().addSymbol(this._symbol);
+        this._onParsed();
         return true;
     }
 });
 
+var InPlaceVariableInitFor = InPlaceVariableInit.extend({
+    init: function EberonContext$InPlaceVariableInitFor(context){
+        InPlaceVariableInit.prototype.init.call(this, context);
+    },
+    _onParsed: function(){
+        this.parent().handleInPlaceInit(this._symbol, this._code);
+    }
+});
+
 var ExpressionProcedureCall = Context.Chained.extend({
     init: function EberonContext$init(context){
         Context.Chained.prototype.init.call(this, context);
@@ -1035,6 +1047,10 @@ var For = Context.For.extend({
             this.language().stdSymbols);
         this.pushScope(scope);
     },
+    handleInPlaceInit: function(symbol, code){
+        this._handleInitCode(symbol.id(), "for (" + code);
+        this._handleInitExpression(symbol.info().type());
+    },
     endParse: function(){
         this.popScope();
         Context.For.prototype.endParse.call(this);
@@ -1072,7 +1088,8 @@ exports.ProcOrMethodDecl = ProcOrMethodDecl;
 exports.RecordDecl = RecordDecl;
 exports.Repeat = Repeat;
 exports.SimpleExpression = SimpleExpression;
-exports.TemplValueInit = TemplValueInit;
+exports.InPlaceVariableInit = InPlaceVariableInit;
+exports.InPlaceVariableInitFor = InPlaceVariableInitFor;
 exports.Term = Term;
 exports.TypeDeclaration = TypeDeclaration;
 exports.VariableDeclaration = VariableDeclaration;

+ 11 - 1
src/eberon/eberon_grammar.js

@@ -21,9 +21,13 @@ function makeProcedureHeading(ident, identdef, formalParameters){
                );
 }
 
+function makeInPlaceInit(ident, expression, inPlaceContext){
+    return context(and(ident, "<-", required(expression, "initialization expression expected")), inPlaceContext);
+}
+
 function makeAssignmentOrProcedureCall(ident, designator, assignment, expression){
     return or(
-        context(and(ident, "<-", required(expression, "initialization expression expected")), EbContext.TemplValueInit),
+        makeInPlaceInit(ident, expression, EbContext.InPlaceVariableInit),
         context(and(designator, optional(assignment)), EbContext.AssignmentOrProcedureCall)
         );
 }
@@ -65,6 +69,11 @@ function makeFieldList(identdef, identList, type, formalParameters){
         Context.FieldListDeclaration);
 }
 
+function makeForInit(ident, expression, assignment){
+    return or(makeInPlaceInit(ident, expression, EbContext.InPlaceVariableInitFor), 
+              and(ident, assignment));
+}
+
 exports.language = {
     grammar: Grammar.make(
         makeIdentdef,
@@ -72,6 +81,7 @@ exports.language = {
         makeProcedureHeading,
         makeProcedureDeclaration,
         makeFieldList, 
+        makeForInit,
         { 
             constDeclaration:   EbContext.ConstDecl, 
             typeDeclaration:    EbContext.TypeDeclaration,

+ 2 - 1
src/grammar.js

@@ -27,6 +27,7 @@ function make(makeIdentdef,
               makeProcedureHeading, 
               makeProcedureDeclaration,
               makeFieldList,
+              makeForInit,
               contexts,
               reservedWords
               ){
@@ -142,7 +143,7 @@ var repeatStatement = and("REPEAT",
                                   contexts.Repeat));
 
 var forStatement = and("FOR", 
-                       context(and(ident, ":=", expression, "TO", expression
+                       context(and(makeForInit(ident, expression, assignment), "TO", expression
                                  , optional(and("BY", constExpression))
                                  , emit("DO", Context.emitForBegin)
                                  , statementSequence, required("END", "END expected (FOR)"))

+ 1 - 3
src/ob/Code.ob

@@ -130,11 +130,9 @@ PROCEDURE SimpleGenerator.result(): STRING;
 END SimpleGenerator.result;
 
 PROCEDURE putIndent(s: STRING; indent: INTEGER): STRING;
-VAR
-    i: INTEGER;
 BEGIN
     result <- s;
-    FOR i := 0 TO indent - 1 DO
+    FOR i <- 0 TO indent - 1 DO
         result := result + kTab;
     END;
     RETURN result

+ 2 - 4
src/ob/Procedure.ob

@@ -250,14 +250,13 @@ VAR
     VAR
         expectedArgs: JsArray.Type;
         a: Object.PType;
-        i: INTEGER;
 
     BEGIN
         expectedArgs := SELF.args;
         IF expectedArgs # NIL THEN
             processArguments(args, expectedArgs, SELF.argumentsCode, cx.types);
         ELSE
-            FOR i := 0 TO JsArray.len(args) - 1 DO
+            FOR i <- 0 TO JsArray.len(args) - 1 DO
                 a := JsArray.at(args, i);
                 SELF.argumentsCode.write(a(Code.PExpression), NIL, NIL);
             END;
@@ -870,7 +869,6 @@ PROCEDURE dumpProcArgs(proc: Type): STRING;
 VAR
     result: STRING;
     len: INTEGER;
-    i: INTEGER;
     arg: Object.PType;
 BEGIN
     len := JsArray.len(proc.mArgs);
@@ -880,7 +878,7 @@ BEGIN
         END;
     ELSE
         result := "(";
-        FOR i := 0 TO len - 1 DO
+        FOR i <- 0 TO len - 1 DO
             IF i # 0 THEN
                 result := result + ", ";
             END;

+ 2 - 4
src/ob/Scope.ob

@@ -53,7 +53,6 @@ END addSymbolForType;
 PROCEDURE makeStdSymbols*(): JsMap.Type;
 VAR 
     result: JsMap.Type;
-    i: INTEGER;
     proc: Object.PType;
 
     PROCEDURE addSymbol(t: Types.PBasicType);
@@ -69,7 +68,7 @@ BEGIN
     addSymbol(Types.basic.real);
     addSymbol(Types.basic.set); 
 
-    FOR i := 0 TO JsArray.len(Procedures.predefined) - 1 DO
+    FOR i <- 0 TO JsArray.len(Procedures.predefined) - 1 DO
         proc := JsArray.at(Procedures.predefined, i);
         JsMap.put(result, proc(Symbols.PSymbol).id(), proc);
     END;
@@ -141,12 +140,11 @@ END unresolved;
 
 PROCEDURE Type.close();
 VAR
-    i: INTEGER;
     p: Object.PType;
     finalizer: Finalizer;
 BEGIN
     IF SELF.finalizers # NIL THEN
-        FOR i := 0 TO JsArray.len(SELF.finalizers) - 1 DO
+        FOR i <- 0 TO JsArray.len(SELF.finalizers) - 1 DO
             p := JsArray.at(SELF.finalizers, i);
             finalizer := p(Finalizer);
             finalizer.proc(finalizer.closure);

+ 1 - 3
src/ob/Types.ob

@@ -187,10 +187,8 @@ BEGIN
 END finalizeRecord;
 
 PROCEDURE Record.finalize();
-VAR
-    i: INTEGER;
 BEGIN
-    FOR i := 0 TO JsArray.stringsLen(SELF.notExported) - 1 DO
+    FOR i <- 0 TO JsArray.stringsLen(SELF.notExported) - 1 DO
         JsMap.erase(SELF.fields, JsArray.stringsAt(SELF.notExported, i))
     END;
     SELF.notExported := NIL;

+ 5 - 0
src/oberon/oberon_grammar.js

@@ -52,6 +52,10 @@ function makeFieldList(identdef, identList, type){
     return context(and(identList, ":", type), Context.FieldListDeclaration);
 }
 
+function makeForInit(ident, expression, assignment){
+    return and(ident, assignment);
+}
+
 exports.language = {
     grammar: Grammar.make(
         makeIdentdef,
@@ -59,6 +63,7 @@ exports.language = {
         makeProcedureHeading,
         makeProcedureDeclaration,
         makeFieldList,
+        makeForInit,
         {
             constDeclaration:   Context.ConstDecl, 
             typeDeclaration:    Context.TypeDeclaration,

+ 2 - 0
test/expected/eberon/in_place_variables.js

@@ -150,4 +150,6 @@ if (pb instanceof Derived){
 	pb.derivedField = 123;
 }
 RTL$.assert(!(pb instanceof Derived) || pb.derivedField == 123);
+for (var j = 0; j <= 10; ++j){
+}
 }();

+ 3 - 0
test/input/eberon/in_place_variables.ob

@@ -75,4 +75,7 @@ BEGIN
 
     ASSERT(~(pb IS PDerived) OR (pb.derivedField = 123));
 
+    FOR j <- 0 TO 10 DO
+    END;
+
 END m.

+ 8 - 13
test/test_unit_eberon.js

@@ -632,22 +632,17 @@ exports.suite = {
           fail(["PROCEDURE p(a: ARRAY OF INTEGER); BEGIN v <- a; END p;",
                 "cannot initialize variable 'v' with open array"]
               )
-      )    /*
-,
+    ),
     "FOR variable": testWithContext(
           context(grammar.statement, ""),
-          pass("FOR i <- 0 TO 10 DO END")
-          ),
-    "as references": testWithContext(
-          context(grammar.declarationSequence,
-                "TYPE Base = RECORD pBase: POINTER TO Base END; Derived = RECORD (Base) END;"
-                + "VAR base: Base;"
+          pass("FOR i <- 0 TO 10 DO END",
+               "FOR i <- 0 TO 10 DO FOR j <- 0 TO 10 BY 1 DO END END",
+               "IF TRUE THEN FOR i <- 0 TO 10 DO END; FOR i <- 0 TO 10 BY 1 DO END; END"
                ),
-          pass("PROCEDURE p(); BEGIN baseRef <- base.pBase^; ASSERT(baseRef IS Derived); END p;",
-               "PROCEDURE p(VAR b: Base); BEGIN baseRef <- b; ASSERT(baseRef IS Derived); END p;"),
-          fail(["PROCEDURE p(b: Base); BEGIN baseRef <- b; ASSERT(baseRef IS Derived); END p;",
-                "invalid type test: a value variable cannot be used"])
-      )*/
+          fail(["FOR i <- 0.0 TO 10 DO END", "'INTEGER' expression expected to assign 'i', got 'REAL'"],
+               ["IF TRUE THEN FOR i <- 0 TO 10 DO END; i := 1; END", "undeclared identifier: 'i'"]
+               )
+          )
     },
     "type promotion for VAR arguments": testWithContext(
         context(grammar.declarationSequence,