source: proto/Compiler/Cgen.py @ 3095

Last change on this file since 3095 was 810, checked in by cameron, 9 years ago

SIMD register dump facility for debugging.

File size: 14.9 KB
Line 
1# Cgen.py
2#
3# Generate C-style syntax from Pablo/Python
4#
5# Robert D. Cameron, 2010
6# Licensed under Open Software License 3.0
7# Basic structure adapted from unparse.py
8#   modified to generate a string; many functions modified.
9# http://svn.python.org/projects/python/trunk/Demo/parser/unparse.py
10#
11#
12
13import ast
14
15class py2C:
16    def __init__(self, indent = 1):
17        self.base_indent = indent
18
19    def gen(self, t):
20        self.Ccode = ""
21        self._indent = self.base_indent
22        self.dispatch(t)
23        return self.Ccode
24
25    def fill(self, text = ""):
26        "Indent a piece of text, according to the current indentation level"
27        self.Ccode += "\n"+"  "*self._indent + text
28
29    def write(self, text):
30        self.Ccode += text
31
32    def do_block(self, suite):
33        "Print '{', and increase the indentation."
34        self.write("{")
35        self._indent += 1
36        for s in suite:
37            self.dispatch(s)
38        self._indent -= 1
39        self.fill("}")
40
41    def dispatch(self, tree):
42        "Dispatcher function, dispatching tree type T to method Cgen_T."
43        if isinstance(tree, list):
44            for t in tree:
45                self.dispatch(t)
46            return
47        meth = getattr(self, "Cgen_"+tree.__class__.__name__)
48        meth(tree)
49
50#
51# Cgen_XXX routines for Python AST node types
52#
53    def Cgen_Module(self, tree):
54        for stmt in tree.body:
55            self.dispatch(stmt)
56
57    # stmt
58    def Cgen_Expr(self, tree):
59        self.fill()
60        self.dispatch(tree.value)
61        self.write(";")
62
63    def Cgen_Import(self, t):
64        for nm in t.names:
65          self.fill("#include <")
66          self.dispatch(nm)
67          self.write(">")
68
69    def Cgen_ImportFrom(self, t):
70        # A from __future__ import may affect unparsing, so record it.
71        if t.module and t.module == '__future__':
72            self.future_imports.extend(n.name for n in t.names)
73
74        self.fill("from ")
75        self.write("." * t.level)
76        if t.module:
77            self.write(t.module)
78        for nm in t.names:
79          self.fill("#include <")
80          self.dispatch(nm)
81          self.write(">")
82
83    def Cgen_Assign(self, t):
84        self.fill()
85        for target in t.targets:
86            self.dispatch(target)
87            self.write(" = ")
88        self.dispatch(t.value)
89        self.write(";")
90
91    def Cgen_AugAssign(self, t):
92        self.fill()
93        self.dispatch(t.target)
94        self.write(" "+self.binop[t.op.__class__.__name__]+"= ")
95        self.dispatch(t.value)
96        self.write(";")
97
98    def Cgen_Return(self, t):
99        self.fill("return")
100        if t.value:
101            self.write(" ")
102            self.dispatch(t.value)
103        self.write(";")
104
105    def Cgen_Pass(self, t):
106        self.fill(";")
107
108    def Cgen_Break(self, t):
109        self.fill("break;")
110
111    def Cgen_Continue(self, t):
112        self.fill("continue;")
113
114    def Cgen_Delete(self, t):
115        self.fill("delete ")
116        pending = ""
117        for d in t.targets:
118          self.write(pending)
119          self.dispatch(d)
120          pending = ", "
121        self.write(";")
122
123    def Cgen_Assert(self, t):
124        self.fill("assert ")
125        self.dispatch(t.test)
126        if t.msg:
127            self.write(", ")
128            self.dispatch(t.msg)
129        self.write(";")
130
131    def Cgen_Exec(self, t):
132        self.fill("EXEC ")
133        self.dispatch(t.body)
134        if t.globals:
135            self.write(" in ")
136            self.dispatch(t.globals)
137        if t.locals:
138            self.write(", ")
139            self.dispatch(t.locals)
140        self.write(";")
141
142    def Cgen_Print(self, t):
143        self.fill("print ")
144        do_comma = False
145        if t.dest:
146            self.write(">>")
147            self.dispatch(t.dest)
148            do_comma = True
149        for e in t.values:
150            if do_comma:self.write(", ")
151            else:do_comma=True
152            self.dispatch(e)
153        if not t.nl:
154            self.write(",")
155        self.write(";")
156
157    def Cgen_Global(self, t):
158        self.fill("PYGLOBALS ")
159        self.write(";")
160        pending = ""
161        for nm in t.names:
162          self.write(pending)
163          self.dispatch(nm)
164          pending = ", "
165        self.write(";")
166
167    def Cgen_Yield(self, t):
168        self.write("(")
169        self.write("PYYIELD")
170        if t.value:
171            self.write(" ")
172            self.dispatch(t.value)
173        self.write(")")
174        self.write(";")
175
176    def Cgen_Raise(self, t):
177        self.fill('PYRAISE ')
178        if t.type:
179            self.dispatch(t.type)
180        if t.inst:
181            self.write(", ")
182            self.dispatch(t.inst)
183        if t.tback:
184            self.write(", ")
185            self.dispatch(t.tback)
186        self.write(";")
187
188    def Cgen_TryExcept(self, t):
189        self.fill("try")
190        self.do_block(t.body)
191
192
193        for ex in t.handlers:
194            self.dispatch(ex)
195        self.write(";")
196        if t.orelse:
197            self.fill("else")
198            self.do_block(t.orelse)
199
200
201    def Cgen_TryFinally(self, t):
202        if len(t.body) == 1 and isinstance(t.body[0], ast.TryExcept):
203            # try-except-finally
204            self.dispatch(t.body)
205        else:
206            self.fill("try")
207            self.do_block(t.body)
208
209        self.fill("finally")
210        self.do_block(t.finalbody)
211
212    def Cgen_ExceptHandler(self, t):
213        self.fill("except")
214        if t.type:
215            self.write(" ")
216            self.dispatch(t.type)
217        if t.name:
218            self.write(" as ")
219            self.dispatch(t.name)
220        self.do_block(t.body)
221
222    def Cgen_ClassDef(self, t):
223        self.write("\n")
224        for deco in t.decorator_list:
225            self.fill("@")
226            self.dispatch(deco)
227        self.fill("class "+t.name)
228        if t.bases:
229            self.write("(")
230            for a in t.bases:
231                self.dispatch(a)
232                self.write(", ")
233            self.write(")")
234        self.do_block(t.body)
235
236    def Cgen_FunctionDef(self, t):
237        self.write("\n")
238        for deco in t.decorator_list:
239            self.fill("@")
240            self.dispatch(deco)
241        self.fill("void "+t.name + "(")
242        self.dispatch(t.args)
243        self.write(")")
244        self.do_block(t.body)
245
246    def Cgen_For(self, t):
247        self.fill("for (")
248        self.dispatch(t.target)
249        self.write(" in ")
250        self.dispatch(t.iter)
251        self.write(") ")
252        self.do_block(t.body)
253        if t.orelse:
254            self.fill("else")
255            self.do_block(t.orelse)
256 
257    def Cgen_If(self, t):
258        self.fill("if (")
259        self.dispatch(t.test)
260        self.write(") ")
261        self.do_block(t.body)
262        # collapse nested ifs into equivalent elifs.
263        while (t.orelse and len(t.orelse) == 1 and
264               isinstance(t.orelse[0], ast.If)):
265            t = t.orelse[0]
266            self.fill("else if (")
267            self.dispatch(t.test)
268            self.write(") ")
269            self.do_block(t.body)
270        # final else
271        if t.orelse:
272            self.fill("else ")
273            self.do_block(t.orelse)
274
275    def Cgen_While(self, t):
276        self.fill("while (")
277        self.dispatch(t.test)
278        self.write(") ")
279        self.do_block(t.body)
280        if t.orelse:
281            self.fill("else ")
282            self.do_block(t.orelse)
283
284    def Cgen_With(self, t):
285        self.fill("with ")
286        self.dispatch(t.context_expr)
287        if t.optional_vars:
288            self.write(" as ")
289            self.dispatch(t.optional_vars)
290        self.do_block()
291        self.dispatch(t.body)
292        self.leave_block()
293
294    # expr
295    def Cgen_Str(self, tree):
296        self.write('"%s"' % tree.s)
297 
298    def Cgen_Name(self, t):
299        self.write(t.id)
300
301    def Cgen_Repr(self, t):
302        self.write("'")
303        self.dispatch(t.value)
304        self.write("'")
305
306    def Cgen_Num(self, t):
307        repr_n = repr(t.n)
308        # Parenthesize negative numbers, to avoid turning (-1)**2 into -1**2.
309        if repr_n.startswith("-"):
310            self.write("(" + repr_n + ")")
311        else: self.write(repr_n)
312
313    def Cgen_List(self, t):
314        self.write("[")
315        pending = ""
316        for e in t.elts:
317          self.write(pending)
318          self.dispatch(e)
319          pending = ", "
320        self.write("]")
321
322    def Cgen_ListComp(self, t):
323        self.write("[")
324        self.dispatch(t.elt)
325        for gen in t.generators:
326            self.dispatch(gen)
327        self.write("]")
328
329    def Cgen_GeneratorExp(self, t):
330        self.write("(")
331        self.dispatch(t.elt)
332        for gen in t.generators:
333            self.dispatch(gen)
334        self.write(")")
335
336    def Cgen_SetComp(self, t):
337        self.write("{")
338        self.dispatch(t.elt)
339        for gen in t.generators:
340            self.dispatch(gen)
341        self.write("}")
342
343    def Cgen_DictComp(self, t):
344        self.write("{")
345        self.dispatch(t.key)
346        self.write(": ")
347        self.dispatch(t.value)
348        for gen in t.generators:
349            self.dispatch(gen)
350        self.write("}")
351
352    def Cgen_comprehension(self, t):
353        self.write(" for ")
354        self.dispatch(t.target)
355        self.write(" in ")
356        self.dispatch(t.iter)
357        for if_clause in t.ifs:
358            self.write(" if ")
359            self.dispatch(if_clause)
360
361    def Cgen_IfExp(self, t):
362        self.write("(")
363        self.dispatch(t.test)
364        self.write(" ? ")
365        self.dispatch(t.body)
366        self.write(" : ")
367        self.dispatch(t.orelse)
368        self.write(")")
369
370    def Cgen_Set(self, t):
371        assert(t.elts) # should be at least one element
372        self.write("{")
373        pending = ""
374        for e in t.elts:
375          self.write(pending)
376          self.dispatch(e)
377          pending = ", "
378        self.write("}")
379
380    def Cgen_Dict(self, t):
381        self.write("{")
382        pending = ""
383        for (k, v) in (t.keys, t.values):
384          self.write(pending)
385          self.dispatch(k)
386          self.write(": ")
387          self.dispatch(v)
388          pending = ", "
389        self.write("}")
390
391    def Cgen_Tuple(self, t):
392        self.write("(")
393        if len(t.elts) == 1:
394            (elt,) = t.elts
395            self.dispatch(elt)
396            self.write(",")
397        else:
398            pending = ""
399            for e in t.elts:
400                self.write(pending)
401                self.dispatch(e)
402                pending = ", "
403        self.write(")")
404
405    unop = {"Invert":"~", "Not": "!", "UAdd":"+", "USub":"-"}
406    def Cgen_UnaryOp(self, t):
407        self.write("(")
408        self.write(self.unop[t.op.__class__.__name__])
409        self.write(" ")
410        # If we're applying unary minus to a number, parenthesize the number.
411        # This is necessary: -2147483648 is different from -(2147483648) on
412        # a 32-bit machine (the first is an int, the second a long), and
413        # -7j is different from -(7j).  (The first has real part 0.0, the second
414        # has real part -0.0.)
415        if isinstance(t.op, ast.USub) and isinstance(t.operand, ast.Num):
416            self.write("(")
417            self.dispatch(t.operand)
418            self.write(")")
419        else:
420            self.dispatch(t.operand)
421        self.write(")")
422
423    binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
424                    "LShift":"<<", "RShift":">>", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
425                    "FloorDiv":"//", "Pow": "**"}
426    def Cgen_BinOp(self, t):
427        self.write("(")
428        self.dispatch(t.left)
429        self.write(" " + self.binop[t.op.__class__.__name__] + " ")
430        self.dispatch(t.right)
431        self.write(")")
432
433    cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
434                        "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
435    def Cgen_Compare(self, t):
436        self.write("(")
437        self.dispatch(t.left)
438        for o, e in zip(t.ops, t.comparators):
439            self.write(" " + self.cmpops[o.__class__.__name__] + " ")
440            self.dispatch(e)
441        self.write(")")
442
443    boolops = {ast.And: '&&', ast.Or: '||'}
444    def Cgen_BoolOp(self, t):
445        op = " %s " % self.boolops[t.op.__class__]
446        self.write("(")
447        self.dispatch(t.values[0])
448        for v in t.values[1:]:
449          self.write(op)
450          self.dispatch(v)
451        self.write(")")
452
453    def Cgen_Attribute(self,t):
454        self.dispatch(t.value)
455        # Special case: 3.__abs__() is a syntax error, so if t.value
456        # is an integer literal then we need to either parenthesize
457        # it or add an extra space to get 3 .__abs__().
458        if isinstance(t.value, ast.Num) and isinstance(t.value.n, int):
459            self.write(" ")
460        self.write(".")
461        self.write(t.attr)
462
463    def Cgen_Call(self, t):
464        self.dispatch(t.func)
465        self.write("(")
466        comma = False
467        for e in t.args:
468            if comma: self.write(", ")
469            else: comma = True
470            self.dispatch(e)
471        for e in t.keywords:
472            if comma: self.write(", ")
473            else: comma = True
474            self.dispatch(e)
475        if t.starargs:
476            if comma: self.write(", ")
477            else: comma = True
478            self.write("*")
479            self.dispatch(t.starargs)
480        if t.kwargs:
481            if comma: self.write(", ")
482            else: comma = True
483            self.write("**")
484            self.dispatch(t.kwargs)
485        self.write(")")
486
487    def Cgen_Subscript(self, t):
488        self.dispatch(t.value)
489        self.write("[")
490        self.dispatch(t.slice)
491        self.write("]")
492
493    # slice
494    def Cgen_Ellipsis(self, t):
495        self.write("...")
496
497    def Cgen_Index(self, t):
498        self.dispatch(t.value)
499
500    def Cgen_Slice(self, t):
501        if t.lower:
502            self.dispatch(t.lower)
503        self.write(":")
504        if t.upper:
505            self.dispatch(t.upper)
506        if t.step:
507            self.write(":")
508            self.dispatch(t.step)
509
510    def Cgen_ExtSlice(self, t):
511        pending = ""
512        for d in t.dims:
513            self.write(pending)
514            self.dispatch(d)
515            pending = ", "
516
517    # others
518    def Cgen_arguments(self, t):
519        first = True
520        # normal arguments
521        defaults = [None] * (len(t.args) - len(t.defaults)) + t.defaults
522        for a,d in zip(t.args, defaults):
523            if first:first = False
524            else: self.write(", ")
525            self.dispatch(a),
526            if d:
527                self.write("=")
528                self.dispatch(d)
529
530        # varargs
531        if t.vararg:
532            if first:first = False
533            else: self.write(", ")
534            self.write("*")
535            self.write(t.vararg)
536
537        # kwargs
538        if t.kwarg:
539            if first:first = False
540            else: self.write(", ")
541            self.write("**"+t.kwarg)
542
543    def Cgen_keyword(self, t):
544        self.write(t.arg)
545        self.write("=")
546        self.dispatch(t.value)
547
548    def Cgen_Lambda(self, t):
549        self.write("(")
550        self.write("lambda ")
551        self.dispatch(t.args)
552        self.write(": ")
553        self.dispatch(t.body)
554        self.write(")")
555
556    def Cgen_alias(self, t):
557        self.write(t.name)
558        if t.asname:
559            self.write(" as "+t.asname)
560
Note: See TracBrowser for help on using the repository browser.