root/livinglogic.java.ul4/library/src/com/livinglogic/ul4/ul4c.py @ 123:8b5ca02b386c

Revision 123:8b5ca02b386c, 15.2 KB (checked in by Alexander Lamm <alexander.lamm@…>, 12 years ago)

Implemented date literals and the format and isoformat methods

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_bracket(self, (_0, expr, _1)):
163        return expr
164    expr_bracket.spark = ['expr11 ::= ( expr0 )']
165
166    def expr_callfunc0(self, (name, _0, _1)):
167        return ul4.CallFunc(name.start, _1.end, name)
168    expr_callfunc0.spark = ['expr10 ::= name ( )']
169
170    def expr_callfunc1(self, (name, _0, arg0, _1)):
171        return ul4.CallFunc(name.start, _1.end, name, arg0)
172    expr_callfunc1.spark = ['expr10 ::= name ( expr0 )']
173
174    def expr_callfunc2(self, (name, _0, arg0, _1, arg1, _2)):
175        return ul4.CallFunc(name.start, _2.end, name, arg0, arg1)
176    expr_callfunc2.spark = ['expr10 ::= name ( expr0 , expr0 )']
177
178    def expr_callfunc3(self, (name, _0, arg0, _1, arg1, _2, arg2, _3)):
179        return ul4.CallFunc(name.start, _3.end, name, arg0, arg1, arg2)
180    expr_callfunc3.spark = ['expr10 ::= name ( expr0 , expr0 , expr0 )']
181
182    def expr_getattr(self, (expr, _0, name)):
183        return ul4.GetAttr(expr.start, name.end, expr, name)
184    expr_getattr.spark = ['expr9 ::= expr9 . name']
185
186    def expr_callmeth0(self, (expr, _0, name, _1, _2)):
187        return ul4.CallMeth(expr.start, _2.end, expr, name)
188    expr_callmeth0.spark = ['expr9 ::= expr9 . name ( )']
189
190    def expr_callmeth1(self, (expr, _0, name, _1, arg1, _2)):
191        return ul4.CallMeth(expr.start, _2.end, expr, name, arg1)
192    expr_callmeth1.spark = ['expr9 ::= expr9 . name ( expr0 )']
193
194    def expr_callmeth2(self, (expr, _0, name, _1, arg1, _2, arg2, _3)):
195        return ul4.CallMeth(expr.start, _3.end, expr, name, arg1, arg2)
196    expr_callmeth2.spark = ['expr9 ::= expr9 . name ( expr0 , expr0 )']
197
198    def expr_callmeth3(self, (expr, _0, name, _1, arg1, _2, arg2, _3, arg3, _4)):
199        return ul4.CallMeth(expr.start, _4.end, expr, name, arg1, arg2, arg3)
200    expr_callmeth3.spark = ['expr9 ::= expr9 . name ( expr0 , expr0 , expr0 )']
201
202    def expr_getitem(self, (expr, _0, key, _1)):
203        if isinstance(expr, ul4.Const) and isinstance(key, ul4.Const): # Constant folding
204            return self.makeconst(expr.start, _1.end, expr.value[key.value])
205        return ul4.GetItem(expr.start, _1.end, expr, key)
206    expr_getitem.spark = ['expr9 ::= expr9 [ expr0 ]']
207
208    def expr_getslice12(self, (expr, _0, index1, _1, index2, _2)):
209        if isinstance(expr, ul4.Const) and isinstance(index1, ul4.Const) and isinstance(index2, ul4.Const): # Constant folding
210            return self.makeconst(expr.start, _2.end, expr.value[index1.value:index1.value])
211        return ul4.GetSlice12(expr.start, _2.end, expr, index1, index2)
212    expr_getslice12.spark = ['expr8 ::= expr8 [ expr0 : expr0 ]']
213
214    def expr_getslice1(self, (expr, _0, index1, _1, _2)):
215        if isinstance(expr, ul4.Const) and isinstance(index1, ul4.Const): # Constant folding
216            return self.makeconst(expr.start, _2.end, expr.value[index1.value:])
217        return ul4.GetSlice1(expr.start, _2.end, expr, index1)
218    expr_getslice1.spark = ['expr8 ::= expr8 [ expr0 : ]']
219
220    def expr_getslice2(self, (expr, _0, _1, index2, _2)):
221        if isinstance(expr, ul4.Const) and isinstance(index2, ul4.Const): # Constant folding
222            return self.makeconst(expr.start, _2.end, expr.value[:index2.value])
223        return ul4.GetSlice2(expr.start, _2.end, expr, index2)
224    expr_getslice2.spark = ['expr8 ::= expr8 [ : expr0 ]']
225
226    def expr_getslice(self, (expr, _0, _1, _2)):
227        if isinstance(expr, ul4.Const): # Constant folding
228            return self.makeconst(expr.start, _2.end, expr.value[:])
229        return ul4.GetSlice(expr.start, _2.end, expr)
230    expr_getslice.spark = ['expr8 ::= expr8 [ : ]']
231
232    def expr_neg(self, (_0, expr)):
233        if isinstance(expr, ul4.Const): # Constant folding
234            return self.makeconst(_0.start, expr.end, -expr.value)
235        return ul4.Neg(_0.start, expr.end, expr)
236    expr_neg.spark = ['expr7 ::= - expr7']
237
238    def expr_mul(self, (obj1, _0, obj2)):
239        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
240            return self.makeconst(obj1.start, obj2.end, obj1.value * obj2.value)
241        return ul4.Mul(obj1.start, obj2.end, obj1, obj2)
242    expr_mul.spark = ['expr6 ::= expr6 * expr6']
243
244    def expr_floordiv(self, (obj1, _0, obj2)):
245        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
246            return self.makeconst(obj1.start, obj2.end, obj1.value // obj2.value)
247        return ul4.FloorDiv(obj1.start, obj2.end, obj1, obj2)
248    expr_floordiv.spark = ['expr6 ::= expr6 // expr6']
249
250    def expr_truediv(self, (obj1, _0, obj2)):
251        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
252            return self.makeconst(obj1.start, obj2.end, obj1.value / obj2.value)
253        return ul4.TrueDiv(obj1.start, obj2.end, obj1, obj2)
254    expr_truediv.spark = ['expr6 ::= expr6 / expr6']
255
256    def expr_mod(self, (obj1, _0, obj2)):
257        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
258            return self.makeconst(obj1.start, obj2.end, obj1.value % obj2.value)
259        return ul4.Mod(obj1.start, obj2.end, obj1, obj2)
260    expr_mod.spark = ['expr6 ::= expr6 % expr6']
261
262    def expr_add(self, (obj1, _0, obj2)):
263        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
264            return self.makeconst(obj1.start, obj2.end, obj1.value + obj2.value)
265        return ul4.Add(obj1.start, obj2.end, obj1, obj2)
266    expr_add.spark = ['expr5 ::= expr5 + expr5']
267
268    def expr_sub(self, (obj1, _0, obj2)):
269        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
270            return self.makeconst(obj1.start, obj2.end, obj1.value - obj2.value)
271        return ul4.Sub(obj1.start, obj2.end, obj1, obj2)
272    expr_sub.spark = ['expr5 ::= expr5 - expr5']
273
274    def expr_equal(self, (obj1, _0, obj2)):
275        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
276            return self.makeconst(obj1.start, obj2.end, obj1.value == obj2.value)
277        return ul4.Equal(obj1.start, obj2.end, obj1, obj2)
278    expr_equal.spark = ['expr4 ::= expr4 == expr4']
279
280    def expr_notequal(self, (obj1, _0, obj2)):
281        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
282            return self.makeconst(obj1.start, obj2.end, obj1.value != obj2.value)
283        return ul4.NotEqual(obj1.start, obj2.end, obj1, obj2)
284    expr_notequal.spark = ['expr4 ::= expr4 != expr4']
285
286    def expr_contains(self, (obj, _0, container)):
287        if isinstance(obj, ul4.Const) and isinstance(container, ul4.Const): # Constant folding
288            return self.makeconst(obj.start, container.end, obj.value in container.value)
289        return ul4.Contains(obj.start, container.end, obj, container)
290    expr_contains.spark = ['expr3 ::= expr3 in expr3']
291
292    def expr_notcontains(self, (obj, _0, _1, container)):
293        if isinstance(obj, ul4.Const) and isinstance(container, ul4.Const): # Constant folding
294            return self.makeconst(obj.start, container.end, obj.value not in container.value)
295        return ul4.NotContains(obj.start, container.end, obj, container)
296    expr_notcontains.spark = ['expr3 ::= expr3 not in expr3']
297
298    def expr_not(self, (_0, expr)):
299        if isinstance(expr, ul4.Const): # Constant folding
300            return self.makeconst(_0.start, expr.end, not expr.value)
301        return ul4.Not(_0.start, expr.end, expr)
302    expr_not.spark = ['expr2 ::= not expr2']
303
304    def expr_and(self, (obj1, _0, obj2)):
305        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
306            return self.makeconst(obj1.start, obj2.end, bool(obj1.value and obj2.value))
307        return ul4.And(obj1.start, obj2.end, obj1, obj2)
308    expr_and.spark = ['expr1 ::= expr1 and expr1']
309
310    def expr_or(self, (obj1, _0, obj2)):
311        if isinstance(obj1, ul4.Const) and isinstance(obj2, ul4.Const): # Constant folding
312            return self.makeconst(obj1.start, obj2.end, bool(obj1.value or obj2.value))
313        return ul4.Or(obj1.start, obj2.end, obj1, obj2)
314    expr_or.spark = ['expr0 ::= expr0 or expr0']
315
316    # These rules make operators of different precedences interoperable, by allowing an expression to "drop" its precedence.
317    def expr_dropprecedence(self, (expr, )):
318        return expr
319    expr_dropprecedence.spark = [
320        'expr10 ::= expr11',
321        'expr9 ::= expr10',
322        'expr8 ::= expr9',
323        'expr7 ::= expr8',
324        'expr6 ::= expr7',
325        'expr5 ::= expr6',
326        'expr4 ::= expr5',
327        'expr3 ::= expr4',
328        'expr2 ::= expr3',
329        'expr1 ::= expr2',
330        'expr0 ::= expr1',
331    ]
332
333
334class ForParser(ExprParser):
335    emptyerror = "loop expression required"
336
337    def __init__(self, start="for"):
338        ExprParser.__init__(self, start)
339
340    def for0(self, (iter, _0, cont)):
341        return ul4.For(iter.start, cont.end, iter, cont)
342    for0.spark = ['for ::= name in expr0']
343
344    def for1(self, (_0, iter, _1, _2, _3, cont)):
345        return ul4.For1(_0.start, cont.end, iter, cont)
346    for1.spark = ['for ::= ( name , ) in expr0']
347
348    def for2a(self, (_0, iter1, _1, iter2, _2, _3, cont)):
349        return ul4.For2(_0.start, cont.end, iter1, iter2, cont)
350    for2a.spark = ['for ::= ( name , name ) in expr0']
351
352    def for2b(self, (_0, iter1, _1, iter2, _2, _3, _4, cont)):
353        return ul4.For2(_0.start, cont.end, iter1, iter2, cont)
354    for2a.spark = ['for ::= ( name , name , ) in expr0']
355
356
357class StmtParser(ExprParser):
358    emptyerror = "statement required"
359
360    def __init__(self, start="stmt"):
361        ExprParser.__init__(self, start)
362
363    def stmt_assign(self, (name, _0, value)):
364        return ul4.StoreVar(name.start, value.end, name, value)
365    stmt_assign.spark = ['stmt ::= name = expr0']
366
367    def stmt_iadd(self, (name, _0, value)):
368        return ul4.AddVar(name.start, value.end, name, value)
369    stmt_iadd.spark = ['stmt ::= name += expr0']
370
371    def stmt_isub(self, (name, _0, value)):
372        return ul4.SubVar(name.start, value.end, name, value)
373    stmt_isub.spark = ['stmt ::= name -= expr0']
374
375    def stmt_imul(self, (name, _0, value)):
376        return ul4.MulVar(name.start, value.end, name, value)
377    stmt_imul.spark = ['stmt ::= name *= expr0']
378
379    def stmt_itruediv(self, (name, _0, value)):
380        return ul4.TrueDivVar(name.start, value.end, name, value)
381    stmt_itruediv.spark = ['stmt ::= name /= expr0']
382
383    def stmt_ifloordiv(self, (name, _0, value)):
384        return ul4.FloorDivVar(name.start, value.end, name, value)
385    stmt_ifloordiv.spark = ['stmt ::= name //= expr0']
386
387    def stmt_imod(self, (name, _0, value)):
388        return ul4.ModVar(name.start, value.end, name, value)
389    stmt_imod.spark = ['stmt ::= name %= expr0']
390
391    def stmt_del(self, (_0, name)):
392        return ul4.DelVar(_0.start, name.end, name)
393    stmt_del.spark = ['stmt ::= del name']
394
395
396class RenderParser(ExprParser):
397    emptyerror = "render statement required"
398
399    def __init__(self, start="render"):
400        ExprParser.__init__(self, start)
401
402    def render(self, (name, _1, expr, _2)):
403        return ul4.Render(name.start, _2.end, name, expr)
404    render.spark = ['render ::= name ( expr0 )']
405
406
407class Compiler(ul4.CompilerType):
408    def compile(self, source, tags, startdelim, enddelim):
409        template = ul4.Template()
410        template.startdelim = startdelim
411        template.enddelim = enddelim
412        template.source = source
413        _compile(template, tags)
414        return template
Note: See TracBrowser for help on using the browser.