Browse Source

key is optional in FOR..IN

Vladislav Folts 10 years ago
parent
commit
a2d9386b59

BIN
bin/compiled.zip


+ 17 - 8
src/eberon/EberonContextLoop.ob

@@ -144,18 +144,25 @@ BEGIN
                      + type.description() + "'");
     ELSE
         root <- SELF.root();
-        scope <- EberonScope.makeOperator(
-            root.currentScope(),
-            root.language().stdSymbols);
+        currentScope <- root.currentScope();
+        scope <- EberonScope.makeOperator(currentScope, root.language().stdSymbols);
         root.pushScope(scope);
         SELF.scopeWasCreated := TRUE;
 
         code <- SELF.parent().codeGenerator();
-        mapVar <- root.currentScope().generateTempVar("seq");
+        mapVar <- currentScope.generateTempVar("seq");
         code.write("var " + mapVar + " = " + e.code() + ";" + Chars.ln);
-        code.write("for(var " + SELF.keyId + " in " + mapVar + ")");
+        
+        keyId <- SELF.keyId;
+        valueId <- SELF.valueId;
+        IF LEN(valueId) = 0 THEN
+            valueId := keyId;
+            keyId := currentScope.generateTempVar("key");
+        END;
+
+        code.write("for(var " + keyId + " in " + mapVar + ")");
         code.openScope();
-        code.write("var " + SELF.valueId + " = " + mapVar + "[" + SELF.keyId + "];" + Chars.ln);
+        code.write("var " + valueId + " = " + mapVar + "[" + keyId + "];" + Chars.ln);
         SELF.code := code;
 
         keyType <- Types.basic.integer;
@@ -163,8 +170,10 @@ BEGIN
             keyType := EberonString.string;
         END;
 
-        makeVariable(SELF.keyId, keyType, scope);
-        makeVariable(SELF.valueId, type.elementsType, scope);
+        IF LEN(valueId) # 0 THEN
+            makeVariable(keyId, keyType, scope);
+        END;
+        makeVariable(valueId, type.elementsType, scope);
     END;
 END;
 

+ 1 - 1
src/eberon/eberon_grammar.js

@@ -35,7 +35,7 @@ function makeStrucType(base, type){
 }
 
 function makeStatement(base, statementSequence, ident, expression){
-    return or(context(and("FOR", ident, ",", ident, "IN", expression, "DO", 
+    return or(context(and("FOR", ident, optional(and(",", ident)), "IN", expression, "DO", 
                           statementSequence, required("END", "END expected (FOR)")), 
                       EberonContextLoop.ForEach),
               base

+ 18 - 0
test/expected/eberon/for_in.js

@@ -9,4 +9,22 @@ function array(){
 		RTL$.assert(a[i] == v);
 	}
 }
+
+function arrayWithValueOnly(){
+	var a = RTL$.makeArray(3, false);
+	var $seq1 = a;
+	for(var $key2 in $seq1){
+		var v = $seq1[$key2];
+		RTL$.assert(!v);
+	}
+}
+
+function mapWithValueOnly(){
+	var a = {};
+	var $seq1 = a;
+	for(var $key2 in $seq1){
+		var v = $seq1[$key2];
+		RTL$.assert(!v);
+	}
+}
 }();

+ 18 - 0
test/input/eberon/for_in.ob

@@ -9,4 +9,22 @@ BEGIN
     END;
 END;
 
+PROCEDURE arrayWithValueOnly();
+VAR
+    a: ARRAY 3 OF BOOLEAN;
+BEGIN
+    FOR v IN a DO
+        ASSERT(~v);
+    END;
+END;
+
+PROCEDURE mapWithValueOnly();
+VAR
+    a: MAP OF BOOLEAN;
+BEGIN
+    FOR v IN a DO
+        ASSERT(~v);
+    END;
+END;
+
 END test.

+ 28 - 26
test/test_unit_eberon.js

@@ -1342,9 +1342,36 @@ exports.suite = {
         context(grammar.statement, 
                 "VAR a: ARRAY 3 OF BOOLEAN;"),
         pass("FOR i, v IN a DO END",
-             "FOR i, v IN a DO ASSERT(a[i] = v); END"),
+             "FOR i, v IN a DO ASSERT(a[i] = v); END",
+             "FOR v IN a DO END",
+             "FOR v IN a DO ASSERT(~v) END"),
         fail()
     ),
+    "map": testWithContext(
+        context(grammar.statement,
+                "TYPE T = RECORD END;"
+              + "VAR m: MAP OF INTEGER; r: T;"),
+        pass("FOR k, v IN m DO END",
+             "FOR k, v IN m DO ASSERT(k # \"abc\"); END",
+             "FOR k, v IN m DO ASSERT(v # 123); END"
+            ),
+        fail(["FOR k, k IN m DO END", "'k' already declared"],
+             ["FOR m, v IN m DO END", "'m' already declared in module scope"],
+             ["FOR k, m IN m DO END", "'m' already declared in module scope"],
+             ["FOR k, v IN m DO k := \"\"; END", "cannot assign to FOR variable"],
+             ["FOR k, v IN m DO v := 0; END", "cannot assign to FOR variable"],
+             ["FOR k, v IN r DO END", "expression of type ARRAY or MAP is expected in FOR, got 'T'"],
+             ["FOR k, v IN T DO END", "type name 'T' cannot be used as an expression"]
+            )
+        ),
+    "scope": testWithContext(
+        context(grammar.declarationSequence,
+                "VAR m: MAP OF INTEGER;"),
+        pass(),
+        fail(["PROCEDURE p(); BEGIN FOR k, v IN m DO END; ASSERT(k # \"abc\"); END;", "undeclared identifier: 'k'"],
+             ["PROCEDURE p(); BEGIN FOR k, v IN m DO END; ASSERT(v # 123); END;", "undeclared identifier: 'v'"]
+             )
+        )
 },
 "map": {
     "declaration": testWithGrammar(
@@ -1427,31 +1454,6 @@ exports.suite = {
         pass(),
         fail(["PROCEDURE p(m: M); BEGIN m[\"abc\"] := 123; END;", "cannot assign to read-only MAP's element"])
         ),
-    "FOR": testWithContext(
-        context(grammar.statement,
-                "TYPE T = RECORD END;"
-              + "VAR m: MAP OF INTEGER; r: T;"),
-        pass("FOR k, v IN m DO END",
-             "FOR k, v IN m DO ASSERT(k # \"abc\"); END",
-             "FOR k, v IN m DO ASSERT(v # 123); END"
-            ),
-        fail(["FOR k, k IN m DO END", "'k' already declared"],
-             ["FOR m, v IN m DO END", "'m' already declared in module scope"],
-             ["FOR k, m IN m DO END", "'m' already declared in module scope"],
-             ["FOR k, v IN m DO k := \"\"; END", "cannot assign to FOR variable"],
-             ["FOR k, v IN m DO v := 0; END", "cannot assign to FOR variable"],
-             ["FOR k, v IN r DO END", "expression of type ARRAY or MAP is expected in FOR, got 'T'"],
-             ["FOR k, v IN T DO END", "type name 'T' cannot be used as an expression"]
-            )
-        ),
-    "FOR scope": testWithContext(
-        context(grammar.declarationSequence,
-                "VAR m: MAP OF INTEGER;"),
-        pass(),
-        fail(["PROCEDURE p(); BEGIN FOR k, v IN m DO END; ASSERT(k # \"abc\"); END;", "undeclared identifier: 'k'"],
-             ["PROCEDURE p(); BEGIN FOR k, v IN m DO END; ASSERT(v # 123); END;", "undeclared identifier: 'v'"]
-             )
-        ),
     "remove": testWithContext(
         context(grammar.statement,
                 "VAR m: MAP OF INTEGER; a: ARRAY * OF CHAR;"),