File: astlib.py

package info (click to toggle)
jython 2.5.3-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 43,304 kB
  • sloc: python: 351,314; java: 216,338; xml: 1,547; sh: 330; perl: 124; ansic: 102; makefile: 101
file content (148 lines) | stat: -rw-r--r-- 4,436 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python
"""lispify_ast - returns a tuple representation of the AST

Uses 2.5's _ast, not other AST implementations in CPython, since these
are not used by the compilation phase. And that's what we're
interested in.

Since this is a tuple, we can directly compare, and this is going to
be handy when comparing Jython's implementation vs CPython.

"""

import _ast
import os
import globwalk

def lispify_ast(node):
    return tuple(lispify_ast2(node))

def lispify_ast2(node):
    yield node.__class__.__name__
    try:
        for field in node._fields:
            yield tuple(lispify_field(field, getattr(node, field)))
    except:
        pass

def lispify_field(field, child):
    yield field
    if not isinstance(child, list):
        children = [child]
    else:
        children = child

    for node in children:
        if isinstance(node, _ast.AST):
            yield lispify_ast(node)
        else:
            if isinstance(node, float):
                #XXX: stringify floats so they match Java's float representation better
                #This may mask problems for very small numbers.
                if .0001 < node < 10000:
                    yield "%5.5f" % node
                else:
                    yield "%.5e" % node
            else:
                yield node

def main(code_path, jy_exe="jython", testfile=False, print_diff=True, print_fail=False, print_success=False, print_diff_lines=False):
    from pprint import pprint
    from popen2 import popen2
    from StringIO import StringIO
    from difflib import Differ

    if testfile:
        pyfiles = [f.rstrip() for f in file(code_path)]
    elif os.path.isdir(code_path):
        pyfiles = globwalk.GlobDirectoryWalker(code_path, "*.py")
    else:
        pyfiles = [code_path]

    for pyfile in pyfiles:
        ast = compile(open(pyfile).read(), pyfile, "exec", _ast.PyCF_ONLY_AST)
        lispified = lispify_ast(ast)
        sio = StringIO()
        pprint(lispified, stream=sio)

        fin, fout = popen2("%s jastlib.py %s" % (jy_exe, pyfile))

        sio.seek(0)
        pstr = sio.readlines()
        jstr = fin.readlines()

        differs = False
        diffstr = []
        difflines = 0
        diff = Differ()
        results = diff.compare(pstr, jstr)
        for d in results:
            diffstr.append(d)
            if d[0] in ['+', '-']:
                differs = True
                difflines += 1

        if print_success and not differs:
            print "SUCCESS: %s" % pyfile

        if print_fail and differs:
            print "FAIL: %s" % pyfile

        if print_diff_lines:
            print "%s diff lines in %s" % (difflines, pyfile)

        if print_diff and differs:
            print "---------- ouput -------------"
            print "py: %s" % sio.getvalue()
            print "jy: %s" % "".join(jstr)
            print "---------- DIFF -------------"
            print "".join(diffstr)

if __name__ == '__main__':
    import sys
    import getopt

    usage = """\
Usage: python %s [-j jython_exe_name] [-t testfile] [-s -f -d -n] code_path
       where -s = print success messages
             -f = print failure messages
             -n = print number of diff lines
             -d = don't print diffs on failure
             -t = treat codepath as a file containing a list of filenames to test
             -j jython_exe_name = runs jython with jython_exe_name
       unless -t is specified, if codepath is a file test it, if codepath is a directory
             test all .py files in and below that directory.
""" % sys.argv[0]

    testfile = False
    jy_exe = 'jython'
    print_diff = True
    print_diff_lines = False
    print_fail = False
    print_success = False
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'j:tsfdhn')
    except:
        print usage
        sys.exit(1)
    for o, v in opts:
        if o == '-h':
            print usage
            sys.exit(0)
        if o == '-j' and v != '':
            jy_exe = v
        if o == '-t':
            testfile = True
        if o == '-s':
            print_success = True
        if o == '-f':
            print_fail = True
        if o == '-d':
            print_diff = False
        if o == '-n':
            print_diff_lines = True
    if len(args) < 1 or len(args) > 7:
        print usage
        sys.exit(1)

    main(args[0], jy_exe, testfile, print_diff, print_fail, print_success, print_diff_lines)