~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
"""
Some support for genxxx implementations of source generators.
Another name could be genEric, but well...
"""

from __future__ import generators

import sys

from pypy.objspace.flow.model import Block
from pypy.objspace.flow.model import traverse

# ordering the blocks of a graph by source position

def ordered_blocks(graph):
    # collect all blocks
    allblocks = []
    def visit(block):
        if isinstance(block, Block):
            # first we order by offset in the code string
            if block.operations:
                ofs = block.operations[0].offset
            else:
                ofs = sys.maxint
            # then we order by input variable name or value
            if block.inputargs:
                txt = str(block.inputargs[0])
            else:
                txt = "dummy"
            allblocks.append((ofs, txt, block))
    traverse(visit, graph)
    allblocks.sort()
    #for ofs, txt, block in allblocks:
    #    print ofs, txt, block
    return [block for ofs, txt, block in allblocks]

# a unique list, similar to a list.
# append1 appends an object only if it is not there, already.

class UniqueList(list):
    def __init__(self, *args, **kwds):
        list.__init__(self, *args, **kwds)
        self.dic = {}

    def append1(self, arg):
        try:
            self.dic[arg]
        except KeyError:
            self.dic[arg] = 1
            list.append(self, arg)
        except TypeError: # not hashable
            if arg not in self:
                list.append(self, arg)

def builtin_base(obj):
    typ = type(obj)
    from copy_reg import _HEAPTYPE
    while typ.__flags__&_HEAPTYPE:
        typ = typ.__base__
    return typ

def c_string(s):
    return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),)

def uniquemodulename(name, SEEN={}):
    # never reuse the same module name within a Python session!
    i = 0
    while True:
        i += 1
        result = '%s_%d' % (name, i)
        if result not in SEEN:
            SEEN[result] = True
            return result

# a translation table suitable for str.translate() to remove
# non-C characters from an identifier
C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or
                          'a' <= chr(i) <= 'z' or
                          'A' <= chr(i) <= 'Z') and chr(i) or '_')
                        for i in range(256)])

# a name manager knows about all global and local names in the
# program and keeps them disjoint. It provides ways to generate
# shorter local names with and without wrapping prefixes,
# while always keeping all globals visible.

class NameManager(object):
    def __init__(self):
        self.seennames = {}
        self.scope = 0
        self.scopelist = []

    def make_reserved_names(self, txt):
        """add names to list of known names. If one exists already,
        then we raise an exception. This function should be called
        before generating any new names."""
        for name in txt.split():
            if name in self.seennames:
                raise NameError, "%s has already been seen!"
            self.seennames[name] = 1

    def uniquename(self, basename):
        basename = basename.translate(C_IDENTIFIER)
        n = self.seennames.get(basename, 0)
        self.seennames[basename] = n+1
        if basename in ('v', 'w_'):
            if n == 0:
                return '%s%d' % (basename, n)
            else:
                return self.uniquename('%s%d' % (basename, n))
        if n == 0:
            return basename
        else:
            return self.uniquename('%s_%d' % (basename, n))

    def localScope(self, parent=None):
        ret = _LocalScope(self, parent)
        while ret.scope >= len(self.scopelist):
            self.scopelist.append({})
        return ret

class _LocalScope(object):
    """track local names without hiding globals or nested locals"""
    def __init__(self, glob, parent):
        self.glob = glob
        if not parent:
            parent = glob
        self.parent = parent
        self.mapping = {}
        self.usednames = {}
        self.scope = parent.scope + 1

    def uniquename(self, basename):
        basename = basename.translate(C_IDENTIFIER)
        glob = self.glob
        p = self.usednames.get(basename, 0)
        self.usednames[basename] = p+1
        namesbyscope = glob.scopelist[self.scope]
        namelist = namesbyscope.setdefault(basename, [])
        if p == len(namelist):
            namelist.append(glob.uniquename(basename))
        return namelist[p]

    def localname(self, name, wrapped=False):
        """modify and mangle local names"""
        if name in self.mapping:
            return self.mapping[name]
        scorepos = name.rfind("_")
        if name.startswith("v") and name[1:].isdigit():
            basename = ('v', 'w_') [wrapped]
        elif scorepos >= 0 and name[scorepos+1:].isdigit():
            basename = name[:scorepos]
            # for wrapped named things, prepend a w_
            # for other named things, prepend a l_.
            # XXX The latter is needed because tcc has a nasty parser bug that
            # produces errors if names co-incide with global typedefs,
            # if the type prefix is itself a typedef reference!
            # XXX report this bug to the tcc maintainer(s)
            # YYY drop this comment afterwards, but keep the code, it's better.
            basename = ("l_", "w_")[wrapped] + basename
        else:
            basename = name
        ret = self.uniquename(basename)
        self.mapping[name] = ret
        return ret