Coverage for pyVHDLModel/Base.py: 98%

422 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-25 10:05 +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 

35Base-classes for the VHDL language model. 

36""" 

37from __future__ import annotations 

38 

39from enum import unique, Enum 

40from typing import TYPE_CHECKING, ClassVar, Type, Iterable, Optional as Nullable, Union, cast, Self 

41 

42from pyTooling.Common import StringEnum, getFullyQualifiedName 

43from pyTooling.Decorators import export, notimplemented, readonly 

44from pyTooling.MetaClasses import ExtendedType, abstractclass 

45if TYPE_CHECKING: 45 ↛ 46line 45 didn't jump to line 46 because the condition on line 45 was never true

46 from pyVHDLModel.Symbol import Symbol 

47 from pyVHDLModel.Visitor import Visitor 

48 

49 

50__all__ = ["ExpressionUnion", "ModelElementUnion"] 

51 

52 

53ExpressionUnion = Union[ 

54 'BaseExpression', 

55 'QualifiedExpression', 

56 'FunctionCall', 

57 'TypeConversion', 

58 # ConstantOrSymbol, TODO: ObjectSymbol 

59 'Literal', 

60] 

61 

62ModelElementUnion = Union['ModelEntity', 'Symbol'] 

63""" 

64A model element a visitor walks or the VHDL writer writes: a :class:`ModelEntity` or a 

65:class:`~pyVHDLModel.Symbol.Symbol`. 

66""" 

67 

68 

69@export 

70@unique 

71class ReservedWord(StringEnum): 

72 """ 

73 A ``ReservedWord`` is an enumeration of VHDL's reserved words (IEEE Std 1076-2019, 15.10). 

74 

75 A member is a :class:`str`: its value is the reserved word in lower case, e.g. ``ReservedWord.DownTo == "downto"``. 

76 The VHDL writer (:mod:`pyVHDLModel.Formatting.VHDL`) applies the configured keyword case to it. 

77 

78 Each member states the revision of IEEE Std 1076 that first reserved it. Earlier revisions reserved words, which 

79 VHDL-2019 doesn't: ``procedural`` and ``reference`` (VHDL-2000 and VHDL-2002), ``assume_guarantee`` and 

80 ``restrict_guarantee`` (VHDL-2008). 

81 """ 

82 

83 Abs = "abs" #: Reserved word since VHDL-87. 

84 Access = "access" #: Reserved word since VHDL-87. 

85 After = "after" #: Reserved word since VHDL-87. 

86 Alias = "alias" #: Reserved word since VHDL-87. 

87 All = "all" #: Reserved word since VHDL-87. 

88 And = "and" #: Reserved word since VHDL-87. 

89 Architecture = "architecture" #: Reserved word since VHDL-87. 

90 Array = "array" #: Reserved word since VHDL-87. 

91 Assert = "assert" #: Reserved word since VHDL-87. 

92 Assume = "assume" #: Reserved word since VHDL-2008. 

93 Attribute = "attribute" #: Reserved word since VHDL-87. 

94 Begin = "begin" #: Reserved word since VHDL-87. 

95 Block = "block" #: Reserved word since VHDL-87. 

96 Body = "body" #: Reserved word since VHDL-87. 

97 Buffer = "buffer" #: Reserved word since VHDL-87. 

98 Bus = "bus" #: Reserved word since VHDL-87. 

99 Case = "case" #: Reserved word since VHDL-87. 

100 Component = "component" #: Reserved word since VHDL-87. 

101 Configuration = "configuration" #: Reserved word since VHDL-87. 

102 Constant = "constant" #: Reserved word since VHDL-87. 

103 Context = "context" #: Reserved word since VHDL-2008. 

104 Cover = "cover" #: Reserved word since VHDL-2008. 

105 Default = "default" #: Reserved word since VHDL-2008. 

106 Disconnect = "disconnect" #: Reserved word since VHDL-87. 

107 DownTo = "downto" #: Reserved word since VHDL-87. 

108 Else = "else" #: Reserved word since VHDL-87. 

109 ElsIf = "elsif" #: Reserved word since VHDL-87. 

110 End = "end" #: Reserved word since VHDL-87. 

111 Entity = "entity" #: Reserved word since VHDL-87. 

112 Exit = "exit" #: Reserved word since VHDL-87. 

113 Fairness = "fairness" #: Reserved word since VHDL-2008. 

114 File = "file" #: Reserved word since VHDL-87. 

115 For = "for" #: Reserved word since VHDL-87. 

116 Force = "force" #: Reserved word since VHDL-2008. 

117 Function = "function" #: Reserved word since VHDL-87. 

118 Generate = "generate" #: Reserved word since VHDL-87. 

119 Generic = "generic" #: Reserved word since VHDL-87. 

120 Group = "group" #: Reserved word since VHDL-93. 

121 Guarded = "guarded" #: Reserved word since VHDL-87. 

122 If = "if" #: Reserved word since VHDL-87. 

123 Impure = "impure" #: Reserved word since VHDL-93. 

124 In = "in" #: Reserved word since VHDL-87. 

125 Inertial = "inertial" #: Reserved word since VHDL-93. 

126 InOut = "inout" #: Reserved word since VHDL-87. 

127 Is = "is" #: Reserved word since VHDL-87. 

128 Label = "label" #: Reserved word since VHDL-87. 

129 Library = "library" #: Reserved word since VHDL-87. 

130 Linkage = "linkage" #: Reserved word since VHDL-87. 

131 Literal = "literal" #: Reserved word since VHDL-93. 

132 Loop = "loop" #: Reserved word since VHDL-87. 

133 Map = "map" #: Reserved word since VHDL-87. 

134 Mod = "mod" #: Reserved word since VHDL-87. 

135 Nand = "nand" #: Reserved word since VHDL-87. 

136 New = "new" #: Reserved word since VHDL-87. 

137 Next = "next" #: Reserved word since VHDL-87. 

138 Nor = "nor" #: Reserved word since VHDL-87. 

139 Not = "not" #: Reserved word since VHDL-87. 

140 Null = "null" #: Reserved word since VHDL-87. 

141 Of = "of" #: Reserved word since VHDL-87. 

142 On = "on" #: Reserved word since VHDL-87. 

143 Open = "open" #: Reserved word since VHDL-87. 

144 Or = "or" #: Reserved word since VHDL-87. 

145 Others = "others" #: Reserved word since VHDL-87. 

146 Out = "out" #: Reserved word since VHDL-87. 

147 Package = "package" #: Reserved word since VHDL-87. 

148 Parameter = "parameter" #: Reserved word since VHDL-2008. 

149 Port = "port" #: Reserved word since VHDL-87. 

150 Postponed = "postponed" #: Reserved word since VHDL-93. 

151 Private = "private" #: Reserved word since VHDL-2019. 

152 Procedure = "procedure" #: Reserved word since VHDL-87. 

153 Process = "process" #: Reserved word since VHDL-87. 

154 Property = "property" #: Reserved word since VHDL-2008. 

155 Protected = "protected" #: Reserved word since VHDL-2000. 

156 Pure = "pure" #: Reserved word since VHDL-93. 

157 Range = "range" #: Reserved word since VHDL-87. 

158 Record = "record" #: Reserved word since VHDL-87. 

159 Register = "register" #: Reserved word since VHDL-87. 

160 Reject = "reject" #: Reserved word since VHDL-93. 

161 Release = "release" #: Reserved word since VHDL-2008. 

162 Rem = "rem" #: Reserved word since VHDL-87. 

163 Report = "report" #: Reserved word since VHDL-87. 

164 Restrict = "restrict" #: Reserved word since VHDL-2008. 

165 Return = "return" #: Reserved word since VHDL-87. 

166 Rol = "rol" #: Reserved word since VHDL-93. 

167 Ror = "ror" #: Reserved word since VHDL-93. 

168 Select = "select" #: Reserved word since VHDL-87. 

169 Sequence = "sequence" #: Reserved word since VHDL-2008. 

170 Severity = "severity" #: Reserved word since VHDL-87. 

171 Shared = "shared" #: Reserved word since VHDL-93. 

172 Signal = "signal" #: Reserved word since VHDL-87. 

173 Sla = "sla" #: Reserved word since VHDL-93. 

174 Sll = "sll" #: Reserved word since VHDL-93. 

175 Sra = "sra" #: Reserved word since VHDL-93. 

176 Srl = "srl" #: Reserved word since VHDL-93. 

177 Strong = "strong" #: Reserved word since VHDL-2008. 

178 Subtype = "subtype" #: Reserved word since VHDL-87. 

179 Then = "then" #: Reserved word since VHDL-87. 

180 To = "to" #: Reserved word since VHDL-87. 

181 Transport = "transport" #: Reserved word since VHDL-87. 

182 Type = "type" #: Reserved word since VHDL-87. 

183 Unaffected = "unaffected" #: Reserved word since VHDL-93. 

184 Units = "units" #: Reserved word since VHDL-87. 

185 Until = "until" #: Reserved word since VHDL-87. 

186 Use = "use" #: Reserved word since VHDL-87. 

187 Variable = "variable" #: Reserved word since VHDL-87. 

188 View = "view" #: Reserved word since VHDL-2019. 

189 VMode = "vmode" #: Reserved word since VHDL-2008. 

190 VPkg = "vpkg" #: Reserved word since VHDL-2019. 

191 VProp = "vprop" #: Reserved word since VHDL-2008. 

192 VUnit = "vunit" #: Reserved word since VHDL-2008. 

193 Wait = "wait" #: Reserved word since VHDL-87. 

194 When = "when" #: Reserved word since VHDL-87. 

195 While = "while" #: Reserved word since VHDL-87. 

196 With = "with" #: Reserved word since VHDL-87. 

197 Xnor = "xnor" #: Reserved word since VHDL-93. 

198 Xor = "xor" #: Reserved word since VHDL-87. 

199 

200 

201_ReservedWord = ReservedWord #: Alias of :class:`ReservedWord` for annotations in classes with a property of that name. 

202 

203 

204@export 

205@unique 

206class Direction(Enum): 

207 """An enumeration representing a direction in a range (``to`` or ``downto``).""" 

208 

209 To = 0 #: Ascending direction 

210 DownTo = 1 #: Descending direction 

211 

212 __RESERVED_WORDS: ClassVar[dict[int, _ReservedWord]] = { 

213 0: _ReservedWord.To, 

214 1: _ReservedWord.DownTo 

215 } #: The reserved word of each direction, by value. 

216 

217 @readonly 

218 def ReservedWord(self) -> _ReservedWord: 

219 """ 

220 Read-only property to return the reserved word of the direction. 

221 

222 :returns: The reserved word, ``to`` or ``downto``. 

223 """ 

224 return self.__RESERVED_WORDS[self.value] 

225 

226 def __str__(self) -> str: 

227 """ 

228 Formats the direction to ``to`` or ``downto``. 

229 

230 :returns: Formatted direction. 

231 """ 

232 return ("to", "downto")[cast(int, self.value)] # TODO: check performance 

233 

234 

235@export 

236@unique 

237class Mode(Enum): 

238 """ 

239 A ``Mode`` is an enumeration. It represents the direction of data exchange (``in``, ``out``, ...) for objects in 

240 generic, port or parameter lists. 

241 

242 In case no *mode* is defined, ``Default`` is used, so the *mode* is inferred from context. 

243 """ 

244 

245 Default = 0 #: Mode not defined, thus it's context dependent. 

246 In = 1 #: Input 

247 Out = 2 #: Output 

248 InOut = 3 #: Bi-directional 

249 Buffer = 4 #: Buffered output 

250 Linkage = 5 #: undocumented 

251 

252 __RESERVED_WORDS: ClassVar[dict[int, _ReservedWord]] = { 

253 1: _ReservedWord.In, 

254 2: _ReservedWord.Out, 

255 3: _ReservedWord.InOut, 

256 4: _ReservedWord.Buffer, 

257 5: _ReservedWord.Linkage 

258 } #: The reserved word of each mode, by value; ``Default`` has none. 

259 

260 @readonly 

261 def ReservedWord(self) -> Nullable[_ReservedWord]: 

262 """ 

263 Read-only property to return the reserved word of the mode. 

264 

265 :returns: The reserved word, or ``None`` for ``Mode.Default``. 

266 """ 

267 return self.__RESERVED_WORDS.get(self.value, None) 

268 

269 def __str__(self) -> str: 

270 """ 

271 Formats the mode. 

272 

273 :returns: Formatted mode. 

274 """ 

275 return ("", "in", "out", "inout", "buffer", "linkage")[cast(int, self.value)] # TODO: check performance 

276 

277 

278@export 

279@abstractclass 

280class ModelEntity(metaclass=ExtendedType, slots=True): 

281 """ 

282 ``ModelEntity`` is the base-class for all classes in the VHDL language model, except for mixin classes (see multiple 

283 inheritance) and enumerations. 

284 

285 Each entity in this model has a reference to its parent entity. Therefore, a protected variable :attr:`_parent` is 

286 available and a readonly property :attr:`Parent`. 

287 """ 

288 

289 _parent: ModelEntity #: Reference to a parent entity in the logical model hierarchy. 

290 

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

292 """ 

293 Initializes a VHDL model entity. 

294 

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

296 """ 

297 self._parent = parent 

298 

299 @property 

300 def Parent(self) -> ModelEntity: 

301 """ 

302 Property to access the model entity's parent element reference in a logical hierarchy (:attr:`_parent`). 

303 

304 :returns: Reference to the parent entity. 

305 """ 

306 return self._parent 

307 

308 @Parent.setter 

309 def Parent(self, parent: ModelEntity) -> None: 

310 if parent is None: 

311 raise ValueError("Parameter 'parent' is None.") 

312 

313 self._parent = parent 

314 

315 def GetAncestor(self, type: Type) -> ModelEntity: 

316 """ 

317 Return the closest ancestor of the given ``type`` found by walking the parent chain upwards. 

318 

319 Iterates the parent chain - starting at this model entity - upwards (toward the root of the model) until an 

320 ancestor of the requested type is found. 

321 

322 :param type: Class (type) of the ancestor to find. 

323 :returns: The closest ancestor of the requested type. 

324 :raises VHDLModelException: If the root of the model is reached without finding an ancestor of the requested 

325 type. 

326 """ 

327 # Deferred import to avoid a circular import: Base -> Exception -> Symbol -> Base. 

328 from pyVHDLModel.Exception import VHDLModelException 

329 

330 parent = self._parent 

331 while parent is not None: 

332 if isinstance(parent, type): 

333 break 

334 

335 parent = parent._parent 

336 else: 

337 raise VHDLModelException(f"No ancestor of type '{type.__name__}' found for {self!r}.") 

338 

339 return parent 

340 

341 @notimplemented("Model element has no walk for a visitor.") 

342 def Visit(self, visitor: Visitor) -> None: 

343 """ 

344 Walk this model element with a visitor. 

345 

346 A model class implements its walk; a class without one raises. 

347 

348 :param visitor: The visitor receiving the events. 

349 :raises NotImplementedError: Always, because the element's class has no walk of its own. 

350 """ 

351 

352 

353@export 

354class NamedEntityMixin(metaclass=ExtendedType, mixin=True): 

355 """ 

356 A ``NamedEntityMixin`` is a mixin class for all VHDL entities that have an identifier. 

357 

358 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as 

359 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access. 

360 

361 .. seealso:: 

362 

363 * :class:`Attribute <pyVHDLModel.Declaration.Attribute>` 

364 * :class:`Alias <pyVHDLModel.Declaration.Alias>` 

365 * :class:`Design unit <pyVHDLModel.DesignUnit.DesignUnit>` 

366 * :class:`Component <pyVHDLModel.DesignUnit.Component>` 

367 * :class:`Mode view declaration <pyVHDLModel.Interface.ModeViewDeclaration>` 

368 * :class:`Interface package <pyVHDLModel.Interface.InterfacePackage>` 

369 * :class:`Default clock <pyVHDLModel.PSLModel.DefaultClock>` 

370 * :class:`Subprogram <pyVHDLModel.Subprogram.Subprogram>` 

371 * :class:`Base type <pyVHDLModel.Type.BaseType>` 

372 * :class:`Library <pyVHDLModel.Library>` 

373 """ 

374 

375 _identifier: str #: The identifier of a model entity. 

376 _normalizedIdentifier: str #: The normalized (lower case) identifier of a model entity. 

377 

378 def __init__(self, identifier: str) -> None: 

379 """ 

380 Initializes a named entity. 

381 

382 :param identifier: Identifier (name) of the model entity. 

383 """ 

384 self._identifier = identifier 

385 self._normalizedIdentifier = identifier.lower() 

386 

387 @readonly 

388 def Identifier(self) -> str: 

389 """ 

390 Read-only property to access the model entity's identifier (:attr:`_identifier`). 

391 

392 :returns: Name of a model entity. 

393 """ 

394 return self._identifier 

395 

396 @readonly 

397 def NormalizedIdentifier(self) -> str: 

398 """ 

399 Read-only property to access the model entity's normalized identifier (:attr:`_normalizedIdentifier`). 

400 

401 :returns: Normalized name of a model entity. 

402 """ 

403 return self._normalizedIdentifier 

404 

405 

406@export 

407class OptionallyNamedEntityMixin(metaclass=ExtendedType, mixin=True): 

408 """ 

409 A ``OptionallyNamedEntityMixin`` is a mixin class for all VHDL entities that have an optional identifier. 

410 

411 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as 

412 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access. 

413 

414 .. seealso:: 

415 

416 * :class:`Interface group <pyVHDLModel.Interface.InterfaceGroup>` 

417 """ 

418 

419 _identifier: Nullable[str] #: The identifier of a model entity. 

420 _normalizedIdentifier: Nullable[str] #: The normalized (lower case) identifier of a model entity. 

421 

422 def __init__(self, identifier: Nullable[str]) -> None: 

423 """ 

424 Initializes a named entity. 

425 

426 :param identifier: Identifier (name) of the model entity. 

427 """ 

428 self._identifier = identifier 

429 self._normalizedIdentifier = identifier.lower() if identifier is not None else None 

430 

431 @readonly 

432 def Identifier(self) -> Nullable[str]: 

433 """ 

434 Read-only property to access the model entity's optional identifier (:attr:`_identifier`). 

435 

436 :returns: Name of a model entity, or ``None`` if unnamed. 

437 """ 

438 return self._identifier 

439 

440 @readonly 

441 def NormalizedIdentifier(self) -> Nullable[str]: 

442 """ 

443 Read-only property to access the model entity's optional normalized identifier (:attr:`_normalizedIdentifier`). 

444 

445 :returns: Normalized name of a model entity, or ``None`` if unnamed. 

446 """ 

447 return self._normalizedIdentifier 

448 

449 

450@export 

451class MultipleNamedEntityMixin(metaclass=ExtendedType, mixin=True): 

452 """ 

453 A ``MultipleNamedEntityMixin`` is a mixin class for all VHDL entities that declare multiple instances at once by 

454 defining multiple identifiers. 

455 

456 Protected variables :attr:`_identifiers` and :attr:`_normalizedIdentifiers` are available to derived classes as well 

457 as two readonly properties :attr:`Identifiers` and :attr:`NormalizedIdentifiers` for public access. 

458 

459 .. seealso:: 

460 

461 * :class:`Mode view element <pyVHDLModel.Interface.ModeViewElement>` 

462 * :class:`Obj <pyVHDLModel.Object.Obj>` 

463 * :class:`Record type element <pyVHDLModel.Type.RecordTypeElement>` 

464 """ 

465 

466 _identifiers: tuple[str] #: A list of identifiers. 

467 _normalizedIdentifiers: tuple[str] #: A list of normalized (lower case) identifiers. 

468 

469 def __init__(self, identifiers: Iterable[str]) -> None: 

470 """ 

471 Initializes a multiple-named entity. 

472 

473 :param identifiers: Sequence of identifiers (names) of the model entity. 

474 """ 

475 self._identifiers = tuple(identifiers) 

476 self._normalizedIdentifiers = tuple([identifier.lower() for identifier in self._identifiers]) 

477 

478 @readonly 

479 def Identifiers(self) -> tuple[str]: 

480 """ 

481 Read-only property to access the model entity's identifiers (:attr:`_identifiers`). 

482 

483 :returns: Tuple of identifiers. 

484 """ 

485 return self._identifiers 

486 

487 @readonly 

488 def NormalizedIdentifiers(self) -> tuple[str]: 

489 """ 

490 Read-only property to access the model entity's normalized identifiers (:attr:`_normalizedIdentifiers`). 

491 

492 :returns: Tuple of normalized identifiers. 

493 """ 

494 return self._normalizedIdentifiers 

495 

496 

497@export 

498def identifiersOf(item) -> tuple[str, ...]: 

499 """ 

500 Return an item's identifier(s), regardless of how many names its declaration carries. 

501 

502 VHDL entities come in two shapes: singularly named ones deriving from :class:`NamedEntityMixin` 

503 (``generic (type T)``, ``GenericProcedureInterfaceItem``, ...) and plurally named ones deriving from 

504 :class:`MultipleNamedEntityMixin`, where one declaration names several items at once 

505 (``port (p1, p2 : in bit)``, and every ``Constant``/``Signal``/``Variable``/``File``-derived item). 

506 

507 :param item: A singularly or plurally named entity. 

508 :returns: The item's identifiers. 

509 :raises TypeError: If the item is neither singularly nor plurally named. 

510 

511 .. seealso:: 

512 

513 :func:`normalizedIdentifiersOf` 

514 The same, but normalized (lower case) - use that for dictionary keys and name resolution. 

515 """ 

516 if isinstance(item, MultipleNamedEntityMixin): 

517 return item._identifiers 

518 elif isinstance(item, NamedEntityMixin): 518 ↛ 521line 518 didn't jump to line 521 because the condition on line 518 was always true

519 return (item._identifier, ) 

520 

521 ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.") 

522 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") 

523 raise ex 

524 

525 

526@export 

527def normalizedIdentifiersOf(item) -> tuple[str, ...]: 

528 """ 

529 Return an item's normalized (lower case) identifier(s). 

530 

531 This is the form used as dictionary keys and for name resolution, because VHDL identifiers are 

532 case-insensitive. 

533 

534 :param item: A singularly or plurally named entity. 

535 :returns: The item's normalized identifiers. 

536 :raises TypeError: If the item is neither singularly nor plurally named. 

537 

538 .. seealso:: 

539 

540 :func:`identifiersOf` 

541 The same, but as written in the source - use that for rendering. 

542 """ 

543 if isinstance(item, MultipleNamedEntityMixin): 

544 return item._normalizedIdentifiers 

545 elif isinstance(item, NamedEntityMixin): 545 ↛ 548line 545 didn't jump to line 548 because the condition on line 545 was always true

546 return (item._normalizedIdentifier, ) 

547 

548 ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.") 

549 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") 

550 raise ex 

551 

552 

553@export 

554def normalizedDeclaredNamesOf(item: ModelEntity) -> tuple[str, ...]: 

555 """ 

556 Return the normalized (lower case) names an item declares in its declarative region. 

557 

558 A declaration declares its identifiers. A statement label is declared implicitly in the declarative region enclosing 

559 the statement, so a labeled statement declares its label. 

560 

561 :param item: A model entity. 

562 :returns: The normalized identifiers of a singularly or plurally named entity, the normalized label of a labeled 

563 entity, or an empty tuple. 

564 

565 .. seealso:: 

566 

567 :func:`normalizedIdentifiersOf` 

568 The normalized identifiers of a singularly or plurally named entity. 

569 """ 

570 if isinstance(item, (NamedEntityMixin, MultipleNamedEntityMixin)): 

571 return normalizedIdentifiersOf(item) 

572 elif isinstance(item, LabeledEntityMixin) and item._normalizedLabel is not None: 

573 return (item._normalizedLabel, ) 

574 

575 return () 

576 

577 

578@export 

579class LabeledEntityMixin(metaclass=ExtendedType, mixin=True): 

580 """ 

581 A ``LabeledEntityMixin`` is a mixin class for all VHDL entities that can have labels. 

582 

583 protected variables :attr:`_label` and :attr:`_normalizedLabel` are available to derived classes as well as two 

584 readonly properties :attr:`Label` and :attr:`NormalizedLabel` for public access. 

585 

586 .. seealso:: 

587 

588 * :class:`Statement <pyVHDLModel.Common.Statement>` 

589 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>` 

590 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>` 

591 """ 

592 _label: Nullable[str] #: The label of a model entity. 

593 _normalizedLabel: Nullable[str] #: The normalized (lower case) label of a model entity. 

594 

595 def __init__(self, label: Nullable[str]) -> None: 

596 """ 

597 Initializes a labeled entity. 

598 

599 :param label: Label of the model entity. 

600 """ 

601 self._label = label 

602 self._normalizedLabel = label.lower() if label is not None else None 

603 

604 @readonly 

605 def Label(self) -> Nullable[str]: 

606 """ 

607 Read-only property to access the model entity's label (:attr:`_label`). 

608 

609 :returns: Label of a model entity. 

610 """ 

611 return self._label 

612 

613 @readonly 

614 def NormalizedLabel(self) -> Nullable[str]: 

615 """ 

616 Read-only property to access the model entity's normalized label (:attr:`_normalizedLabel`). 

617 

618 :returns: Normalized label of a model entity. 

619 """ 

620 return self._normalizedLabel 

621 

622 

623@export 

624class DocumentedEntityMixin(metaclass=ExtendedType, mixin=True): 

625 """ 

626 A ``DocumentedEntityMixin`` is a mixin class for all VHDL entities that can have an associated documentation. 

627 

628 A protected variable :attr:`_documentation` is available to derived classes as well as a readonly property 

629 :attr:`Documentation` for public access. 

630 """ 

631 

632 _documentation: Nullable[str] #: The associated documentation of a model entity. 

633 

634 def __init__(self, documentation: Nullable[str]) -> None: 

635 """ 

636 Initializes a documented entity. 

637 

638 :param documentation: Documentation of a model entity. 

639 """ 

640 self._documentation = documentation 

641 

642 @readonly 

643 def Documentation(self) -> Nullable[str]: 

644 """ 

645 Read-only property to access the model entity's documentation (:attr:`_documentation`). 

646 

647 :returns: Associated documentation of a model entity. 

648 """ 

649 return self._documentation 

650 

651 

652@export 

653class ConditionalMixin(metaclass=ExtendedType, mixin=True): 

654 """ 

655 A ``ConditionalMixin`` is a mixin-class for all statements with a condition. 

656 

657 .. seealso:: 

658 

659 * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>` 

660 * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>` 

661 * :class:`Conditional waveform <pyVHDLModel.Common.ConditionalWaveform>` 

662 * :class:`Conditional expression <pyVHDLModel.Common.ConditionalExpression>` 

663 * :class:`While loop statement <pyVHDLModel.Sequential.WhileLoopStatement>` 

664 * :class:`Loop control statement <pyVHDLModel.Sequential.LoopControlStatement>` 

665 * :class:`Wait statement <pyVHDLModel.Sequential.WaitStatement>` 

666 """ 

667 

668 _condition: ExpressionUnion #: The condition guarding this statement. 

669 

670 def __init__(self, condition: Nullable[ExpressionUnion] = None) -> None: 

671 """ 

672 Initializes a statement with a condition. 

673 

674 When the condition is not None, the condition's parent reference is set to this statement. 

675 

676 :param condition: The expression representing the condition. 

677 """ 

678 self._condition = condition 

679 if condition is not None: 

680 condition.Parent = self 

681 

682 @readonly 

683 def Condition(self) -> ExpressionUnion: 

684 """ 

685 Read-only property to access the condition of a statement (:attr:`_condition`). 

686 

687 :returns: The expression representing the condition of a statement. 

688 """ 

689 return self._condition 

690 

691 

692@export 

693class BranchMixin(metaclass=ExtendedType, mixin=True): 

694 """ 

695 A ``BranchMixin`` is a mixin-class for all statements with branches. 

696 

697 .. seealso:: 

698 

699 * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>` 

700 * :class:`Else branch mixin <pyVHDLModel.Base.ElseBranchMixin>` 

701 """ 

702 

703 def __init__(self) -> None: 

704 """ 

705 Initializes a branch. 

706 """ 

707 pass 

708 

709 

710@export 

711class ConditionalBranchMixin(BranchMixin, ConditionalMixin, mixin=True): 

712 """ 

713 A ``BaseBranch`` is a mixin-class for all branch statements with a condition. 

714 

715 .. seealso:: 

716 

717 * :class:`If branch mixin <pyVHDLModel.Base.IfBranchMixin>` 

718 * :class:`Elsif branch mixin <pyVHDLModel.Base.ElsifBranchMixin>` 

719 """ 

720 def __init__(self, condition: ExpressionUnion) -> None: 

721 """ 

722 Initializes a conditional branch. 

723 

724 :param condition: The condition guarding this statement. 

725 """ 

726 super().__init__() 

727 ConditionalMixin.__init__(self, condition) 

728 

729 

730@export 

731class IfBranchMixin(ConditionalBranchMixin, mixin=True): 

732 """ 

733 A ``BaseIfBranch`` is a mixin-class for all if-branches. 

734 

735 .. seealso:: 

736 

737 * :class:`If generate branch <pyVHDLModel.Concurrent.IfGenerateBranch>` 

738 * :class:`If branch <pyVHDLModel.Sequential.IfBranch>` 

739 """ 

740 

741 

742@export 

743class ElsifBranchMixin(ConditionalBranchMixin, mixin=True): 

744 """ 

745 A ``BaseElsifBranch`` is a mixin-class for all elsif-branches. 

746 

747 .. seealso:: 

748 

749 * :class:`Elsif generate branch <pyVHDLModel.Concurrent.ElsifGenerateBranch>` 

750 * :class:`Elsif branch <pyVHDLModel.Sequential.ElsifBranch>` 

751 """ 

752 

753 

754@export 

755class ElseBranchMixin(BranchMixin, mixin=True): 

756 """ 

757 A ``BaseElseBranch`` is a mixin-class for all else-branches. 

758 

759 .. seealso:: 

760 

761 * :class:`Else generate branch <pyVHDLModel.Concurrent.ElseGenerateBranch>` 

762 * :class:`Else branch <pyVHDLModel.Sequential.ElseBranch>` 

763 """ 

764 

765 

766@export 

767class ReportStatementMixin(metaclass=ExtendedType, mixin=True): 

768 """ 

769 A ``MixinReportStatement`` is a mixin-class for all report and assert statements. 

770 

771 .. seealso:: 

772 

773 * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>` 

774 * :class:`Sequential report statement <pyVHDLModel.Sequential.SequentialReportStatement>` 

775 """ 

776 

777 _message: Nullable[ExpressionUnion] #: The reported message, or ``None`` if none was given. 

778 _severity: Nullable[ExpressionUnion] #: The reported severity level, or ``None`` if none was given. 

779 

780 def __init__(self, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None: 

781 """ 

782 Initializes a report statement. 

783 

784 :param message: The reported message, or ``None`` if none was given. 

785 :param severity: The reported severity level, or ``None`` if none was given. 

786 """ 

787 self._message = message 

788 if message is not None: 

789 message.Parent = self 

790 

791 self._severity = severity 

792 if severity is not None: 

793 severity.Parent = self 

794 

795 def _VisitReportAndSeverity(self, visitor: Visitor) -> None: 

796 """ 

797 Walk the message and the severity, if given, each after its reserved word, with a visitor. 

798 

799 :param visitor: The visitor receiving the events. 

800 """ 

801 if self._message is not None: 

802 visitor.VisitReport(self) 

803 self._message.Visit(visitor) 

804 

805 if self._severity is not None: 

806 visitor.VisitSeverity(self) 

807 self._severity.Visit(visitor) 

808 

809 @readonly 

810 def Message(self) -> Nullable[ExpressionUnion]: 

811 """ 

812 Read-only property to access the message (:attr:`_message`). 

813 

814 :returns: The message, or ``None`` if not set. 

815 """ 

816 return self._message 

817 

818 @readonly 

819 def Severity(self) -> Nullable[ExpressionUnion]: 

820 """ 

821 Read-only property to access the severity (:attr:`_severity`). 

822 

823 :returns: The severity, or ``None`` if not set. 

824 """ 

825 return self._severity 

826 

827 

828@export 

829class AssertStatementMixin(ReportStatementMixin, ConditionalMixin, mixin=True): 

830 """ 

831 A ``MixinAssertStatement`` is a mixin-class for all assert statements. 

832 

833 .. seealso:: 

834 

835 * :class:`Concurrent assert statement <pyVHDLModel.Concurrent.ConcurrentAssertStatement>` 

836 * :class:`Sequential assert statement <pyVHDLModel.Sequential.SequentialAssertStatement>` 

837 """ 

838 

839 def __init__(self, condition: ExpressionUnion, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None: 

840 """ 

841 Initializes an assert statement. 

842 

843 :param condition: The condition guarding this statement. 

844 :param message: The reported message, or ``None`` if none was given. 

845 :param severity: The reported severity level, or ``None`` if none was given. 

846 """ 

847 super().__init__(message, severity) 

848 ConditionalMixin.__init__(self, condition) 

849 

850 def _VisitAssertion(self, visitor: Visitor) -> None: 

851 """ 

852 Walk the condition, the message and the severity of an assertion with a visitor. 

853 

854 :param visitor: The visitor receiving the events. 

855 """ 

856 self._condition.Visit(visitor) 

857 self._VisitReportAndSeverity(visitor) 

858 

859 

860class BlockStatementMixin(metaclass=ExtendedType, mixin=True): 

861 """ 

862 A ``BlockStatement`` is a mixin-class for all block statements. 

863 

864 .. seealso:: 

865 

866 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>` 

867 """ 

868 

869 def __init__(self) -> None: 

870 """ 

871 Initializes a block statement. 

872 """ 

873 pass 

874 

875 

876@export 

877@abstractclass 

878class BaseChoice(ModelEntity): 

879 """ 

880 A ``Choice`` is a base-class for all choices. 

881 

882 .. seealso:: 

883 

884 * :class:`Concurrent choice <pyVHDLModel.Concurrent.ConcurrentChoice>` 

885 * :class:`Sequential choice <pyVHDLModel.Sequential.SequentialChoice>` 

886 """ 

887 

888 

889@export 

890@abstractclass 

891class BaseCase(ModelEntity): 

892 """ 

893 A ``Case`` is a base-class for all cases. 

894 

895 .. seealso:: 

896 

897 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>` 

898 * :class:`Others selected waveform <pyVHDLModel.Common.OthersSelectedWaveform>` 

899 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>` 

900 * :class:`Others selected expression <pyVHDLModel.Common.OthersSelectedExpression>` 

901 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>` 

902 * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>` 

903 """ 

904 

905 

906@export 

907class ChoicesMixin(metaclass=ExtendedType, mixin=True): 

908 """ 

909 A mixin-class for all statements/entities holding a list of :class:`BaseChoice`. 

910 

911 .. seealso:: 

912 

913 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>` 

914 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>` 

915 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>` 

916 * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>` 

917 """ 

918 

919 _choices: list[BaseChoice] #: List of all choices selecting this alternative. 

920 

921 def __init__(self, choices: Nullable[Iterable[BaseChoice]] = None) -> None: 

922 """ 

923 Initializes choices. 

924 

925 :param choices: List of all choices selecting this alternative. 

926 """ 

927 self._choices = choiceList = [] 

928 if choices is not None: 

929 for choice in choices: 

930 choiceList.append(choice) 

931 choice.Parent = self 

932 

933 @readonly 

934 def Choices(self) -> list[BaseChoice]: 

935 """ 

936 Read-only property to access the choices (:attr:`_choices`). 

937 

938 :returns: List of choices. 

939 """ 

940 return self._choices 

941 

942 

943@export 

944class Range(ModelEntity): 

945 """ 

946 Base-class for all ranges. 

947 

948 VHDL's ``range`` rule offers a range denoted by a name (:class:`RangeFromName`) as well as a range 

949 given by explicit bounds (:class:`SimpleRange`). 

950 

951 .. seealso:: 

952 

953 * :class:`Simple range <pyVHDLModel.Base.SimpleRange>` 

954 * :class:`Range from name <pyVHDLModel.Base.RangeFromName>` 

955 """ 

956 

957 

958@export 

959class SimpleRange(Range): 

960 """ 

961 A range with both bounds given as expressions. 

962 

963 ``0 to 7`` is such a range. 

964 """ 

965 

966 _leftBound: ExpressionUnion #: The range's left bound. 

967 _rightBound: ExpressionUnion #: The range's right bound. 

968 _direction: Direction #: The range's direction, either ascending (``to``) or descending (``downto``). 

969 

970 def __init__(self, leftBound: ExpressionUnion, rightBound: ExpressionUnion, direction: Direction, parent: Nullable[ModelEntity] = None) -> None: 

971 """ 

972 Initialize a simple range. 

973 

974 :param leftBound: The range's left bound. 

975 :param rightBound: The range's right bound. 

976 :param direction: The range's direction (``to`` or ``downto``). 

977 :param parent: The parent model entity. 

978 """ 

979 super().__init__(parent) 

980 

981 self._leftBound = leftBound 

982 leftBound.Parent = self 

983 

984 self._rightBound = rightBound 

985 rightBound.Parent = self 

986 

987 self._direction = direction 

988 

989 @readonly 

990 def LeftBound(self) -> ExpressionUnion: 

991 """ 

992 Read-only property to access the range's left bound (:attr:`_leftBound`). 

993 

994 :returns: The left bound. 

995 """ 

996 return self._leftBound 

997 

998 @readonly 

999 def RightBound(self) -> ExpressionUnion: 

1000 """ 

1001 Read-only property to access the range's right bound (:attr:`_rightBound`). 

1002 

1003 :returns: The right bound. 

1004 """ 

1005 return self._rightBound 

1006 

1007 @readonly 

1008 def Direction(self) -> Direction: 

1009 """ 

1010 Read-only property to access the range's direction (:attr:`_direction`). 

1011 

1012 :returns: The direction. 

1013 """ 

1014 return self._direction 

1015 

1016 def Copy(self) -> Self: 

1017 """ 

1018 Create a copy of this simple range. 

1019 

1020 The copy has no parent. Its bounds are copies of this range's bounds. 

1021 

1022 :returns: The new simple range. 

1023 """ 

1024 return self.__class__(self._leftBound.Copy(), self._rightBound.Copy(), self._direction) 

1025 

1026 def Visit(self, visitor: Visitor) -> None: 

1027 """ 

1028 Walk this range, its left bound and its right bound with a visitor. 

1029 

1030 :param visitor: The visitor receiving the events. 

1031 """ 

1032 visitor.VisitSimpleRange(self) 

1033 self._leftBound.Visit(visitor) 

1034 visitor.VisitDirection(self) 

1035 self._rightBound.Visit(visitor) 

1036 visitor.DepartSimpleRange(self) 

1037 

1038 def __str__(self) -> str: 

1039 """ 

1040 Formats the simple range. 

1041 

1042 **Format:** ``0 to 7`` 

1043 

1044 :returns: Formatted simple range. 

1045 """ 

1046 return f"{self._leftBound!s} {self._direction!s} {self._rightBound!s}" 

1047 

1048 

1049@export 

1050class RangeFromName(Range): 

1051 """ 

1052 A range denoted by a name, so its bounds are inferred from whatever that name references. 

1053 

1054 The name is represented by a :class:`~pyVHDLModel.Symbol.Symbol`, so the bounds become available once 

1055 that symbol is resolved. A constrained subtype indication keeps its type mark *and* its range 

1056 constraint, because it's carried by a :class:`~pyVHDLModel.Symbol.ConstrainedScalarSubtypeSymbol`. 

1057 

1058 .. note:: 

1059 

1060 Two forms reach this class, because a parser can't tell them apart beyond "a name, optionally with 

1061 a range constraint": 

1062 

1063 * a range attribute like ``vector'range``, and 

1064 * a discrete subtype indication like ``bit`` or ``integer range 0 to 7``. 

1065 

1066 VHDL's grammar puts the latter one level up (``discrete_range ::= discrete_subtype_indication | 

1067 range``), so representing both as a range deviates from the rule split deliberately. 

1068 """ 

1069 

1070 _symbol: Symbol #: Reference to the name the range's bounds are inferred from. 

1071 

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

1073 """ 

1074 Initialize a range denoted by a name. 

1075 

1076 :param symbol: The symbol referencing the range attribute or discrete subtype. 

1077 :param parent: The parent model entity. 

1078 """ 

1079 super().__init__(parent) 

1080 

1081 self._symbol = symbol 

1082 symbol.Parent = self 

1083 

1084 @readonly 

1085 def Symbol(self) -> Symbol: 

1086 """ 

1087 Read-only property to access the referenced symbol (:attr:`_symbol`). 

1088 

1089 :returns: The symbol. 

1090 """ 

1091 return self._symbol 

1092 

1093 def Copy(self) -> Self: 

1094 """ 

1095 Create a copy of this range denoted by a name. 

1096 

1097 The copy has no parent. Its symbol is a copy of this range's symbol. 

1098 

1099 :returns: The new range denoted by a name. 

1100 """ 

1101 return self.__class__(self._symbol.Copy()) 

1102 

1103 def Visit(self, visitor: Visitor) -> None: 

1104 """ 

1105 Walk this range and its name with a visitor. 

1106 

1107 :param visitor: The visitor receiving the events. 

1108 """ 

1109 visitor.VisitRangeFromName(self) 

1110 self._symbol.Visit(visitor) 

1111 visitor.DepartRangeFromName(self) 

1112 

1113 def __str__(self) -> str: 

1114 """ 

1115 Formats the range denoted by a name. 

1116 

1117 **Format:** ``v'range`` 

1118 

1119 :returns: Formatted range denoted by a name. 

1120 """ 

1121 return f"{self._symbol!s}" 

1122 

1123 

1124@export 

1125class WaveformElement(ModelEntity): 

1126 """ 

1127 Represents one element of a waveform in a signal assignment. 

1128 

1129 A waveform element assigns a value (:data:`Expression`) after an optional delay (:data:`After`). 

1130 

1131 .. admonition:: Example 

1132 

1133 .. code-block:: VHDL 

1134 

1135 s <= '1' after 5 ns; 

1136 -- ^^^ <- Expression 

1137 -- ^^^^ <- After 

1138 

1139 .. seealso:: 

1140 

1141 * :class:`Waveform of a simple assignment <pyVHDLModel.Common.WaveformMixin>` 

1142 * :class:`Waveform of one conditional branch <pyVHDLModel.Common.ConditionalWaveform>` 

1143 * :class:`Waveform of one selected alternative <pyVHDLModel.Common.SelectedWaveform>` 

1144 """ 

1145 _expression: ExpressionUnion #: The value this waveform element assigns. 

1146 _after: ExpressionUnion #: The delay after which the value is assigned, or ``None`` if none was given. 

1147 

1148 def __init__(self, expression: ExpressionUnion, after: Nullable[ExpressionUnion] = None, parent: Nullable[ModelEntity] = None) -> None: 

1149 """ 

1150 Initializes a waveform element. 

1151 

1152 :param expression: The value this waveform element assigns. 

1153 :param after: The delay after which the value is assigned, or ``None`` if none was given. 

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

1155 """ 

1156 super().__init__(parent) 

1157 

1158 self._expression = expression 

1159 expression.Parent = self 

1160 

1161 self._after = after 

1162 if after is not None: 

1163 after.Parent = self 

1164 

1165 def Visit(self, visitor: Visitor) -> None: 

1166 """ 

1167 Walk this waveform element, its value and its delay (if any) with a visitor. 

1168 

1169 :param visitor: The visitor receiving the events. 

1170 """ 

1171 visitor.VisitWaveformElement(self) 

1172 self._expression.Visit(visitor) 

1173 if self._after is not None: 

1174 visitor.VisitAfter(self) 

1175 self._after.Visit(visitor) 

1176 

1177 visitor.DepartWaveformElement(self) 

1178 

1179 @readonly 

1180 def Expression(self) -> ExpressionUnion: 

1181 """ 

1182 Read-only property to access the expression (:attr:`_expression`). 

1183 

1184 :returns: The expression. 

1185 """ 

1186 return self._expression 

1187 

1188 @readonly 

1189 def After(self) -> Expression: 

1190 """ 

1191 Read-only property to access the waveform element's delay (:attr:`_after`). 

1192 

1193 :returns: The after. 

1194 """ 

1195 return self._after