diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
commit | 458120dd40db6b4df55a4e96b650e16798ef06a0 (patch) | |
tree | 8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/python/Demo/parser | |
parent | 3a742c699f6806c1145aea5149bf15de15a0afd7 (diff) |
add hg and python
Diffstat (limited to 'sys/src/cmd/python/Demo/parser')
-rw-r--r-- | sys/src/cmd/python/Demo/parser/FILES | 6 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/README | 31 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/docstring.py | 2 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/example.py | 190 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/simple.py | 1 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/source.py | 27 | ||||
-rwxr-xr-x | sys/src/cmd/python/Demo/parser/test_parser.py | 48 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/texipre.dat | 100 | ||||
-rw-r--r-- | sys/src/cmd/python/Demo/parser/unparse.py | 519 |
9 files changed, 924 insertions, 0 deletions
diff --git a/sys/src/cmd/python/Demo/parser/FILES b/sys/src/cmd/python/Demo/parser/FILES new file mode 100644 index 000000000..1ff59a31a --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/FILES @@ -0,0 +1,6 @@ +Demo/parser +Doc/libparser.tex +Lib/AST.py +Lib/symbol.py +Lib/token.py +Modules/parsermodule.c diff --git a/sys/src/cmd/python/Demo/parser/README b/sys/src/cmd/python/Demo/parser/README new file mode 100644 index 000000000..a576d33b0 --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/README @@ -0,0 +1,31 @@ +These files are from the large example of using the `parser' module. Refer +to the Python Library Reference for more information. + +It also contains examples for the AST parser. + +Files: +------ + + FILES -- list of files associated with the parser module. + + README -- this file. + + example.py -- module that uses the `parser' module to extract + information from the parse tree of Python source + code. + + docstring.py -- sample source file containing only a module docstring. + + simple.py -- sample source containing a "short form" definition. + + source.py -- sample source code used to demonstrate ability to + handle nested constructs easily using the functions + and classes in example.py. + + test_parser.py program to put the parser module through its paces. + + unparse.py AST (2.5) based example to recreate source code + from an AST. This is incomplete; contributions + are welcome. + +Enjoy! diff --git a/sys/src/cmd/python/Demo/parser/docstring.py b/sys/src/cmd/python/Demo/parser/docstring.py new file mode 100644 index 000000000..45a261b61 --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/docstring.py @@ -0,0 +1,2 @@ +"""Some documentation. +""" diff --git a/sys/src/cmd/python/Demo/parser/example.py b/sys/src/cmd/python/Demo/parser/example.py new file mode 100644 index 000000000..2aa9ec285 --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/example.py @@ -0,0 +1,190 @@ +"""Simple code to extract class & function docstrings from a module. + +This code is used as an example in the library reference manual in the +section on using the parser module. Refer to the manual for a thorough +discussion of the operation of this code. +""" + +import os +import parser +import symbol +import token +import types + +from types import ListType, TupleType + + +def get_docs(fileName): + """Retrieve information from the parse tree of a source file. + + fileName + Name of the file to read Python source code from. + """ + source = open(fileName).read() + basename = os.path.basename(os.path.splitext(fileName)[0]) + ast = parser.suite(source) + return ModuleInfo(ast.totuple(), basename) + + +class SuiteInfoBase: + _docstring = '' + _name = '' + + def __init__(self, tree = None): + self._class_info = {} + self._function_info = {} + if tree: + self._extract_info(tree) + + def _extract_info(self, tree): + # extract docstring + if len(tree) == 2: + found, vars = match(DOCSTRING_STMT_PATTERN[1], tree[1]) + else: + found, vars = match(DOCSTRING_STMT_PATTERN, tree[3]) + if found: + self._docstring = eval(vars['docstring']) + # discover inner definitions + for node in tree[1:]: + found, vars = match(COMPOUND_STMT_PATTERN, node) + if found: + cstmt = vars['compound'] + if cstmt[0] == symbol.funcdef: + name = cstmt[2][1] + self._function_info[name] = FunctionInfo(cstmt) + elif cstmt[0] == symbol.classdef: + name = cstmt[2][1] + self._class_info[name] = ClassInfo(cstmt) + + def get_docstring(self): + return self._docstring + + def get_name(self): + return self._name + + def get_class_names(self): + return self._class_info.keys() + + def get_class_info(self, name): + return self._class_info[name] + + def __getitem__(self, name): + try: + return self._class_info[name] + except KeyError: + return self._function_info[name] + + +class SuiteFuncInfo: + # Mixin class providing access to function names and info. + + def get_function_names(self): + return self._function_info.keys() + + def get_function_info(self, name): + return self._function_info[name] + + +class FunctionInfo(SuiteInfoBase, SuiteFuncInfo): + def __init__(self, tree = None): + self._name = tree[2][1] + SuiteInfoBase.__init__(self, tree and tree[-1] or None) + + +class ClassInfo(SuiteInfoBase): + def __init__(self, tree = None): + self._name = tree[2][1] + SuiteInfoBase.__init__(self, tree and tree[-1] or None) + + def get_method_names(self): + return self._function_info.keys() + + def get_method_info(self, name): + return self._function_info[name] + + +class ModuleInfo(SuiteInfoBase, SuiteFuncInfo): + def __init__(self, tree = None, name = "<string>"): + self._name = name + SuiteInfoBase.__init__(self, tree) + if tree: + found, vars = match(DOCSTRING_STMT_PATTERN, tree[1]) + if found: + self._docstring = vars["docstring"] + + +def match(pattern, data, vars=None): + """Match `data' to `pattern', with variable extraction. + + pattern + Pattern to match against, possibly containing variables. + + data + Data to be checked and against which variables are extracted. + + vars + Dictionary of variables which have already been found. If not + provided, an empty dictionary is created. + + The `pattern' value may contain variables of the form ['varname'] which + are allowed to match anything. The value that is matched is returned as + part of a dictionary which maps 'varname' to the matched value. 'varname' + is not required to be a string object, but using strings makes patterns + and the code which uses them more readable. + + This function returns two values: a boolean indicating whether a match + was found and a dictionary mapping variable names to their associated + values. + """ + if vars is None: + vars = {} + if type(pattern) is ListType: # 'variables' are ['varname'] + vars[pattern[0]] = data + return 1, vars + if type(pattern) is not TupleType: + return (pattern == data), vars + if len(data) != len(pattern): + return 0, vars + for pattern, data in map(None, pattern, data): + same, vars = match(pattern, data, vars) + if not same: + break + return same, vars + + +# This pattern identifies compound statements, allowing them to be readily +# differentiated from simple statements. +# +COMPOUND_STMT_PATTERN = ( + symbol.stmt, + (symbol.compound_stmt, ['compound']) + ) + + +# This pattern will match a 'stmt' node which *might* represent a docstring; +# docstrings require that the statement which provides the docstring be the +# first statement in the class or function, which this pattern does not check. +# +DOCSTRING_STMT_PATTERN = ( + symbol.stmt, + (symbol.simple_stmt, + (symbol.small_stmt, + (symbol.expr_stmt, + (symbol.testlist, + (symbol.test, + (symbol.and_test, + (symbol.not_test, + (symbol.comparison, + (symbol.expr, + (symbol.xor_expr, + (symbol.and_expr, + (symbol.shift_expr, + (symbol.arith_expr, + (symbol.term, + (symbol.factor, + (symbol.power, + (symbol.atom, + (token.STRING, ['docstring']) + )))))))))))))))), + (token.NEWLINE, '') + )) diff --git a/sys/src/cmd/python/Demo/parser/simple.py b/sys/src/cmd/python/Demo/parser/simple.py new file mode 100644 index 000000000..184e2fe5d --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/simple.py @@ -0,0 +1 @@ +def f(): "maybe a docstring" diff --git a/sys/src/cmd/python/Demo/parser/source.py b/sys/src/cmd/python/Demo/parser/source.py new file mode 100644 index 000000000..b90062851 --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/source.py @@ -0,0 +1,27 @@ +"""Exmaple file to be parsed for the parsermodule example. + +The classes and functions in this module exist only to exhibit the ability +of the handling information extraction from nested definitions using parse +trees. They shouldn't interest you otherwise! +""" + +class Simple: + "This class does very little." + + def method(self): + "This method does almost nothing." + return 1 + + class Nested: + "This is a nested class." + + def nested_method(self): + "Method of Nested class." + def nested_function(): + "Function in method of Nested class." + pass + return nested_function + +def function(): + "This function lives at the module level." + return 0 diff --git a/sys/src/cmd/python/Demo/parser/test_parser.py b/sys/src/cmd/python/Demo/parser/test_parser.py new file mode 100755 index 000000000..be39bca7f --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/test_parser.py @@ -0,0 +1,48 @@ +#! /usr/bin/env python +# (Force the script to use the latest build.) +# +# test_parser.py + +import parser, traceback + +_numFailed = 0 + +def testChunk(t, fileName): + global _numFailed + print '----', fileName, + try: + ast = parser.suite(t) + tup = parser.ast2tuple(ast) + # this discards the first AST; a huge memory savings when running + # against a large source file like Tkinter.py. + ast = None + new = parser.tuple2ast(tup) + except parser.ParserError, err: + print + print 'parser module raised exception on input file', fileName + ':' + traceback.print_exc() + _numFailed = _numFailed + 1 + else: + if tup != parser.ast2tuple(new): + print + print 'parser module failed on input file', fileName + _numFailed = _numFailed + 1 + else: + print 'o.k.' + +def testFile(fileName): + t = open(fileName).read() + testChunk(t, fileName) + +def test(): + import sys + args = sys.argv[1:] + if not args: + import glob + args = glob.glob("*.py") + args.sort() + map(testFile, args) + sys.exit(_numFailed != 0) + +if __name__ == '__main__': + test() diff --git a/sys/src/cmd/python/Demo/parser/texipre.dat b/sys/src/cmd/python/Demo/parser/texipre.dat new file mode 100644 index 000000000..8ad03a617 --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/texipre.dat @@ -0,0 +1,100 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename parser.info +@settitle Python Parser Module Reference +@setchapternewpage odd +@footnotestyle end +@c %**end of header + +@ifinfo +This file describes the interfaces +published by the optional @code{parser} module and gives examples of +how they may be used. It contains the same text as the chapter on the +@code{parser} module in the @cite{Python Library Reference}, but is +presented as a separate document. + +Copyright 1995-1996 by Fred L. Drake, Jr., Reston, Virginia, USA, and +Virginia Polytechnic Institute and State University, Blacksburg, +Virginia, USA. Portions of the software copyright 1991-1995 by +Stichting Mathematisch Centrum, Amsterdam, The Netherlands. Copying is +permitted under the terms associated with the main Python distribution, +with the additional restriction that this additional notice be included +and maintained on all distributed copies. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Fred L. Drake, Jr. and +Virginia Polytechnic Institute and State University not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +FRED L. DRAKE, JR. AND VIRGINIA POLYTECHNIC INSTITUTE AND STATE +UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +EVENT SHALL FRED L. DRAKE, JR. OR VIRGINIA POLYTECHNIC INSTITUTE AND +STATE UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +@end ifinfo + +@titlepage +@title Python Parser Module Reference +@author Fred L. Drake, Jr. + +@c The following two commands start the copyright page. +@page +@vskip 0pt plus 1filll +Copyright 1995-1996 by Fred L. Drake, Jr., Reston, Virginia, USA, and +Virginia Polytechnic Institute and State University, Blacksburg, +Virginia, USA. Portions of the software copyright 1991-1995 by +Stichting Mathematisch Centrum, Amsterdam, The Netherlands. Copying is +permitted under the terms associated with the main Python distribution, +with the additional restriction that this additional notice be included +and maintained on all distributed copies. + +@center All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Fred L. Drake, Jr. and +Virginia Polytechnic Institute and State University not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +FRED L. DRAKE, JR. AND VIRGINIA POLYTECHNIC INSTITUTE AND STATE +UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +EVENT SHALL FRED L. DRAKE, JR. OR VIRGINIA POLYTECHNIC INSTITUTE AND +STATE UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +@end titlepage + + +@node Top, Overview, (dir), (dir) +@top The Python Parser Module + +@ifinfo +This file describes the interfaces +published by the optional @code{parser} module and gives examples of +how they may be used. It contains the same text as the chapter on the +@code{parser} module in the @cite{Python Library Reference}, but is +presented as a separate document. + +This version corresponds to Python version 1.4 (1 Sept. 1996). + +@end ifinfo + +@c placeholder for the master menu -- patched by texinfo-all-menus-update +@menu +@end menu diff --git a/sys/src/cmd/python/Demo/parser/unparse.py b/sys/src/cmd/python/Demo/parser/unparse.py new file mode 100644 index 000000000..f4dd90c95 --- /dev/null +++ b/sys/src/cmd/python/Demo/parser/unparse.py @@ -0,0 +1,519 @@ +"Usage: unparse.py <path to source file>" +import sys +import _ast +import cStringIO +import os + +class Unparser: + """Methods in this class recursively traverse an AST and + output source code for the abstract syntax; original formatting + is disregarged. """ + + def __init__(self, tree, file = sys.stdout): + """Unparser(tree, file=sys.stdout) -> None. + Print the source for tree to file.""" + self.f = file + self._indent = 0 + self.dispatch(tree) + print >>self.f,"" + self.f.flush() + + def fill(self, text = ""): + "Indent a piece of text, according to the current indentation level" + self.f.write("\n"+" "*self._indent + text) + + def write(self, text): + "Append a piece of text to the current line." + self.f.write(text) + + def enter(self): + "Print ':', and increase the indentation." + self.write(":") + self._indent += 1 + + def leave(self): + "Decrease the indentation level." + self._indent -= 1 + + def dispatch(self, tree): + "Dispatcher function, dispatching tree type T to method _T." + if isinstance(tree, list): + for t in tree: + self.dispatch(t) + return + meth = getattr(self, "_"+tree.__class__.__name__) + meth(tree) + + + ############### Unparsing methods ###################### + # There should be one method per concrete grammar type # + # Constructors should be grouped by sum type. Ideally, # + # this would follow the order in the grammar, but # + # currently doesn't. # + ######################################################## + + def _Module(self, tree): + for stmt in tree.body: + self.dispatch(stmt) + + # stmt + def _Expr(self, tree): + self.fill() + self.dispatch(tree.value) + + def _Import(self, t): + self.fill("import ") + first = True + for a in t.names: + if first: + first = False + else: + self.write(", ") + self.write(a.name) + if a.asname: + self.write(" as "+a.asname) + + def _ImportFrom(self, t): + self.fill("from ") + self.write(t.module) + self.write(" import ") + for i, a in enumerate(t.names): + if i == 0: + self.write(", ") + self.write(a.name) + if a.asname: + self.write(" as "+a.asname) + # XXX(jpe) what is level for? + + def _Assign(self, t): + self.fill() + for target in t.targets: + self.dispatch(target) + self.write(" = ") + self.dispatch(t.value) + + def _AugAssign(self, t): + self.fill() + self.dispatch(t.target) + self.write(" "+self.binop[t.op.__class__.__name__]+"= ") + self.dispatch(t.value) + + def _Return(self, t): + self.fill("return ") + if t.value: + self.dispatch(t.value) + + def _Pass(self, t): + self.fill("pass") + + def _Break(self, t): + self.fill("break") + + def _Continue(self, t): + self.fill("continue") + + def _Delete(self, t): + self.fill("del ") + self.dispatch(t.targets) + + def _Assert(self, t): + self.fill("assert ") + self.dispatch(t.test) + if t.msg: + self.write(", ") + self.dispatch(t.msg) + + def _Exec(self, t): + self.fill("exec ") + self.dispatch(t.body) + if t.globals: + self.write(" in ") + self.dispatch(t.globals) + if t.locals: + self.write(", ") + self.dispatch(t.locals) + + def _Print(self, t): + self.fill("print ") + do_comma = False + if t.dest: + self.write(">>") + self.dispatch(t.dest) + do_comma = True + for e in t.values: + if do_comma:self.write(", ") + else:do_comma=True + self.dispatch(e) + if not t.nl: + self.write(",") + + def _Global(self, t): + self.fill("global") + for i, n in enumerate(t.names): + if i != 0: + self.write(",") + self.write(" " + n) + + def _Yield(self, t): + self.fill("yield") + if t.value: + self.write(" (") + self.dispatch(t.value) + self.write(")") + + def _Raise(self, t): + self.fill('raise ') + if t.type: + self.dispatch(t.type) + if t.inst: + self.write(", ") + self.dispatch(t.inst) + if t.tback: + self.write(", ") + self.dispatch(t.tback) + + def _TryExcept(self, t): + self.fill("try") + self.enter() + self.dispatch(t.body) + self.leave() + + for ex in t.handlers: + self.dispatch(ex) + if t.orelse: + self.fill("else") + self.enter() + self.dispatch(t.orelse) + self.leave() + + def _TryFinally(self, t): + self.fill("try") + self.enter() + self.dispatch(t.body) + self.leave() + + self.fill("finally") + self.enter() + self.dispatch(t.finalbody) + self.leave() + + def _excepthandler(self, t): + self.fill("except ") + if t.type: + self.dispatch(t.type) + if t.name: + self.write(", ") + self.dispatch(t.name) + self.enter() + self.dispatch(t.body) + self.leave() + + def _ClassDef(self, t): + self.write("\n") + self.fill("class "+t.name) + if t.bases: + self.write("(") + for a in t.bases: + self.dispatch(a) + self.write(", ") + self.write(")") + self.enter() + self.dispatch(t.body) + self.leave() + + def _FunctionDef(self, t): + self.write("\n") + for deco in t.decorators: + self.fill("@") + self.dispatch(deco) + self.fill("def "+t.name + "(") + self.dispatch(t.args) + self.write(")") + self.enter() + self.dispatch(t.body) + self.leave() + + def _For(self, t): + self.fill("for ") + self.dispatch(t.target) + self.write(" in ") + self.dispatch(t.iter) + self.enter() + self.dispatch(t.body) + self.leave() + if t.orelse: + self.fill("else") + self.enter() + self.dispatch(t.orelse) + self.leave + + def _If(self, t): + self.fill("if ") + self.dispatch(t.test) + self.enter() + # XXX elif? + self.dispatch(t.body) + self.leave() + if t.orelse: + self.fill("else") + self.enter() + self.dispatch(t.orelse) + self.leave() + + def _While(self, t): + self.fill("while ") + self.dispatch(t.test) + self.enter() + self.dispatch(t.body) + self.leave() + if t.orelse: + self.fill("else") + self.enter() + self.dispatch(t.orelse) + self.leave + + def _With(self, t): + self.fill("with ") + self.dispatch(t.context_expr) + if t.optional_vars: + self.write(" as ") + self.dispatch(t.optional_vars) + self.enter() + self.dispatch(t.body) + self.leave() + + # expr + def _Str(self, tree): + self.write(repr(tree.s)) + + def _Name(self, t): + self.write(t.id) + + def _Repr(self, t): + self.write("`") + self.dispatch(t.value) + self.write("`") + + def _Num(self, t): + self.write(repr(t.n)) + + def _List(self, t): + self.write("[") + for e in t.elts: + self.dispatch(e) + self.write(", ") + self.write("]") + + def _ListComp(self, t): + self.write("[") + self.dispatch(t.elt) + for gen in t.generators: + self.dispatch(gen) + self.write("]") + + def _GeneratorExp(self, t): + self.write("(") + self.dispatch(t.elt) + for gen in t.generators: + self.dispatch(gen) + self.write(")") + + def _comprehension(self, t): + self.write(" for ") + self.dispatch(t.target) + self.write(" in ") + self.dispatch(t.iter) + for if_clause in t.ifs: + self.write(" if ") + self.dispatch(if_clause) + + def _IfExp(self, t): + self.dispatch(t.body) + self.write(" if ") + self.dispatch(t.test) + if t.orelse: + self.write(" else ") + self.dispatch(t.orelse) + + def _Dict(self, t): + self.write("{") + for k,v in zip(t.keys, t.values): + self.dispatch(k) + self.write(" : ") + self.dispatch(v) + self.write(", ") + self.write("}") + + def _Tuple(self, t): + if not t.elts: + self.write("()") + return + self.write("(") + for e in t.elts: + self.dispatch(e) + self.write(", ") + self.write(")") + + unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"} + def _UnaryOp(self, t): + self.write(self.unop[t.op.__class__.__name__]) + self.write("(") + self.dispatch(t.operand) + self.write(")") + + binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%", + "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&", + "FloorDiv":"//", "Pow": "**"} + def _BinOp(self, t): + self.write("(") + self.dispatch(t.left) + self.write(")" + self.binop[t.op.__class__.__name__] + "(") + self.dispatch(t.right) + self.write(")") + + cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=", + "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"} + def _Compare(self, t): + self.write("(") + self.dispatch(t.left) + for o, e in zip(t.ops, t.comparators): + self.write(") " +self.cmpops[o.__class__.__name__] + " (") + self.dispatch(e) + self.write(")") + + boolops = {_ast.And: 'and', _ast.Or: 'or'} + def _BoolOp(self, t): + self.write("(") + self.dispatch(t.values[0]) + for v in t.values[1:]: + self.write(" %s " % self.boolops[t.op.__class__]) + self.dispatch(v) + self.write(")") + + def _Attribute(self,t): + self.dispatch(t.value) + self.write(".") + self.write(t.attr) + + def _Call(self, t): + self.dispatch(t.func) + self.write("(") + comma = False + for e in t.args: + if comma: self.write(", ") + else: comma = True + self.dispatch(e) + for e in t.keywords: + if comma: self.write(", ") + else: comma = True + self.dispatch(e) + if t.starargs: + if comma: self.write(", ") + else: comma = True + self.write("*") + self.dispatch(t.starargs) + if t.kwargs: + if comma: self.write(", ") + else: comma = True + self.write("**") + self.dispatch(t.kwargs) + self.write(")") + + def _Subscript(self, t): + self.dispatch(t.value) + self.write("[") + self.dispatch(t.slice) + self.write("]") + + # slice + def _Ellipsis(self, t): + self.write("...") + + def _Index(self, t): + self.dispatch(t.value) + + def _Slice(self, t): + if t.lower: + self.dispatch(t.lower) + self.write(":") + if t.upper: + self.dispatch(t.upper) + if t.step: + self.write(":") + self.dispatch(t.step) + + def _ExtSlice(self, t): + for i, d in enumerate(t.dims): + if i != 0: + self.write(': ') + self.dispatch(d) + + # others + def _arguments(self, t): + first = True + nonDef = len(t.args)-len(t.defaults) + for a in t.args[0:nonDef]: + if first:first = False + else: self.write(", ") + self.dispatch(a) + for a,d in zip(t.args[nonDef:], t.defaults): + if first:first = False + else: self.write(", ") + self.dispatch(a), + self.write("=") + self.dispatch(d) + if t.vararg: + if first:first = False + else: self.write(", ") + self.write("*"+t.vararg) + if t.kwarg: + if first:first = False + else: self.write(", ") + self.write("**"+t.kwarg) + + def _keyword(self, t): + self.write(t.arg) + self.write("=") + self.dispatch(t.value) + + def _Lambda(self, t): + self.write("lambda ") + self.dispatch(t.args) + self.write(": ") + self.dispatch(t.body) + +def roundtrip(filename, output=sys.stdout): + source = open(filename).read() + tree = compile(source, filename, "exec", 0x400) + Unparser(tree, output) + + + +def testdir(a): + try: + names = [n for n in os.listdir(a) if n.endswith('.py')] + except OSError: + print >> sys.stderr, "Directory not readable: %s" % a + else: + for n in names: + fullname = os.path.join(a, n) + if os.path.isfile(fullname): + output = cStringIO.StringIO() + print 'Testing %s' % fullname + try: + roundtrip(fullname, output) + except Exception, e: + print ' Failed to compile, exception is %s' % repr(e) + elif os.path.isdir(fullname): + testdir(fullname) + +def main(args): + if args[0] == '--testdir': + for a in args[1:]: + testdir(a) + else: + for a in args: + roundtrip(a) + +if __name__=='__main__': + main(sys.argv[1:]) |