clindocs 1.5.2__py3-none-any.whl
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.
- clindocs-1.5.2.dist-info/METADATA +81 -0
- clindocs-1.5.2.dist-info/RECORD +41 -0
- clindocs-1.5.2.dist-info/WHEEL +5 -0
- clindocs-1.5.2.dist-info/entry_points.txt +2 -0
- clindocs-1.5.2.dist-info/licenses/LICENSE +21 -0
- clindocs-1.5.2.dist-info/top_level.txt +1 -0
- mkdocstrings_handlers/asp/__init__.py +5 -0
- mkdocstrings_handlers/asp/_internal/__init__.py +0 -0
- mkdocstrings_handlers/asp/_internal/collect/__init__.py +0 -0
- mkdocstrings_handlers/asp/_internal/collect/debug.py +19 -0
- mkdocstrings_handlers/asp/_internal/collect/extractors.py +317 -0
- mkdocstrings_handlers/asp/_internal/collect/load.py +92 -0
- mkdocstrings_handlers/asp/_internal/collect/queries/body.scm +11 -0
- mkdocstrings_handlers/asp/_internal/collect/queries/documentation_argument.scm +4 -0
- mkdocstrings_handlers/asp/_internal/collect/queries/documentation_predicate.scm +12 -0
- mkdocstrings_handlers/asp/_internal/collect/queries/head.scm +54 -0
- mkdocstrings_handlers/asp/_internal/collect/queries/predicate.scm +29 -0
- mkdocstrings_handlers/asp/_internal/collect/queries/show.scm +15 -0
- mkdocstrings_handlers/asp/_internal/collect/syntax.py +95 -0
- mkdocstrings_handlers/asp/_internal/config.py +135 -0
- mkdocstrings_handlers/asp/_internal/domain.py +140 -0
- mkdocstrings_handlers/asp/_internal/error.py +5 -0
- mkdocstrings_handlers/asp/_internal/handler.py +175 -0
- mkdocstrings_handlers/asp/_internal/render/__init__.py +0 -0
- mkdocstrings_handlers/asp/_internal/render/dependency_graph_context.py +66 -0
- mkdocstrings_handlers/asp/_internal/render/encodings_context.py +139 -0
- mkdocstrings_handlers/asp/_internal/render/glossary_context.py +155 -0
- mkdocstrings_handlers/asp/_internal/render/predicate_info.py +197 -0
- mkdocstrings_handlers/asp/_internal/render/predicate_table_context.py +56 -0
- mkdocstrings_handlers/asp/_internal/render/render_context.py +74 -0
- mkdocstrings_handlers/asp/py.typed +0 -0
- mkdocstrings_handlers/asp/templates/material/dependency_graph.html.jinja +55 -0
- mkdocstrings_handlers/asp/templates/material/documentation.html.jinja +13 -0
- mkdocstrings_handlers/asp/templates/material/encodings.html.jinja +59 -0
- mkdocstrings_handlers/asp/templates/material/glossary.html.jinja +67 -0
- mkdocstrings_handlers/asp/templates/material/glossary_references.html.jinja +51 -0
- mkdocstrings_handlers/asp/templates/material/icons.html.jinja +62 -0
- mkdocstrings_handlers/asp/templates/material/predicate_table.html.jinja +39 -0
- mkdocstrings_handlers/asp/templates/material/separator.html.jinja +3 -0
- mkdocstrings_handlers/asp/templates/material/source.html.jinja +8 -0
- mkdocstrings_handlers/asp/templates/material/style.css +89 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clindocs
|
|
3
|
+
Version: 1.5.2
|
|
4
|
+
Summary: Mkdocs plugin to generate documentation from clingo files
|
|
5
|
+
Author-email: Potassco <hahnmartinlu@uni-potsdam.de>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 Potassco
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/potassco/clindocs.git/
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: clingo
|
|
33
|
+
Requires-Dist: mkdocstrings>=1.0.0
|
|
34
|
+
Requires-Dist: tree-sitter
|
|
35
|
+
Requires-Dist: tree-sitter-clingo>=1.0.5
|
|
36
|
+
Requires-Dist: pydantic
|
|
37
|
+
Requires-Dist: pygments_clingo
|
|
38
|
+
Requires-Dist: mkdocs>=1.5
|
|
39
|
+
Requires-Dist: mkdocs-material>=9.5
|
|
40
|
+
Requires-Dist: mkdocs-autorefs>=1.4
|
|
41
|
+
Provides-Extra: format
|
|
42
|
+
Requires-Dist: black; extra == "format"
|
|
43
|
+
Requires-Dist: isort; extra == "format"
|
|
44
|
+
Requires-Dist: autoflake; extra == "format"
|
|
45
|
+
Provides-Extra: lint-pylint
|
|
46
|
+
Requires-Dist: pylint; extra == "lint-pylint"
|
|
47
|
+
Requires-Dist: djlint; extra == "lint-pylint"
|
|
48
|
+
Provides-Extra: typecheck
|
|
49
|
+
Requires-Dist: types-setuptools; extra == "typecheck"
|
|
50
|
+
Requires-Dist: mypy; extra == "typecheck"
|
|
51
|
+
Requires-Dist: types-Markdown; extra == "typecheck"
|
|
52
|
+
Requires-Dist: types-Pygments; extra == "typecheck"
|
|
53
|
+
Provides-Extra: test
|
|
54
|
+
Requires-Dist: coverage[toml]; extra == "test"
|
|
55
|
+
Requires-Dist: pytest; extra == "test"
|
|
56
|
+
Provides-Extra: doc
|
|
57
|
+
Requires-Dist: mkdocstrings[python]; extra == "doc"
|
|
58
|
+
Requires-Dist: mkdocs-literate-nav; extra == "doc"
|
|
59
|
+
Provides-Extra: dev
|
|
60
|
+
Requires-Dist: clindocs[doc,lint_pylint,test,typecheck]; extra == "dev"
|
|
61
|
+
Dynamic: license-file
|
|
62
|
+
|
|
63
|
+
# clindocs
|
|
64
|
+
|
|
65
|
+
**clindocs** is an automated documentation tool tailored for **Answer Set
|
|
66
|
+
Programming (ASP)** code. Built on [MkDocs](https://www.mkdocs.org/) and
|
|
67
|
+
[mkdocs-material](https://squidfunk.github.io/mkdocs-material/), it streamlines
|
|
68
|
+
the creation of high-quality documentation with the following features:
|
|
69
|
+
|
|
70
|
+
- **Render encodings**: Automatically format ASP encodings with comments
|
|
71
|
+
written in Markdown.
|
|
72
|
+
- **Predicate analysis**: Collect and document predicates used across included
|
|
73
|
+
files.
|
|
74
|
+
- **Navigation-friendly documentation**: Generate organized predicate
|
|
75
|
+
documentation with intuitive navigation.
|
|
76
|
+
- **Input/output identification**: Detect and highlight input and output
|
|
77
|
+
predicates.
|
|
78
|
+
- **Dependency graphs**: Visualize dependencies between predicates and files.
|
|
79
|
+
|
|
80
|
+
For installation instructions and detailed usage, visit our
|
|
81
|
+
[official documentation](https://potassco.org/clindocs/docs).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
clindocs-1.5.2.dist-info/licenses/LICENSE,sha256=ENv21OEPTlPYM34OARsrJK5nyORaoT0-Bp-H3Xa3gyg,1065
|
|
2
|
+
mkdocstrings_handlers/asp/__init__.py,sha256=3R9Ma3P3-t8LJtHm1RCoEmOhpnORGVOSx4FXPx2ZPs8,150
|
|
3
|
+
mkdocstrings_handlers/asp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
mkdocstrings_handlers/asp/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
mkdocstrings_handlers/asp/_internal/config.py,sha256=WdU-m_3PR5Et8ESJr2hWRa4de6_WoptGOGemRs7mreI,4211
|
|
6
|
+
mkdocstrings_handlers/asp/_internal/domain.py,sha256=pjtl7djVbs7ID4GVzVFcHLAPLzkpPbbJLUKYrWOfw3Y,3923
|
|
7
|
+
mkdocstrings_handlers/asp/_internal/error.py,sha256=1KeOtM31AKvCELVi4kcqnXQjIhy1hP_7XfeSaUbH4Wc,169
|
|
8
|
+
mkdocstrings_handlers/asp/_internal/handler.py,sha256=TYMPVJtQ5gGVobFDxsIhfJLul8UWEnta1PcEy-bep7A,5299
|
|
9
|
+
mkdocstrings_handlers/asp/_internal/collect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
mkdocstrings_handlers/asp/_internal/collect/debug.py,sha256=zUPYCq-h-iW7_tCuDv-zdBzvAYqdW6FjnqIbMg3WJyw,595
|
|
11
|
+
mkdocstrings_handlers/asp/_internal/collect/extractors.py,sha256=2klxVlYnV-fhKWt2Zg2Wg7EljWdNGWbKDE_Pit6Ogp8,9052
|
|
12
|
+
mkdocstrings_handlers/asp/_internal/collect/load.py,sha256=LQakM5oVIcELcy3-w6tQSJTAxeh36p12ZnxD9mo5bZY,3270
|
|
13
|
+
mkdocstrings_handlers/asp/_internal/collect/syntax.py,sha256=8oH7BOc_Yd342QD_SindIWyJu0HGUI79OqNmk38VHGc,2747
|
|
14
|
+
mkdocstrings_handlers/asp/_internal/collect/queries/body.scm,sha256=yfkZakz32nkbmSZJD6udhe2FrtaVrZ27H778dbhcod4,305
|
|
15
|
+
mkdocstrings_handlers/asp/_internal/collect/queries/documentation_argument.scm,sha256=WdgpiFuSRWdTqVJChC_sgZEM8o_zBox3p71ojkCqsQs,67
|
|
16
|
+
mkdocstrings_handlers/asp/_internal/collect/queries/documentation_predicate.scm,sha256=VbkRK8PxkeXArtu8LngZU9M-mhmibzNgJ5TkL2tfsGM,223
|
|
17
|
+
mkdocstrings_handlers/asp/_internal/collect/queries/head.scm,sha256=_fX566sB8zS1QZqQijD1SZlRQpjZwhxXiOLFT4NiNtg,1105
|
|
18
|
+
mkdocstrings_handlers/asp/_internal/collect/queries/predicate.scm,sha256=Ga9Tm7zM4ti-W3mbD9raYP6jF7eFYjmGYibZKo5Cww0,692
|
|
19
|
+
mkdocstrings_handlers/asp/_internal/collect/queries/show.scm,sha256=lhQ8pez9EKIl8cvXDvLGO7FGQSdESQkfyBZ2YstmQ60,199
|
|
20
|
+
mkdocstrings_handlers/asp/_internal/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
mkdocstrings_handlers/asp/_internal/render/dependency_graph_context.py,sha256=QnJ50hpkfRP--T-zVHN2jI7RGJmJ7_DXmuY5G6UUMJ0,2232
|
|
22
|
+
mkdocstrings_handlers/asp/_internal/render/encodings_context.py,sha256=ystrk5ravvGrXNI2hSFHagilEuiuVgLAsANLtvtDQOo,4358
|
|
23
|
+
mkdocstrings_handlers/asp/_internal/render/glossary_context.py,sha256=UxqDaKG-SUK2jSWKeHlZq5RxGUizNKY4cWODz0yJ-vE,4853
|
|
24
|
+
mkdocstrings_handlers/asp/_internal/render/predicate_info.py,sha256=dvXGS4lnexUXkVVGIvWhhCkyYlPtHS6h27hPVFUcbSk,7110
|
|
25
|
+
mkdocstrings_handlers/asp/_internal/render/predicate_table_context.py,sha256=I6wl1YejWEce1tEV7cgtLq_TYP8b2v7nTYpjL0LSFsk,1793
|
|
26
|
+
mkdocstrings_handlers/asp/_internal/render/render_context.py,sha256=uhoe1tHCpyRd3oB6_SDkV8qHyw71eeaLpIinB_kNUR8,2654
|
|
27
|
+
mkdocstrings_handlers/asp/templates/material/dependency_graph.html.jinja,sha256=PXLhW2zlYMFsQSzZF476d0wEV15kjYTJgUCo4bIr_6g,2913
|
|
28
|
+
mkdocstrings_handlers/asp/templates/material/documentation.html.jinja,sha256=B4tepM5f0HjzUQxPLK-HwCKSV1Qye5Lwy0qXkZvQofQ,439
|
|
29
|
+
mkdocstrings_handlers/asp/templates/material/encodings.html.jinja,sha256=rfZQXgMyqcy_rLMDr2zE2Tjb25QRVuF1KDnQRXMo4j0,3838
|
|
30
|
+
mkdocstrings_handlers/asp/templates/material/glossary.html.jinja,sha256=OHXeoXMpgnXrLhRI0JUw5pWTxBE04b9xYBDv8b_rOOM,2649
|
|
31
|
+
mkdocstrings_handlers/asp/templates/material/glossary_references.html.jinja,sha256=3YTnNMAQGm66YK89F8oefEMHDppmxnXql0yp8m5I4ZQ,1918
|
|
32
|
+
mkdocstrings_handlers/asp/templates/material/icons.html.jinja,sha256=nCi2uDpWEnCXbTa6csULENr73bkLVQokXCT_m0XF6Fg,1993
|
|
33
|
+
mkdocstrings_handlers/asp/templates/material/predicate_table.html.jinja,sha256=BxxhTEUs7QE8J2HlHIbs-eXv9L10_srAyQER0O1kmHg,1562
|
|
34
|
+
mkdocstrings_handlers/asp/templates/material/separator.html.jinja,sha256=oX1ZUWDBCFcR2uGLrcR_fZYwSFD6qiwIeigq0KZ7PEA,61
|
|
35
|
+
mkdocstrings_handlers/asp/templates/material/source.html.jinja,sha256=cs7vXtFhJ2_WrxljVKLE408MtV5bFUkFC2h2zVMErS0,159
|
|
36
|
+
mkdocstrings_handlers/asp/templates/material/style.css,sha256=TD6mkJY7jxxyEdjA3-FZaTwXYFdgqhiavui7vltIa_M,2778
|
|
37
|
+
clindocs-1.5.2.dist-info/METADATA,sha256=x94Fs6M3QFbBoK9G29rMK2_4NfYtVL9hpvECXHnr5-Q,3580
|
|
38
|
+
clindocs-1.5.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
39
|
+
clindocs-1.5.2.dist-info/entry_points.txt,sha256=r4jCxLx7C7iZyzmXNS5d_XnMEeRjUPXwqgRfgVnRtqA,88
|
|
40
|
+
clindocs-1.5.2.dist-info/top_level.txt,sha256=IP9FE6TMun3TXULzTNhW_Y0Tlj9Dh3J4k1QHrzs9NnY,22
|
|
41
|
+
clindocs-1.5.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Potassco
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mkdocstrings_handlers
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Utility functions for debugging tree-sitter trees."""
|
|
2
|
+
|
|
3
|
+
from tree_sitter import Node
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def print_tree(node: Node, source: bytes, depth: int) -> None:
|
|
7
|
+
"""Recursively print the tree structure of a node.
|
|
8
|
+
Args:
|
|
9
|
+
node: The node to print.
|
|
10
|
+
source: The source code from which the node was created.
|
|
11
|
+
depth: The current depth in the tree.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
node_text = node.text.decode("utf-8") if node.text is not None else ""
|
|
15
|
+
|
|
16
|
+
print(f"{' ' * depth}{node.grammar_name} {node.id}: {node_text}")
|
|
17
|
+
|
|
18
|
+
for child in node.children:
|
|
19
|
+
print_tree(child, source, depth + 1)
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"""Extractors for various ASP constructs from Tree-sitter nodes."""
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from tree_sitter import Node
|
|
7
|
+
|
|
8
|
+
from mkdocstrings_handlers.asp._internal.collect.syntax import Queries
|
|
9
|
+
from mkdocstrings_handlers.asp._internal.domain import (
|
|
10
|
+
ArgumentDocumentation,
|
|
11
|
+
BlockComment,
|
|
12
|
+
Include,
|
|
13
|
+
LineComment,
|
|
14
|
+
Predicate,
|
|
15
|
+
PredicateDocumentation,
|
|
16
|
+
Show,
|
|
17
|
+
ShowStatus,
|
|
18
|
+
Statement,
|
|
19
|
+
)
|
|
20
|
+
from mkdocstrings_handlers.asp._internal.error import ExtractionError
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_node_text(node: Node | None) -> str:
|
|
24
|
+
"""
|
|
25
|
+
Safely extracts and decodes text from a Tree-sitter node.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
node: The Tree-sitter node.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The decoded text content of the node.
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
ExtractionError: If the node is None or has no text.
|
|
35
|
+
"""
|
|
36
|
+
if node is None:
|
|
37
|
+
raise ExtractionError("Expected a node, but got None.")
|
|
38
|
+
|
|
39
|
+
if node.text is None:
|
|
40
|
+
# This usually happens with 'missing' nodes in Tree-sitter (syntax errors)
|
|
41
|
+
raise ExtractionError(f"Node {node.type} exists but has no text content.")
|
|
42
|
+
|
|
43
|
+
return node.text.decode("utf-8")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_capture_text(captures: dict[str, list[Node]], key: str, index: int = 0) -> str:
|
|
47
|
+
"""
|
|
48
|
+
Safely retrieves the text from a capture group.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
captures: The dictionary of captured nodes.
|
|
52
|
+
key: The capture group name (e.g., "identifier").
|
|
53
|
+
index: Which item in the capture list to retrieve (default 0).
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The decoded text content of the specified capture.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ExtractionError: If the capture group is missing, empty, or the index is out of
|
|
60
|
+
bounds.
|
|
61
|
+
"""
|
|
62
|
+
nodes = captures.get(key)
|
|
63
|
+
|
|
64
|
+
if not nodes:
|
|
65
|
+
raise ExtractionError(f"Required capture group '{key}' is missing or empty.")
|
|
66
|
+
|
|
67
|
+
if index >= len(nodes):
|
|
68
|
+
raise ExtractionError(f"Capture group '{key}' does not have an element at index {index}.")
|
|
69
|
+
|
|
70
|
+
return get_node_text(nodes[index])
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def extract_include(node: Node, parent_file_path: Path) -> Include:
|
|
74
|
+
"""
|
|
75
|
+
Extract an Include from a node.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
node: The node representing the include.
|
|
79
|
+
base_path: The base path of the current file.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The created Include.
|
|
83
|
+
"""
|
|
84
|
+
# If the node is an include,
|
|
85
|
+
# then the first child is the include directive
|
|
86
|
+
# and the second child is the file path.
|
|
87
|
+
|
|
88
|
+
# The second child of the file path is the file path
|
|
89
|
+
# as a string fragment without the quotes.
|
|
90
|
+
file_path_node = node.children[1]
|
|
91
|
+
file_path = Path(get_node_text(file_path_node.children[1]))
|
|
92
|
+
resolved_path = parent_file_path.parent / file_path
|
|
93
|
+
|
|
94
|
+
return Include(row=node.start_point.row, content=get_node_text(node), path=resolved_path)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def extract_predicates(node: Node) -> list[Predicate]:
|
|
98
|
+
"""
|
|
99
|
+
Extract a Predicate from a node.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
node: A `literal` node representing the predicate.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The created Predicate.
|
|
106
|
+
"""
|
|
107
|
+
captures = Queries.PREDICATE.captures(node)
|
|
108
|
+
|
|
109
|
+
identifier = get_node_text(captures["identifier"][0])
|
|
110
|
+
is_negated = len(captures.get("negation", [])) > 0
|
|
111
|
+
|
|
112
|
+
if "term_group" not in captures:
|
|
113
|
+
return [Predicate(identifier=identifier, arity=0, negation=is_negated)]
|
|
114
|
+
|
|
115
|
+
predicates = []
|
|
116
|
+
for group_node in captures["term_group"]:
|
|
117
|
+
arity = group_node.named_child_count
|
|
118
|
+
|
|
119
|
+
predicates.append(Predicate(identifier=identifier, arity=arity, negation=is_negated))
|
|
120
|
+
|
|
121
|
+
return predicates
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def extract_show(node: Node) -> Show:
|
|
125
|
+
"""
|
|
126
|
+
Extract a Show directive from a node.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
node: A `show_signature` or `show_term` node representing the show directive.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
The created Show directive.
|
|
133
|
+
"""
|
|
134
|
+
captures = Queries.SHOW.captures(node)
|
|
135
|
+
|
|
136
|
+
raw_identifier = captures.get("identifier", [])
|
|
137
|
+
raw_arity = captures.get("arity", [])
|
|
138
|
+
raw_terms = captures.get("term", [])
|
|
139
|
+
|
|
140
|
+
identifier: str | None = get_node_text(raw_identifier[0]) if raw_identifier else None
|
|
141
|
+
arity: int | None = int(get_node_text(raw_arity[0])) if raw_arity else None
|
|
142
|
+
predicate: Predicate | None = None
|
|
143
|
+
status = ShowStatus.EXPLICIT
|
|
144
|
+
|
|
145
|
+
if raw_terms:
|
|
146
|
+
status = ShowStatus.PARTIAL
|
|
147
|
+
arity = len(raw_terms)
|
|
148
|
+
|
|
149
|
+
if identifier is not None and arity is not None:
|
|
150
|
+
predicate = Predicate(
|
|
151
|
+
identifier=identifier,
|
|
152
|
+
arity=arity,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return Show(
|
|
156
|
+
row=node.start_point.row,
|
|
157
|
+
content=get_node_text(node),
|
|
158
|
+
predicate=predicate,
|
|
159
|
+
status=status,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def extract_line_comment(node: Node) -> LineComment:
|
|
164
|
+
"""
|
|
165
|
+
Extract a LineComment from a node.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
node: A `line_comment` node representing the line comment.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
The created LineComment.
|
|
172
|
+
"""
|
|
173
|
+
return LineComment(
|
|
174
|
+
row=node.start_point.row,
|
|
175
|
+
content=get_node_text(node).removeprefix("%"),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def extract_block_comment(node: Node) -> BlockComment:
|
|
180
|
+
"""
|
|
181
|
+
Extract a BlockComment from a node.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
node: A `block_comment` node representing the block comment.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
The created BlockComment.
|
|
188
|
+
"""
|
|
189
|
+
return BlockComment(
|
|
190
|
+
row=node.start_point.row,
|
|
191
|
+
content=get_node_text(node).removeprefix("%*").removesuffix("*%"),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def extract_bare_statement(node: Node) -> Statement:
|
|
196
|
+
"""
|
|
197
|
+
Extract a Statement without predicate tracking.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
node: A node representing the statement.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
The created Statement.
|
|
204
|
+
"""
|
|
205
|
+
return Statement(
|
|
206
|
+
row=node.start_point.row,
|
|
207
|
+
content=get_node_text(node),
|
|
208
|
+
provided_predicates=[],
|
|
209
|
+
needed_predicates=[],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def extract_statement(node: Node) -> Statement:
|
|
214
|
+
"""
|
|
215
|
+
Extract a Statement from a node.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
node: A node representing the statement.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
The created Statement.
|
|
222
|
+
"""
|
|
223
|
+
head_node = node.child_by_field_name("head")
|
|
224
|
+
body_node = node.child_by_field_name("body")
|
|
225
|
+
|
|
226
|
+
captures = defaultdict(list)
|
|
227
|
+
|
|
228
|
+
if head_node:
|
|
229
|
+
# We don't use the head_node here
|
|
230
|
+
# because `head` is a supertype in the current grammar
|
|
231
|
+
# which leads to query difficulties with literals
|
|
232
|
+
head_captures = Queries.HEAD.captures(node)
|
|
233
|
+
for key, nodes in head_captures.items():
|
|
234
|
+
captures[key].extend(nodes)
|
|
235
|
+
|
|
236
|
+
if body_node:
|
|
237
|
+
body_captures = Queries.BODY.captures(body_node)
|
|
238
|
+
for key, nodes in body_captures.items():
|
|
239
|
+
captures[key].extend(nodes)
|
|
240
|
+
|
|
241
|
+
provided_predicates = [pred for node in captures.get("provided", []) for pred in extract_predicates(node)]
|
|
242
|
+
needed_predicates = [pred for node in captures.get("needed", []) for pred in extract_predicates(node)]
|
|
243
|
+
|
|
244
|
+
return Statement(
|
|
245
|
+
row=node.start_point.row,
|
|
246
|
+
content=get_node_text(node),
|
|
247
|
+
provided_predicates=provided_predicates,
|
|
248
|
+
needed_predicates=needed_predicates,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def extract_argument_documentation(node: Node) -> ArgumentDocumentation:
|
|
253
|
+
"""
|
|
254
|
+
Extract an ArgumentDocumentation from a node.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
node: The node representing the argument documentation.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
The created ArgumentDocumentation.
|
|
261
|
+
"""
|
|
262
|
+
captures = Queries.DOC_ARGUMENT.captures(node)
|
|
263
|
+
|
|
264
|
+
identifier = get_capture_text(captures, "identifier", 0)
|
|
265
|
+
description = get_node_text(captures["description"][0]).strip() if captures.get("description") else ""
|
|
266
|
+
|
|
267
|
+
return ArgumentDocumentation(
|
|
268
|
+
identifier=identifier,
|
|
269
|
+
description=description,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def extract_predicate_documentation(node: Node) -> PredicateDocumentation:
|
|
274
|
+
"""
|
|
275
|
+
Extract a PredicateDocumentation from a node.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
node: The node representing the predicate documentation.
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
The created PredicateDocumentation.
|
|
282
|
+
"""
|
|
283
|
+
captures = Queries.DOC_PREDICATE.captures(node)
|
|
284
|
+
|
|
285
|
+
identifier = get_capture_text(captures, "identifier", 0)
|
|
286
|
+
|
|
287
|
+
# For some reason the query does not return the arguments
|
|
288
|
+
# in the order they appear. So we order them by their start byte.
|
|
289
|
+
argument_nodes = captures.get("argument", [])
|
|
290
|
+
argument_nodes.sort(key=lambda n: n.start_byte)
|
|
291
|
+
arguments = [get_node_text(arg) for arg in argument_nodes]
|
|
292
|
+
|
|
293
|
+
explicit_docs_map = {}
|
|
294
|
+
for arg_node in captures.get("arg.documentation", []):
|
|
295
|
+
doc = extract_argument_documentation(arg_node)
|
|
296
|
+
explicit_docs_map[doc.identifier] = doc
|
|
297
|
+
|
|
298
|
+
final_arguments = []
|
|
299
|
+
for name in arguments:
|
|
300
|
+
if name in explicit_docs_map:
|
|
301
|
+
final_arguments.append(explicit_docs_map[name])
|
|
302
|
+
else:
|
|
303
|
+
final_arguments.append(ArgumentDocumentation(identifier=name, description=""))
|
|
304
|
+
|
|
305
|
+
description = (
|
|
306
|
+
get_node_text(captures["description"][0]).removeprefix("%*!").removesuffix("*%").strip()
|
|
307
|
+
if captures.get("description")
|
|
308
|
+
else ""
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return PredicateDocumentation(
|
|
312
|
+
row=node.start_point.row,
|
|
313
|
+
content=get_node_text(node),
|
|
314
|
+
signature=f"{identifier}/{len(arguments)}",
|
|
315
|
+
description=description,
|
|
316
|
+
arguments=final_arguments,
|
|
317
|
+
)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""This module handles loading and parsing ASP documents."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections import deque
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from mkdocstrings_handlers.asp._internal.collect.extractors import (
|
|
8
|
+
extract_bare_statement,
|
|
9
|
+
extract_block_comment,
|
|
10
|
+
extract_include,
|
|
11
|
+
extract_line_comment,
|
|
12
|
+
extract_predicate_documentation,
|
|
13
|
+
extract_show,
|
|
14
|
+
extract_statement,
|
|
15
|
+
)
|
|
16
|
+
from mkdocstrings_handlers.asp._internal.collect.syntax import NodeKind, get_parser
|
|
17
|
+
from mkdocstrings_handlers.asp._internal.domain import Document, ShowStatus
|
|
18
|
+
|
|
19
|
+
log = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_documents(paths: list[Path]) -> list[Document]:
|
|
23
|
+
"""
|
|
24
|
+
Load and parse multiple ASP documents from the given file paths.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
paths: List of paths to ASP files.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
List of parsed Document objects.
|
|
31
|
+
"""
|
|
32
|
+
parse_queue = deque(paths)
|
|
33
|
+
documents: dict[Path, Document] = {}
|
|
34
|
+
while parse_queue:
|
|
35
|
+
path = parse_queue.popleft()
|
|
36
|
+
if path.suffix != ".lp" or not path.is_file():
|
|
37
|
+
log.warning("skip file %s, not a valid ASP file.", path)
|
|
38
|
+
continue
|
|
39
|
+
document = load_document(path)
|
|
40
|
+
documents[path] = document
|
|
41
|
+
parse_queue.extend(include.path for include in document.includes if include.path not in documents)
|
|
42
|
+
|
|
43
|
+
return list(documents.values())
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def load_document(file_path: Path) -> Document:
|
|
47
|
+
"""
|
|
48
|
+
Load and parse an ASP document from the given file path.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
file_path: Path to the ASP file.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
The parsed Document object.
|
|
55
|
+
"""
|
|
56
|
+
with open(file_path, "rb") as f:
|
|
57
|
+
source_bytes = f.read()
|
|
58
|
+
|
|
59
|
+
document = Document(path=file_path, content=source_bytes.decode("utf-8"))
|
|
60
|
+
tree = get_parser().parse(source_bytes)
|
|
61
|
+
|
|
62
|
+
for node in tree.root_node.children:
|
|
63
|
+
match NodeKind.from_grammar_name(node.grammar_name):
|
|
64
|
+
case NodeKind.RULE | NodeKind.INTEGRITY_CONSTRAINT:
|
|
65
|
+
statement = extract_statement(node)
|
|
66
|
+
document.statements.append(statement)
|
|
67
|
+
case NodeKind.LINE_COMMENT:
|
|
68
|
+
line_comment = extract_line_comment(node)
|
|
69
|
+
document.line_comments.append(line_comment)
|
|
70
|
+
case NodeKind.BLOCK_COMMENT:
|
|
71
|
+
block_comment = extract_block_comment(node)
|
|
72
|
+
document.block_comments.append(block_comment)
|
|
73
|
+
case NodeKind.INCLUDE:
|
|
74
|
+
include = extract_include(node, file_path)
|
|
75
|
+
document.includes.append(include)
|
|
76
|
+
case NodeKind.SHOW | NodeKind.SHOW_SIGNATURE | NodeKind.SHOW_TERM:
|
|
77
|
+
show = extract_show(node)
|
|
78
|
+
statement = extract_statement(node)
|
|
79
|
+
|
|
80
|
+
if show.predicate is not None and show.status == ShowStatus.PARTIAL:
|
|
81
|
+
statement.provided_predicates.append(show.predicate)
|
|
82
|
+
|
|
83
|
+
document.shows.append(show)
|
|
84
|
+
document.statements.append(statement)
|
|
85
|
+
case NodeKind.DOC_COMMENT:
|
|
86
|
+
predicate_documentation = extract_predicate_documentation(node)
|
|
87
|
+
document.predicate_documentations.append(predicate_documentation)
|
|
88
|
+
case _:
|
|
89
|
+
statement = extract_bare_statement(node)
|
|
90
|
+
document.statements.append(statement)
|
|
91
|
+
|
|
92
|
+
return document
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
; -----------------------------------------------------------------------------
|
|
2
|
+
; This gathers needed predicates in the body of a statement
|
|
3
|
+
; -----------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
(body_literal
|
|
6
|
+
(symbolic_atom)
|
|
7
|
+
) @needed
|
|
8
|
+
|
|
9
|
+
(literal
|
|
10
|
+
(symbolic_atom)
|
|
11
|
+
) @needed
|