Changeset 336:0dcff6da7e64 in livinglogic.java.ul4

Show
Ignore:
Timestamp:
02/03/11 11:14:13 (8 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Move functionality for generating Javscript source to newclass JavascriptSource?4Template.

Files:
3 modified
1 copied

Legend:

Unmodified
Added
Removed
  • docs/versiondoc.txt

    r332 r336  
     1HEAD: 
     2------- 
     3Comments: 
     4* The functionality for generating Javscript source from a template has been 
     5  moved to a separate class JavascriptSource4Template. 
     6 
     7 
    18exp-35: 
    29------- 
  • library/src/com/livinglogic/ul4/InterpretedTemplate.java

    r334 r336  
    18841884    } 
    18851885 
    1886     private void code(StringBuffer buffer, int indent, String code) 
    1887     { 
    1888         for (int i = 0; i < indent; ++i) 
    1889             buffer.append("\t"); 
    1890         buffer.append(code); 
    1891         buffer.append("\n"); 
    1892     } 
    1893  
    18941886    public String javascriptSource() 
    18951887    { 
    1896         StringBuffer buffer = new StringBuffer(); 
    1897         int indent = 0; 
    1898         int varcounter = 0; 
    1899         Location lastLocation = null; 
    1900  
    1901         code(buffer, indent, "ul4.Template.create(function(vars){"); 
    1902         indent += 1; 
    1903         code(buffer, indent, "//@@@ BEGIN template source"); 
    1904         code(buffer, indent, "//@@@ BEGIN template code"); 
    1905         code(buffer, indent, "var out = [], r0 = null, r1 = null, r2 = null, r3 = null, r4 = null, r5 = null, r6 = null, r7 = null, r8 = null, r9 = null;"); 
    1906  
    1907         int size = opcodes.size(); 
    1908  
    1909         for (int i = 0; i < size; ++i) 
    1910         { 
    1911             Opcode opcode = opcodes.get(i); 
    1912             if (opcode.location != lastLocation && opcode.name != Opcode.OC_TEXT) 
    1913             { 
    1914                 lastLocation = opcode.location; 
    1915                 String code = Utils.repr(lastLocation.getTag()); 
    1916                 code = code.substring(1, code.length()-1); 
    1917                 code(buffer, indent, "// " + lastLocation + ": " + code); 
    1918             } 
    1919  
    1920             switch (opcode.name) 
    1921             { 
    1922                 case Opcode.OC_TEXT: 
    1923                     code(buffer, indent, "out.push(" + Utils.json(opcode.location.getCode()) + ");"); 
    1924                     break; 
    1925                 case Opcode.OC_LOADSTR: 
    1926                     code(buffer, indent, "r" + opcode.r1 + " = " + Utils.json(opcode.arg) + ";"); 
    1927                     break; 
    1928                 case Opcode.OC_LOADINT: 
    1929                     code(buffer, indent, "r" + opcode.r1 + " = " + opcode.arg + ";"); 
    1930                     break; 
    1931                 case Opcode.OC_LOADFLOAT: 
    1932                     code(buffer, indent, "r" + opcode.r1 + " = " + opcode.arg + ";"); 
    1933                     break; 
    1934                 case Opcode.OC_LOADNONE: 
    1935                     code(buffer, indent, "r" + opcode.r1 + " = null;"); 
    1936                     break; 
    1937                 case Opcode.OC_LOADFALSE: 
    1938                     code(buffer, indent, "r" + opcode.r1 + " = false;"); 
    1939                     break; 
    1940                 case Opcode.OC_LOADTRUE: 
    1941                     code(buffer, indent, "r" + opcode.r1 + " = true;"); 
    1942                     break; 
    1943                 case Opcode.OC_LOADDATE: 
    1944                     code(buffer, indent, "r" + opcode.r1 + " = " + Utils.json(Utils.isoparse(opcode.arg)) + ";"); 
    1945                     break; 
    1946                 case Opcode.OC_LOADCOLOR: 
    1947                     code(buffer, indent, "r" + opcode.r1 + " = " + Utils.json(Color.fromdump(opcode.arg)) + ";"); 
    1948                     break; 
    1949                 case Opcode.OC_BUILDLIST: 
    1950                     code(buffer, indent, "r" + opcode.r1 + " = [];"); 
    1951                     break; 
    1952                 case Opcode.OC_BUILDDICT: 
    1953                     code(buffer, indent, "r" + opcode.r1 + " = {};"); 
    1954                     break; 
    1955                 case Opcode.OC_ADDLIST: 
    1956                     code(buffer, indent, "r" + opcode.r1 + ".push(r" + opcode.r2 + ");"); 
    1957                     break; 
    1958                 case Opcode.OC_ADDDICT: 
    1959                     code(buffer, indent, "r" + opcode.r1 + "[r" + opcode.r2 + "] = r" + opcode.r3 + ";"); 
    1960                     break; 
    1961                 case Opcode.OC_UPDATEDICT: 
    1962                     code(buffer, indent, "for (var key in r" + opcode.r2 + ")"); 
    1963                     indent++; 
    1964                     code(buffer, indent, "r" + opcode.r1 + "[key] = r" + opcode.r2 + "[key];"); 
    1965                     indent--; 
    1966                     break; 
    1967                 case Opcode.OC_LOADVAR: 
    1968                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getitem(vars, " + Utils.repr(opcode.arg) + ");"); 
    1969                     break; 
    1970                 case Opcode.OC_STOREVAR: 
    1971                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = r" + opcode.r1 + ";"); 
    1972                     break; 
    1973                 case Opcode.OC_ADDVAR: 
    1974                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_add(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1975                     break; 
    1976                 case Opcode.OC_SUBVAR: 
    1977                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_sub(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1978                     break; 
    1979                 case Opcode.OC_MULVAR: 
    1980                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_mul(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1981                     break; 
    1982                 case Opcode.OC_TRUEDIVVAR: 
    1983                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_truediv(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1984                     break; 
    1985                 case Opcode.OC_FLOORDIVVAR: 
    1986                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_floordiv(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1987                     break; 
    1988                 case Opcode.OC_MODVAR: 
    1989                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_mod(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1990                     break; 
    1991                 case Opcode.OC_DELVAR: 
    1992                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = undefined;"); 
    1993                     break; 
    1994                 case Opcode.OC_GETATTR: 
    1995                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getitem(r" + opcode.r2 + ", " + Utils.repr(opcode.arg) + ");"); 
    1996                     break; 
    1997                 case Opcode.OC_GETITEM: 
    1998                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getitem(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    1999                     break; 
    2000                 case Opcode.OC_GETSLICE12: 
    2001                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2002                     break; 
    2003                 case Opcode.OC_GETSLICE1: 
    2004                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2005                     break; 
    2006                 case Opcode.OC_GETSLICE2: 
    2007                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", null, r" + opcode.r3 + ");"); 
    2008                     break; 
    2009                 case Opcode.OC_PRINT: 
    2010                     code(buffer, indent, "out.push(ul4._fu_str(r" + opcode.r1 + "));"); 
    2011                     break; 
    2012                 case Opcode.OC_PRINTX: 
    2013                     code(buffer, indent, "out.push(ul4._fu_xmlescape(r" + opcode.r1 + "));"); 
    2014                     break; 
    2015                 case Opcode.OC_FOR: 
    2016                     varcounter++; 
    2017                     code(buffer, indent, "for (var iter" + varcounter + " = ul4._iter(r" + opcode.r2 + ");;)"); 
    2018                     code(buffer, indent, "{"); 
    2019                     indent++; 
    2020                     code(buffer, indent, "r" + opcode.r1 + " = iter" + varcounter + "();"); 
    2021                     code(buffer, indent, "if (r" + opcode.r1 + " === null)"); 
    2022                     indent++; 
    2023                     code(buffer, indent, "break;"); 
    2024                     indent--; 
    2025                     code(buffer, indent, "r" + opcode.r1 + " = r" + opcode.r1 + "[0];"); 
    2026                     break; 
    2027                 case Opcode.OC_ENDFOR: 
    2028                     indent--; 
    2029                     code(buffer, indent, "}"); 
    2030                     break; 
    2031                 case Opcode.OC_DEF: 
    2032                     code(buffer, indent, "vars[" + Utils.json(opcode.arg) + "] = ul4.Template.create(function(vars){"); 
    2033                     indent++; 
    2034                     code(buffer, indent, "var out = [], r0 = null, r1 = null, r2 = null, r3 = null, r4 = null, r5 = null, r6 = null, r7 = null, r8 = null, r9 = null;"); 
    2035                     break; 
    2036                 case Opcode.OC_ENDDEF: 
    2037                     code(buffer, indent, "return out;"); 
    2038                     indent--; 
    2039                     code(buffer, indent, "});"); 
    2040                     break; 
    2041                 case Opcode.OC_BREAK: 
    2042                     code(buffer, indent, "break;"); 
    2043                     break; 
    2044                 case Opcode.OC_CONTINUE: 
    2045                     code(buffer, indent, "continue;"); 
    2046                     break; 
    2047                 case Opcode.OC_NOT: 
    2048                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._fu_bool(r" + opcode.r2 + ");"); 
    2049                     break; 
    2050                 case Opcode.OC_NEG: 
    2051                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_neg(r" + opcode.r2 + ");"); 
    2052                     break; 
    2053                 case Opcode.OC_CONTAINS: 
    2054                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_contains(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2055                     break; 
    2056                 case Opcode.OC_NOTCONTAINS: 
    2057                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_contains(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2058                     break; 
    2059                 case Opcode.OC_EQ: 
    2060                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_eq(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2061                     break; 
    2062                 case Opcode.OC_NE: 
    2063                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_eq(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2064                     break; 
    2065                 case Opcode.OC_LT: 
    2066                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_lt(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2067                     break; 
    2068                 case Opcode.OC_LE: 
    2069                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_le(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2070                     break; 
    2071                 case Opcode.OC_GT: 
    2072                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_le(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2073                     break; 
    2074                 case Opcode.OC_GE: 
    2075                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_lt(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2076                     break; 
    2077                 case Opcode.OC_ADD: 
    2078                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_add(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2079                     break; 
    2080                 case Opcode.OC_SUB: 
    2081                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_sub(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2082                     break; 
    2083                 case Opcode.OC_MUL: 
    2084                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_mul(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2085                     break; 
    2086                 case Opcode.OC_FLOORDIV: 
    2087                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_floordiv(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2088                     break; 
    2089                 case Opcode.OC_TRUEDIV: 
    2090                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_truediv(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2091                     break; 
    2092                 case Opcode.OC_MOD: 
    2093                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_mod(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2094                     break; 
    2095                 case Opcode.OC_AND: 
    2096                     code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r3 + ") ? r" + opcode.r2 + " : r" + opcode.r3 + ";"); 
    2097                     break; 
    2098                 case Opcode.OC_OR: 
    2099                     code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r2 + ") ? r" + opcode.r2 + " : r" + opcode.r3 + ";"); 
    2100                     break; 
    2101                 case Opcode.OC_CALLFUNC0: 
    2102                     switch (opcode.argcode) 
    2103                     { 
    2104                         case Opcode.CF0_NOW: 
    2105                             code(buffer, indent, "r" + opcode.r1 + " = new Date();"); 
    2106                             break; 
    2107                         case Opcode.CF0_UTCNOW: 
    2108                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_utcnow();"); 
    2109                             break; 
    2110                         case Opcode.CF0_RANDOM: 
    2111                             code(buffer, indent, "r" + opcode.r1 + " = Math.random();"); 
    2112                             break; 
    2113                         case Opcode.CF0_VARS: 
    2114                             code(buffer, indent, "r" + opcode.r1 + " = vars;"); 
    2115                             break; 
    2116                     } 
    2117                     break; 
    2118                 case Opcode.OC_CALLFUNC1: 
    2119                     switch (opcode.argcode) 
    2120                     { 
    2121                         case Opcode.CF1_XMLESCAPE: 
    2122                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_xmlescape(r" + opcode.r2 + ");"); 
    2123                             break; 
    2124                         case Opcode.CF1_CSV: 
    2125                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_csv(r" + opcode.r2 + ");"); 
    2126                             break; 
    2127                         case Opcode.CF1_REPR: 
    2128                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_repr(r" + opcode.r2 + ");"); 
    2129                             break; 
    2130                         case Opcode.CF1_ENUMERATE: 
    2131                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_enumerate(r" + opcode.r2 + ");"); 
    2132                             break; 
    2133                         case Opcode.CF1_CHR: 
    2134                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_chr(r" + opcode.r2 + ");"); 
    2135                             break; 
    2136                         case Opcode.CF1_ORD: 
    2137                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_ord(r" + opcode.r2 + ");"); 
    2138                             break; 
    2139                         case Opcode.CF1_HEX: 
    2140                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hex(r" + opcode.r2 + ");"); 
    2141                             break; 
    2142                         case Opcode.CF1_OCT: 
    2143                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_oct(r" + opcode.r2 + ");"); 
    2144                             break; 
    2145                         case Opcode.CF1_BIN: 
    2146                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bin(r" + opcode.r2 + ");"); 
    2147                             break; 
    2148                         case Opcode.CF1_SORTED: 
    2149                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_sorted(r" + opcode.r2 + ");"); 
    2150                             break; 
    2151                         case Opcode.CF1_TYPE: 
    2152                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_type(r" + opcode.r2 + ");"); 
    2153                             break; 
    2154                         case Opcode.CF1_JSON: 
    2155                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_json(r" + opcode.r2 + ");"); 
    2156                             break; 
    2157                         case Opcode.CF1_REVERSED: 
    2158                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_reversed(r" + opcode.r2 + ");"); 
    2159                             break; 
    2160                         case Opcode.CF1_RANDCHOICE: 
    2161                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randchoice(r" + opcode.r2 + ");"); 
    2162                             break; 
    2163                         case Opcode.CF1_STR: 
    2164                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_str(r" + opcode.r2 + ");"); 
    2165                             break; 
    2166                         case Opcode.CF1_INT: 
    2167                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_int(r" + opcode.r2 + ");"); 
    2168                             break; 
    2169                         case Opcode.CF1_FLOAT: 
    2170                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_float(r" + opcode.r2 + ");"); 
    2171                             break; 
    2172                         case Opcode.CF1_BOOL: 
    2173                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r2 + ");"); 
    2174                             break; 
    2175                         case Opcode.CF1_LEN: 
    2176                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_len(r" + opcode.r2 + ");"); 
    2177                             break; 
    2178                         case Opcode.CF1_ISSTR: 
    2179                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isstr(r" + opcode.r2 + ");"); 
    2180                             break; 
    2181                         case Opcode.CF1_ISINT: 
    2182                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isint(r" + opcode.r2 + ");"); 
    2183                             break; 
    2184                         case Opcode.CF1_ISFLOAT: 
    2185                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isfloat(r" + opcode.r2 + ");"); 
    2186                             break; 
    2187                         case Opcode.CF1_ISBOOL: 
    2188                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isbool(r" + opcode.r2 + ");"); 
    2189                             break; 
    2190                         case Opcode.CF1_ISDATE: 
    2191                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isdate(r" + opcode.r2 + ");"); 
    2192                             break; 
    2193                         case Opcode.CF1_ISLIST: 
    2194                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_islist(r" + opcode.r2 + ");"); 
    2195                             break; 
    2196                         case Opcode.CF1_ISDICT: 
    2197                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isdict(r" + opcode.r2 + ");"); 
    2198                             break; 
    2199                         case Opcode.CF1_ISTEMPLATE: 
    2200                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_istemplate(r" + opcode.r2 + ");"); 
    2201                             break; 
    2202                         case Opcode.CF1_ISCOLOR: 
    2203                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_iscolor(r" + opcode.r2 + ");"); 
    2204                             break; 
    2205                         case Opcode.CF1_ABS: 
    2206                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_abs(r" + opcode.r2 + ");"); 
    2207                             break; 
    2208                         case Opcode.CF1_RANGE: 
    2209                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_range(0, r" + opcode.r2 + ", 1);"); 
    2210                             break; 
    2211                         case Opcode.CF1_RANDRANGE: 
    2212                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randrange(0, r" + opcode.r2 + ", 1);"); 
    2213                             break; 
    2214                         case Opcode.CF1_ISNONE: 
    2215                             code(buffer, indent, "r" + opcode.r1 + " = (r" + opcode.r2 + " === null);"); 
    2216                             break; 
    2217                         case Opcode.CF1_GET: 
    2218                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(vars, r" + opcode.r2 + ");"); 
    2219                             break; 
    2220                     } 
    2221                     break; 
    2222                 case Opcode.OC_CALLFUNC2: 
    2223                     switch (opcode.argcode) 
    2224                     { 
    2225                         case Opcode.CF2_ZIP: 
    2226                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_zip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2227                             break; 
    2228                         case Opcode.CF2_INT: 
    2229                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_int(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2230                             break; 
    2231                         case Opcode.CF2_RANGE: 
    2232                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_range(r" + opcode.r2 + ", r" + opcode.r3 + ", 1);"); 
    2233                             break; 
    2234                         case Opcode.CF2_RANDRANGE: 
    2235                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randrange(r" + opcode.r2 + ", r" + opcode.r3 + ", 1);"); 
    2236                             break; 
    2237                         case Opcode.CF2_GET: 
    2238                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(vars, r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2239                             break; 
    2240                     } 
    2241                     break; 
    2242                 case Opcode.OC_CALLFUNC3: 
    2243                     switch (opcode.argcode) 
    2244                     { 
    2245                         case Opcode.CF3_RANGE: 
    2246                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_range(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2247                             break; 
    2248                         case Opcode.CF3_RANDRANGE: 
    2249                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randrange(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2250                             break; 
    2251                         case Opcode.CF3_ZIP: 
    2252                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_zip(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2253                             break; 
    2254                         case Opcode.CF3_HLS: 
    2255                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hls(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
    2256                             break; 
    2257                         case Opcode.CF3_HSV: 
    2258                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hsv(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
    2259                             break; 
    2260                         case Opcode.CF3_RGB: 
    2261                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_rgb(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
    2262                             break; 
    2263                     } 
    2264                     break; 
    2265                 case Opcode.OC_CALLFUNC4: 
    2266                     switch (opcode.argcode) 
    2267                     { 
    2268                         case Opcode.CF4_RGB: 
    2269                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_rgb(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2270                             break; 
    2271                         case Opcode.CF4_HLS: 
    2272                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hls(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2273                             break; 
    2274                         case Opcode.CF4_HSV: 
    2275                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hsv(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2276                             break; 
    2277                     } 
    2278                     break; 
    2279                 case Opcode.OC_CALLMETH0: 
    2280                     switch (opcode.argcode) 
    2281                     { 
    2282                         case Opcode.CM0_STRIP: 
    2283                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_strip(r" + opcode.r2 + ");"); 
    2284                             break; 
    2285                         case Opcode.CM0_LSTRIP: 
    2286                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lstrip(r" + opcode.r2 + ");"); 
    2287                             break; 
    2288                         case Opcode.CM0_RSTRIP: 
    2289                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rstrip(r" + opcode.r2 + ");"); 
    2290                             break; 
    2291                         case Opcode.CM0_UPPER: 
    2292                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_upper(r" + opcode.r2 + ");"); 
    2293                             break; 
    2294                         case Opcode.CM0_LOWER: 
    2295                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lower(r" + opcode.r2 + ");"); 
    2296                             break; 
    2297                         case Opcode.CM0_CAPITALIZE: 
    2298                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_capitalize(r" + opcode.r2 + ");"); 
    2299                             break; 
    2300                         case Opcode.CM0_ITEMS: 
    2301                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_items(r" + opcode.r2 + ");"); 
    2302                             break; 
    2303                         case Opcode.CM0_ISOFORMAT: 
    2304                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_isoformat(r" + opcode.r2 + ");"); 
    2305                             break; 
    2306                         case Opcode.CM0_MIMEFORMAT: 
    2307                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_mimeformat(r" + opcode.r2 + ");"); 
    2308                             break; 
    2309                         case Opcode.CM0_DAY: 
    2310                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_day(r" + opcode.r2 + ");"); 
    2311                             break; 
    2312                         case Opcode.CM0_MONTH: 
    2313                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_month(r" + opcode.r2 + ");"); 
    2314                             break; 
    2315                         case Opcode.CM0_YEAR: 
    2316                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_year(r" + opcode.r2 + ");"); 
    2317                             break; 
    2318                         case Opcode.CM0_HOUR: 
    2319                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hour(r" + opcode.r2 + ");"); 
    2320                             break; 
    2321                         case Opcode.CM0_MINUTE: 
    2322                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_minute(r" + opcode.r2 + ");"); 
    2323                             break; 
    2324                         case Opcode.CM0_SECOND: 
    2325                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_second(r" + opcode.r2 + ");"); 
    2326                             break; 
    2327                         case Opcode.CM0_MICROSECOND: 
    2328                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_microsecond(r" + opcode.r2 + ");"); 
    2329                             break; 
    2330                         case Opcode.CM0_WEEKDAY: 
    2331                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_weekday(r" + opcode.r2 + ");"); 
    2332                             break; 
    2333                         case Opcode.CM0_YEARDAY: 
    2334                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_yearday(r" + opcode.r2 + ");"); 
    2335                             break; 
    2336                         case Opcode.CM0_R: 
    2337                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_r(r" + opcode.r2 + ");"); 
    2338                             break; 
    2339                         case Opcode.CM0_G: 
    2340                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_g(r" + opcode.r2 + ");"); 
    2341                             break; 
    2342                         case Opcode.CM0_B: 
    2343                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_b(r" + opcode.r2 + ");"); 
    2344                             break; 
    2345                         case Opcode.CM0_A: 
    2346                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_a(r" + opcode.r2 + ");"); 
    2347                             break; 
    2348                         case Opcode.CM0_LUM: 
    2349                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lum(r" + opcode.r2 + ");"); 
    2350                             break; 
    2351                         case Opcode.CM0_HLS: 
    2352                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hls(r" + opcode.r2 + ");"); 
    2353                             break; 
    2354                         case Opcode.CM0_HLSA: 
    2355                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hlsa(r" + opcode.r2 + ");"); 
    2356                             break; 
    2357                         case Opcode.CM0_HSV: 
    2358                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hsv(r" + opcode.r2 + ");"); 
    2359                             break; 
    2360                         case Opcode.CM0_HSVA: 
    2361                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hsva(r" + opcode.r2 + ");"); 
    2362                             break; 
    2363                         case Opcode.CM0_SPLIT: 
    2364                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", null, null);"); 
    2365                             break; 
    2366                         case Opcode.CM0_RSPLIT: 
    2367                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", null, null);"); 
    2368                             break; 
    2369                         case Opcode.CM0_RENDER: 
    2370                             code(buffer, indent, "r" + opcode.r1 + " = r" + opcode.r2 + ".renders({});"); 
    2371                             break; 
    2372                     } 
    2373                     break; 
    2374                 case Opcode.OC_CALLMETH1: 
    2375                     switch (opcode.argcode) 
    2376                     { 
    2377                         case Opcode.CM1_JOIN: 
    2378                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_join(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2379                             break; 
    2380                         case Opcode.CM1_STRIP: 
    2381                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_strip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2382                             break; 
    2383                         case Opcode.CM1_LSTRIP: 
    2384                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lstrip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2385                             break; 
    2386                         case Opcode.CM1_RSTRIP: 
    2387                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rstrip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2388                             break; 
    2389                         case Opcode.CM1_STARTSWITH: 
    2390                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_startswith(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2391                             break; 
    2392                         case Opcode.CM1_ENDSWITH: 
    2393                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_endswith(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2394                             break; 
    2395                         case Opcode.CM1_FORMAT: 
    2396                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_format(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2397                             break; 
    2398                         case Opcode.CM1_WITHLUM: 
    2399                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_withlum(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2400                             break; 
    2401                         case Opcode.CM1_WITHA: 
    2402                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_witha(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2403                             break; 
    2404                         case Opcode.CM1_SPLIT: 
    2405                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2406                             break; 
    2407                         case Opcode.CM1_RSPLIT: 
    2408                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2409                             break; 
    2410                         case Opcode.CM1_GET: 
    2411                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2412                             break; 
    2413                         case Opcode.CM1_FIND: 
    2414                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", null, null);"); 
    2415                             break; 
    2416                         case Opcode.CM1_RFIND: 
    2417                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", null, null);"); 
    2418                             break; 
    2419                     } 
    2420                     break; 
    2421                 case Opcode.OC_CALLMETH2: 
    2422                     switch (opcode.argcode) 
    2423                     { 
    2424                         case Opcode.CM2_SPLIT: 
    2425                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2426                             break; 
    2427                         case Opcode.CM2_RSPLIT: 
    2428                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2429                             break; 
    2430                         case Opcode.CM2_REPLACE: 
    2431                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_replace(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2432                             break; 
    2433                         case Opcode.CM2_GET: 
    2434                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2435                             break; 
    2436                         case Opcode.CM2_FIND: 
    2437                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", null);"); 
    2438                             break; 
    2439                         case Opcode.CM2_RFIND: 
    2440                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", null);"); 
    2441                             break; 
    2442                     } 
    2443                     break; 
    2444                 case Opcode.OC_CALLMETH3: 
    2445                     switch (opcode.argcode) 
    2446                     { 
    2447                         case Opcode.CM3_FIND: 
    2448                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2449                             break; 
    2450                         case Opcode.CM3_RFIND: 
    2451                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2452                             break; 
    2453                     } 
    2454                     break; 
    2455                 case Opcode.OC_CALLMETHKW: 
    2456                     switch (opcode.argcode) 
    2457                     { 
    2458                         case Opcode.CMKW_RENDER: 
    2459                             code(buffer, indent, "r" + opcode.r1 + " = r" + opcode.r2 + ".renders(r" + opcode.r3 + ");"); 
    2460                             break; 
    2461                     } 
    2462                     break; 
    2463                 case Opcode.OC_IF: 
    2464                     code(buffer, indent, "if (ul4._fu_bool(r" + opcode.r1 + "))"); 
    2465                     code(buffer, indent, "{"); 
    2466                     indent++; 
    2467                     break; 
    2468                 case Opcode.OC_ELSE: 
    2469                     indent--; 
    2470                     code(buffer, indent, "}"); 
    2471                     code(buffer, indent, "else"); 
    2472                     code(buffer, indent, "{"); 
    2473                     indent++; 
    2474                     break; 
    2475                 case Opcode.OC_ENDIF: 
    2476                     indent--; 
    2477                     code(buffer, indent, "}"); 
    2478                     break; 
    2479                 case Opcode.OC_RENDER: 
    2480                     code(buffer, indent, "out = out.concat(r" + opcode.r1 + ".render(r" + opcode.r2 + "));"); 
    2481                     break; 
    2482             } 
    2483         } 
    2484         code(buffer, indent, "return out;"); 
    2485         code(buffer, indent, "//@@@ END template code"); 
    2486         indent--; 
    2487         code(buffer, indent, "})"); 
    2488         return buffer.toString(); 
     1888        return new JavascriptSource4Template(this).toString(); 
    24891889    } 
    24901890} 
  • library/src/com/livinglogic/ul4/JavascriptSource4Template.java

    r334 r336  
    1919import org.apache.commons.lang.ObjectUtils; 
    2020 
    21 public class InterpretedTemplate implements Template 
     21public class JavascriptSource4Template 
    2222{ 
    23     // used by the code tokenizer 
    24     private static Pattern tokenPattern; 
    25     private static Pattern namePattern; 
    26     private static Pattern floatPattern; 
    27     private static Pattern hexintPattern; 
    28     private static Pattern octintPattern; 
    29     private static Pattern binintPattern; 
    30     private static Pattern intPattern; 
    31     private static Pattern datePattern; 
    32     private static Pattern color3Pattern; 
    33     private static Pattern color4Pattern; 
    34     private static Pattern color6Pattern; 
    35     private static Pattern color8Pattern; 
    36     private static Pattern whitespacePattern; 
    37     private static Pattern escaped8BitCharPattern; 
    38     private static Pattern escaped16BitCharPattern; 
    39     private static Pattern escaped32BitCharPattern; 
    40  
    41     static 
     23    private InterpretedTemplate template; 
     24    private StringBuffer buffer; 
     25    private int indent; 
     26 
     27    public JavascriptSource4Template(InterpretedTemplate template) 
    4228    { 
    43         // Initializes regular expressions 
    44         tokenPattern = Pattern.compile("\\(|\\)|\\[|\\]|\\{|\\}|\\.|,|==|\\!=|<=|<|>=|>|=|\\+=|\\-=|\\*=|/=|//=|%=|%|:|\\+|-|\\*\\*|\\*|//|/"); 
    45         namePattern = Pattern.compile("[a-zA-Z_][\\w]*"); 
    46         // We don't have negative numbers, this is handled by constant folding in the AST for unary minus 
    47         floatPattern = Pattern.compile("(\\d+(\\.\\d*)?[eE][+-]?\\d+|\\d+\\.\\d*([eE][+-]?\\d+)?)"); 
    48         hexintPattern = Pattern.compile("0[xX][\\da-fA-F]+"); 
    49         octintPattern = Pattern.compile("0[oO][0-7]+"); 
    50         binintPattern = Pattern.compile("0[bB][01]+"); 
    51         intPattern = Pattern.compile("\\d+"); 
    52         datePattern = Pattern.compile("@\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2}(:\\d{2}(.\\d{6})?)?)?"); 
    53         color3Pattern = Pattern.compile("[#][0-9a-zA-Z]{3}"); 
    54         color4Pattern = Pattern.compile("[#][0-9a-zA-Z]{4}"); 
    55         color6Pattern = Pattern.compile("[#][0-9a-zA-Z]{6}"); 
    56         color8Pattern = Pattern.compile("[#][0-9a-zA-Z]{8}"); 
    57         whitespacePattern = Pattern.compile("\\s+"); 
    58         escaped8BitCharPattern = Pattern.compile("\\\\x[0-9a-fA-F]{2}"); 
    59         escaped16BitCharPattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); 
    60         escaped32BitCharPattern = Pattern.compile("\\\\U[0-9a-fA-F]{8}"); 
     29        this.template = template; 
    6130    } 
    6231 
    63     /** 
    64      * Contains information about the currently running loops during rendering 
    65      * of the template. 
    66      */ 
    67     class IteratorStackEntry 
    68     { 
    69         /** 
    70          * The register number where the loop variable has to be stored for each 
    71          * run through the loop body. 
    72          */ 
    73         public int iteratorRegSpec; 
    74  
    75         /** 
    76          * The program counter (i.e. the index of the opcode in the 
    77          * {@link #opcodes} list) where the loop started (i.e. the location of the 
    78          * <code>for</code> opcode). 
    79          */ 
    80         public int pcFor; 
    81  
    82         /** 
    83          * The program counter (i.e. the index of the opcode in the 
    84          * {@link #opcodes} list) where the loop ends (i.e. the location of the 
    85          * <code>endfor</code> opcode). 
    86          */ 
    87         public int pcEndFor; 
    88  
    89         /** 
    90          * The iterator producing the values for the loop variable. 
    91          */ 
    92         public Iterator iterator; 
    93  
    94         public IteratorStackEntry(int iteratorRegSpec, int pcFor, int pcEndFor, Iterator iterator) 
    95         { 
    96             this.iteratorRegSpec = iteratorRegSpec; 
    97             this.pcFor = pcFor; 
    98             this.pcEndFor = pcEndFor; 
    99             this.iterator = iterator; 
    100         } 
    101     } 
    102  
    103     /** 
    104      * The header used in the compiled format of the template. 
    105      */ 
    106     public static final String HEADER = "ul4"; 
    107  
    108     /** 
    109      * The version number used in the compiled format of the template. 
    110      */ 
    111     public static final String VERSION = "14"; 
    112  
    113     /** 
    114      * The start delimiter for tags (defaults to <code>&lt;?</code>) 
    115      */ 
    116     public String startdelim; 
    117  
    118     /** 
    119      * The end delimiter for tags (defaults to <code>?&gt;</code>) 
    120      */ 
    121     public String enddelim; 
    122  
    123     /** 
    124      * The template source. 
    125      */ 
    126     public String source; 
    127  
    128     /** 
    129      * The list of opcodes. 
    130      */ 
    131     public List<Opcode> opcodes; 
    132  
    133     /** 
    134      * The locale to be used when formatting int, float or date objects. 
    135      */ 
    136     public Locale defaultLocale; 
    137  
    138     /** 
    139      * Has {@link annotate} been called for this template? 
    140      */ 
    141     private boolean annotated = false; 
    142  
    143     /** 
    144      * Creates an empty template object. 
    145      */ 
    146     public InterpretedTemplate() 
    147     { 
    148         this.source = null; 
    149         this.opcodes = new LinkedList<Opcode>(); 
    150         this.defaultLocale = Locale.GERMANY; 
    151     } 
    152  
    153     /** 
    154      * Creates an template object for a source string and a list of opcodes. 
    155      */ 
    156     public InterpretedTemplate(String source, List<Opcode> opcodes, String startdelim, String enddelim, int startindex, int endindex) 
    157     { 
    158         this.source = source; 
    159         this.startdelim = startdelim; 
    160         this.enddelim = enddelim; 
    161         this.opcodes = opcodes.subList(startindex, endindex); 
    162         this.defaultLocale = Locale.GERMANY; 
    163     } 
    164  
    165     /** 
    166      * Creates an template object for a source string and a list of opcodes. 
    167      */ 
    168     public InterpretedTemplate(String source, List<Opcode> opcodes, String startdelim, String enddelim) 
    169     { 
    170         this.source = source; 
    171         this.startdelim = startdelim; 
    172         this.enddelim = enddelim; 
    173         this.opcodes = opcodes.subList(0, opcodes.size()); 
    174         this.defaultLocale = Locale.GERMANY; 
    175     } 
    176  
    177     /** 
    178      * Appends a new opcode to {@link opcodes}. 
    179      */ 
    180     public void opcode(int name, Location location) 
    181     { 
    182         opcodes.add(new Opcode(name, -1, -1, -1, -1, -1, null, location)); 
    183     } 
    184  
    185     /** 
    186      * Appends a new opcode to {@link opcodes}. 
    187      */ 
    188     public void opcode(int name, String arg, Location location) 
    189     { 
    190         opcodes.add(new Opcode(name, -1, -1, -1, -1, -1, arg, location)); 
    191     } 
    192  
    193     /** 
    194      * Appends a new opcode to {@link opcodes}. 
    195      */ 
    196     public void opcode(int name, int r1, Location location) 
    197     { 
    198         opcodes.add(new Opcode(name, r1, -1, -1, -1, -1, null, location)); 
    199     } 
    200  
    201     /** 
    202      * Appends a new opcode to {@link opcodes}. 
    203      */ 
    204     public void opcode(int name, int r1, String arg, Location location) 
    205     { 
    206         opcodes.add(new Opcode(name, r1, -1, -1, -1, -1, arg, location)); 
    207     } 
    208  
    209     /** 
    210      * Appends a new opcode to {@link opcodes}. 
    211      */ 
    212     public void opcode(int name, int r1, int r2, Location location) 
    213     { 
    214         opcodes.add(new Opcode(name, r1, r2, -1, -1, -1, null, location)); 
    215     } 
    216  
    217     /** 
    218      * Appends a new opcode to {@link opcodes}. 
    219      */ 
    220     public void opcode(int name, int r1, int r2, String arg, Location location) 
    221     { 
    222         opcodes.add(new Opcode(name, r1, r2, -1, -1, -1, arg, location)); 
    223     } 
    224  
    225     /** 
    226      * Appends a new opcode to {@link opcodes}. 
    227      */ 
    228     public void opcode(int name, int r1, int r2, int r3, Location location) 
    229     { 
    230         opcodes.add(new Opcode(name, r1, r2, r3, -1, -1, null, location)); 
    231     } 
    232  
    233     /** 
    234      * Appends a new opcode to {@link opcodes}. 
    235      */ 
    236     public void opcode(int name, int r1, int r2, int r3, String arg, Location location) 
    237     { 
    238         opcodes.add(new Opcode(name, r1, r2, r3, -1, -1, arg, location)); 
    239     } 
    240  
    241     /** 
    242      * Appends a new opcode to {@link opcodes}. 
    243      */ 
    244     public void opcode(int name, int r1, int r2, int r3, int r4, Location location) 
    245     { 
    246         opcodes.add(new Opcode(name, r1, r2, r3, r4, -1, null, location)); 
    247     } 
    248  
    249     /** 
    250      * Appends a new opcode to {@link opcodes}. 
    251      */ 
    252     public void opcode(int name, int r1, int r2, int r3, int r4, String arg, Location location) 
    253     { 
    254         opcodes.add(new Opcode(name, r1, r2, r3, r4, -1, arg, location)); 
    255     } 
    256  
    257     /** 
    258      * Appends a new opcode to {@link opcodes}. 
    259      */ 
    260     public void opcode(int name, int r1, int r2, int r3, int r4, int r5, Location location) 
    261     { 
    262         opcodes.add(new Opcode(name, r1, r2, r3, r4, r5, null, location)); 
    263     } 
    264  
    265     /** 
    266      * Appends a new opcode to {@link opcodes}. 
    267      */ 
    268     public void opcode(int name, int r1, int r2, int r3, int r4, int r5, String arg, Location location) 
    269     { 
    270         opcodes.add(new Opcode(name, r1, r2, r3, r4, r5, arg, location)); 
    271     } 
    272  
    273     protected static String read(Reader reader, int length) throws IOException 
    274     { 
    275         char[] chars = new char[length]; 
    276         int readlength = reader.read(chars); 
    277         return new String(chars); 
    278     } 
    279  
    280     /** 
    281      * Reads a character from a stream. 
    282      * @param reader the reader from which the linefeed is read. 
    283      * @throws IOException if reading from the stream fails 
    284      * @throws RuntimeException if the character read from the stream is not a 
    285      *                          linefeed 
    286      */ 
    287     protected static void readchar(Reader reader, char expected) throws IOException 
    288     { 
    289         int readInt = reader.read(); 
    290         if (-1 < readInt) 
    291         { 
    292             char charValue = (char)readInt; 
    293             if (expected != charValue) 
    294             { 
    295                 throw new RuntimeException("Invalid character, expected '" + expected + "', got '" + charValue + "'"); 
    296             } 
    297         } 
    298         else 
    299         { 
    300             throw new RuntimeException("Short read!"); 
    301         } 
    302     } 
    303  
    304     protected static int readintInternal(Reader reader, String prefix) throws IOException 
    305     { 
    306         int retVal = 0; 
    307         boolean digitFound = false; 
    308         if (prefix != null) 
    309         { 
    310             String prefixread = read(reader, prefix.length()); 
    311             if (!prefixread.equals(prefix)) 
    312                 throw new RuntimeException("Invalid prefix, expected '" + prefix + "', got '" + prefixread + "'"); 
    313         } 
    314         while (true) 
    315         { 
    316             int readInt = reader.read(); 
    317             char charValue = (char)readInt; 
    318             int intValue = Character.digit(charValue, 10); 
    319             if (-1 < intValue) 
    320             { 
    321                 retVal = retVal * 10 + intValue; 
    322                 digitFound = true; 
    323             } 
    324             else if (charValue == '|') 
    325             { 
    326                 if (!digitFound) 
    327                     retVal = -1; 
    328                 return retVal; 
    329             } 
    330             else 
    331             { 
    332                 throw new RuntimeException("Invalid terminator, expected '|', got '" + charValue + "'"); 
    333             } 
    334         } 
    335     } 
    336  
    337     /** 
    338      * Reads a (non-negative) integer value from a stream. 
    339      * @param reader the reader from which the value is read. 
    340      * @param prefix The string before the digits of the integer value 
    341      * @return The integer value 
    342      * @throws IOException if reading from the stream fails 
    343      * @throws RuntimeException if the integer value is malformed (i.e. the 
    344      *                          terminator is missing) 
    345      */ 
    346     protected static int readint(Reader reader, String prefix) throws IOException 
    347     { 
    348         int retVal = readintInternal(reader, prefix); 
    349         if (0 > retVal) 
    350         { 
    351             throw new RuntimeException("Invalid integer read!"); 
    352         } 
    353         return retVal; 
    354     } 
    355  
    356     /** 
    357      * Reads a string value (or <code>null</code>) from a stream. 
    358      * <code>readstr</code> is the inverse operation of {@link writestr}. 
    359      * @param reader the reader from which the string is read. 
    360      * @param prefix The string that was used in {@link writestr}. 
    361      * @return The string or <code>null</code> 
    362      * @throws IOException if reading from the stream fails 
    363      * @throws RuntimeException if the integer value is malformed 
    364      */ 
    365     protected static String readstr(Reader reader, String prefix) throws IOException 
    366     { 
    367         int stringLength = readintInternal(reader, prefix); 
    368         if (-1 == stringLength) 
    369             return null; 
    370  
    371         String retVal = read(reader, stringLength); 
    372         if (retVal.length() != stringLength) 
    373             throw new RuntimeException("Short read!"); 
    374         readchar(reader, '|'); 
    375         return retVal; 
    376     } 
    377  
    378     /** 
    379      * loads the source of a template from a reader, without checking the version 
    380      * number of the binary file. This is helpful when updating an old stored source. 
    381      * @param reader the reader from which the source is read. 
    382      * @return The source as a string. 
    383      * @throws IOException if reading from the stream fails 
    384      */ 
    385     public static String loadsource(Reader reader) throws IOException 
    386     { 
    387         BufferedReader bufferedReader = new BufferedReader(reader); 
    388         bufferedReader.readLine(); // skip header (without checking) 
    389         bufferedReader.readLine(); // skip version number (with checking) 
    390         readstr(bufferedReader, "SD"); // skip start delimiter 
    391         readchar(bufferedReader, '\n'); 
    392         readstr(bufferedReader, "ED"); // skip end delimiter 
    393         readchar(bufferedReader, '\n'); 
    394         return readstr(bufferedReader, "SRC"); 
    395     } 
    396  
    397     /** 
    398      * loads the source of a template from a string containing the compiled 
    399      * template. 
    400      * @param bytecode of the compiled template. 
    401      * @return The source as a string. 
    402      */ 
    403     public static String loadsource(String bytecode) 
    404     { 
    405         try 
    406         { 
    407             return loadsource(new StringReader(bytecode)); 
    408         } 
    409         catch (IOException ex) // can not happen when reading from a StringReader 
    410         { 
    411             return null; 
    412         } 
    413     } 
    414  
    415     /** 
    416      * loads a template from a reader. 
    417      * @param reader the reader from which the template is read. 
    418      * @return The template object. 
    419      * @throws IOException if reading from the stream fails 
    420      */ 
    421     public static InterpretedTemplate load(Reader reader) throws IOException 
    422     { 
    423         InterpretedTemplate retVal = new InterpretedTemplate(); 
    424         BufferedReader bufferedReader = new BufferedReader(reader); 
    425         String header = bufferedReader.readLine(); 
    426         if (!HEADER.equals(header)) 
    427         { 
    428             throw new RuntimeException("Invalid header, expected " + HEADER + ", got " + header); 
    429         } 
    430         String version = bufferedReader.readLine(); 
    431         if (!VERSION.equals(version)) 
    432         { 
    433             throw new RuntimeException("Invalid version, expected " + VERSION + ", got " + version); 
    434         } 
    435         retVal.startdelim = readstr(bufferedReader, "SD"); 
    436         readchar(bufferedReader, '\n'); 
    437         retVal.enddelim = readstr(bufferedReader, "ED"); 
    438         readchar(bufferedReader, '\n'); 
    439         retVal.source = readstr(bufferedReader, "SRC"); 
    440         readchar(bufferedReader, '\n'); 
    441         int count = readint(bufferedReader, "n"); 
    442         readchar(bufferedReader, '\n'); 
    443         Location location = null; 
    444         for (int i = 0; i < count; i++) 
    445         { 
    446             int r1 = readintInternal(bufferedReader, null); 
    447             int r2 = readintInternal(bufferedReader, null); 
    448             int r3 = readintInternal(bufferedReader, null); 
    449             int r4 = readintInternal(bufferedReader, null); 
    450             int r5 = readintInternal(bufferedReader, null); 
    451             String code = readstr(bufferedReader, "C"); 
    452             String arg = readstr(bufferedReader, "A"); 
    453             int readInt = bufferedReader.read(); 
    454             if (-1 < readInt) 
    455             { 
    456                 char charValue = (char)readInt; 
    457                 if ('^' == charValue) 
    458                 { 
    459                     if (null == location) 
    460                     { 
    461                         throw new RuntimeException("No previous location!"); 
    462                     } 
    463                 } 
    464                 else if ('*' == charValue) 
    465                 { 
    466                     int readInt2 = bufferedReader.read(); 
    467                     char charValue2 = (char)readInt2; 
    468                     if ('|' != charValue2) 
    469                     { 
    470                         throw new RuntimeException("Invalid location spec " + charValue + charValue2); 
    471                     } 
    472                     location = new Location(retVal.source, readstr(bufferedReader, "T"), 
    473                         readint(bufferedReader, "st"), readint(bufferedReader, "et"), 
    474                         readint(bufferedReader, "sc"), readint(bufferedReader, "ec")); 
    475                 } 
    476                 else 
    477                 { 
    478                     throw new RuntimeException("Invalid location spec " + charValue); 
    479                 } 
    480             } 
    481             else 
    482             { 
    483                 throw new RuntimeException("Short read!"); 
    484             } 
    485             retVal.opcodes.add(new Opcode(code, r1, r2, r3, r4, r5, arg, location)); 
    486             readchar(bufferedReader, '\n'); 
    487         } 
    488         return retVal; 
    489     } 
    490  
    491     /** 
    492      * loads a template from a string. 
    493      * @param bytecode of the compiled template. 
    494      * @return The template object. 
    495      * @throws IOException if reading from the stream fails 
    496      */ 
    497     public static InterpretedTemplate load(String bytecode) 
    498     { 
    499         try 
    500         { 
    501             return load(new StringReader(bytecode)); 
    502         } 
    503         catch (IOException ex) // can not happen when reading from a StringReader 
    504         { 
    505             return null; 
    506         } 
    507     } 
    508  
    509     /** 
    510      * writes an int to a stream in such a way that the int can be reliable read 
    511      * again. This is done by writing the digits of the integer followed by a 
    512      * terminator character (that may not be a digit). 
    513      * @param writer the stream to which to write. 
    514      * @param value the int value to be written. 
    515      * @param terminator a terminating character written after the value. 
    516      * @throws IOException if writing to the stream fails 
    517      */ 
    518     protected static void writeint(Writer writer, String prefix, int value) throws IOException 
    519     { 
    520         writer.write(prefix); 
    521         writer.write(String.valueOf(value)); 
    522         writer.write("|"); 
    523     } 
    524  
    525     /** 
    526      * writes a string to a stream in such a way that the string can be reliable read again. 
    527      * @param writer the stream to which to write. 
    528      * @param value the string value to be written (may be null). 
    529      * @param terminator a terminating character written after the string length. 
    530      * @throws IOException if writing to the stream fails 
    531      */ 
    532     protected static void writestr(Writer writer, String prefix, String value) throws IOException 
    533     { 
    534         writer.write(prefix); 
    535         if (value != null) 
    536         { 
    537             writer.write(String.valueOf(value.length())); 
    538             writer.write("|"); 
    539             writer.write(value); 
    540         } 
    541         writer.write("|"); 
    542     } 
    543  
    544     /** 
    545      * writes a register specification to a stream (which is either a digit or '-' in case the register spec is empty. 
    546      * @param writer the stream to which to write. 
    547      * @param spec the register number or -1 in case the register spec is empty. 
    548      * @throws IOException if writing to the stream fails 
    549      */ 
    550     protected static void writespec(Writer writer, int spec) throws IOException 
    551     { 
    552         if (spec != -1) 
    553             writer.write(String.valueOf(spec)); 
    554         writer.write("|"); 
    555     } 
    556  
    557     /** 
    558      * writes the Template object to a stream. 
    559      * @param writer the stream to which to write. 
    560      * @throws IOException if writing to the stream fails 
    561      */ 
    562     public void dump(Writer writer) throws IOException 
    563     { 
    564         writer.write(HEADER); 
    565         writer.write("\n"); 
    566         writer.write(VERSION); 
    567         writer.write("\n"); 
    568         writestr(writer, "SD", startdelim); 
    569         writer.write("\n"); 
    570         writestr(writer, "ED", enddelim); 
    571         writer.write("\n"); 
    572         writestr(writer, "SRC", source); 
    573         writer.write("\n"); 
    574         writeint(writer, "n", opcodes.size()); 
    575         writer.write("\n"); 
    576         Location lastLocation = null; 
    577         int size = opcodes.size(); 
    578         for (int i = 0; i < size; ++i) 
    579         { 
    580             Opcode opcode = opcodes.get(i); 
    581             writespec(writer, opcode.r1); 
    582             writespec(writer, opcode.r2); 
    583             writespec(writer, opcode.r3); 
    584             writespec(writer, opcode.r4); 
    585             writespec(writer, opcode.r5); 
    586             writestr(writer, "C", Opcode.code2name(opcode.name)); 
    587             writestr(writer, "A", opcode.arg); 
    588             if (opcode.location != lastLocation) 
    589             { 
    590                 writer.write("*|"); 
    591                 writestr(writer, "T", opcode.location.type); 
    592                 writeint(writer, "st", opcode.location.starttag); 
    593                 writeint(writer, "et", opcode.location.endtag); 
    594                 writeint(writer, "sc", opcode.location.startcode); 
    595                 writeint(writer, "ec", opcode.location.endcode); 
    596                 lastLocation = opcode.location; 
    597             } 
    598             else 
    599             { 
    600                 writer.write("^"); 
    601             } 
    602             writer.write("\n"); 
    603         } 
    604     } 
    605  
    606     /** 
    607      * writes the Template object to a string. 
    608      * @return The string containing the template in compiled format. 
    609      */ 
    610     public String dumps() 
    611     { 
    612         StringWriter writer = new StringWriter(); 
    613         try 
    614         { 
    615             dump(writer); 
    616         } 
    617         catch (IOException ex) // can not happen when dumping to a StringWriter 
    618         { 
    619         } 
    620         return writer.toString(); 
    621     } 
    622  
    623     /** 
    624      * Annotates all control flow opcodes in the template with a jump location. 
    625      * <ul> 
    626      * <li>(a <code>for</code> opcode gets annotated with the location of the 
    627      * associated <code>endfor</code> opcode;</li> 
    628      * <li>a <code>def</code> opcode gets annotated with the location of the 
    629      * associated <code>enddef</code> opcode;</li> 
    630      * <li>an <code>if</code> opcode gets annotated with the location of the 
    631      * associated <code>else</code> or <code>endif</code> opcode;</li> 
    632      * <li>an <code>else</code> opcode gets annotated with the location of 
    633      * <code>endif</code> opcode;</li> 
    634      * <li>a <code>break</code> opcode gets annotated with the location of next 
    635      * opcode after the associated <code>endfor</code> opcode.</li> 
    636      * <li>a <code>continue</code> opcode gets annotated with the location of next 
    637      * opcode after the associated ENDFOR opcode.</li> 
    638      * </ul> 
    639      */ 
    640     protected void annotate() 
    641     { 
    642         if (!annotated) 
    643         { 
    644             int size = opcodes.size(); 
    645             for (int i = 0; i < size; ++i) 
    646             { 
    647                 Opcode opcode = opcodes.get(i); 
    648                 switch (opcode.name) 
    649                 { 
    650                     case Opcode.OC_IF: 
    651                         i = annotateIf(i, 0); 
    652                         break; 
    653                     case Opcode.OC_FOR: 
    654                         i = annotateFor(i, 0); 
    655                         break; 
    656                     case Opcode.OC_DEF: 
    657                         i = annotateDef(i, 0); 
    658                         break; 
    659                     case Opcode.OC_ELSE: 
    660                         throw new BlockException("else outside if block"); 
    661                     case Opcode.OC_ENDIF: 
    662                         throw new BlockException("endif outside if block"); 
    663                     case Opcode.OC_ENDFOR: 
    664                         throw new BlockException("endfor outside for loop"); 
    665                     case Opcode.OC_BREAK: 
    666                         throw new BlockException("break outside for loop"); 
    667                     case Opcode.OC_CONTINUE: 
    668                         throw new BlockException("continue outside for loop"); 
    669                     case Opcode.OC_ENDDEF: 
    670                         throw new BlockException("enddef outside def block"); 
    671                 } 
    672             } 
    673             annotated = true; 
    674         } 
    675     } 
    676  
    677     protected int annotateIf(int ifStart, int forDepth) 
    678     { 
    679         int jump = ifStart; 
    680         int size = opcodes.size(); 
    681         for (int i = ifStart+1; i < size; ++i) 
    682         { 
    683             Opcode opcode = opcodes.get(i); 
    684             switch (opcode.name) 
    685             { 
    686                 case Opcode.OC_IF: 
    687                     i = annotateIf(i, forDepth); 
    688                     break; 
    689                 case Opcode.OC_FOR: 
    690                     i = annotateFor(i, forDepth); 
    691                     break; 
    692                 case Opcode.OC_DEF: 
    693                     i = annotateDef(i, forDepth); 
    694                     break; 
    695                 case Opcode.OC_ELSE: 
    696                     opcodes.get(jump).jump = i; 
    697                     jump = i; 
    698                     break; 
    699                 case Opcode.OC_ENDIF: 
    700                     opcodes.get(jump).jump = i; 
    701                     return i; 
    702                 case Opcode.OC_BREAK: 
    703                     if (forDepth == 0) 
    704                         throw new BlockException("break outside for loop"); 
    705                     break; 
    706                 case Opcode.OC_CONTINUE: 
    707                     if (forDepth == 0) 
    708                         throw new BlockException("continue outside for loop"); 
    709                     break; 
    710                 case Opcode.OC_ENDFOR: 
    711                     throw new BlockException("endfor in if block"); 
    712                 case Opcode.OC_ENDDEF: 
    713                     throw new BlockException("enddef in if block"); 
    714             } 
    715         } 
    716         throw new BlockException("unclosed if block"); 
    717     } 
    718  
    719     protected int annotateDef(int defStart, int forDepth) 
    720     { 
    721         int jump = defStart; 
    722         int size = opcodes.size(); 
    723         for (int i = defStart+1; i < size; ++i) 
    724         { 
    725             Opcode opcode = opcodes.get(i); 
    726             switch (opcode.name) 
    727             { 
    728                 case Opcode.OC_IF: 
    729                     i = annotateIf(i, forDepth); 
    730                     break; 
    731                 case Opcode.OC_FOR: 
    732                     i = annotateFor(i, forDepth); 
    733                     break; 
    734                 case Opcode.OC_DEF: 
    735                     i = annotateDef(i, forDepth); 
    736                     break; 
    737                 case Opcode.OC_ELSE: 
    738                     throw new BlockException("else in def"); 
    739                 case Opcode.OC_ENDIF: 
    740                     throw new BlockException("endif in def"); 
    741                 case Opcode.OC_BREAK: 
    742                     throw new BlockException("break in def"); 
    743                 case Opcode.OC_CONTINUE: 
    744                     throw new BlockException("continue in def"); 
    745                 case Opcode.OC_ENDFOR: 
    746                     throw new BlockException("endfor in def"); 
    747                 case Opcode.OC_ENDDEF: 
    748                     opcodes.get(defStart).jump = i; 
    749                     return i; 
    750             } 
    751         } 
    752         throw new BlockException("unclosed def block"); 
    753     } 
    754  
    755     protected int annotateFor(int loopStart, int forDepth) 
    756     { 
    757         ++forDepth; 
    758         LinkedList<Integer> breaks = new LinkedList<Integer>(); 
    759         LinkedList<Integer> continues = new LinkedList<Integer>(); 
    760  
    761         int size = opcodes.size(); 
    762         for (int i = loopStart+1; i < size; ++i) 
    763         { 
    764             Opcode opcode = opcodes.get(i); 
    765             switch (opcode.name) 
    766             { 
    767                 case Opcode.OC_IF: 
    768                     i = annotateIf(i, forDepth); 
    769                     break; 
    770                 case Opcode.OC_FOR: 
    771                     i = annotateFor(i, forDepth); 
    772                     break; 
    773                 case Opcode.OC_DEF: 
    774                     i = annotateDef(i, forDepth); 
    775                     break; 
    776                 case Opcode.OC_ELSE: 
    777                     throw new BlockException("else in for loop"); 
    778                 case Opcode.OC_ENDIF: 
    779                     throw new BlockException("endif in for loop"); 
    780                 case Opcode.OC_BREAK: 
    781                     breaks.add(i); 
    782                     break; 
    783                 case Opcode.OC_CONTINUE: 
    784                     continues.add(i); 
    785                     break; 
    786                 case Opcode.OC_ENDFOR: 
    787                     int j; 
    788                     int jump; 
    789                     for (j = 0; j < breaks.size(); ++j) 
    790                     { 
    791                         jump = breaks.get(j); 
    792                         opcodes.get(jump).jump = i; 
    793                     } 
    794                     for (j = 0; j < continues.size(); ++j) 
    795                     { 
    796                         jump = continues.get(j); 
    797                         opcodes.get(jump).jump = i; 
    798                     } 
    799                     opcodes.get(loopStart).jump = i; 
    800                     return i; 
    801                 case Opcode.OC_ENDDEF: 
    802                     throw new BlockException("enddef in for loop"); 
    803             } 
    804         } 
    805         throw new BlockException("unclosed loop"); 
    806     } 
    807  
    808     /** 
    809      * Renders the template. 
    810      * @param variables a map containing the top level variables that should be 
    811      *                  available to the template code. 
    812      * @return An iterator that returns the string output piece by piece. 
    813      */ 
    814     public Iterator<String> render(Map<String, Object> variables) 
    815     { 
    816         return new Renderer(variables); 
    817     } 
    818  
    819     /** 
    820      * Renders the template. 
    821      * @param variables a map containing the top level variables that should be 
    822      *                  available to the template code. 
    823      * @return A java.io.Reader object from which the template output can be read. 
    824      */ 
    825     public Reader reader(Map<String, Object> variables) 
    826     { 
    827         return new IteratorReader(new Renderer(variables)); 
    828     } 
    829  
    830     /** 
    831      * Renders the template to a java.io.Writer object. 
    832      * @param writer    the java.io.Writer object to which the output is written. 
    833      * @param variables a map containing the top level variables that should be 
    834      *                  available to the template code. 
    835      */ 
    836     public void render(java.io.Writer writer, Map<String, Object> variables) throws java.io.IOException 
    837     { 
    838         for (Iterator<String> iterator = render(variables); iterator.hasNext();) 
    839         { 
    840             writer.write(iterator.next()); 
    841         } 
    842     } 
    843  
    844     /** 
    845      * Renders the template and returns the resulting string. 
    846      * @param variables a map containing the top level variables that should be 
    847      *                  available to the template code. 
    848      * @return The render output as a string. 
    849      */ 
    850     public String renders(Map<String, Object> variables) 
    851     { 
    852         StringBuffer output = new StringBuffer(); 
    853  
    854         for (Iterator<String> iterator = render(variables); iterator.hasNext();) 
    855         { 
    856             output.append(iterator.next()); 
    857         } 
    858         return output.toString(); 
    859     } 
    860  
    861     class Renderer implements Iterator<String> 
    862     { 
    863         /** 
    864          * The current program counter 
    865          */ 
    866         private int pc = 0; 
    867  
    868         /** 
    869          * The ten registers of our CPU 
    870          */ 
    871         private Object[] reg = new Object[10]; 
    872  
    873         /** 
    874          * The variables passed to the {@com.livinglogic.ul4.InterpretedTemplate#render} call 
    875          * During the run of the iterator loop variables and variables from 
    876          * <code>&lt;?code>&gt;</code> tag will be stored here 
    877          */ 
    878         private Map<String, Object> variables; 
    879  
    880         /** 
    881          * The stack of active for loops 
    882          */ 
    883         private LinkedList<IteratorStackEntry> iterators = new LinkedList<IteratorStackEntry>(); 
    884  
    885         /** 
    886          * If a subtemplate is running (i.e. if we're inside a 
    887          * <code>&lt;?render?&gt;</code> tag), this variable references the 
    888          * active part iterator for the subtemplate. 
    889          */ 
    890         private Iterator<String> subTemplateIterator = null; 
    891  
    892         /** 
    893          * Since we implement the iterator interface we have to support both 
    894          * <code>next</code> and <code>hasNext</code>. This means that neither 
    895          * of the two methods can directly execute the opcodes to get the next 
    896          * output chunk. Instead of that we have a method {@link getNextChunk} 
    897          * that executes the opcodes until the next output chunk is produced and 
    898          * stores it in <code>nextChunk</code>, where both <code>next</code> and 
    899          * <code>hasNext</code> can refer to it. 
    900          */ 
    901         private String nextChunk = null; 
    902  
    903         public Renderer(Map<String, Object> variables) 
    904         { 
    905             annotate(); 
    906             if (variables == null) 
    907                 variables = new HashMap<String, Object>(); 
    908             this.variables = variables; 
    909             getNextChunk(); 
    910         } 
    911  
    912         public void remove() 
    913         { 
    914             throw new UnsupportedOperationException("remove() not supported for " + getClass() + "!"); 
    915         } 
    916  
    917         public boolean hasNext() 
    918         { 
    919             return nextChunk != null; 
    920         } 
    921  
    922         public String next() 
    923         { 
    924             String result = nextChunk; 
    925             getNextChunk(); 
    926             return result; 
    927         } 
    928  
    929         /** 
    930          * Gets the next output chunk and stores it in {@link nextChunk} 
    931          */ 
    932         private void getNextChunk() 
    933         { 
    934             if (subTemplateIterator != null) 
    935             { 
    936                 if (subTemplateIterator.hasNext()) 
    937                 { 
    938                     nextChunk = subTemplateIterator.next(); 
    939                     return; 
    940                 } 
    941                 else 
    942                 { 
    943                     subTemplateIterator = null; 
    944                 } 
    945             } 
    946             int opcodecount = opcodes.size(); 
    947             while (pc < opcodecount) 
    948             { 
    949                 Opcode code = opcodes.get(pc); 
    950  
    951                 try 
    952                 { 
    953                     switch (code.name) 
    954                     { 
    955                         case Opcode.OC_TEXT: 
    956                             nextChunk = code.location.getCode(); 
    957                             ++pc; 
    958                             return; 
    959                         case Opcode.OC_PRINT: 
    960                             nextChunk = ObjectUtils.toString(reg[code.r1]); 
    961                             ++pc; 
    962                             return; 
    963                         case Opcode.OC_PRINTX: 
    964                             nextChunk = Utils.xmlescape(ObjectUtils.toString(reg[code.r1])); 
    965                             ++pc; 
    966                             return; 
    967                         case Opcode.OC_LOADNONE: 
    968                             reg[code.r1] = null; 
    969                             break; 
    970                         case Opcode.OC_LOADFALSE: 
    971                             reg[code.r1] = Boolean.FALSE; 
    972                             break; 
    973                         case Opcode.OC_LOADTRUE: 
    974                             reg[code.r1] = Boolean.TRUE; 
    975                             break; 
    976                         case Opcode.OC_LOADSTR: 
    977                             reg[code.r1] = code.arg; 
    978                             break; 
    979                         case Opcode.OC_LOADINT: 
    980                             reg[code.r1] = Integer.parseInt(code.arg); 
    981                             break; 
    982                         case Opcode.OC_LOADFLOAT: 
    983                             reg[code.r1] = Double.parseDouble(code.arg); 
    984                             break; 
    985                         case Opcode.OC_LOADDATE: 
    986                             reg[code.r1] = Utils.isoparse(code.arg); 
    987                             break; 
    988                         case Opcode.OC_LOADCOLOR: 
    989                             reg[code.r1] = Color.fromdump(code.arg); 
    990                             break; 
    991                         case Opcode.OC_BUILDLIST: 
    992                             reg[code.r1] = new ArrayList(); 
    993                             break; 
    994                         case Opcode.OC_BUILDDICT: 
    995                             reg[code.r1] = new HashMap(); 
    996                             break; 
    997                         case Opcode.OC_ADDLIST: 
    998                             ((List)reg[code.r1]).add(reg[code.r2]); 
    999                             break; 
    1000                         case Opcode.OC_ADDDICT: 
    1001                             ((Map)reg[code.r1]).put(reg[code.r2], reg[code.r3]); 
    1002                             break; 
    1003                         case Opcode.OC_UPDATEDICT: 
    1004                             ((Map)reg[code.r1]).putAll((Map)reg[code.r2]); 
    1005                             break; 
    1006                         case Opcode.OC_LOADVAR: 
    1007                             reg[code.r1] = variables.get(code.arg); 
    1008                             break; 
    1009                         case Opcode.OC_STOREVAR: 
    1010                             variables.put(code.arg, reg[code.r1]); 
    1011                             break; 
    1012                         case Opcode.OC_ADDVAR: 
    1013                             variables.put(code.arg, Utils.add(variables.get(code.arg), reg[code.r1])); 
    1014                             break; 
    1015                         case Opcode.OC_SUBVAR: 
    1016                             variables.put(code.arg, Utils.sub(variables.get(code.arg), reg[code.r1])); 
    1017                             break; 
    1018                         case Opcode.OC_MULVAR: 
    1019                             variables.put(code.arg, Utils.mul(variables.get(code.arg), reg[code.r1])); 
    1020                             break; 
    1021                         case Opcode.OC_TRUEDIVVAR: 
    1022                             variables.put(code.arg, Utils.truediv(variables.get(code.arg), reg[code.r1])); 
    1023                             break; 
    1024                         case Opcode.OC_FLOORDIVVAR: 
    1025                             variables.put(code.arg, Utils.floordiv(variables.get(code.arg), reg[code.r1])); 
    1026                             break; 
    1027                         case Opcode.OC_MODVAR: 
    1028                             variables.put(code.arg, Utils.mod(variables.get(code.arg), reg[code.r1])); 
    1029                             break; 
    1030                         case Opcode.OC_DELVAR: 
    1031                             variables.remove(code.arg); 
    1032                             break; 
    1033                         case Opcode.OC_FOR: 
    1034                             Iterator iterator = Utils.iterator(reg[code.r2]); 
    1035                             if (iterator.hasNext()) 
    1036                             { 
    1037                                 reg[code.r1] = iterator.next(); 
    1038                                 iterators.add(new IteratorStackEntry(code.r1, pc, code.jump, iterator)); 
    1039                             } 
    1040                             else 
    1041                             { 
    1042                                 pc = code.jump+1; 
    1043                                 continue; 
    1044                             } 
    1045                             break; 
    1046                         case Opcode.OC_BREAK: 
    1047                         { 
    1048                             IteratorStackEntry entry = iterators.getLast(); 
    1049                             pc = entry.pcEndFor; 
    1050                             iterators.removeLast(); 
    1051                             break; 
    1052                         } 
    1053                         case Opcode.OC_CONTINUE: 
    1054                         { 
    1055                             IteratorStackEntry entry = iterators.getLast(); 
    1056                             pc = entry.pcEndFor; 
    1057                             // Fall through 
    1058                         } 
    1059                         case Opcode.OC_ENDFOR: 
    1060                         { 
    1061                             IteratorStackEntry entry = iterators.getLast(); 
    1062                             if (entry.iterator.hasNext()) 
    1063                             { 
    1064                                 reg[entry.iteratorRegSpec] = entry.iterator.next(); 
    1065                                 pc = entry.pcFor; 
    1066                             } 
    1067                             else 
    1068                             { 
    1069                                 iterators.removeLast(); 
    1070                             } 
    1071                             break; 
    1072                         } 
    1073                         case Opcode.OC_IF: 
    1074                             if (!Utils.getBool(reg[code.r1])) 
    1075                             { 
    1076                                 pc = code.jump+1; 
    1077                                 continue; 
    1078                             } 
    1079                             break; 
    1080                         case Opcode.OC_ELSE: 
    1081                             pc = code.jump+1; 
    1082                             continue; 
    1083                         case Opcode.OC_ENDIF: 
    1084                             // Skip to next opcode 
    1085                             break; 
    1086                         case Opcode.OC_GETATTR: 
    1087                             reg[code.r1] = Utils.getItem(reg[code.r2], code.arg); 
    1088                             break; 
    1089                         case Opcode.OC_GETITEM: 
    1090                             reg[code.r1] = Utils.getItem(reg[code.r2], reg[code.r3]); 
    1091                             break; 
    1092                         case Opcode.OC_GETSLICE12: 
    1093                             reg[code.r1] = Utils.getSlice(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1094                             break; 
    1095                         case Opcode.OC_GETSLICE1: 
    1096                             reg[code.r1] = Utils.getSlice(reg[code.r2], reg[code.r3], null); 
    1097                             break; 
    1098                         case Opcode.OC_GETSLICE2: 
    1099                             reg[code.r1] = Utils.getSlice(reg[code.r2], null, reg[code.r3]); 
    1100                             break; 
    1101                         case Opcode.OC_NOT: 
    1102                             reg[code.r1] = Utils.getBool(reg[code.r2]) ? Boolean.FALSE : Boolean.TRUE; 
    1103                             break; 
    1104                         case Opcode.OC_NEG: 
    1105                             reg[code.r1] = Utils.neg(reg[code.r2]); 
    1106                             break; 
    1107                         case Opcode.OC_EQ: 
    1108                             reg[code.r1] = ObjectUtils.equals(reg[code.r2], reg[code.r3]) ? Boolean.TRUE : Boolean.FALSE; 
    1109                             break; 
    1110                         case Opcode.OC_NE: 
    1111                             reg[code.r1] = ObjectUtils.equals(reg[code.r2], reg[code.r3]) ? Boolean.FALSE : Boolean.TRUE; 
    1112                             break; 
    1113                         case Opcode.OC_LT: 
    1114                             reg[code.r1] = Utils.lt(reg[code.r2], reg[code.r3]) ? Boolean.TRUE : Boolean.FALSE; 
    1115                             break; 
    1116                         case Opcode.OC_LE: 
    1117                             reg[code.r1] = Utils.le(reg[code.r2], reg[code.r3]) ? Boolean.TRUE : Boolean.FALSE; 
    1118                             break; 
    1119                         case Opcode.OC_GT: 
    1120                             reg[code.r1] = Utils.le(reg[code.r2], reg[code.r3]) ? Boolean.FALSE : Boolean.TRUE; 
    1121                             break; 
    1122                         case Opcode.OC_GE: 
    1123                             reg[code.r1] = Utils.lt(reg[code.r2], reg[code.r3]) ? Boolean.FALSE : Boolean.TRUE; 
    1124                             break; 
    1125                         case Opcode.OC_CONTAINS: 
    1126                             reg[code.r1] = Utils.contains(reg[code.r2], reg[code.r3]); 
    1127                             break; 
    1128                         case Opcode.OC_NOTCONTAINS: 
    1129                             reg[code.r1] = !Utils.contains(reg[code.r2], reg[code.r3]); 
    1130                             break; 
    1131                         case Opcode.OC_OR: 
    1132                             reg[code.r1] = Utils.getBool(reg[code.r2]) ? reg[code.r2] : reg[code.r3]; 
    1133                             break; 
    1134                         case Opcode.OC_AND: 
    1135                             reg[code.r1] = Utils.getBool(reg[code.r3]) ? reg[code.r2] : reg[code.r3]; 
    1136                             break; 
    1137                         case Opcode.OC_ADD: 
    1138                             reg[code.r1] = Utils.add(reg[code.r2], reg[code.r3]); 
    1139                             break; 
    1140                         case Opcode.OC_SUB: 
    1141                             reg[code.r1] = Utils.sub(reg[code.r2], reg[code.r3]); 
    1142                             break; 
    1143                         case Opcode.OC_MUL: 
    1144                             reg[code.r1] = Utils.mul(reg[code.r2], reg[code.r3]); 
    1145                             break; 
    1146                         case Opcode.OC_TRUEDIV: 
    1147                             reg[code.r1] = Utils.truediv(reg[code.r2], reg[code.r3]); 
    1148                             break; 
    1149                         case Opcode.OC_FLOORDIV: 
    1150                             reg[code.r1] = Utils.floordiv(reg[code.r2], reg[code.r3]); 
    1151                             break; 
    1152                         case Opcode.OC_MOD: 
    1153                             reg[code.r1] = Utils.mod(reg[code.r2], reg[code.r3]); 
    1154                             break; 
    1155                         case Opcode.OC_CALLFUNC0: 
    1156                             switch (code.argcode) 
    1157                             { 
    1158                                 case Opcode.CF0_NOW: 
    1159                                     reg[code.r1] = new Date(); 
    1160                                     break; 
    1161                                 case Opcode.CF0_UTCNOW: 
    1162                                     reg[code.r1] = Utils.utcnow(); 
    1163                                     break; 
    1164                                 case Opcode.CF0_VARS: 
    1165                                     reg[code.r1] = variables; 
    1166                                     break; 
    1167                                 case Opcode.CF0_RANDOM: 
    1168                                     reg[code.r1] = Utils.random(); 
    1169                                     break; 
    1170                             } 
    1171                             break; 
    1172                         case Opcode.OC_CALLFUNC1: 
    1173                             switch (code.argcode) 
    1174                             { 
    1175                                 case Opcode.CF1_XMLESCAPE: 
    1176                                     reg[code.r1] = Utils.xmlescape(reg[code.r2]); 
    1177                                     break; 
    1178                                 case Opcode.CF1_CSV: 
    1179                                     reg[code.r1] = Utils.csv(reg[code.r2]); 
    1180                                     break; 
    1181                                 case Opcode.CF1_STR: 
    1182                                     reg[code.r1] = ObjectUtils.toString(reg[code.r2]); 
    1183                                     break; 
    1184                                 case Opcode.CF1_REPR: 
    1185                                     reg[code.r1] = Utils.repr(reg[code.r2]); 
    1186                                     break; 
    1187                                 case Opcode.CF1_INT: 
    1188                                     reg[code.r1] = Utils.toInteger(reg[code.r2]); 
    1189                                     break; 
    1190                                 case Opcode.CF1_FLOAT: 
    1191                                     reg[code.r1] = Utils.toFloat(reg[code.r2]); 
    1192                                     break; 
    1193                                 case Opcode.CF1_BOOL: 
    1194                                     reg[code.r1] = Utils.getBool(reg[code.r2]) ? Boolean.TRUE : Boolean.FALSE; 
    1195                                     break; 
    1196                                 case Opcode.CF1_LEN: 
    1197                                     reg[code.r1] = Utils.length(reg[code.r2]); 
    1198                                     break; 
    1199                                 case Opcode.CF1_ENUMERATE: 
    1200                                     reg[code.r1] = Utils.enumerate(reg[code.r2]); 
    1201                                     break; 
    1202                                 case Opcode.CF1_ISNONE: 
    1203                                     reg[code.r1] = (null == reg[code.r2]) ? Boolean.TRUE : Boolean.FALSE; 
    1204                                     break; 
    1205                                 case Opcode.CF1_ISSTR: 
    1206                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof String)) ? Boolean.TRUE : Boolean.FALSE; 
    1207                                     break; 
    1208                                 case Opcode.CF1_ISINT: 
    1209                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Integer)) ? Boolean.TRUE : Boolean.FALSE; 
    1210                                     break; 
    1211                                 case Opcode.CF1_ISFLOAT: 
    1212                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Double)) ? Boolean.TRUE : Boolean.FALSE; 
    1213                                     break; 
    1214                                 case Opcode.CF1_ISBOOL: 
    1215                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Boolean)) ? Boolean.TRUE : Boolean.FALSE; 
    1216                                     break; 
    1217                                 case Opcode.CF1_ISDATE: 
    1218                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Date)) ? Boolean.TRUE : Boolean.FALSE; 
    1219                                     break; 
    1220                                 case Opcode.CF1_ISLIST: 
    1221                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof List)) ? Boolean.TRUE : Boolean.FALSE; 
    1222                                     break; 
    1223                                 case Opcode.CF1_ISDICT: 
    1224                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Map)) ? Boolean.TRUE : Boolean.FALSE; 
    1225                                     break; 
    1226                                 case Opcode.CF1_ISTEMPLATE: 
    1227                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Template)) ? Boolean.TRUE : Boolean.FALSE; 
    1228                                     break; 
    1229                                 case Opcode.CF1_ISCOLOR: 
    1230                                     reg[code.r1] = ((null != reg[code.r2]) && (reg[code.r2] instanceof Color)) ? Boolean.TRUE : Boolean.FALSE; 
    1231                                     break; 
    1232                                 case Opcode.CF1_CHR: 
    1233                                     reg[code.r1] = Utils.chr(reg[code.r2]); 
    1234                                     break; 
    1235                                 case Opcode.CF1_ORD: 
    1236                                     reg[code.r1] = Utils.ord(reg[code.r2]); 
    1237                                     break; 
    1238                                 case Opcode.CF1_HEX: 
    1239                                     reg[code.r1] = Utils.hex(reg[code.r2]); 
    1240                                     break; 
    1241                                 case Opcode.CF1_OCT: 
    1242                                     reg[code.r1] = Utils.oct(reg[code.r2]); 
    1243                                     break; 
    1244                                 case Opcode.CF1_BIN: 
    1245                                     reg[code.r1] = Utils.bin(reg[code.r2]); 
    1246                                     break; 
    1247                                 case Opcode.CF1_ABS: 
    1248                                     reg[code.r1] = Utils.abs(reg[code.r2]); 
    1249                                     break; 
    1250                                 case Opcode.CF1_SORTED: 
    1251                                     reg[code.r1] = Utils.sorted(reg[code.r2]); 
    1252                                     break; 
    1253                                 case Opcode.CF1_RANGE: 
    1254                                     reg[code.r1] = Utils.range(reg[code.r2]); 
    1255                                     break; 
    1256                                 case Opcode.CF1_TYPE: 
    1257                                     reg[code.r1] = Utils.type(reg[code.r2]); 
    1258                                     break; 
    1259                                 case Opcode.CF1_GET: 
    1260                                     reg[code.r1] = variables.get(reg[code.r2]); 
    1261                                     break; 
    1262                                 case Opcode.CF1_JSON: 
    1263                                     reg[code.r1] = Utils.json(reg[code.r2]); 
    1264                                     break; 
    1265                                 case Opcode.CF1_REVERSED: 
    1266                                     reg[code.r1] = Utils.reversed(reg[code.r2]); 
    1267                                     break; 
    1268                                 case Opcode.CF1_RANDRANGE: 
    1269                                     reg[code.r1] = Utils.randrange(reg[code.r2]); 
    1270                                     break; 
    1271                                 case Opcode.CF1_RANDCHOICE: 
    1272                                     reg[code.r1] = Utils.randchoice(reg[code.r2]); 
    1273                                     break; 
    1274                             } 
    1275                             break; 
    1276                         case Opcode.OC_CALLFUNC2: 
    1277                             switch (code.argcode) 
    1278                             { 
    1279                                 case Opcode.CF2_RANGE: 
    1280                                     reg[code.r1] = Utils.range(reg[code.r2], reg[code.r3]); 
    1281                                     break; 
    1282                                 case Opcode.CF2_GET: 
    1283                                     reg[code.r1] = variables.containsKey(reg[code.r2]) ? variables.get(reg[code.r2]) : reg[code.r3]; 
    1284                                     break; 
    1285                                 case Opcode.CF2_ZIP: 
    1286                                     reg[code.r1] = Utils.zip(reg[code.r2], reg[code.r3]); 
    1287                                     break; 
    1288                                 case Opcode.CF2_INT: 
    1289                                     reg[code.r1] = Utils.toInteger(reg[code.r2], reg[code.r3]); 
    1290                                     break; 
    1291                                 case Opcode.CF2_RANDRANGE: 
    1292                                     reg[code.r1] = Utils.randrange(reg[code.r2], reg[code.r3]); 
    1293                                     break; 
    1294                             } 
    1295                             break; 
    1296                         case Opcode.OC_CALLFUNC3: 
    1297                             switch (code.argcode) 
    1298                             { 
    1299                                 case Opcode.CF3_RANGE: 
    1300                                     reg[code.r1] = Utils.range(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1301                                     break; 
    1302                                 case Opcode.CF3_ZIP: 
    1303                                     reg[code.r1] = Utils.zip(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1304                                     break; 
    1305                                 case Opcode.CF3_RGB: 
    1306                                     reg[code.r1] = Utils.rgb(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1307                                     break; 
    1308                                 case Opcode.CF3_HLS: 
    1309                                     reg[code.r1] = Utils.hls(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1310                                     break; 
    1311                                 case Opcode.CF3_HSV: 
    1312                                     reg[code.r1] = Utils.hsv(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1313                                     break; 
    1314                                 case Opcode.CF3_RANDRANGE: 
    1315                                     reg[code.r1] = Utils.randrange(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1316                                     break; 
    1317                             } 
    1318                             break; 
    1319                         case Opcode.OC_CALLFUNC4: 
    1320                             switch (code.argcode) 
    1321                             { 
    1322                                 case Opcode.CF4_RGB: 
    1323                                     reg[code.r1] = Utils.rgb(reg[code.r2], reg[code.r3], reg[code.r4], reg[code.r5]); 
    1324                                     break; 
    1325                                 case Opcode.CF4_HLS: 
    1326                                     reg[code.r1] = Utils.hls(reg[code.r2], reg[code.r3], reg[code.r4], reg[code.r5]); 
    1327                                     break; 
    1328                                 case Opcode.CF4_HSV: 
    1329                                     reg[code.r1] = Utils.hsv(reg[code.r2], reg[code.r3], reg[code.r4], reg[code.r5]); 
    1330                                     break; 
    1331                             } 
    1332                             break; 
    1333                         case Opcode.OC_CALLMETH0: 
    1334                             switch (code.argcode) 
    1335                             { 
    1336                                 case Opcode.CM0_SPLIT: 
    1337                                     reg[code.r1] = Utils.split(reg[code.r2]); 
    1338                                     break; 
    1339                                 case Opcode.CM0_STRIP: 
    1340                                     reg[code.r1] = Utils.strip(reg[code.r2]); 
    1341                                     break; 
    1342                                 case Opcode.CM0_LSTRIP: 
    1343                                     reg[code.r1] = Utils.lstrip(reg[code.r2]); 
    1344                                     break; 
    1345                                 case Opcode.CM0_RSTRIP: 
    1346                                     reg[code.r1] = Utils.rstrip(reg[code.r2]); 
    1347                                     break; 
    1348                                 case Opcode.CM0_UPPER: 
    1349                                     reg[code.r1] = Utils.upper(reg[code.r2]); 
    1350                                     break; 
    1351                                 case Opcode.CM0_LOWER: 
    1352                                     reg[code.r1] = Utils.lower(reg[code.r2]); 
    1353                                     break; 
    1354                                 case Opcode.CM0_CAPITALIZE: 
    1355                                     reg[code.r1] = Utils.capitalize(reg[code.r2]); 
    1356                                     break; 
    1357                                 case Opcode.CM0_ITEMS: 
    1358                                     reg[code.r1] = Utils.items(reg[code.r2]); 
    1359                                     break; 
    1360                                 case Opcode.CM0_ISOFORMAT: 
    1361                                     reg[code.r1] = Utils.isoformat(reg[code.r2]); 
    1362                                     break; 
    1363                                 case Opcode.CM0_MIMEFORMAT: 
    1364                                     reg[code.r1] = Utils.mimeformat(reg[code.r2]); 
    1365                                     break; 
    1366                                 case Opcode.CM0_R: 
    1367                                     reg[code.r1] = ((Color)reg[code.r2]).getR(); 
    1368                                     break; 
    1369                                 case Opcode.CM0_G: 
    1370                                     reg[code.r1] = ((Color)reg[code.r2]).getG(); 
    1371                                     break; 
    1372                                 case Opcode.CM0_B: 
    1373                                     reg[code.r1] = ((Color)reg[code.r2]).getB(); 
    1374                                     break; 
    1375                                 case Opcode.CM0_A: 
    1376                                     reg[code.r1] = ((Color)reg[code.r2]).getA(); 
    1377                                     break; 
    1378                                 case Opcode.CM0_HLS: 
    1379                                     reg[code.r1] = ((Color)reg[code.r2]).hls(); 
    1380                                     break; 
    1381                                 case Opcode.CM0_HLSA: 
    1382                                     reg[code.r1] = ((Color)reg[code.r2]).hlsa(); 
    1383                                     break; 
    1384                                 case Opcode.CM0_HSV: 
    1385                                     reg[code.r1] = ((Color)reg[code.r2]).hsv(); 
    1386                                     break; 
    1387                                 case Opcode.CM0_HSVA: 
    1388                                     reg[code.r1] = ((Color)reg[code.r2]).hsva(); 
    1389                                     break; 
    1390                                 case Opcode.CM0_LUM: 
    1391                                     reg[code.r1] = new Double(((Color)reg[code.r2]).lum()); 
    1392                                     break; 
    1393                                 case Opcode.CM0_DAY: 
    1394                                     reg[code.r1] = Utils.day(reg[code.r2]); 
    1395                                     break; 
    1396                                 case Opcode.CM0_MONTH: 
    1397                                     reg[code.r1] = Utils.month(reg[code.r2]); 
    1398                                     break; 
    1399                                 case Opcode.CM0_YEAR: 
    1400                                     reg[code.r1] = Utils.year(reg[code.r2]); 
    1401                                     break; 
    1402                                 case Opcode.CM0_HOUR: 
    1403                                     reg[code.r1] = Utils.hour(reg[code.r2]); 
    1404                                     break; 
    1405                                 case Opcode.CM0_MINUTE: 
    1406                                     reg[code.r1] = Utils.minute(reg[code.r2]); 
    1407                                     break; 
    1408                                 case Opcode.CM0_SECOND: 
    1409                                     reg[code.r1] = Utils.second(reg[code.r2]); 
    1410                                     break; 
    1411                                 case Opcode.CM0_MICROSECOND: 
    1412                                     reg[code.r1] = Utils.microsecond(reg[code.r2]); 
    1413                                     break; 
    1414                                 case Opcode.CM0_WEEKDAY: 
    1415                                     reg[code.r1] = Utils.weekday(reg[code.r2]); 
    1416                                     break; 
    1417                                 case Opcode.CM0_YEARDAY: 
    1418                                     reg[code.r1] = Utils.yearday(reg[code.r2]); 
    1419                                     break; 
    1420                             } 
    1421                             break; 
    1422                         case Opcode.OC_CALLMETH1: 
    1423                             switch (code.argcode) 
    1424                             { 
    1425                                 case Opcode.CM1_SPLIT: 
    1426                                     reg[code.r1] = Utils.split(reg[code.r2], reg[code.r3]); 
    1427                                     break; 
    1428 /*                              case Opcode.CM1_RSPLIT: 
    1429                                     reg[code.r1] = Utils.rsplit(reg[code.r2], reg[code.r3]); 
    1430                                     break; 
    1431                                 case Opcode.CM1_STRIP: 
    1432                                     reg[code.r1] = Utils.strip(reg[code.r2], reg[code.r3]); 
    1433                                     break; 
    1434                                 case Opcode.CM1_LSTRIP: 
    1435                                     reg[code.r1] = Utils.lstrip(reg[code.r2], reg[code.r3]); 
    1436                                     break; 
    1437                                 case Opcode.CM1_RSTRIP: 
    1438                                     reg[code.r1] = Utils.rstrip(reg[code.r2], reg[code.r3]); 
    1439                                     break; 
    1440                                 case Opcode.CM1_STARTSWITH: 
    1441                                     reg[code.r1] = Utils.startswith(reg[code.r2], reg[code.r3]); 
    1442                                     break; 
    1443                                 case Opcode.CM1_ENDSWITH: 
    1444                                     reg[code.r1] = Utils.endswith(reg[code.r2], reg[code.r3]); 
    1445                                     break;*/ 
    1446                                 case Opcode.CM1_FIND: 
    1447                                     reg[code.r1] = Utils.find(reg[code.r2], reg[code.r3]); 
    1448                                     break; 
    1449                                 case Opcode.CM1_RFIND: 
    1450                                     reg[code.r1] = Utils.rfind(reg[code.r2], reg[code.r3]); 
    1451                                     break; 
    1452                                 case Opcode.CM1_FORMAT: 
    1453                                     reg[code.r1] = Utils.format(reg[code.r2], reg[code.r3], defaultLocale); 
    1454                                     break; 
    1455                                 case Opcode.CM1_GET: 
    1456                                     reg[code.r1] = ((Map)reg[code.r2]).get(reg[code.r3]); 
    1457                                     break; 
    1458                                 case Opcode.CM1_WITHLUM: 
    1459                                     reg[code.r1] = Utils.withlum(reg[code.r2], reg[code.r3]); 
    1460                                     break; 
    1461                                 case Opcode.CM1_WITHA: 
    1462                                     reg[code.r1] = Utils.witha(reg[code.r2], reg[code.r3]); 
    1463                                     break; 
    1464                                 case Opcode.CM1_JOIN: 
    1465                                     reg[code.r1] = Utils.join(reg[code.r2], reg[code.r3]); 
    1466                                     break; 
    1467                             } 
    1468                             break; 
    1469                         case Opcode.OC_CALLMETH2: 
    1470                             switch (code.argcode) 
    1471                             { 
    1472                                 case Opcode.CM2_REPLACE: 
    1473                                     reg[code.r1] = Utils.replace(reg[code.r2], reg[code.r3], reg[code.r4]); 
    1474                                     break; 
    1475                                 case Opcode.CM2_GET: 
    1476                                     reg[code.r1] = ((Map)reg[code.r2]).containsKey(reg[code.r3]) ? ((Map)reg[code.r2]).get(reg[code.r3]) : reg[code.r4]; 
    1477                                     break; 
    1478                             } 
    1479                             break; 
    1480                         case Opcode.OC_CALLMETH3: 
    1481                             throw new UnknownMethodException(code.arg); 
    1482                         case Opcode.OC_CALLMETHKW: 
    1483                             switch (code.argcode) 
    1484                             { 
    1485                                 case Opcode.CMKW_RENDER: 
    1486                                     reg[code.r1] = ((Template)reg[code.r2]).renders((Map)reg[code.r3]); 
    1487                                     break; 
    1488                                 default: 
    1489                                     throw new UnknownMethodException(code.arg); 
    1490                             } 
    1491                             break; 
    1492                         case Opcode.OC_RENDER: 
    1493                             if (reg[code.r1] instanceof InterpretedTemplate) 
    1494                             { 
    1495                                 subTemplateIterator = ((InterpretedTemplate)reg[code.r1]).render((Map)reg[code.r2]); 
    1496                                 if (subTemplateIterator.hasNext()) 
    1497                                 { 
    1498                                     nextChunk = (String)subTemplateIterator.next(); 
    1499                                     ++pc; 
    1500                                     return; 
    1501                                 } 
    1502                                 else 
    1503                                 { 
    1504                                     subTemplateIterator = null; 
    1505                                 } 
    1506                                 break; 
    1507                             } 
    1508                             else 
    1509                                 nextChunk = ((Template)reg[code.r1]).renders((Map)reg[code.r2]); 
    1510                         case Opcode.OC_DEF: 
    1511                             variables.put(code.arg, new InterpretedTemplate(source.substring(code.location.endtag, opcodes.get(code.jump).location.starttag), opcodes, startdelim, enddelim, pc+1, code.jump)); 
    1512                             pc = code.jump+1; 
    1513                             continue; 
    1514                         case Opcode.OC_ENDDEF: 
    1515                             // Skip to next opcode 
    1516                             break; 
    1517                         default: 
    1518                             throw new RuntimeException("Unknown opcode '" + code.name + "'!"); 
    1519                     } 
    1520                 } 
    1521                 catch (Exception ex) 
    1522                 { 
    1523                     throw new LocationException(ex, code.location); 
    1524                 } 
    1525                 ++pc; 
    1526             } 
    1527             // finished => no next chunk available 
    1528             nextChunk = null; 
    1529         } 
    1530     } 
    1531  
    1532     class IteratorReader extends Reader 
    1533     { 
    1534         private Iterator<String> iterator; 
    1535         private StringBuffer buffered; 
    1536  
    1537         public IteratorReader(Iterator<String> iterator) 
    1538         { 
    1539             this.iterator = iterator; 
    1540             this.buffered = new StringBuffer(); 
    1541         } 
    1542  
    1543         public int read(char[] cbuf, int off, int len) 
    1544         { 
    1545             if (iterator == null) 
    1546                 return -1; 
    1547             while (buffered.length() < len) 
    1548             { 
    1549                 if (!iterator.hasNext()) 
    1550                     break; 
    1551                 buffered.append(iterator.next()); 
    1552             } 
    1553             int resultlen = buffered.length(); 
    1554             if (resultlen > len) // don't return more than we have to. 
    1555                 resultlen = len; 
    1556             buffered.getChars(0, resultlen, cbuf, off); // copy the chars 
    1557             buffered.delete(0, resultlen); // remove output from buffer 
    1558             return resultlen>0 ? resultlen : -1; 
    1559         } 
    1560  
    1561         public void close() 
    1562         { 
    1563             this.iterator = null; 
    1564         } 
    1565     } 
    1566  
    1567     public static List<Location> tokenizeTags(String source, String startdelim, String enddelim) 
    1568     { 
    1569         Pattern tagPattern = Pattern.compile(escapeREchars(startdelim) + "(printx|print|code|for|if|elif|else|end|break|continue|render|def|note)(\\s*((.|\\n)*?)\\s*)?" + escapeREchars(enddelim)); 
    1570         LinkedList<Location> tags = new LinkedList<Location>(); 
    1571         if (source != null) 
    1572         { 
    1573             Matcher matcher = tagPattern.matcher(source); 
    1574             int pos = 0; 
    1575  
    1576             int start; 
    1577             int end; 
    1578             while (matcher.find()) 
    1579             { 
    1580                 start = matcher.start(); 
    1581                 end = start + matcher.group().length(); 
    1582                 if (pos != start) 
    1583                     tags.add(new Location(source, null, pos, start, pos, start)); 
    1584                 int codestart = matcher.start(3); 
    1585                 int codeend = codestart + matcher.group(3).length(); 
    1586                 String type = matcher.group(1); 
    1587                 if (!type.equals("note")) 
    1588                     tags.add(new Location(source, matcher.group(1), start, end, codestart, codeend)); 
    1589                 pos = end; 
    1590             } 
    1591             end = source.length(); 
    1592             if (pos != end) 
    1593                 tags.add(new Location(source, null, pos, end, pos, end)); 
    1594         } 
    1595         return tags; 
    1596     } 
    1597  
    1598     private static String escapeREchars(String input) 
    1599     { 
    1600         int len = input.length(); 
    1601  
    1602         StringBuffer output = new StringBuffer(len); 
    1603  
    1604         for (int i = 0; i < len; ++i) 
    1605         { 
    1606             char c = input.charAt(i); 
    1607             if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) 
    1608                 output.append('\\'); 
    1609             output.append(c); 
    1610         } 
    1611         return output.toString(); 
    1612     } 
    1613  
    1614     public static List tokenizeCode(Location location) throws LexicalException 
    1615     { 
    1616         String source = location.getCode(); 
    1617  
    1618         LinkedList tokens = new LinkedList(); 
    1619  
    1620         int pos = 0; 
    1621         int stringStartPos = 0; // The starting position of a string constant 
    1622         int stringMode = 0; // 0 == default; 1 == single-quoted string; 2 == double-quoted strings 
    1623         StringBuffer collectString = null; // characters are collected here, while we're in a string constant 
    1624  
    1625         try 
    1626         { 
    1627             while (source.length() != 0) 
    1628             { 
    1629                 Matcher tokenMatcher = tokenPattern.matcher(source); 
    1630                 Matcher nameMatcher = namePattern.matcher(source); 
    1631                 Matcher floatMatcher = floatPattern.matcher(source); 
    1632                 Matcher hexintMatcher = hexintPattern.matcher(source); 
    1633                 Matcher octintMatcher = octintPattern.matcher(source); 
    1634                 Matcher binintMatcher = binintPattern.matcher(source); 
    1635                 Matcher intMatcher = intPattern.matcher(source); 
    1636                 Matcher dateMatcher = datePattern.matcher(source); 
    1637                 Matcher color3Matcher = color3Pattern.matcher(source); 
    1638                 Matcher color4Matcher = color4Pattern.matcher(source); 
    1639                 Matcher color6Matcher = color6Pattern.matcher(source); 
    1640                 Matcher color8Matcher = color8Pattern.matcher(source); 
    1641                 Matcher whitespaceMatcher = whitespacePattern.matcher(source); 
    1642                 Matcher escaped8BitCharMatcher = escaped8BitCharPattern.matcher(source); 
    1643                 Matcher escaped16BitCharMatcher = escaped16BitCharPattern.matcher(source); 
    1644                 Matcher escaped32BitCharMatcher = escaped32BitCharPattern.matcher(source); 
    1645  
    1646                 int len; 
    1647                 if (stringMode==0 && tokenMatcher.lookingAt()) 
    1648                 { 
    1649                     len = tokenMatcher.end(); 
    1650                     tokens.add(new Token(pos, pos+len, tokenMatcher.group())); 
    1651                 } 
    1652                 else if (stringMode==0 && nameMatcher.lookingAt()) 
    1653                 { 
    1654                     len = nameMatcher.end(); 
    1655                     String name = nameMatcher.group(); 
    1656                     if (name.equals("in") || name.equals("not") || name.equals("or") || name.equals("and") || name.equals("del")) 
    1657                         tokens.add(new Token(pos, pos+len, name)); 
    1658                     else if (name.equals("None")) 
    1659                         tokens.add(new LoadNone(pos, pos+len)); 
    1660                     else if (name.equals("True")) 
    1661                         tokens.add(new LoadTrue(pos, pos+len)); 
    1662                     else if (name.equals("False")) 
    1663                         tokens.add(new LoadFalse(pos, pos+len)); 
    1664                     else 
    1665                         tokens.add(new Name(pos, pos+len, name)); 
    1666                 } 
    1667                 else if (stringMode==0 && dateMatcher.lookingAt()) 
    1668                 { 
    1669                     len = dateMatcher.end(); 
    1670                     tokens.add(new LoadDate(pos, pos+len, Utils.isoparse(dateMatcher.group().substring(1)))); 
    1671                 } 
    1672                 else if (stringMode==0 && color8Matcher.lookingAt()) 
    1673                 { 
    1674                     len = color8Matcher.end(); 
    1675                     String value = color8Matcher.group(); 
    1676                     int r = Integer.valueOf(value.substring(1, 3), 16); 
    1677                     int g = Integer.valueOf(value.substring(3, 5), 16); 
    1678                     int b = Integer.valueOf(value.substring(5, 7), 16); 
    1679                     int a = Integer.valueOf(value.substring(7, 9), 16); 
    1680                     tokens.add(new LoadColor(pos, pos+len, new Color(r, g, b, a))); 
    1681                 } 
    1682                 else if (stringMode==0 && color6Matcher.lookingAt()) 
    1683                 { 
    1684                     len = color6Matcher.end(); 
    1685                     String value = color6Matcher.group(); 
    1686                     int r = Integer.valueOf(value.substring(1, 3), 16); 
    1687                     int g = Integer.valueOf(value.substring(3, 5), 16); 
    1688                     int b = Integer.valueOf(value.substring(5, 7), 16); 
    1689                     tokens.add(new LoadColor(pos, pos+len, new Color(r, g, b))); 
    1690                 } 
    1691                 else if (stringMode==0 && color4Matcher.lookingAt()) 
    1692                 { 
    1693                     len = color4Matcher.end(); 
    1694                     String value = color4Matcher.group(); 
    1695                     int r = 17*Integer.valueOf(value.substring(1, 2), 16); 
    1696                     int g = 17*Integer.valueOf(value.substring(2, 3), 16); 
    1697                     int b = 17*Integer.valueOf(value.substring(3, 4), 16); 
    1698                     int a = 17*Integer.valueOf(value.substring(4, 5), 16); 
    1699                     tokens.add(new LoadColor(pos, pos+len, new Color(r, g, b, a))); 
    1700                 } 
    1701                 else if (stringMode==0 && color3Matcher.lookingAt()) 
    1702                 { 
    1703                     len = color3Matcher.end(); 
    1704                     String value = color3Matcher.group(); 
    1705                     int r = 17*Integer.valueOf(value.substring(1, 2), 16); 
    1706                     int g = 17*Integer.valueOf(value.substring(2, 3), 16); 
    1707                     int b = 17*Integer.valueOf(value.substring(3, 4), 16); 
    1708                     tokens.add(new LoadColor(pos, pos+len, new Color(r, g, b))); 
    1709                 } 
    1710                 else if (stringMode==0 && floatMatcher.lookingAt()) 
    1711                 { 
    1712                     len = floatMatcher.end(); 
    1713                     tokens.add(new LoadFloat(pos, pos+len, Double.parseDouble(floatMatcher.group()))); 
    1714                 } 
    1715                 else if (stringMode==0 && hexintMatcher.lookingAt()) 
    1716                 { 
    1717                     len = hexintMatcher.end(); 
    1718                     tokens.add(new LoadInt(pos, pos+len, Integer.parseInt(hexintMatcher.group().substring(2), 16))); 
    1719                 } 
    1720                 else if (stringMode==0 && octintMatcher.lookingAt()) 
    1721                 { 
    1722                     len = octintMatcher.end(); 
    1723                     tokens.add(new LoadInt(pos, pos+len, Integer.parseInt(octintMatcher.group().substring(2), 8))); 
    1724                 } 
    1725                 else if (stringMode==0 && binintMatcher.lookingAt()) 
    1726                 { 
    1727                     len = binintMatcher.end(); 
    1728                     tokens.add(new LoadInt(pos, pos+len, Integer.parseInt(binintMatcher.group().substring(2), 2))); 
    1729                 } 
    1730                 else if (stringMode==0 && intMatcher.lookingAt()) 
    1731                 { 
    1732                     len = intMatcher.end(); 
    1733                     tokens.add(new LoadInt(pos, pos+len, Integer.parseInt(intMatcher.group()))); 
    1734                 } 
    1735                 else if (stringMode==0 && source.startsWith("'")) 
    1736                 { 
    1737                     stringStartPos = pos; 
    1738                     len = 1; 
    1739                     stringMode = 1; 
    1740                     collectString = new StringBuffer(); 
    1741                 } 
    1742                 else if (stringMode==0 && source.startsWith("\"")) 
    1743                 { 
    1744                     stringStartPos = pos; 
    1745                     len = 1; 
    1746                     stringMode = 2; 
    1747                     collectString = new StringBuffer(); 
    1748                 } 
    1749                 else if (stringMode==1 && source.startsWith("'") || (stringMode==2 && source.startsWith("\""))) 
    1750                 { 
    1751                     len = 1; 
    1752                     stringMode = 0; 
    1753                     tokens.add(new LoadStr(stringStartPos, pos+len, collectString.toString())); 
    1754                     collectString = null; 
    1755                 } 
    1756                 else if (stringMode==0 && whitespaceMatcher.lookingAt()) 
    1757                 { 
    1758                     len = whitespaceMatcher.end(); 
    1759                 } 
    1760                 else if (stringMode!=0 && source.startsWith("\\\\")) 
    1761                 { 
    1762                     len = 2; 
    1763                     collectString.append("\\"); 
    1764                 } 
    1765                 else if (stringMode!=0 && source.startsWith("\\'")) 
    1766                 { 
    1767                     len = 2; 
    1768                     collectString.append("'"); 
    1769                 } 
    1770                 else if (stringMode!=0 && source.startsWith("\\\"")) 
    1771                 { 
    1772                     len = 2; 
    1773                     collectString.append("\""); 
    1774                 } 
    1775                 else if (stringMode!=0 && source.startsWith("\\a")) 
    1776                 { 
    1777                     len = 2; 
    1778                     collectString.append("\u0007"); 
    1779                 } 
    1780                 else if (stringMode!=0 && source.startsWith("\\b")) 
    1781                 { 
    1782                     len = 2; 
    1783                     collectString.append("\u0008"); 
    1784                 } 
    1785                 else if (stringMode!=0 && source.startsWith("\\f")) 
    1786                 { 
    1787                     len = 2; 
    1788                     collectString.append("\u000c"); 
    1789                 } 
    1790                 else if (stringMode!=0 && source.startsWith("\\n")) 
    1791                 { 
    1792                     len = 2; 
    1793                     collectString.append("\n"); 
    1794                 } 
    1795                 else if (stringMode!=0 && source.startsWith("\\r")) 
    1796                 { 
    1797                     len = 2; 
    1798                     collectString.append("\r"); 
    1799                 } 
    1800                 else if (stringMode!=0 && source.startsWith("\\t")) 
    1801                 { 
    1802                     len = 2; 
    1803                     collectString.append("\t"); 
    1804                 } 
    1805                 else if (stringMode!=0 && source.startsWith("\\v")) 
    1806                 { 
    1807                     len = 2; 
    1808                     collectString.append("\u000b"); 
    1809                 } 
    1810                 else if (stringMode!=0 && source.startsWith("\\e")) 
    1811                 { 
    1812                     len = 2; 
    1813                     collectString.append("\u001b"); 
    1814                 } 
    1815                 else if (stringMode!=0 && escaped8BitCharMatcher.lookingAt()) 
    1816                 { 
    1817                     len = 4; 
    1818                     collectString.append((char)Integer.parseInt(escaped8BitCharMatcher.group().substring(2), 16)); 
    1819                 } 
    1820                 else if (stringMode!=0 && escaped16BitCharMatcher.lookingAt()) 
    1821                 { 
    1822                     len = 6; 
    1823                     collectString.append((char)Integer.parseInt(escaped16BitCharMatcher.group().substring(2), 16)); 
    1824                 } 
    1825                 else if (stringMode!=0 && escaped32BitCharMatcher.lookingAt()) 
    1826                 { 
    1827                     len = 10; 
    1828                     throw new RuntimeException("character " + escaped32BitCharMatcher.group() + " (outside the BMP) not supported"); 
    1829                 } 
    1830                 else if (stringMode!=0) 
    1831                 { 
    1832                     len = 1; 
    1833                     collectString.append(source.charAt(0)); 
    1834                 } 
    1835                 else 
    1836                 { 
    1837                     throw new LexicalException(pos, pos+1, source.substring(0, 1)); 
    1838                 } 
    1839                 pos += len; 
    1840                 source = source.substring(len); 
    1841             } 
    1842             if (stringMode != 0) 
    1843                 throw new UnterminatedStringException(); 
    1844         } 
    1845         catch (LocationException ex) 
    1846         { 
    1847             throw ex; 
    1848         } 
    1849         catch (Exception ex) 
    1850         { 
    1851             // decorate inner exception with location information 
    1852             throw new LocationException(ex, location); 
    1853         } 
    1854         return tokens; 
    1855     } 
    1856  
    1857     public String toString() 
    1858     { 
    1859         StringBuffer buffer = new StringBuffer(); 
    1860         int indent = 0; 
    1861  
    1862         int size = opcodes.size(); 
    1863         for (int i = 0; i < size; ++i) 
    1864         { 
    1865             Opcode code = opcodes.get(i); 
    1866  
    1867             if (code.name == Opcode.OC_ELSE || code.name == Opcode.OC_ENDIF || code.name == Opcode.OC_ENDFOR) 
    1868                 --indent; 
    1869             for (int j = 0; j < indent; ++j) 
    1870                 buffer.append("\t"); 
    1871             if (code.name == Opcode.OC_ENDIF || code.name == Opcode.OC_ENDFOR) 
    1872                 buffer.append("}"); 
    1873             else if (code.name == Opcode.OC_FOR || code.name == Opcode.OC_IF) 
    1874                 buffer.append(code + " {"); 
    1875             else if (code.name == Opcode.OC_ELSE) 
    1876                 buffer.append("} else {"); 
    1877             else 
    1878                 buffer.append(code); 
    1879             buffer.append("\n"); 
    1880             if (code.name == Opcode.OC_FOR || code.name == Opcode.OC_IF || code.name == Opcode.OC_ELSE) 
    1881                 ++indent; 
    1882         } 
    1883         return buffer.toString(); 
    1884     } 
    1885  
    1886     private void code(StringBuffer buffer, int indent, String code) 
     32    private void code(String code) 
    188733    { 
    188834        for (int i = 0; i < indent; ++i) 
     
    189238    } 
    189339 
    1894     public String javascriptSource() 
     40    public String toString() 
    189541    { 
    1896         StringBuffer buffer = new StringBuffer(); 
    1897         int indent = 0; 
     42        buffer = new StringBuffer(); 
     43        indent = 0; 
    189844        int varcounter = 0; 
    189945        Location lastLocation = null; 
    190046 
    1901         code(buffer, indent, "ul4.Template.create(function(vars){"); 
     47        code("ul4.Template.create(function(vars){"); 
    190248        indent += 1; 
    1903         code(buffer, indent, "//@@@ BEGIN template source"); 
    1904         code(buffer, indent, "//@@@ BEGIN template code"); 
    1905         code(buffer, indent, "var out = [], r0 = null, r1 = null, r2 = null, r3 = null, r4 = null, r5 = null, r6 = null, r7 = null, r8 = null, r9 = null;"); 
    1906  
    1907         int size = opcodes.size(); 
     49        code("//@@@ BEGIN template source"); 
     50        code("//@@@ BEGIN template code"); 
     51        code("var out = [], r0 = null, r1 = null, r2 = null, r3 = null, r4 = null, r5 = null, r6 = null, r7 = null, r8 = null, r9 = null;"); 
     52 
     53        int size = template.opcodes.size(); 
    190854 
    190955        for (int i = 0; i < size; ++i) 
    191056        { 
    1911             Opcode opcode = opcodes.get(i); 
     57            Opcode opcode = template.opcodes.get(i); 
    191258            if (opcode.location != lastLocation && opcode.name != Opcode.OC_TEXT) 
    191359            { 
     
    191561                String code = Utils.repr(lastLocation.getTag()); 
    191662                code = code.substring(1, code.length()-1); 
    1917                 code(buffer, indent, "// " + lastLocation + ": " + code); 
     63                code("// " + lastLocation + ": " + code); 
    191864            } 
    191965 
     
    192167            { 
    192268                case Opcode.OC_TEXT: 
    1923                     code(buffer, indent, "out.push(" + Utils.json(opcode.location.getCode()) + ");"); 
     69                    code("out.push(" + Utils.json(opcode.location.getCode()) + ");"); 
    192470                    break; 
    192571                case Opcode.OC_LOADSTR: 
    1926                     code(buffer, indent, "r" + opcode.r1 + " = " + Utils.json(opcode.arg) + ";"); 
     72                    code("r" + opcode.r1 + " = " + Utils.json(opcode.arg) + ";"); 
    192773                    break; 
    192874                case Opcode.OC_LOADINT: 
    1929                     code(buffer, indent, "r" + opcode.r1 + " = " + opcode.arg + ";"); 
     75                    code("r" + opcode.r1 + " = " + opcode.arg + ";"); 
    193076                    break; 
    193177                case Opcode.OC_LOADFLOAT: 
    1932                     code(buffer, indent, "r" + opcode.r1 + " = " + opcode.arg + ";"); 
     78                    code("r" + opcode.r1 + " = " + opcode.arg + ";"); 
    193379                    break; 
    193480                case Opcode.OC_LOADNONE: 
    1935                     code(buffer, indent, "r" + opcode.r1 + " = null;"); 
     81                    code("r" + opcode.r1 + " = null;"); 
    193682                    break; 
    193783                case Opcode.OC_LOADFALSE: 
    1938                     code(buffer, indent, "r" + opcode.r1 + " = false;"); 
     84                    code("r" + opcode.r1 + " = false;"); 
    193985                    break; 
    194086                case Opcode.OC_LOADTRUE: 
    1941                     code(buffer, indent, "r" + opcode.r1 + " = true;"); 
     87                    code("r" + opcode.r1 + " = true;"); 
    194288                    break; 
    194389                case Opcode.OC_LOADDATE: 
    1944                     code(buffer, indent, "r" + opcode.r1 + " = " + Utils.json(Utils.isoparse(opcode.arg)) + ";"); 
     90                    code("r" + opcode.r1 + " = " + Utils.json(Utils.isoparse(opcode.arg)) + ";"); 
    194591                    break; 
    194692                case Opcode.OC_LOADCOLOR: 
    1947                     code(buffer, indent, "r" + opcode.r1 + " = " + Utils.json(Color.fromdump(opcode.arg)) + ";"); 
     93                    code("r" + opcode.r1 + " = " + Utils.json(Color.fromdump(opcode.arg)) + ";"); 
    194894                    break; 
    194995                case Opcode.OC_BUILDLIST: 
    1950                     code(buffer, indent, "r" + opcode.r1 + " = [];"); 
     96                    code("r" + opcode.r1 + " = [];"); 
    195197                    break; 
    195298                case Opcode.OC_BUILDDICT: 
    1953                     code(buffer, indent, "r" + opcode.r1 + " = {};"); 
     99                    code("r" + opcode.r1 + " = {};"); 
    1954100                    break; 
    1955101                case Opcode.OC_ADDLIST: 
    1956                     code(buffer, indent, "r" + opcode.r1 + ".push(r" + opcode.r2 + ");"); 
     102                    code("r" + opcode.r1 + ".push(r" + opcode.r2 + ");"); 
    1957103                    break; 
    1958104                case Opcode.OC_ADDDICT: 
    1959                     code(buffer, indent, "r" + opcode.r1 + "[r" + opcode.r2 + "] = r" + opcode.r3 + ";"); 
     105                    code("r" + opcode.r1 + "[r" + opcode.r2 + "] = r" + opcode.r3 + ";"); 
    1960106                    break; 
    1961107                case Opcode.OC_UPDATEDICT: 
    1962                     code(buffer, indent, "for (var key in r" + opcode.r2 + ")"); 
     108                    code("for (var key in r" + opcode.r2 + ")"); 
    1963109                    indent++; 
    1964                     code(buffer, indent, "r" + opcode.r1 + "[key] = r" + opcode.r2 + "[key];"); 
     110                    code("r" + opcode.r1 + "[key] = r" + opcode.r2 + "[key];"); 
    1965111                    indent--; 
    1966112                    break; 
    1967113                case Opcode.OC_LOADVAR: 
    1968                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getitem(vars, " + Utils.repr(opcode.arg) + ");"); 
     114                    code("r" + opcode.r1 + " = ul4._op_getitem(vars, " + Utils.repr(opcode.arg) + ");"); 
    1969115                    break; 
    1970116                case Opcode.OC_STOREVAR: 
    1971                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = r" + opcode.r1 + ";"); 
     117                    code("vars[" + Utils.repr(opcode.arg) + "] = r" + opcode.r1 + ";"); 
    1972118                    break; 
    1973119                case Opcode.OC_ADDVAR: 
    1974                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_add(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
     120                    code("vars[" + Utils.repr(opcode.arg) + "] = ul4._op_add(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1975121                    break; 
    1976122                case Opcode.OC_SUBVAR: 
    1977                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_sub(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
     123                    code("vars[" + Utils.repr(opcode.arg) + "] = ul4._op_sub(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1978124                    break; 
    1979125                case Opcode.OC_MULVAR: 
    1980                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_mul(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
     126                    code("vars[" + Utils.repr(opcode.arg) + "] = ul4._op_mul(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1981127                    break; 
    1982128                case Opcode.OC_TRUEDIVVAR: 
    1983                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_truediv(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
     129                    code("vars[" + Utils.repr(opcode.arg) + "] = ul4._op_truediv(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1984130                    break; 
    1985131                case Opcode.OC_FLOORDIVVAR: 
    1986                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_floordiv(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
     132                    code("vars[" + Utils.repr(opcode.arg) + "] = ul4._op_floordiv(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1987133                    break; 
    1988134                case Opcode.OC_MODVAR: 
    1989                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = ul4._op_mod(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
     135                    code("vars[" + Utils.repr(opcode.arg) + "] = ul4._op_mod(vars[" + Utils.repr(opcode.arg) + "], r" + opcode.r1 + ");"); 
    1990136                    break; 
    1991137                case Opcode.OC_DELVAR: 
    1992                     code(buffer, indent, "vars[" + Utils.repr(opcode.arg) + "] = undefined;"); 
     138                    code("vars[" + Utils.repr(opcode.arg) + "] = undefined;"); 
    1993139                    break; 
    1994140                case Opcode.OC_GETATTR: 
    1995                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getitem(r" + opcode.r2 + ", " + Utils.repr(opcode.arg) + ");"); 
     141                    code("r" + opcode.r1 + " = ul4._op_getitem(r" + opcode.r2 + ", " + Utils.repr(opcode.arg) + ");"); 
    1996142                    break; 
    1997143                case Opcode.OC_GETITEM: 
    1998                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getitem(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     144                    code("r" + opcode.r1 + " = ul4._op_getitem(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    1999145                    break; 
    2000146                case Opcode.OC_GETSLICE12: 
    2001                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     147                    code("r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2002148                    break; 
    2003149                case Opcode.OC_GETSLICE1: 
    2004                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
     150                    code("r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2005151                    break; 
    2006152                case Opcode.OC_GETSLICE2: 
    2007                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", null, r" + opcode.r3 + ");"); 
     153                    code("r" + opcode.r1 + " = ul4._op_getslice(r" + opcode.r2 + ", null, r" + opcode.r3 + ");"); 
    2008154                    break; 
    2009155                case Opcode.OC_PRINT: 
    2010                     code(buffer, indent, "out.push(ul4._fu_str(r" + opcode.r1 + "));"); 
     156                    code("out.push(ul4._fu_str(r" + opcode.r1 + "));"); 
    2011157                    break; 
    2012158                case Opcode.OC_PRINTX: 
    2013                     code(buffer, indent, "out.push(ul4._fu_xmlescape(r" + opcode.r1 + "));"); 
     159                    code("out.push(ul4._fu_xmlescape(r" + opcode.r1 + "));"); 
    2014160                    break; 
    2015161                case Opcode.OC_FOR: 
    2016162                    varcounter++; 
    2017                     code(buffer, indent, "for (var iter" + varcounter + " = ul4._iter(r" + opcode.r2 + ");;)"); 
    2018                     code(buffer, indent, "{"); 
     163                    code("for (var iter" + varcounter + " = ul4._iter(r" + opcode.r2 + ");;)"); 
     164                    code("{"); 
    2019165                    indent++; 
    2020                     code(buffer, indent, "r" + opcode.r1 + " = iter" + varcounter + "();"); 
    2021                     code(buffer, indent, "if (r" + opcode.r1 + " === null)"); 
     166                    code("r" + opcode.r1 + " = iter" + varcounter + "();"); 
     167                    code("if (r" + opcode.r1 + " === null)"); 
    2022168                    indent++; 
    2023                     code(buffer, indent, "break;"); 
     169                    code("break;"); 
    2024170                    indent--; 
    2025                     code(buffer, indent, "r" + opcode.r1 + " = r" + opcode.r1 + "[0];"); 
     171                    code("r" + opcode.r1 + " = r" + opcode.r1 + "[0];"); 
    2026172                    break; 
    2027173                case Opcode.OC_ENDFOR: 
    2028174                    indent--; 
    2029                     code(buffer, indent, "}"); 
     175                    code("}"); 
    2030176                    break; 
    2031177                case Opcode.OC_DEF: 
    2032                     code(buffer, indent, "vars[" + Utils.json(opcode.arg) + "] = ul4.Template.create(function(vars){"); 
     178                    code("vars[" + Utils.json(opcode.arg) + "] = ul4.Template.create(function(vars){"); 
    2033179                    indent++; 
    2034                     code(buffer, indent, "var out = [], r0 = null, r1 = null, r2 = null, r3 = null, r4 = null, r5 = null, r6 = null, r7 = null, r8 = null, r9 = null;"); 
     180                    code("var out = [], r0 = null, r1 = null, r2 = null, r3 = null, r4 = null, r5 = null, r6 = null, r7 = null, r8 = null, r9 = null;"); 
    2035181                    break; 
    2036182                case Opcode.OC_ENDDEF: 
    2037                     code(buffer, indent, "return out;"); 
     183                    code("return out;"); 
    2038184                    indent--; 
    2039                     code(buffer, indent, "});"); 
     185                    code("});"); 
    2040186                    break; 
    2041187                case Opcode.OC_BREAK: 
    2042                     code(buffer, indent, "break;"); 
     188                    code("break;"); 
    2043189                    break; 
    2044190                case Opcode.OC_CONTINUE: 
    2045                     code(buffer, indent, "continue;"); 
     191                    code("continue;"); 
    2046192                    break; 
    2047193                case Opcode.OC_NOT: 
    2048                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._fu_bool(r" + opcode.r2 + ");"); 
     194                    code("r" + opcode.r1 + " = !ul4._fu_bool(r" + opcode.r2 + ");"); 
    2049195                    break; 
    2050196                case Opcode.OC_NEG: 
    2051                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_neg(r" + opcode.r2 + ");"); 
     197                    code("r" + opcode.r1 + " = ul4._op_neg(r" + opcode.r2 + ");"); 
    2052198                    break; 
    2053199                case Opcode.OC_CONTAINS: 
    2054                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_contains(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     200                    code("r" + opcode.r1 + " = ul4._op_contains(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2055201                    break; 
    2056202                case Opcode.OC_NOTCONTAINS: 
    2057                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_contains(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     203                    code("r" + opcode.r1 + " = !ul4._op_contains(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2058204                    break; 
    2059205                case Opcode.OC_EQ: 
    2060                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_eq(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     206                    code("r" + opcode.r1 + " = ul4._op_eq(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2061207                    break; 
    2062208                case Opcode.OC_NE: 
    2063                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_eq(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     209                    code("r" + opcode.r1 + " = !ul4._op_eq(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2064210                    break; 
    2065211                case Opcode.OC_LT: 
    2066                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_lt(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     212                    code("r" + opcode.r1 + " = ul4._op_lt(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2067213                    break; 
    2068214                case Opcode.OC_LE: 
    2069                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_le(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     215                    code("r" + opcode.r1 + " = ul4._op_le(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2070216                    break; 
    2071217                case Opcode.OC_GT: 
    2072                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_le(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     218                    code("r" + opcode.r1 + " = !ul4._op_le(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2073219                    break; 
    2074220                case Opcode.OC_GE: 
    2075                     code(buffer, indent, "r" + opcode.r1 + " = !ul4._op_lt(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     221                    code("r" + opcode.r1 + " = !ul4._op_lt(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2076222                    break; 
    2077223                case Opcode.OC_ADD: 
    2078                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_add(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     224                    code("r" + opcode.r1 + " = ul4._op_add(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2079225                    break; 
    2080226                case Opcode.OC_SUB: 
    2081                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_sub(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     227                    code("r" + opcode.r1 + " = ul4._op_sub(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2082228                    break; 
    2083229                case Opcode.OC_MUL: 
    2084                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_mul(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     230                    code("r" + opcode.r1 + " = ul4._op_mul(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2085231                    break; 
    2086232                case Opcode.OC_FLOORDIV: 
    2087                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_floordiv(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     233                    code("r" + opcode.r1 + " = ul4._op_floordiv(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2088234                    break; 
    2089235                case Opcode.OC_TRUEDIV: 
    2090                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_truediv(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     236                    code("r" + opcode.r1 + " = ul4._op_truediv(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2091237                    break; 
    2092238                case Opcode.OC_MOD: 
    2093                     code(buffer, indent, "r" + opcode.r1 + " = ul4._op_mod(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     239                    code("r" + opcode.r1 + " = ul4._op_mod(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2094240                    break; 
    2095241                case Opcode.OC_AND: 
    2096                     code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r3 + ") ? r" + opcode.r2 + " : r" + opcode.r3 + ";"); 
     242                    code("r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r3 + ") ? r" + opcode.r2 + " : r" + opcode.r3 + ";"); 
    2097243                    break; 
    2098244                case Opcode.OC_OR: 
    2099                     code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r2 + ") ? r" + opcode.r2 + " : r" + opcode.r3 + ";"); 
     245                    code("r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r2 + ") ? r" + opcode.r2 + " : r" + opcode.r3 + ";"); 
    2100246                    break; 
    2101247                case Opcode.OC_CALLFUNC0: 
     
    2103249                    { 
    2104250                        case Opcode.CF0_NOW: 
    2105                             code(buffer, indent, "r" + opcode.r1 + " = new Date();"); 
     251                            code("r" + opcode.r1 + " = new Date();"); 
    2106252                            break; 
    2107253                        case Opcode.CF0_UTCNOW: 
    2108                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_utcnow();"); 
     254                            code("r" + opcode.r1 + " = ul4._fu_utcnow();"); 
    2109255                            break; 
    2110256                        case Opcode.CF0_RANDOM: 
    2111                             code(buffer, indent, "r" + opcode.r1 + " = Math.random();"); 
     257                            code("r" + opcode.r1 + " = Math.random();"); 
    2112258                            break; 
    2113259                        case Opcode.CF0_VARS: 
    2114                             code(buffer, indent, "r" + opcode.r1 + " = vars;"); 
     260                            code("r" + opcode.r1 + " = vars;"); 
    2115261                            break; 
    2116262                    } 
     
    2120266                    { 
    2121267                        case Opcode.CF1_XMLESCAPE: 
    2122                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_xmlescape(r" + opcode.r2 + ");"); 
     268                            code("r" + opcode.r1 + " = ul4._fu_xmlescape(r" + opcode.r2 + ");"); 
    2123269                            break; 
    2124270                        case Opcode.CF1_CSV: 
    2125                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_csv(r" + opcode.r2 + ");"); 
     271                            code("r" + opcode.r1 + " = ul4._fu_csv(r" + opcode.r2 + ");"); 
    2126272                            break; 
    2127273                        case Opcode.CF1_REPR: 
    2128                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_repr(r" + opcode.r2 + ");"); 
     274                            code("r" + opcode.r1 + " = ul4._fu_repr(r" + opcode.r2 + ");"); 
    2129275                            break; 
    2130276                        case Opcode.CF1_ENUMERATE: 
    2131                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_enumerate(r" + opcode.r2 + ");"); 
     277                            code("r" + opcode.r1 + " = ul4._fu_enumerate(r" + opcode.r2 + ");"); 
    2132278                            break; 
    2133279                        case Opcode.CF1_CHR: 
    2134                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_chr(r" + opcode.r2 + ");"); 
     280                            code("r" + opcode.r1 + " = ul4._fu_chr(r" + opcode.r2 + ");"); 
    2135281                            break; 
    2136282                        case Opcode.CF1_ORD: 
    2137                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_ord(r" + opcode.r2 + ");"); 
     283                            code("r" + opcode.r1 + " = ul4._fu_ord(r" + opcode.r2 + ");"); 
    2138284                            break; 
    2139285                        case Opcode.CF1_HEX: 
    2140                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hex(r" + opcode.r2 + ");"); 
     286                            code("r" + opcode.r1 + " = ul4._fu_hex(r" + opcode.r2 + ");"); 
    2141287                            break; 
    2142288                        case Opcode.CF1_OCT: 
    2143                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_oct(r" + opcode.r2 + ");"); 
     289                            code("r" + opcode.r1 + " = ul4._fu_oct(r" + opcode.r2 + ");"); 
    2144290                            break; 
    2145291                        case Opcode.CF1_BIN: 
    2146                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bin(r" + opcode.r2 + ");"); 
     292                            code("r" + opcode.r1 + " = ul4._fu_bin(r" + opcode.r2 + ");"); 
    2147293                            break; 
    2148294                        case Opcode.CF1_SORTED: 
    2149                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_sorted(r" + opcode.r2 + ");"); 
     295                            code("r" + opcode.r1 + " = ul4._fu_sorted(r" + opcode.r2 + ");"); 
    2150296                            break; 
    2151297                        case Opcode.CF1_TYPE: 
    2152                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_type(r" + opcode.r2 + ");"); 
     298                            code("r" + opcode.r1 + " = ul4._fu_type(r" + opcode.r2 + ");"); 
    2153299                            break; 
    2154300                        case Opcode.CF1_JSON: 
    2155                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_json(r" + opcode.r2 + ");"); 
     301                            code("r" + opcode.r1 + " = ul4._fu_json(r" + opcode.r2 + ");"); 
    2156302                            break; 
    2157303                        case Opcode.CF1_REVERSED: 
    2158                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_reversed(r" + opcode.r2 + ");"); 
     304                            code("r" + opcode.r1 + " = ul4._fu_reversed(r" + opcode.r2 + ");"); 
    2159305                            break; 
    2160306                        case Opcode.CF1_RANDCHOICE: 
    2161                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randchoice(r" + opcode.r2 + ");"); 
     307                            code("r" + opcode.r1 + " = ul4._fu_randchoice(r" + opcode.r2 + ");"); 
    2162308                            break; 
    2163309                        case Opcode.CF1_STR: 
    2164                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_str(r" + opcode.r2 + ");"); 
     310                            code("r" + opcode.r1 + " = ul4._fu_str(r" + opcode.r2 + ");"); 
    2165311                            break; 
    2166312                        case Opcode.CF1_INT: 
    2167                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_int(r" + opcode.r2 + ");"); 
     313                            code("r" + opcode.r1 + " = ul4._fu_int(r" + opcode.r2 + ");"); 
    2168314                            break; 
    2169315                        case Opcode.CF1_FLOAT: 
    2170                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_float(r" + opcode.r2 + ");"); 
     316                            code("r" + opcode.r1 + " = ul4._fu_float(r" + opcode.r2 + ");"); 
    2171317                            break; 
    2172318                        case Opcode.CF1_BOOL: 
    2173                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r2 + ");"); 
     319                            code("r" + opcode.r1 + " = ul4._fu_bool(r" + opcode.r2 + ");"); 
    2174320                            break; 
    2175321                        case Opcode.CF1_LEN: 
    2176                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_len(r" + opcode.r2 + ");"); 
     322                            code("r" + opcode.r1 + " = ul4._fu_len(r" + opcode.r2 + ");"); 
    2177323                            break; 
    2178324                        case Opcode.CF1_ISSTR: 
    2179                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isstr(r" + opcode.r2 + ");"); 
     325                            code("r" + opcode.r1 + " = ul4._fu_isstr(r" + opcode.r2 + ");"); 
    2180326                            break; 
    2181327                        case Opcode.CF1_ISINT: 
    2182                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isint(r" + opcode.r2 + ");"); 
     328                            code("r" + opcode.r1 + " = ul4._fu_isint(r" + opcode.r2 + ");"); 
    2183329                            break; 
    2184330                        case Opcode.CF1_ISFLOAT: 
    2185                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isfloat(r" + opcode.r2 + ");"); 
     331                            code("r" + opcode.r1 + " = ul4._fu_isfloat(r" + opcode.r2 + ");"); 
    2186332                            break; 
    2187333                        case Opcode.CF1_ISBOOL: 
    2188                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isbool(r" + opcode.r2 + ");"); 
     334                            code("r" + opcode.r1 + " = ul4._fu_isbool(r" + opcode.r2 + ");"); 
    2189335                            break; 
    2190336                        case Opcode.CF1_ISDATE: 
    2191                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isdate(r" + opcode.r2 + ");"); 
     337                            code("r" + opcode.r1 + " = ul4._fu_isdate(r" + opcode.r2 + ");"); 
    2192338                            break; 
    2193339                        case Opcode.CF1_ISLIST: 
    2194                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_islist(r" + opcode.r2 + ");"); 
     340                            code("r" + opcode.r1 + " = ul4._fu_islist(r" + opcode.r2 + ");"); 
    2195341                            break; 
    2196342                        case Opcode.CF1_ISDICT: 
    2197                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_isdict(r" + opcode.r2 + ");"); 
     343                            code("r" + opcode.r1 + " = ul4._fu_isdict(r" + opcode.r2 + ");"); 
    2198344                            break; 
    2199345                        case Opcode.CF1_ISTEMPLATE: 
    2200                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_istemplate(r" + opcode.r2 + ");"); 
     346                            code("r" + opcode.r1 + " = ul4._fu_istemplate(r" + opcode.r2 + ");"); 
    2201347                            break; 
    2202348                        case Opcode.CF1_ISCOLOR: 
    2203                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_iscolor(r" + opcode.r2 + ");"); 
     349                            code("r" + opcode.r1 + " = ul4._fu_iscolor(r" + opcode.r2 + ");"); 
    2204350                            break; 
    2205351                        case Opcode.CF1_ABS: 
    2206                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_abs(r" + opcode.r2 + ");"); 
     352                            code("r" + opcode.r1 + " = ul4._fu_abs(r" + opcode.r2 + ");"); 
    2207353                            break; 
    2208354                        case Opcode.CF1_RANGE: 
    2209                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_range(0, r" + opcode.r2 + ", 1);"); 
     355                            code("r" + opcode.r1 + " = ul4._fu_range(0, r" + opcode.r2 + ", 1);"); 
    2210356                            break; 
    2211357                        case Opcode.CF1_RANDRANGE: 
    2212                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randrange(0, r" + opcode.r2 + ", 1);"); 
     358                            code("r" + opcode.r1 + " = ul4._fu_randrange(0, r" + opcode.r2 + ", 1);"); 
    2213359                            break; 
    2214360                        case Opcode.CF1_ISNONE: 
    2215                             code(buffer, indent, "r" + opcode.r1 + " = (r" + opcode.r2 + " === null);"); 
     361                            code("r" + opcode.r1 + " = (r" + opcode.r2 + " === null);"); 
    2216362                            break; 
    2217363                        case Opcode.CF1_GET: 
    2218                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(vars, r" + opcode.r2 + ");"); 
     364                            code("r" + opcode.r1 + " = ul4._me_get(vars, r" + opcode.r2 + ");"); 
    2219365                            break; 
    2220366                    } 
     
    2224370                    { 
    2225371                        case Opcode.CF2_ZIP: 
    2226                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_zip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     372                            code("r" + opcode.r1 + " = ul4._fu_zip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2227373                            break; 
    2228374                        case Opcode.CF2_INT: 
    2229                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_int(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     375                            code("r" + opcode.r1 + " = ul4._fu_int(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2230376                            break; 
    2231377                        case Opcode.CF2_RANGE: 
    2232                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_range(r" + opcode.r2 + ", r" + opcode.r3 + ", 1);"); 
     378                            code("r" + opcode.r1 + " = ul4._fu_range(r" + opcode.r2 + ", r" + opcode.r3 + ", 1);"); 
    2233379                            break; 
    2234380                        case Opcode.CF2_RANDRANGE: 
    2235                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randrange(r" + opcode.r2 + ", r" + opcode.r3 + ", 1);"); 
     381                            code("r" + opcode.r1 + " = ul4._fu_randrange(r" + opcode.r2 + ", r" + opcode.r3 + ", 1);"); 
    2236382                            break; 
    2237383                        case Opcode.CF2_GET: 
    2238                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(vars, r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     384                            code("r" + opcode.r1 + " = ul4._me_get(vars, r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2239385                            break; 
    2240386                    } 
     
    2244390                    { 
    2245391                        case Opcode.CF3_RANGE: 
    2246                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_range(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     392                            code("r" + opcode.r1 + " = ul4._fu_range(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2247393                            break; 
    2248394                        case Opcode.CF3_RANDRANGE: 
    2249                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_randrange(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     395                            code("r" + opcode.r1 + " = ul4._fu_randrange(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2250396                            break; 
    2251397                        case Opcode.CF3_ZIP: 
    2252                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_zip(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     398                            code("r" + opcode.r1 + " = ul4._fu_zip(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2253399                            break; 
    2254400                        case Opcode.CF3_HLS: 
    2255                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hls(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
     401                            code("r" + opcode.r1 + " = ul4._fu_hls(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
    2256402                            break; 
    2257403                        case Opcode.CF3_HSV: 
    2258                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hsv(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
     404                            code("r" + opcode.r1 + " = ul4._fu_hsv(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
    2259405                            break; 
    2260406                        case Opcode.CF3_RGB: 
    2261                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_rgb(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
     407                            code("r" + opcode.r1 + " = ul4._fu_rgb(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", 1.0);"); 
    2262408                            break; 
    2263409                    } 
     
    2267413                    { 
    2268414                        case Opcode.CF4_RGB: 
    2269                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_rgb(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
     415                            code("r" + opcode.r1 + " = ul4._fu_rgb(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2270416                            break; 
    2271417                        case Opcode.CF4_HLS: 
    2272                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hls(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
     418                            code("r" + opcode.r1 + " = ul4._fu_hls(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2273419                            break; 
    2274420                        case Opcode.CF4_HSV: 
    2275                             code(buffer, indent, "r" + opcode.r1 + " = ul4._fu_hsv(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
     421                            code("r" + opcode.r1 + " = ul4._fu_hsv(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2276422                            break; 
    2277423                    } 
     
    2281427                    { 
    2282428                        case Opcode.CM0_STRIP: 
    2283                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_strip(r" + opcode.r2 + ");"); 
     429                            code("r" + opcode.r1 + " = ul4._me_strip(r" + opcode.r2 + ");"); 
    2284430                            break; 
    2285431                        case Opcode.CM0_LSTRIP: 
    2286                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lstrip(r" + opcode.r2 + ");"); 
     432                            code("r" + opcode.r1 + " = ul4._me_lstrip(r" + opcode.r2 + ");"); 
    2287433                            break; 
    2288434                        case Opcode.CM0_RSTRIP: 
    2289                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rstrip(r" + opcode.r2 + ");"); 
     435                            code("r" + opcode.r1 + " = ul4._me_rstrip(r" + opcode.r2 + ");"); 
    2290436                            break; 
    2291437                        case Opcode.CM0_UPPER: 
    2292                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_upper(r" + opcode.r2 + ");"); 
     438                            code("r" + opcode.r1 + " = ul4._me_upper(r" + opcode.r2 + ");"); 
    2293439                            break; 
    2294440                        case Opcode.CM0_LOWER: 
    2295                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lower(r" + opcode.r2 + ");"); 
     441                            code("r" + opcode.r1 + " = ul4._me_lower(r" + opcode.r2 + ");"); 
    2296442                            break; 
    2297443                        case Opcode.CM0_CAPITALIZE: 
    2298                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_capitalize(r" + opcode.r2 + ");"); 
     444                            code("r" + opcode.r1 + " = ul4._me_capitalize(r" + opcode.r2 + ");"); 
    2299445                            break; 
    2300446                        case Opcode.CM0_ITEMS: 
    2301                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_items(r" + opcode.r2 + ");"); 
     447                            code("r" + opcode.r1 + " = ul4._me_items(r" + opcode.r2 + ");"); 
    2302448                            break; 
    2303449                        case Opcode.CM0_ISOFORMAT: 
    2304                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_isoformat(r" + opcode.r2 + ");"); 
     450                            code("r" + opcode.r1 + " = ul4._me_isoformat(r" + opcode.r2 + ");"); 
    2305451                            break; 
    2306452                        case Opcode.CM0_MIMEFORMAT: 
    2307                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_mimeformat(r" + opcode.r2 + ");"); 
     453                            code("r" + opcode.r1 + " = ul4._me_mimeformat(r" + opcode.r2 + ");"); 
    2308454                            break; 
    2309455                        case Opcode.CM0_DAY: 
    2310                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_day(r" + opcode.r2 + ");"); 
     456                            code("r" + opcode.r1 + " = ul4._me_day(r" + opcode.r2 + ");"); 
    2311457                            break; 
    2312458                        case Opcode.CM0_MONTH: 
    2313                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_month(r" + opcode.r2 + ");"); 
     459                            code("r" + opcode.r1 + " = ul4._me_month(r" + opcode.r2 + ");"); 
    2314460                            break; 
    2315461                        case Opcode.CM0_YEAR: 
    2316                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_year(r" + opcode.r2 + ");"); 
     462                            code("r" + opcode.r1 + " = ul4._me_year(r" + opcode.r2 + ");"); 
    2317463                            break; 
    2318464                        case Opcode.CM0_HOUR: 
    2319                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hour(r" + opcode.r2 + ");"); 
     465                            code("r" + opcode.r1 + " = ul4._me_hour(r" + opcode.r2 + ");"); 
    2320466                            break; 
    2321467                        case Opcode.CM0_MINUTE: 
    2322                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_minute(r" + opcode.r2 + ");"); 
     468                            code("r" + opcode.r1 + " = ul4._me_minute(r" + opcode.r2 + ");"); 
    2323469                            break; 
    2324470                        case Opcode.CM0_SECOND: 
    2325                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_second(r" + opcode.r2 + ");"); 
     471                            code("r" + opcode.r1 + " = ul4._me_second(r" + opcode.r2 + ");"); 
    2326472                            break; 
    2327473                        case Opcode.CM0_MICROSECOND: 
    2328                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_microsecond(r" + opcode.r2 + ");"); 
     474                            code("r" + opcode.r1 + " = ul4._me_microsecond(r" + opcode.r2 + ");"); 
    2329475                            break; 
    2330476                        case Opcode.CM0_WEEKDAY: 
    2331                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_weekday(r" + opcode.r2 + ");"); 
     477                            code("r" + opcode.r1 + " = ul4._me_weekday(r" + opcode.r2 + ");"); 
    2332478                            break; 
    2333479                        case Opcode.CM0_YEARDAY: 
    2334                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_yearday(r" + opcode.r2 + ");"); 
     480                            code("r" + opcode.r1 + " = ul4._me_yearday(r" + opcode.r2 + ");"); 
    2335481                            break; 
    2336482                        case Opcode.CM0_R: 
    2337                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_r(r" + opcode.r2 + ");"); 
     483                            code("r" + opcode.r1 + " = ul4._me_r(r" + opcode.r2 + ");"); 
    2338484                            break; 
    2339485                        case Opcode.CM0_G: 
    2340                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_g(r" + opcode.r2 + ");"); 
     486                            code("r" + opcode.r1 + " = ul4._me_g(r" + opcode.r2 + ");"); 
    2341487                            break; 
    2342488                        case Opcode.CM0_B: 
    2343                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_b(r" + opcode.r2 + ");"); 
     489                            code("r" + opcode.r1 + " = ul4._me_b(r" + opcode.r2 + ");"); 
    2344490                            break; 
    2345491                        case Opcode.CM0_A: 
    2346                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_a(r" + opcode.r2 + ");"); 
     492                            code("r" + opcode.r1 + " = ul4._me_a(r" + opcode.r2 + ");"); 
    2347493                            break; 
    2348494                        case Opcode.CM0_LUM: 
    2349                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lum(r" + opcode.r2 + ");"); 
     495                            code("r" + opcode.r1 + " = ul4._me_lum(r" + opcode.r2 + ");"); 
    2350496                            break; 
    2351497                        case Opcode.CM0_HLS: 
    2352                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hls(r" + opcode.r2 + ");"); 
     498                            code("r" + opcode.r1 + " = ul4._me_hls(r" + opcode.r2 + ");"); 
    2353499                            break; 
    2354500                        case Opcode.CM0_HLSA: 
    2355                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hlsa(r" + opcode.r2 + ");"); 
     501                            code("r" + opcode.r1 + " = ul4._me_hlsa(r" + opcode.r2 + ");"); 
    2356502                            break; 
    2357503                        case Opcode.CM0_HSV: 
    2358                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hsv(r" + opcode.r2 + ");"); 
     504                            code("r" + opcode.r1 + " = ul4._me_hsv(r" + opcode.r2 + ");"); 
    2359505                            break; 
    2360506                        case Opcode.CM0_HSVA: 
    2361                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_hsva(r" + opcode.r2 + ");"); 
     507                            code("r" + opcode.r1 + " = ul4._me_hsva(r" + opcode.r2 + ");"); 
    2362508                            break; 
    2363509                        case Opcode.CM0_SPLIT: 
    2364                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", null, null);"); 
     510                            code("r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", null, null);"); 
    2365511                            break; 
    2366512                        case Opcode.CM0_RSPLIT: 
    2367                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", null, null);"); 
     513                            code("r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", null, null);"); 
    2368514                            break; 
    2369515                        case Opcode.CM0_RENDER: 
    2370                             code(buffer, indent, "r" + opcode.r1 + " = r" + opcode.r2 + ".renders({});"); 
     516                            code("r" + opcode.r1 + " = r" + opcode.r2 + ".renders({});"); 
    2371517                            break; 
    2372518                    } 
     
    2376522                    { 
    2377523                        case Opcode.CM1_JOIN: 
    2378                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_join(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     524                            code("r" + opcode.r1 + " = ul4._me_join(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2379525                            break; 
    2380526                        case Opcode.CM1_STRIP: 
    2381                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_strip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     527                            code("r" + opcode.r1 + " = ul4._me_strip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2382528                            break; 
    2383529                        case Opcode.CM1_LSTRIP: 
    2384                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_lstrip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     530                            code("r" + opcode.r1 + " = ul4._me_lstrip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2385531                            break; 
    2386532                        case Opcode.CM1_RSTRIP: 
    2387                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rstrip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     533                            code("r" + opcode.r1 + " = ul4._me_rstrip(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2388534                            break; 
    2389535                        case Opcode.CM1_STARTSWITH: 
    2390                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_startswith(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     536                            code("r" + opcode.r1 + " = ul4._me_startswith(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2391537                            break; 
    2392538                        case Opcode.CM1_ENDSWITH: 
    2393                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_endswith(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     539                            code("r" + opcode.r1 + " = ul4._me_endswith(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2394540                            break; 
    2395541                        case Opcode.CM1_FORMAT: 
    2396                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_format(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     542                            code("r" + opcode.r1 + " = ul4._me_format(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2397543                            break; 
    2398544                        case Opcode.CM1_WITHLUM: 
    2399                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_withlum(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     545                            code("r" + opcode.r1 + " = ul4._me_withlum(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2400546                            break; 
    2401547                        case Opcode.CM1_WITHA: 
    2402                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_witha(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
     548                            code("r" + opcode.r1 + " = ul4._me_witha(r" + opcode.r2 + ", r" + opcode.r3 + ");"); 
    2403549                            break; 
    2404550                        case Opcode.CM1_SPLIT: 
    2405                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
     551                            code("r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2406552                            break; 
    2407553                        case Opcode.CM1_RSPLIT: 
    2408                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
     554                            code("r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2409555                            break; 
    2410556                        case Opcode.CM1_GET: 
    2411                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
     557                            code("r" + opcode.r1 + " = ul4._me_get(r" + opcode.r2 + ", r" + opcode.r3 + ", null);"); 
    2412558                            break; 
    2413559                        case Opcode.CM1_FIND: 
    2414                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", null, null);"); 
     560                            code("r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", null, null);"); 
    2415561                            break; 
    2416562                        case Opcode.CM1_RFIND: 
    2417                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", null, null);"); 
     563                            code("r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", null, null);"); 
    2418564                            break; 
    2419565                    } 
     
    2423569                    { 
    2424570                        case Opcode.CM2_SPLIT: 
    2425                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     571                            code("r" + opcode.r1 + " = ul4._me_split(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2426572                            break; 
    2427573                        case Opcode.CM2_RSPLIT: 
    2428                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     574                            code("r" + opcode.r1 + " = ul4._me_rsplit(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2429575                            break; 
    2430576                        case Opcode.CM2_REPLACE: 
    2431                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_replace(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     577                            code("r" + opcode.r1 + " = ul4._me_replace(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2432578                            break; 
    2433579                        case Opcode.CM2_GET: 
    2434                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_get(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
     580                            code("r" + opcode.r1 + " = ul4._me_get(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ");"); 
    2435581                            break; 
    2436582                        case Opcode.CM2_FIND: 
    2437                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", null);"); 
     583                            code("r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", null);"); 
    2438584                            break; 
    2439585                        case Opcode.CM2_RFIND: 
    2440                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", null);"); 
     586                            code("r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", null);"); 
    2441587                            break; 
    2442588                    } 
     
    2446592                    { 
    2447593                        case Opcode.CM3_FIND: 
    2448                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
     594                            code("r" + opcode.r1 + " = ul4._me_find(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2449595                            break; 
    2450596                        case Opcode.CM3_RFIND: 
    2451                             code(buffer, indent, "r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
     597                            code("r" + opcode.r1 + " = ul4._me_rfind(r" + opcode.r2 + ", r" + opcode.r3 + ", r" + opcode.r4 + ", r" + opcode.r5 + ");"); 
    2452598                            break; 
    2453599                    } 
     
    2457603                    { 
    2458604                        case Opcode.CMKW_RENDER: 
    2459                             code(buffer, indent, "r" + opcode.r1 + " = r" + opcode.r2 + ".renders(r" + opcode.r3 + ");"); 
     605                            code("r" + opcode.r1 + " = r" + opcode.r2 + ".renders(r" + opcode.r3 + ");"); 
    2460606                            break; 
    2461607                    } 
    2462608                    break; 
    2463609                case Opcode.OC_IF: 
    2464                     code(buffer, indent, "if (ul4._fu_bool(r" + opcode.r1 + "))"); 
    2465                     code(buffer, indent, "{"); 
     610                    code("if (ul4._fu_bool(r" + opcode.r1 + "))"); 
     611                    code("{"); 
    2466612                    indent++; 
    2467613                    break; 
    2468614                case Opcode.OC_ELSE: 
    2469615                    indent--; 
    2470                     code(buffer, indent, "}"); 
    2471                     code(buffer, indent, "else"); 
    2472                     code(buffer, indent, "{"); 
     616                    code("}"); 
     617                    code("else"); 
     618                    code("{"); 
    2473619                    indent++; 
    2474620                    break; 
    2475621                case Opcode.OC_ENDIF: 
    2476622                    indent--; 
    2477                     code(buffer, indent, "}"); 
     623                    code("}"); 
    2478624                    break; 
    2479625                case Opcode.OC_RENDER: 
    2480                     code(buffer, indent, "out = out.concat(r" + opcode.r1 + ".render(r" + opcode.r2 + "));"); 
     626                    code("out = out.concat(r" + opcode.r1 + ".render(r" + opcode.r2 + "));"); 
    2481627                    break; 
    2482628            } 
    2483629        } 
    2484         code(buffer, indent, "return out;"); 
    2485         code(buffer, indent, "//@@@ END template code"); 
     630        code("return out;"); 
     631        code("//@@@ END template code"); 
    2486632        indent--; 
    2487         code(buffer, indent, "})"); 
    2488         return buffer.toString(); 
     633        code("})"); 
     634        String result = buffer.toString(); 
     635        buffer = null; 
     636        return result; 
    2489637    } 
    2490638} 
  • library/src/com/livinglogic/ul4/Main.java

    r302 r336  
    1111    public static void main(String[] args) 
    1212    { 
    13         Template tmpl = Compiler.compile("<?print json(t)?>"); 
     13        InterpretedTemplate tmpl = Compiler.compile("<?print json(t)?>"); 
    1414        System.out.println(tmpl); 
    1515 
     
    2020        System.out.println("rendered " + (System.currentTimeMillis()-start)); 
    2121        System.out.println(output); 
     22        System.out.println(new JavascriptSource4Template(tmpl)); 
    2223    } 
    2324}