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
|