Coverage for pyVHDLModel/Base.py: 96%

225 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 

35Base-classes for the VHDL language model. 

36""" 

37from enum import unique, Enum 

38from typing import Type, Tuple, List, Iterable, Optional as Nullable, Union, cast 

39 

40from pyTooling.Common import getFullyQualifiedName 

41from pyTooling.Decorators import export, readonly 

42from pyTooling.MetaClasses import ExtendedType 

43 

44 

45__all__ = ["ExpressionUnion"] 

46 

47 

48ExpressionUnion = Union[ 

49 'BaseExpression', 

50 'QualifiedExpression', 

51 'FunctionCall', 

52 'TypeConversion', 

53 # ConstantOrSymbol, TODO: ObjectSymbol 

54 'Literal', 

55] 

56 

57 

58@export 

59@unique 

60class Direction(Enum): 

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

62 

63 To = 0 #: Ascending direction 

64 DownTo = 1 #: Descending direction 

65 

66 def __str__(self) -> str: 

67 """ 

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

69 

70 :returns: Formatted direction. 

71 """ 

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

73 

74 

75@export 

76@unique 

77class Mode(Enum): 

78 """ 

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

80 generic, port or parameter lists. 

81 

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

83 """ 

84 

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

86 In = 1 #: Input 

87 Out = 2 #: Output 

88 InOut = 3 #: Bi-directional 

89 Buffer = 4 #: Buffered output 

90 Linkage = 5 #: undocumented 

91 

92 def __str__(self) -> str: 

93 """ 

94 Formats the mode. 

95 

96 :returns: Formatted mode. 

97 """ 

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

99 

100 

101@export 

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

103 """ 

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

105 inheritance) and enumerations. 

106 

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

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

109 """ 

110 

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

112 

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

114 """ 

115 Initializes a VHDL model entity. 

116 

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

118 """ 

119 self._parent = parent 

120 

121 @property 

122 def Parent(self) -> 'ModelEntity': 

123 """ 

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

125 

126 :returns: Reference to the parent entity. 

127 """ 

128 return self._parent 

129 

130 @Parent.setter 

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

132 if parent is None: 

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

134 

135 self._parent = parent 

136 

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

138 """ 

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

140 

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

142 ancestor of the requested type is found. 

143 

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

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

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

147 type. 

148 """ 

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

150 from pyVHDLModel.Exception import VHDLModelException 

151 

152 parent = self._parent 

153 while parent is not None: 

154 if isinstance(parent, type): 

155 break 

156 

157 parent = parent._parent 

158 else: 

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

160 

161 return parent 

162 

163 

164@export 

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

166 """ 

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

168 

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

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

171 

172 .. seealso:: 

173 

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

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

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

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

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

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

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

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

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

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

184 """ 

185 

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

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

188 

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

190 """ 

191 Initializes a named entity. 

192 

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

194 """ 

195 self._identifier = identifier 

196 self._normalizedIdentifier = identifier.lower() 

197 

198 @readonly 

199 def Identifier(self) -> str: 

200 """ 

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

202 

203 :returns: Name of a model entity. 

204 """ 

205 return self._identifier 

206 

207 @readonly 

208 def NormalizedIdentifier(self) -> str: 

209 """ 

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

211 

212 :returns: Normalized name of a model entity. 

213 """ 

214 return self._normalizedIdentifier 

215 

216 

217@export 

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

219 """ 

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

221 

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

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

224 

225 .. seealso:: 

226 

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

228 """ 

229 

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

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

232 

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

234 """ 

235 Initializes a named entity. 

236 

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

238 """ 

239 self._identifier = identifier 

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

241 

242 @readonly 

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

244 """ 

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

246 

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

248 """ 

249 return self._identifier 

250 

251 @readonly 

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

253 """ 

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

255 

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

257 """ 

258 return self._normalizedIdentifier 

259 

260 

261@export 

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

263 """ 

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

265 defining multiple identifiers. 

266 

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

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

269 

270 .. seealso:: 

271 

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

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

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

275 """ 

276 

277 _identifiers: Tuple[str] #: A list of identifiers. 

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

279 

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

281 """ 

282 Initializes a multiple-named entity. 

283 

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

285 """ 

286 self._identifiers = tuple(identifiers) 

287 self._normalizedIdentifiers = tuple([identifier.lower() for identifier in identifiers]) 

288 

289 @readonly 

290 def Identifiers(self) -> Tuple[str]: 

291 """ 

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

293 

294 :returns: Tuple of identifiers. 

295 """ 

296 return self._identifiers 

297 

298 @readonly 

299 def NormalizedIdentifiers(self) -> Tuple[str]: 

300 """ 

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

302 

303 :returns: Tuple of normalized identifiers. 

304 """ 

305 return self._normalizedIdentifiers 

306 

307 

308@export 

309def identifiersOf(item) -> Tuple[str, ...]: 

310 """ 

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

312 

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

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

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

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

317 

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

319 :returns: The item's identifiers. 

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

321 

322 .. seealso:: 

323 

324 :func:`normalizedIdentifiersOf` 

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

326 """ 

327 if isinstance(item, MultipleNamedEntityMixin): 

328 return item._identifiers 

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

330 return (item._identifier, ) 

331 

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

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

334 raise ex 

335 

336 

337@export 

338def normalizedIdentifiersOf(item) -> Tuple[str, ...]: 

339 """ 

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

341 

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

343 case-insensitive. 

344 

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

346 :returns: The item's normalized identifiers. 

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

348 

349 .. seealso:: 

350 

351 :func:`identifiersOf` 

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

353 """ 

354 if isinstance(item, MultipleNamedEntityMixin): 

355 return item._normalizedIdentifiers 

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

357 return (item._normalizedIdentifier, ) 

358 

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

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

361 raise ex 

362 

363 

364@export 

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

366 """ 

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

368 

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

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

371 

372 .. seealso:: 

373 

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

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

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

377 """ 

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

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

380 

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

382 """ 

383 Initializes a labeled entity. 

384 

385 :param label: Label of the model entity. 

386 """ 

387 self._label = label 

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

389 

390 @readonly 

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

392 """ 

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

394 

395 :returns: Label of a model entity. 

396 """ 

397 return self._label 

398 

399 @readonly 

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

401 """ 

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

403 

404 :returns: Normalized label of a model entity. 

405 """ 

406 return self._normalizedLabel 

407 

408 

409@export 

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

411 """ 

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

413 

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

415 :attr:`Documentation` for public access. 

416 """ 

417 

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

419 

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

421 """ 

422 Initializes a documented entity. 

423 

424 :param documentation: Documentation of a model entity. 

425 """ 

426 self._documentation = documentation 

427 

428 @readonly 

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

430 """ 

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

432 

433 :returns: Associated documentation of a model entity. 

434 """ 

435 return self._documentation 

436 

437 

438@export 

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

440 """ 

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

442 

443 .. seealso:: 

444 

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

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

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

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

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

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

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

452 """ 

453 

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

455 

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

457 """ 

458 Initializes a statement with a condition. 

459 

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

461 

462 :param condition: The expression representing the condition. 

463 """ 

464 self._condition = condition 

465 if condition is not None: 

466 condition.Parent = self 

467 

468 @readonly 

469 def Condition(self) -> ExpressionUnion: 

470 """ 

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

472 

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

474 """ 

475 return self._condition 

476 

477 

478@export 

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

480 """ 

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

482 

483 .. seealso:: 

484 

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

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

487 """ 

488 

489 def __init__(self) -> None: 

490 """ 

491 Initializes a branch. 

492 """ 

493 pass 

494 

495 

496@export 

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

498 """ 

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

500 

501 .. seealso:: 

502 

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

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

505 """ 

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

507 """ 

508 Initializes a conditional branch. 

509 

510 :param condition: The condition guarding this statement. 

511 """ 

512 super().__init__() 

513 ConditionalMixin.__init__(self, condition) 

514 

515 

516@export 

517class IfBranchMixin(ConditionalBranchMixin, mixin=True): 

518 """ 

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

520 

521 .. seealso:: 

522 

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

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

525 """ 

526 

527 

528@export 

529class ElsifBranchMixin(ConditionalBranchMixin, mixin=True): 

530 """ 

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

532 

533 .. seealso:: 

534 

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

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

537 """ 

538 

539 

540@export 

541class ElseBranchMixin(BranchMixin, mixin=True): 

542 """ 

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

544 

545 .. seealso:: 

546 

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

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

549 """ 

550 

551 

552@export 

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

554 """ 

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

556 

557 .. seealso:: 

558 

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

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

561 """ 

562 

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

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

565 

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

567 """ 

568 Initializes a report statement. 

569 

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

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

572 """ 

573 self._message = message 

574 if message is not None: 574 ↛ 577line 574 didn't jump to line 577 because the condition on line 574 was always true

575 message.Parent = self 

576 

577 self._severity = severity 

578 if severity is not None: 

579 severity.Parent = self 

580 

581 @readonly 

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

583 """ 

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

585 

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

587 """ 

588 return self._message 

589 

590 @readonly 

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

592 """ 

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

594 

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

596 """ 

597 return self._severity 

598 

599 

600@export 

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

602 """ 

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

604 

605 .. seealso:: 

606 

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

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

609 """ 

610 

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

612 """ 

613 Initializes an assert statement. 

614 

615 :param condition: The condition guarding this statement. 

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

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

618 """ 

619 super().__init__(message, severity) 

620 ConditionalMixin.__init__(self, condition) 

621 

622 

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

624 """ 

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

626 

627 .. seealso:: 

628 

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

630 """ 

631 

632 def __init__(self) -> None: 

633 """ 

634 Initializes a block statement. 

635 """ 

636 pass 

637 

638 

639@export 

640class BaseChoice(ModelEntity): 

641 """ 

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

643 

644 .. seealso:: 

645 

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

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

648 """ 

649 

650 

651@export 

652class BaseCase(ModelEntity): 

653 """ 

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

655 

656 .. seealso:: 

657 

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

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

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

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

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

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

664 """ 

665 

666 

667@export 

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

669 """ 

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

671 

672 .. seealso:: 

673 

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

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

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

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

678 """ 

679 

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

681 

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

683 """ 

684 Initializes choices. 

685 

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

687 """ 

688 self._choices = [] 

689 if choices is not None: 

690 for choice in choices: 

691 self._choices.append(choice) 

692 choice.Parent = self 

693 

694 @readonly 

695 def Choices(self) -> List[BaseChoice]: 

696 """ 

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

698 

699 :returns: List of choices. 

700 """ 

701 return self._choices 

702 

703 

704@export 

705class Range(ModelEntity): 

706 """ 

707 Base-class for all ranges. 

708 

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

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

711 

712 .. seealso:: 

713 

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

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

716 """ 

717 

718 

719@export 

720class SimpleRange(Range): 

721 """ 

722 A range with both bounds given as expressions, e.g. ``0 to 7``. 

723 """ 

724 

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

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

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

728 

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

730 """ 

731 Initialize a simple range. 

732 

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

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

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

736 :param parent: The parent model entity. 

737 """ 

738 super().__init__(parent) 

739 

740 self._leftBound = leftBound 

741 leftBound.Parent = self 

742 

743 self._rightBound = rightBound 

744 rightBound.Parent = self 

745 

746 self._direction = direction 

747 

748 @readonly 

749 def LeftBound(self) -> ExpressionUnion: 

750 """ 

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

752 

753 :returns: The left bound. 

754 """ 

755 return self._leftBound 

756 

757 @readonly 

758 def RightBound(self) -> ExpressionUnion: 

759 """ 

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

761 

762 :returns: The right bound. 

763 """ 

764 return self._rightBound 

765 

766 @readonly 

767 def Direction(self) -> Direction: 

768 """ 

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

770 

771 :returns: The direction. 

772 """ 

773 return self._direction 

774 

775 def __str__(self) -> str: 

776 """ 

777 Formats the simple range. 

778 

779 **Format:** ``0 to 7`` 

780 

781 :returns: Formatted simple range. 

782 """ 

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

784 

785 

786@export 

787class RangeFromName(Range): 

788 """ 

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

790 

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

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

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

794 

795 .. note:: 

796 

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

798 a range constraint": 

799 

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

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

802 

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

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

805 """ 

806 

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

808 

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

810 """ 

811 Initialize a range denoted by a name. 

812 

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

814 :param parent: The parent model entity. 

815 """ 

816 super().__init__(parent) 

817 

818 self._symbol = symbol 

819 symbol.Parent = self 

820 

821 @readonly 

822 def Symbol(self) -> 'Symbol': 

823 """ 

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

825 

826 :returns: The symbol. 

827 """ 

828 return self._symbol 

829 

830 def __str__(self) -> str: 

831 """ 

832 Formats the range denoted by a name. 

833 

834 **Format:** ``v'range`` 

835 

836 :returns: Formatted range denoted by a name. 

837 """ 

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

839 

840 

841@export 

842class WaveformElement(ModelEntity): 

843 """ 

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

845 

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

847 

848 .. admonition:: Example 

849 

850 .. code-block:: VHDL 

851 

852 s <= '1' after 5 ns; 

853 -- ^^^ <- Expression 

854 -- ^^^^ <- After 

855 

856 .. seealso:: 

857 

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

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

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

861 """ 

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

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

864 

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

866 """ 

867 Initializes a waveform element. 

868 

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

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

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

872 """ 

873 super().__init__(parent) 

874 

875 self._expression = expression 

876 expression.Parent = self 

877 

878 self._after = after 

879 if after is not None: 

880 after.Parent = self 

881 

882 @readonly 

883 def Expression(self) -> ExpressionUnion: 

884 """ 

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

886 

887 :returns: The expression. 

888 """ 

889 return self._expression 

890 

891 @readonly 

892 def After(self) -> Expression: 

893 """ 

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

895 

896 :returns: The after. 

897 """ 

898 return self._after