Coverage for pyVHDLModel/Base.py: 77%

178 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-10 23:46 +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 

35Base-classes for the VHDL language model. 

36""" 

37from enum import unique, Enum 

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

39 

40from pyTooling.Decorators import export, readonly 

41from pyTooling.MetaClasses import ExtendedType 

42 

43 

44__all__ = ["ExpressionUnion"] 

45 

46 

47ExpressionUnion = Union[ 

48 'BaseExpression', 

49 'QualifiedExpression', 

50 'FunctionCall', 

51 'TypeConversion', 

52 # ConstantOrSymbol, TODO: ObjectSymbol 

53 'Literal', 

54] 

55 

56 

57@export 

58@unique 

59class Direction(Enum): 

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

61 

62 To = 0 #: Ascending direction 

63 DownTo = 1 #: Descending direction 

64 

65 def __str__(self) -> str: 

66 """ 

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

68 

69 :returns: Formatted direction. 

70 """ 

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

72 

73 

74@export 

75@unique 

76class Mode(Enum): 

77 """ 

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

79 generic, port or parameter lists. 

80 

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

82 """ 

83 

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

85 In = 1 #: Input 

86 Out = 2 #: Output 

87 InOut = 3 #: Bi-directional 

88 Buffer = 4 #: Buffered output 

89 Linkage = 5 #: undocumented 

90 

91 def __str__(self) -> str: 

92 """ 

93 Formats the direction. 

94 

95 :returns: Formatted direction. 

96 """ 

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

98 

99 

100@export 

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

102 """ 

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

104 inheritance) and enumerations. 

105 

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

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

108 """ 

109 

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

111 

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

113 """ 

114 Initializes a VHDL model entity. 

115 

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

117 """ 

118 self._parent = parent 

119 

120 @readonly 

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

122 """ 

123 Read-only property to access the model entity's parent element reference in a logical hierarchy (:attr:`_parent`). 

124 

125 :returns: Reference to the parent entity. 

126 """ 

127 return self._parent 

128 

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

130 parent = self._parent 

131 while not isinstance(parent, type): 

132 parent = parent._parent 

133 

134 return parent 

135 

136 

137@export 

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

139 """ 

140 A ``NamedEntityMixin`` is a mixin class for all VHDL entities that have identifiers. 

141 

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

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

144 """ 

145 

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

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

148 

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

150 """ 

151 Initializes a named entity. 

152 

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

154 """ 

155 self._identifier = identifier 

156 self._normalizedIdentifier = identifier.lower() 

157 

158 @readonly 

159 def Identifier(self) -> str: 

160 """ 

161 Returns a model entity's identifier (name). 

162 

163 :returns: Name of a model entity. 

164 """ 

165 return self._identifier 

166 

167 @readonly 

168 def NormalizedIdentifier(self) -> str: 

169 """ 

170 Returns a model entity's normalized identifier (lower case name). 

171 

172 :returns: Normalized name of a model entity. 

173 """ 

174 return self._normalizedIdentifier 

175 

176 

177@export 

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

179 """ 

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

181 defining multiple identifiers. 

182 

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

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

185 """ 

186 

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

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

189 

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

191 """ 

192 Initializes a multiple-named entity. 

193 

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

195 """ 

196 self._identifiers = tuple(identifiers) 

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

198 

199 @readonly 

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

201 """ 

202 Returns a model entity's tuple of identifiers (names). 

203 

204 :returns: Tuple of identifiers. 

205 """ 

206 return self._identifiers 

207 

208 @readonly 

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

210 """ 

211 Returns a model entity's tuple of normalized identifiers (lower case names). 

212 

213 :returns: Tuple of normalized identifiers. 

214 """ 

215 return self._normalizedIdentifiers 

216 

217 

218@export 

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

220 """ 

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

222 

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

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

225 """ 

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

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

228 

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

230 """ 

231 Initializes a labeled entity. 

232 

233 :param label: Label of the model entity. 

234 """ 

235 self._label = label 

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

237 

238 @readonly 

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

240 """ 

241 Returns a model entity's label. 

242 

243 :returns: Label of a model entity. 

244 """ 

245 return self._label 

246 

247 @readonly 

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

249 """ 

250 Returns a model entity's normalized (lower case) label. 

251 

252 :returns: Normalized label of a model entity. 

253 """ 

254 return self._normalizedLabel 

255 

256 

257@export 

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

259 """ 

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

261 

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

263 :attr:`Documentation` for public access. 

264 """ 

265 

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

267 

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

269 """ 

270 Initializes a documented entity. 

271 

272 :param documentation: Documentation of a model entity. 

273 """ 

274 self._documentation = documentation 

275 

276 @readonly 

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

278 """ 

279 Returns a model entity's associated documentation. 

280 

281 :returns: Associated documentation of a model entity. 

282 """ 

283 return self._documentation 

284 

285 

286@export 

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

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

289 

290 _condition: ExpressionUnion 

291 

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

293 """ 

294 Initializes a statement with a condition. 

295 

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

297 

298 :param condition: The expression representing the condition. 

299 """ 

300 self._condition = condition 

301 if condition is not None: 

302 condition._parent = self 

303 

304 @readonly 

305 def Condition(self) -> ExpressionUnion: 

306 """ 

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

308 

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

310 """ 

311 return self._condition 

312 

313 

314@export 

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

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

317 

318 def __init__(self) -> None: 

319 pass 

320 

321 

322@export 

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

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

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

326 super().__init__() 

327 ConditionalMixin.__init__(self, condition) 

328 

329 

330@export 

331class IfBranchMixin(ConditionalBranchMixin, mixin=True): 

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

333 

334 

335@export 

336class ElsifBranchMixin(ConditionalBranchMixin, mixin=True): 

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

338 

339 

340@export 

341class ElseBranchMixin(BranchMixin, mixin=True): 

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

343 

344 

345@export 

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

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

348 

349 _message: Nullable[ExpressionUnion] 

350 _severity: Nullable[ExpressionUnion] 

351 

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

353 self._message = message 

354 if message is not None: 

355 message._parent = self 

356 

357 self._severity = severity 

358 if severity is not None: 

359 severity._parent = self 

360 

361 @property 

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

363 return self._message 

364 

365 @property 

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

367 return self._severity 

368 

369 

370@export 

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

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

373 

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

375 super().__init__(message, severity) 

376 ConditionalMixin.__init__(self, condition) 

377 

378 

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

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

381 

382 def __init__(self) -> None: 

383 pass 

384 

385 

386@export 

387class BaseChoice(ModelEntity): 

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

389 

390 

391@export 

392class BaseCase(ModelEntity): 

393 """ 

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

395 """ 

396 

397 

398@export 

399class Range(ModelEntity): 

400 _leftBound: ExpressionUnion 

401 _rightBound: ExpressionUnion 

402 _direction: Direction 

403 

404 def __init__(self, leftBound: ExpressionUnion, rightBound: ExpressionUnion, direction: Direction, parent: ModelEntity = None) -> None: 

405 super().__init__(parent) 

406 

407 self._leftBound = leftBound 

408 leftBound._parent = self 

409 

410 self._rightBound = rightBound 

411 rightBound._parent = self 

412 

413 self._direction = direction 

414 

415 @property 

416 def LeftBound(self) -> ExpressionUnion: 

417 return self._leftBound 

418 

419 @property 

420 def RightBound(self) -> ExpressionUnion: 

421 return self._rightBound 

422 

423 @property 

424 def Direction(self) -> Direction: 

425 return self._direction 

426 

427 def __str__(self) -> str: 

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

429 

430 

431@export 

432class WaveformElement(ModelEntity): 

433 _expression: ExpressionUnion 

434 _after: ExpressionUnion 

435 

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

437 super().__init__(parent) 

438 

439 self._expression = expression 

440 expression._parent = self 

441 

442 self._after = after 

443 if after is not None: 

444 after._parent = self 

445 

446 @property 

447 def Expression(self) -> ExpressionUnion: 

448 return self._expression 

449 

450 @property 

451 def After(self) -> Expression: 

452 return self._after