root/livinglogic.java.ul4/library/src/com/livinglogic/ul4/ul4c.py @ 125:d39e1f38f6ff

Revision 125:d39e1f38f6ff, 17.3 KB (checked in by Walter Doerwald <walter@…>, 11 years ago)

New render opcode (variables are passed as keyword arguments).

Line 
1# -*- coding: utf-8 -*-
2
3## Copyright 2008 by LivingLogic AG, Bayreuth/Germany
4## Copyright 2008 by Walter Dörwald
5##
6## All Rights Reserved
7##
8## See ll/__init__.py for the license
9
10
11import sys, re, StringIO
12
13import spark
14
15from com.livinglogic import ul4
16
17from java import lang
18
19###
20### helper functions for compiling
21###
22
23def _compile(template, tags):
24    opcodes = []
25    parseexpr = ExprParser().compile
26    parsestmt = StmtParser().compile
27    parsefor = ForParser().compile
28    parserender = RenderParser().compile
29
30    # This stack stores for each nested for/foritem/if/elif/else the following information:
31    # 1) Which construct we're in (i.e. "if" or "for")
32    # For ifs:
33    # 2) How many if's or elif's we have seen (this is used for simulating elif's via nested if's, for each additional elif, we have one more endif to add)
34    # 3) Whether we've already seen the else
35    stack = []
36    for location in tags:
37        try:
38            if location.type is None:
39                template.opcode(ul4.Opcode.OC_TEXT, location)
40            elif location.type == "print":
41                r = parseexpr(template, location)
42                template.opcode(ul4.Opcode.OC_PRINT, r, location)
43            elif location.type == "code":
44                parsestmt(template, location)
45            elif location.type == "if":
46                r = parseexpr(template, location)
47                template.opcode(ul4.Opcode.OC_IF, r, location)
48                stack.append(("if", 1, False))
49            elif location.type == "elif":
50                if not stack or stack[-1][0] != "if":
51                    raise ul4.BlockException("elif doesn't match any if")
52                elif stack[-1][2]:
53                    raise ul4.BlockException("else already seen in elif")
54                template.opcode(ul4.Opcode.OC_ELSE, location)
55                r = parseexpr(template, location)
56                template.opcode(ul4.Opcode.OC_IF, r, location)
57                stack[-1] = ("if", stack[-1][1]+1, False)
58            elif location.type == "else":
59                if not stack or stack[-1][0] != "if":
60                    raise ul4.BlockException("else doesn't match any if")
61                elif stack[-1][2]:
62                    raise ul4.BlockException("duplicate else")
63                template.opcode(ul4.Opcode.OC_ELSE, location)
64                stack[-1] = ("if", stack[-1][1], True)
65            elif location.type == "end":
66                if not stack:
67                    raise ul4.BlockException("not in any block")
68                code = location.code
69                if code:
70                    if code == "if":
71                        if stack[-1][0] != "if":
72                            raise ul4.BlockException("endif doesn't match any if")
73                    elif code == "for":
74                        if stack[-1][0] != "for":
75                            raise ul4.BlockException("endfor doesn't match any for")
76                    else:
77                        raise ul4.BlockException("illegal end value %r" % code)
78                last = stack.pop()
79                if last[0] == "if":
80                    for i in xrange(last[1]):
81                        template.opcode(ul4.Opcode.OC_ENDIF, location)
82                else: # last[0] == "for":
83                    template.opcode(ul4.Opcode.OC_ENDFOR, location)
84            elif location.type == "for":
85                parsefor(template, location)
86                stack.append(("for",))
87            elif location.type == "render":
88                parserender(template, location)
89            else: # Can't happen
90                raise ValueError("unknown tag %r" % location.type)
91        except ul4.LocationException, exc:
92            raise
93        except lang.Exception, exc:
94            raise ul4.LocationException(exc, location)
95    if stack:
96        raise ul4.BlockException("unclosed blocks")
97    return opcodes
98
99
100###
101### Parsers for different types of code
102###
103
104class ExprParser(spark.GenericParser):
105    emptyerror = "expression required"
106
107    def __init__(self, start="expr0"):
108        spark.GenericParser.__init__(self, start)
109
110    def compile(self, template, location):
111        if not location.code:
112            raise ValueError(self.emptyerror)
113        try:
114            ast = self.parse(ul4.Template.tokenizeCode(location))
115            registers = ul4.Registers()
116            return ast.compile(template, registers, location)
117        except ul4.LocationException, exc:
118            raise
119        except lang.Exception, exc:
120            raise ul4.LocationException(exc, location)
121
122    def typestring(self, token):
123        return token.getTokenType()
124
125    def error(self, token):
126        raise ul4.SyntaxException(token)
127
128    def makeconst(self, start, end, value):
129        if value is None:
130            return ul4.None(start, end)
131        elif value is True:
132            return ul4.True(start, end)
133        elif value is False:
134            return ul4.False(start, end)
135        elif isinstance(value, int):
136            return ul4.Int(start, end, value)
137        elif isinstance(value, float):
138            return ul4.Float(start, end, value)
139        elif isinstance(value, basestring):
140            return ul4.Str(start, end, value)
141        else:
142            raise TypeError("can't convert %r" % value)
143
144    # To implement operator precedence, each expression rule has the precedence in its name. The highest precedence is 11 for atomic expressions.
145    # Each expression can have only expressions as parts, which have the some or a higher precedence with two exceptions:
146    #    1) Expressions where there's no ambiguity, like the index for a getitem/getslice or function/method arguments;
147    #    2) Brackets, which can be used to boost the precedence of an expression to the level of an atomic expression.
148
149    def expr_atomic(self, (atom,)):
150        return atom
151    expr_atomic.spark = [
152        'expr11 ::= none',
153        'expr11 ::= true',
154        'expr11 ::= false',
155        'expr11 ::= str',
156        'expr11 ::= int',
157        'expr11 ::= float',
158        'expr11 ::= date',
159        'expr11 ::= name',
160    ]
161
162    def expr_emptylist(self, (_0, _1)):
163        return ul4.List(_0.start, _1.end)
164    expr_emptylist.spark = ['expr11 ::= [ ]']
165
166    def expr_buildlist(self, (_0, expr)):
167        list = ul4.List(_0.start, expr.end)
168        list.append(expr)
169        return list
170    expr_buildlist.spark = ['buildlist ::= [ expr0']
171
172    def expr_addlist(self, (list, _0, expr)):
173        list.append(expr)
174        list.end = expr.end
175        return list
176    expr_addlist.spark = ['buildlist ::= buildlist , expr0']
177
178    def expr_finishlist(self, (list, _0)):
179        list.end = _0.end
180        return list
181    expr_finishlist.spark = ['expr11 ::= buildlist ]']
182
183    def expr_finishlist1(self, (list, _0, _1)):
184        list.end = _1.end
185        return list
186    expr_finishlist1.spark = ['expr11 ::= buildlist , ]']
187
188    def expr_emptydict(self, (_0, _1)):
189        return ul4.Dict(_0.start, _1.end)
190    expr_emptydict.spark = ['expr11 ::= { }']
191
192    def expr_builddict(self, (_0, key, _1, value)):
193        dict = ul4.Dict(_0.start, value.end)
194        dict.append(key, value)
195        return dict
196    expr_builddict.spark = ['builddict ::= { expr0 : expr0']
197
198    def expr_adddict(self, (dict, _0, key, _1, value)):
199        dict.append(key, value)
200        dict.end = value.end
201        return dict
202    expr_adddict.spark = ['builddict ::= builddict , expr0 : expr0']
203
204    def expr_finishdict(self, (dict, _0)):
205        dict.end = _0.end
206        return dict
207    expr_finishdict.spark = ['expr11 ::= builddict }']
208
209    def expr_finishdict1(self, (dict, _0, _1)):
210        dict.end = _1.end
211        return dict
212    expr_finishdict1.spark = ['expr11 ::= builddict , }']
213
214    def expr_bracket(self, (_0, expr, _1)):
215        return expr
216    expr_bracket.spark = ['expr11 ::= ( expr0 )']
217
218    def expr_callfunc0(self, (name, _0, _1)):
219        return ul4.CallFunc(name.start, _1.end, name)
220    expr_callfunc0.spark = ['expr10 ::= name ( )']
221
222    def expr_callfunc1(self, (name, _0, arg0, _1)):
223        return ul4.CallFunc(name.start, _1.end, name, arg0)
224    expr_callfunc1.spark = ['expr10 ::= name ( expr0 )']
225
226    def expr_callfunc2(self, (name, _0, arg0, _1, arg1, _2)):
227        return ul4.CallFunc(name.start, _2.end, name, arg0, arg1)
228    expr_callfunc2.spark = ['expr10 ::= name ( expr0 , expr0 )']
229
230    def expr_callfunc3(self, (name, _0, arg0, _1, arg1, _2, arg2, _3)):
231        return ul4.CallFunc(name.start, _3.end, name, arg0, arg1, arg2)
232    expr_callfunc3.spark = ['expr10 ::= name ( expr0 , expr0 , expr0 )']
233
234    def expr_getattr(self, (expr, _0, name)):
235        return ul4.GetAttr(expr.start, name.end, expr, name)
236    expr_getattr.spark = ['expr9 ::= expr9 . name']
237
238    def expr_callmeth0(self, (expr, _0, name, _1, _2)):
239        return ul4.CallMeth(expr.start, _2.end, expr, name)
240    expr_callmeth0.spark = ['expr9 ::= expr9 . name ( )']
241
242    def expr_callmeth1(self, (expr, _0, name, _1, arg1, _2)):
243        return ul4.CallMeth(expr.start, _2.end, expr, name, arg1)
244    expr_callmeth1.spark = ['expr9 ::= expr9 . name ( expr0 )']
245
246    def expr_callmeth2(self, (expr, _0, name, _1, arg1, _2, arg2, _3)):
247        return ul4.CallMeth(expr.start, _3.end, expr, name, arg1, arg2)
248    expr_callmeth2.spark = ['expr9 ::= expr9 . name ( expr0 , expr0 )']
249
250    def expr_callmeth3(self, (expr, _0, name, _1, arg1, _2, arg2, _3, arg3, _4)):
251        return ul4.CallMeth(expr.start, _4.end, expr, name, arg1, arg2, arg3)
252    expr_callmeth3.spark = ['expr9 ::= expr9 . name ( expr0 , expr0 , expr0 )']
253
254    def expr_getitem(self, (expr, _0, key, _1)):
255        if isinstance(expr, ul4.Const) and isinstance(key, ul4.Const): # Constant folding
256            return self.makeconst(expr.start, _1.end, expr.value[key.value])
257        return ul4.GetItem(expr.start, _1.end, expr, key)
258    expr_getitem.spark = ['expr9 ::= expr9 [ expr0 ]']
259
260    def expr_getslice12(self, (expr, _0, index1, _1, index2, _2)):
261        if isinstance(expr, ul4.Const) and isinstance(index1, ul4.Const) and isinstance(index2, ul4.Const): # Constant folding
262            return self.makeconst(expr.start, _2.end, expr.value[index1.value:index1.value])
263        return ul4.GetSlice12(expr.start, _2.end, expr, index1, index2)
264    expr_getslice12.spark = ['expr8 ::= expr8 [ expr0 : expr0 ]']
265
266    def expr_getslice1(self, (expr, _0, index1, _1, _2)):
267        if isinstance(expr, ul4.Const) and isinstance(index1, ul4.Const): # Constant folding
268            return self.makeconst(expr.start, _2.end, expr.value[index1.value:])
269        return ul4.GetSlice1(expr.start, _2.end, expr, index1)
270    expr_getslice1.spark = ['expr8 ::= expr8 [ expr0 : ]']
271
272    def expr_getslice2(self, (expr, _0, _1, index2, _2)):
273        if isinstance(expr, ul4.Const) and isinstance(index2, ul4.Const): # Constant folding
274            return self.makeconst(expr.start, _2.end, expr.value[:index2.value])
275        return ul4.GetSlice2(expr.start, _2.end, expr, index2)
276    expr_getslice2.spark = ['expr8 ::= expr8 [ : expr0 ]']
277
278    def expr_getslice(self, (expr, _0, _1, _2)):
279        if isinstance(expr, ul4.Const): # Constant folding
280            return self.makeconst(expr.start, _2.end, expr.value[:])
281        return ul4.GetSlice(expr.start, _2.end, expr)
282    expr_getslice.spark = ['expr8 ::= expr8 [ : ]']
283
284    def expr_neg(self, (_0, expr)):
285        if isinstance(expr, ul4.Const): # Constant folding
286            return self.makeconst(_0.start, expr.end, -expr.value)
287        return ul4.Neg(_0.start, expr.end, expr)
288    expr_neg.spark = ['expr7 ::= - expr7']
289
290    def expr_mul(self, (obj1, _0, obj2)):
291        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
292            return self.makeconst(obj1.start, obj2.end, obj1.value * obj2.value)
293        return ul4.Mul(obj1.start, obj2.end, obj1, obj2)
294    expr_mul.spark = ['expr6 ::= expr6 * expr6']
295
296    def expr_floordiv(self, (obj1, _0, obj2)):
297        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
298            return self.makeconst(obj1.start, obj2.end, obj1.value // obj2.value)
299        return ul4.FloorDiv(obj1.start, obj2.end, obj1, obj2)
300    expr_floordiv.spark = ['expr6 ::= expr6 // expr6']
301
302    def expr_truediv(self, (obj1, _0, obj2)):
303        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
304            return self.makeconst(obj1.start, obj2.end, obj1.value / obj2.value)
305        return ul4.TrueDiv(obj1.start, obj2.end, obj1, obj2)
306    expr_truediv.spark = ['expr6 ::= expr6 / expr6']
307
308    def expr_mod(self, (obj1, _0, obj2)):
309        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
310            return self.makeconst(obj1.start, obj2.end, obj1.value % obj2.value)
311        return ul4.Mod(obj1.start, obj2.end, obj1, obj2)
312    expr_mod.spark = ['expr6 ::= expr6 % expr6']
313
314    def expr_add(self, (obj1, _0, obj2)):
315        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
316            return self.makeconst(obj1.start, obj2.end, obj1.value + obj2.value)
317        return ul4.Add(obj1.start, obj2.end, obj1, obj2)
318    expr_add.spark = ['expr5 ::= expr5 + expr5']
319
320    def expr_sub(self, (obj1, _0, obj2)):
321        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
322            return self.makeconst(obj1.start, obj2.end, obj1.value - obj2.value)
323        return ul4.Sub(obj1.start, obj2.end, obj1, obj2)
324    expr_sub.spark = ['expr5 ::= expr5 - expr5']
325
326    def expr_equal(self, (obj1, _0, obj2)):
327        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
328            return self.makeconst(obj1.start, obj2.end, obj1.value == obj2.value)
329        return ul4.Equal(obj1.start, obj2.end, obj1, obj2)
330    expr_equal.spark = ['expr4 ::= expr4 == expr4']
331
332    def expr_notequal(self, (obj1, _0, obj2)):
333        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
334            return self.makeconst(obj1.start, obj2.end, obj1.value != obj2.value)
335        return ul4.NotEqual(obj1.start, obj2.end, obj1, obj2)
336    expr_notequal.spark = ['expr4 ::= expr4 != expr4']
337
338    def expr_contains(self, (obj, _0, container)):
339        if isinstance(obj, ul4.Const) and isinstance(container, ul4.Const): # Constant folding
340            return self.makeconst(obj.start, container.end, obj.value in container.value)
341        return ul4.Contains(obj.start, container.end, obj, container)
342    expr_contains.spark = ['expr3 ::= expr3 in expr3']
343
344    def expr_notcontains(self, (obj, _0, _1, container)):
345        if isinstance(obj, ul4.Const) and isinstance(container, ul4.Const): # Constant folding
346            return self.makeconst(obj.start, container.end, obj.value not in container.value)
347        return ul4.NotContains(obj.start, container.end, obj, container)
348    expr_notcontains.spark = ['expr3 ::= expr3 not in expr3']
349
350    def expr_not(self, (_0, expr)):
351        if isinstance(expr, ul4.Const): # Constant folding
352            return self.makeconst(_0.start, expr.end, not expr.value)
353        return ul4.Not(_0.start, expr.end, expr)
354    expr_not.spark = ['expr2 ::= not expr2']
355
356    def expr_and(self, (obj1, _0, obj2)):
357        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
358            return self.makeconst(obj1.start, obj2.end, bool(obj1.value and obj2.value))
359        return ul4.And(obj1.start, obj2.end, obj1, obj2)
360    expr_and.spark = ['expr1 ::= expr1 and expr1']
361
362    def expr_or(self, (obj1, _0, obj2)):
363        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
364            return self.makeconst(obj1.start, obj2.end, bool(obj1.value or obj2.value))
365        return ul4.Or(obj1.start, obj2.end, obj1, obj2)
366    expr_or.spark = ['expr0 ::= expr0 or expr0']
367
368    # These rules make operators of different precedences interoperable, by allowing an expression to "drop" its precedence.
369    def expr_dropprecedence(self, (expr, )):
370        return expr
371    expr_dropprecedence.spark = [
372        'expr10 ::= expr11',
373        'expr9 ::= expr10',
374        'expr8 ::= expr9',
375        'expr7 ::= expr8',
376        'expr6 ::= expr7',
377        'expr5 ::= expr6',
378        'expr4 ::= expr5',
379        'expr3 ::= expr4',
380        'expr2 ::= expr3',
381        'expr1 ::= expr2',
382        'expr0 ::= expr1',
383    ]
384
385
386class ForParser(ExprParser):
387    emptyerror = "loop expression required"
388
389    def __init__(self, start="for"):
390        ExprParser.__init__(self, start)
391
392    def for0(self, (iter, _0, cont)):
393        return ul4.For(iter.start, cont.end, iter, cont)
394    for0.spark = ['for ::= name in expr0']
395
396    def for1(self, (_0, iter, _1, _2, _3, cont)):
397        return ul4.For1(_0.start, cont.end, iter, cont)
398    for1.spark = ['for ::= ( name , ) in expr0']
399
400    def for2a(self, (_0, iter1, _1, iter2, _2, _3, cont)):
401        return ul4.For2(_0.start, cont.end, iter1, iter2, cont)
402    for2a.spark = ['for ::= ( name , name ) in expr0']
403
404    def for2b(self, (_0, iter1, _1, iter2, _2, _3, _4, cont)):
405        return ul4.For2(_0.start, cont.end, iter1, iter2, cont)
406    for2b.spark = ['for ::= ( name , name , ) in expr0']
407
408
409class StmtParser(ExprParser):
410    emptyerror = "statement required"
411
412    def __init__(self, start="stmt"):
413        ExprParser.__init__(self, start)
414
415    def stmt_assign(self, (name, _0, value)):
416        return ul4.StoreVar(name.start, value.end, name, value)
417    stmt_assign.spark = ['stmt ::= name = expr0']
418
419    def stmt_iadd(self, (name, _0, value)):
420        return ul4.AddVar(name.start, value.end, name, value)
421    stmt_iadd.spark = ['stmt ::= name += expr0']
422
423    def stmt_isub(self, (name, _0, value)):
424        return ul4.SubVar(name.start, value.end, name, value)
425    stmt_isub.spark = ['stmt ::= name -= expr0']
426
427    def stmt_imul(self, (name, _0, value)):
428        return ul4.MulVar(name.start, value.end, name, value)
429    stmt_imul.spark = ['stmt ::= name *= expr0']
430
431    def stmt_itruediv(self, (name, _0, value)):
432        return ul4.TrueDivVar(name.start, value.end, name, value)
433    stmt_itruediv.spark = ['stmt ::= name /= expr0']
434
435    def stmt_ifloordiv(self, (name, _0, value)):
436        return ul4.FloorDivVar(name.start, value.end, name, value)
437    stmt_ifloordiv.spark = ['stmt ::= name //= expr0']
438
439    def stmt_imod(self, (name, _0, value)):
440        return ul4.ModVar(name.start, value.end, name, value)
441    stmt_imod.spark = ['stmt ::= name %= expr0']
442
443    def stmt_del(self, (_0, name)):
444        return ul4.DelVar(_0.start, name.end, name)
445    stmt_del.spark = ['stmt ::= del name']
446
447
448class RenderParser(ExprParser):
449    emptyerror = "render statement required"
450
451    def __init__(self, start="render"):
452        ExprParser.__init__(self, start)
453
454    def emptyrender(self, (name, _1, _2)):
455        return ul4.Render(name.start, _2.end, name)
456    emptyrender.spark = ['render ::= name ( )']
457
458    def startrender(self, (name, _1, argname, _2, argexpr)):
459        render = ul4.Render(name.start, argexpr.end, name)
460        render.append(argname.value, argexpr)
461        return render
462    startrender.spark = ['buildrender ::= name ( name = expr0 ']
463
464    def buildrender(self, (render, _1, argname, _2, argexpr)):
465        render.append(argname.value, argexpr)
466        render.end = argexpr.end
467        return render
468    buildrender.spark = ['buildrender ::= buildrender , name = expr0']
469
470    def finishrender(self, (render, _0)):
471        render.end = _0.end
472        return render
473    finishrender.spark = ['render ::= buildrender )']
474
475    def finishrender1(self, (render, _0, _1)):
476        render.end = _1.end
477        return render
478    finishrender1.spark = ['render ::= buildrender , )']
479
480
481class Compiler(ul4.CompilerType):
482    def compile(self, source, tags, startdelim, enddelim):
483        template = ul4.Template()
484        template.startdelim = startdelim
485        template.enddelim = enddelim
486        template.source = source
487        _compile(template, tags)
488        return template
Note: See TracBrowser for help on using the browser.