File: name.py

package info (click to toggle)
python-peachpy 0.0~git20211013.257881e-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 2,452 kB
  • sloc: python: 29,286; ansic: 54; makefile: 44; cpp: 31
file content (147 lines) | stat: -rw-r--r-- 5,955 bytes parent folder | download
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
# This file is part of PeachPy package and is licensed under the Simplified BSD license.
#    See license.rst for the full text of the license.

import six


class Name:
    def __init__(self, name=None, prename=None):
        assert name is None or isinstance(name, str)
        assert prename is None or isinstance(prename, str)
        assert name is None or prename is None, \
            "Either name or prename, but not both, can be specified"
        self.name = name
        self.prename = prename

    def __str__(self):
        if self.name is not None:
            return self.name
        elif self.prename is not None:
            return "<" + self.prename + ">"
        else:
            return "<?>"

    def __repr__(self):
        return str(self)

    def __hash__(self):
        return hash(self.name) ^ id(self)

    def __eq__(self, other):
        return isinstance(other, Name) and (self is other or self.name == other.name)

    def __ne__(self, other):
        return not isinstance(other, Name) or (self is not other and self.name != other.name)

    @staticmethod
    def check_name(name):
        """Verifies that the name is appropriate for a symbol"""
        if not isinstance(name, str):
            raise TypeError("Invalid name %s: string required" % str(name))
        import re
        if not re.match("^[_a-zA-Z]\\w*$", name):
            raise ValueError("Invalid name: " + name)
        if name.startswith("__"):
            raise ValueError("Invalid name %s: names starting with __ are reserved for PeachPy purposes" % name)


class Namespace:
    def __init__(self, scope_name):
        assert scope_name is None or isinstance(scope_name, Name)
        # Name of the namespace.
        self.scope_name = scope_name
        # Map from name string to either Name or Namespace object
        self.names = dict()
        # Map from prename string to a set of Name and Namespace objects
        self.prenames = dict()

    def __str__(self):
        return str(self.scope_name)

    def __hash__(self):
        return hash(self.scope_name)

    def __eq__(self, other):
        return isinstance(other, Namespace) and self.scope_name == other.scope_name

    def __ne__(self, other):
        return not isinstance(other, Namespace) or self.scope_name != other.scope_name

    def add_scoped_name(self, scoped_name):
        assert isinstance(scoped_name, tuple)
        scope_name, subscoped_name = scoped_name[0], scoped_name[1:]
        assert isinstance(scope_name, Name)
        scope = scope_name
        if subscoped_name:
            scope = Namespace(scope_name)
            scope.add_scoped_name(subscoped_name)
        if scope_name.name:
            assert scope_name.prename is None
            if scope_name.name in self.names:
                if subscoped_name and isinstance(self.names[scope_name.name], Namespace):
                    self.names[scope_name.name].add_scoped_name(subscoped_name)
                else:
                    raise ValueError("Name %s already exists" % scope_name.name)
            else:
                self.names[scope_name.name] = scope
        else:
            assert scope_name.name is None
            self.prenames.setdefault(scope_name.prename, set())
            if subscoped_name:
                for subscope in iter(self.prenames[scope_name.prename]):
                    if isinstance(subscope, Namespace) and subscope.scope_name is scope_name:
                        subscope.add_scoped_name(subscoped_name)
                        return
            self.prenames[scope_name.prename].add(scope)

    def assign_names(self):
        # Step 1: assign names to symbols with prenames with no conflicts
        for prename in six.iterkeys(self.prenames):
            if prename is not None:
                if len(self.prenames[prename]) == 1 and prename not in self.names:
                    name_object = next(iter(self.prenames[prename]))
                    self.names[prename] = name_object
                    if isinstance(name_object, Namespace):
                        name_object = name_object.scope_name
                    name_object.name = prename

        # Step 2: assign names to symbols with conflicting prenames
        for prename, prename_objects in six.iteritems(self.prenames):
            if prename is not None:
                suffix = 0
                suffixed_name = prename + str(suffix)
                for name_object in iter(prename_objects):
                    # Check that the name wasn't already assigned at Step 1
                    if name_object.name is None:
                        # Generate a non-conflicting name by appending a suffix
                        while suffixed_name in self.names:
                            suffix += 1
                            suffixed_name = prename + str(suffix)
                        self.names[suffixed_name] = name_object
                        if isinstance(name_object, Namespace):
                            name_object = name_object.scope_name
                        name_object.name = suffixed_name

        # Step 3: assign names to symbols without prenames
        if None in self.prenames:
            unnamed_objects = self.prenames[None]
            suffix = 0
            suffixed_name = "__local" + str(suffix)
            for name_object in iter(unnamed_objects):
                # Generate a non-conflicting name by appending a suffix
                while suffixed_name in self.names:
                    suffix += 1
                    suffixed_name = "__local" + str(suffix)
                self.names[suffixed_name] = name_object
                if isinstance(name_object, Namespace):
                    name_object = name_object.scope_name
                name_object.name = suffixed_name
        pass

    @property
    def name(self):
        return self.scope_name.name

    @property
    def prename(self):
        return self.scope_name.prename