Changeset 686:9c00a7e3b94e in livinglogic.java.ul4

Show
Ignore:
Timestamp:
09/28/12 16:42:18 (6 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Variable unpacking in for loops can now be nested arbitrarily deep.

Location:
src
Files:
2 removed
5 modified

Legend:

Unmodified
Added
Removed
  • src/main/antlr3/com/livinglogic/ul4/UL4.g

    r569 r686  
    487487/* Additional rules for "for" tag */ 
    488488 
     489nestedvarname returns [Object varname] 
     490    : 
     491        n=name { $varname = $n.text; } 
     492    | 
     493        '(' n0=nestedvarname ',' ')' { $varname = java.util.Arrays.asList($n0.varname); } 
     494    | 
     495        '(' 
     496        n1=nestedvarname 
     497        ',' 
     498        n2=nestedvarname { $varname = new ArrayList(2); ((ArrayList)$varname).add($n1.varname); ((ArrayList)$varname).add($n2.varname); } 
     499        ( 
     500            ',' 
     501            n3=nestedvarname { ((ArrayList)$varname).add($n3.varname); } 
     502        )* 
     503        ','? 
     504        ')'  
     505    ; 
     506 
    489507for_ returns [For node] 
    490508    : 
    491         n=name 
     509        n=nestedvarname 
    492510        'in' 
    493         e=expr1 { $node = new ForNormal(location, $e.node, $n.text); } 
    494         EOF 
    495     | 
    496         '(' 
    497         n1=name 
    498         ',' 
    499         ')' 
    500         'in' 
    501         e=expr1 { $node = new ForUnpack(location, $e.node); ((ForUnpack)$node).appendName($n1.text); } 
    502         EOF 
    503     | 
    504         '(' { $node = new ForUnpack(location); } 
    505         n1=name { ((ForUnpack)$node).appendName($n1.text); } 
    506         ( 
    507             ',' 
    508             n2=name { ((ForUnpack)$node).appendName($n2.text); } 
    509         )+ 
    510         ','? 
    511         ')' 
    512         'in' 
    513         e=expr1 { $node.setContainer($e.node); } 
     511        e=expr1 { $node = new For(location, $n.varname, $e.node); } 
    514512        EOF 
    515513    ; 
  • src/main/java/com/livinglogic/ul4/For.java

    r678 r686  
    99import java.io.IOException; 
    1010import java.util.Iterator; 
     11import java.util.List; 
    1112 
    1213import com.livinglogic.ul4on.Decoder; 
    1314import com.livinglogic.ul4on.Encoder; 
    1415 
    15 public abstract class For extends Block 
     16public class For extends Block 
    1617{ 
     18    /** 
     19     * This is either a string or a list of strings/lists 
     20     */ 
     21    protected Object varname; 
    1722    protected AST container; 
    1823 
    19     public For(Location location, AST container) 
     24    public For(Location location, Object varname, AST container) 
    2025    { 
    2126        super(location); 
     27        this.varname = varname; 
    2228        this.container = container; 
    2329    } 
    2430 
    25     public void setContainer(AST container) 
     31    public String getType() 
    2632    { 
    27         this.container = container; 
     33        return "for"; 
    2834    } 
    2935 
     
    3642    } 
    3743 
     44    private void formatVarname(StringBuilder buffer, Object varname) 
     45    { 
     46        if (varname instanceof String) 
     47            buffer.append((String)varname); 
     48        else 
     49        { 
     50            List varnames = (List)varname; 
     51            buffer.append("("); 
     52            int count = 0; 
     53            for (Object subvarname : varnames) 
     54            { 
     55                ++count; 
     56                formatVarname(buffer, subvarname); 
     57                if (count == 1 || count != varnames.size()) 
     58                    buffer.append(", "); 
     59            } 
     60            buffer.append(")"); 
     61        } 
     62    } 
     63 
     64    public String toString(int indent) 
     65    { 
     66        StringBuilder buffer = new StringBuilder(); 
     67        for (int i = 0; i < indent; ++i) 
     68            buffer.append("\t"); 
     69        buffer.append("for "); 
     70        formatVarname(buffer, varname); 
     71        buffer.append(" in "); 
     72        buffer.append(container.toString(indent)); 
     73        buffer.append("\n"); 
     74        for (int i = 0; i < indent; ++i) 
     75            buffer.append("\t"); 
     76        buffer.append("{\n"); 
     77        ++indent; 
     78        for (AST item : content) 
     79            buffer.append(item.toString(indent)); 
     80        --indent; 
     81        for (int i = 0; i < indent; ++i) 
     82            buffer.append("\t"); 
     83        buffer.append("}\n"); 
     84        return buffer.toString(); 
     85    } 
     86 
    3887    public boolean handleLoopControl(String name) 
    3988    { 
     
    4190    } 
    4291 
    43     abstract protected void unpackLoopVariable(EvaluationContext context, Object item); 
     92    private void unpackVariable(EvaluationContext context, Object varname, Object item) 
     93    { 
     94        if (varname instanceof String) 
     95        { 
     96            context.put((String)varname, item); 
     97        } 
     98        else 
     99        { 
     100            Iterator<Object> itemIter = Utils.iterator(item); 
     101            Iterator<String> nameIter = ((List)varname).iterator(); 
     102 
     103            int count = 0; 
     104 
     105            for (;;) 
     106            { 
     107                if (itemIter.hasNext()) 
     108                { 
     109                    if (nameIter.hasNext()) 
     110                    { 
     111                        unpackVariable(context, nameIter.next(), itemIter.next()); 
     112                        ++count; 
     113                    } 
     114                    else 
     115                    { 
     116                        throw new UnpackingException("mismatched for loop unpacking: " + count + " varnames, " + count + "+ items"); 
     117                    } 
     118                } 
     119                else 
     120                { 
     121                    if (nameIter.hasNext()) 
     122                    { 
     123                        throw new UnpackingException("mismatched for loop unpacking: " + count + "+ varnames, " + count + " items"); 
     124                    } 
     125                    else 
     126                    { 
     127                        break; 
     128                    } 
     129                } 
     130            } 
     131        } 
     132    } 
    44133 
    45134    public Object evaluate(EvaluationContext context) throws IOException 
     
    51140        while (iter.hasNext()) 
    52141        { 
    53             unpackLoopVariable(context, iter.next()); 
     142            unpackVariable(context, varname, iter.next()); 
    54143 
    55144            try 
     
    73162    { 
    74163        super.dumpUL4ON(encoder); 
     164        encoder.dump(varname); 
    75165        encoder.dump(container); 
    76166    } 
     
    79169    { 
    80170        super.loadUL4ON(decoder); 
     171        varname = decoder.load(); 
    81172        container = (AST)decoder.load(); 
    82173    } 
  • src/main/java/com/livinglogic/ul4/InterpretedTemplate.java

    r678 r686  
    545545        Utils.register("de.livinglogic.ul4.elif", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ElIf(null, null); }}); 
    546546        Utils.register("de.livinglogic.ul4.else", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Else(null); }}); 
    547         Utils.register("de.livinglogic.ul4.for", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ForNormal(null, null, null); }}); 
    548         Utils.register("de.livinglogic.ul4.foru", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ForUnpack(null, null); }}); 
     547        Utils.register("de.livinglogic.ul4.for", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.For(null, null, null); }}); 
    549548        Utils.register("de.livinglogic.ul4.break", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Break(null); }}); 
    550549        Utils.register("de.livinglogic.ul4.continue", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Continue(null); }}); 
  • src/main/resources/versiondoc.txt

    r685 r686  
     1exp-53: 
     2------- 
     3Comments: 
     4* Variable unpacking in for loops can now be nested arbitrarily deep. 
     5 
     6 
    17exp-52: 
    28------- 
  • src/test/java/tests/UL4Test.java

    r678 r686  
    373373 
    374374    @Test 
    375     public void tag_for_nested() 
     375    public void tag_for_nested_loop() 
    376376    { 
    377377        String source = "<?for list in data?>[<?for n in list?>(<?print n?>)<?end for?>]<?end for?>"; 
     
    410410        checkTemplateOutput("(spam,eggs,17)(gurk,hurz,23)(hinz,kunz,42)", "<?for (a, b, c) in data?>(<?print a?>,<?print b?>,<?print c?>)<?end for?>", "data", data3); 
    411411        checkTemplateOutput("(spam,eggs,17,)(gurk,hurz,23,False)(hinz,kunz,42,True)", "<?for (a, b, c, d) in data?>(<?print a?>,<?print b?>,<?print c?>,<?print d?>)<?end for?>", "data", data4); 
     412    } 
     413 
     414    @Test 
     415    public void tag_for_nested_unpacking() 
     416    { 
     417        Object data = asList( 
     418            asList(asList("spam", "eggs"), asList(17), null), 
     419            asList(asList("gurk", "hurz"), asList(23), false), 
     420            asList(asList("hinz", "kunz"), asList(42), true) 
     421        ); 
     422 
     423        checkTemplateOutput("(spam,eggs,17,)(gurk,hurz,23,False)(hinz,kunz,42,True)", "<?for ((a, b), (c,), d) in data?>(<?print a?>,<?print b?>,<?print c?>,<?print d?>)<?end for?>", "data", data); 
    412424    } 
    413425