Changeset 3673:f6f6953add49 in livinglogic.python.xist

Show
Ignore:
Timestamp:
01/01/09 18:40:25 (10 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Generating the Python source from an UL4 template is now 20-25% faster.

This is done by mapping the opcode to a method via attribute lookup instead of
using if chains.

Files:
2 modified

Legend:

Unmodified
Added
Removed
  • NEWS.rst

    r3671 r3673  
     1Changes in 3.6.1 (released ??/??/2008) 
     2-------------------------------------- 
     3 
     4*   Generating the Python source from an UL4 template is now 20-25% faster. 
     5 
     6 
    17Changes in 3.6 (released 12/31/2008) 
    28------------------------------------ 
  • src/ll/ul4c.py

    r3659 r3673  
    788788        return "".join(self.iterdump()) 
    789789 
     790    def _pythonsource_dispatch_None(self, opcode): 
     791        self.lines.append("%syield %r" % (self.indent, opcode.location.code)) 
     792    def _pythonsource_dispatch_loadstr(self, opcode): 
     793        self.lines.append("%sreg%d = %r" % (self.indent, opcode.r1, opcode.arg)) 
     794    def _pythonsource_dispatch_loadint(self, opcode): 
     795        self.lines.append("%sreg%d = %s" % (self.indent, opcode.r1, opcode.arg)) 
     796    def _pythonsource_dispatch_loadfloat(self, opcode): 
     797        self.lines.append("%sreg%d = %s" % (self.indent, opcode.r1, opcode.arg)) 
     798    def _pythonsource_dispatch_loadnone(self, opcode): 
     799        self.lines.append("%sreg%d = None" % (self.indent, opcode.r1)) 
     800    def _pythonsource_dispatch_loadfalse(self, opcode): 
     801        self.lines.append("%sreg%d = False" % (self.indent, opcode.r1)) 
     802    def _pythonsource_dispatch_loadtrue(self, opcode): 
     803        self.lines.append("%sreg%d = True" % (self.indent, opcode.r1)) 
     804    def _pythonsource_dispatch_loaddate(self, opcode): 
     805        self.lines.append("%sreg%d = datetime.datetime(%s)" % (self.indent, opcode.r1, ", ".join(str(int(p)) for p in datesplitter.split(opcode.arg)))) 
     806    def _pythonsource_dispatch_loadcolor(self, opcode): 
     807        self.lines.append("%sreg%d = color.Color(0x%s, 0x%s, 0x%s, 0x%s)" % (self.indent, opcode.r1, opcode.arg[:2], opcode.arg[2:4], opcode.arg[4:6], opcode.arg[6:])) 
     808    def _pythonsource_dispatch_buildlist(self, opcode): 
     809        self.lines.append("%sreg%d = []" % (self.indent, opcode.r1)) 
     810    def _pythonsource_dispatch_builddict(self, opcode): 
     811        self.lines.append("%sreg%d = {}" % (self.indent, opcode.r1)) 
     812    def _pythonsource_dispatch_addlist(self, opcode): 
     813        self.lines.append("%sreg%d.append(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     814    def _pythonsource_dispatch_adddict(self, opcode): 
     815        self.lines.append("%sreg%d[reg%d] = reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     816    def _pythonsource_dispatch_updatedict(self, opcode): 
     817        self.lines.append("%sreg%d.update(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     818    def _pythonsource_dispatch_loadvar(self, opcode): 
     819        self.lines.append("%sreg%d = variables[%r]" % (self.indent, opcode.r1, opcode.arg)) 
     820    def _pythonsource_dispatch_storevar(self, opcode): 
     821        self.lines.append("%svariables[%r] = reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     822    def _pythonsource_dispatch_addvar(self, opcode): 
     823        self.lines.append("%svariables[%r] += reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     824    def _pythonsource_dispatch_subvar(self, opcode): 
     825        self.lines.append("%svariables[%r] -= reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     826    def _pythonsource_dispatch_mulvar(self, opcode): 
     827        self.lines.append("%svariables[%r] *= reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     828    def _pythonsource_dispatch_truedivvar(self, opcode): 
     829        self.lines.append("%svariables[%r] /= reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     830    def _pythonsource_dispatch_floordivvar(self, opcode): 
     831        self.lines.append("%svariables[%r] //= reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     832    def _pythonsource_dispatch_modvar(self, opcode): 
     833        self.lines.append("%svariables[%r] %%= reg%d" % (self.indent, opcode.arg, opcode.r1)) 
     834    def _pythonsource_dispatch_delvar(self, opcode): 
     835        self.lines.append("%sdel variables[%r]" % (self.indent, opcode.arg)) 
     836    def _pythonsource_dispatch_getattr(self, opcode): 
     837        self.lines.append("%sreg%d = reg%d[%r]" % (self.indent, opcode.r1, opcode.r2, opcode.arg)) 
     838    def _pythonsource_dispatch_getitem(self, opcode): 
     839        self.lines.append("%sreg%d = reg%d[reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     840    def _pythonsource_dispatch_getslice12(self, opcode): 
     841        self.lines.append("%sreg%d = reg%d[reg%d:reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
     842    def _pythonsource_dispatch_getslice1(self, opcode): 
     843        self.lines.append("%sreg%d = reg%d[reg%d:]" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     844    def _pythonsource_dispatch_getslice2(self, opcode): 
     845        self.lines.append("%sreg%d = reg%d[:reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     846    def _pythonsource_dispatch_print(self, opcode): 
     847        self.lines.append("%sif reg%d is not None: yield unicode(reg%d)" % (self.indent, opcode.r1, opcode.r1)) 
     848    def _pythonsource_dispatch_printx(self, opcode): 
     849        self.lines.append("%sif reg%d is not None: yield xmlescape(unicode(reg%d))" % (self.indent, opcode.r1, opcode.r1)) 
     850    def _pythonsource_dispatch_for(self, opcode): 
     851        self.lines.append("%sfor reg%d in reg%d:" % (self.indent, opcode.r1, opcode.r2)) 
     852        self.indent += "\t" 
     853    def _pythonsource_dispatch_endfor(self, opcode): 
     854        # we don't have to check for empty loops here, as a ``<?for?>`` tag always generates at least one ``storevar`` opcode inside the loop 
     855        self.indent = self.indent[:-1] 
     856        self.lines.append("%s# end for" % self.indent) 
     857    def _pythonsource_dispatch_break(self, opcode): 
     858        self.lines.append("%sbreak" % self.indent) 
     859    def _pythonsource_dispatch_continue(self, opcode): 
     860        self.lines.append("%scontinue" % self.indent) 
     861    def _pythonsource_dispatch_not(self, opcode): 
     862        self.lines.append("%sreg%d = not reg%d" % (self.indent, opcode.r1, opcode.r2)) 
     863    def _pythonsource_dispatch_neg(self, opcode): 
     864        self.lines.append("%sreg%d = -reg%d" % (self.indent, opcode.r1, opcode.r2)) 
     865    def _pythonsource_dispatch_contains(self, opcode): 
     866        self.lines.append("%sreg%d = reg%d in reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     867    def _pythonsource_dispatch_notcontains(self, opcode): 
     868        self.lines.append("%sreg%d = reg%d not in reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     869    def _pythonsource_dispatch_eq(self, opcode): 
     870        self.lines.append("%sreg%d = reg%d == reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     871    def _pythonsource_dispatch_ne(self, opcode): 
     872        self.lines.append("%sreg%d = reg%d != reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     873    def _pythonsource_dispatch_lt(self, opcode): 
     874        self.lines.append("%sreg%d = reg%d < reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     875    def _pythonsource_dispatch_le(self, opcode): 
     876        self.lines.append("%sreg%d = reg%d <= reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     877    def _pythonsource_dispatch_gt(self, opcode): 
     878        self.lines.append("%sreg%d = reg%d > reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     879    def _pythonsource_dispatch_ge(self, opcode): 
     880        self.lines.append("%sreg%d = reg%d >= reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     881    def _pythonsource_dispatch_add(self, opcode): 
     882        self.lines.append("%sreg%d = reg%d + reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     883    def _pythonsource_dispatch_sub(self, opcode): 
     884        self.lines.append("%sreg%d = reg%d - reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     885    def _pythonsource_dispatch_mul(self, opcode): 
     886        self.lines.append("%sreg%d = reg%d * reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     887    def _pythonsource_dispatch_floordiv(self, opcode): 
     888        self.lines.append("%sreg%d = reg%d // reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     889    def _pythonsource_dispatch_truediv(self, opcode): 
     890        self.lines.append("%sreg%d = reg%d / reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     891    def _pythonsource_dispatch_and(self, opcode): 
     892        self.lines.append("%sreg%d = reg%d and reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     893    def _pythonsource_dispatch_or(self, opcode): 
     894        self.lines.append("%sreg%d = reg%d or reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     895    def _pythonsource_dispatch_mod(self, opcode): 
     896        self.lines.append("%sreg%d = reg%d %% reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     897    def _pythonsource_dispatch_mod(self, opcode): 
     898        self.lines.append("%sreg%d = reg%d %% reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     899    def _pythonsource_dispatch_callfunc0(self, opcode): 
     900        try: 
     901            getattr(self, "_pythonsource_dispatch_callfunc0_%s" % opcode.arg)(opcode) 
     902        except AttributeError: 
     903            raise UnknownFunctionError(opcode.arg) 
     904    def _pythonsource_dispatch_callfunc1(self, opcode): 
     905        try: 
     906            getattr(self, "_pythonsource_dispatch_callfunc1_%s" % opcode.arg)(opcode) 
     907        except AttributeError: 
     908            raise UnknownFunctionError(opcode.arg) 
     909    def _pythonsource_dispatch_callfunc2(self, opcode): 
     910        try: 
     911            getattr(self, "_pythonsource_dispatch_callfunc2_%s" % opcode.arg)(opcode) 
     912        except AttributeError: 
     913            raise UnknownFunctionError(opcode.arg) 
     914    def _pythonsource_dispatch_callfunc3(self, opcode): 
     915        try: 
     916            getattr(self, "_pythonsource_dispatch_callfunc3_%s" % opcode.arg)(opcode) 
     917        except AttributeError: 
     918            raise UnknownFunctionError(opcode.arg) 
     919    def _pythonsource_dispatch_callfunc4(self, opcode): 
     920        try: 
     921            getattr(self, "_pythonsource_dispatch_callfunc4_%s" % opcode.arg)(opcode) 
     922        except AttributeError: 
     923            raise UnknownFunctionError(opcode.arg) 
     924    def _pythonsource_dispatch_callmeth0(self, opcode): 
     925        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "isoformat", "r", "g", "b", "a", "hls", "hlsa", "hsv", "hsva", "lum"): 
     926            self.lines.append("%sreg%d = reg%d.%s()" % (self.indent, opcode.r1, opcode.r2, opcode.arg)) 
     927        elif opcode.arg == "items": 
     928            self.lines.append("%sreg%d = reg%d.iteritems()" % (self.indent, opcode.r1, opcode.r2)) 
     929        else: 
     930            raise UnknownMethodError(opcode.arg) 
     931    def _pythonsource_dispatch_callmeth1(self, opcode): 
     932        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "startswith", "endswith", "find", "get", "withlum", "witha"): 
     933            self.lines.append("%sreg%d = reg%d.%s(reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3)) 
     934        elif opcode.arg == "format": 
     935            self.lines.append("%sreg%d = ul4c._format(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     936        else: 
     937            raise UnknownMethodError(opcode.arg) 
     938    def _pythonsource_dispatch_callmeth2(self, opcode): 
     939        if opcode.arg in ("split", "rsplit", "find", "replace", "get"): 
     940            self.lines.append("%sreg%d = reg%d.%s(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4)) 
     941        else: 
     942            raise UnknownMethodError(opcode.arg) 
     943    def _pythonsource_dispatch_callmeth3(self, opcode): 
     944        if opcode.arg == "find": 
     945            self.lines.append("%sreg%d = reg%d.%s(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4, opcode.r5)) 
     946        else: 
     947            raise UnknownMethodError(opcode.arg) 
     948    def _pythonsource_dispatch_if(self, opcode): 
     949        self.lines.append("%sif reg%d:" % (self.indent, opcode.r1)) 
     950        self.indent += "\t" 
     951    def _pythonsource_dispatch_else(self, opcode): 
     952        if self.lastopcode == "if": 
     953            self.lines[-1] += " pass" 
     954        self.indent = self.indent[:-1] 
     955        self.lines.append("%selse:" % self.indent) 
     956        self.indent += "\t" 
     957    def _pythonsource_dispatch_endif(self, opcode): 
     958        if self.lastopcode in ("if", "else"): 
     959            self.lines[-1] += " pass" 
     960        self.indent = self.indent[:-1] 
     961        self.lines.append("%s# end if" % self.indent) 
     962    def _pythonsource_dispatch_render(self, opcode): 
     963        self.lines.append('%sfor chunk in reg%d(**dict((key.encode("utf-8"), value) for (key, value) in reg%d.iteritems())): yield chunk' % (self.indent, opcode.r1, opcode.r2)) 
     964    def _pythonsource_dispatch_callfunc0_now(self, opcode): 
     965        self.lines.append("%sreg%d = datetime.datetime.now()" % (self.indent, opcode.r1)) 
     966    def _pythonsource_dispatch_callfunc0_vars(self, opcode): 
     967        self.lines.append("%sreg%d = variables" % (self.indent, opcode.r1)) 
     968    def _pythonsource_dispatch_callfunc1_xmlescape(self, opcode): 
     969        self.lines.append("%sreg%d = xmlescape(unicode(reg%d)) if reg%d is not None else u''" % (self.indent, opcode.r1, opcode.r2, opcode.r2)) 
     970    def _pythonsource_dispatch_callfunc1_csv(self, opcode): 
     971        self.lines.append("%sreg%d = ul4c._csv(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     972    def _pythonsource_dispatch_callfunc1_json(self, opcode): 
     973        self.lines.append("%sreg%d = json.dumps(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     974    def _pythonsource_dispatch_callfunc1_str(self, opcode): 
     975        self.lines.append("%sreg%d = unicode(reg%d) if reg%d is not None else u''" % (self.indent, opcode.r1, opcode.r2, opcode.r2)) 
     976    def _pythonsource_dispatch_callfunc1_int(self, opcode): 
     977        self.lines.append("%sreg%d = int(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     978    def _pythonsource_dispatch_callfunc1_bool(self, opcode): 
     979        self.lines.append("%sreg%d = bool(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     980    def _pythonsource_dispatch_callfunc1_len(self, opcode): 
     981        self.lines.append("%sreg%d = len(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     982    def _pythonsource_dispatch_callfunc1_enumerate(self, opcode): 
     983        self.lines.append("%sreg%d = enumerate(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     984    def _pythonsource_dispatch_callfunc1_isnone(self, opcode): 
     985        self.lines.append("%sreg%d = reg%d is None" % (self.indent, opcode.r1, opcode.r2)) 
     986    def _pythonsource_dispatch_callfunc1_isstr(self, opcode): 
     987        self.lines.append("%sreg%d = isinstance(reg%d, basestring)" % (self.indent, opcode.r1, opcode.r2)) 
     988    def _pythonsource_dispatch_callfunc1_isint(self, opcode): 
     989        self.lines.append("%sreg%d = isinstance(reg%d, (int, long)) and not isinstance(reg%d, bool)" % (self.indent, opcode.r1, opcode.r2, opcode.r2)) 
     990    def _pythonsource_dispatch_callfunc1_isfloat(self, opcode): 
     991        self.lines.append("%sreg%d = isinstance(reg%d, float)" % (self.indent, opcode.r1, opcode.r2)) 
     992    def _pythonsource_dispatch_callfunc1_isbool(self, opcode): 
     993        self.lines.append("%sreg%d = isinstance(reg%d, bool)" % (self.indent, opcode.r1, opcode.r2)) 
     994    def _pythonsource_dispatch_callfunc1_isdate(self, opcode): 
     995        self.lines.append("%sreg%d = isinstance(reg%d, datetime.datetime)" % (self.indent, opcode.r1, opcode.r2)) 
     996    def _pythonsource_dispatch_callfunc1_islist(self, opcode): 
     997        self.lines.append("%sreg%d = isinstance(reg%d, (list, tuple))" % (self.indent, opcode.r1, opcode.r2)) 
     998    def _pythonsource_dispatch_callfunc1_isdict(self, opcode): 
     999        self.lines.append("%sreg%d = isinstance(reg%d, dict)" % (self.indent, opcode.r1, opcode.r2)) 
     1000    def _pythonsource_dispatch_callfunc1_istemplate(self, opcode): 
     1001        self.lines.append("%sreg%d = hasattr(reg%d, '__call__')" % (self.indent, opcode.r1, opcode.r2)) # this supports normal generators too 
     1002    def _pythonsource_dispatch_callfunc1_repr(self, opcode): 
     1003        self.lines.append("%sreg%d = ul4c._repr(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1004    def _pythonsource_dispatch_callfunc1_get(self, opcode): 
     1005        self.lines.append("%sreg%d = variables.get(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1006    def _pythonsource_dispatch_callfunc1_chr(self, opcode): 
     1007        self.lines.append("%sreg%d = unichr(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1008    def _pythonsource_dispatch_callfunc1_ord(self, opcode): 
     1009        self.lines.append("%sreg%d = ord(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1010    def _pythonsource_dispatch_callfunc1_hex(self, opcode): 
     1011        self.lines.append("%sreg%d = hex(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1012    def _pythonsource_dispatch_callfunc1_oct(self, opcode): 
     1013        self.lines.append("%sreg%d = ul4c._oct(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1014    def _pythonsource_dispatch_callfunc1_bin(self, opcode): 
     1015        self.lines.append("%sreg%d = ul4c._bin(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1016    def _pythonsource_dispatch_callfunc1_sorted(self, opcode): 
     1017        self.lines.append("%sreg%d = sorted(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1018    def _pythonsource_dispatch_callfunc1_range(self, opcode): 
     1019        self.lines.append("%sreg%d = xrange(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1020    def _pythonsource_dispatch_callfunc1_type(self, opcode): 
     1021        self.lines.append("%sreg%d = ul4c._type(reg%d)" % (self.indent, opcode.r1, opcode.r2)) 
     1022    def _pythonsource_dispatch_callfunc2_range(self, opcode): 
     1023        self.lines.append("%sreg%d = xrange(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     1024    def _pythonsource_dispatch_callfunc2_get(self, opcode): 
     1025        self.lines.append("%sreg%d = variables.get(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     1026    def _pythonsource_dispatch_callfunc2_zip(self, opcode): 
     1027        self.lines.append("%sreg%d = itertools.izip(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3)) 
     1028    def _pythonsource_dispatch_callfunc3_range(self, opcode): 
     1029        self.lines.append("%sreg%d = xrange(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
     1030    def _pythonsource_dispatch_callfunc3_zip(self, opcode): 
     1031        self.lines.append("%sreg%d = itertools.izip(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
     1032    def _pythonsource_dispatch_callfunc3_rgb(self, opcode): 
     1033        self.lines.append("%sreg%d = color.Color.fromrgb(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
     1034    def _pythonsource_dispatch_callfunc3_hls(self, opcode): 
     1035        self.lines.append("%sreg%d = color.Color.fromhls(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
     1036    def _pythonsource_dispatch_callfunc3_hsv(self, opcode): 
     1037        self.lines.append("%sreg%d = color.Color.fromhsv(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
     1038    def _pythonsource_dispatch_callfunc4_rgb(self, opcode): 
     1039        self.lines.append("%sreg%d = color.Color.fromrgb(reg%d, reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5)) 
     1040    def _pythonsource_dispatch_callfunc4_hls(self, opcode): 
     1041        self.lines.append("%sreg%d = color.Color.fromhls(reg%d, reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5)) 
     1042    def _pythonsource_dispatch_callfunc4_hsv(self, opcode): 
     1043        self.lines.append("%sreg%d = color.Color.fromhsv(reg%d, reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5)) 
     1044 
    7901045    def pythonsource(self, function=None): 
    7911046        """ 
     
    7931048        the code will be wrapped in a function with this name. 
    7941049        """ 
    795         indent = 0 
    796         output = [] 
    797  
    798         def _code(code): 
    799             output.append("%s%s" % ("\t"*indent, code)) 
     1050        self.indent = "" 
     1051        self.lines = [] 
    8001052 
    8011053        if function is not None: 
    802             _code("def %s(**variables):" % function) 
    803             indent += 1 
    804         _code("import sys, datetime, itertools") 
    805         _code("try:") 
    806         indent += 1 
    807         _code("import json") 
    808         indent -= 1 
    809         _code("except ImportError:") 
    810         indent += 1 
    811         _code("import simplejson as json") 
    812         indent -= 1 
    813         _code("from ll.misc import xmlescape") 
    814         _code("from ll import ul4c, color") 
    815         _code("source = %r" % self.source) 
    816         _code('variables = dict((key.decode("utf-8"), value) for (key, value) in variables.iteritems())') # FIXME: This can be dropped in Python 3.0 where strings are unicode 
     1054            self.lines.append("%sdef %s(**variables):" % (self.indent, function)) 
     1055            self.indent += "\t" 
     1056        self.lines.append("%simport sys, datetime, itertools" % self.indent) 
     1057        self.lines.append("%stry:" % self.indent) 
     1058        self.indent += "\t" 
     1059        self.lines.append("%simport json" % self.indent) 
     1060        self.indent = self.indent[:-1] 
     1061        self.lines.append("%sexcept ImportError:" % self.indent) 
     1062        self.indent += "\t" 
     1063        self.lines.append("%simport simplejson as json" % self.indent) 
     1064        self.indent = self.indent[:-1] 
     1065        self.lines.append("%sfrom ll.misc import xmlescape" % self.indent) 
     1066        self.lines.append("%sfrom ll import ul4c, color" % self.indent) 
     1067        self.lines.append("%ssource = %r" % (self.indent, self.source)) 
     1068        self.lines.append('%svariables = dict((key.decode("utf-8"), value) for (key, value) in variables.iteritems())' % self.indent) # FIXME: This can be dropped in Python 3.0 where strings are unicode 
    8171069        locations = [] 
    8181070        lines2locs = [] 
     
    8261078        locations = tuple(locations) 
    8271079        lines2locs = tuple(lines2locs) 
    828         _code("".join("reg%d = " % i for i in xrange(10)) + "None") 
    829  
    830         _code("try:") 
    831         indent += 1 
    832         _code("startline = sys._getframe().f_lineno+1") # The source line of the first opcode 
     1080        self.lines.append("%sreg0 = reg1 = reg2 = reg3 = reg4 = reg5 = reg6 = reg7 = reg8 = reg9 = None" % self.indent) 
     1081        self.lines.append("%stry:" % self.indent) 
     1082        self.indent += "\t" 
     1083        self.lines.append("%sstartline = sys._getframe().f_lineno+1" % self.indent) # The source line of the first opcode 
    8331084        try: 
    834             lastopcode = None 
     1085            self.lastopcode = None 
    8351086            for opcode in self.opcodes: 
    8361087                # The following code ensures that each opcode outputs exactly one source code line 
    8371088                # This makes it possible in case of an error to find out which opcode produced the error 
    838                 if opcode.code is None: 
    839                     _code("yield %r" % opcode.location.code) 
    840                 elif opcode.code == "loadstr": 
    841                     _code("reg%d = %r" % (opcode.r1, opcode.arg)) 
    842                 elif opcode.code == "loadint": 
    843                     _code("reg%d = %s" % (opcode.r1, opcode.arg)) 
    844                 elif opcode.code == "loadfloat": 
    845                     _code("reg%d = %s" % (opcode.r1, opcode.arg)) 
    846                 elif opcode.code == "loadnone": 
    847                     _code("reg%d = None" % opcode.r1) 
    848                 elif opcode.code == "loadfalse": 
    849                     _code("reg%d = False" % opcode.r1) 
    850                 elif opcode.code == "loadtrue": 
    851                     _code("reg%d = True" % opcode.r1) 
    852                 elif opcode.code == "loaddate": 
    853                     _code("reg%d = datetime.datetime(%s)" % (opcode.r1, ", ".join(str(int(p)) for p in datesplitter.split(opcode.arg)))) 
    854                 elif opcode.code == "loadcolor": 
    855                     _code("reg%d = color.Color(0x%s, 0x%s, 0x%s, 0x%s)" % (opcode.r1, opcode.arg[:2], opcode.arg[2:4], opcode.arg[4:6], opcode.arg[6:])) 
    856                 elif opcode.code == "buildlist": 
    857                     _code("reg%d = []" % opcode.r1) 
    858                 elif opcode.code == "builddict": 
    859                     _code("reg%d = {}" % opcode.r1) 
    860                 elif opcode.code == "addlist": 
    861                     _code("reg%d.append(reg%d)" % (opcode.r1, opcode.r2)) 
    862                 elif opcode.code == "adddict": 
    863                     _code("reg%d[reg%d] = reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    864                 elif opcode.code == "updatedict": 
    865                     _code("reg%d.update(reg%d)" % (opcode.r1, opcode.r2)) 
    866                 elif opcode.code == "loadvar": 
    867                     _code("reg%d = variables[%r]" % (opcode.r1, opcode.arg)) 
    868                 elif opcode.code == "storevar": 
    869                     _code("variables[%r] = reg%d" % (opcode.arg, opcode.r1)) 
    870                 elif opcode.code == "addvar": 
    871                     _code("variables[%r] += reg%d" % (opcode.arg, opcode.r1)) 
    872                 elif opcode.code == "subvar": 
    873                     _code("variables[%r] -= reg%d" % (opcode.arg, opcode.r1)) 
    874                 elif opcode.code == "mulvar": 
    875                     _code("variables[%r] *= reg%d" % (opcode.arg, opcode.r1)) 
    876                 elif opcode.code == "truedivvar": 
    877                     _code("variables[%r] /= reg%d" % (opcode.arg, opcode.r1)) 
    878                 elif opcode.code == "floordivvar": 
    879                     _code("variables[%r] //= reg%d" % (opcode.arg, opcode.r1)) 
    880                 elif opcode.code == "modvar": 
    881                     _code("variables[%r] %%= reg%d" % (opcode.arg, opcode.r1)) 
    882                 elif opcode.code == "delvar": 
    883                     _code("del variables[%r]" % opcode.arg) 
    884                 elif opcode.code == "getattr": 
    885                     _code("reg%d = reg%d[%r]" % (opcode.r1, opcode.r2, opcode.arg)) 
    886                 elif opcode.code == "getitem": 
    887                     _code("reg%d = reg%d[reg%d]" % (opcode.r1, opcode.r2, opcode.r3)) 
    888                 elif opcode.code == "getslice12": 
    889                     _code("reg%d = reg%d[reg%d:reg%d]" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
    890                 elif opcode.code == "getslice1": 
    891                     _code("reg%d = reg%d[reg%d:]" % (opcode.r1, opcode.r2, opcode.r3)) 
    892                 elif opcode.code == "getslice2": 
    893                     _code("reg%d = reg%d[:reg%d]" % (opcode.r1, opcode.r2, opcode.r3)) 
    894                 elif opcode.code == "print": 
    895                     _code("if reg%d is not None: yield unicode(reg%d)" % (opcode.r1, opcode.r1)) 
    896                 elif opcode.code == "printx": 
    897                     _code("if reg%d is not None: yield xmlescape(unicode(reg%d))" % (opcode.r1, opcode.r1)) 
    898                 elif opcode.code == "for": 
    899                     _code("for reg%d in reg%d:" % (opcode.r1, opcode.r2)) 
    900                     indent += 1 
    901                 elif opcode.code == "endfor": 
    902                     # we don't have to check for empty loops here, as a ``<?for?>`` tag always generates at least one ``storevar`` opcode inside the loop 
    903                     indent -= 1 
    904                     _code("# end for") 
    905                 elif opcode.code == "break": 
    906                     _code("break") 
    907                 elif opcode.code == "continue": 
    908                     _code("continue") 
    909                 elif opcode.code == "not": 
    910                     _code("reg%d = not reg%d" % (opcode.r1, opcode.r2)) 
    911                 elif opcode.code == "neg": 
    912                     _code("reg%d = -reg%d" % (opcode.r1, opcode.r2)) 
    913                 elif opcode.code == "contains": 
    914                     _code("reg%d = reg%d in reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    915                 elif opcode.code == "notcontains": 
    916                     _code("reg%d = reg%d not in reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    917                 elif opcode.code == "eq": 
    918                     _code("reg%d = reg%d == reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    919                 elif opcode.code == "ne": 
    920                     _code("reg%d = reg%d != reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    921                 elif opcode.code == "lt": 
    922                     _code("reg%d = reg%d < reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    923                 elif opcode.code == "le": 
    924                     _code("reg%d = reg%d <= reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    925                 elif opcode.code == "gt": 
    926                     _code("reg%d = reg%d > reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    927                 elif opcode.code == "ge": 
    928                     _code("reg%d = reg%d >= reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    929                 elif opcode.code == "add": 
    930                     _code("reg%d = reg%d + reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    931                 elif opcode.code == "sub": 
    932                     _code("reg%d = reg%d - reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    933                 elif opcode.code == "mul": 
    934                     _code("reg%d = reg%d * reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    935                 elif opcode.code == "floordiv": 
    936                     _code("reg%d = reg%d // reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    937                 elif opcode.code == "truediv": 
    938                     _code("reg%d = reg%d / reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    939                 elif opcode.code == "and": 
    940                     _code("reg%d = reg%d and reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    941                 elif opcode.code == "or": 
    942                     _code("reg%d = reg%d or reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    943                 elif opcode.code == "mod": 
    944                     _code("reg%d = reg%d %% reg%d" % (opcode.r1, opcode.r2, opcode.r3)) 
    945                 elif opcode.code == "callfunc0": 
    946                     if opcode.arg == "now": 
    947                         _code("reg%d = datetime.datetime.now()" % opcode.r1) 
    948                     elif opcode.arg == "vars": 
    949                         _code("reg%d = variables" % opcode.r1) 
    950                     else: 
    951                         raise UnknownFunctionError(opcode.arg) 
    952                 elif opcode.code == "callfunc1": 
    953                     if opcode.arg == "xmlescape": 
    954                         _code("reg%d = xmlescape(unicode(reg%d)) if reg%d is not None else u''" % (opcode.r1, opcode.r2, opcode.r2)) 
    955                     elif opcode.arg == "csv": 
    956                         _code("reg%d = ul4c._csv(reg%d)" % (opcode.r1, opcode.r2)) 
    957                     elif opcode.arg == "json": 
    958                         _code("reg%d = json.dumps(reg%d)" % (opcode.r1, opcode.r2)) 
    959                     elif opcode.arg == "str": 
    960                         _code("reg%d = unicode(reg%d) if reg%d is not None else u''" % (opcode.r1, opcode.r2, opcode.r2)) 
    961                     elif opcode.arg == "int": 
    962                         _code("reg%d = int(reg%d)" % (opcode.r1, opcode.r2)) 
    963                     elif opcode.arg == "bool": 
    964                         _code("reg%d = bool(reg%d)" % (opcode.r1, opcode.r2)) 
    965                     elif opcode.arg == "len": 
    966                         _code("reg%d = len(reg%d)" % (opcode.r1, opcode.r2)) 
    967                     elif opcode.arg == "enumerate": 
    968                         _code("reg%d = enumerate(reg%d)" % (opcode.r1, opcode.r2)) 
    969                     elif opcode.arg == "isnone": 
    970                         _code("reg%d = reg%d is None" % (opcode.r1, opcode.r2)) 
    971                     elif opcode.arg == "isstr": 
    972                         _code("reg%d = isinstance(reg%d, basestring)" % (opcode.r1, opcode.r2)) 
    973                     elif opcode.arg == "isint": 
    974                         _code("reg%d = isinstance(reg%d, (int, long)) and not isinstance(reg%d, bool)" % (opcode.r1, opcode.r2, opcode.r2)) 
    975                     elif opcode.arg == "isfloat": 
    976                         _code("reg%d = isinstance(reg%d, float)" % (opcode.r1, opcode.r2)) 
    977                     elif opcode.arg == "isbool": 
    978                         _code("reg%d = isinstance(reg%d, bool)" % (opcode.r1, opcode.r2)) 
    979                     elif opcode.arg == "isdate": 
    980                         _code("reg%d = isinstance(reg%d, datetime.datetime)" % (opcode.r1, opcode.r2)) 
    981                     elif opcode.arg == "islist": 
    982                         _code("reg%d = isinstance(reg%d, (list, tuple))" % (opcode.r1, opcode.r2)) 
    983                     elif opcode.arg == "isdict": 
    984                         _code("reg%d = isinstance(reg%d, dict)" % (opcode.r1, opcode.r2)) 
    985                     elif opcode.arg == "istemplate": 
    986                         _code("reg%d = hasattr(reg%d, '__call__')" % (opcode.r1, opcode.r2)) # this supports normal generators too. 
    987                     elif opcode.arg == "repr": 
    988                         _code("reg%d = ul4c._repr(reg%d)" % (opcode.r1, opcode.r2)) 
    989                     elif opcode.arg == "get": 
    990                         _code("reg%d = variables.get(reg%d)" % (opcode.r1, opcode.r2)) 
    991                     elif opcode.arg == "chr": 
    992                         _code("reg%d = unichr(reg%d)" % (opcode.r1, opcode.r2)) 
    993                     elif opcode.arg == "ord": 
    994                         _code("reg%d = ord(reg%d)" % (opcode.r1, opcode.r2)) 
    995                     elif opcode.arg == "hex": 
    996                         _code("reg%d = hex(reg%d)" % (opcode.r1, opcode.r2)) 
    997                     elif opcode.arg == "oct": 
    998                         _code('reg%d = ul4c._oct(reg%d)' % (opcode.r1, opcode.r2)) 
    999                     elif opcode.arg == "bin": 
    1000                         _code('reg%d = ul4c._bin(reg%d)' % (opcode.r1, opcode.r2)) 
    1001                     elif opcode.arg == "sorted": 
    1002                         _code("reg%d = sorted(reg%d)" % (opcode.r1, opcode.r2)) 
    1003                     elif opcode.arg == "range": 
    1004                         _code("reg%d = xrange(reg%d)" % (opcode.r1, opcode.r2)) 
    1005                     elif opcode.arg == "type": 
    1006                         _code("reg%d = ul4c._type(reg%d)" % (opcode.r1, opcode.r2)) 
    1007                     else: 
    1008                         raise UnknownFunctionError(opcode.arg) 
    1009                 elif opcode.code == "callfunc2": 
    1010                     if opcode.arg == "range": 
    1011                         _code("reg%d = xrange(reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3)) 
    1012                     elif opcode.arg == "get": 
    1013                         _code("reg%d = variables.get(reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3)) 
    1014                     elif opcode.arg == "zip": 
    1015                         _code("reg%d = itertools.izip(reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3)) 
    1016                     else: 
    1017                         raise UnknownFunctionError(opcode.arg) 
    1018                 elif opcode.code == "callfunc3": 
    1019                     if opcode.arg == "range": 
    1020                         _code("reg%d = xrange(reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
    1021                     elif opcode.arg == "zip": 
    1022                         _code("reg%d = itertools.izip(reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
    1023                     elif opcode.arg == "rgb": 
    1024                         _code("reg%d = color.Color.fromrgb(reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
    1025                     elif opcode.arg == "hls": 
    1026                         _code("reg%d = color.Color.fromhls(reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
    1027                     elif opcode.arg == "hsv": 
    1028                         _code("reg%d = color.Color.fromhsv(reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4)) 
    1029                     else: 
    1030                         raise UnknownFunctionError(opcode.arg) 
    1031                 elif opcode.code == "callfunc4": 
    1032                     if opcode.arg == "rgb": 
    1033                         _code("reg%d = color.Color.fromrgb(reg%d, reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5)) 
    1034                     if opcode.arg == "hls": 
    1035                         _code("reg%d = color.Color.fromhls(reg%d, reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5)) 
    1036                     if opcode.arg == "hsv": 
    1037                         _code("reg%d = color.Color.fromhsv(reg%d, reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5)) 
    1038                     else: 
    1039                         raise UnknownFunctionError(opcode.arg) 
    1040                 elif opcode.code == "callmeth0": 
    1041                     if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "isoformat", "r", "g", "b", "a", "hls", "hlsa", "hsv", "hsva", "lum"): 
    1042                         _code("reg%d = reg%d.%s()" % (opcode.r1, opcode.r2, opcode.arg)) 
    1043                     elif opcode.arg == "items": 
    1044                         _code("reg%d = reg%d.iteritems()" % (opcode.r1, opcode.r2)) 
    1045                     else: 
    1046                         raise UnknownMethodError(opcode.arg) 
    1047                 elif opcode.code == "callmeth1": 
    1048                     if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "startswith", "endswith", "find", "get", "withlum", "witha"): 
    1049                         _code("reg%d = reg%d.%s(reg%d)" % (opcode.r1, opcode.r2, opcode.arg, opcode.r3)) 
    1050                     elif opcode.arg == "format": 
    1051                         _code("reg%d = ul4c._format(reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.r3)) 
    1052                     else: 
    1053                         raise UnknownMethodError(opcode.arg) 
    1054                 elif opcode.code == "callmeth2": 
    1055                     if opcode.arg in ("split", "rsplit", "find", "replace", "get"): 
    1056                         _code("reg%d = reg%d.%s(reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4)) 
    1057                     else: 
    1058                         raise UnknownMethodError(opcode.arg) 
    1059                 elif opcode.code == "callmeth3": 
    1060                     if opcode.arg == "find": 
    1061                         _code("reg%d = reg%d.%s(reg%d, reg%d, reg%d)" % (opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4, opcode.r5)) 
    1062                     else: 
    1063                         raise UnknownMethodError(opcode.arg) 
    1064                 elif opcode.code == "if": 
    1065                     _code("if reg%d:" % opcode.r1) 
    1066                     indent += 1 
    1067                 elif opcode.code == "else": 
    1068                     if lastopcode == "if": 
    1069                         output[-1] += " pass" 
    1070                     indent -= 1 
    1071                     _code("else:") 
    1072                     indent += 1 
    1073                 elif opcode.code == "endif": 
    1074                     if lastopcode in ("if", "else"): 
    1075                         output[-1] += " pass" 
    1076                     indent -= 1 
    1077                     _code("# end if") 
    1078                 elif opcode.code == "render": 
    1079                     _code('for chunk in reg%d(**dict((key.encode("utf-8"), value) for (key, value) in reg%d.iteritems())): yield chunk' % (opcode.r1, opcode.r2)) 
    1080                 else: 
     1089                try: 
     1090                    getattr(self, "_pythonsource_dispatch_%s" % opcode.code)(opcode) 
     1091                except AttributeError: 
    10811092                    raise UnknownOpcodeError(opcode.code) 
    1082                 lastopcode = opcode.code 
     1093                self.lastopcode = opcode.code 
    10831094        except Exception, exc: 
    1084             raise Error(opcode.location, exc) 
    1085         indent -= 1 
    1086         _code("except Exception, exc:") 
    1087         indent += 1 
    1088         _code("locations = %r" % (locations,)) 
    1089         _code("lines2locs = %r" % (lines2locs,)) 
    1090         _code("raise ul4c.Error(ul4c.Location(source, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]), exc)") 
    1091         return "\n".join(output) 
     1095            raise #Error(opcode.location, exc) 
     1096        self.indent = self.indent[:-1] 
     1097        self.lines.append("%sexcept Exception, exc:" % self.indent) 
     1098        self.indent += "\t" 
     1099        self.lines.append("%slocations = %r" % (self.indent, locations)) 
     1100        self.lines.append("%slines2locs = %r" % (self.indent, lines2locs)) 
     1101        self.lines.append("%sraise ul4c.Error(ul4c.Location(source, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]), exc)" % self.indent) 
     1102        result = "\n".join(self.lines) 
     1103        del self.lines 
     1104        del self.indent 
     1105        return result 
    10921106 
    10931107    def pythonfunction(self):