Coverage for pyVHDLModel/Name.py: 100%

86 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-11 23:50 +0000

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

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

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

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

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

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

7# |_| |___/ # 

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2017-2026 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 """ 

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

50 

51 .. seealso:: 

52 

53 * :class:`Simple name <pyVHDLModel.Name.SimpleName>` 

54 * :class:`Parenthesis name <pyVHDLModel.Name.ParenthesisName>` 

55 * :class:`Indexed name <pyVHDLModel.Name.IndexedName>` 

56 * :class:`Sliced name <pyVHDLModel.Name.SlicedName>` 

57 * :class:`Selected name <pyVHDLModel.Name.SelectedName>` 

58 * :class:`Attribute name <pyVHDLModel.Name.AttributeName>` 

59 * :class:`Open name <pyVHDLModel.Name.OpenName>` 

60 """ 

61 

62 _identifier: str #: The name's identifier. 

63 _normalizedIdentifier: str #: The normalized (lower case) identifier. 

64 # TODO: seams to be unused. There is no reverse linking, or? 

65 _root: Nullable['Name'] #: Reference to the root of the name chain. 

66 _prefix: Nullable['Name'] #: Reference to the name's prefix, or ``None`` for a simple name. 

67 

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

69 """ 

70 Initializes a name. 

71 

72 :param identifier: The name's identifier. 

73 :param prefix: Reference to the name's prefix, or ``None`` for a simple name. 

74 :param parent: The parent model entity of this entity. 

75 """ 

76 super().__init__(parent) 

77 

78 self._identifier = identifier 

79 self._normalizedIdentifier = identifier.lower() 

80 

81 if prefix is None: 

82 self._prefix = None 

83 self._root = self 

84 else: 

85 self._prefix = prefix 

86 self._root = prefix._root 

87 

88 @readonly 

89 def Identifier(self) -> str: 

90 """ 

91 Read-only property to access the identifier this name references (:attr:`_identifier`). 

92 

93 :returns: The referenced identifier. 

94 """ 

95 return self._identifier 

96 

97 @readonly 

98 def NormalizedIdentifier(self) -> str: 

99 """ 

100 Read-only property to access the normalized identifier this name references (:attr:`_normalizedIdentifier`). 

101 

102 :returns: The referenced identifier (normalized). 

103 """ 

104 return self._normalizedIdentifier 

105 

106 @readonly 

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

108 """ 

109 Read-only property to access the root (left-most) element in a chain of names (:attr:`_root`). 

110 

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

112 

113 :returns: The name's root element. 

114 """ 

115 return self._root 

116 

117 @readonly 

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

119 """ 

120 Read-only property to access the name's prefix in a chain of names (:attr:`_prefix`). 

121 

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

123 """ 

124 return self._prefix 

125 

126 @readonly 

127 def HasPrefix(self) -> bool: 

128 """ 

129 Check if the name has a prefix, i.e. :attr:`_prefix` is set. 

130 

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

132 

133 :returns: ``True``, if the name has a prefix. 

134 """ 

135 return self._prefix is not None 

136 

137 def __repr__(self) -> str: 

138 """ 

139 Formats a representation of the name. 

140 

141 **Format:** ``Name: 'sig'`` 

142 

143 :returns: String representation of the name. 

144 """ 

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

146 

147 def __str__(self) -> str: 

148 """ 

149 Formats the name. 

150 

151 **Format:** ``sig`` 

152 

153 :returns: Formatted name. 

154 """ 

155 return self._identifier 

156 

157 

158@export 

159class SimpleName(Name): 

160 """ 

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

162 

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

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

165 reference other (already) declared language entities. 

166 """ 

167 

168 

169@export 

170class ParenthesisName(Name): 

171 """ 

172 Represents a name followed by a parenthesized association list. 

173 

174 Used where indexing and a function call are indistinguishable before resolution. 

175 """ 

176 _associations: List #: List of all associations in the parenthesis. 

177 

178 def __init__(self, prefix: Name, associations: Iterable, parent: Nullable[ModelEntity] = None) -> None: 

179 """ 

180 Initializes a name followed by a parenthesized association list. 

181 

182 :param prefix: Reference to the name's prefix, or ``None`` for a simple name. 

183 :param associations: List of all associations in the parenthesis. 

184 :param parent: The parent model entity of this entity. 

185 """ 

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

187 

188 self._associations = [] 

189 for association in associations: 

190 self._associations.append(association) 

191 association.Parent = self 

192 

193 @readonly 

194 def Associations(self) -> List: 

195 """ 

196 Read-only property to access the associations (:attr:`_associations`). 

197 

198 :returns: List of associations. 

199 """ 

200 return self._associations 

201 

202 def __str__(self) -> str: 

203 """ 

204 Formats the parenthesis name. 

205 

206 **Format:** ``func(a, b)`` 

207 

208 :returns: Formatted parenthesis name. 

209 """ 

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

211 

212 

213@export 

214class IndexedName(Name): 

215 """ 

216 Represents a name indexing an array by one or more values. 

217 

218 .. admonition:: Example 

219 

220 .. code-block:: VHDL 

221 

222 s <= v(0); 

223 -- ^^^^ <- the indexed name 

224 """ 

225 _indices: List[ExpressionUnion] #: List of all index expressions, one per dimension. 

226 

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

228 """ 

229 Initializes a name indexing an array by one or more values. 

230 

231 :param prefix: Reference to the name's prefix, or ``None`` for a simple name. 

232 :param indices: List of all index expressions, one per dimension. 

233 :param parent: The parent model entity of this entity. 

234 """ 

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

236 

237 self._indices = [] 

238 for index in indices: 

239 self._indices.append(index) 

240 index.Parent = self 

241 

242 @readonly 

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

244 """ 

245 Read-only property to access the indices (:attr:`_indices`). 

246 

247 :returns: List of indices. 

248 """ 

249 return self._indices 

250 

251 def __str__(self) -> str: 

252 """ 

253 Formats the indexed name. 

254 

255 **Format:** ``arr(0)`` 

256 

257 :returns: Formatted indexed name. 

258 """ 

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

260 

261 

262@export 

263class SlicedName(Name): 

264 """ 

265 Represents a name selecting a slice of an array. 

266 

267 .. admonition:: Example 

268 

269 .. code-block:: VHDL 

270 

271 vres := v(3 downto 0); 

272 -- ^^^^^^^^^^^^^ <- the sliced name 

273 """ 

274 pass 

275 

276 

277@export 

278class SelectedName(Name): 

279 """ 

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

281 

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

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

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

285 

286 .. seealso:: 

287 

288 * :class:`All name <pyVHDLModel.Name.AllName>` 

289 """ 

290 

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

292 """ 

293 Initializes a selected name. 

294 

295 :param identifier: The name's identifier. 

296 :param prefix: Reference to the name's prefix, or ``None`` for a simple name. 

297 :param parent: The parent model entity of this entity. 

298 """ 

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

300 

301 def __str__(self) -> str: 

302 """ 

303 Formats the selected name. 

304 

305 **Format:** ``rec.elem`` 

306 

307 :returns: Formatted selected name. 

308 """ 

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

310 

311 

312@export 

313class AttributeName(Name): 

314 """ 

315 Represents a name selecting an attribute of its prefix. 

316 

317 .. admonition:: Example 

318 

319 .. code-block:: VHDL 

320 

321 for i in v'range loop 

322 -- ^^^^^^^ <- the attribute name 

323 """ 

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

325 """ 

326 Initializes a name selecting an attribute of its prefix. 

327 

328 :param identifier: The name's identifier. 

329 :param prefix: Reference to the name's prefix, or ``None`` for a simple name. 

330 :param parent: The parent model entity of this entity. 

331 """ 

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

333 

334 def __str__(self) -> str: 

335 """ 

336 Formats the attribute name. 

337 

338 **Format:** ``v'range`` 

339 

340 :returns: Formatted attribute name. 

341 """ 

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

343 

344 

345@export 

346class AllName(SelectedName): 

347 """ 

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

349 

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

351 """ 

352 def __init__(self, prefix: Name, parent: Nullable[ModelEntity] = None) -> None: 

353 """ 

354 Initializes an ``all`` name. 

355 

356 :param prefix: Reference to the name's prefix, or ``None`` for a simple name. 

357 :param parent: The parent model entity of this entity. 

358 """ 

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

360 

361 

362@export 

363class OpenName(Name): 

364 """ 

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

366 

367 Most likely this name is used in port associations. 

368 """ 

369 def __init__(self, parent: Nullable[ModelEntity] = None) -> None: 

370 """ 

371 Initializes an ``open`` name. 

372 

373 :param parent: The parent model entity of this entity. 

374 """ 

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

376 

377 def __str__(self) -> str: 

378 """ 

379 Formats the open name. 

380 

381 **Format:** ``open`` 

382 

383 :returns: Formatted open name. 

384 """ 

385 return "open"