Coverage for pyVHDLModel/Common.py: 96%

299 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 

35Common definitions and Mixins are used by many classes in the model as base-classes. 

36""" 

37from __future__ import annotations 

38 

39from typing import TYPE_CHECKING, Iterable, Union, Optional as Nullable 

40 

41from pyTooling.Common import getFullyQualifiedName, getTypeName 

42from pyTooling.Decorators import export, readonly 

43from pyTooling.MetaClasses import ExtendedType, abstractclass 

44 

45from pyVHDLModel.Base import ModelEntity, LabeledEntityMixin, BaseCase, BaseChoice, WaveformElement, \ 

46 ConditionalMixin, ChoicesMixin 

47from pyVHDLModel.Exception import AlreadyInDesignError, NotAChildError, AssociationOrderError, \ 

48 DuplicateParameterAssociationError 

49from pyVHDLModel.Expression import BaseExpression, QualifiedExpression, FunctionCall, TypeConversion, Literal 

50from pyVHDLModel.Name import SimpleName 

51from pyVHDLModel.Symbol import Symbol, SignalSymbol, VariableSymbol 

52from pyVHDLModel.Association import ParameterAssociationItem 

53 

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

55 from pyVHDLModel.Visitor import Visitor 

56 

57 

58ExpressionUnion = Union[ 

59 BaseExpression, 

60 QualifiedExpression, 

61 FunctionCall, 

62 TypeConversion, 

63 # ConstantOrSymbol, TODO: ObjectSymbol 

64 Literal, 

65] 

66 

67 

68@export 

69class AllowBlackboxMixin(metaclass=ExtendedType, mixin=True, expects=("_parent",)): 

70 """ 

71 A mixin-class for language entities that may permit blackboxes. 

72 

73 The setting is inherited from the parent when not set locally (:data:`AllowBlackbox`). The host class provides the 

74 reference to the parent ``_parent``. 

75 

76 .. seealso:: 

77 

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

79 * :class:`Generate branch <pyVHDLModel.Concurrent.GenerateBranch>` 

80 * :class:`Generate statement <pyVHDLModel.Concurrent.GenerateStatement>` 

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

82 * :class:`Package <pyVHDLModel.DesignUnit.Package>` 

83 * :class:`Entity <pyVHDLModel.DesignUnit.Entity>` 

84 * :class:`Architecture <pyVHDLModel.DesignUnit.Architecture>` 

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

86 * :class:`Design <pyVHDLModel.Design>` 

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

88 """ 

89 _allowBlackbox: Nullable[bool] #: Allow blackboxes for components; ``None`` inherits the parent's setting. 

90 

91 def __init__(self, allowBlackbox: Nullable[bool] = None) -> None: 

92 """ 

93 Initializes a hierarchical model entity allow for blackboxes. 

94 

95 :param allowBlackbox: Allow blackboxes for components in language entity. 

96 """ 

97 self._allowBlackbox = allowBlackbox 

98 

99 @property 

100 def AllowBlackbox(self) -> bool: 

101 """ 

102 Property to return whether a design supports blackboxes, inherited from the parent if not set locally 

103 (:attr:`_allowBlackbox`). 

104 

105 .. rubric:: Algorithm 

106 

107 1. If allow blackbox property is locally set, return the local value, 

108 2. Otherwise, return allow blackbox value from parent object. 

109 

110 :returns: ``True``, if blackboxes are allowed. 

111 :raises VHDLModelException: If neither a local value is set nor a parent object is available to inherit the 

112 value from. 

113 """ 

114 if self._allowBlackbox is not None: 

115 return self._allowBlackbox 

116 elif self._parent is None: 

117 from pyVHDLModel.Exception import VHDLModelException 

118 

119 raise VHDLModelException(f"AllowBlackbox is not set on {self!r} and no parent is available to inherit it from.") 

120 else: 

121 return self._parent.AllowBlackbox 

122 

123 @AllowBlackbox.setter 

124 def AllowBlackbox(self, value: Nullable[bool]) -> None: 

125 self._allowBlackbox = value 

126 

127 

128@export 

129@abstractclass 

130class Statement(ModelEntity, LabeledEntityMixin): 

131 """ 

132 A ``Statement`` is a base-class for all statements. 

133 

134 .. seealso:: 

135 

136 * :class:`Concurrent statement <pyVHDLModel.Concurrent.ConcurrentStatement>` 

137 * :class:`Sequential statement <pyVHDLModel.Sequential.SequentialStatement>` 

138 """ 

139 def __init__(self, label: Nullable[str] = None, parent=None) -> None: 

140 """ 

141 Initializes a statement. 

142 

143 :param label: The label of a model entity. 

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

145 """ 

146 super().__init__(parent) 

147 LabeledEntityMixin.__init__(self, label) 

148 

149 

150@export 

151class ProcedureCallMixin(metaclass=ExtendedType, mixin=True): 

152 """ 

153 A mixin-class for statements calling a procedure. 

154 

155 The called procedure is available as :data:`Procedure`, its actual parameters as 

156 :data:`ParameterAssociationItems`. 

157 

158 An association declares nothing: the mutators update neither a namespace nor a lookup table of the host class, so the 

159 mixin expects nothing from its host. 

160 

161 .. seealso:: 

162 

163 * :class:`Concurrent procedure call <pyVHDLModel.Concurrent.ConcurrentProcedureCall>` 

164 * :class:`Sequential procedure call <pyVHDLModel.Sequential.SequentialProcedureCall>` 

165 """ 

166 # TODO: implement a ProcedureSymbol 

167 _procedure: Symbol #: Reference to the called procedure. 

168 _parameterAssociationItems: list[ParameterAssociationItem] #: List of all parameter associations of the call. 

169 

170 def __init__(self, procedureName: Symbol, parameterAssociationItems: Nullable[Iterable[ParameterAssociationItem]] = None) -> None: 

171 """ 

172 Initializes a procedure call. 

173 

174 :param procedureName: Reference to the called procedure. 

175 :param parameterAssociationItems: List of all parameter associations of the call. 

176 """ 

177 self._procedure = procedureName 

178 procedureName.Parent = self 

179 

180 # TODO: extract to mixin 

181 self._parameterAssociationItems = parameterAssociationItemList = [] 

182 if parameterAssociationItems is not None: 

183 for parameterMapping in parameterAssociationItems: 

184 parameterAssociationItemList.append(parameterMapping) 

185 parameterMapping.Parent = self 

186 

187 def _VisitProcedureCall(self, visitor: Visitor) -> None: 

188 """ 

189 Walk the called procedure and the actual parameter part, if there are parameters, with a visitor. 

190 

191 :param visitor: The visitor receiving the events. 

192 """ 

193 self._procedure.Visit(visitor) 

194 if len(self._parameterAssociationItems) == 0: 

195 return 

196 

197 visitor.VisitActualParameterPart(self) 

198 for index, item in enumerate(self._parameterAssociationItems): 

199 if index > 0: 

200 visitor.VisitComma(self) 

201 

202 item.Visit(visitor) 

203 

204 visitor.DepartActualParameterPart(self) 

205 

206 @readonly 

207 def Procedure(self) -> Symbol: 

208 """ 

209 Read-only property to access the procedure (:attr:`_procedure`). 

210 

211 :returns: The procedure. 

212 """ 

213 return self._procedure 

214 

215 @readonly 

216 def ParameterAssociationItems(self) -> list[ParameterAssociationItem]: 

217 """ 

218 Read-only property to access the parameter association items (:attr:`_parameterAssociationItems`). 

219 

220 :returns: List of parameter association items. 

221 """ 

222 return self._parameterAssociationItems 

223 

224 def AddParameterAssociationItem(self, parameterAssociationItem: ParameterAssociationItem) -> None: 

225 """ 

226 Add a parameter association at the end of the parameter association list. 

227 

228 The association's parent is set to this procedure call. 

229 

230 :param parameterAssociationItem: The parameter association to add. 

231 :raises ValueError: If parameter 'parameterAssociationItem' is ``None``. 

232 :raises TypeError: If parameter 'parameterAssociationItem' is not of type 

233 :class:`~pyVHDLModel.Association.ParameterAssociationItem`. 

234 :raises AlreadyInDesignError: If parameter 'parameterAssociationItem' already has a parent. 

235 :raises DuplicateParameterAssociationError: If the association is named, and another named association of the 

236 parameter association list has the same formal. 

237 :raises AssociationOrderError: If the association is positional, and the parameter association list has 

238 a named association. 

239 

240 .. seealso:: 

241 

242 :meth:`InsertParameterAssociationItem` 

243 |rarr| Insert a parameter association at a position of the parameter association list. 

244 :meth:`RemoveParameterAssociationItem` 

245 |rarr| Remove a parameter association from the parameter association list. 

246 """ 

247 self.InsertParameterAssociationItem(len(self._parameterAssociationItems), parameterAssociationItem) 

248 

249 def InsertParameterAssociationItem(self, index: int, parameterAssociationItem: ParameterAssociationItem) -> None: 

250 """ 

251 Insert a parameter association at a position of the parameter association list. 

252 

253 The association's parent is set to this procedure call. 

254 

255 A named association (``formal => actual``) can't repeat the formal of another named association of the parameter 

256 association list. Only formals given as a simple name are compared: a partial association (``a(0) => x``) or a 

257 conversion function (``to_integer(a) => x``) is accepted. All positional associations precede the named 

258 associations. 

259 

260 :param index: Position, from ``0`` (first) to the number of parameter associations 

261 (append). A negative index counts from the end, as for 

262 :meth:`list.insert`: ``-1`` inserts before the last parameter 

263 association. 

264 :param parameterAssociationItem: The parameter association to insert. 

265 :raises ValueError: If parameter 'index' is ``None``. 

266 :raises TypeError: If parameter 'index' is not of type :class:`int`. 

267 :raises ValueError: If parameter 'index' is out of range. 

268 :raises ValueError: If parameter 'parameterAssociationItem' is ``None``. 

269 :raises TypeError: If parameter 'parameterAssociationItem' is not of type 

270 :class:`~pyVHDLModel.Association.ParameterAssociationItem`. 

271 :raises AlreadyInDesignError: If parameter 'parameterAssociationItem' already has a parent. 

272 :raises DuplicateParameterAssociationError: If the association is named, and another named association of the 

273 parameter association list has the same formal. 

274 :raises AssociationOrderError: If the association is positional, and a named association precedes the 

275 position. 

276 :raises AssociationOrderError: If the association is named, and a positional association follows the 

277 position. 

278 

279 .. seealso:: 

280 

281 :meth:`AddParameterAssociationItem` 

282 |rarr| Add a parameter association at the end of the parameter association list. 

283 :meth:`RemoveParameterAssociationItem` 

284 |rarr| Remove a parameter association from the parameter association list. 

285 """ 

286 count = len(self._parameterAssociationItems) 

287 if index is None: 287 ↛ 288line 287 didn't jump to line 288 because the condition on line 287 was never true

288 raise ValueError("Parameter 'index' is None.") 

289 elif not isinstance(index, int): 289 ↛ 290line 289 didn't jump to line 290 because the condition on line 289 was never true

290 ex = TypeError("Parameter 'index' is not of type 'int'.") 

291 ex.add_note(f"Got type '{getFullyQualifiedName(index)}'.") 

292 raise ex 

293 elif not (-count <= index <= count): 293 ↛ 294line 293 didn't jump to line 294 because the condition on line 293 was never true

294 ex = ValueError(f"Parameter 'index' is out of range {-count}..{count}.") 

295 ex.add_note(f"Got value '{index}'.") 

296 raise ex 

297 

298 if parameterAssociationItem is None: 

299 raise ValueError("Parameter 'parameterAssociationItem' is None.") 

300 elif not isinstance(parameterAssociationItem, ParameterAssociationItem): 

301 ex = TypeError("Parameter 'parameterAssociationItem' is not of type 'ParameterAssociationItem'.") 

302 ex.add_note(f"Got type '{getFullyQualifiedName(parameterAssociationItem)}'.") 

303 raise ex 

304 elif parameterAssociationItem._parent is not None: 

305 ex = AlreadyInDesignError( 

306 f"{getTypeName(parameterAssociationItem)} already has a parent.", 

307 element=parameterAssociationItem, 

308 parent=parameterAssociationItem._parent 

309 ) 

310 ex.add_note(f"Remove it from its {getTypeName(parameterAssociationItem._parent)} first.") 

311 raise ex 

312 

313 formal = parameterAssociationItem._formal 

314 if isinstance(formal, SimpleName): 

315 normalizedFormal = formal._normalizedIdentifier 

316 for existing in self._parameterAssociationItems: 

317 if isinstance(existing._formal, SimpleName) and existing._formal._normalizedIdentifier == normalizedFormal: 

318 ex = DuplicateParameterAssociationError( 

319 f"{getTypeName(self)} already associates parameter '{formal._identifier}'.", 

320 identifier=formal._identifier, 

321 parent=self, 

322 element=parameterAssociationItem, 

323 existing=existing 

324 ) 

325 ex.add_note(f"Existing association is '{existing!s}'.") 

326 raise ex 

327 

328 position = index if index >= 0 else count + index 

329 if formal is None: 

330 for existing in self._parameterAssociationItems[:position]: 

331 if existing._formal is not None: 

332 ex = AssociationOrderError( 

333 f"Positional parameter association can't follow named association '{existing!s}'.", 

334 parent=self, 

335 element=parameterAssociationItem, 

336 existing=existing 

337 ) 

338 ex.add_note("Insert it before the first named association, or name its formal.") 

339 raise ex 

340 else: 

341 for existing in self._parameterAssociationItems[position:]: 

342 if existing._formal is None: 342 ↛ 341line 342 didn't jump to line 341 because the condition on line 342 was always true

343 ex = AssociationOrderError( 

344 f"Named parameter association can't precede positional association '{existing!s}'.", 

345 parent=self, 

346 element=parameterAssociationItem, 

347 existing=existing 

348 ) 

349 ex.add_note("Insert it after the last positional association.") 

350 raise ex 

351 

352 self._parameterAssociationItems.insert(index, parameterAssociationItem) 

353 parameterAssociationItem.Parent = self 

354 

355 def RemoveParameterAssociationItem(self, parameterAssociationItem: ParameterAssociationItem) -> None: 

356 """ 

357 Remove a parameter association from the parameter association list. 

358 

359 The association is detached: its parent is cleared. The association itself is unchanged and can be added to another 

360 procedure call, or inserted at another position. 

361 

362 :param parameterAssociationItem: The parameter association to remove. 

363 :raises ValueError: If parameter 'parameterAssociationItem' is ``None``. 

364 :raises TypeError: If parameter 'parameterAssociationItem' is not of type 

365 :class:`~pyVHDLModel.Association.ParameterAssociationItem`. 

366 :raises NotAChildError: If parameter 'parameterAssociationItem' is not a parameter association of this 

367 procedure call. 

368 

369 .. seealso:: 

370 

371 :meth:`AddParameterAssociationItem` 

372 |rarr| Add a parameter association at the end of the parameter association list. 

373 :meth:`InsertParameterAssociationItem` 

374 |rarr| Insert a parameter association at a position of the parameter association list. 

375 """ 

376 if parameterAssociationItem is None: 

377 raise ValueError("Parameter 'parameterAssociationItem' is None.") 

378 elif not isinstance(parameterAssociationItem, ParameterAssociationItem): 

379 ex = TypeError("Parameter 'parameterAssociationItem' is not of type 'ParameterAssociationItem'.") 

380 ex.add_note(f"Got type '{getFullyQualifiedName(parameterAssociationItem)}'.") 

381 raise ex 

382 

383 for index, item in enumerate(self._parameterAssociationItems): 

384 if item is parameterAssociationItem: 384 ↛ 383line 384 didn't jump to line 383 because the condition on line 384 was always true

385 break 

386 else: 

387 raise NotAChildError( 

388 f"{getTypeName(parameterAssociationItem)} is not a parameter association of this {getTypeName(self)}.", 

389 element=parameterAssociationItem, 

390 parent=self 

391 ) 

392 

393 del self._parameterAssociationItems[index] 

394 parameterAssociationItem._parent = None 

395 

396 

397@export 

398class AssignmentMixin(metaclass=ExtendedType, mixin=True): 

399 """ 

400 A mixin-class for all assignment statements. 

401 

402 .. seealso:: 

403 

404 * :class:`Signal assignment mixin <pyVHDLModel.Common.SignalAssignmentMixin>` 

405 * :class:`Variable assignment mixin <pyVHDLModel.Common.VariableAssignmentMixin>` 

406 * :class:`Conditional variable assignment <pyVHDLModel.Sequential.SequentialConditionalVariableAssignment>` 

407 * :class:`Sequential selected variable assignment <pyVHDLModel.Sequential.SequentialSelectedVariableAssignment>` 

408 """ 

409 

410 _target: Symbol #: Reference to the assignment's destination. 

411 

412 def __init__(self, target: Symbol) -> None: 

413 """ 

414 Initializes an assignment. 

415 

416 :param target: Reference to the assignment's destination. 

417 """ 

418 self._target = target 

419 target.Parent = self 

420 

421 @readonly 

422 def Target(self) -> Symbol: 

423 """ 

424 Read-only property to access the target (:attr:`_target`). 

425 

426 :returns: The target. 

427 """ 

428 return self._target 

429 

430 

431@export 

432class SignalAssignmentMixin(AssignmentMixin, mixin=True): 

433 """ 

434 A mixin-class for all signal assignment statements. 

435 

436 .. seealso:: 

437 

438 * :class:`Concurrent signal assignment <pyVHDLModel.Concurrent.ConcurrentSignalAssignment>` 

439 * :class:`Sequential signal assignment <pyVHDLModel.Sequential.SequentialSignalAssignment>` 

440 * :class:`Conditional signal assignment <pyVHDLModel.Sequential.SequentialConditionalSignalAssignment>` 

441 * :class:`Sequential selected signal assignment <pyVHDLModel.Sequential.SequentialSelectedSignalAssignment>` 

442 * :class:`Signal force assignment <pyVHDLModel.Sequential.SignalForceAssignment>` 

443 * :class:`Signal release assignment <pyVHDLModel.Sequential.SignalReleaseAssignment>` 

444 """ 

445 

446 @readonly 

447 def Target(self) -> SignalSymbol: 

448 """ 

449 Read-only property to access the target (:attr:`_target`). 

450 

451 :returns: The target. 

452 """ 

453 return self._target 

454 

455 

456@export 

457class VariableAssignmentMixin(AssignmentMixin, mixin=True): 

458 """ 

459 A mixin-class for all variable assignment statements. 

460 

461 .. seealso:: 

462 

463 * :class:`Sequential variable assignment <pyVHDLModel.Sequential.SequentialVariableAssignment>` 

464 """ 

465 

466 # FIXME: move to sequential? 

467 _expression: ExpressionUnion #: The assigned expression. 

468 

469 def __init__(self, target: VariableSymbol, expression: ExpressionUnion) -> None: 

470 """ 

471 Initializes a variable assignment. 

472 

473 :param target: Reference to the assignment's destination. 

474 :param expression: The assigned expression. 

475 """ 

476 super().__init__(target) 

477 

478 self._expression = expression 

479 expression.Parent = self 

480 

481 @readonly 

482 def Target(self) -> VariableSymbol: 

483 """ 

484 Read-only property to access the target (:attr:`_target`). 

485 

486 :returns: The target. 

487 """ 

488 return self._target 

489 

490 @readonly 

491 def Expression(self) -> ExpressionUnion: 

492 """ 

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

494 

495 :returns: The expression. 

496 """ 

497 return self._expression 

498 

499 

500@export 

501class WaveformMixin(metaclass=ExtendedType, mixin=True): 

502 """ 

503 A mixin-class for all statements/entities holding a waveform (a list of :class:`WaveformElement`). 

504 

505 .. seealso:: 

506 

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

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

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

510 * :class:`Concurrent simple signal assignment <pyVHDLModel.Concurrent.ConcurrentSimpleSignalAssignment>` 

511 * :class:`Sequential simple signal assignment <pyVHDLModel.Sequential.SequentialSimpleSignalAssignment>` 

512 * :class:`Waveform element <pyVHDLModel.Base.WaveformElement>` 

513 """ 

514 

515 _waveform: list[WaveformElement] #: List of all waveform elements, in the order they were written. 

516 

517 def __init__(self, waveform: Iterable[WaveformElement]) -> None: 

518 """ 

519 Initializes a waveform. 

520 

521 :param waveform: List of all waveform elements, in the order they were written. 

522 """ 

523 self._waveform = waveformList = [] 

524 for waveformElement in waveform: 

525 waveformList.append(waveformElement) 

526 waveformElement.Parent = self 

527 

528 def _VisitWaveform(self, visitor: Visitor) -> None: 

529 """ 

530 Walk the waveform elements, separated by commas, with a visitor. 

531 

532 :param visitor: The visitor receiving the events. 

533 """ 

534 for index, element in enumerate(self._waveform): 

535 if index > 0: 

536 visitor.VisitComma(self) 

537 

538 element.Visit(visitor) 

539 

540 @readonly 

541 def Waveform(self) -> list[WaveformElement]: 

542 """ 

543 Read-only property to access the waveform (:attr:`_waveform`). 

544 

545 :returns: List of waveform. 

546 """ 

547 return self._waveform 

548 

549 

550@export 

551class ExpressionMixin(metaclass=ExtendedType, mixin=True): 

552 """ 

553 A mixin-class for all statements/entities holding a single expression. 

554 

555 .. seealso:: 

556 

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

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

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

560 * :class:`Concurrent selected signal assignment <pyVHDLModel.Concurrent.ConcurrentSelectedSignalAssignment>` 

561 * :class:`Sequential selected variable assignment <pyVHDLModel.Sequential.SequentialSelectedVariableAssignment>` 

562 * :class:`Sequential selected signal assignment <pyVHDLModel.Sequential.SequentialSelectedSignalAssignment>` 

563 * :class:`Signal force assignment <pyVHDLModel.Sequential.SignalForceAssignment>` 

564 """ 

565 

566 _expression: ExpressionUnion #: The expression held by this construct. 

567 

568 def __init__(self, expression: ExpressionUnion) -> None: 

569 """ 

570 Initializes an expression. 

571 

572 :param expression: The expression held by this construct. 

573 """ 

574 self._expression = expression 

575 expression.Parent = self 

576 

577 @readonly 

578 def Expression(self) -> ExpressionUnion: 

579 """ 

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

581 

582 :returns: The expression. 

583 """ 

584 return self._expression 

585 

586 

587@export 

588class ConditionalWaveform(ModelEntity, WaveformMixin, ConditionalMixin): 

589 """ 

590 Represents one branch of a conditional signal assignment. 

591 

592 Each branch pairs a waveform (:data:`Waveform`) with a condition (:data:`Condition`). The final 

593 branch has no ``when``, so its condition is ``None``. 

594 

595 .. admonition:: Example 

596 

597 .. code-block:: VHDL 

598 

599 s <= '1' when cond else '0'; 

600 -- ^^^^^^^^^^^^^ <- this branch: Waveform=['1'], Condition=cond 

601 -- ^^^ <- final branch (no ``when``): Waveform=['0'], Condition=None 

602 

603 .. seealso:: 

604 

605 * :class:`Waveform element <pyVHDLModel.Base.WaveformElement>` 

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

607 """ 

608 

609 def __init__( 

610 self, 

611 waveform: Iterable[WaveformElement], 

612 condition: Nullable[ExpressionUnion] = None, 

613 parent: Nullable[ModelEntity] = None 

614 ) -> None: 

615 """ 

616 Initializes a conditional waveform. 

617 

618 :param waveform: List of all waveform elements, in the order they were written. 

619 :param condition: The condition selecting this alternative. 

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

621 """ 

622 super().__init__(parent) 

623 WaveformMixin.__init__(self, waveform) 

624 ConditionalMixin.__init__(self, condition) 

625 

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

627 """ 

628 Walk this conditional waveform, its waveform and its condition (if any) with a visitor. 

629 

630 :param visitor: The visitor receiving the events. 

631 """ 

632 visitor.VisitConditionalWaveform(self) 

633 self._VisitWaveform(visitor) 

634 if self._condition is not None: 

635 visitor.VisitWhen(self) 

636 self._condition.Visit(visitor) 

637 

638 visitor.DepartConditionalWaveform(self) 

639 

640 

641@export 

642class ConditionalExpression(ModelEntity, ExpressionMixin, ConditionalMixin): 

643 """ 

644 Represents one branch of a conditional variable assignment. 

645 

646 Each branch pairs an expression (:data:`Expression`) with a condition (:data:`Condition`). The 

647 final branch has no ``when``, so its condition is ``None``. 

648 

649 .. admonition:: Example 

650 

651 .. code-block:: VHDL 

652 

653 v := '1' when cond else '0'; 

654 -- ^^^^^^^^^^^^^ <- this branch: Expression='1', Condition=cond 

655 -- ^^^ <- final branch (no ``when``): Expression='0', Condition=None 

656 

657 .. seealso:: 

658 

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

660 """ 

661 

662 def __init__( 

663 self, 

664 expression: ExpressionUnion, 

665 condition: Nullable[ExpressionUnion] = None, 

666 parent: Nullable[ModelEntity] = None 

667 ) -> None: 

668 """ 

669 Initializes a conditional expression. 

670 

671 :param expression: The value assigned when the condition holds. 

672 :param condition: The condition selecting this alternative. 

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

674 """ 

675 super().__init__(parent) 

676 ExpressionMixin.__init__(self, expression) 

677 ConditionalMixin.__init__(self, condition) 

678 

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

680 """ 

681 Walk this conditional expression, its value and its condition (if any) with a visitor. 

682 

683 :param visitor: The visitor receiving the events. 

684 """ 

685 visitor.VisitConditionalExpression(self) 

686 self._expression.Visit(visitor) 

687 if self._condition is not None: 

688 visitor.VisitWhen(self) 

689 self._condition.Visit(visitor) 

690 

691 visitor.DepartConditionalExpression(self) 

692 

693 

694@export 

695class ConditionalWaveformsMixin(metaclass=ExtendedType, mixin=True): 

696 """ 

697 A mixin-class for all statements holding a list of :class:`ConditionalWaveform` (both the 

698 concurrent and sequential forms of a conditional signal assignment). 

699 

700 .. seealso:: 

701 

702 * :class:`Conditional signal assignment <pyVHDLModel.Concurrent.ConcurrentConditionalSignalAssignment>` 

703 * :class:`Conditional signal assignment <pyVHDLModel.Sequential.SequentialConditionalSignalAssignment>` """ 

704 

705 _conditionalWaveforms: list[ConditionalWaveform] #: All alternatives, in order. 

706 

707 def __init__(self, conditionalWaveforms: Iterable[ConditionalWaveform]) -> None: 

708 """ 

709 Initializes conditional waveforms. 

710 

711 :param conditionalWaveforms: All alternatives, in order. 

712 """ 

713 self._conditionalWaveforms = conditionalWaveformList = [] 

714 for conditionalWaveform in conditionalWaveforms: 

715 conditionalWaveformList.append(conditionalWaveform) 

716 conditionalWaveform.Parent = self 

717 

718 def _VisitConditionalWaveforms(self, visitor: Visitor) -> None: 

719 """ 

720 Walk the conditional waveforms, separated by the reserved word ``else``, with a visitor. 

721 

722 :param visitor: The visitor receiving the events. 

723 """ 

724 for index, conditionalWaveform in enumerate(self._conditionalWaveforms): 

725 if index > 0: 

726 visitor.VisitElse(self) 

727 

728 conditionalWaveform.Visit(visitor) 

729 

730 @readonly 

731 def ConditionalWaveforms(self) -> list[ConditionalWaveform]: 

732 """ 

733 Read-only property to access the conditional waveforms (:attr:`_conditionalWaveforms`). 

734 

735 :returns: List of conditional waveforms. 

736 """ 

737 return self._conditionalWaveforms 

738 

739 

740@export 

741class SelectedWaveform(BaseCase, WaveformMixin, ChoicesMixin): 

742 """ 

743 Represents one alternative of a selected signal assignment. 

744 

745 Each alternative pairs a waveform (:data:`Waveform`) with the choices selecting it 

746 (:data:`Choices`). 

747 

748 .. admonition:: Example 

749 

750 .. code-block:: VHDL 

751 

752 with sel select s <= '1' when '0', '0' when others; 

753 -- ^^^^^^^^^^^^ <- this alternative: Choices=['0'], Waveform=['1'] 

754 

755 .. seealso:: 

756 

757 * :class:`Waveform element <pyVHDLModel.Base.WaveformElement>` 

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

759 """ 

760 

761 def __init__( 

762 self, 

763 choices: Iterable[BaseChoice], 

764 waveform: Iterable[WaveformElement], 

765 parent: Nullable[ModelEntity] = None 

766 ) -> None: 

767 """ 

768 Initializes a selected waveform. 

769 

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

771 :param waveform: List of all waveform elements, in the order they were written. 

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

773 """ 

774 super().__init__(parent) 

775 WaveformMixin.__init__(self, waveform) 

776 ChoicesMixin.__init__(self, choices) 

777 

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

779 """ 

780 Walk this selected waveform, its waveform and its choices with a visitor. 

781 

782 :param visitor: The visitor receiving the events. 

783 """ 

784 visitor.VisitSelectedWaveform(self) 

785 self._VisitWaveform(visitor) 

786 visitor.VisitWhen(self) 

787 for index, choice in enumerate(self._choices): 

788 if index > 0: 

789 visitor.VisitBar(self) 

790 

791 choice.Visit(visitor) 

792 

793 visitor.DepartSelectedWaveform(self) 

794 

795 

796@export 

797class OthersSelectedWaveform(BaseCase, WaveformMixin): 

798 """ 

799 Represents the ``others`` alternative of a selected signal assignment. 

800 

801 It supplies the waveform (:data:`Waveform`) for every choice not named explicitly. 

802 

803 .. admonition:: Example 

804 

805 .. code-block:: VHDL 

806 

807 with sel select s <= '1' when '0', '0' when others; 

808 -- ^^^^^^^^^^^^^^^ <- the others alternative 

809 """ 

810 

811 def __init__(self, waveform: Iterable[WaveformElement], parent: Nullable[ModelEntity] = None) -> None: 

812 """ 

813 Initializes an others selected waveform. 

814 

815 :param waveform: List of all waveform elements, in the order they were written. 

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

817 """ 

818 super().__init__(parent) 

819 WaveformMixin.__init__(self, waveform) 

820 

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

822 """ 

823 Walk this ``others`` selected waveform and its waveform with a visitor. 

824 

825 :param visitor: The visitor receiving the events. 

826 """ 

827 visitor.VisitOthersSelectedWaveform(self) 

828 self._VisitWaveform(visitor) 

829 visitor.VisitWhen(self) 

830 visitor.DepartOthersSelectedWaveform(self) 

831 

832 

833@export 

834class SelectedExpression(BaseCase, ExpressionMixin, ChoicesMixin): 

835 """ 

836 Represents one alternative of a selected variable assignment. 

837 

838 Each alternative pairs an expression (:data:`Expression`) with the choices selecting it 

839 (:data:`Choices`). 

840 

841 .. admonition:: Example 

842 

843 .. code-block:: VHDL 

844 

845 with sel select v := '1' when '0', '0' when others; 

846 -- ^^^^^^^^^^^^ <- this alternative: Choices=['0'], Expression='1' 

847 

848 .. seealso:: 

849 

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

851 """ 

852 

853 def __init__( 

854 self, 

855 choices: Iterable[BaseChoice], 

856 expression: ExpressionUnion, 

857 parent: Nullable[ModelEntity] = None 

858 ) -> None: 

859 """ 

860 Initializes a selected expression. 

861 

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

863 :param expression: The value assigned for the matching choices. 

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

865 """ 

866 super().__init__(parent) 

867 ExpressionMixin.__init__(self, expression) 

868 ChoicesMixin.__init__(self, choices) 

869 

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

871 """ 

872 Walk this selected expression, its value and its choices with a visitor. 

873 

874 :param visitor: The visitor receiving the events. 

875 """ 

876 visitor.VisitSelectedExpression(self) 

877 self._expression.Visit(visitor) 

878 visitor.VisitWhen(self) 

879 for index, choice in enumerate(self._choices): 

880 if index > 0: 

881 visitor.VisitBar(self) 

882 

883 choice.Visit(visitor) 

884 

885 visitor.DepartSelectedExpression(self) 

886 

887 

888@export 

889class OthersSelectedExpression(BaseCase, ExpressionMixin): 

890 """ 

891 Represents the ``others`` alternative of a selected variable assignment. 

892 

893 It supplies the expression (:data:`Expression`) for every choice not named explicitly. 

894 

895 .. admonition:: Example 

896 

897 .. code-block:: VHDL 

898 

899 with sel select v := '1' when '0', '0' when others; 

900 -- ^^^^^^^^^^^^^^^ <- the others alternative 

901 """ 

902 

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

904 """ 

905 Initializes an others selected expression. 

906 

907 :param expression: The value assigned for every unnamed choice. 

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

909 """ 

910 super().__init__(parent) 

911 ExpressionMixin.__init__(self, expression) 

912 

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

914 """ 

915 Walk this ``others`` selected expression and its value with a visitor. 

916 

917 :param visitor: The visitor receiving the events. 

918 """ 

919 visitor.VisitOthersSelectedExpression(self) 

920 self._expression.Visit(visitor) 

921 visitor.VisitWhen(self) 

922 visitor.DepartOthersSelectedExpression(self) 

923 

924 

925@export 

926class SelectedWaveformsMixin(metaclass=ExtendedType, mixin=True): 

927 """ 

928 A mixin-class for all statements holding a list of :class:`SelectedWaveform`/ 

929 :class:`OthersSelectedWaveform` (both the concurrent and sequential forms of a selected signal 

930 assignment). 

931 

932 .. seealso:: 

933 

934 * :class:`Concurrent selected signal assignment <pyVHDLModel.Concurrent.ConcurrentSelectedSignalAssignment>` 

935 * :class:`Sequential selected signal assignment <pyVHDLModel.Sequential.SequentialSelectedSignalAssignment>` 

936 """ 

937 

938 _selectedWaveforms: list[Union[SelectedWaveform, OthersSelectedWaveform]] #: All alternatives, in order. 

939 

940 def __init__(self, selectedWaveforms: Iterable[Union[SelectedWaveform, OthersSelectedWaveform]]) -> None: 

941 """ 

942 Initializes selected waveforms. 

943 

944 :param selectedWaveforms: All alternatives, in order. 

945 """ 

946 self._selectedWaveforms = selectedWaveformList = [] 

947 for selectedWaveform in selectedWaveforms: 

948 selectedWaveformList.append(selectedWaveform) 

949 selectedWaveform.Parent = self 

950 

951 def _VisitSelectedWaveforms(self, visitor: Visitor) -> None: 

952 """ 

953 Walk the selected waveforms, separated by commas, with a visitor. 

954 

955 :param visitor: The visitor receiving the events. 

956 """ 

957 for index, selectedWaveform in enumerate(self._selectedWaveforms): 

958 if index > 0: 

959 visitor.VisitComma(self) 

960 

961 selectedWaveform.Visit(visitor) 

962 

963 @readonly 

964 def SelectedWaveforms(self) -> list[Union[SelectedWaveform, OthersSelectedWaveform]]: 

965 """ 

966 Read-only property to access the selected waveforms (:attr:`_selectedWaveforms`). 

967 

968 :returns: List of selected waveforms. 

969 """ 

970 return self._selectedWaveforms 

971 

972 

973@export 

974class SelectedExpressionsMixin(metaclass=ExtendedType, mixin=True): 

975 """ 

976 A mixin-class for all statements holding a list of :class:`SelectedExpression`/ 

977 :class:`OthersSelectedExpression`. 

978 

979 .. seealso:: 

980 

981 * :class:`Sequential selected variable assignment <pyVHDLModel.Sequential.SequentialSelectedVariableAssignment>` 

982 """ 

983 

984 _selectedExpressions: list[Union[SelectedExpression, OthersSelectedExpression]] #: All alternatives, in order. 

985 

986 def __init__(self, selectedExpressions: Iterable[Union[SelectedExpression, OthersSelectedExpression]]) -> None: 

987 """ 

988 Initializes selected expressions. 

989 

990 :param selectedExpressions: All alternatives, in order. 

991 """ 

992 self._selectedExpressions = selectedExpressionList = [] 

993 for selectedExpression in selectedExpressions: 

994 selectedExpressionList.append(selectedExpression) 

995 selectedExpression.Parent = self 

996 

997 def _VisitSelectedExpressions(self, visitor: Visitor) -> None: 

998 """ 

999 Walk the selected expressions, separated by commas, with a visitor. 

1000 

1001 :param visitor: The visitor receiving the events. 

1002 """ 

1003 for index, selectedExpression in enumerate(self._selectedExpressions): 

1004 if index > 0: 

1005 visitor.VisitComma(self) 

1006 

1007 selectedExpression.Visit(visitor) 

1008 

1009 @readonly 

1010 def SelectedExpressions(self) -> list[Union[SelectedExpression, OthersSelectedExpression]]: 

1011 """ 

1012 Read-only property to access the selected expressions (:attr:`_selectedExpressions`). 

1013 

1014 :returns: List of selected expressions. 

1015 """ 

1016 return self._selectedExpressions