~mwhudson/pypy/imported-translator-without-old-genc

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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
"""PyPy Translator Frontend

The Translator is a glue class putting together the various pieces of the
translation-related code.  It can be used for interactive testing of the
translator; see pypy/bin/translator.py.
"""
import autopath, os, sys

from pypy.objspace.flow.model import *
from pypy.translator.simplify import simplify_graph
from pypy.translator.gensupp import uniquemodulename
from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring
from pypy.translator.tool.buildpyxmodule import make_module_from_c
from pypy.objspace.flow import FlowObjSpace


class Translator:

    def __init__(self, func=None, verbose=False, simplifying=True,
                 do_imports_immediately=True,
                 builtins_can_raise_exceptions=False):
        self.entrypoint = func
        self.verbose = verbose
        self.simplifying = simplifying
        self.builtins_can_raise_exceptions = builtins_can_raise_exceptions
        self.do_imports_immediately = do_imports_immediately
        self.clear()

    def clear(self):
        """Clear all annotations and all flow graphs."""
        self.annotator = None
        self.rtyper = None
        self.flowgraphs = {}  # {function: graph}
        self.functions = []   # the keys of self.flowgraphs, in creation order
        self.callgraph = {}   # {opaque_tag: (caller, callee)}
        self.frozen = False   # when frozen, no more flowgraphs can be generated
        #self.concretetypes = {}  # see getconcretetype()
        #self.ctlist = []         #  "
        if self.entrypoint:
            self.getflowgraph()

    def getflowgraph(self, func=None, called_by=None, call_tag=None):
        """Get the flow graph for a function (default: the entry point)."""
        func = func or self.entrypoint
        try:
            graph = self.flowgraphs[func]
        except KeyError:
            if self.verbose:
                print 'getflowgraph (%s:%d) %s' % (
                    func.func_globals.get('__name__', '?'),
                    func.func_code.co_firstlineno,
                    func.__name__),
                sys.stdout.flush()
            assert not self.frozen
            space = FlowObjSpace()
            space.builtins_can_raise_exceptions = self.builtins_can_raise_exceptions
            space.do_imports_immediately = self.do_imports_immediately
            graph = space.build_flow(func)
            if self.simplifying:
                simplify_graph(graph, self.simplifying)
            if self.verbose:
                print
            self.flowgraphs[func] = graph
            self.functions.append(func)
            try:
                import inspect
                graph.func = func
                graph.source = inspect.getsource(func)
            except IOError:
                pass  # e.g. when func is defined interactively
        if called_by:
            self.callgraph[called_by, func, call_tag] = called_by, func
        return graph

    def gv(self, func=None):
        """Shows the control flow graph for a function (default: all)
        -- requires 'dot' and 'gv'."""
        import os
        from pypy.translator.tool.make_dot import make_dot, make_dot_graphs
        if func is None:
            # show the graph of *all* functions at the same time
            graphs = []
            for func in self.functions:
                graph = self.getflowgraph(func)
                graphs.append((graph.name, graph))
            dest = make_dot_graphs(self.entrypoint.__name__, graphs)
        else:
            graph = self.getflowgraph(func)
            dest = make_dot(graph.name, graph)
        os.system('gv %s' % str(dest))

    def view(self, *functions):
        """Shows the control flow graph with annotations if computed.
        Requires 'dot' and pygame."""
        from pypy.translator.tool.graphpage import FlowGraphPage
        FlowGraphPage(self).display()

    def viewcg(self):
        """Shows the whole call graph and the class hierarchy, based on
        the computed annotations."""
        from pypy.translator.tool.graphpage import TranslatorPage
        TranslatorPage(self).display()

    def simplify(self, func=None, passes=True):
        """Simplifies the control flow graph (default: for all functions)."""
        if func is None:
            for func in self.flowgraphs.keys():
                self.simplify(func)
        else:
            graph = self.getflowgraph(func)
            simplify_graph(graph, passes)
            
    def annotate(self, input_args_types, func=None, policy=None):
        """annotate(self, input_arg_types[, func]) -> Annotator

        Provides type information of arguments. Returns annotator.
        """
        func = func or self.entrypoint
        if self.annotator is None:
            from pypy.translator.annrpython import RPythonAnnotator
            self.annotator = RPythonAnnotator(self, policy=policy)
        graph = self.getflowgraph(func)
        self.annotator.build_types(graph, input_args_types, func)
        return self.annotator

    def checkgraphs(self):
        for graph in self.flowgraphs.itervalues():
            checkgraph(graph)

    def specialize(self):
        if self.annotator is None:
            raise ValueError("you need to call annotate() first")
        if self.rtyper is not None:
            raise ValueError("cannot specialize() several times")
        from pypy.rpython.rtyper import RPythonTyper
        self.rtyper = RPythonTyper(self.annotator)
        self.rtyper.specialize()

    def source(self, func=None):
        """Returns original Python source.
        
        Returns <interactive> for functions written while the
        interactive session.
        """
        func = func or self.entrypoint
        graph = self.getflowgraph(func)
        return getattr(graph, 'source', '<interactive>')

    def pyrex(self, input_arg_types=None, func=None):
        """pyrex(self[, input_arg_types][, func]) -> Pyrex translation

        Returns Pyrex translation. If input_arg_types is provided,
        returns type annotated translation. Subsequent calls are
        not affected by this.
        """
        from pypy.translator.pyrex.genpyrex import GenPyrex
        return self.generatecode(GenPyrex, input_arg_types, func)

    def cl(self, input_arg_types=None, func=None):
        """cl(self[, input_arg_types][, func]) -> Common Lisp translation
        
        Returns Common Lisp translation. If input_arg_types is provided,
        returns type annotated translation. Subsequent calls are
        not affected by this.
        """
        from pypy.translator.gencl import GenCL
        return self.generatecode(GenCL, input_arg_types, func)

    def c(self):
        """c(self) -> C (CPython) translation
        
        Returns C (CPython) translation.
        """
        from pypy.translator.c import genc
        from cStringIO import StringIO
        f = StringIO()
        database, ignored = genc.translator2database(self)
        genc.gen_readable_parts_of_main_c_file(f, database)
        return f.getvalue()

    def llvm(self):
        """llvm(self) -> LLVM translation
        
        Returns LLVM translation.
        """
        from pypy.translator.llvm import genllvm
        if self.annotator is None:
            raise genllvm.CompileError, "function has to be annotated."
        gen = genllvm.LLVMGenerator(self)
        return str(gen)
    
    def generatecode(self, gencls, input_arg_types, func):
        if input_arg_types is None:
            ann = self.annotator
        else:
            from pypy.translator.annrpython import RPythonAnnotator
            ann = RPythonAnnotator(self)
        if func is None:
            codes = [self.generatecode1(gencls, input_arg_types,
                                        self.entrypoint, ann)]
            for func in self.functions:
                if func is not self.entrypoint:
                    code = self.generatecode1(gencls, None, func, ann,
                                              public=False)
                    codes.append(code)
        else:
            codes = [self.generatecode1(gencls, input_arg_types, func, ann)]
        code = self.generateglobaldecl(gencls, func, ann)
        if code:
            codes.insert(0, code)
        return '\n\n#_________________\n\n'.join(codes)

    def generatecode1(self, gencls, input_arg_types, func, ann, public=True):
        graph = self.getflowgraph(func)
        g = gencls(graph)
        g.by_the_way_the_function_was = func   # XXX
        if input_arg_types is not None:
            ann.build_types(graph, input_arg_types, func)
        if ann is not None:
            g.setannotator(ann)
        return g.emitcode(public)

    def generateglobaldecl(self, gencls, func, ann):
        graph = self.getflowgraph(func)
        g = gencls(graph)
        if ann is not None:
            g.setannotator(ann)
        return g.globaldeclarations()

    def pyrexcompile(self):
        """Returns compiled function, compiled using Pyrex.
        """
        from pypy.tool.udir import udir
        name = self.entrypoint.func_name
        pyxcode = self.pyrex()
        mod = make_module_from_pyxstring(name, udir, pyxcode)
        return getattr(mod, name)

    def ccompile(self, really_compile=True):
        """Returns compiled function, compiled using the C generator.
        """
        from pypy.translator.c import genc
        if self.annotator is not None:
            self.frozen = True

        result = genc.genc(self, compile=really_compile)
        if really_compile:  # result is the module
            result = getattr(result, self.entrypoint.func_name)
        return result

    def llvmcompile(self, optimize=True):
        """llvmcompile(self, optimize=True) -> LLVM translation
        
        Returns LLVM translation with or without optimization.
        """
        from pypy.translator.llvm import genllvm
        if self.annotator is None:
            raise genllvm.CompileError, "function has to be annotated."
        gen = genllvm.LLVMGenerator(self)
        return gen.compile(optimize)

    def call(self, *args):
        """Calls underlying Python function."""
        return self.entrypoint(*args)

    def dis(self, func=None):
        """Disassembles underlying Python function to bytecodes."""
        from dis import dis
        dis(func or self.entrypoint)

##    def consider_call(self, ann, func, args):
##        graph = self.getflowgraph(func)
##        ann.addpendingblock(graph.startblock, args)
##        result_var = graph.getreturnvar()
##        try:
##            return ann.binding(result_var)
##        except KeyError:
##            # typical case for the 1st call, because addpendingblock() did
##            # not actually start the analysis of the called function yet.
##            return impossiblevalue

##    def getconcretetype(self, cls, *args):
##        "DEPRECATED.  To be removed"
##        # Return a (cached) 'concrete type' object attached to this translator.
##        # Concrete types are what is put in the 'concretetype' attribute of
##        # the Variables and Constants of the flow graphs by typer.py to guide
##        # the code generators.
##        try:
##            return self.concretetypes[cls, args]
##        except KeyError:
##            result = self.concretetypes[cls, args] = cls(self, *args)
##            self.ctlist.append(result)
##            return result