Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'upstream2/master'

  • Loading branch information...
commit 0b17e3c1691d439df2d993a41b9de09011df5177 2 parents 279103e + e9f66a6
@andrewschaaf authored
Showing with 135 additions and 82 deletions.
  1. +105 −82 codegen.py
  2. +30 −0 test/test_codegen.py
View
187 codegen.py
@@ -7,43 +7,51 @@
:copyright: Copyright 2008 by Armin Ronacher.
:license: BSD.
"""
+
+# Updated ton contain latest pull requests from Doboy, jbremer,
+# gemoe100, and cwa-, even though those have not been pulled into
+# andreif's repo
+
from ast import *
-BINOP_SYMBOLS = {}
-BINOP_SYMBOLS[Add] = '+'
-BINOP_SYMBOLS[Sub] = '-'
-BINOP_SYMBOLS[Mult] = '*'
-BINOP_SYMBOLS[Div] = '/'
-BINOP_SYMBOLS[Mod] = '%'
-BINOP_SYMBOLS[Pow] = '**'
-BINOP_SYMBOLS[LShift] = '<<'
-BINOP_SYMBOLS[RShift] = '>>'
-BINOP_SYMBOLS[BitOr] = '|'
-BINOP_SYMBOLS[BitXor] = '^'
-BINOP_SYMBOLS[BitAnd] = '&'
-BINOP_SYMBOLS[FloorDiv] = '//'
-
-BOOLOP_SYMBOLS = {}
-BOOLOP_SYMBOLS[And] = 'and'
-BOOLOP_SYMBOLS[Or] = 'or'
-
-CMPOP_SYMBOLS = {}
-CMPOP_SYMBOLS[Eq] = '=='
-CMPOP_SYMBOLS[NotEq] = '!='
-CMPOP_SYMBOLS[Lt] = '<'
-CMPOP_SYMBOLS[LtE] = '<='
-CMPOP_SYMBOLS[Gt] = '>'
-CMPOP_SYMBOLS[GtE] = '>='
-CMPOP_SYMBOLS[Is] = 'is'
-CMPOP_SYMBOLS[IsNot] = 'is not'
-CMPOP_SYMBOLS[In] = 'in'
-CMPOP_SYMBOLS[NotIn] = 'not in'
-
-UNARYOP_SYMBOLS = {}
-UNARYOP_SYMBOLS[Invert] = '~'
-UNARYOP_SYMBOLS[Not] = 'not'
-UNARYOP_SYMBOLS[UAdd] = '+'
-UNARYOP_SYMBOLS[USub] = '-'
+BOOLOP_SYMBOLS = {
+ And: 'and',
+ Or: 'or'
+}
+
+BINOP_SYMBOLS = {
+ Add: '+',
+ Sub: '-',
+ Mult: '*',
+ Div: '/',
+ FloorDiv: '//',
+ Mod: '%',
+ LShift: '<<',
+ RShift: '>>',
+ BitOr: '|',
+ BitAnd: '&',
+ BitXor: '^'
+}
+
+CMPOP_SYMBOLS = {
+ Eq: '==',
+ Gt: '>',
+ GtE: '>=',
+ In: 'in',
+ Is: 'is',
+ IsNot: 'is not',
+ Lt: '<',
+ LtE: '<=',
+ NotEq: '!=',
+ NotIn: 'not in'
+}
+
+UNARYOP_SYMBOLS = {
+ Invert: '~',
+ Not: 'not',
+ UAdd: '+',
+ USub: '-'
+}
def to_source(node, indent_with=' ' * 4, add_line_information=False):
@@ -69,6 +77,7 @@ def to_source(node, indent_with=' ' * 4, add_line_information=False):
return ''.join(generator.result)
+
class SourceGenerator(NodeVisitor):
"""This visitor is able to transform a well formed syntax tree into python
sourcecode. For more details have a look at the docstring of the
@@ -138,29 +147,32 @@ def decorators(self, node):
self.write('@')
self.visit(decorator)
+ # Module
+ def visit_Module(self, node):
+ NodeVisitor.generic_visit(self, node)
+ self.write('\n')
+
# Statements
def visit_Assert(self, node):
self.newline(node)
self.write('assert ')
self.visit(node.test)
- if node.msg is not None:
- self.write(', ')
- self.visit(node.msg)
+ if node.msg:
+ self.write(', ')
+ self.visit(node.msg)
def visit_Assign(self, node):
self.newline(node)
for idx, target in enumerate(node.targets):
- if idx:
- self.write(', ')
self.visit(target)
- self.write(' = ')
+ self.write(' = ')
self.visit(node.value)
def visit_AugAssign(self, node):
self.newline(node)
self.visit(node.target)
- self.write(' ' + BINOP_SYMBOLS[type(node.op)] + '= ')
+ self.write(BINOP_SYMBOLS[type(node.op)] + '=')
self.visit(node.value)
def visit_ImportFrom(self, node):
@@ -169,13 +181,17 @@ def visit_ImportFrom(self, node):
for idx, item in enumerate(node.names):
if idx:
self.write(', ')
- self.write(item)
+ self.write(item.name)
+ if item.asname is not None:
+ self.write(' as ')
+ self.write(item.asname)
def visit_Import(self, node):
self.newline(node)
for item in node.names:
self.write('import ')
self.visit(item)
+ self.newline(node)
def visit_Expr(self, node):
self.newline(node)
@@ -186,7 +202,7 @@ def visit_FunctionDef(self, node):
self.decorators(node)
self.newline(node)
self.write('def %s(' % node.name)
- self.visit(node.args)
+ self.signature(node.args)
self.write('):')
self.body(node.body)
@@ -232,9 +248,7 @@ def visit_If(self, node):
self.body(node.body)
while True:
else_ = node.orelse
- if len(else_) == 0:
- break
- elif len(else_) == 1 and isinstance(else_[0], If):
+ if len(else_) == 1 and isinstance(else_[0], If):
node = else_[0]
self.newline()
self.write('elif ')
@@ -242,9 +256,10 @@ def visit_If(self, node):
self.write(':')
self.body(node.body)
else:
- self.newline()
- self.write('else:')
- self.body(else_)
+ if else_:
+ self.newline()
+ self.write('else:')
+ self.body(else_)
break
def visit_For(self, node):
@@ -297,7 +312,7 @@ def visit_Print(self, node):
def visit_Delete(self, node):
self.newline(node)
self.write('del ')
- for idx, target in enumerate(node):
+ for idx, target in enumerate(node.targets):
if idx:
self.write(', ')
self.visit(target)
@@ -308,6 +323,32 @@ def visit_TryExcept(self, node):
self.body(node.body)
for handler in node.handlers:
self.visit(handler)
+ if node.orelse:
+ self.newline(node)
+ self.write('else:')
+ self.body(node.orelse)
+
+ def visit_ExceptHandler(self, node):
+ self.newline(node)
+ self.write('except')
+ if node.type:
+ self.write(' ')
+ self.visit(node.type)
+ if node.name:
+ self.write(' as ')
+ self.visit(node.name)
+ self.write(':')
+ self.body(node.body)
+
+ def visit_ExceptHandler(self, node):
+ self.newline(node)
+ self.write('except ')
+ self.visit(node.type)
+ if node.name is not None:
+ self.write(', ')
+ self.visit(node.name)
+ self.write(':')
+ self.body(node.body)
def visit_TryFinally(self, node):
self.newline(node)
@@ -327,11 +368,8 @@ def visit_Nonlocal(self, node):
def visit_Return(self, node):
self.newline(node)
- if node.value is None:
- self.write('return')
- else:
- self.write('return ')
- self.visit(node.value)
+ self.write('return ')
+ self.visit(node.value)
def visit_Break(self, node):
self.newline(node)
@@ -414,7 +452,7 @@ def visit_Tuple(self, node):
self.visit(item)
self.write(idx and ')' or ',)')
- def sequence_visit(left, right):
+ def _sequence_visit(left, right): # pylint: disable=E0213
def visit(self, node):
self.write(left)
for idx, item in enumerate(node.elts):
@@ -424,9 +462,8 @@ def visit(self, node):
self.write(right)
return visit
- visit_List = sequence_visit('[', ']')
- visit_Set = sequence_visit('{', '}')
- del sequence_visit
+ visit_List = _sequence_visit('[', ']')
+ visit_Set = _sequence_visit('{', '}')
def visit_Dict(self, node):
self.write('{')
@@ -439,9 +476,11 @@ def visit_Dict(self, node):
self.write('}')
def visit_BinOp(self, node):
+ self.write('(')
self.visit(node.left)
self.write(' %s ' % BINOP_SYMBOLS[type(node.op)])
self.visit(node.right)
+ self.write(')')
def visit_BoolOp(self, node):
self.write('(')
@@ -486,7 +525,7 @@ def visit_Slice(self, node):
self.visit(node.step)
def visit_ExtSlice(self, node):
- for idx, item in node.dims:
+ for idx, item in enumerate(node.dims):
if idx:
self.write(', ')
self.visit(item)
@@ -497,14 +536,14 @@ def visit_Yield(self, node):
def visit_Lambda(self, node):
self.write('lambda ')
- self.visit(node.args)
+ self.signature(node.args)
self.write(': ')
self.visit(node.body)
def visit_Ellipsis(self, node):
self.write('Ellipsis')
- def generator_visit(left, right):
+ def _generator_visit(left, right): # pylint: disable=E0213
def visit(self, node):
self.write(left)
self.visit(node.elt)
@@ -513,10 +552,9 @@ def visit(self, node):
self.write(right)
return visit
- visit_ListComp = generator_visit('[', ']')
- visit_GeneratorExp = generator_visit('(', ')')
- visit_SetComp = generator_visit('{', '}')
- del generator_visit
+ visit_ListComp = _generator_visit('[', ']')
+ visit_GeneratorExp = _generator_visit('(', ')')
+ visit_SetComp = _generator_visit('{', '}')
def visit_DictComp(self, node):
self.write('{')
@@ -560,18 +598,3 @@ def visit_comprehension(self, node):
for if_ in node.ifs:
self.write(' if ')
self.visit(if_)
-
- def visit_excepthandler(self, node):
- self.newline(node)
- self.write('except')
- if node.type is not None:
- self.write(' ')
- self.visit(node.type)
- if node.name is not None:
- self.write(' as ')
- self.visit(node.name)
- self.write(':')
- self.body(node.body)
-
- def visit_arguments(self, node):
- self.signature(node)
View
30 test/test_codegen.py
@@ -0,0 +1,30 @@
+import codegen
+import ast
+
+def to_ast_and_back_again(source):
+ return codegen.to_source(ast.parse(source))
+
+def test_del():
+ source = "del l[0]"
+ assert source == to_ast_and_back_again(source)
+ source = "del obj.x"
+ assert source == to_ast_and_back_again(source)
+
+def test_try_expect():
+ source = ("try:\n"
+ " '#'[2]\n"
+ "except IndexError:\n"
+ " print 'What did you expect?!'")
+ assert source == to_ast_and_back_again(source)
+ source = ("try:\n"
+ " l = []\n"
+ " l[1]\n"
+ "except IndexError, index_error:\n"
+ " print index_error")
+ assert source == to_ast_and_back_again(source)
+
+def test_import():
+ source = "import intertools as iterators"
+ assert source == to_ast_and_back_again(source)
+ source = "from math import floor as fl, ceil as cl"
+ assert source == to_ast_and_back_again(source)
Please sign in to comment.
Something went wrong with that request. Please try again.