Coverage for pyVHDLModel/Sequential.py: 52%

270 statements  

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

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

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

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

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

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

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

7# |_| |___/ # 

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

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

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

16# # 

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

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

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

20# # 

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

22# # 

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

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

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

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

27# limitations under the License. # 

28# # 

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

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

31# 

32""" 

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

34 

35Declarations for sequential statements. 

36""" 

37from typing import List, Iterable, Optional as Nullable 

38 

39from pyTooling.Decorators import export, readonly 

40from pyTooling.MetaClasses import ExtendedType 

41 

42from pyVHDLModel.Base import ModelEntity, ExpressionUnion, Range, BaseChoice, BaseCase, ConditionalMixin, IfBranchMixin, ElsifBranchMixin 

43from pyVHDLModel.Base import ElseBranchMixin, ReportStatementMixin, AssertStatementMixin, WaveformElement 

44from pyVHDLModel.Symbol import Symbol 

45from pyVHDLModel.Common import Statement, ProcedureCallMixin 

46from pyVHDLModel.Common import SignalAssignmentMixin, VariableAssignmentMixin 

47from pyVHDLModel.Association import ParameterAssociationItem 

48 

49 

50@export 

51class SequentialStatement(Statement): 

52 """A ``SequentialStatement`` is a base-class for all sequential statements.""" 

53 

54 

55@export 

56class SequentialStatementsMixin(metaclass=ExtendedType, mixin=True): 

57 _statements: List[SequentialStatement] 

58 

59 def __init__(self, statements: Nullable[Iterable[SequentialStatement]] = None) -> None: 

60 # TODO: extract to mixin 

61 self._statements = [] 

62 if statements is not None: 

63 for item in statements: 

64 self._statements.append(item) 

65 item._parent = self 

66 

67 @readonly 

68 def Statements(self) -> List[SequentialStatement]: 

69 """ 

70 Read-only property to access the list of sequential statements (:attr:`_statements`). 

71 

72 :returns: A list of sequential statements. 

73 """ 

74 return self._statements 

75 

76 

77@export 

78class SequentialProcedureCall(SequentialStatement, ProcedureCallMixin): 

79 def __init__( 

80 self, 

81 procedureName: Symbol, 

82 parameterMappings: Nullable[Iterable[ParameterAssociationItem]] = None, 

83 label: Nullable[str] = None, 

84 parent: ModelEntity = None 

85 ) -> None: 

86 super().__init__(label, parent) 

87 ProcedureCallMixin.__init__(self, procedureName, parameterMappings) 

88 

89 

90@export 

91class SequentialSignalAssignment(SequentialStatement, SignalAssignmentMixin): 

92 def __init__(self, target: Symbol, label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

93 super().__init__(label, parent) 

94 SignalAssignmentMixin.__init__(self, target) 

95 

96 

97@export 

98class SequentialSimpleSignalAssignment(SequentialSignalAssignment): 

99 _waveform: List[WaveformElement] 

100 

101 def __init__(self, target: Symbol, waveform: Iterable[WaveformElement], label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

102 super().__init__(target, label, parent) 

103 

104 # TODO: extract to mixin 

105 self._waveform = [] 

106 if waveform is not None: 

107 for waveformElement in waveform: 

108 self._waveform.append(waveformElement) 

109 waveformElement._parent = self 

110 

111 @readonly 

112 def Waveform(self) -> List[WaveformElement]: 

113 """ 

114 Read-only property to access the list waveform elements (:attr:`_waveform`). 

115 

116 :returns: A list of waveform elements. 

117 """ 

118 return self._waveform 

119 

120 

121@export 

122class SequentialVariableAssignment(SequentialStatement, VariableAssignmentMixin): 

123 def __init__(self, target: Symbol, expression: ExpressionUnion, label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

124 super().__init__(label, parent) 

125 VariableAssignmentMixin.__init__(self, target, expression) 

126 

127 

128@export 

129class SequentialReportStatement(SequentialStatement, ReportStatementMixin): 

130 def __init__(self, message: ExpressionUnion, severity: Nullable[ExpressionUnion] = None, label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

131 super().__init__(label, parent) 

132 ReportStatementMixin.__init__(self, message, severity) 

133 

134 

135@export 

136class SequentialAssertStatement(SequentialStatement, AssertStatementMixin): 

137 def __init__( 

138 self, 

139 condition: ExpressionUnion, 

140 message: Nullable[ExpressionUnion] = None, 

141 severity: Nullable[ExpressionUnion] = None, 

142 label: Nullable[str] = None, 

143 parent: ModelEntity = None 

144 ) -> None: 

145 super().__init__(label, parent) 

146 AssertStatementMixin.__init__(self, condition, message, severity) 

147 

148 

149@export 

150class CompoundStatement(SequentialStatement): 

151 """A ``CompoundStatement`` is a base-class for all compound statements.""" 

152 

153 

154@export 

155class Branch(ModelEntity, SequentialStatementsMixin): 

156 """A ``Branch`` is a base-class for all branches in a if statement.""" 

157 

158 def __init__(self, statements: Nullable[Iterable[SequentialStatement]] = None, parent: ModelEntity = None) -> None: 

159 super().__init__(parent) 

160 SequentialStatementsMixin.__init__(self, statements) 

161 

162 

163@export 

164class IfBranch(Branch, IfBranchMixin): 

165 def __init__(self, condition: ExpressionUnion, statements: Nullable[Iterable[SequentialStatement]] = None, parent: ModelEntity = None) -> None: 

166 super().__init__(statements, parent) 

167 IfBranchMixin.__init__(self, condition) 

168 

169 

170@export 

171class ElsifBranch(Branch, ElsifBranchMixin): 

172 def __init__(self, condition: ExpressionUnion, statements: Nullable[Iterable[SequentialStatement]] = None, parent: ModelEntity = None) -> None: 

173 super().__init__(statements, parent) 

174 ElsifBranchMixin.__init__(self, condition) 

175 

176 

177@export 

178class ElseBranch(Branch, ElseBranchMixin): 

179 def __init__(self, statements: Nullable[Iterable[SequentialStatement]] = None, parent: ModelEntity = None) -> None: 

180 super().__init__(statements, parent) 

181 ElseBranchMixin.__init__(self) 

182 

183 

184@export 

185class IfStatement(CompoundStatement): 

186 _ifBranch: IfBranch 

187 _elsifBranches: List['ElsifBranch'] 

188 _elseBranch: Nullable[ElseBranch] 

189 

190 def __init__( 

191 self, 

192 ifBranch: IfBranch, 

193 elsifBranches: Nullable[Iterable[ElsifBranch]] = None, 

194 elseBranch: Nullable[ElseBranch] = None, 

195 label: Nullable[str] = None, 

196 parent: ModelEntity = None 

197 ) -> None: 

198 super().__init__(label, parent) 

199 

200 self._ifBranch = ifBranch 

201 ifBranch._parent = self 

202 

203 self._elsifBranches = [] 

204 if elsifBranches is not None: 

205 for branch in elsifBranches: 

206 self._elsifBranches.append(branch) 

207 branch._parent = self 

208 

209 if elseBranch is not None: 

210 self._elseBranch = elseBranch 

211 elseBranch._parent = self 

212 else: 

213 self._elseBranch = None 

214 

215 @readonly 

216 def IfBranch(self) -> IfBranch: 

217 """ 

218 Read-only property to access the if-branch of the if-statement (:attr:`_ifBranch`). 

219 

220 :returns: The if-branch. 

221 """ 

222 return self._ifBranch 

223 

224 @property 

225 def ElsIfBranches(self) -> List['ElsifBranch']: 

226 """ 

227 Read-only property to access the elsif-branch of the if-statement (:attr:`_elsifBranch`). 

228 

229 :returns: The elsif-branch. 

230 """ 

231 return self._elsifBranches 

232 

233 @property 

234 def ElseBranch(self) -> Nullable[ElseBranch]: 

235 """ 

236 Read-only property to access the else-branch of the if-statement (:attr:`_elseBranch`). 

237 

238 :returns: The else-branch. 

239 """ 

240 return self._elseBranch 

241 

242 

243@export 

244class SequentialChoice(BaseChoice): 

245 """A ``SequentialChoice`` is a base-class for all sequential choices (in case statements).""" 

246 

247 

248@export 

249class IndexedChoice(SequentialChoice): 

250 _expression: ExpressionUnion 

251 

252 def __init__(self, expression: ExpressionUnion, parent: ModelEntity = None) -> None: 

253 super().__init__(parent) 

254 

255 self._expression = expression 

256 # expression._parent = self # FIXME: received None 

257 

258 @property 

259 def Expression(self) -> ExpressionUnion: 

260 return self._expression 

261 

262 def __str__(self) -> str: 

263 return str(self._expression) 

264 

265 

266@export 

267class RangedChoice(SequentialChoice): 

268 _range: 'Range' 

269 

270 def __init__(self, rng: 'Range', parent: ModelEntity = None) -> None: 

271 super().__init__(parent) 

272 

273 self._range = rng 

274 rng._parent = self 

275 

276 @property 

277 def Range(self) -> 'Range': 

278 return self._range 

279 

280 def __str__(self) -> str: 

281 return str(self._range) 

282 

283 

284@export 

285class SequentialCase(BaseCase, SequentialStatementsMixin): 

286 _choices: List 

287 

288 def __init__(self, statements: Nullable[Iterable[SequentialStatement]] = None, parent: ModelEntity = None) -> None: 

289 super().__init__(parent) 

290 SequentialStatementsMixin.__init__(self, statements) 

291 

292 # TODO: what about choices? 

293 

294 @property 

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

296 return self._choices 

297 

298 

299@export 

300class Case(SequentialCase): 

301 def __init__(self, choices: Iterable[SequentialChoice], statements: Nullable[Iterable[SequentialStatement]] = None, parent: ModelEntity = None) -> None: 

302 super().__init__(statements, parent) 

303 

304 self._choices = [] 

305 if choices is not None: 

306 for choice in choices: 

307 self._choices.append(choice) 

308 choice._parent = self 

309 

310 @property 

311 def Choices(self) -> List[SequentialChoice]: 

312 return self._choices 

313 

314 def __str__(self) -> str: 

315 return "when {choices} =>".format(choices=" | ".join(str(c) for c in self._choices)) 

316 

317 

318@export 

319class OthersCase(SequentialCase): 

320 def __str__(self) -> str: 

321 return "when others =>" 

322 

323 

324@export 

325class CaseStatement(CompoundStatement): 

326 _expression: ExpressionUnion 

327 _cases: List[SequentialCase] 

328 

329 def __init__(self, expression: ExpressionUnion, cases: Iterable[SequentialCase], label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

330 super().__init__(label, parent) 

331 

332 self._expression = expression 

333 expression._parent = self 

334 

335 self._cases = [] 

336 if cases is not None: 

337 for case in cases: 

338 self._cases.append(case) 

339 case._parent = self 

340 

341 @property 

342 def SelectExpression(self) -> ExpressionUnion: 

343 return self._expression 

344 

345 @property 

346 def Cases(self) -> List[SequentialCase]: 

347 return self._cases 

348 

349 

350@export 

351class LoopStatement(CompoundStatement, SequentialStatementsMixin): 

352 """A ``LoopStatement`` is a base-class for all loop statements.""" 

353 

354 def __init__(self, statements: Nullable[Iterable[SequentialStatement]] = None, label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

355 super().__init__(label, parent) 

356 SequentialStatementsMixin.__init__(self, statements) 

357 

358 

359@export 

360class EndlessLoopStatement(LoopStatement): 

361 pass 

362 

363 

364@export 

365class ForLoopStatement(LoopStatement): 

366 _loopIndex: str 

367 _range: Range 

368 

369 def __init__(self, loopIndex: str, rng: Range, statements: Nullable[Iterable[SequentialStatement]] = None, label: Nullable[str] = None, parent: ModelEntity = None) -> None: 

370 super().__init__(statements, label, parent) 

371 

372 self._loopIndex = loopIndex 

373 

374 self._range = rng 

375 rng._parent = self 

376 

377 @property 

378 def LoopIndex(self) -> str: 

379 return self._loopIndex 

380 

381 @property 

382 def Range(self) -> Range: 

383 return self._range 

384 

385 

386@export 

387class WhileLoopStatement(LoopStatement, ConditionalMixin): 

388 def __init__( 

389 self, 

390 condition: ExpressionUnion, 

391 statements: Nullable[Iterable[SequentialStatement]] = None, 

392 label: Nullable[str] = None, 

393 parent: ModelEntity = None 

394 ) -> None: 

395 super().__init__(statements, label, parent) 

396 ConditionalMixin.__init__(self, condition) 

397 

398 

399@export 

400class LoopControlStatement(SequentialStatement, ConditionalMixin): 

401 """A ``LoopControlStatement`` is a base-class for all loop controlling statements.""" 

402 

403 _loopReference: LoopStatement 

404 

405 def __init__(self, condition: Nullable[ExpressionUnion] = None, loopLabel: Nullable[str] = None, parent: ModelEntity = None) -> None: # TODO: is this label (currently str) a Name or a Label class? 

406 super().__init__(parent) 

407 ConditionalMixin.__init__(self, condition) 

408 

409 # TODO: loopLabel 

410 # TODO: loop reference -> is it a symbol? 

411 

412 @property 

413 def LoopReference(self) -> LoopStatement: 

414 return self._loopReference 

415 

416 

417@export 

418class NextStatement(LoopControlStatement): 

419 pass 

420 

421 

422@export 

423class ExitStatement(LoopControlStatement): 

424 pass 

425 

426 

427@export 

428class NullStatement(SequentialStatement): 

429 pass 

430 

431 

432@export 

433class ReturnStatement(SequentialStatement, ConditionalMixin): 

434 _returnValue: ExpressionUnion 

435 

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

437 super().__init__(parent) 

438 ConditionalMixin.__init__(self, returnValue) 

439 

440 # TODO: return value? 

441 

442 @property 

443 def ReturnValue(self) -> ExpressionUnion: 

444 return self._returnValue 

445 

446 

447@export 

448class WaitStatement(SequentialStatement, ConditionalMixin): 

449 _sensitivityList: Nullable[List[Symbol]] 

450 _timeout: ExpressionUnion 

451 

452 def __init__( 

453 self, 

454 sensitivityList: Nullable[Iterable[Symbol]] = None, 

455 condition: Nullable[ExpressionUnion] = None, 

456 timeout: Nullable[ExpressionUnion] = None, 

457 label: Nullable[str] = None, 

458 parent: ModelEntity = None 

459 ) -> None: 

460 super().__init__(label, parent) 

461 ConditionalMixin.__init__(self, condition) 

462 

463 if sensitivityList is None: 

464 self._sensitivityList = None 

465 else: 

466 self._sensitivityList = [] # TODO: convert to dict 

467 for signalSymbol in sensitivityList: 

468 self._sensitivityList.append(signalSymbol) 

469 signalSymbol._parent = self 

470 

471 self._timeout = timeout 

472 if timeout is not None: 

473 timeout._parent = self 

474 

475 @property 

476 def SensitivityList(self) -> List[Symbol]: 

477 return self._sensitivityList 

478 

479 @property 

480 def Timeout(self) -> ExpressionUnion: 

481 return self._timeout 

482 

483 

484@export 

485class SequentialDeclarationsMixin(metaclass=ExtendedType, mixin=True): 

486 _declaredItems: List 

487 

488 def __init__(self, declaredItems: Iterable) -> None: 

489 # TODO: extract to mixin 

490 self._declaredItems = [] # TODO: convert to dict 

491 if declaredItems is not None: 

492 for item in declaredItems: 

493 self._declaredItems.append(item) 

494 item._parent = self 

495 

496 @property 

497 def DeclaredItems(self) -> List: 

498 return self._declaredItems