Coverage for pyVHDLModel/Subprogram.py: 97%

92 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 

35Subprograms are procedures, functions and methods. 

36""" 

37from typing import ClassVar, List, Iterable, Optional as Nullable 

38 

39from pyTooling.Decorators import export, readonly 

40from pyTooling.MetaClasses import ExtendedType 

41 

42from pyVHDLModel.Base import ModelEntity, NamedEntityMixin, DocumentedEntityMixin, identifiersOf 

43from pyVHDLModel.Symbol import SubtypeSymbol 

44from pyVHDLModel.Type import ProtectedType 

45from pyVHDLModel.Regions import ConcurrentDeclarationRegionMixin, SequentialDeclarationRegionMixin 

46from pyVHDLModel.Regions import ProtectedTypeDeclarationRegionMixin 

47from pyVHDLModel.Sequential import SequentialStatement 

48 

49 

50@export 

51class Subprogram(ModelEntity, NamedEntityMixin, DocumentedEntityMixin, SequentialDeclarationRegionMixin): 

52 """ 

53 Represents the base-class of all subprograms: procedures and functions. 

54 

55 A subprogram is a named entity (:data:`Identifier`) with an optional generic clause 

56 (:data:`GenericItems`), a parameter list (:data:`ParameterItems`), its own declarative part 

57 (:data:`DeclaredItems`) and a sequence of statements (:data:`Statements`). 

58 

59 .. seealso:: 

60 

61 * :class:`Procedure <pyVHDLModel.Subprogram.Procedure>` 

62 * :class:`Function <pyVHDLModel.Subprogram.Function>` 

63 """ 

64 _subprogramKeyword: ClassVar[str] = "subprogram" #: The VHDL keyword introducing this subprogram kind. 

65 

66 _genericItems: List['GenericInterfaceItemMixin'] #: List of all generics, in declaration order. 

67 _parameterItems: List['ParameterInterfaceItemMixin'] #: List of all parameters, in declaration order. 

68 _statements: List[SequentialStatement] #: List of all sequential statements in the subprogram's body. 

69 _isPure: bool #: ``True`` if the subprogram was declared pure. 

70 

71 def __init__( 

72 self, 

73 identifier: str, 

74 isPure: bool, 

75 genericItems: Nullable[Iterable['GenericInterfaceItemMixin']] = None, 

76 parameterItems: Nullable[Iterable['ParameterInterfaceItemMixin']] = None, 

77 declaredItems: Nullable[Iterable] = None, 

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

79 documentation: Nullable[str] = None, 

80 parent: Nullable[ModelEntity] = None 

81 ) -> None: 

82 """ 

83 Initializes a subprogram. 

84 

85 :param identifier: The identifier of a model entity. 

86 :param isPure: ``True`` if the subprogram was declared pure. 

87 :param genericItems: List of all generics, in declaration order. 

88 :param parameterItems: List of all parameters, in declaration order. 

89 :param declaredItems: List of all declared items in this sequential declaration region. 

90 :param statements: List of all sequential statements in the subprogram's body. 

91 :param documentation: The documentation comment associated with this declaration. 

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

93 """ 

94 super().__init__(parent) 

95 NamedEntityMixin.__init__(self, identifier) 

96 DocumentedEntityMixin.__init__(self, documentation) 

97 SequentialDeclarationRegionMixin.__init__(self, self._normalizedIdentifier, declaredItems) 

98 

99 self._genericItems = [] # TODO: convert to dict 

100 if genericItems is not None: 

101 for item in genericItems: 

102 self._genericItems.append(item) 

103 item.Parent = self 

104 

105 self._parameterItems = [] # TODO: convert to dict 

106 if parameterItems is not None: 

107 for item in parameterItems: 

108 self._parameterItems.append(item) 

109 item.Parent = self 

110 

111 self._statements = [] # TODO: use mixin class 

112 if statements is not None: 

113 for item in statements: 

114 self._statements.append(item) 

115 item.Parent = self 

116 

117 self._isPure = isPure 

118 

119 @ModelEntity.Parent.setter 

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

121 ModelEntity.Parent.fset(self, parent) 

122 

123 # Connect the subprogram's namespace to the enclosing declaration region's namespace, so a 

124 # declaration inside the subprogram hides a same-named one from the scope around it. Protected 

125 # types and their bodies are declaration regions too, so a method chains like any other 

126 # subprogram; the check remains because a parent need not be a region at all. 

127 regions = (ConcurrentDeclarationRegionMixin, SequentialDeclarationRegionMixin, ProtectedTypeDeclarationRegionMixin) 

128 if isinstance(parent, regions): 128 ↛ exitline 128 didn't return from function 'Parent' because the condition on line 128 was always true

129 self._namespace.ParentNamespace = parent._namespace 

130 

131 @readonly 

132 def GenericItems(self) -> List['GenericInterfaceItemMixin']: 

133 """ 

134 Read-only property to access the generic items (:attr:`_genericItems`). 

135 

136 :returns: List of generic items. 

137 """ 

138 return self._genericItems 

139 

140 @readonly 

141 def ParameterItems(self) -> List['ParameterInterfaceItemMixin']: 

142 """ 

143 Read-only property to access the parameter items (:attr:`_parameterItems`). 

144 

145 :returns: List of parameter items. 

146 """ 

147 return self._parameterItems 

148 

149 @readonly 

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

151 """ 

152 Read-only property to access the statements (:attr:`_statements`). 

153 

154 :returns: List of statements. 

155 """ 

156 return self._statements 

157 

158 @readonly 

159 def IsPure(self) -> bool: 

160 """ 

161 Check if the subprogram is pure (:attr:`_isPure`). 

162 

163 :returns: ``True``, if the subprogram is pure. 

164 """ 

165 return self._isPure 

166 

167 

168 def IndexDeclaredItems(self) -> None: 

169 """A subprogram's generics and parameters share the declarative region of its declarative part.""" 

170 self._IndexGenericItems() 

171 self._IndexParameterItems() 

172 

173 super().IndexDeclaredItems() 

174 

175 def __str__(self) -> str: 

176 """ 

177 Formats the subprogram declaration. 

178 

179 **Format:** ``procedure myProcedure(a, b)`` 

180 

181 :returns: Formatted subprogram declaration. 

182 """ 

183 parameters = ", ".join(name for item in self._parameterItems for name in identifiersOf(item)) 

184 return f"{self._subprogramKeyword} {self._identifier}({parameters})" 

185 

186 

187@export 

188class Procedure(Subprogram): 

189 """ 

190 Represents a procedure. 

191 

192 Unlike a function, a procedure returns no value. Besides its parameters, it has its own 

193 declarative part (:data:`DeclaredItems`) and statements (:data:`Statements`). 

194 

195 .. admonition:: Example 

196 

197 .. code-block:: VHDL 

198 

199 procedure proc(signal s : in bit; variable v : out bit) is 

200 -- ^^^^ <- Identifier 

201 -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- ParameterItems 

202 variable tmp : bit; 

203 --^^^^^^^^^^^^^^^^^^^ <- DeclaredItems 

204 begin 

205 tmp := s; 

206 --^^^^^^^^^ <- Statements 

207 v := tmp; 

208 end procedure; 

209 

210 .. seealso:: 

211 

212 * :class:`Procedure instantiation <pyVHDLModel.Instantiation.ProcedureInstantiation>` 

213 * :class:`Generic procedure interface item <pyVHDLModel.Interface.GenericProcedureInterfaceItem>` 

214 * :class:`Procedure method <pyVHDLModel.Subprogram.ProcedureMethod>` 

215 * :class:`Function <pyVHDLModel.Subprogram.Function>` 

216 """ 

217 

218 _subprogramKeyword: ClassVar[str] = "procedure" 

219 def __init__( 

220 self, 

221 identifier: str, 

222 genericItems: Nullable[Iterable['GenericInterfaceItemMixin']] = None, 

223 parameterItems: Nullable[Iterable['ParameterInterfaceItemMixin']] = None, 

224 declaredItems: Nullable[Iterable] = None, 

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

226 documentation: Nullable[str] = None, 

227 parent: Nullable[ModelEntity] = None 

228 ) -> None: 

229 """ 

230 Initializes a procedure. 

231 

232 :param identifier: The identifier of a model entity. 

233 :param genericItems: List of all generics, in declaration order. 

234 :param parameterItems: List of all parameters, in declaration order. 

235 :param declaredItems: List of all declared items in this sequential declaration region. 

236 :param statements: List of all sequential statements in the subprogram's body. 

237 :param documentation: The documentation comment associated with this declaration. 

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

239 """ 

240 super().__init__(identifier, False, genericItems, parameterItems, declaredItems, statements, documentation, parent) 

241 

242 

243@export 

244class Function(Subprogram): 

245 """ 

246 Represents a function. 

247 

248 A function returns a value of its return type (:data:`ReturnType`) and is either pure or impure 

249 (:data:`IsPure`). Besides its parameters, it has its own declarative part (:data:`DeclaredItems`) 

250 and statements (:data:`Statements`). 

251 

252 .. admonition:: Example 

253 

254 .. code-block:: VHDL 

255 

256 function fun(constant c : in positive) return integer is 

257 -- ^^^ <- Identifier 

258 -- ^^^^^^^^^^^^^^^^^^^^^^^^ <- ParameterItems 

259 -- ^^^^^^^ <- ReturnType 

260 variable tmp : integer; 

261 --^^^^^^^^^^^^^^^^^^^^^^^ <- DeclaredItems 

262 begin 

263 tmp := c; 

264 --^^^^^^^^^ <- Statements 

265 return tmp; 

266 end function; 

267 

268 .. seealso:: 

269 

270 * :class:`Function instantiation <pyVHDLModel.Instantiation.FunctionInstantiation>` 

271 * :class:`Generic function interface item <pyVHDLModel.Interface.GenericFunctionInterfaceItem>` 

272 * :class:`Function method <pyVHDLModel.Subprogram.FunctionMethod>` 

273 * :class:`Procedure <pyVHDLModel.Subprogram.Procedure>` 

274 """ 

275 

276 _subprogramKeyword: ClassVar[str] = "function" 

277 _returnType: SubtypeSymbol #: Reference to the subtype of the function's return value. 

278 

279 def __init__( 

280 self, 

281 identifier: str, 

282 returnType: SubtypeSymbol, 

283 isPure: bool = True, 

284 genericItems: Nullable[Iterable['GenericInterfaceItemMixin']] = None, 

285 parameterItems: Nullable[Iterable['ParameterInterfaceItemMixin']] = None, 

286 declaredItems: Nullable[Iterable] = None, 

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

288 documentation: Nullable[str] = None, 

289 parent: Nullable[ModelEntity] = None 

290 ) -> None: 

291 """ 

292 Initializes a function. 

293 

294 :param identifier: The identifier of a model entity. 

295 :param returnType: Reference to the subtype of the function's return value. 

296 :param isPure: ``True`` if the subprogram was declared pure. 

297 :param genericItems: List of all generics, in declaration order. 

298 :param parameterItems: List of all parameters, in declaration order. 

299 :param declaredItems: List of all declared items in this sequential declaration region. 

300 :param statements: List of all sequential statements in the subprogram's body. 

301 :param documentation: The documentation comment associated with this declaration. 

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

303 """ 

304 super().__init__(identifier, isPure, genericItems, parameterItems, declaredItems, statements, documentation, parent) 

305 

306 self._returnType = returnType 

307 returnType.Parent = self 

308 

309 @readonly 

310 def ReturnType(self) -> SubtypeSymbol: 

311 """ 

312 Read-only property to access the return type (:attr:`_returnType`). 

313 

314 :returns: The return type. 

315 """ 

316 return self._returnType 

317 

318 

319@export 

320class MethodMixin(metaclass=ExtendedType, mixin=True): 

321 """ 

322 A ``Method`` is a mixin class for all subprograms in a protected type. 

323 

324 .. seealso:: 

325 

326 * :class:`Procedure method <pyVHDLModel.Subprogram.ProcedureMethod>` 

327 * :class:`Function method <pyVHDLModel.Subprogram.FunctionMethod>` 

328 """ 

329 

330 _protectedType: ProtectedType #: Reference to the protected type this method belongs to. 

331 

332 def __init__(self, protectedType: Nullable[ProtectedType] = None) -> None: 

333 """ 

334 Initializes a method. 

335 

336 :param protectedType: Reference to the protected type this method belongs to. 

337 """ 

338 self._protectedType = protectedType 

339 if protectedType is not None: 

340 protectedType.Parent = self 

341 

342 @readonly 

343 def ProtectedType(self) -> ProtectedType: 

344 """ 

345 Read-only property to access the protected type (:attr:`_protectedType`). 

346 

347 :returns: The protected type. 

348 """ 

349 return self._protectedType 

350 

351 

352@export 

353class ProcedureMethod(Procedure, MethodMixin): 

354 """ 

355 Represents a procedure declared as a method of a protected type. 

356 

357 The protected type is available as :data:`ProtectedType`. 

358 

359 .. seealso:: 

360 

361 * :class:`Protected type <pyVHDLModel.Type.ProtectedType>` 

362 """ 

363 def __init__( 

364 self, 

365 identifier: str, 

366 genericItems: Nullable[Iterable['GenericInterfaceItemMixin']] = None, 

367 parameterItems: Nullable[Iterable['ParameterInterfaceItemMixin']] = None, 

368 declaredItems: Nullable[Iterable] = None, 

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

370 documentation: Nullable[str] = None, 

371 protectedType: Nullable[ProtectedType] = None, 

372 parent: Nullable[ModelEntity] = None 

373 ) -> None: 

374 """ 

375 Initializes a procedure declared as a method of a protected type. 

376 

377 :param identifier: The identifier of a model entity. 

378 :param genericItems: List of all generics, in declaration order. 

379 :param parameterItems: List of all parameters, in declaration order. 

380 :param declaredItems: List of all declared items in this sequential declaration region. 

381 :param statements: List of all sequential statements in the subprogram's body. 

382 :param documentation: The documentation comment associated with this declaration. 

383 :param protectedType: Reference to the protected type this method belongs to. 

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

385 """ 

386 super().__init__(identifier, genericItems, parameterItems, declaredItems, statements, documentation, parent) 

387 MethodMixin.__init__(self, protectedType) 

388 

389 

390@export 

391class FunctionMethod(Function, MethodMixin): 

392 """ 

393 Represents a function declared as a method of a protected type. 

394 

395 The protected type is available as :data:`ProtectedType`. 

396 

397 .. seealso:: 

398 

399 * :class:`Protected type <pyVHDLModel.Type.ProtectedType>` 

400 """ 

401 def __init__( 

402 self, 

403 identifier: str, 

404 returnType: SubtypeSymbol, 

405 isPure: bool = True, 

406 genericItems: Nullable[Iterable['GenericInterfaceItemMixin']] = None, 

407 parameterItems: Nullable[Iterable['ParameterInterfaceItemMixin']] = None, 

408 declaredItems: Nullable[Iterable] = None, 

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

410 documentation: Nullable[str] = None, 

411 protectedType: Nullable[ProtectedType] = None, 

412 parent: Nullable[ModelEntity] = None 

413 ) -> None: 

414 """ 

415 Initializes a function declared as a method of a protected type. 

416 

417 :param identifier: The identifier of a model entity. 

418 :param returnType: Reference to the subtype of the function's return value. 

419 :param isPure: ``True`` if the subprogram was declared pure. 

420 :param genericItems: List of all generics, in declaration order. 

421 :param parameterItems: List of all parameters, in declaration order. 

422 :param declaredItems: List of all declared items in this sequential declaration region. 

423 :param statements: List of all sequential statements in the subprogram's body. 

424 :param documentation: The documentation comment associated with this declaration. 

425 :param protectedType: Reference to the protected type this method belongs to. 

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

427 """ 

428 super().__init__(identifier, returnType, isPure, genericItems, parameterItems, declaredItems, statements, documentation, parent) 

429 MethodMixin.__init__(self, protectedType)