Changeset 796:8db43aa29203 in livinglogic.java.ul4

Show
Ignore:
Timestamp:
02/16/13 17:23:37 (6 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Update to the current state of the Python implmentation.

Templates and functions are merged again.

AST nodes keep their start and end index for simplified toString() formatting.

Location:
src
Files:
7 removed
67 modified
1 moved

Legend:

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

    r784 r796  
    55    language=Java; 
    66    backtrack=true; 
     7    TokenLabelType=CommonToken; 
    78} 
    89 
     
    2930    public UL4Lexer(Location location, CharStream input) 
    3031    { 
    31         super(input); 
     32        this(input); 
    3233        this.location = location; 
    3334    } 
     
    4748    public UL4Parser(Location location, TokenStream input) 
    4849    { 
    49         super(input); 
     50        this(input); 
    5051        this.location = location; 
    5152    } 
     
    5657        String message = getErrorMessage(e, tokenNames) + " (at index " + e.index + ")"; 
    5758        throw new SyntaxException(message, e); 
     59    } 
     60 
     61    public int getStart(CommonToken token) 
     62    { 
     63        return location.startcode + token.getStartIndex(); 
     64    } 
     65 
     66    public int getEnd(CommonToken token) 
     67    { 
     68        return location.startcode + token.getStopIndex() + 1; 
    5869    } 
    5970} 
     
    164175 
    165176none returns [AST node] 
    166     : NONE { $node = new Const(null); } 
     177    : NONE { $node = new Const(location, getStart($NONE), getEnd($NONE), null); } 
    167178    ; 
    168179 
    169180true_ returns [AST node] 
    170     : TRUE { $node = new Const(true); } 
     181    : TRUE { $node = new Const(location, getStart($TRUE), getEnd($TRUE), true); } 
    171182    ; 
    172183 
    173184false_ returns [AST node] 
    174     : FALSE { $node = new Const(false); } 
     185    : FALSE { $node = new Const(location, getStart($FALSE), getEnd($FALSE), false); } 
    175186    ; 
    176187 
    177188int_ returns [AST node] 
    178     : INT { $node = new Const(Utils.parseUL4Int($INT.text)); } 
     189    : INT { $node = new Const(location, getStart($INT), getEnd($INT), Utils.parseUL4Int($INT.text)); } 
    179190    ; 
    180191 
    181192float_ returns [AST node] 
    182     : FLOAT { $node = new Const(Double.parseDouble($FLOAT.text)); } 
     193    : FLOAT { $node = new Const(location, getStart($FLOAT), getEnd($FLOAT), Double.parseDouble($FLOAT.text)); } 
    183194    ; 
    184195 
    185196string returns [AST node] 
    186     : STRING { $node = new Const(Utils.unescapeUL4String($STRING.text.substring(1, $STRING.text.length()-1))); } 
     197    : STRING { $node = new Const(location, getStart($STRING), getEnd($STRING), Utils.unescapeUL4String($STRING.text.substring(1, $STRING.text.length()-1))); } 
    187198    ; 
    188199 
    189200date returns [AST node] 
    190     : DATE { $node = new Const(Utils.isoparse($DATE.text.substring(2, $DATE.text.length()-1))); } 
     201    : DATE { $node = new Const(location, getStart($DATE), getEnd($DATE), Utils.isoparse($DATE.text.substring(2, $DATE.text.length()-1))); } 
    191202    ; 
    192203 
    193204color returns [AST node] 
    194     : COLOR { $node = new Const(Color.fromrepr($COLOR.text)); } 
     205    : COLOR { $node = new Const(location, getStart($COLOR), getEnd($COLOR), Color.fromrepr($COLOR.text)); } 
    195206    ; 
    196207 
    197208name returns [Var node] 
    198     : NAME { $node = new Var($NAME.text); } 
     209    : NAME { $node = new Var(location, getStart($NAME), getEnd($NAME), $NAME.text); } 
    199210    ; 
    200211 
     
    214225list returns [com.livinglogic.ul4.List node] 
    215226    : 
    216         '[' 
    217         ']' { $node = new com.livinglogic.ul4.List(); } 
    218     | 
    219         '[' {$node = new com.livinglogic.ul4.List(); } 
     227        open='[' 
     228        close=']' { $node = new com.livinglogic.ul4.List(location, getStart($open), getEnd($close)); } 
     229    | 
     230        open='[' {$node = new com.livinglogic.ul4.List(location, getStart($open), -1); } 
    220231        e1=expr1 { $node.append($e1.node); } 
    221232        ( 
     
    224235        )* 
    225236        ','? 
    226         ']' 
     237        close=']' { $node.setEnd(getEnd($close)); } 
    227238    ; 
    228239 
     
    233244    } 
    234245    : 
    235         '[' 
     246        open='[' 
    236247        item=expr1 
    237248        'for' 
     
    243254            condition=expr1 { _condition = $condition.node; } 
    244255        )? 
    245         ']' { $node = new ListComprehension($item.node, $n.varname, $container.node, _condition); } 
     256        close=']' { $node = new ListComprehension(location, getStart($open), getEnd($close), $item.node, $n.varname, $container.node, _condition); } 
    246257    ; 
    247258 
     
    260271dict returns [Dict node] 
    261272    : 
    262         '{' 
    263         '}' { $node = new Dict(); } 
    264     | 
    265         '{' { $node = new Dict(); } 
     273        open='{' 
     274        close='}' { $node = new Dict(location, getStart($open), getEnd($close)); } 
     275    | 
     276        open='{' { $node = new Dict(location, getStart($open), -1); } 
    266277        i1=dictitem { $node.append($i1.node); } 
    267278        ( 
     
    270281        )* 
    271282        ','? 
    272         '}' 
     283        close='}' { $node.setEnd(getEnd($close)); } 
    273284    ; 
    274285 
     
    279290    } 
    280291    : 
    281         '{' 
     292        open='{' 
    282293        key=expr1 
    283294        ':' 
     
    291302            condition=expr1 { _condition = $condition.node; } 
    292303        )? 
    293         '}' { $node = new DictComprehension($key.node, $value.node, $n.varname, $container.node, _condition); } 
     304        close='}' { $node = new DictComprehension(location, getStart($open), getEnd($close), $key.node, $value.node, $n.varname, $container.node, _condition); } 
    294305    ; 
    295306 
     
    298309    { 
    299310        AST _condition = null; 
     311        int _end = -1; 
    300312    } 
    301313    : 
     
    304316        n=nestedname 
    305317        'in' 
    306         container=expr1 
     318        container=expr1 { _end = $container.node.getEnd(); } 
    307319        ( 
    308320            'if' 
    309             condition=expr1 { _condition = $condition.node; } 
    310         )? { $node = new GeneratorExpression($item.node, $n.varname, $container.node, _condition); } 
     321            condition=expr1 { _condition = $condition.node; _end = $condition.node.getEnd(); } 
     322        )? { $node = new GeneratorExpression(location, $item.node.getStart(), _end, $item.node, $n.varname, $container.node, _condition); } 
    311323    ; 
    312324 
     
    353365            /* Attribute access */ 
    354366            '.' 
    355             n=name { $node = new GetAttr($node, $n.text); } 
     367            n=name { $node = new GetAttr(location, $e1.node.getStart(), $n.node.getEnd(), $node, $n.text); } 
    356368        | 
    357369            /* Function/method call */ 
    358             '(' { $node = ($node instanceof GetAttr) ? ((GetAttr)$node).makeCallMeth() : new CallFunc($node); } 
     370            '(' { $node = ($node instanceof GetAttr) ? ((GetAttr)$node).makeCallMeth() : new CallFunc(location, $e1.node.getStart(), -1, $node); } 
    359371            ( 
    360372                /* No arguments */ 
     
    408420                ','? 
    409421            ) 
    410             ')' 
     422            close=')' { $node.setEnd(getEnd($close)); } 
    411423        | 
    412424            /* Item/slice access */ 
     
    416428                ( 
    417429                    e2=expr1 { index2 = $e2.node; } 
    418                 )? { $node = GetSlice.make($node, null, index2); } 
     430                )? { $node = GetSlice.make(location, $e1.node.getStart(), -1, $node, null, index2); } 
    419431            | 
    420432                e2=expr1 { index1 = $e2.node; } 
     
    424436                        e3=expr1 { index2 = $e3.node; } 
    425437                    )? 
    426                 )? { $node = slice ? GetSlice.make($node, index1, index2) : GetItem.make($node, index1); } 
     438                )? { $node = slice ? GetSlice.make(location, $e1.node.getStart(), -1, $node, index1, index2) : GetItem.make(location, $e1.node.getStart(), -1, $node, index1); } 
    427439            ) 
    428             ']' 
     440            close=']' { $node.setEnd(getEnd($close)); } 
    429441        )* 
    430442    ; 
     
    432444/* Negation */ 
    433445expr8 returns [AST node] 
    434     @init 
    435     { 
    436         int count = 0; 
    437     } 
    438     : 
    439         ( 
    440             '-' { ++count; } 
    441         )* 
    442         e=expr9 { $node = $e.node; while (count-- != 0) { $node = Neg.make($node); } } 
     446    : 
     447        e1=expr9 { $node = $e1.node; } 
     448    | 
     449        minus='-' e2=expr8 { $node = Neg.make(location, getStart($minus), $e2.node.getEnd(), $e2.node); } 
    443450    ; 
    444451 
     
    461468                '%' { opcode = 3; } 
    462469            ) 
    463             e2=expr8 { switch (opcode) { case 0: $node = Mul.make($node, $e2.node); break; case 1: $node = TrueDiv.make($node, $e2.node); break; case 2: $node = FloorDiv.make($node, $e2.node); break; case 3: $node = Mod.make($node, $e2.node); break; } } 
     470            e2=expr8 { switch (opcode) { case 0: $node = Mul.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 1: $node = TrueDiv.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 2: $node = FloorDiv.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 3: $node = Mod.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; } } 
    464471        )* 
    465472    ; 
     
    479486                '-' { add = false; } 
    480487            ) 
    481             e2=expr7 { $node = add ? Add.make($node, $e2.node) : Sub.make($node, $e2.node); } 
     488            e2=expr7 { $node = add ? Add.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node) : Sub.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); } 
    482489        )* 
    483490    ; 
     
    505512                '>=' { opcode = 5; } 
    506513            ) 
    507             e2=expr6 { switch (opcode) { case 0: $node = EQ.make($node, $e2.node); break; case 1: $node = NE.make($node, $e2.node); break; case 2: $node = LT.make($node, $e2.node); break; case 3: $node = LE.make($node, $e2.node); break; case 4: $node = GT.make($node, $e2.node); break; case 5: $node = GE.make($node, $e2.node); break; } } 
     514            e2=expr6 { switch (opcode) { case 0: $node = EQ.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 1: $node = NE.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 2: $node = LT.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 3: $node = LE.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 4: $node = GT.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 5: $node = GE.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; } } 
    508515        )* 
    509516    ; 
     
    523530            )? 
    524531            'in' 
    525             e2=expr5 { $node = not ? NotContains.make($node, $e2.node) : Contains.make($node, $e2.node); } 
     532            e2=expr5 { $node = not ? NotContains.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node) : Contains.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); } 
    526533        )? 
    527534    ; 
     
    530537expr3 returns [AST node] 
    531538    : 
    532         'not' 
    533         e=expr4 { $node = Not.make($e.node); } 
    534     | 
    535         e=expr4 { $node = $e.node; } 
     539        e1=expr4 { $node = $e1.node; } 
     540    | 
     541        n='not' e2=expr3 { $node = Not.make(location, getStart($n), $e2.node.getEnd(), $e2.node); } 
    536542    ; 
    537543 
     
    543549        ( 
    544550            'and' 
    545             e2=expr3 { $node = And.make($node, $e2.node); } 
     551            e2=expr3 { $node = And.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); } 
    546552        )* 
    547553    ; 
     
    553559        ( 
    554560            'or' 
    555             e2=expr2 { $node = Or.make($node, $e2.node); } 
     561            e2=expr2 { $node = Or.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); } 
    556562        )* 
    557563    ; 
     
    574580        n=nestedname 
    575581        'in' 
    576         e=expr1 { $node = new For(location, $n.varname, $e.node); } 
     582        e=expr1 { $node = new For(location, location.getStartCode(), $e.node.getEnd(), $n.varname, $e.node); } 
    577583        EOF 
    578584    ; 
     
    581587/* Additional rules for "code" tag */ 
    582588 
    583 stmt returns [Tag node] 
    584     : nn=nestedname '=' e=expr1 EOF { $node = new StoreVar(location, $nn.varname, $e.node); } 
    585     | n=name '+=' e=expr1 EOF { $node = new AddVar(location, $n.text, $e.node); } 
    586     | n=name '-=' e=expr1 EOF { $node = new SubVar(location, $n.text, $e.node); } 
    587     | n=name '*=' e=expr1 EOF { $node = new MulVar(location, $n.text, $e.node); } 
    588     | n=name '/=' e=expr1 EOF { $node = new TrueDivVar(location, $n.text, $e.node); } 
    589     | n=name '//=' e=expr1 EOF { $node = new FloorDivVar(location, $n.text, $e.node); } 
    590     | n=name '%=' e=expr1 EOF { $node = new ModVar(location, $n.text, $e.node); } 
    591     ; 
     589stmt returns [AST node] 
     590    : nn=nestedname '=' e=expr1 EOF { $node = new StoreVar(location, location.getStartCode(), $e.node.getEnd(), $nn.varname, $e.node); } 
     591    | n=name '+=' e=expr1 EOF { $node = new AddVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); } 
     592    | n=name '-=' e=expr1 EOF { $node = new SubVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); } 
     593    | n=name '*=' e=expr1 EOF { $node = new MulVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); } 
     594    | n=name '/=' e=expr1 EOF { $node = new TrueDivVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); } 
     595    | n=name '//=' e=expr1 EOF { $node = new FloorDivVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); } 
     596    | n=name '%=' e=expr1 EOF { $node = new ModVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); } 
     597    | e=expression EOF { $node = $e.node; } 
     598    ; 
  • src/main/java/com/livinglogic/ul4/AST.java

    r784 r796  
    2222{ 
    2323    /** 
     24     * The source code location where this node appears in. 
     25     */ 
     26    protected Location location = null; 
     27 
     28    /** 
     29     * The start index of this node in the source 
     30     */ 
     31    protected int start; 
     32 
     33    /** 
     34     * The end index of this node in the source 
     35     */ 
     36    protected int end; 
     37 
     38    /** 
    2439     * Create a new {@code AST} object. 
    25      */ 
    26     public AST() 
    27     { 
     40     * @param location The source code location where this node appears in. 
     41     */ 
     42    public AST(Location location, int start, int end) 
     43    { 
     44        this.location = location; 
     45        this.start = start; 
     46        this.end = end; 
    2847    } 
    2948 
     
    8099    public String toString() 
    81100    { 
    82         return toString(null, 0); 
    83     } 
    84  
    85     /** 
    86      * This is an extension of the normal {@code toString} method: Returns 
    87      * nicely formatted sourcecode for this node formatted for indentation level 
    88      * {@code indent}. 
    89      * @param code the top level code for which this node should be formatted 
    90      * @param indent the indentation level 
    91      * @return The formatted sourcecode 
    92      */ 
    93     abstract public String toString(InterpretedCode code, int indent); 
     101        Formatter formatter = new Formatter(); 
     102        toString(formatter); 
     103        formatter.finish(); 
     104        return formatter.toString(); 
     105    } 
     106 
     107    /** 
     108     * Return the source code location where this node appears in. 
     109     */ 
     110    public Location getLocation() 
     111    { 
     112        return location; 
     113    } 
     114 
     115    public int getStart() 
     116    { 
     117        return start; 
     118    } 
     119 
     120    public int getEnd() 
     121    { 
     122        return end; 
     123    } 
     124 
     125    public void setEnd(int end) 
     126    { 
     127        this.end = end; 
     128    } 
     129 
     130    protected static class Formatter 
     131    { 
     132        private StringBuilder builder = new StringBuilder(); 
     133        private int level = 0; 
     134        private boolean needsLF = false; 
     135 
     136        public Formatter() 
     137        { 
     138        } 
     139 
     140        public void indent() 
     141        { 
     142            ++level; 
     143        } 
     144 
     145        public void dedent() 
     146        { 
     147            --level; 
     148        } 
     149 
     150        public void lf() 
     151        { 
     152            needsLF = true; 
     153        } 
     154 
     155        public void write(String string) 
     156        { 
     157            if (needsLF) 
     158            { 
     159                builder.append("\n"); 
     160                for (int i = 0; i < level; ++i) 
     161                    builder.append("\t"); 
     162                needsLF = false; 
     163            } 
     164            builder.append(string); 
     165        } 
     166 
     167        public void finish() 
     168        { 
     169            if (needsLF) 
     170                builder.append("\n"); 
     171        } 
     172        public String toString() 
     173        { 
     174            return builder.toString(); 
     175        } 
     176    } 
     177    /** 
     178     * Format this object using a Formatter object. 
     179     * @param formmatter the Fomatter object 
     180     */ 
     181    public void toString(Formatter formatter) 
     182    { 
     183        toStringFromSource(formatter); 
     184    } 
     185 
     186    public void toStringFromSource(Formatter formatter) 
     187    { 
     188        formatter.write(location.getSource().substring(start, end)); 
     189    } 
    94190 
    95191    public String getUL4ONName() 
     
    100196    public void dumpUL4ON(Encoder encoder) throws IOException 
    101197    { 
     198        encoder.dump(location); 
     199        encoder.dump(start); 
     200        encoder.dump(end); 
    102201    } 
    103202 
    104203    public void loadUL4ON(Decoder decoder) throws IOException 
    105204    { 
     205        location = (Location)decoder.load(); 
     206        start = (Integer)decoder.load(); 
     207        end = (Integer)decoder.load(); 
    106208    } 
    107209 
     
    114216            HashMap<String, ValueMaker> v = new HashMap<String, ValueMaker>(); 
    115217            v.put("type", new ValueMaker(){public Object getValue(Object object){return ((AST)object).getType();}}); 
     218            v.put("location", new ValueMaker(){public Object getValue(Object object){return ((AST)object).getLocation();}}); 
     219            v.put("start", new ValueMaker(){public Object getValue(Object object){return ((AST)object).getStart();}}); 
     220            v.put("end", new ValueMaker(){public Object getValue(Object object){return ((AST)object).getEnd();}}); 
    116221            valueMakers = v; 
    117222        } 
  • src/main/java/com/livinglogic/ul4/ASTException.java

    r757 r796  
    1313    public ASTException(Throwable cause, AST node) 
    1414    { 
    15         super("in " + node, cause); 
     15        super("in " + node + " in tag " + node.getLocation(), cause); 
    1616        this.node = node; 
    1717    } 
  • src/main/java/com/livinglogic/ul4/Add.java

    r757 r796  
    1616public class Add extends Binary 
    1717{ 
    18     public Add(AST obj1, AST obj2) 
    19     { 
    20         super(obj1, obj2); 
     18    public Add(Location location, int start, int end, AST obj1, AST obj2) 
     19    { 
     20        super(location, start, end, obj1, obj2); 
    2121    } 
    2222 
     
    2626    } 
    2727 
    28     public static AST make(AST obj1, AST obj2) 
     28    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2929    { 
    3030        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    3232            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3333            if (!(result instanceof Undefined)) 
    34                 return new Const(result); 
    35         } 
    36         return new Add(obj1, obj2); 
     34                return new Const(location, start, end, result); 
     35        } 
     36        return new Add(location, start, end, obj1, obj2); 
    3737    } 
    3838 
  • src/main/java/com/livinglogic/ul4/AddVar.java

    r757 r796  
    1111public class AddVar extends ChangeVar 
    1212{ 
    13     public AddVar(Location location, String varname, AST value) 
     13    public AddVar(Location location, int start, int end, String varname, AST value) 
    1414    { 
    15         super(location, varname, value); 
     15        super(location, start, end, varname, value); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/And.java

    r757 r796  
    1111public class And extends Binary 
    1212{ 
    13     public And(AST obj1, AST obj2) 
     13    public And(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new And(obj1, obj2); 
     31        return new And(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/Binary.java

    r784 r796  
    3535     * @param obj2 The right operand 
    3636     */ 
    37     public Binary(AST obj1, AST obj2) 
     37    public Binary(Location location, int start, int end, AST obj1, AST obj2) 
    3838    { 
    39         super(); 
     39        super(location, start, end); 
    4040        this.obj1 = obj1; 
    4141        this.obj2 = obj2; 
    42     } 
    43  
    44     public String toString(InterpretedCode code, int indent) 
    45     { 
    46         return getType() + "(" + obj1 + ", " + obj2 + ")"; 
    4742    } 
    4843 
  • src/main/java/com/livinglogic/ul4/Block.java

    r784 r796  
    1616import com.livinglogic.ul4on.Encoder; 
    1717 
    18 abstract class Block extends Tag 
     18abstract class Block extends AST 
    1919{ 
    20     protected List<Tag> content = new LinkedList<Tag>(); 
     20    protected List<AST> content = new LinkedList<AST>(); 
    2121    protected Location endlocation = null; 
    2222 
    23     public Block(Location location) 
     23    public Block(Location location, int start, int end) 
    2424    { 
    25         super(location); 
     25        super(location, start, end); 
    2626    } 
    2727 
    28     public void append(Tag item) 
     28    public void append(AST item) 
    2929    { 
    3030        content.add(item); 
     
    4141    } 
    4242 
    43     public List<Tag> getContent() 
     43    public List<AST> getContent() 
    4444    { 
    4545        return content; 
     
    6666            throw ex; 
    6767        } 
    68         catch (TagException ex) 
    69         { 
    70             if (ex.location != location && location != null) 
    71                 throw new TagException(ex, location); 
    72             else 
    73                 throw ex; 
    74         } 
    7568        catch (Exception ex) 
    7669        { 
    77             throw new TagException(ex, location); 
     70            throw new ASTException(ex, this); 
    7871        } 
    7972    } 
     
    8174    public Object evaluate(EvaluationContext context) throws IOException 
    8275    { 
    83         for (Tag item : content) 
     76        for (AST item : content) 
    8477            item.decoratedEvaluate(context); 
    8578        return null; 
     79    } 
     80 
     81    public void toString(Formatter formatter) 
     82    { 
     83        if (content.size() != 0) 
     84        { 
     85            for (AST item : content) 
     86            { 
     87                item.toString(formatter); 
     88                formatter.lf(); 
     89            } 
     90        } 
     91        else 
     92        { 
     93            formatter.write("pass"); 
     94            formatter.lf(); 
     95        } 
    8696    } 
    8797 
     
    97107        super.loadUL4ON(decoder); 
    98108        endlocation = (Location)decoder.load(); 
    99         content = (List<Tag>)decoder.load(); 
     109        content = (List<AST>)decoder.load(); 
    100110    } 
    101111 
  • src/main/java/com/livinglogic/ul4/Break.java

    r784 r796  
    77package com.livinglogic.ul4; 
    88 
    9 class Break extends Tag 
     9class Break extends AST 
    1010{ 
    11     public Break(Location location) 
     11    public Break(Location location, int start, int end) 
    1212    { 
    13         super(location); 
     13        super(location, start, end); 
    1414    } 
    1515 
     
    2424    } 
    2525 
    26     public String toString(InterpretedCode code, int indent) 
     26    public String toString(int indent) 
    2727    { 
    2828        StringBuilder buffer = new StringBuilder(); 
  • src/main/java/com/livinglogic/ul4/CallFunc.java

    r784 r796  
    2222    protected AST obj; 
    2323 
    24     public CallFunc(AST obj) 
     24    public CallFunc(Location location, int start, int end, AST obj) 
    2525    { 
    26         super(); 
     26        super(location, start, end); 
    2727        this.obj = obj; 
    28     } 
    29  
    30     public String toString(InterpretedCode code, int indent) 
    31     { 
    32         StringBuilder buffer = new StringBuilder(); 
    33  
    34         buffer.append("callfunc("); 
    35         buffer.append(obj.toString(code, indent)); 
    36         for (AST arg : args) 
    37         { 
    38             buffer.append(", "); 
    39             buffer.append(arg); 
    40         } 
    41         for (KeywordArgument arg : kwargs) 
    42         { 
    43             buffer.append(", "); 
    44             buffer.append(arg.getName()); 
    45             buffer.append("="); 
    46             buffer.append(arg.getArg().toString(code, indent)); 
    47         } 
    48         if (remainingArgs != null) 
    49         { 
    50             buffer.append(", *"); 
    51             buffer.append(remainingArgs.toString(code, indent)); 
    52         } 
    53         if (remainingKWArgs != null) 
    54         { 
    55             buffer.append(", **"); 
    56             buffer.append(remainingKWArgs); 
    57         } 
    58         buffer.append(")"); 
    59         return buffer.toString(); 
    6028    } 
    6129 
  • src/main/java/com/livinglogic/ul4/CallMeth.java

    r784 r796  
    7575    } 
    7676 
    77     public CallMeth(AST obj, Method method) 
     77    public CallMeth(Location location, int start, int end, AST obj, Method method) 
    7878    { 
    79         super(); 
     79        super(location, start, end); 
    8080        this.obj = obj; 
    8181        this.method = method; 
    8282    } 
    8383 
    84     public CallMeth(AST obj, String methname) 
     84    public CallMeth(Location location, int start, int end, AST obj, String methname) 
    8585    { 
    86         super(); 
     86        super(location, start, end); 
    8787        this.obj = obj; 
    8888        method = getMethod(methname); 
    89     } 
    90  
    91     public String toString(InterpretedCode code, int indent) 
    92     { 
    93         StringBuilder buffer = new StringBuilder(); 
    94  
    95         buffer.append("callmeth("); 
    96         buffer.append(obj); 
    97         buffer.append(", "); 
    98         buffer.append(FunctionRepr.call(method.nameUL4())); 
    99         for (AST arg : args) 
    100         { 
    101             buffer.append(", "); 
    102             buffer.append(arg); 
    103         } 
    104         for (KeywordArgument arg : kwargs) 
    105         { 
    106             buffer.append(", "); 
    107             buffer.append(arg.getName()); 
    108             buffer.append("="); 
    109             buffer.append(arg.getArg().toString(code, indent)); 
    110         } 
    111         if (remainingArgs != null) 
    112         { 
    113             buffer.append(", *"); 
    114             buffer.append(remainingArgs.toString(code, indent)); 
    115         } 
    116         if (remainingKWArgs != null) 
    117         { 
    118             buffer.append(", **"); 
    119             buffer.append(remainingKWArgs.toString(code, indent)); 
    120         } 
    121         buffer.append(")"); 
    122         return buffer.toString(); 
    12389    } 
    12490 
  • src/main/java/com/livinglogic/ul4/Callable.java

    r784 r796  
    2525    protected AST remainingKWArgs = null; 
    2626 
    27     public Callable() 
     27    public Callable(Location location, int start, int end) 
    2828    { 
    29         super(); 
     29        super(location, start, end); 
    3030    } 
    3131 
  • src/main/java/com/livinglogic/ul4/ChangeVar.java

    r784 r796  
    1414import com.livinglogic.ul4on.Encoder; 
    1515 
    16 public abstract class ChangeVar extends Tag 
     16public abstract class ChangeVar extends AST 
    1717{ 
    1818    protected String varname; 
    1919    protected AST value; 
    2020 
    21     public ChangeVar(Location location, String varname, AST value) 
     21    public ChangeVar(Location location, int start, int end, String varname, AST value) 
    2222    { 
    23         super(location); 
     23        super(location, start, end); 
    2424        this.varname = varname; 
    2525        this.value = value; 
    26     } 
    27  
    28     public String toString(InterpretedCode code, int indent) 
    29     { 
    30         StringBuilder buffer = new StringBuilder(); 
    31  
    32         for (int i = 0; i < indent; ++i) 
    33             buffer.append("\t"); 
    34         buffer.append(getType() + "(" + FunctionRepr.call(varname) + ", " + value.toString(code, indent) + ")\n"); 
    35         return buffer.toString(); 
    3626    } 
    3727 
  • src/main/java/com/livinglogic/ul4/ConditionalBlock.java

    r757 r796  
    1111abstract class ConditionalBlock extends Block 
    1212{ 
    13     public ConditionalBlock(Location location) 
     13    public ConditionalBlock(Location location, int start, int end) 
    1414    { 
    15         super(location); 
     15        super(location, start, end); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/ConditionalBlockBlock.java

    r784 r796  
    1111class ConditionalBlockBlock extends Block 
    1212{ 
    13     public ConditionalBlockBlock(Location location) 
     13    public ConditionalBlockBlock(Location location, int start, int end) 
    1414    { 
    15         super(location); 
     15        super(location, start, end); 
    1616    } 
    1717 
    18     public ConditionalBlockBlock(Location location, If block) 
     18    public ConditionalBlockBlock(Location location, int start, int end, If block) 
    1919    { 
    20         super(location); 
     20        super(location, start, end); 
    2121        startNewBlock(block); 
    2222    } 
     
    2727    } 
    2828 
    29     public String toString(InterpretedCode code, int indent) 
    30     { 
    31         StringBuilder buffer = new StringBuilder(); 
    32         for (AST item : content) 
    33             buffer.append(item.toString(code, indent)); 
    34         return buffer.toString(); 
    35     } 
    36  
    3729    public boolean handleLoopControl(String name) 
    3830    { 
     
    4032    } 
    4133 
    42     public void append(Tag item) 
     34    public void append(AST item) 
    4335    { 
    4436        ((ConditionalBlock)content.get(content.size()-1)).append(item); 
     
    8274    public Object evaluate(EvaluationContext context) throws IOException 
    8375    { 
    84         for (Tag item : content) 
     76        for (AST item : content) 
    8577        { 
    8678            if (((ConditionalBlock)item).hasToBeExecuted(context)) 
  • src/main/java/com/livinglogic/ul4/ConditionalBlockWithCondition.java

    r784 r796  
    1818    protected AST condition; 
    1919 
    20     public ConditionalBlockWithCondition(Location location, AST condition) 
     20    public ConditionalBlockWithCondition(Location location, int start, int end, AST condition) 
    2121    { 
    22         super(location); 
     22        super(location, start, end); 
    2323        this.condition = condition; 
    2424    } 
     
    2929    } 
    3030 
    31     public String toString(InterpretedCode code, int indent) 
     31    public void toString(Formatter formatter) 
    3232    { 
    33         StringBuilder buffer = new StringBuilder(); 
    34  
    35         for (int i = 0; i < indent; ++i) 
    36             buffer.append("\t"); 
    37         buffer.append(getType()); 
    38         buffer.append(" ("); 
    39         buffer.append(condition.toString(code, indent)); 
    40         buffer.append(")\n"); 
    41         for (int i = 0; i < indent; ++i) 
    42             buffer.append("\t"); 
    43         buffer.append("{\n"); 
    44         for (AST item : content) 
    45             buffer.append(item.toString(code, indent+1)); 
    46         for (int i = 0; i < indent; ++i) 
    47             buffer.append("\t"); 
    48         buffer.append("}\n"); 
    49         return buffer.toString(); 
     33        formatter.write(getType()); 
     34        formatter.write(" "); 
     35        toStringFromSource(formatter); 
     36        formatter.write(":"); 
     37        formatter.lf(); 
     38        formatter.indent(); 
     39        super.toString(formatter); 
     40        formatter.dedent(); 
    5041    } 
    5142 
  • src/main/java/com/livinglogic/ul4/Const.java

    r784 r796  
    1818    protected Object value; 
    1919 
    20     public Const(Object value) 
     20    public Const(Location location, int start, int end, Object value) 
    2121    { 
    22         super(); 
     22        super(location, start, end); 
    2323        this.value = value; 
    2424    } 
     
    2929    } 
    3030 
    31     public String toString(InterpretedCode code, int indent) 
     31    public String toString(int indent) 
    3232    { 
    3333        return FunctionRepr.call(value); 
  • src/main/java/com/livinglogic/ul4/Contains.java

    r757 r796  
    1313public class Contains extends Binary 
    1414{ 
    15     public Contains(AST obj1, AST obj2) 
     15    public Contains(Location location, int start, int end, AST obj1, AST obj2) 
    1616    { 
    17         super(obj1, obj2); 
     17        super(location, start, end, obj1, obj2); 
    1818    } 
    1919 
     
    2323    } 
    2424 
    25     public static AST make(AST obj1, AST obj2) 
     25    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2626    { 
    2727        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2929            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3030            if (!(result instanceof Undefined)) 
    31                 return new Const(result); 
     31                return new Const(location, start, end, result); 
    3232        } 
    33         return new Contains(obj1, obj2); 
     33        return new Contains(location, start, end, obj1, obj2); 
    3434    } 
    3535 
  • src/main/java/com/livinglogic/ul4/Continue.java

    r784 r796  
    77package com.livinglogic.ul4; 
    88 
    9 class Continue extends Tag 
     9class Continue extends AST 
    1010{ 
    11     public Continue(Location location) 
     11    public Continue(Location location, int start, int end) 
    1212    { 
    13         super(location); 
     13        super(location, start, end); 
    1414    } 
    1515 
     
    2424    } 
    2525 
    26     public String toString(InterpretedCode code, int indent) 
     26    public String toString(int indent) 
    2727    { 
    28         StringBuilder buffer = new StringBuilder(); 
    29         for (int i = 0; i < indent; ++i) 
    30             buffer.append("\t"); 
    31         buffer.append("continue\n"); 
    32         return buffer.toString(); 
     28        return "continue"; 
    3329    } 
    3430} 
  • src/main/java/com/livinglogic/ul4/Dict.java

    r784 r796  
    1919    protected LinkedList<DictItem> items = new LinkedList<DictItem>(); 
    2020 
    21     public Dict() 
     21    public Dict(Location location, int start, int end) 
    2222    { 
    23         super(); 
     23        super(location, start, end); 
    2424    } 
    2525 
     
    3737    { 
    3838        items.add(item); 
    39     } 
    40  
    41     public String toString(InterpretedCode code, int indent) 
    42     { 
    43         StringBuilder buffer = new StringBuilder(); 
    44         buffer.append("{"); 
    45  
    46         boolean first = true; 
    47         for (DictItem item : items) 
    48         { 
    49             if (first) 
    50                 first = false; 
    51             else 
    52                 buffer.append(", "); 
    53             buffer.append(item.toString(code, indent)); 
    54         } 
    55         buffer.append("}"); 
    56         return buffer.toString(); 
    5739    } 
    5840 
  • src/main/java/com/livinglogic/ul4/DictComprehension.java

    r795 r796  
    2424    protected AST condition; 
    2525 
    26     public DictComprehension(AST key, AST value, Object varname, AST container, AST condition) 
     26    public DictComprehension(Location location, int start, int end, AST key, AST value, Object varname, AST container, AST condition) 
    2727    { 
    28         super(); 
     28        super(location, start, end); 
    2929        this.key = key; 
    3030        this.value = value; 
     
    3232        this.container = container; 
    3333        this.condition = condition; 
    34     } 
    35  
    36     public String toString(InterpretedCode code, int indent) 
    37     { 
    38         StringBuilder buffer = new StringBuilder(); 
    39         buffer.append("{"); 
    40         buffer.append(key.toString(code, indent)); 
    41         buffer.append(":"); 
    42         buffer.append(value.toString(code, indent)); 
    43         buffer.append(" for "); 
    44         Utils.formatVarname(buffer, varname); 
    45         buffer.append(" in "); 
    46         buffer.append(container.toString(code, indent)); 
    47         if (condition != null) 
    48         { 
    49             buffer.append(" if "); 
    50             buffer.append(condition.toString(code, indent)); 
    51         } 
    52         buffer.append("}"); 
    53         return buffer.toString(); 
    5434    } 
    5535 
  • src/main/java/com/livinglogic/ul4/DictItem.java

    r784 r796  
    1515 
    1616    public abstract Object object4UL4ON(); 
    17  
    18     public abstract String toString(InterpretedCode code, int indent); 
    1917} 
  • src/main/java/com/livinglogic/ul4/DictItemDict.java

    r784 r796  
    2020    } 
    2121 
    22     public String toString(InterpretedCode code, int indent) 
    23     { 
    24         return "**" + dict.toString(code, indent); 
    25     } 
    26  
    2722    public void addTo(EvaluationContext context, Map dict) throws IOException 
    2823    { 
  • src/main/java/com/livinglogic/ul4/DictItemKeyValue.java

    r784 r796  
    2222    } 
    2323 
    24     public String toString(InterpretedCode code, int indent) 
    25     { 
    26         return key.toString() + ": " + value.toString(code, indent); 
    27     } 
    28  
    2924    public void addTo(EvaluationContext context, Map dict) throws IOException 
    3025    { 
  • src/main/java/com/livinglogic/ul4/EQ.java

    r757 r796  
    1111public class EQ extends Binary 
    1212{ 
    13     public EQ(AST obj1, AST obj2) 
     13    public EQ(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new EQ(obj1, obj2); 
     31        return new EQ(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/ElIf.java

    r757 r796  
    99class ElIf extends ConditionalBlockWithCondition 
    1010{ 
    11     public ElIf(Location location, AST condition) 
     11    public ElIf(Location location, int start, int end, AST condition) 
    1212    { 
    13         super(location, condition); 
     13        super(location, start, end, condition); 
    1414    } 
    1515 
  • src/main/java/com/livinglogic/ul4/Else.java

    r784 r796  
    1111class Else extends ConditionalBlock 
    1212{ 
    13     public Else(Location location) 
     13    public Else(Location location, int start, int end) 
    1414    { 
    15         super(location); 
     15        super(location, start, end); 
    1616    } 
    1717 
     
    2626    } 
    2727 
    28     public String toString(InterpretedCode code, int indent) 
     28    public void toString(Formatter formatter) 
    2929    { 
    30         StringBuilder buffer = new StringBuilder(); 
    31  
    32         for (int i = 0; i < indent; ++i) 
    33             buffer.append("\t"); 
    34         buffer.append("else\n"); 
    35         for (int i = 0; i < indent; ++i) 
    36             buffer.append("\t"); 
    37         buffer.append("{\n"); 
    38         for (AST item : content) 
    39             buffer.append(item.toString(code, indent+1)); 
    40         for (int i = 0; i < indent; ++i) 
    41             buffer.append("\t"); 
    42         buffer.append("}\n"); 
    43         return buffer.toString(); 
     30        formatter.write("else:"); 
     31        formatter.lf(); 
     32        formatter.indent(); 
     33        super.toString(formatter); 
     34        formatter.dedent(); 
    4435    } 
    4536} 
  • src/main/java/com/livinglogic/ul4/EvaluationContext.java

    r794 r796  
    3737 
    3838    /** 
    39      * The currently executing code object 
    40      */ 
    41     InterpretedCode code; 
     39     * The currently executing template object 
     40     */ 
     41    InterpretedTemplate template; 
    4242 
    4343    /** 
     
    7070            variables = new HashMap<String, Object>(); 
    7171        this.variables = variables; 
    72         this.code = null; 
     72        this.template = null; 
    7373        this.allVariables = new MapChain<String, Object>(variables, functions); 
    7474    } 
     
    8585 
    8686    /** 
    87      * Set the active code object and return the previously active ones. 
    88      */ 
    89     public InterpretedCode setCode(InterpretedCode code) 
    90     { 
    91         InterpretedCode result = this.code; 
    92         this.code = code; 
     87     * Set the active template object and return the previously active one. 
     88     */ 
     89    public InterpretedTemplate setTemplate(InterpretedTemplate template) 
     90    { 
     91        InterpretedTemplate result = this.template; 
     92        this.template = template; 
    9393        return result; 
    9494    } 
    9595 
    9696    /** 
    97      * Return the currently active code object. 
    98      */ 
    99     public InterpretedCode getCode() 
    100     { 
    101         return code; 
     97     * Return the currently active template object. 
     98     */ 
     99    public InterpretedTemplate getTemplate() 
     100    { 
     101        return template; 
    102102    } 
    103103 
  • src/main/java/com/livinglogic/ul4/FloorDiv.java

    r757 r796  
    1313public class FloorDiv extends Binary 
    1414{ 
    15     public FloorDiv(AST obj1, AST obj2) 
     15    public FloorDiv(Location location, int start, int end, AST obj1, AST obj2) 
    1616    { 
    17         super(obj1, obj2); 
     17        super(location, start, end, obj1, obj2); 
    1818    } 
    1919 
     
    2323    } 
    2424 
    25     public static AST make(AST obj1, AST obj2) 
     25    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2626    { 
    2727        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2929            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3030            if (!(result instanceof Undefined)) 
    31                 return new Const(result); 
     31                return new Const(location, start, end, result); 
    3232        } 
    33         return new FloorDiv(obj1, obj2); 
     33        return new FloorDiv(location, start, end, obj1, obj2); 
    3434    } 
    3535 
  • src/main/java/com/livinglogic/ul4/FloorDivVar.java

    r757 r796  
    1111public class FloorDivVar extends ChangeVar 
    1212{ 
    13     public FloorDivVar(Location location, String varname, AST value) 
     13    public FloorDivVar(Location location, int start, int end, String varname, AST value) 
    1414    { 
    15         super(location, varname, value); 
     15        super(location, start, end, varname, value); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/For.java

    r787 r796  
    2222    protected AST container; 
    2323 
    24     public For(Location location, Object varname, AST container) 
     24    public For(Location location, int start, int end, Object varname, AST container) 
    2525    { 
    26         super(location); 
     26        super(location, start, end); 
    2727        this.varname = varname; 
    2828        this.container = container; 
     
    4242    } 
    4343 
    44     public String toString(InterpretedCode code, int indent) 
     44    public void toString(Formatter formatter) 
    4545    { 
    46         StringBuilder buffer = new StringBuilder(); 
    47         for (int i = 0; i < indent; ++i) 
    48             buffer.append("\t"); 
    49         buffer.append("for "); 
    50         Utils.formatVarname(buffer, varname); 
    51         buffer.append(" in "); 
    52         buffer.append(container.toString(code, indent)); 
    53         buffer.append("\n"); 
    54         for (int i = 0; i < indent; ++i) 
    55             buffer.append("\t"); 
    56         buffer.append("{\n"); 
    57         ++indent; 
    58         for (AST item : content) 
    59             buffer.append(item.toString(code, indent)); 
    60         --indent; 
    61         for (int i = 0; i < indent; ++i) 
    62             buffer.append("\t"); 
    63         buffer.append("}\n"); 
    64         return buffer.toString(); 
     46        formatter.write("for "); 
     47        toStringFromSource(formatter); 
     48        formatter.write(":"); 
     49        formatter.lf(); 
     50        formatter.indent(); 
     51        super.toString(formatter); 
     52        formatter.dedent(); 
    6553    } 
    6654 
  • src/main/java/com/livinglogic/ul4/FunctionAsJSON.java

    r784 r796  
    137137            return new StringBuilder().append("ul4.Template.loads(").append(((InterpretedTemplate)obj).dumps()).append(")").toString(); 
    138138        } 
    139         else if (obj instanceof InterpretedFunction) 
    140         { 
    141             return new StringBuilder().append("ul4.Function.loads(").append(((InterpretedFunction)obj).dumps()).append(")").toString(); 
    142         } 
    143139        return null; 
    144140    } 
  • src/main/java/com/livinglogic/ul4/GE.java

    r757 r796  
    1111public class GE extends Binary 
    1212{ 
    13     public GE(AST obj1, AST obj2) 
     13    public GE(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new GE(obj1, obj2); 
     31        return new GE(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/GT.java

    r757 r796  
    1111public class GT extends Binary 
    1212{ 
    13     public GT(AST obj1, AST obj2) 
     13    public GT(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new GT(obj1, obj2); 
     31        return new GT(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/GeneratorExpression.java

    r795 r796  
    2727    protected AST condition; 
    2828 
    29     public GeneratorExpression(AST item, Object varname, AST container, AST condition) 
     29    public GeneratorExpression(Location location, int start, int end, AST item, Object varname, AST container, AST condition) 
    3030    { 
    31         super(); 
     31        super(location, start, end); 
    3232        this.item = item; 
    3333        this.varname = varname; 
    3434        this.container = container; 
    3535        this.condition = condition; 
    36     } 
    37  
    38     public String toString(InterpretedCode code, int indent) 
    39     { 
    40         StringBuilder buffer = new StringBuilder(); 
    41         buffer.append("("); 
    42         buffer.append(item.toString(code, indent)); 
    43         buffer.append(" for "); 
    44         Utils.formatVarname(buffer, varname); 
    45         buffer.append(" in "); 
    46         buffer.append(container.toString(code, indent)); 
    47         if (condition != null) 
    48         { 
    49             buffer.append(" if "); 
    50             buffer.append(condition.toString(code, indent)); 
    51         } 
    52         buffer.append(")"); 
    53         return buffer.toString(); 
    5436    } 
    5537 
  • src/main/java/com/livinglogic/ul4/GetAttr.java

    r784 r796  
    1919    protected String attrname; 
    2020 
    21     public GetAttr(AST obj, String attrname) 
     21    public GetAttr(Location location, int start, int end, AST obj, String attrname) 
    2222    { 
    23         super(); 
     23        super(location, start, end); 
    2424        this.obj = obj; 
    2525        this.attrname = attrname; 
    26     } 
    27  
    28     public String toString(InterpretedCode code, int indent) 
    29     { 
    30         return "getattr(" + obj + ", " + FunctionRepr.call(attrname) + ")"; 
    3126    } 
    3227 
     
    3833    public CallMeth makeCallMeth() 
    3934    { 
    40         return new CallMeth(obj, attrname); 
     35        return new CallMeth(location, start, end, obj, attrname); 
    4136    } 
    4237 
  • src/main/java/com/livinglogic/ul4/GetItem.java

    r757 r796  
    1313public class GetItem extends Binary 
    1414{ 
    15     public GetItem(AST obj1, AST obj2) 
     15    public GetItem(Location location, int start, int end, AST obj1, AST obj2) 
    1616    { 
    17         super(obj1, obj2); 
     17        super(location, start, end, obj1, obj2); 
    1818    } 
    1919 
     
    2323    } 
    2424 
    25     public static AST make(AST obj1, AST obj2) 
     25    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2626    { 
    2727        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2929            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3030            if (!(result instanceof Undefined)) 
    31                 return new Const(result); 
     31                return new Const(location, start, end, result); 
    3232        } 
    33         return new GetItem(obj1, obj2); 
     33        return new GetItem(location, start, end, obj1, obj2); 
    3434    } 
    3535 
  • src/main/java/com/livinglogic/ul4/GetSlice.java

    r784 r796  
    2323    protected AST index2; 
    2424 
    25     public GetSlice(AST obj, AST index1, AST index2) 
     25    public GetSlice(Location location, int start, int end, AST obj, AST index1, AST index2) 
    2626    { 
    27         super(); 
     27        super(location, start, end); 
    2828        this.obj = obj; 
    2929        this.index1 = index1; 
    3030        this.index2 = index2; 
    31     } 
    32  
    33     public String toString(InterpretedCode code, int indent) 
    34     { 
    35         return "getslice(" + obj.toString(code, indent) + ", " + (index1 != null ? index1.toString(code, indent) : "None") + ", " + (index2 != null ? index2.toString(code, indent) : "None") + ")"; 
    3631    } 
    3732 
     
    4136    } 
    4237 
    43     public static AST make(AST obj, AST index1, AST index2) 
     38    public static AST make(Location location, int start, int end, AST obj, AST index1, AST index2) 
    4439    { 
    4540        if (obj instanceof Const) 
     
    5146                    Object result = call(((Const)obj).value, null, null); 
    5247                    if (!(result instanceof Undefined)) 
    53                         return new Const(result); 
     48                        return new Const(location, start, end, result); 
    5449                } 
    5550                else if (index2 instanceof Const) 
     
    5752                    Object result = call(((Const)obj).value, null, ((Const)index2).value); 
    5853                    if (!(result instanceof Undefined)) 
    59                         return new Const(result); 
     54                        return new Const(location, start, end, result); 
    6055                } 
    6156            } 
     
    6661                    Object result = call(((Const)obj).value, ((Const)index1).value, null); 
    6762                    if (!(result instanceof Undefined)) 
    68                         return new Const(result); 
     63                        return new Const(location, start, end, result); 
    6964                } 
    7065                else if (index2 instanceof Const) 
     
    7267                    Object result = call(((Const)obj).value, ((Const)index1).value, ((Const)index2).value); 
    7368                    if (!(result instanceof Undefined)) 
    74                         return new Const(result); 
     69                        return new Const(location, start, end, result); 
    7570                } 
    7671            } 
    7772        } 
    78         return new GetSlice(obj, index1, index2); 
     73        return new GetSlice(location, start, end, obj, index1, index2); 
    7974    } 
    8075 
  • src/main/java/com/livinglogic/ul4/If.java

    r757 r796  
    99class If extends ConditionalBlockWithCondition 
    1010{ 
    11     public If(Location location, AST condition) 
     11    public If(Location location, int start, int end, AST condition) 
    1212    { 
    13         super(location, condition); 
     13        super(location, start, end, condition); 
    1414    } 
    1515 
  • src/main/java/com/livinglogic/ul4/InterpretedTemplate.java

    r785 r796  
    3333import com.livinglogic.ul4on.Utils; 
    3434 
    35 public class InterpretedTemplate extends InterpretedCode implements Template, UL4Type 
     35public class InterpretedTemplate extends Block implements Template, UL4Name, UL4CallableWithContext, UL4Type 
    3636{ 
    3737    /** 
    38      * Creates an empty {@code InterpretedTemplate} object. Must be filled in later (used for creating subtemplates) 
     38     * The version number used in the UL4ON dump of the template. 
     39     */ 
     40    public static final String VERSION = "24"; 
     41 
     42    /** 
     43     * The name of the template/function (defaults to {@code null}) 
     44     */ 
     45    public String name = null; 
     46 
     47    /** 
     48     * Should whitespace be skipped when outputting text nodes? 
     49     * (i.e. linefeed and the whitespace after the linefeed will be skipped. Other spaces/tabs etc. will not be skipped) 
     50     */ 
     51    public boolean keepWhitespace = true; 
     52 
     53    /** 
     54     * The start delimiter for tags (defaults to {@code "<?"}) 
     55     */ 
     56    public String startdelim = "<?"; 
     57 
     58    /** 
     59     * The end delimiter for tags (defaults to {@code "?>"}) 
     60     */ 
     61    public String enddelim = "?>"; 
     62 
     63    /** 
     64     * The template/function source (of the top-level template, i.e. subtemplates always get the full source). 
     65     */ 
     66    public String source = null; 
     67 
     68    public InterpretedTemplate(String source) throws RecognitionException 
     69    { 
     70        this(source, null, true, "<?", "?>"); 
     71    } 
     72 
     73    public InterpretedTemplate(String source, boolean keepWhitespace) throws RecognitionException 
     74    { 
     75        this(source, null, keepWhitespace, "<?", "?>"); 
     76    } 
     77 
     78    public InterpretedTemplate(String source, String name) throws RecognitionException 
     79    { 
     80        this(source, name, true, "<?", "?>"); 
     81    } 
     82 
     83    public InterpretedTemplate(String source, String name, boolean keepWhitespace) throws RecognitionException 
     84    { 
     85        this(source, name, keepWhitespace, "<?", "?>"); 
     86    } 
     87 
     88    public InterpretedTemplate(String source, String startdelim, String enddelim) throws RecognitionException 
     89    { 
     90        this(source, null, true, startdelim, enddelim); 
     91    } 
     92 
     93    public InterpretedTemplate(String source, boolean keepWhitespace, String startdelim, String enddelim) throws RecognitionException 
     94    { 
     95        this(source, null, keepWhitespace, startdelim, enddelim); 
     96    } 
     97 
     98    public InterpretedTemplate(String source, String name, boolean keepWhitespace, String startdelim, String enddelim) throws RecognitionException 
     99    { 
     100        this(null, source, name, keepWhitespace, startdelim, enddelim); 
     101        compile(); 
     102    } 
     103 
     104    /** 
     105     * Creates an {@code InterpretedTemplate} object. The content will be filled later through a call to {@link #compile) 
    39106     */ 
    40107    public InterpretedTemplate(Location location, String source, String name, boolean keepWhitespace, String startdelim, String enddelim) 
    41108    { 
    42         super(location, source, name, keepWhitespace, startdelim, enddelim); 
    43     } 
    44  
    45     public InterpretedTemplate(String source) throws RecognitionException 
    46     { 
    47         this(source, null, true, "<?", "?>"); 
    48     } 
    49  
    50     public InterpretedTemplate(String source, boolean keepWhitespace) throws RecognitionException 
    51     { 
    52         this(source, null, keepWhitespace, "<?", "?>"); 
    53     } 
    54  
    55     public InterpretedTemplate(String source, String name) throws RecognitionException 
    56     { 
    57         this(source, name, true, "<?", "?>"); 
    58     } 
    59  
    60     public InterpretedTemplate(String source, String name, boolean keepWhitespace) throws RecognitionException 
    61     { 
    62         this(source, name, keepWhitespace, "<?", "?>"); 
    63     } 
    64  
    65     public InterpretedTemplate(String source, String startdelim, String enddelim) throws RecognitionException 
    66     { 
    67         this(source, null, true, startdelim, enddelim); 
    68     } 
    69  
    70     public InterpretedTemplate(String source, boolean keepWhitespace, String startdelim, String enddelim) throws RecognitionException 
    71     { 
    72         this(source, null, keepWhitespace, startdelim, enddelim); 
    73     } 
    74  
    75     public InterpretedTemplate(String source, String name, boolean keepWhitespace, String startdelim, String enddelim) throws RecognitionException 
    76     { 
    77         super(null, source, name, keepWhitespace, startdelim, enddelim); 
    78         compile(); 
     109        super(location, 0, 0); 
     110        this.source = source; 
     111        this.name = name; 
     112        this.keepWhitespace = keepWhitespace; 
     113        this.startdelim = startdelim; 
     114        this.enddelim = enddelim; 
     115    } 
     116 
     117    protected void compile() throws RecognitionException 
     118    { 
     119        if (source == null) 
     120            return; 
     121 
     122        List<Location> tags = tokenizeTags(source, startdelim, enddelim); 
     123 
     124        // Stack of currently active blocks 
     125        Stack<Block> stack = new Stack<Block>(); 
     126        stack.push(this); 
     127 
     128        for (Location location : tags) 
     129        { 
     130            try 
     131            { 
     132                Block innerBlock = stack.peek(); 
     133                String type = location.getType(); 
     134                // FIXME: use a switch in Java 7 
     135                if (type == null) 
     136                { 
     137                    innerBlock.append(new Text(location, location.getStartCode(), location.getEndCode())); 
     138                } 
     139                else if (type.equals("print")) 
     140                { 
     141                    UL4Parser parser = getParser(location); 
     142                    innerBlock.append(new Print(location, location.getStartCode(), location.getEndCode(), parser.expression())); 
     143                } 
     144                else if (type.equals("printx")) 
     145                { 
     146                    UL4Parser parser = getParser(location); 
     147                    innerBlock.append(new PrintX(location, location.getStartCode(), location.getEndCode(), parser.expression())); 
     148                } 
     149                else if (type.equals("code")) 
     150                { 
     151                    UL4Parser parser = getParser(location); 
     152                    innerBlock.append(parser.stmt()); 
     153                } 
     154                else if (type.equals("if")) 
     155                { 
     156                    UL4Parser parser = getParser(location); 
     157                    ConditionalBlockBlock node = new ConditionalBlockBlock(location, location.getStartCode(), location.getEndCode(), new If(location, location.getStartCode(), location.getEndCode(), parser.expression())); 
     158                    innerBlock.append(node); 
     159                    stack.push(node); 
     160                } 
     161                else if (type.equals("elif")) 
     162                { 
     163                    if (innerBlock instanceof ConditionalBlockBlock) 
     164                    { 
     165                        UL4Parser parser = getParser(location); 
     166                        ((ConditionalBlockBlock)innerBlock).startNewBlock(new ElIf(location, location.getStartCode(), location.getEndCode(), parser.expression())); 
     167                    } 
     168                    else 
     169                        throw new BlockException("elif doesn't match any if"); 
     170                } 
     171                else if (type.equals("else")) 
     172                { 
     173                    if (innerBlock instanceof ConditionalBlockBlock) 
     174                    { 
     175                        ((ConditionalBlockBlock)innerBlock).startNewBlock(new Else(location, location.getStartCode(), location.getEndCode())); 
     176                    } 
     177                    else 
     178                        throw new BlockException("else doesn't match any if"); 
     179                } 
     180                else if (type.equals("end")) 
     181                { 
     182                    if (stack.size() > 1) 
     183                    { 
     184                        innerBlock.finish(location); 
     185                        stack.pop(); 
     186                    } 
     187                    else 
     188                        throw new BlockException("not in any block"); 
     189                } 
     190                else if (type.equals("for")) 
     191                { 
     192                    UL4Parser parser = getParser(location); 
     193                    Block node = parser.for_(); 
     194                    innerBlock.append(node); 
     195                    stack.push(node); 
     196                } 
     197                else if (type.equals("break")) 
     198                { 
     199                    for (int i = stack.size()-1; i >= 0; --i) 
     200                    { 
     201                        if (stack.get(i).handleLoopControl("break")) 
     202                            break; 
     203                    } 
     204                    innerBlock.append(new Break(location, location.getStartCode(), location.getEndCode())); 
     205                } 
     206                else if (type.equals("continue")) 
     207                { 
     208                    for (int i = stack.size()-1; i >= 0; --i) 
     209                    { 
     210                        if (stack.get(i).handleLoopControl("continue")) 
     211                            break; 
     212                    } 
     213                    innerBlock.append(new Continue(location, location.getStartCode(), location.getEndCode())); 
     214                } 
     215                else if (type.equals("return")) 
     216                { 
     217                    UL4Parser parser = getParser(location); 
     218                    innerBlock.append(new Return(location, location.getStartCode(), location.getEndCode(), parser.expression())); 
     219                } 
     220                else if (type.equals("def")) 
     221                { 
     222                    // Copy over all the attributes, however passing a {@link Location} will prevent compilation 
     223                    InterpretedTemplate subtemplate = new InterpretedTemplate(location, source, location.getCode(), keepWhitespace, startdelim, enddelim); 
     224                    innerBlock.append(subtemplate); 
     225                    stack.push(subtemplate); 
     226                } 
     227                else 
     228                { 
     229                    // Can't happen 
     230                    throw new RuntimeException("unknown tag " + type); 
     231                } 
     232            } 
     233            catch (Exception ex) 
     234            { 
     235                throw new TemplateException(ex, this); 
     236            } 
     237        } 
     238        if (stack.size() > 1) // the template itself is still on the stack 
     239        { 
     240            Block innerBlock = stack.peek(); 
     241            throw new ASTException(new BlockException(innerBlock.getType() + " block unclosed"), innerBlock); 
     242        } 
     243    } 
     244 
     245    private UL4Parser getParser(Location location) 
     246    { 
     247        return getParser(location, location.getCode()); 
     248    } 
     249 
     250    private UL4Parser getParser(Location location, String source) 
     251    { 
     252        ANTLRStringStream input = new ANTLRStringStream(source); 
     253        UL4Lexer lexer = new UL4Lexer(location, input); 
     254        CommonTokenStream tokens = new CommonTokenStream(lexer); 
     255        UL4Parser parser = new UL4Parser(location, tokens); 
     256        return parser; 
     257    } 
     258 
     259    public String nameUL4() 
     260    { 
     261        return name; 
     262    } 
     263 
     264    public void setName(String name) 
     265    { 
     266        this.name = name; 
     267    } 
     268 
     269    public String getSource() 
     270    { 
     271        return source; 
     272    } 
     273 
     274    public boolean getKeepWhitespace() 
     275    { 
     276        return keepWhitespace; 
     277    } 
     278 
     279    public String getStartDelim() 
     280    { 
     281        return startdelim; 
     282    } 
     283 
     284    public String getEndDelim() 
     285    { 
     286        return enddelim; 
     287    } 
     288 
     289    public void toString(Formatter formatter) 
     290    { 
     291        formatter.write("def "); 
     292        formatter.write(name != null ? name : "unnamed"); 
     293        formatter.write(":"); 
     294        formatter.lf(); 
     295        formatter.indent(); 
     296        super.toString(formatter); 
     297        formatter.dedent(); 
    79298    } 
    80299 
     
    100319    } 
    101320 
    102     public Object evaluate(EvaluationContext context) throws IOException 
    103     { 
    104         context.put(name, new TemplateClosure(this, context.getVariables())); 
    105         return null; 
     321    /** 
     322     * writes the {@code InterpretedTemplate} object to a string in the UL4ON serialization format. 
     323     * @return The string containing the template/function in serialized form. 
     324     */ 
     325    public String dumps() 
     326    { 
     327        return Utils.dumps(this); 
    106328    } 
    107329 
     
    112334    public void render(EvaluationContext context) throws IOException 
    113335    { 
    114         InterpretedCode oldCode = context.setCode(this); 
     336        InterpretedTemplate oldTemplate = context.setTemplate(this); 
    115337        try 
    116338        { 
     
    125347            throw ex; 
    126348        } 
     349        catch (ReturnException ex) 
     350        { 
     351            // ignore return value and end rendering 
     352        } 
    127353        catch (Exception ex) 
    128354        { 
    129             if (location == null) 
    130                 throw new CodeException(ex, this); 
    131             else 
    132                 throw new TagException(ex, location); 
     355            throw new TemplateException(ex, this); 
    133356        } 
    134357        finally 
    135358        { 
    136             context.setCode(oldCode); 
    137         } 
    138     } 
     359            context.setTemplate(oldTemplate); 
     360        } 
     361    } 
    139362 
    140363    /** 
     
    273496    } 
    274497 
     498    public Object callUL4(EvaluationContext context, Object[] args, Map<String, Object> kwargs) 
     499    { 
     500        if (args.length > 0) 
     501            throw new PositionalArgumentsNotSupportedException(name); 
     502        return call(context, kwargs); 
     503    } 
     504 
     505    /** 
     506     * Executes the function. 
     507     * @param context   the EvaluationContext. 
     508     * @return the return value of the function 
     509     */ 
     510    public Object call(EvaluationContext context) 
     511    { 
     512        InterpretedTemplate oldTemplate = context.setTemplate(this); 
     513        try 
     514        { 
     515            super.evaluate(context); 
     516            return null; 
     517        } 
     518        catch (IOException ex) 
     519        { 
     520            throw new ReturnException(ex); // can't happen, as a function can't produce any output 
     521        } 
     522        catch (BreakException ex) 
     523        { 
     524            throw ex; 
     525        } 
     526        catch (ContinueException ex) 
     527        { 
     528            throw ex; 
     529        } 
     530        catch (ReturnException ex) 
     531        { 
     532            return ex.getValue(); 
     533        } 
     534        catch (Exception ex) 
     535        { 
     536            throw new TemplateException(ex, this); 
     537        } 
     538        finally 
     539        { 
     540            context.setTemplate(oldTemplate); 
     541        } 
     542    } 
     543 
     544    /** 
     545     * Executes the function using the passed in variables. 
     546     * @param variables a map containing the top level variables that should be 
     547     *                  available to the function code. May be null. 
     548     * @return the return value of the function 
     549     */ 
     550    public Object call(EvaluationContext context, Map<String, Object> variables) 
     551    { 
     552        Map<String, Object> oldVariables = context.setVariables(variables); 
     553        try 
     554        { 
     555            return call(context); 
     556        } 
     557        finally 
     558        { 
     559            context.setVariables(oldVariables); 
     560        } 
     561    } 
     562 
     563    /** 
     564     * Executes the function. 
     565     * @param variables a map containing the top level variables that should be 
     566     *                  available to the function code. May be null. 
     567     * @return the return value of the function 
     568     */ 
     569    public Object call(Map<String, Object> variables) 
     570    { 
     571        return call(new EvaluationContext(null, variables)); 
     572    } 
     573 
     574    public Object evaluate(EvaluationContext context) throws IOException 
     575    { 
     576        context.put(name, new TemplateClosure(this, context.getVariables())); 
     577        return null; 
     578    } 
     579 
    275580    public String getType() 
    276581    { 
     
    282587        return "template"; 
    283588    } 
     589 
     590    public String formatText(String text) 
     591    { 
     592        return keepWhitespace ? text : removeWhitespace(text); 
     593    } 
     594 
     595    /** 
     596     * Split the template source into tags and literal text. 
     597     * @param source The sourcecode of the template 
     598     * @param startdelim The start delimiter for template tags (usually {@code "<?"}) 
     599     * @param enddelim The end delimiter for template tags (usually {@code "?>"}) 
     600     * @return A list of {@link Location} objects 
     601     */ 
     602    public List<Location> tokenizeTags(String source, String startdelim, String enddelim) 
     603    { 
     604        Pattern tagPattern = Pattern.compile(escapeREchars(startdelim) + "(printx|print|code|for|if|elif|else|end|break|continue|def|return|note)(\\s*(.*?)\\s*)?" + escapeREchars(enddelim), Pattern.DOTALL); 
     605        LinkedList<Location> tags = new LinkedList<Location>(); 
     606        if (source != null) 
     607        { 
     608            Matcher matcher = tagPattern.matcher(source); 
     609            int pos = 0; 
     610 
     611            int start; 
     612            int end; 
     613            while (matcher.find()) 
     614            { 
     615                start = matcher.start(); 
     616                end = start + matcher.group().length(); 
     617                if (pos != start) 
     618                    tags.add(new Location(this, source, null, pos, start, pos, start)); 
     619                int codestart = matcher.start(3); 
     620                int codeend = codestart + matcher.group(3).length(); 
     621                String type = matcher.group(1); 
     622                if (!type.equals("note")) 
     623                    tags.add(new Location(this, source, matcher.group(1), start, end, codestart, codeend)); 
     624                pos = end; 
     625            } 
     626            end = source.length(); 
     627            if (pos != end) 
     628                tags.add(new Location(this, source, null, pos, end, pos, end)); 
     629        } 
     630        return tags; 
     631    } 
     632 
     633    private static String escapeREchars(String input) 
     634    { 
     635        int len = input.length(); 
     636 
     637        StringBuilder buffer = new StringBuilder(len); 
     638 
     639        for (int i = 0; i < len; ++i) 
     640        { 
     641            char c = input.charAt(i); 
     642            if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) 
     643                buffer.append('\\'); 
     644            buffer.append(c); 
     645        } 
     646        return buffer.toString(); 
     647    } 
     648 
     649    public void finish(Location endlocation) 
     650    { 
     651        super.finish(endlocation); 
     652        String type = endlocation.getCode().trim(); 
     653        if (type != null && type.length() != 0 && !type.equals("def")) 
     654            throw new BlockException("def ended by end" + type); 
     655    } 
     656 
     657    public boolean handleLoopControl(String name) 
     658    { 
     659        throw new BlockException(name + " outside of for loop"); 
     660    } 
     661 
     662    static 
     663    { 
     664        Utils.register("de.livinglogic.ul4.location", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Location(null, null, null, -1, -1, -1, -1); }}); 
     665        Utils.register("de.livinglogic.ul4.text", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Text(null, -1, -1); }}); 
     666        Utils.register("de.livinglogic.ul4.const", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Const(null, -1, -1, null); }}); 
     667        Utils.register("de.livinglogic.ul4.list", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.List(null, -1, -1); }}); 
     668        Utils.register("de.livinglogic.ul4.listcomp", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ListComprehension(null, -1, -1, null, null, null, null); }}); 
     669        Utils.register("de.livinglogic.ul4.dict", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Dict(null, -1, -1); }}); 
     670        Utils.register("de.livinglogic.ul4.dictcomp", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.DictComprehension(null, -1, -1, null, null, null, null, null); }}); 
     671        Utils.register("de.livinglogic.ul4.genexpr", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.GeneratorExpression(null, -1, -1, null, null, null, null); }}); 
     672        Utils.register("de.livinglogic.ul4.var", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Var(null, -1, -1, null); }}); 
     673        Utils.register("de.livinglogic.ul4.ieie", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ConditionalBlockBlock(null, -1, -1); }}); 
     674        Utils.register("de.livinglogic.ul4.if", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.If(null, -1, -1, null); }}); 
     675        Utils.register("de.livinglogic.ul4.elif", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ElIf(null, -1, -1, null); }}); 
     676        Utils.register("de.livinglogic.ul4.else", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Else(null, -1, -1); }}); 
     677        Utils.register("de.livinglogic.ul4.for", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.For(null, -1, -1, null, null); }}); 
     678        Utils.register("de.livinglogic.ul4.break", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Break(null, -1, -1); }}); 
     679        Utils.register("de.livinglogic.ul4.continue", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Continue(null, -1, -1); }}); 
     680        Utils.register("de.livinglogic.ul4.getattr", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.GetAttr(null, -1, -1, null, null); }}); 
     681        Utils.register("de.livinglogic.ul4.getslice", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.GetSlice(null, -1, -1, null, null, null); }}); 
     682        Utils.register("de.livinglogic.ul4.not", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Not(null, -1, -1, null); }}); 
     683        Utils.register("de.livinglogic.ul4.neg", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Neg(null, -1, -1, null); }}); 
     684        Utils.register("de.livinglogic.ul4.print", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Print(null, -1, -1, null); }}); 
     685        Utils.register("de.livinglogic.ul4.printx", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.PrintX(null, -1, -1, null); }}); 
     686        Utils.register("de.livinglogic.ul4.return", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Return(null, -1, -1, null); }}); 
     687        Utils.register("de.livinglogic.ul4.getitem", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.GetItem(null, -1, -1, null, null); }}); 
     688        Utils.register("de.livinglogic.ul4.eq", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.EQ(null, -1, -1, null, null); }}); 
     689        Utils.register("de.livinglogic.ul4.ne", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.NE(null, -1, -1, null, null); }}); 
     690        Utils.register("de.livinglogic.ul4.lt", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.LT(null, -1, -1, null, null); }}); 
     691        Utils.register("de.livinglogic.ul4.le", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.LE(null, -1, -1, null, null); }}); 
     692        Utils.register("de.livinglogic.ul4.gt", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.GT(null, -1, -1, null, null); }}); 
     693        Utils.register("de.livinglogic.ul4.ge", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.GE(null, -1, -1, null, null); }}); 
     694        Utils.register("de.livinglogic.ul4.contains", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Contains(null, -1, -1, null, null); }}); 
     695        Utils.register("de.livinglogic.ul4.notcontains", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.NotContains(null, -1, -1, null, null); }}); 
     696        Utils.register("de.livinglogic.ul4.add", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Add(null, -1, -1, null, null); }}); 
     697        Utils.register("de.livinglogic.ul4.sub", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Sub(null, -1, -1, null, null); }}); 
     698        Utils.register("de.livinglogic.ul4.mul", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Mul(null, -1, -1, null, null); }}); 
     699        Utils.register("de.livinglogic.ul4.floordiv", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.FloorDiv(null, -1, -1, null, null); }}); 
     700        Utils.register("de.livinglogic.ul4.truediv", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.TrueDiv(null, -1, -1, null, null); }}); 
     701        Utils.register("de.livinglogic.ul4.or", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Or(null, -1, -1, null, null); }}); 
     702        Utils.register("de.livinglogic.ul4.and", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.And(null, -1, -1, null, null); }}); 
     703        Utils.register("de.livinglogic.ul4.mod", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.Mod(null, -1, -1, null, null); }}); 
     704        Utils.register("de.livinglogic.ul4.storevar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.StoreVar(null, -1, -1, null, null); }}); 
     705        Utils.register("de.livinglogic.ul4.addvar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.AddVar(null, -1, -1, null, null); }}); 
     706        Utils.register("de.livinglogic.ul4.subvar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.SubVar(null, -1, -1, null, null); }}); 
     707        Utils.register("de.livinglogic.ul4.mulvar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.MulVar(null, -1, -1, null, null); }}); 
     708        Utils.register("de.livinglogic.ul4.floordivvar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.FloorDivVar(null, -1, -1, null, null); }}); 
     709        Utils.register("de.livinglogic.ul4.truedivvar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.TrueDivVar(null, -1, -1, null, null); }}); 
     710        Utils.register("de.livinglogic.ul4.modvar", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.ModVar(null, -1, -1, null, null); }}); 
     711        Utils.register("de.livinglogic.ul4.callfunc", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.CallFunc(null, -1, -1, null); }}); 
     712        Utils.register("de.livinglogic.ul4.callmeth", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.CallMeth(null, -1, -1, null, (Method)null); }}); 
     713        Utils.register("de.livinglogic.ul4.template", new ObjectFactory(){ public UL4ONSerializable create() { return new com.livinglogic.ul4.InterpretedTemplate(null, null, null, false, null, null); }}); 
     714    } 
     715 
     716    public void dumpUL4ON(Encoder encoder) throws IOException 
     717    { 
     718        encoder.dump(VERSION); 
     719        encoder.dump(source); 
     720        encoder.dump(name); 
     721        encoder.dump(keepWhitespace); 
     722        encoder.dump(startdelim); 
     723        encoder.dump(enddelim); 
     724        super.dumpUL4ON(encoder); 
     725    } 
     726 
     727    public void loadUL4ON(Decoder decoder) throws IOException 
     728    { 
     729        String version = (String)decoder.load(); 
     730        if (!VERSION.equals(version)) 
     731        { 
     732            throw new RuntimeException("Invalid version, expected " + VERSION + ", got " + version); 
     733        } 
     734        source = (String)decoder.load(); 
     735        name = (String)decoder.load(); 
     736        keepWhitespace = (Boolean)decoder.load(); 
     737        startdelim = (String)decoder.load(); 
     738        enddelim = (String)decoder.load(); 
     739        super.loadUL4ON(decoder); 
     740    } 
     741 
     742    private static Map<String, ValueMaker> valueMakers = null; 
     743 
     744    public Map<String, ValueMaker> getValueMakers() 
     745    { 
     746        if (valueMakers == null) 
     747        { 
     748            HashMap<String, ValueMaker> v = new HashMap<String, ValueMaker>(super.getValueMakers()); 
     749            v.put("name", new ValueMaker(){public Object getValue(Object object){return ((InterpretedTemplate)object).name;}}); 
     750            v.put("keepws", new ValueMaker(){public Object getValue(Object object){return ((InterpretedTemplate)object).keepWhitespace;}}); 
     751            v.put("startdelim", new ValueMaker(){public Object getValue(Object object){return ((InterpretedTemplate)object).startdelim;}}); 
     752            v.put("enddelim", new ValueMaker(){public Object getValue(Object object){return ((InterpretedTemplate)object).enddelim;}}); 
     753            v.put("source", new ValueMaker(){public Object getValue(Object object){return ((InterpretedTemplate)object).source;}}); 
     754            valueMakers = v; 
     755        } 
     756        return valueMakers; 
     757    } 
    284758} 
  • src/main/java/com/livinglogic/ul4/LE.java

    r757 r796  
    1111public class LE extends Binary 
    1212{ 
    13     public LE(AST obj1, AST obj2) 
     13    public LE(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new LE(obj1, obj2); 
     31        return new LE(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/LT.java

    r757 r796  
    1111public class LT extends Binary 
    1212{ 
    13     public LT(AST obj1, AST obj2) 
     13    public LT(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new LT(obj1, obj2); 
     31        return new LT(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/List.java

    r784 r796  
    1818    protected java.util.List<AST> items = new LinkedList<AST>(); 
    1919 
    20     public List() 
     20    public List(Location location, int start, int end) 
    2121    { 
    22         super(); 
     22        super(location, start, end); 
    2323    } 
    2424 
     
    2626    { 
    2727        items.add(item); 
    28     } 
    29  
    30     public String toString(InterpretedCode code, int indent) 
    31     { 
    32         StringBuilder buffer = new StringBuilder(); 
    33         buffer.append("["); 
    34  
    35         boolean first = true; 
    36         for (AST item : items) 
    37         { 
    38             if (first) 
    39                 first = false; 
    40             else 
    41                 buffer.append(", "); 
    42             buffer.append(item.toString(code, indent)); 
    43         } 
    44         buffer.append("]"); 
    45         return buffer.toString(); 
    4628    } 
    4729 
  • src/main/java/com/livinglogic/ul4/ListComprehension.java

    r795 r796  
    2727    protected AST condition; 
    2828 
    29     public ListComprehension(AST item, Object varname, AST container, AST condition) 
     29    public ListComprehension(Location location, int start, int end, AST item, Object varname, AST container, AST condition) 
    3030    { 
    31         super(); 
     31        super(location, start, end); 
    3232        this.item = item; 
    3333        this.varname = varname; 
    3434        this.container = container; 
    3535        this.condition = condition; 
    36     } 
    37  
    38     public String toString(InterpretedCode code, int indent) 
    39     { 
    40         StringBuilder buffer = new StringBuilder(); 
    41         buffer.append("["); 
    42         buffer.append(item.toString(code, indent)); 
    43         buffer.append(" for "); 
    44         Utils.formatVarname(buffer, varname); 
    45         buffer.append(" in "); 
    46         buffer.append(container.toString(code, indent)); 
    47         if (condition != null) 
    48         { 
    49             buffer.append(" if "); 
    50             buffer.append(condition.toString(code, indent)); 
    51         } 
    52         buffer.append("]"); 
    53         return buffer.toString(); 
    5436    } 
    5537 
  • src/main/java/com/livinglogic/ul4/Location.java

    r757 r796  
    2424{ 
    2525    /** 
     26    * The template object this location belongs to 
     27    */ 
     28    public InterpretedTemplate root; 
     29 
     30    /** 
    2631     * The source code of the UL4 template this location refers to. 
    2732     * 
     
    6974     * source code of the template into tags and literal text. 
    7075     */ 
    71     public Location(String source, String type, int starttag, int endtag, int startcode, int endcode) 
    72     { 
     76    public Location(InterpretedTemplate root, String source, String type, int starttag, int endtag, int startcode, int endcode) 
     77    { 
     78        this.root = root; 
    7379        this.source = source; 
    7480        this.type = type; 
     
    8086 
    8187    /** 
     88     * Return the {@link InterpretedTemplate} object this {@code Location} belongs to 
     89     */ 
     90    public InterpretedTemplate getRoot() 
     91    { 
     92        return root; 
     93    } 
     94 
     95    /** 
     96     * Return the template source code 
     97     */ 
     98    public String getSource() 
     99    { 
     100        return source; 
     101    } 
     102 
     103    /** 
    82104     * Return the type of the tag (for {@code null} for literal text) 
    83105     */ 
     
    94116    { 
    95117        return source.substring(starttag, endtag); 
     118    } 
     119 
     120    public int getStartTag() 
     121    { 
     122        return starttag; 
     123    } 
     124 
     125    public int getEndTag() 
     126    { 
     127        return endtag; 
     128    } 
     129 
     130    public int getStartCode() 
     131    { 
     132        return startcode; 
     133    } 
     134 
     135    public int getEndCode() 
     136    { 
     137        return endcode; 
    96138    } 
    97139 
     
    151193    public void dumpUL4ON(Encoder encoder) throws IOException 
    152194    { 
     195        encoder.dump(root); 
    153196        encoder.dump(source); 
    154197        encoder.dump(type); 
     
    161204    public void loadUL4ON(Decoder decoder) throws IOException 
    162205    { 
     206        root = (InterpretedTemplate)decoder.load(); 
    163207        source = (String)decoder.load(); 
    164208        type = (String)decoder.load(); 
     
    176220        { 
    177221            HashMap<String, ValueMaker> v = new HashMap<String, ValueMaker>(); 
     222            v.put("root", new ValueMaker(){public Object getValue(Object object){return ((Location)object).getRoot();}}); 
     223            v.put("source", new ValueMaker(){public Object getValue(Object object){return ((Location)object).getSource();}}); 
    178224            v.put("type", new ValueMaker(){public Object getValue(Object object){return ((Location)object).getType();}}); 
    179225            v.put("starttag", new ValueMaker(){public Object getValue(Object object){return ((Location)object).starttag;}}); 
  • src/main/java/com/livinglogic/ul4/Mod.java

    r757 r796  
    1313public class Mod extends Binary 
    1414{ 
    15     public Mod(AST obj1, AST obj2) 
     15    public Mod(Location location, int start, int end, AST obj1, AST obj2) 
    1616    { 
    17         super(obj1, obj2); 
     17        super(location, start, end, obj1, obj2); 
    1818    } 
    1919 
     
    2323    } 
    2424 
    25     public static AST make(AST obj1, AST obj2) 
     25    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2626    { 
    2727        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2929            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3030            if (!(result instanceof Undefined)) 
    31                 return new Const(result); 
     31                return new Const(location, start, end, result); 
    3232        } 
    33         return new Mod(obj1, obj2); 
     33        return new Mod(location, start, end, obj1, obj2); 
    3434    } 
    3535 
  • src/main/java/com/livinglogic/ul4/ModVar.java

    r757 r796  
    1111public class ModVar extends ChangeVar 
    1212{ 
    13     public ModVar(Location location, String varname, AST value) 
     13    public ModVar(Location location, int start, int end, String varname, AST value) 
    1414    { 
    15         super(location, varname, value); 
     15        super(location, start, end, varname, value); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/Mul.java

    r757 r796  
    1717public class Mul extends Binary 
    1818{ 
    19     public Mul(AST obj1, AST obj2) 
    20     { 
    21         super(obj1, obj2); 
     19    public Mul(Location location, int start, int end, AST obj1, AST obj2) 
     20    { 
     21        super(location, start, end, obj1, obj2); 
    2222    } 
    2323 
     
    2727    } 
    2828 
    29     public static AST make(AST obj1, AST obj2) 
     29    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    3030    { 
    3131        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    3333            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3434            if (!(result instanceof Undefined)) 
    35                 return new Const(result); 
    36         } 
    37         return new Mul(obj1, obj2); 
     35                return new Const(location, start, end, result); 
     36        } 
     37        return new Mul(location, start, end, obj1, obj2); 
    3838    } 
    3939 
  • src/main/java/com/livinglogic/ul4/MulVar.java

    r757 r796  
    1111public class MulVar extends ChangeVar 
    1212{ 
    13     public MulVar(Location location, String varname, AST value) 
     13    public MulVar(Location location, int start, int end, String varname, AST value) 
    1414    { 
    15         super(location, varname, value); 
     15        super(location, start, end, varname, value); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/NE.java

    r757 r796  
    1111public class NE extends Binary 
    1212{ 
    13     public NE(AST obj1, AST obj2) 
     13    public NE(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new NE(obj1, obj2); 
     31        return new NE(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/Neg.java

    r757 r796  
    1313public class Neg extends Unary 
    1414{ 
    15     public Neg(AST obj) 
     15    public Neg(Location location, int start, int end, AST obj) 
    1616    { 
    17         super(obj); 
     17        super(location, start, end, obj); 
    1818    } 
    1919 
     
    2323    } 
    2424 
    25     public static AST make(AST obj) 
     25    public static AST make(Location location, int start, int end, AST obj) 
    2626    { 
    2727        if (obj instanceof Const) 
     
    2929            Object result = call(((Const)obj).value); 
    3030            if (!(result instanceof Undefined)) 
    31                 return new Const(result); 
     31                return new Const(location, start, end, result); 
    3232        } 
    33         return new Neg(obj); 
     33        return new Neg(location, start, end, obj); 
    3434    } 
    3535 
  • src/main/java/com/livinglogic/ul4/Not.java

    r757 r796  
    1111public class Not extends Unary 
    1212{ 
    13     public Not(AST obj) 
     13    public Not(Location location, int start, int end, AST obj) 
    1414    { 
    15         super(obj); 
     15        super(location, start, end, obj); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj) 
     23    public static AST make(Location location, int start, int end, AST obj) 
    2424    { 
    2525        if (obj instanceof Const) 
     
    2727            Object result = call(((Const)obj).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new Not(obj); 
     31        return new Not(location, start, end, obj); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/NotContains.java

    r757 r796  
    1111public class NotContains extends Binary 
    1212{ 
    13     public NotContains(AST obj1, AST obj2) 
     13    public NotContains(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new NotContains(obj1, obj2); 
     31        return new NotContains(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/Or.java

    r757 r796  
    1111public class Or extends Binary 
    1212{ 
    13     public Or(AST obj1, AST obj2) 
     13    public Or(Location location, int start, int end, AST obj1, AST obj2) 
    1414    { 
    15         super(obj1, obj2); 
     15        super(location, start, end, obj1, obj2); 
    1616    } 
    1717 
     
    2121    } 
    2222 
    23     public static AST make(AST obj1, AST obj2) 
     23    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2424    { 
    2525        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    2727            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    2828            if (!(result instanceof Undefined)) 
    29                 return new Const(result); 
     29                return new Const(location, start, end, result); 
    3030        } 
    31         return new Or(obj1, obj2); 
     31        return new Or(location, start, end, obj1, obj2); 
    3232    } 
    3333 
  • src/main/java/com/livinglogic/ul4/Print.java

    r784 r796  
    1010 
    1111/** 
    12  * {@code Print} is an unary Tag node that writes a string version of its 
     12 * {@code Print} is an unary AST node that writes a string version of its 
    1313 * operand to the output stream. 
    1414 */ 
    15 public class Print extends UnaryTag 
     15public class Print extends Unary 
    1616{ 
    17     public Print(Location location, AST obj) 
     17    public Print(Location location, int start, int end, AST obj) 
    1818    { 
    19         super(location, obj); 
     19        super(location, start, end, obj); 
    2020    } 
    2121 
    22     public String toString(InterpretedCode code, int indent) 
     22    public void toString(Formatter formatter) 
    2323    { 
    24         StringBuilder buffer = new StringBuilder(); 
    25  
    26         for (int i = 0; i < indent; ++i) 
    27             buffer.append("\t"); 
    28         buffer.append("print("); 
    29         buffer.append(obj.toString(code, indent)); 
    30         buffer.append(")\n"); 
    31         return buffer.toString(); 
     24        formatter.write("print "); 
     25        super.toString(formatter); 
    3226    } 
    3327 
  • src/main/java/com/livinglogic/ul4/PrintX.java

    r784 r796  
    1010 
    1111/** 
    12  * {@code PrintX} is an unary Tag node that writes a string version of its 
     12 * {@code PrintX} is an unary AST node that writes a string version of its 
    1313 * operand to the output stream and replaces the characters {@code <}, {@code >}, 
    1414 * {@code &}, {@code '} and {@code "} with the appropriate XML character 
    1515 * entities. 
    1616 */ 
    17 public class PrintX extends UnaryTag 
     17public class PrintX extends Unary 
    1818{ 
    19     public PrintX(Location location, AST obj) 
     19    public PrintX(Location location, int start, int end, AST obj) 
    2020    { 
    21         super(location, obj); 
     21        super(location, start, end, obj); 
    2222    } 
    2323 
    24     public String toString(InterpretedCode code, int indent) 
     24    public void toString(Formatter formatter) 
    2525    { 
    26         StringBuilder buffer = new StringBuilder(); 
    27  
    28         for (int i = 0; i < indent; ++i) 
    29             buffer.append("\t"); 
    30         buffer.append("printx("); 
    31         buffer.append(obj.toString(code, indent)); 
    32         buffer.append(")\n"); 
    33         return buffer.toString(); 
     26        formatter.write("printx "); 
     27        super.toString(formatter); 
    3428    } 
    3529 
  • src/main/java/com/livinglogic/ul4/Return.java

    r784 r796  
    1010 
    1111/** 
    12  * {@code Return} is an unary Tag node that can only be used inside functions 
     12 * {@code Return} is an unary AST node that can only be used inside functions 
    1313 * and that returns an expression from that function. 
    1414 */ 
    15 public class Return extends UnaryTag 
     15public class Return extends Unary 
    1616{ 
    17     public Return(Location location, AST obj) 
     17    public Return(Location location, int start, int end, AST obj) 
    1818    { 
    19         super(location, obj); 
     19        super(location, start, end, obj); 
    2020    } 
    2121 
    22     public String toString(InterpretedCode code, int indent) 
     22    public void toString(Formatter formatter) 
    2323    { 
    24         StringBuilder buffer = new StringBuilder(); 
    25  
    26         for (int i = 0; i < indent; ++i) 
    27             buffer.append("\t"); 
    28         buffer.append("return "); 
    29         buffer.append(obj.toString(code, indent)); 
    30         buffer.append("\n"); 
    31         return buffer.toString(); 
     24        formatter.write("return "); 
     25        super.toString(formatter); 
    3226    } 
    3327 
  • src/main/java/com/livinglogic/ul4/StoreVar.java

    r787 r796  
    1414import com.livinglogic.ul4on.Encoder; 
    1515 
    16 public class StoreVar extends Tag 
     16public class StoreVar extends AST 
    1717{ 
    1818    /** 
     
    2222    protected AST value; 
    2323 
    24     public StoreVar(Location location, Object varname, AST value) 
     24    public StoreVar(Location location, int start, int end, Object varname, AST value) 
    2525    { 
    26         super(location); 
     26        super(location, start, end); 
    2727        this.varname = varname; 
    2828        this.value = value; 
     
    3232    { 
    3333        return "storevar"; 
    34     } 
    35  
    36     public String toString(InterpretedCode code, int indent) 
    37     { 
    38         StringBuilder buffer = new StringBuilder(); 
    39  
    40         for (int i = 0; i < indent; ++i) 
    41             buffer.append("\t"); 
    42         buffer.append(getType() + "(" + FunctionRepr.call(varname) + ", " + value.toString(code, indent) + ")\n"); 
    43         return buffer.toString(); 
    4434    } 
    4535 
  • src/main/java/com/livinglogic/ul4/Sub.java

    r757 r796  
    1616public class Sub extends Binary 
    1717{ 
    18     public Sub(AST obj1, AST obj2) 
     18    public Sub(Location location, int start, int end, AST obj1, AST obj2) 
    1919    { 
    20         super(obj1, obj2); 
     20        super(location, start, end, obj1, obj2); 
    2121    } 
    2222 
     
    2626    } 
    2727 
    28     public static AST make(AST obj1, AST obj2) 
     28    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2929    { 
    3030        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    3232            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3333            if (!(result instanceof Undefined)) 
    34                 return new Const(result); 
     34                return new Const(location, start, end, result); 
    3535        } 
    36         return new Sub(obj1, obj2); 
     36        return new Sub(location, start, end, obj1, obj2); 
    3737    } 
    3838 
  • src/main/java/com/livinglogic/ul4/SubVar.java

    r757 r796  
    1111public class SubVar extends ChangeVar 
    1212{ 
    13     public SubVar(Location location, String varname, AST value) 
     13    public SubVar(Location location, int start, int end, String varname, AST value) 
    1414    { 
    15         super(location, varname, value); 
     15        super(location, start, end, varname, value); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/TemplateClosure.java

    r788 r796  
    2222 */ 
    2323 
    24 public class TemplateClosure extends ObjectAsMap implements Template, UL4Name, UL4Type 
     24public class TemplateClosure extends ObjectAsMap implements Template, UL4CallableWithContext, UL4Name, UL4Type 
    2525{ 
    2626    private InterpretedTemplate template; 
     
    124124    } 
    125125 
     126 
     127    public Object callUL4(EvaluationContext context, Object[] args, Map<String, Object> kwargs) 
     128    { 
     129        if (args.length > 0) 
     130            throw new PositionalArgumentsNotSupportedException(nameUL4()); 
     131        return call(context, kwargs); 
     132    } 
     133 
     134    public Object call(EvaluationContext context) 
     135    { 
     136        Map<String, Object> oldVariables = context.setVariables(variables); 
     137        try 
     138        { 
     139            return template.call(context); 
     140        } 
     141        finally 
     142        { 
     143            context.setVariables(oldVariables); 
     144        } 
     145    } 
     146 
     147    public Object call(EvaluationContext context, Map<String, Object> variables) 
     148    { 
     149        return template.call(context, new MapChain<String, Object>(variables, this.variables)); 
     150    } 
     151 
    126152    public String typeUL4() 
    127153    { 
  • src/main/java/com/livinglogic/ul4/TemplateException.java

    r788 r796  
    77package com.livinglogic.ul4; 
    88 
    9 public class CodeException extends RuntimeException 
     9public class TemplateException extends RuntimeException 
    1010{ 
    11     protected InterpretedCode code; 
     11    protected InterpretedTemplate template; 
    1212 
    13     public CodeException(Throwable cause, InterpretedCode code) 
     13    public TemplateException(Throwable cause, InterpretedTemplate template) 
    1414    { 
    15         super(code.nameUL4() != null ? "in " + code.getType() + " named " + code.nameUL4() : "in unnamed " + code.getType(), cause); 
    16         this.code = code; 
     15        super(template.nameUL4() != null ? "in template named " + template.nameUL4() : "in unnamed template", cause); 
     16        this.template = template; 
    1717    } 
    1818} 
  • src/main/java/com/livinglogic/ul4/Text.java

    r784 r796  
    1414import com.livinglogic.ul4on.Encoder; 
    1515 
    16 class Text extends Tag 
     16class Text extends AST 
    1717{ 
    18     public Text(Location location) 
     18    public Text(Location location, int start, int end) 
    1919    { 
    20         super(location); 
     20        super(location, start, end); 
    2121    } 
    2222 
    23     public String getText(InterpretedCode code) 
     23    public String getText() 
    2424    { 
     25        InterpretedTemplate template = location.getRoot(); 
    2526        String text = location.getCode(); 
    26         if (code != null) 
    27             text = code.formatText(text); 
     27        if (template != null) 
     28            text = template.formatText(text); 
    2829        return text; 
    2930    } 
    3031 
    31     public String toString(InterpretedCode code, int indent) 
     32    public void toString(Formatter formatter) 
    3233    { 
    33         StringBuilder buffer = new StringBuilder(); 
    34  
    35         for (int i = 0; i < indent; ++i) 
    36             buffer.append("\t"); 
    37         buffer.append("text("); 
    38         buffer.append(FunctionRepr.call(getText(code))); 
    39         buffer.append(")\n"); 
    40         return buffer.toString(); 
     34        formatter.write("text "); 
     35        formatter.write(FunctionRepr.call(getText())); 
    4136    } 
    4237 
     
    4843    public Object evaluate(EvaluationContext context) throws IOException 
    4944    { 
    50         context.write(getText(context.getCode())); 
     45        context.write(getText()); 
    5146        return null; 
    5247    } 
  • src/main/java/com/livinglogic/ul4/TrueDiv.java

    r757 r796  
    1414public class TrueDiv extends Binary 
    1515{ 
    16     public TrueDiv(AST obj1, AST obj2) 
     16    public TrueDiv(Location location, int start, int end, AST obj1, AST obj2) 
    1717    { 
    18         super(obj1, obj2); 
     18        super(location, start, end, obj1, obj2); 
    1919    } 
    2020 
     
    2424    } 
    2525 
    26     public static AST make(AST obj1, AST obj2) 
     26    public static AST make(Location location, int start, int end, AST obj1, AST obj2) 
    2727    { 
    2828        if (obj1 instanceof Const && obj2 instanceof Const) 
     
    3030            Object result = call(((Const)obj1).value, ((Const)obj2).value); 
    3131            if (!(result instanceof Undefined)) 
    32                 return new Const(result); 
     32                return new Const(location, start, end, result); 
    3333        } 
    34         return new TrueDiv(obj1, obj2); 
     34        return new TrueDiv(location, start, end, obj1, obj2); 
    3535    } 
    3636 
  • src/main/java/com/livinglogic/ul4/TrueDivVar.java

    r757 r796  
    1111public class TrueDivVar extends ChangeVar 
    1212{ 
    13     public TrueDivVar(Location location, String varname, AST value) 
     13    public TrueDivVar(Location location, int start, int end, String varname, AST value) 
    1414    { 
    15         super(location, varname, value); 
     15        super(location, start, end, varname, value); 
    1616    } 
    1717 
  • src/main/java/com/livinglogic/ul4/Unary.java

    r784 r796  
    2929     * @param obj The operand 
    3030     */ 
    31     public Unary(AST obj) 
     31    public Unary(Location location, int start, int end, AST obj) 
    3232    { 
    33         super(); 
     33        super(location, start, end); 
    3434        this.obj = obj; 
    35     } 
    36  
    37     public String toString(InterpretedCode code, int indent) 
    38     { 
    39         return getType() + "(" + obj.toString(code, indent) + ")"; 
    4035    } 
    4136 
  • src/main/java/com/livinglogic/ul4/Var.java

    r784 r796  
    1818    protected String name; 
    1919 
    20     public Var(String name) 
     20    public Var(Location location, int start, int end, String name) 
    2121    { 
    22         super(); 
     22        super(location, start, end); 
    2323        this.name = name; 
    24     } 
    25  
    26     public String toString(InterpretedCode code, int indent) 
    27     { 
    28         return name; 
    2924    } 
    3025 
  • src/test/java/tests/UL4Test.java

    r791 r796  
    2929import com.livinglogic.ul4.Color; 
    3030import com.livinglogic.ul4.InterpretedTemplate; 
    31 import com.livinglogic.ul4.InterpretedFunction; 
    3231import com.livinglogic.ul4.FunctionDate; 
    3332import com.livinglogic.ul4.KeyException; 
     
    10099    } 
    101100 
    102     private static InterpretedFunction getFunction(String source, String name) 
    103     { 
    104         try 
    105         { 
    106             InterpretedFunction function = new InterpretedFunction(source, name, false); 
    107             // System.out.println(function); 
    108             return function; 
    109         } 
    110         catch (RecognitionException ex) 
    111         { 
    112             throw new RuntimeException(ex); 
    113         } 
    114     } 
    115  
    116     private static InterpretedFunction getFunction(String source) 
    117     { 
    118         return getFunction(source, null); 
    119     } 
    120  
    121     private static Object getFunctionOutput(String source, Object... args) 
    122     { 
    123         InterpretedFunction function = getFunction(source); 
    124         return function.call(makeMap(args)); 
    125     } 
    126  
    127     private static void checkFunctionOutput(Object expected, String source, Object... args) 
    128     { 
    129         // Execute the function once by directly compiling and calling it 
    130         InterpretedFunction function1 = getFunction(source); 
    131         Object output1 = function1.call(makeMap(args)); 
     101    private static Object getTemplateResult(String source, Object... args) 
     102    { 
     103        InterpretedTemplate template = getTemplate(source); 
     104        return template.call(makeMap(args)); 
     105    } 
     106 
     107    private static void checkTemplateResult(Object expected, String source, Object... args) 
     108    { 
     109        // Execute the template once by directly compiling and calling it 
     110        InterpretedTemplate template1 = getTemplate(source); 
     111        Object output1 = template1.call(makeMap(args)); 
    132112        assertEquals(expected, output1); 
    133113 
    134         // Recreate the function from the dump of the compiled function 
    135         InterpretedFunction function2 = InterpretedFunction.loads(function1.dumps()); 
    136  
    137         // Check that the functions format the same 
    138         assertEquals(function1.toString(), function2.toString()); 
     114        // Recreate the template from the dump of the compiled template 
     115        InterpretedTemplate template2 = InterpretedTemplate.loads(template1.dumps()); 
     116 
     117        // Check that the templates format the same 
     118        assertEquals(template1.toString(), template2.toString()); 
    139119 
    140120        // Check that they have the same output 
    141         Object output2 = function2.call(makeMap(args)); 
     121        Object output2 = template2.call(makeMap(args)); 
    142122        assertEquals(expected, output2); 
    143123    } 
     
    516496    public void tag_break_outside_loop_in_template() 
    517497    { 
    518         checkTemplateOutput("", "<?template gurk?><?break?><?end template?>"); 
     498        checkTemplateOutput("", "<?def gurk?><?break?><?end def?>"); 
    519499    } 
    520500 
     
    540520    public void tag_continue_outside_loop_in_template() 
    541521    { 
    542         checkTemplateOutput("", "<?template gurk?><?continue?><?end template?>"); 
     522        checkTemplateOutput("", "<?def gurk?><?continue?><?end def?>"); 
    543523    } 
    544524 
     
    22382218        checkTemplateOutput("False", source, "data", asList()); 
    22392219        checkTemplateOutput("False", source, "data", makeMap()); 
    2240         checkTemplateOutput("False", source, "data", getTemplate("")); 
     2220        checkTemplateOutput("True", source, "data", getTemplate("")); 
    22412221        checkTemplateOutput("True", "<?print isfunction(repr)?>"); 
    22422222        checkTemplateOutput("False", source, "data", new Color(0, 0, 0)); 
     
    26552635        checkTemplateOutput("dict", source, "data", makeMap(1, 2)); 
    26562636        checkTemplateOutput("template", source, "data", getTemplate("")); 
    2657         checkTemplateOutput("function", source, "data", getFunction("")); 
    26582637        checkTemplateOutput("color", source, "data", new Color(0, 0, 0)); 
    26592638 
     
    28332812        InterpretedTemplate t2 = getTemplate("<?print 'foo'?>"); 
    28342813 
    2835         checkTemplateOutput("(f)(o)(o)", "<?for c in data?><?render t.render(data=c, prefix='(', suffix=')')?><?end for?>", "t", t1, "data", "foo"); 
     2814        checkTemplateOutput("(f)(o)(o)", "<?for c in data?><?code t.render(data=c, prefix='(', suffix=')')?><?end for?>", "t", t1, "data", "foo"); 
    28362815        checkTemplateOutput("foo", "<?print t.render()?>", "t", t2); 
    28372816        checkTemplateOutput("foo", "<?print t.render \n\t(\n \t)\n\t ?>", "t", t2); 
    28382817 
    2839         checkTemplateOutput("42", "<?render globals.template.render(value=42)?>", "globals", makeMap("template", getTemplate("<?print value?>"))); 
    2840         checkTemplateOutput("", "<?render globals.template.render(value=42)?>", "globals", makeMap("template", getTemplate(""))); 
     2818        checkTemplateOutput("42", "<?code globals.template.render(value=42)?>", "globals", makeMap("template", getTemplate("<?print value?>"))); 
     2819        checkTemplateOutput("", "<?code globals.template.render(value=42)?>", "globals", makeMap("template", getTemplate(""))); 
    28412820    } 
    28422821 
     
    28462825        InterpretedTemplate t = getTemplate("<?code x += 1?><?print x?>"); 
    28472826 
    2848         checkTemplateOutput("42,43,42", "<?print x?>,<?render t.render(x=x)?>,<?print x?>", "t", t, "x", 42); 
     2827        checkTemplateOutput("42,43,42", "<?print x?>,<?code t.render(x=x)?>,<?print x?>", "t", t, "x", 42); 
    28492828    } 
    28502829 
     
    28522831    public void method_render_localtemplate() 
    28532832    { 
    2854         checkTemplateOutput("foo", "<?template lower?><?print x.lower()?><?end template?><?print lower.renders(x='FOO')?>"); 
     2833        checkTemplateOutput("foo", "<?def lower?><?print x.lower()?><?end def?><?print lower.renders(x='FOO')?>"); 
    28552834    } 
    28562835 
     
    28592838    { 
    28602839        String source = ( 
    2861             "<?template outer?>" + 
    2862                 "<?template inner?>" + 
     2840            "<?def outer?>" + 
     2841                "<?def inner?>" + 
    28632842                    "<?code x += 1?>" + 
    28642843                    "<?code y += 1?>" + 
    28652844                    "<?print x?>!" + 
    28662845                    "<?print y?>!" + 
    2867                 "<?end template?>" + 
     2846                "<?end def?>" + 
    28682847                "<?code x += 1?>" + 
    28692848                "<?code y += 1?>" + 
    2870                 "<?render inner.render(x=x)?>" + 
     2849                "<?code inner.render(x=x)?>" + 
    28712850                "<?print x?>!" + 
    28722851                "<?print y?>!" + 
    2873             "<?end template?>" + 
     2852            "<?end def?>" + 
    28742853            "<?code x += 1?>" + 
    28752854            "<?code y += 1?>" + 
    2876             "<?render outer.render(x=x)?>" + 
     2855            "<?code outer.render(x=x)?>" + 
    28772856            "<?print x?>!" + 
    28782857            "<?print y?>!" 
     
    31583137    public void templateattributes_localtemplate() 
    31593138    { 
    3160         String source = "<?template lower?><?print t.lower()?><?end template?>"; 
     3139        String source = "<?def lower?><?print t.lower()?><?end def?>"; 
    31613140 
    31623141        checkTemplateOutput(source + "<?print lower.source?>", source + "<?print lower.source?>"); 
     
    31693148    public void nestedscopes() 
    31703149    { 
    3171         checkTemplateOutput("0;1;2;", "<?for i in range(3)?><?template x?><?print i?>;<?end template?><?render x.render()?><?end for?>"); 
    3172         checkTemplateOutput("1;", "<?for i in range(3)?><?if i == 1?><?template x?><?print i?>;<?end template?><?end if?><?end for?><?render x.render()?>"); 
    3173         checkTemplateOutput("1", "<?code i = 1?><?template x?><?print i?><?end template?><?code i = 2?><?render x.render()?>"); 
    3174         checkTemplateOutput("1", "<?code i = 1?><?template x?><?template y?><?print i?><?end template?><?code i = 2?><?render y.render()?><?end template?><?code i = 3?><?render x.render()?>"); 
     3150        checkTemplateOutput("0;1;2;", "<?for i in range(3)?><?def x?><?print i?>;<?end def?><?code x.render()?><?end for?>"); 
     3151        checkTemplateOutput("1;", "<?for i in range(3)?><?if i == 1?><?def x?><?print i?>;<?end def?><?end if?><?end for?><?code x.render()?>"); 
     3152        checkTemplateOutput("1", "<?code i = 1?><?def x?><?print i?><?end def?><?code i = 2?><?code x.render()?>"); 
     3153        checkTemplateOutput("1", "<?code i = 1?><?def x?><?def y?><?print i?><?end def?><?code i = 2?><?code y.render()?><?end def?><?code i = 3?><?code x.render()?>"); 
    31753154    } 
    31763155 
     
    31783157    public void pass_functions() 
    31793158    { 
    3180         checkTemplateOutput("&lt;", "<?template x?><?print x('<')?><?end template?><?render x.render(x=xmlescape)?>"); 
     3159        checkTemplateOutput("&lt;", "<?def x?><?print x('<')?><?end def?><?code x.render(x=xmlescape)?>"); 
    31813160    } 
    31823161 
     
    31843163    public void function() 
    31853164    { 
    3186         checkFunctionOutput(42, "<?return 42?>"); 
     3165        checkTemplateResult(42, "<?return 42?>"); 
    31873166    } 
    31883167 
     
    31903169    public void function_value() 
    31913170    { 
    3192         checkFunctionOutput(84, "<?return 2*x?>", "x", 42); 
     3171        checkTemplateResult(84, "<?return 2*x?>", "x", 42); 
    31933172    } 
    31943173 
     
    31963175    public void function_multiple_returnvalues() 
    31973176    { 
    3198         checkFunctionOutput(84, "<?return 2*x?><?return 3*x?>", "x", 42); 
     3177        checkTemplateResult(84, "<?return 2*x?><?return 3*x?>", "x", 42); 
    31993178    } 
    32003179 
     
    32023181    public void function_name() 
    32033182    { 
    3204         checkFunctionOutput("f", "<?function f?><?return f.name?><?end function?><?return f(f=f)?>"); 
     3183        checkTemplateResult("f", "<?def f?><?return f.name?><?end def?><?return f(f=f)?>"); 
    32053184    } 
    32063185 
     
    32083187    public void function_closure() 
    32093188    { 
    3210         checkFunctionOutput(24, "<?code y=3?><?function inner?><?return 2*x*y?><?end function?><?return inner(x=4)?>"); 
    3211         checkFunctionOutput(24, "<?function outer?><?code y=3?><?function inner?><?return 2*x*y?><?end function?><?return inner?><?end function?><?return outer()(x=4)?>"); 
     3189        checkTemplateResult(24, "<?code y=3?><?def inner?><?return 2*x*y?><?end def?><?return inner(x=4)?>"); 
     3190        checkTemplateResult(24, "<?def outer?><?code y=3?><?def inner?><?return 2*x*y?><?end def?><?return inner?><?end def?><?return outer()(x=4)?>"); 
     3191    } 
     3192 
     3193    @Test 
     3194    public void return_in_template() 
     3195    { 
     3196        checkTemplateOutput("gurk", "gurk<?return 42?>hurz"); 
    32123197    } 
    32133198 
     
    32743259            "<?print x.find(1, 2, 3)?>" + 
    32753260            "<?if x?>gurk<?elif y?>hurz<?else?>hinz<?end if?>" + 
    3276             "<?template x?>foo<?end template?>" + 
    3277             "<?function x?><?return 42?><?end function?>" 
     3261            "<?def x?>foo<?end def?>" 
    32783262        ); 
    32793263    }