diff options
Diffstat (limited to 'bitbake/lib/codegen.py')
-rw-r--r-- | bitbake/lib/codegen.py | 570 |
1 files changed, 570 insertions, 0 deletions
diff --git a/bitbake/lib/codegen.py b/bitbake/lib/codegen.py new file mode 100644 index 0000000000..be772d5107 --- /dev/null +++ b/bitbake/lib/codegen.py | |||
@@ -0,0 +1,570 @@ | |||
1 | # -*- coding: utf-8 -*- | ||
2 | """ | ||
3 | codegen | ||
4 | ~~~~~~~ | ||
5 | |||
6 | Extension to ast that allow ast -> python code generation. | ||
7 | |||
8 | :copyright: Copyright 2008 by Armin Ronacher. | ||
9 | :license: BSD. | ||
10 | """ | ||
11 | from ast import * | ||
12 | |||
13 | BOOLOP_SYMBOLS = { | ||
14 | And: 'and', | ||
15 | Or: 'or' | ||
16 | } | ||
17 | |||
18 | BINOP_SYMBOLS = { | ||
19 | Add: '+', | ||
20 | Sub: '-', | ||
21 | Mult: '*', | ||
22 | Div: '/', | ||
23 | FloorDiv: '//', | ||
24 | Mod: '%', | ||
25 | LShift: '<<', | ||
26 | RShift: '>>', | ||
27 | BitOr: '|', | ||
28 | BitAnd: '&', | ||
29 | BitXor: '^' | ||
30 | } | ||
31 | |||
32 | CMPOP_SYMBOLS = { | ||
33 | Eq: '==', | ||
34 | Gt: '>', | ||
35 | GtE: '>=', | ||
36 | In: 'in', | ||
37 | Is: 'is', | ||
38 | IsNot: 'is not', | ||
39 | Lt: '<', | ||
40 | LtE: '<=', | ||
41 | NotEq: '!=', | ||
42 | NotIn: 'not in' | ||
43 | } | ||
44 | |||
45 | UNARYOP_SYMBOLS = { | ||
46 | Invert: '~', | ||
47 | Not: 'not', | ||
48 | UAdd: '+', | ||
49 | USub: '-' | ||
50 | } | ||
51 | |||
52 | ALL_SYMBOLS = {} | ||
53 | ALL_SYMBOLS.update(BOOLOP_SYMBOLS) | ||
54 | ALL_SYMBOLS.update(BINOP_SYMBOLS) | ||
55 | ALL_SYMBOLS.update(CMPOP_SYMBOLS) | ||
56 | ALL_SYMBOLS.update(UNARYOP_SYMBOLS) | ||
57 | |||
58 | def to_source(node, indent_with=' ' * 4, add_line_information=False): | ||
59 | """This function can convert a node tree back into python sourcecode. | ||
60 | This is useful for debugging purposes, especially if you're dealing with | ||
61 | custom asts not generated by python itself. | ||
62 | |||
63 | It could be that the sourcecode is evaluable when the AST itself is not | ||
64 | compilable / evaluable. The reason for this is that the AST contains some | ||
65 | more data than regular sourcecode does, which is dropped during | ||
66 | conversion. | ||
67 | |||
68 | Each level of indentation is replaced with `indent_with`. Per default this | ||
69 | parameter is equal to four spaces as suggested by PEP 8, but it might be | ||
70 | adjusted to match the application's styleguide. | ||
71 | |||
72 | If `add_line_information` is set to `True` comments for the line numbers | ||
73 | of the nodes are added to the output. This can be used to spot wrong line | ||
74 | number information of statement nodes. | ||
75 | """ | ||
76 | generator = SourceGenerator(indent_with, add_line_information) | ||
77 | generator.visit(node) | ||
78 | return ''.join(generator.result) | ||
79 | |||
80 | |||
81 | class SourceGenerator(NodeVisitor): | ||
82 | """This visitor is able to transform a well formed syntax tree into python | ||
83 | sourcecode. For more details have a look at the docstring of the | ||
84 | `node_to_source` function. | ||
85 | """ | ||
86 | |||
87 | def __init__(self, indent_with, add_line_information=False): | ||
88 | self.result = [] | ||
89 | self.indent_with = indent_with | ||
90 | self.add_line_information = add_line_information | ||
91 | self.indentation = 0 | ||
92 | self.new_lines = 0 | ||
93 | |||
94 | def write(self, x): | ||
95 | if self.new_lines: | ||
96 | if self.result: | ||
97 | self.result.append('\n' * self.new_lines) | ||
98 | self.result.append(self.indent_with * self.indentation) | ||
99 | self.new_lines = 0 | ||
100 | self.result.append(x) | ||
101 | |||
102 | def newline(self, node=None, extra=0): | ||
103 | self.new_lines = max(self.new_lines, 1 + extra) | ||
104 | if node is not None and self.add_line_information: | ||
105 | self.write('# line: %s' % node.lineno) | ||
106 | self.new_lines = 1 | ||
107 | |||
108 | def body(self, statements): | ||
109 | self.new_line = True | ||
110 | self.indentation += 1 | ||
111 | for stmt in statements: | ||
112 | self.visit(stmt) | ||
113 | self.indentation -= 1 | ||
114 | |||
115 | def body_or_else(self, node): | ||
116 | self.body(node.body) | ||
117 | if node.orelse: | ||
118 | self.newline() | ||
119 | self.write('else:') | ||
120 | self.body(node.orelse) | ||
121 | |||
122 | def signature(self, node): | ||
123 | want_comma = [] | ||
124 | def write_comma(): | ||
125 | if want_comma: | ||
126 | self.write(', ') | ||
127 | else: | ||
128 | want_comma.append(True) | ||
129 | |||
130 | padding = [None] * (len(node.args) - len(node.defaults)) | ||
131 | for arg, default in zip(node.args, padding + node.defaults): | ||
132 | write_comma() | ||
133 | self.visit(arg) | ||
134 | if default is not None: | ||
135 | self.write('=') | ||
136 | self.visit(default) | ||
137 | if node.vararg is not None: | ||
138 | write_comma() | ||
139 | self.write('*' + node.vararg) | ||
140 | if node.kwarg is not None: | ||
141 | write_comma() | ||
142 | self.write('**' + node.kwarg) | ||
143 | |||
144 | def decorators(self, node): | ||
145 | for decorator in node.decorator_list: | ||
146 | self.newline(decorator) | ||
147 | self.write('@') | ||
148 | self.visit(decorator) | ||
149 | |||
150 | # Statements | ||
151 | |||
152 | def visit_Assign(self, node): | ||
153 | self.newline(node) | ||
154 | for idx, target in enumerate(node.targets): | ||
155 | if idx: | ||
156 | self.write(', ') | ||
157 | self.visit(target) | ||
158 | self.write(' = ') | ||
159 | self.visit(node.value) | ||
160 | |||
161 | def visit_AugAssign(self, node): | ||
162 | self.newline(node) | ||
163 | self.visit(node.target) | ||
164 | self.write(BINOP_SYMBOLS[type(node.op)] + '=') | ||
165 | self.visit(node.value) | ||
166 | |||
167 | def visit_ImportFrom(self, node): | ||
168 | self.newline(node) | ||
169 | self.write('from %s%s import ' % ('.' * node.level, node.module)) | ||
170 | for idx, item in enumerate(node.names): | ||
171 | if idx: | ||
172 | self.write(', ') | ||
173 | self.write(item) | ||
174 | |||
175 | def visit_Import(self, node): | ||
176 | self.newline(node) | ||
177 | for item in node.names: | ||
178 | self.write('import ') | ||
179 | self.visit(item) | ||
180 | |||
181 | def visit_Expr(self, node): | ||
182 | self.newline(node) | ||
183 | self.generic_visit(node) | ||
184 | |||
185 | def visit_FunctionDef(self, node): | ||
186 | self.newline(extra=1) | ||
187 | self.decorators(node) | ||
188 | self.newline(node) | ||
189 | self.write('def %s(' % node.name) | ||
190 | self.signature(node.args) | ||
191 | self.write('):') | ||
192 | self.body(node.body) | ||
193 | |||
194 | def visit_ClassDef(self, node): | ||
195 | have_args = [] | ||
196 | def paren_or_comma(): | ||
197 | if have_args: | ||
198 | self.write(', ') | ||
199 | else: | ||
200 | have_args.append(True) | ||
201 | self.write('(') | ||
202 | |||
203 | self.newline(extra=2) | ||
204 | self.decorators(node) | ||
205 | self.newline(node) | ||
206 | self.write('class %s' % node.name) | ||
207 | for base in node.bases: | ||
208 | paren_or_comma() | ||
209 | self.visit(base) | ||
210 | # XXX: the if here is used to keep this module compatible | ||
211 | # with python 2.6. | ||
212 | if hasattr(node, 'keywords'): | ||
213 | for keyword in node.keywords: | ||
214 | paren_or_comma() | ||
215 | self.write(keyword.arg + '=') | ||
216 | self.visit(keyword.value) | ||
217 | if node.starargs is not None: | ||
218 | paren_or_comma() | ||
219 | self.write('*') | ||
220 | self.visit(node.starargs) | ||
221 | if node.kwargs is not None: | ||
222 | paren_or_comma() | ||
223 | self.write('**') | ||
224 | self.visit(node.kwargs) | ||
225 | self.write(have_args and '):' or ':') | ||
226 | self.body(node.body) | ||
227 | |||
228 | def visit_If(self, node): | ||
229 | self.newline(node) | ||
230 | self.write('if ') | ||
231 | self.visit(node.test) | ||
232 | self.write(':') | ||
233 | self.body(node.body) | ||
234 | while True: | ||
235 | else_ = node.orelse | ||
236 | if len(else_) == 1 and isinstance(else_[0], If): | ||
237 | node = else_[0] | ||
238 | self.newline() | ||
239 | self.write('elif ') | ||
240 | self.visit(node.test) | ||
241 | self.write(':') | ||
242 | self.body(node.body) | ||
243 | else: | ||
244 | self.newline() | ||
245 | self.write('else:') | ||
246 | self.body(else_) | ||
247 | break | ||
248 | |||
249 | def visit_For(self, node): | ||
250 | self.newline(node) | ||
251 | self.write('for ') | ||
252 | self.visit(node.target) | ||
253 | self.write(' in ') | ||
254 | self.visit(node.iter) | ||
255 | self.write(':') | ||
256 | self.body_or_else(node) | ||
257 | |||
258 | def visit_While(self, node): | ||
259 | self.newline(node) | ||
260 | self.write('while ') | ||
261 | self.visit(node.test) | ||
262 | self.write(':') | ||
263 | self.body_or_else(node) | ||
264 | |||
265 | def visit_With(self, node): | ||
266 | self.newline(node) | ||
267 | self.write('with ') | ||
268 | self.visit(node.context_expr) | ||
269 | if node.optional_vars is not None: | ||
270 | self.write(' as ') | ||
271 | self.visit(node.optional_vars) | ||
272 | self.write(':') | ||
273 | self.body(node.body) | ||
274 | |||
275 | def visit_Pass(self, node): | ||
276 | self.newline(node) | ||
277 | self.write('pass') | ||
278 | |||
279 | def visit_Print(self, node): | ||
280 | # XXX: python 2.6 only | ||
281 | self.newline(node) | ||
282 | self.write('print ') | ||
283 | want_comma = False | ||
284 | if node.dest is not None: | ||
285 | self.write(' >> ') | ||
286 | self.visit(node.dest) | ||
287 | want_comma = True | ||
288 | for value in node.values: | ||
289 | if want_comma: | ||
290 | self.write(', ') | ||
291 | self.visit(value) | ||
292 | want_comma = True | ||
293 | if not node.nl: | ||
294 | self.write(',') | ||
295 | |||
296 | def visit_Delete(self, node): | ||
297 | self.newline(node) | ||
298 | self.write('del ') | ||
299 | for idx, target in enumerate(node): | ||
300 | if idx: | ||
301 | self.write(', ') | ||
302 | self.visit(target) | ||
303 | |||
304 | def visit_TryExcept(self, node): | ||
305 | self.newline(node) | ||
306 | self.write('try:') | ||
307 | self.body(node.body) | ||
308 | for handler in node.handlers: | ||
309 | self.visit(handler) | ||
310 | |||
311 | def visit_TryFinally(self, node): | ||
312 | self.newline(node) | ||
313 | self.write('try:') | ||
314 | self.body(node.body) | ||
315 | self.newline(node) | ||
316 | self.write('finally:') | ||
317 | self.body(node.finalbody) | ||
318 | |||
319 | def visit_Global(self, node): | ||
320 | self.newline(node) | ||
321 | self.write('global ' + ', '.join(node.names)) | ||
322 | |||
323 | def visit_Nonlocal(self, node): | ||
324 | self.newline(node) | ||
325 | self.write('nonlocal ' + ', '.join(node.names)) | ||
326 | |||
327 | def visit_Return(self, node): | ||
328 | self.newline(node) | ||
329 | self.write('return ') | ||
330 | self.visit(node.value) | ||
331 | |||
332 | def visit_Break(self, node): | ||
333 | self.newline(node) | ||
334 | self.write('break') | ||
335 | |||
336 | def visit_Continue(self, node): | ||
337 | self.newline(node) | ||
338 | self.write('continue') | ||
339 | |||
340 | def visit_Raise(self, node): | ||
341 | # XXX: Python 2.6 / 3.0 compatibility | ||
342 | self.newline(node) | ||
343 | self.write('raise') | ||
344 | if hasattr(node, 'exc') and node.exc is not None: | ||
345 | self.write(' ') | ||
346 | self.visit(node.exc) | ||
347 | if node.cause is not None: | ||
348 | self.write(' from ') | ||
349 | self.visit(node.cause) | ||
350 | elif hasattr(node, 'type') and node.type is not None: | ||
351 | self.visit(node.type) | ||
352 | if node.inst is not None: | ||
353 | self.write(', ') | ||
354 | self.visit(node.inst) | ||
355 | if node.tback is not None: | ||
356 | self.write(', ') | ||
357 | self.visit(node.tback) | ||
358 | |||
359 | # Expressions | ||
360 | |||
361 | def visit_Attribute(self, node): | ||
362 | self.visit(node.value) | ||
363 | self.write('.' + node.attr) | ||
364 | |||
365 | def visit_Call(self, node): | ||
366 | want_comma = [] | ||
367 | def write_comma(): | ||
368 | if want_comma: | ||
369 | self.write(', ') | ||
370 | else: | ||
371 | want_comma.append(True) | ||
372 | |||
373 | self.visit(node.func) | ||
374 | self.write('(') | ||
375 | for arg in node.args: | ||
376 | write_comma() | ||
377 | self.visit(arg) | ||
378 | for keyword in node.keywords: | ||
379 | write_comma() | ||
380 | self.write(keyword.arg + '=') | ||
381 | self.visit(keyword.value) | ||
382 | if node.starargs is not None: | ||
383 | write_comma() | ||
384 | self.write('*') | ||
385 | self.visit(node.starargs) | ||
386 | if node.kwargs is not None: | ||
387 | write_comma() | ||
388 | self.write('**') | ||
389 | self.visit(node.kwargs) | ||
390 | self.write(')') | ||
391 | |||
392 | def visit_Name(self, node): | ||
393 | self.write(node.id) | ||
394 | |||
395 | def visit_Str(self, node): | ||
396 | self.write(repr(node.s)) | ||
397 | |||
398 | def visit_Bytes(self, node): | ||
399 | self.write(repr(node.s)) | ||
400 | |||
401 | def visit_Num(self, node): | ||
402 | self.write(repr(node.n)) | ||
403 | |||
404 | def visit_Tuple(self, node): | ||
405 | self.write('(') | ||
406 | idx = -1 | ||
407 | for idx, item in enumerate(node.elts): | ||
408 | if idx: | ||
409 | self.write(', ') | ||
410 | self.visit(item) | ||
411 | self.write(idx and ')' or ',)') | ||
412 | |||
413 | def sequence_visit(left, right): | ||
414 | def visit(self, node): | ||
415 | self.write(left) | ||
416 | for idx, item in enumerate(node.elts): | ||
417 | if idx: | ||
418 | self.write(', ') | ||
419 | self.visit(item) | ||
420 | self.write(right) | ||
421 | return visit | ||
422 | |||
423 | visit_List = sequence_visit('[', ']') | ||
424 | visit_Set = sequence_visit('{', '}') | ||
425 | del sequence_visit | ||
426 | |||
427 | def visit_Dict(self, node): | ||
428 | self.write('{') | ||
429 | for idx, (key, value) in enumerate(zip(node.keys, node.values)): | ||
430 | if idx: | ||
431 | self.write(', ') | ||
432 | self.visit(key) | ||
433 | self.write(': ') | ||
434 | self.visit(value) | ||
435 | self.write('}') | ||
436 | |||
437 | def visit_BinOp(self, node): | ||
438 | self.visit(node.left) | ||
439 | self.write(' %s ' % BINOP_SYMBOLS[type(node.op)]) | ||
440 | self.visit(node.right) | ||
441 | |||
442 | def visit_BoolOp(self, node): | ||
443 | self.write('(') | ||
444 | for idx, value in enumerate(node.values): | ||
445 | if idx: | ||
446 | self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)]) | ||
447 | self.visit(value) | ||
448 | self.write(')') | ||
449 | |||
450 | def visit_Compare(self, node): | ||
451 | self.write('(') | ||
452 | self.write(node.left) | ||
453 | for op, right in zip(node.ops, node.comparators): | ||
454 | self.write(' %s %%' % CMPOP_SYMBOLS[type(op)]) | ||
455 | self.visit(right) | ||
456 | self.write(')') | ||
457 | |||
458 | def visit_UnaryOp(self, node): | ||
459 | self.write('(') | ||
460 | op = UNARYOP_SYMBOLS[type(node.op)] | ||
461 | self.write(op) | ||
462 | if op == 'not': | ||
463 | self.write(' ') | ||
464 | self.visit(node.operand) | ||
465 | self.write(')') | ||
466 | |||
467 | def visit_Subscript(self, node): | ||
468 | self.visit(node.value) | ||
469 | self.write('[') | ||
470 | self.visit(node.slice) | ||
471 | self.write(']') | ||
472 | |||
473 | def visit_Slice(self, node): | ||
474 | if node.lower is not None: | ||
475 | self.visit(node.lower) | ||
476 | self.write(':') | ||
477 | if node.upper is not None: | ||
478 | self.visit(node.upper) | ||
479 | if node.step is not None: | ||
480 | self.write(':') | ||
481 | if not (isinstance(node.step, Name) and node.step.id == 'None'): | ||
482 | self.visit(node.step) | ||
483 | |||
484 | def visit_ExtSlice(self, node): | ||
485 | for idx, item in node.dims: | ||
486 | if idx: | ||
487 | self.write(', ') | ||
488 | self.visit(item) | ||
489 | |||
490 | def visit_Yield(self, node): | ||
491 | self.write('yield ') | ||
492 | self.visit(node.value) | ||
493 | |||
494 | def visit_Lambda(self, node): | ||
495 | self.write('lambda ') | ||
496 | self.signature(node.args) | ||
497 | self.write(': ') | ||
498 | self.visit(node.body) | ||
499 | |||
500 | def visit_Ellipsis(self, node): | ||
501 | self.write('Ellipsis') | ||
502 | |||
503 | def generator_visit(left, right): | ||
504 | def visit(self, node): | ||
505 | self.write(left) | ||
506 | self.visit(node.elt) | ||
507 | for comprehension in node.generators: | ||
508 | self.visit(comprehension) | ||
509 | self.write(right) | ||
510 | return visit | ||
511 | |||
512 | visit_ListComp = generator_visit('[', ']') | ||
513 | visit_GeneratorExp = generator_visit('(', ')') | ||
514 | visit_SetComp = generator_visit('{', '}') | ||
515 | del generator_visit | ||
516 | |||
517 | def visit_DictComp(self, node): | ||
518 | self.write('{') | ||
519 | self.visit(node.key) | ||
520 | self.write(': ') | ||
521 | self.visit(node.value) | ||
522 | for comprehension in node.generators: | ||
523 | self.visit(comprehension) | ||
524 | self.write('}') | ||
525 | |||
526 | def visit_IfExp(self, node): | ||
527 | self.visit(node.body) | ||
528 | self.write(' if ') | ||
529 | self.visit(node.test) | ||
530 | self.write(' else ') | ||
531 | self.visit(node.orelse) | ||
532 | |||
533 | def visit_Starred(self, node): | ||
534 | self.write('*') | ||
535 | self.visit(node.value) | ||
536 | |||
537 | def visit_Repr(self, node): | ||
538 | # XXX: python 2.6 only | ||
539 | self.write('`') | ||
540 | self.visit(node.value) | ||
541 | self.write('`') | ||
542 | |||
543 | # Helper Nodes | ||
544 | |||
545 | def visit_alias(self, node): | ||
546 | self.write(node.name) | ||
547 | if node.asname is not None: | ||
548 | self.write(' as ' + node.asname) | ||
549 | |||
550 | def visit_comprehension(self, node): | ||
551 | self.write(' for ') | ||
552 | self.visit(node.target) | ||
553 | self.write(' in ') | ||
554 | self.visit(node.iter) | ||
555 | if node.ifs: | ||
556 | for if_ in node.ifs: | ||
557 | self.write(' if ') | ||
558 | self.visit(if_) | ||
559 | |||
560 | def visit_excepthandler(self, node): | ||
561 | self.newline(node) | ||
562 | self.write('except') | ||
563 | if node.type is not None: | ||
564 | self.write(' ') | ||
565 | self.visit(node.type) | ||
566 | if node.name is not None: | ||
567 | self.write(' as ') | ||
568 | self.visit(node.name) | ||
569 | self.write(':') | ||
570 | self.body(node.body) | ||