Changeset 136:ca0e12444b47 in livinglogic.java.ul4

Show
Ignore:
Timestamp:
07/09/08 15:18:13 (11 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Tags:
exp-2
Message:

Added break and continue tags/opcodes.

Files:
6 modified

Legend:

Unmodified
Added
Removed
  • docs/versiondoc.txt

    r134 r136  
     1exp-2: 
     2------ 
     3file format: 4 
     4 
     5Comments: 
     6* Added break and continue tags/opcodes. 
     7 
     8 
    19exp-1: 
    210------ 
  • library/src/com/livinglogic/ul4/BlockException.java

    r116 r136  
    11package com.livinglogic.ul4; 
    22 
    3 public class BlockException extends Exception 
     3public class BlockException extends RuntimeException 
    44{ 
    55    public BlockException(String message) 
  • library/src/com/livinglogic/ul4/Main.java

    r125 r136  
    33import java.util.Date; 
    44import java.util.HashMap; 
     5import java.util.Iterator; 
    56 
    67public class Main 
     
    1314    public static void main(String[] args) 
    1415    { 
    15         Template tmpl1 = Compiler.compile("<?print key?> (<?print value?>)\n"); 
    16         Template tmpl2 = Compiler.compile("<?for (key, value) in {'eins': 1, 'zwei': 2, 'drei': 3,}.items()?><?render item(key=key, value=value)?><?end for?>"); 
     16        Template tmpl = Compiler.compile("<?for i in [1,2,3,4]?><?for j in [1,2,3,4]?><?print j?>, <?if j>=i?><?break?><?end if?><?end for?><?if i>=3?><?break?><?end if?>\n<?end for?>"); 
    1717        long start = new Date().getTime(); 
    18         HashMap templates = new HashMap(); 
    19         templates.put("item", tmpl1); 
    20         String output = tmpl2.renders(null, templates); 
     18        String output = tmpl.renders(); 
    2119        System.out.println("rendered " + (time()-start)); 
    2220        System.out.println(output); 
  • library/src/com/livinglogic/ul4/Opcode.java

    r132 r136  
    3030    public static final int OC_GETSLICE2 = 25; 
    3131    public static final int OC_PRINT = 26; 
    32     public static final int OC_FOR = 27; 
    33     public static final int OC_ENDFOR = 28; 
    34     public static final int OC_NOT = 29; 
    35     public static final int OC_NEG = 30; 
    36     public static final int OC_CONTAINS = 31; 
    37     public static final int OC_NOTCONTAINS = 32; 
    38     public static final int OC_EQ = 33; 
    39     public static final int OC_NE = 34; 
    40     public static final int OC_LT = 35; 
    41     public static final int OC_LE = 36; 
    42     public static final int OC_GT = 37; 
    43     public static final int OC_GE = 38; 
    44     public static final int OC_ADD = 39; 
    45     public static final int OC_SUB = 40; 
    46     public static final int OC_MUL = 41; 
    47     public static final int OC_FLOORDIV = 42; 
    48     public static final int OC_TRUEDIV = 43; 
    49     public static final int OC_AND = 44; 
    50     public static final int OC_OR = 45; 
    51     public static final int OC_MOD = 46; 
    52     public static final int OC_CALLFUNC0 = 47; 
    53     public static final int OC_CALLFUNC1 = 48; 
    54     public static final int OC_CALLFUNC2 = 49; 
    55     public static final int OC_CALLFUNC3 = 50; 
    56     public static final int OC_CALLMETH0 = 51; 
    57     public static final int OC_CALLMETH1 = 52; 
    58     public static final int OC_CALLMETH2 = 53; 
    59     public static final int OC_CALLMETH3 = 54; 
    60     public static final int OC_IF = 55; 
    61     public static final int OC_ELSE = 56; 
    62     public static final int OC_ENDIF = 57; 
    63     public static final int OC_RENDER = 58; 
     32    public static final int OC_NOT = 27; 
     33    public static final int OC_NEG = 28; 
     34    public static final int OC_CONTAINS = 29; 
     35    public static final int OC_NOTCONTAINS = 30; 
     36    public static final int OC_EQ = 31; 
     37    public static final int OC_NE = 32; 
     38    public static final int OC_LT = 33; 
     39    public static final int OC_LE = 34; 
     40    public static final int OC_GT = 35; 
     41    public static final int OC_GE = 36; 
     42    public static final int OC_ADD = 37; 
     43    public static final int OC_SUB = 38; 
     44    public static final int OC_MUL = 39; 
     45    public static final int OC_FLOORDIV = 40; 
     46    public static final int OC_TRUEDIV = 41; 
     47    public static final int OC_AND = 42; 
     48    public static final int OC_OR = 43; 
     49    public static final int OC_MOD = 44; 
     50    public static final int OC_CALLFUNC0 = 45; 
     51    public static final int OC_CALLFUNC1 = 46; 
     52    public static final int OC_CALLFUNC2 = 47; 
     53    public static final int OC_CALLFUNC3 = 48; 
     54    public static final int OC_CALLMETH0 = 49; 
     55    public static final int OC_CALLMETH1 = 50; 
     56    public static final int OC_CALLMETH2 = 51; 
     57    public static final int OC_CALLMETH3 = 52; 
     58    public static final int OC_IF = 53; 
     59    public static final int OC_ELSE = 54; 
     60    public static final int OC_ENDIF = 55; 
     61    public static final int OC_FOR = 56; 
     62    public static final int OC_ENDFOR = 57; 
     63    public static final int OC_BREAK = 58; 
     64    public static final int OC_CONTINUE = 59; 
     65    public static final int OC_RENDER = 60; 
    6466 
    6567    public static final int CF0_NOW = 0; 
     
    177179        else if (name.equals("print")) 
    178180            return OC_PRINT; 
    179         else if (name.equals("for")) 
    180             return OC_FOR; 
    181         else if (name.equals("endfor")) 
    182             return OC_ENDFOR; 
    183181        else if (name.equals("not")) 
    184182            return OC_NOT; 
     
    239237        else if (name.equals("endif")) 
    240238            return OC_ENDIF; 
     239        else if (name.equals("for")) 
     240            return OC_FOR; 
     241        else if (name.equals("endfor")) 
     242            return OC_ENDFOR; 
     243        else if (name.equals("break")) 
     244            return OC_BREAK; 
     245        else if (name.equals("continue")) 
     246            return OC_CONTINUE; 
    241247        else if (name.equals("render")) 
    242248            return OC_RENDER; 
     
    431437        else if (code == OC_PRINT) 
    432438            return "print"; 
    433         else if (code == OC_FOR) 
    434             return "for"; 
    435         else if (code == OC_ENDFOR) 
    436             return "endfor"; 
    437439        else if (code == OC_NOT) 
    438440            return "not"; 
     
    493495        else if (code == OC_ENDIF) 
    494496            return "endif"; 
     497        else if (code == OC_FOR) 
     498            return "for"; 
     499        else if (code == OC_ENDFOR) 
     500            return "endfor"; 
     501        else if (code == OC_BREAK) 
     502            return "break"; 
     503        else if (code == OC_CONTINUE) 
     504            return "continue"; 
    495505        else if (code == OC_RENDER) 
    496506            return "render"; 
  • library/src/com/livinglogic/ul4/Template.java

    r133 r136  
    6363         */ 
    6464        public int iteratorRegSpec; 
     65 
    6566        /** 
    66          * The program counter (i.e. the index of the opcode in the {@link #opcodes} list) 
    67          * where the loop started (i.e. the location of the FOR ocode). 
     67         * The program counter (i.e. the index of the opcode in the 
     68         * {@link #opcodes} list) where the loop started (i.e. the location of the 
     69         * <code>for</code> opcode). 
    6870         */ 
    69         public int pc; 
     71        public int pcFor; 
     72 
     73        /** 
     74         * The program counter (i.e. the index of the opcode in the 
     75         * {@link #opcodes} list) where the loop ends (i.e. the location of the 
     76         * <code>endfor</code> opcode). 
     77         */ 
     78        public int pcEndFor; 
     79 
    7080        /** 
    7181         * The iterator producing the values for the loop variable. 
     
    7383        public Iterator iterator; 
    7484 
    75         public IteratorStackEntry(int iteratorRegSpec, int pc, Iterator iterator) 
     85        public IteratorStackEntry(int iteratorRegSpec, int pcFor, int pcEndFor, Iterator iterator) 
    7686        { 
    7787            this.iteratorRegSpec = iteratorRegSpec; 
    78             this.pc = pc; 
     88            this.pcFor = pcFor; 
     89            this.pcEndFor = pcEndFor; 
    7990            this.iterator = iterator; 
    8091        } 
     
    89100     * The version number used in the compiled format of the template. 
    90101     */ 
    91     public static final String VERSION = "3"; 
     102    public static final String VERSION = "4"; 
    92103 
    93104    /** 
     
    112123     
    113124    /** 
    114      * The locate to be used when formatting int, float or date objects. 
     125     * The locale to be used when formatting int, float or date objects. 
    115126     */  
    116127    public Locale defaultLocale; 
     
    608619 
    609620    /** 
    610      * Annotates all control flow opcodes in the template with the jump location 
    611      * (i.e. a FOR opcode gets annotated with the location of the associated 
    612      * ENDFOR opcode, an IF opcode gets annotated with the location of 
    613      * the associated ELSE or ENDIF opcode, an ELSE opcode gets annotated with 
    614      * the location of ENDIF opcode). 
     621     * Annotates all control flow opcodes in the template with a jump location. 
     622     * <ul> 
     623     * <li>(a <code>for</code> opcode gets annotated with the location of the 
     624     * associated <code>endfor</code> opcode;</li> 
     625     * <li>an <code>if</code> opcode gets annotated with the location of the 
     626     * associated <code>else</code> or <code>endif</code> opcode;</li> 
     627     * <li>an <code>else</code> opcode gets annotated with the location of 
     628     * <code>endif</code> opcode;</li> 
     629     * <li>a <code>break</code> opcode gets annotated with the location of next 
     630     * opcode after the associated <code>endfor</code> opcode.</li> 
     631     * <li>a <code>continue</code> opcode gets annotated with the location of next 
     632     * opcode after the associated ENDFOR opcode.</li> 
     633     * </ul> 
    615634     */ 
    616635    protected void annotate() 
     
    625644                { 
    626645                    case Opcode.OC_IF: 
    627                         stack.add(new Integer(i)); 
     646                        i = annotateIf(i, 0); 
     647                        break; 
     648                    case Opcode.OC_FOR: 
     649                        i = annotateFor(i, 0); 
    628650                        break; 
    629651                    case Opcode.OC_ELSE: 
    630                         ((Opcode)opcodes.get(((Integer)stack.getLast()).intValue())).jump = i; 
    631                         stack.set(stack.size()-1, new Integer(i)); 
    632                         break; 
     652                        throw new BlockException("else outside if block"); 
    633653                    case Opcode.OC_ENDIF: 
    634                         ((Opcode)opcodes.get(((Integer)stack.getLast()).intValue())).jump = i; 
    635                         stack.removeLast(); 
    636                         break; 
    637                     case Opcode.OC_FOR: 
    638                         stack.add(new Integer(i)); 
    639                         break; 
     654                        throw new BlockException("endif outside if block"); 
    640655                    case Opcode.OC_ENDFOR: 
    641                         ((Opcode)opcodes.get(((Integer)stack.getLast()).intValue())).jump = i; 
    642                         stack.removeLast(); 
    643                         break; 
     656                        throw new BlockException("endfor outside for loop"); 
     657                    case Opcode.OC_BREAK: 
     658                        throw new BlockException("break outside for loop"); 
     659                    case Opcode.OC_CONTINUE: 
     660                        throw new BlockException("continue outside for loop"); 
    644661                } 
    645662            } 
    646663            annotated = true; 
    647664        } 
     665    } 
     666 
     667    protected int annotateIf(int ifStart, int forDepth) 
     668    { 
     669        int jump = ifStart; 
     670        for (int i = ifStart+1; i < opcodes.size(); ++i) 
     671        { 
     672            Opcode opcode = (Opcode)opcodes.get(i); 
     673            switch (opcode.name) 
     674            { 
     675                case Opcode.OC_IF: 
     676                    i = annotateIf(i, forDepth); 
     677                    break; 
     678                case Opcode.OC_FOR: 
     679                    i = annotateFor(i, forDepth); 
     680                    break; 
     681                case Opcode.OC_ELSE: 
     682                    ((Opcode)opcodes.get(jump)).jump = i; 
     683                    jump = i; 
     684                    break; 
     685                case Opcode.OC_ENDIF: 
     686                    ((Opcode)opcodes.get(jump)).jump = i; 
     687                    return i; 
     688                case Opcode.OC_BREAK: 
     689                    if (forDepth == 0) 
     690                        throw new BlockException("break outside for loop"); 
     691                    break; 
     692                case Opcode.OC_CONTINUE: 
     693                    if (forDepth == 0) 
     694                        throw new BlockException("continue outside for loop"); 
     695                    break; 
     696                case Opcode.OC_ENDFOR: 
     697                    throw new BlockException("endfor in if block"); 
     698            } 
     699        } 
     700        throw new BlockException("unclosed if block"); 
     701    } 
     702 
     703    protected int annotateFor(int loopStart, int forDepth) 
     704    { 
     705        ++forDepth; 
     706        LinkedList breaks = new LinkedList(); 
     707        LinkedList continues = new LinkedList(); 
     708 
     709        for (int i = loopStart+1; i < opcodes.size(); ++i) 
     710        { 
     711            Opcode opcode = (Opcode)opcodes.get(i); 
     712            switch (opcode.name) 
     713            { 
     714                case Opcode.OC_IF: 
     715                    i = annotateIf(i, forDepth); 
     716                    break; 
     717                case Opcode.OC_FOR: 
     718                    i = annotateFor(i, forDepth); 
     719                    break; 
     720                case Opcode.OC_ELSE: 
     721                    throw new BlockException("else in for loop"); 
     722                case Opcode.OC_ENDIF: 
     723                    throw new BlockException("endif in for loop"); 
     724                case Opcode.OC_BREAK: 
     725                    breaks.add(new Integer(i)); 
     726                    break; 
     727                case Opcode.OC_CONTINUE: 
     728                    continues.add(new Integer(i)); 
     729                    break; 
     730                case Opcode.OC_ENDFOR: 
     731                    int j; 
     732                    int jump; 
     733                    for (j = 0; i < breaks.size(); ++i) 
     734                    { 
     735                        jump = ((Integer)breaks.get(i)).intValue(); 
     736                        ((Opcode)opcodes.get(jump)).jump = i; 
     737                    } 
     738                    for (j = 0; i < continues.size(); ++i) 
     739                    { 
     740                        jump = ((Integer)continues.get(i)).intValue(); 
     741                        ((Opcode)opcodes.get(jump)).jump = i; 
     742                    } 
     743                    ((Opcode)opcodes.get(loopStart)).jump = i; 
     744                    return i; 
     745            } 
     746        } 
     747        throw new BlockException("unclosed loop"); 
     748    } 
     749 
     750    public Iterator render() 
     751    { 
     752        return new Renderer(null, null); 
     753    } 
     754 
     755    public Iterator render(Map variables) 
     756    { 
     757        return new Renderer(variables, null); 
    648758    } 
    649759 
     
    652762     * @param variables a map containing the top level variables that should be 
    653763     *                  available to the template code. 
    654      * @param templates a map containing other template object that can be called 
     764     * @param templates a map containing other template objects that can be called 
    655765     *                  by the template via the <code>&lt;?render?&gt;</code> tag. 
    656766     * @return An iterator that returns the string output piece by piece. 
     
    659769    { 
    660770        return new Renderer(variables, templates); 
     771    } 
     772 
     773    public String renders() 
     774    { 
     775        return renders(null, null); 
     776    } 
     777 
     778    public String renders(Map variables) 
     779    { 
     780        return renders(variables, null); 
    661781    } 
    662782 
     
    665785     * @param variables a map containing the top level variables that should be 
    666786     *                  available to the template code. 
    667      * @param templates a map containing other template object that can be called 
     787     * @param templates a map containing other template objects that can be called 
    668788     *                  by the template via the <code>&lt;?render?&gt;</code> tag. 
    669789     * @return The render output as a string. 
     
    760880         * Gets the next output chunk and stores it in {@link nextChunk} 
    761881         */ 
    762         public void getNextChunk() 
     882        private void getNextChunk() 
    763883        { 
    764884            if (subTemplateIterator != null) 
     
    855975                            { 
    856976                                reg[code.r1] = iterator.next(); 
    857                                 iterators.add(new IteratorStackEntry(code.r1, pc, iterator)); 
     977                                iterators.add(new IteratorStackEntry(code.r1, pc, code.jump, iterator)); 
    858978                            } 
    859979                            else 
     
    863983                            } 
    864984                            break; 
     985                        case Opcode.OC_BREAK: 
     986                        { 
     987                            IteratorStackEntry entry = (IteratorStackEntry)iterators.getLast(); 
     988                            pc = entry.pcEndFor; 
     989                            iterators.removeLast(); 
     990                            break; 
     991                        } 
     992                        case Opcode.OC_CONTINUE: 
     993                        { 
     994                            IteratorStackEntry entry = (IteratorStackEntry)iterators.getLast(); 
     995                            pc = entry.pcEndFor; 
     996                            // Fall through 
     997                        } 
    865998                        case Opcode.OC_ENDFOR: 
     999                        { 
    8661000                            IteratorStackEntry entry = (IteratorStackEntry)iterators.getLast(); 
    8671001                            if (entry.iterator.hasNext()) 
    8681002                            { 
    8691003                                reg[entry.iteratorRegSpec] = entry.iterator.next(); 
    870                                 pc = entry.pc; 
     1004                                pc = entry.pcFor; 
    8711005                            } 
    8721006                            else 
     
    8751009                            } 
    8761010                            break; 
     1011                        } 
    8771012                        case Opcode.OC_IF: 
    8781013                            if (!Utils.getBool(reg[code.r1])) 
     
    8861021                            continue; 
    8871022                        case Opcode.OC_ENDIF: 
    888                             //Skip to next opcode 
     1023                            // Skip to next opcode 
    8891024                            break; 
    8901025                        case Opcode.OC_GETATTR: 
     
    11411276    public static List tokenizeTags(String source, String startdelim, String enddelim) 
    11421277    { 
    1143         Pattern tagPattern = Pattern.compile(escapeREchars(startdelim) + "(print|code|for|if|elif|else|end|render)(\\s*((.|\\n)*?)\\s*)?" + escapeREchars(enddelim)); 
     1278        Pattern tagPattern = Pattern.compile(escapeREchars(startdelim) + "(print|code|for|if|elif|else|end|break|continue|render)(\\s*((.|\\n)*?)\\s*)?" + escapeREchars(enddelim)); 
    11441279        LinkedList tags = new LinkedList(); 
    11451280        Matcher matcher = tagPattern.matcher(source); 
  • library/src/com/livinglogic/ul4/ul4c.py

    r130 r136  
    8585                parsefor(template, location) 
    8686                stack.append(("for",)) 
     87            elif location.type == "break": 
     88                for entry in stack: 
     89                    if entry[0] == "for": 
     90                        break 
     91                else: 
     92                    raise BlockError("break outside of for loop") 
     93                template.opcode(ul4.Opcode.OC_BREAK, location) 
     94            elif location.type == "continue": 
     95                for entry in stack: 
     96                    if entry[0] == "for": 
     97                        break 
     98                else: 
     99                    raise BlockError("continue outside of for loop") 
     100                template.opcode(ul4.Opcode.OC_CONTINUE, location) 
    87101            elif location.type == "render": 
    88102                parserender(template, location)