Coverage for pyVHDLModel/Name.py: 80%

92 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-20 22:13 +0000

1# ==================================================================================================================== # 

2# __ ___ _ ____ _ __ __ _ _ # 

3# _ __ _ \ \ / / | | | _ \| | | \/ | ___ __| | ___| | # 

4# | '_ \| | | \ \ / /| |_| | | | | | | |\/| |/ _ \ / _` |/ _ \ | # 

5# | |_) | |_| |\ V / | _ | |_| | |___| | | | (_) | (_| | __/ | # 

6# | .__/ \__, | \_/ |_| |_|____/|_____|_| |_|\___/ \__,_|\___|_| # 

7# |_| |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2017-2024 Patrick Lehmann - Boetzingen, Germany # 

15# Copyright 2016-2017 Patrick Lehmann - Dresden, Germany # 

16# # 

17# Licensed under the Apache License, Version 2.0 (the "License"); # 

18# you may not use this file except in compliance with the License. # 

19# You may obtain a copy of the License at # 

20# # 

21# http://www.apache.org/licenses/LICENSE-2.0 # 

22# # 

23# Unless required by applicable law or agreed to in writing, software # 

24# distributed under the License is distributed on an "AS IS" BASIS, # 

25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

26# See the License for the specific language governing permissions and # 

27# limitations under the License. # 

28# # 

29# SPDX-License-Identifier: Apache-2.0 # 

30# ==================================================================================================================== # 

31# 

32""" 

33This module contains parts of an abstract document language model for VHDL. 

34 

35VHDL uses *names* to express cross-references from *usage locations* to *declarations*. Here, *names* are single or 

36combined identifiers. :mod:`Symbols <pyVHDLModel.Symbol>` are structures representing a *name* and a reference 

37(pointer) to the referenced vhdl language entity. 

38""" 

39from typing import List, Iterable, Optional as Nullable 

40 

41from pyTooling.Decorators import export, readonly 

42 

43from pyVHDLModel.Base import ModelEntity, ExpressionUnion 

44 

45 

46@export 

47class Name(ModelEntity): 

48 """``Name`` is the base-class for all *names* in the VHDL language model.""" 

49 

50 _identifier: str 

51 _normalizedIdentifier: str 

52 _root: Nullable['Name'] # TODO: seams to be unused. There is no reverse linking, or? 

53 _prefix: Nullable['Name'] 

54 

55 def __init__(self, identifier: str, prefix: Nullable["Name"] = None, parent: ModelEntity = None) -> None: 

56 super().__init__(parent) 

57 

58 self._identifier = identifier 

59 self._normalizedIdentifier = identifier.lower() 

60 

61 if prefix is None: 

62 self._prefix = None 

63 self._root = self 

64 else: 

65 self._prefix = prefix 

66 self._root = prefix._root 

67 

68 @readonly 

69 def Identifier(self) -> str: 

70 """ 

71 The identifier the name is referencing. 

72 

73 :returns: The referenced identifier. 

74 """ 

75 return self._identifier 

76 

77 @readonly 

78 def NormalizedIdentifier(self) -> str: 

79 """ 

80 The normalized identifier the name is referencing. 

81 

82 :returns: The referenced identifier (normalized). 

83 """ 

84 return self._normalizedIdentifier 

85 

86 @readonly 

87 def Root(self) -> 'Name': 

88 """ 

89 The root (left-most) element in a chain of names. 

90 

91 In case the name is a :class:`simple name <SimpleName>`, the root points to the name itself. 

92 

93 :returns: The name's root element. 

94 """ 

95 return self._root 

96 

97 @readonly 

98 def Prefix(self) -> Nullable['Name']: 

99 """ 

100 The name's prefix in a chain of names. 

101 

102 :returns: The name left from current name, if not a simple name, otherwise ``None``. 

103 """ 

104 return self._prefix 

105 

106 @readonly 

107 def HasPrefix(self) -> bool: 

108 """ 

109 Returns true, if the name has a prefix. 

110 

111 This is true for all names except :class:`simple names <SimpleName>`. 

112 

113 :returns: ``True``, if the name as a prefix. 

114 """ 

115 return self._prefix is not None 

116 

117 def __repr__(self) -> str: 

118 return f"Name: '{self.__str__()}'" 

119 

120 def __str__(self) -> str: 

121 return self._identifier 

122 

123 

124@export 

125class SimpleName(Name): 

126 """ 

127 A *simple name* is a name made from a single word. 

128 

129 For example, the entity name in an architecture declaration is a simple name, while the name of the architecture 

130 itself is an identifier. The simple name references is again an identifier in the entity declaration, thus names 

131 reference other (already) declared language entities. 

132 """ 

133 

134 

135@export 

136class ParenthesisName(Name): 

137 _associations: List 

138 

139 def __init__(self, prefix: Name, associations: Iterable, parent: ModelEntity = None) -> None: 

140 super().__init__("", prefix, parent) 

141 

142 self._associations = [] 

143 for association in associations: 

144 self._associations.append(association) 

145 association._parent = self 

146 

147 @readonly 

148 def Associations(self) -> List: 

149 return self._associations 

150 

151 def __str__(self) -> str: 

152 return f"{self._prefix!s}({', '.join(str(a) for a in self._associations)})" 

153 

154 

155@export 

156class IndexedName(Name): 

157 _indices: List[ExpressionUnion] 

158 

159 def __init__(self, prefix: Name, indices: Iterable[ExpressionUnion], parent: ModelEntity = None) -> None: 

160 super().__init__("", prefix, parent) 

161 

162 self._indices = [] 

163 for index in indices: 

164 self._indices.append(index) 

165 index._parent = self 

166 

167 @readonly 

168 def Indices(self) -> List[ExpressionUnion]: 

169 return self._indices 

170 

171 def __str__(self) -> str: 

172 return f"{self._prefix!s}({', '.join(str(i) for i in self._indices)})" 

173 

174 

175@export 

176class SlicedName(Name): 

177 pass 

178 

179 

180@export 

181class SelectedName(Name): 

182 """ 

183 A *selected name* is a name made from multiple words separated by a dot (``.``). 

184 

185 For example, the library and entity name in a direct entity instantiation is a selected name. Here the entity 

186 identifier is a selected name. The library identifier is a :class:`simple name <SimpleName>`, which is 

187 referenced by the selected name via the :attr:`~pyVHDLModel.Name.Prefix` property. 

188 """ 

189 

190 def __init__(self, identifier: str, prefix: Name, parent: ModelEntity = None) -> None: 

191 super().__init__(identifier, prefix, parent) 

192 

193 def __str__(self) -> str: 

194 return f"{self._prefix!s}.{self._identifier}" 

195 

196 

197@export 

198class AttributeName(Name): 

199 def __init__(self, identifier: str, prefix: Name, parent: ModelEntity = None) -> None: 

200 super().__init__(identifier, prefix, parent) 

201 

202 def __str__(self) -> str: 

203 return f"{self._prefix!s}'{self._identifier}" 

204 

205 

206@export 

207class AllName(SelectedName): 

208 """ 

209 The *all name* represents the reserved word ``all`` used in names. 

210 

211 Most likely this name is used in use-statements. 

212 """ 

213 def __init__(self, prefix: Name, parent: ModelEntity = None) -> None: 

214 super().__init__("all", prefix, parent) # TODO: the case of 'ALL' is not preserved 

215 

216 

217@export 

218class OpenName(Name): 

219 """ 

220 The *open name* represents the reserved word ``open``. 

221 

222 Most likely this name is used in port associations. 

223 """ 

224 def __init__(self, parent: ModelEntity = None) -> None: 

225 super().__init__("open", parent) # TODO: the case of 'OPEN' is not preserved 

226 

227 def __str__(self) -> str: 

228 return "open"