pyVHDLModelTreesitter 0.2.2__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. pyvhdlmodeltreesitter-0.3.1/PKG-INFO +93 -0
  2. pyvhdlmodeltreesitter-0.3.1/README.md +61 -0
  3. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/pyproject.toml +4 -6
  4. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/Base.py +163 -0
  5. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/DesignUnit.py +38 -57
  6. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/Expression.py +347 -0
  7. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/Interface.py +55 -109
  8. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/Name.py +24 -3
  9. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/Symbol.py +162 -0
  10. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/_Design.py +57 -0
  11. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/_Document.py +124 -0
  12. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/_Library.py +50 -0
  13. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/__init__.py +38 -0
  14. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/_errors.py +85 -0
  15. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/treesitter/__init__.py +6 -0
  16. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/_base_class.py +22 -0
  17. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/_utils.py +67 -0
  18. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/adding_expression.scm +5 -0
  19. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/constrained_1d_array.scm +27 -0
  20. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/design_units.scm +3 -0
  21. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/interface_declaration.scm +24 -0
  22. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/interface_declarations.scm +4 -0
  23. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/library_clauses.scm +1 -0
  24. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/library_namespaces.scm +6 -0
  25. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/selected_names.scm +1 -0
  26. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/simple_subtype.scm +11 -0
  27. pyvhdlmodeltreesitter-0.3.1/src/pyVHDLModelTreesitter/treesitter/queries/use_clauses.scm +1 -0
  28. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/treesitter/query.py +13 -1
  29. pyvhdlmodeltreesitter-0.2.2/PKG-INFO +0 -38
  30. pyvhdlmodeltreesitter-0.2.2/README.md +0 -4
  31. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/Base.py +0 -31
  32. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/Expression.py +0 -82
  33. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/Symbol.py +0 -64
  34. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/__init__.py +0 -24
  35. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/_error.py +0 -44
  36. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/_root.py +0 -223
  37. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/_utils.py +0 -52
  38. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/design_units.scm +0 -3
  39. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/interface_declaration.scm +0 -11
  40. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/interface_declarations.scm +0 -1
  41. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/library_clauses.scm +0 -1
  42. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/library_namespaces.scm +0 -1
  43. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/selected_names.scm +0 -1
  44. pyvhdlmodeltreesitter-0.2.2/src/pyVHDLModelTreesitter/treesitter/queries/use_clauses.scm +0 -1
  45. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/.gitignore +0 -0
  46. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/LICENSE +0 -0
  47. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/py.typed +0 -0
  48. {pyvhdlmodeltreesitter-0.2.2 → pyvhdlmodeltreesitter-0.3.1}/src/pyVHDLModelTreesitter/treesitter/queries/entity_declaration.scm +0 -0
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyVHDLModelTreesitter
3
+ Version: 0.3.1
4
+ Summary: An implementation of pyVHDLModel using treesitter
5
+ Project-URL: Repository, https://gitlab.com/dawalters/pyVHDLModelTreesitter
6
+ Author: Dominic Adam Walters
7
+ License-File: LICENSE
8
+ Keywords: language,model,treesitter,vhdl
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: pyvhdlmodel>=0.32.0
19
+ Requires-Dist: tree-sitter-vhdl>=1.2.5
20
+ Requires-Dist: tree-sitter>=0.23.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: coverage==7.13.5; extra == 'dev'
23
+ Requires-Dist: hatch==1.16.5; extra == 'dev'
24
+ Requires-Dist: mypy==1.20.1; extra == 'dev'
25
+ Requires-Dist: pre-commit==4.5.1; extra == 'dev'
26
+ Requires-Dist: pytest-cov==7.1.0; extra == 'dev'
27
+ Requires-Dist: pytest-sugar==1.1.1; extra == 'dev'
28
+ Requires-Dist: pytest-xdist==3.8.0; extra == 'dev'
29
+ Requires-Dist: pytest==9.0.3; extra == 'dev'
30
+ Requires-Dist: ruff==0.15.10; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # pyVHDLModelTreesitter
34
+ [![Version][shield-version]][pyVHDLModelTreesitter-pypi]
35
+ [![Releases][shield-releases]][pyVHDLModelTreesitter-releases]
36
+ [![Gitlab][shield-pipeline]][pyVHDLModelTreesitter-pipeline]
37
+ [![pre-commit][shield-precommit]][precommit-github]
38
+ [![Codecov][shield-codecov]][pyVHDLModelTreesitter-codecov]
39
+ [![Python Version][shield-python-version]][pyVHDLModelTreesitter-pypi]
40
+
41
+ `pyVHDLModelTreesitter` is an implementation of the
42
+ [`pyVHDLModel`][pyVHDLModel-github] API using `tree-sitter-vhdl`.
43
+
44
+ > Disclaimer: This project is in early development and only implements a
45
+ fraction of the features of [`pyVHDLModel`][pyVHDLModel-github].
46
+
47
+ ## Dependencies
48
+
49
+ - Python 3.10 or newer.
50
+
51
+ ## Installation
52
+
53
+ ### `pip`
54
+
55
+ You can install the latest release from [PyPI][pyVHDLModelTreesitter-pypi]:
56
+
57
+ ```bash
58
+ pip install pyVHDLModelTreesitter
59
+ ```
60
+
61
+ ### Source tarball
62
+
63
+ You can download source releases from the
64
+ [Gitlab Releases page][pyVHDLModelTreesitter-releases].
65
+
66
+ ## Documentation
67
+
68
+ In the simplest cases where you just want to parse a VHDL file:
69
+
70
+ ```python3
71
+ import pyVHDLModelTreesitter
72
+
73
+ document = pyVHDLModelTreesitter.Document.from_file("path/to/file.vhd")
74
+ ```
75
+
76
+ `pyVHDLModelTreesitter.Document` is a subclass of
77
+ [`pyVHDLModel.Document`][pyVHDLModel-Document].
78
+
79
+ Detailed documentation is currently unavailable.
80
+
81
+ [precommit-github]: https://github.com/pre-commit/pre-commit
82
+ [pyVHDLModel-Document]: https://vhdl.github.io/pyVHDLModel/pyVHDLModel/pyVHDLModel.html#pyVHDLModel.Document
83
+ [pyVHDLModel-github]: https://github.com/VHDL/pyVHDLModel
84
+ [pyVHDLModelTreesitter-codecov]: https://codecov.io/gitlab/dawalters/pyVHDLModelTreesitter
85
+ [pyVHDLModelTreesitter-pipeline]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/-/pipelines?page=1&scope=all&ref=develop
86
+ [pyVHDLModelTreesitter-pypi]: https://pypi.org/project/pyVHDLModelTreesitter
87
+ [pyVHDLModelTreesitter-releases]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/-/releases
88
+ [shield-codecov]: https://codecov.io/gitlab/dawalters/pyVHDLModelTreesitter/branch/develop/graph/badge.svg
89
+ [shield-pipeline]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/badges/develop/pipeline.svg
90
+ [shield-precommit]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit
91
+ [shield-python-version]: https://img.shields.io/pypi/pyversions/pyVHDLModelTreesitter
92
+ [shield-releases]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/-/badges/release.svg
93
+ [shield-version]: https://img.shields.io/pypi/v/pyVHDLModelTreesitter
@@ -0,0 +1,61 @@
1
+ # pyVHDLModelTreesitter
2
+ [![Version][shield-version]][pyVHDLModelTreesitter-pypi]
3
+ [![Releases][shield-releases]][pyVHDLModelTreesitter-releases]
4
+ [![Gitlab][shield-pipeline]][pyVHDLModelTreesitter-pipeline]
5
+ [![pre-commit][shield-precommit]][precommit-github]
6
+ [![Codecov][shield-codecov]][pyVHDLModelTreesitter-codecov]
7
+ [![Python Version][shield-python-version]][pyVHDLModelTreesitter-pypi]
8
+
9
+ `pyVHDLModelTreesitter` is an implementation of the
10
+ [`pyVHDLModel`][pyVHDLModel-github] API using `tree-sitter-vhdl`.
11
+
12
+ > Disclaimer: This project is in early development and only implements a
13
+ fraction of the features of [`pyVHDLModel`][pyVHDLModel-github].
14
+
15
+ ## Dependencies
16
+
17
+ - Python 3.10 or newer.
18
+
19
+ ## Installation
20
+
21
+ ### `pip`
22
+
23
+ You can install the latest release from [PyPI][pyVHDLModelTreesitter-pypi]:
24
+
25
+ ```bash
26
+ pip install pyVHDLModelTreesitter
27
+ ```
28
+
29
+ ### Source tarball
30
+
31
+ You can download source releases from the
32
+ [Gitlab Releases page][pyVHDLModelTreesitter-releases].
33
+
34
+ ## Documentation
35
+
36
+ In the simplest cases where you just want to parse a VHDL file:
37
+
38
+ ```python3
39
+ import pyVHDLModelTreesitter
40
+
41
+ document = pyVHDLModelTreesitter.Document.from_file("path/to/file.vhd")
42
+ ```
43
+
44
+ `pyVHDLModelTreesitter.Document` is a subclass of
45
+ [`pyVHDLModel.Document`][pyVHDLModel-Document].
46
+
47
+ Detailed documentation is currently unavailable.
48
+
49
+ [precommit-github]: https://github.com/pre-commit/pre-commit
50
+ [pyVHDLModel-Document]: https://vhdl.github.io/pyVHDLModel/pyVHDLModel/pyVHDLModel.html#pyVHDLModel.Document
51
+ [pyVHDLModel-github]: https://github.com/VHDL/pyVHDLModel
52
+ [pyVHDLModelTreesitter-codecov]: https://codecov.io/gitlab/dawalters/pyVHDLModelTreesitter
53
+ [pyVHDLModelTreesitter-pipeline]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/-/pipelines?page=1&scope=all&ref=develop
54
+ [pyVHDLModelTreesitter-pypi]: https://pypi.org/project/pyVHDLModelTreesitter
55
+ [pyVHDLModelTreesitter-releases]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/-/releases
56
+ [shield-codecov]: https://codecov.io/gitlab/dawalters/pyVHDLModelTreesitter/branch/develop/graph/badge.svg
57
+ [shield-pipeline]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/badges/develop/pipeline.svg
58
+ [shield-precommit]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit
59
+ [shield-python-version]: https://img.shields.io/pypi/pyversions/pyVHDLModelTreesitter
60
+ [shield-releases]: https://gitlab.com/dawalters/pyVHDLModelTreesitter/-/badges/release.svg
61
+ [shield-version]: https://img.shields.io/pypi/v/pyVHDLModelTreesitter
@@ -4,15 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyVHDLModelTreesitter"
7
- version = "0.2.2"
7
+ version = "0.3.1"
8
8
  description = "An implementation of pyVHDLModel using treesitter"
9
9
  readme = "README.md"
10
- requires-python = ">=3.10"
10
+ requires-python = ">=3.11"
11
11
  dependencies = [
12
- "pyVHDLModel <= 0.31.3",
12
+ "pyVHDLModel >= 0.32.0",
13
13
  "tree-sitter >= 0.23.0",
14
14
  "tree-sitter-vhdl >= 1.2.5",
15
- "typing-extensions >= 4.0.0; python_version < '3.11'",
16
15
  ]
17
16
  authors = [
18
17
  { name = "Dominic Adam Walters" },
@@ -22,7 +21,6 @@ classifiers = [
22
21
  "Development Status :: 3 - Alpha",
23
22
  "License :: OSI Approved :: MIT License",
24
23
  "Programming Language :: Python :: 3 :: Only",
25
- "Programming Language :: Python :: 3.10",
26
24
  "Programming Language :: Python :: 3.11",
27
25
  "Programming Language :: Python :: 3.12",
28
26
  "Programming Language :: Python :: 3.13",
@@ -85,7 +83,7 @@ dependencies = [
85
83
  ]
86
84
 
87
85
  [[tool.hatch.envs.hatch-test.matrix]]
88
- python = ["3.10", "3.11", "3.12", "3.13", "3.14"]
86
+ python = ["3.11", "3.12", "3.13", "3.14"]
89
87
 
90
88
  [tool.mypy]
91
89
  strict = true
@@ -0,0 +1,163 @@
1
+ """Submodule mirroring modified aspects of pyVHDLModel.Base."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "Range",
7
+ ]
8
+
9
+ from typing import TYPE_CHECKING, Self, cast
10
+
11
+ import pyVHDLModel
12
+
13
+ if TYPE_CHECKING:
14
+ from tree_sitter import Node
15
+
16
+ from pyVHDLModelTreesitter._errors import (
17
+ NodeExtraChildError,
18
+ NodeMissingChildError,
19
+ NodeTextIsInvalidError,
20
+ NodeTextIsNoneError,
21
+ NotImplementedWarning,
22
+ )
23
+ from pyVHDLModelTreesitter.Expression import parse_simple_expression
24
+ from pyVHDLModelTreesitter.treesitter import BaseTreesitterNode
25
+
26
+
27
+ def parse_as_direction(string: str) -> pyVHDLModel.Base.Direction | None:
28
+ """
29
+ Parse a string as a direction.
30
+
31
+ This will accept any mix of the following:
32
+ - Incorrect capitalisation
33
+ - "tO"
34
+ - "To"
35
+ - Split words with whitespace
36
+ - "down to"
37
+ """
38
+ # TODO: make a PR on pyVHDLModel to add this
39
+ string = "".join(string.split()).lower().capitalize()
40
+ if string == "Downto":
41
+ string = "DownTo"
42
+ try:
43
+ return pyVHDLModel.Base.Direction[string]
44
+ except IndexError:
45
+ return None
46
+
47
+
48
+ def parse_as_mode(string: str) -> pyVHDLModel.Base.Mode | None:
49
+ """
50
+ Parse a string as a mode.
51
+
52
+ This will accept any mix of the following:
53
+ - Incorrect capitalisation
54
+ - "IN"
55
+ - "iN"
56
+ - "in"
57
+ - Split words with whitespace
58
+ - "in out"
59
+ """
60
+ # TODO: make a PR on pyVHDLModel to add this
61
+ string = "".join(string.split()).lower().capitalize()
62
+ if string == "Inout":
63
+ string = "InOut"
64
+ try:
65
+ return pyVHDLModel.Base.Mode[string]
66
+ except IndexError:
67
+ return None
68
+
69
+
70
+ class Range(BaseTreesitterNode, pyVHDLModel.Base.Range): # noqa: D101
71
+ @classmethod
72
+ def from_treesitter_node( # noqa: C901, PLR0912
73
+ cls,
74
+ node: Node,
75
+ ) -> Self | None:
76
+ """
77
+ Create a Range from a treesitter node.
78
+
79
+ Raises
80
+ ------
81
+ NodeExtraChildError:
82
+ If `node.children` does not have 2 elements.
83
+ NodeMissingChildError:
84
+ If `node.type` is not `simple_range`.
85
+ NodeTextIsInvalidError:
86
+ If the direction in `node` could not be parsed.
87
+ NodeTextIsNoneError:
88
+ If `node` or any relevant subnode doesn't define `text`.
89
+
90
+ """
91
+ if node.type != "simple_range":
92
+ raise NodeMissingChildError(node, "simple_range")
93
+ if node.text is None or len(node.text) == 0:
94
+ raise NodeTextIsNoneError(node)
95
+ if len(node.children) != 3: # noqa: PLR2004
96
+ raise NodeExtraChildError(node, "all children", 3)
97
+ left = node.child(0)
98
+ if left is None:
99
+ raise NodeMissingChildError(node, "first-child")
100
+ if left.type != "simple_expression":
101
+ NotImplementedWarning.warn_child_type(left.type, "simple_range")
102
+ return None
103
+ if left.text is None or len(left.text) == 0:
104
+ raise NodeTextIsNoneError(left)
105
+ direction_node = node.child(1)
106
+ if direction_node is None:
107
+ raise NodeMissingChildError(node, "second-child")
108
+ if len(direction_node.type) == 0:
109
+ NotImplementedWarning.warn_child_type(direction_node.type, "")
110
+ return None
111
+ if direction_node.text is None or len(direction_node.text) == 0:
112
+ raise NodeTextIsNoneError(direction_node)
113
+ direction_str = direction_node.text.decode("utf-8")
114
+ right = node.child(2)
115
+ if right is None:
116
+ raise NodeMissingChildError(node, "third-child")
117
+ if right.type != "simple_expression":
118
+ NotImplementedWarning.warn_child_type(right.type, "simple_range")
119
+ return None
120
+ if right.text is None or len(right.text) == 0:
121
+ raise NodeTextIsNoneError(right)
122
+ left_expr = parse_simple_expression(left)
123
+ if left_expr is None:
124
+ return None
125
+ right_expr = parse_simple_expression(right)
126
+ if right_expr is None:
127
+ return None
128
+ direction = parse_as_direction(direction_str)
129
+ if direction is None:
130
+ raise NodeTextIsInvalidError(
131
+ node,
132
+ f"'{direction_str}' is not a valid VHDL direction",
133
+ )
134
+ return cls(left_expr, right_expr, direction, _treesitter_node=node)
135
+
136
+ def __eq__(self, other: object) -> bool: # noqa: D105
137
+ if not isinstance(other, Range):
138
+ return False
139
+ # Required for LSP completions
140
+ other = cast("Range", other) # type: ignore[redundant-cast]
141
+ return (
142
+ self._leftBound == other._leftBound
143
+ and self._rightBound == other._rightBound
144
+ and self._direction == other._direction
145
+ )
146
+
147
+ def __hash__(self) -> int: # noqa: D105
148
+ return hash(
149
+ (
150
+ self._leftBound,
151
+ self._rightBound,
152
+ self._direction,
153
+ ),
154
+ )
155
+
156
+ def __repr__(self) -> str: # noqa: D105
157
+ return (
158
+ f"{self.__class__.__name__}("
159
+ f"_leftBound={self._leftBound!r}, "
160
+ f"_rightBound={self._rightBound!r}, "
161
+ f"_direction={self._direction!r}, "
162
+ ")"
163
+ )
@@ -8,27 +8,25 @@ __all__ = [
8
8
  "UseClause",
9
9
  ]
10
10
 
11
- import sys
12
- from functools import cmp_to_key
13
- from typing import TYPE_CHECKING, cast
14
-
15
- if sys.version_info >= (3, 11):
16
- from typing import Self
17
- else:
18
- from typing_extensions import Self
11
+ from typing import TYPE_CHECKING, Self, cast
19
12
 
20
13
  import pyVHDLModel
21
14
  from pyVHDLModel.DesignUnit import LibraryClause as BaseLibraryClause
22
15
  from pyVHDLModel.DesignUnit import UseClause as BaseUseClause
23
16
 
24
- from pyVHDLModelTreesitter._error import ExtraNodeError, NodeTextIsNoneError
17
+ from pyVHDLModelTreesitter._errors import NodeExtraChildError, NodeTextIsNoneError
25
18
  from pyVHDLModelTreesitter.Interface import (
26
19
  GenericConstantInterfaceItem,
27
20
  PortSignalInterfaceItem,
28
21
  )
29
22
  from pyVHDLModelTreesitter.Name import SelectedName, SimpleName
30
23
  from pyVHDLModelTreesitter.Symbol import LibraryReferenceSymbol, PackageReferenceSymbol
31
- from pyVHDLModelTreesitter.treesitter import get_node_or_raise, get_nodes_or_raise
24
+ from pyVHDLModelTreesitter.treesitter import (
25
+ BaseTreesitterNode,
26
+ get_node_or_raise,
27
+ get_nodes_or_raise,
28
+ sort_into_text_order,
29
+ )
32
30
  from pyVHDLModelTreesitter.treesitter.query import (
33
31
  EntityDeclaration,
34
32
  InterfaceDeclarations,
@@ -44,7 +42,7 @@ if TYPE_CHECKING:
44
42
  import tree_sitter
45
43
 
46
44
 
47
- class LibraryClause(BaseLibraryClause): # noqa: D101
45
+ class LibraryClause(BaseTreesitterNode, BaseLibraryClause): # noqa: D101
48
46
  @classmethod
49
47
  def from_treesitter_node(
50
48
  cls,
@@ -63,8 +61,7 @@ class LibraryClause(BaseLibraryClause): # noqa: D101
63
61
  library_clause_nodes = get_nodes_or_raise(
64
62
  node,
65
63
  captures,
66
- "library-clause",
67
- LibraryClauses.TEXT,
64
+ "library_clause",
68
65
  )
69
66
  ret = []
70
67
  for library_clause_node in library_clause_nodes:
@@ -73,15 +70,14 @@ class LibraryClause(BaseLibraryClause): # noqa: D101
73
70
  node,
74
71
  captures,
75
72
  "library",
76
- LibraryNamespaces.TEXT,
77
73
  )
78
74
  symbols = []
79
75
  for library_namespace_node in library_namespace_nodes:
80
76
  if library_namespace_node.text is None:
81
- raise NodeTextIsNoneError(node, LibraryNamespaces.TEXT, "library")
77
+ raise NodeTextIsNoneError(node)
82
78
  library = library_namespace_node.text.decode()
83
79
  symbols.append(LibraryReferenceSymbol(SimpleName(library)))
84
- ret.append(cls(symbols))
80
+ ret.append(cls(symbols, _treesitter_node=library_clause_node))
85
81
  return ret
86
82
 
87
83
  def __eq__(self, other: object) -> bool: # noqa: D105
@@ -100,7 +96,7 @@ class LibraryClause(BaseLibraryClause): # noqa: D101
100
96
  return f"{self.__class__.__name__}(_symbols={self._symbols!r}, )"
101
97
 
102
98
 
103
- class UseClause(BaseUseClause): # noqa: D101
99
+ class UseClause(BaseTreesitterNode, BaseUseClause): # noqa: D101
104
100
  @classmethod
105
101
  def from_treesitter_node(
106
102
  cls,
@@ -119,8 +115,7 @@ class UseClause(BaseUseClause): # noqa: D101
119
115
  use_clause_nodes = get_nodes_or_raise(
120
116
  node,
121
117
  captures,
122
- "use-clause",
123
- UseClauses.TEXT,
118
+ "use_clause",
124
119
  )
125
120
  ret = []
126
121
  for use_clause_node in use_clause_nodes:
@@ -128,13 +123,12 @@ class UseClause(BaseUseClause): # noqa: D101
128
123
  selected_name_nodes = get_nodes_or_raise(
129
124
  node,
130
125
  captures,
131
- "selected-name",
132
- SelectedNames.TEXT,
126
+ "selected_name",
133
127
  )
134
128
  symbols = []
135
129
  for selected_name_node in selected_name_nodes:
136
130
  if selected_name_node.text is None:
137
- raise NodeTextIsNoneError(node, SelectedNames.TEXT, "selected-name")
131
+ raise NodeTextIsNoneError(node)
138
132
  selected_name = selected_name_node.text.decode()
139
133
  selected_name_parts = selected_name.split(".")
140
134
  selected_name_obj: SimpleName | SelectedName = SimpleName(
@@ -142,8 +136,11 @@ class UseClause(BaseUseClause): # noqa: D101
142
136
  )
143
137
  for part in selected_name_parts[1:]:
144
138
  selected_name_obj = SelectedName(part, selected_name_obj)
139
+ # TODO: should use:
140
+ # PackageMemberReferenceSymbol
141
+ # AllPackageMembersReferenceSymbol
145
142
  symbols.append(PackageReferenceSymbol(selected_name_obj))
146
- ret.append(cls(symbols))
143
+ ret.append(cls(symbols, _treesitter_node=selected_name_node))
147
144
  return ret
148
145
 
149
146
  def __eq__(self, other: object) -> bool: # noqa: D105
@@ -162,20 +159,20 @@ class UseClause(BaseUseClause): # noqa: D101
162
159
  return f"{self.__class__.__name__}(_symbols={self._symbols!r}, )"
163
160
 
164
161
 
165
- class Entity(pyVHDLModel.Entity): # noqa: D101
162
+ class Entity(BaseTreesitterNode, pyVHDLModel.Entity): # noqa: D101
166
163
  @classmethod
167
164
  def from_treesitter_node(
168
165
  cls,
169
166
  node: tree_sitter.Node,
170
167
  *,
171
- contextItems: Iterable[LibraryClause | UseClause] = [], # noqa: N803
168
+ context_items: Iterable[LibraryClause | UseClause] = [],
172
169
  ) -> Self:
173
170
  """
174
171
  Create an Entity from a treesitter node.
175
172
 
176
173
  Raises
177
174
  ------
178
- ExtraNodeError:
175
+ NodeExtraChildError:
179
176
  If there is more than one `generics` or `ports` capture.
180
177
  NodeTextIsNoneError:
181
178
  If the `name` capture has no text.
@@ -186,56 +183,40 @@ class Entity(pyVHDLModel.Entity): # noqa: D101
186
183
  node,
187
184
  captures,
188
185
  "name",
189
- EntityDeclaration.TEXT,
190
186
  )
191
187
  if name_node.text is None:
192
- raise NodeTextIsNoneError(node, EntityDeclaration.TEXT, "name")
188
+ raise NodeTextIsNoneError(node)
193
189
  name_text = name_node.text.decode()
194
190
  generics_nodes = captures.get("generics", [])
195
191
  if len(generics_nodes) > 1:
196
- raise ExtraNodeError(node, EntityDeclaration.TEXT, "generics")
192
+ raise NodeExtraChildError(node, "generic_clause", 1)
197
193
  ports_nodes = captures.get("ports", [])
198
194
  if len(ports_nodes) > 1:
199
- raise ExtraNodeError(node, EntityDeclaration.TEXT, "generics")
195
+ raise NodeExtraChildError(node, "port_clause", 1)
200
196
  generic_items = None
201
197
  if len(generics_nodes) == 1:
202
198
  generics_node = generics_nodes[0]
203
199
  captures = InterfaceDeclarations.capture(generics_node)
204
- generic_items_with_nodes = [
200
+ generic_items = sort_into_text_order(
205
201
  (
206
- GenericConstantInterfaceItem.from_treesitter_node(interface_node),
207
- interface_node,
208
- )
209
- for interface_node in captures.get("interface", [])
210
- ]
211
- generic_items = [
212
- obj
213
- for obj, _ in sorted(
214
- generic_items_with_nodes,
215
- key=cmp_to_key(lambda l, r: l[1].start_byte - r[1].start_byte), # type: ignore[index] # noqa: E741
216
- )
217
- ]
202
+ GenericConstantInterfaceItem.from_treesitter_node(interface_node)
203
+ for interface_node in captures.get("interface", [])
204
+ ),
205
+ )
218
206
  port_items = None
219
207
  if len(ports_nodes) == 1:
220
208
  ports_node = ports_nodes[0]
221
209
  captures = InterfaceDeclarations.capture(ports_node)
222
- port_items_with_nodes = [
210
+ port_items = sort_into_text_order(
223
211
  (
224
- PortSignalInterfaceItem.from_treesitter_node(interface_node),
225
- interface_node,
226
- )
227
- for interface_node in captures.get("interface", [])
228
- ]
229
- port_items = [
230
- obj
231
- for obj, _ in sorted(
232
- port_items_with_nodes,
233
- key=cmp_to_key(lambda l, r: l[1].start_byte - r[1].start_byte), # type: ignore[index] # noqa: E741
234
- )
235
- ]
212
+ PortSignalInterfaceItem.from_treesitter_node(interface_node)
213
+ for interface_node in captures.get("interface", [])
214
+ ),
215
+ )
236
216
  return cls(
217
+ _treesitter_node=node,
237
218
  identifier=name_text,
238
- contextItems=contextItems,
219
+ contextItems=context_items,
239
220
  genericItems=generic_items,
240
221
  portItems=port_items,
241
222
  declaredItems=None, # TODO: implement