dbrownell-parserlib 0.6.0__tar.gz → 0.7.0__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.
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/PKG-INFO +1 -1
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/pyproject.toml +1 -1
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/__init__.py +12 -1
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/antlr/__init__.py +8 -0
- dbrownell_parserlib-0.7.0/src/dbrownell_ParserLib/antlr/antlr_visitor_mixins.py +155 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/README.md +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/antlr/antlr_parser.py +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/__init__.py +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/antlr-4.13.2-complete.jar +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/errors.py +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/location.py +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/py.typed +0 -0
- {dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/region.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dbrownell-parserlib"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
# ^^^^^
|
|
5
5
|
# Wheel names will be generated according to this value. Do not manually modify this value; instead
|
|
6
6
|
# update it according to committed changes by running this command from the root of the repository:
|
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
from importlib.metadata import version
|
|
4
4
|
|
|
5
|
-
from dbrownell_ParserLib.antlr import
|
|
5
|
+
from dbrownell_ParserLib.antlr import (
|
|
6
|
+
AntlrParser,
|
|
7
|
+
AntlrParserException,
|
|
8
|
+
AntlrVisitorMixinBase,
|
|
9
|
+
BuildAntlrGrammar,
|
|
10
|
+
CreateAntlrParser,
|
|
11
|
+
InsignificantWhitespaceAntlrVisitorMixin,
|
|
12
|
+
SignificantWhitespaceAntlrVisitorMixin,
|
|
13
|
+
)
|
|
6
14
|
from dbrownell_ParserLib.errors import Error, PythonError
|
|
7
15
|
from dbrownell_ParserLib.location import Location
|
|
8
16
|
from dbrownell_ParserLib.region import Region
|
|
@@ -12,12 +20,15 @@ from dbrownell_ParserLib.region import Region
|
|
|
12
20
|
__all__ = [
|
|
13
21
|
"AntlrParser",
|
|
14
22
|
"AntlrParserException",
|
|
23
|
+
"AntlrVisitorMixinBase",
|
|
15
24
|
"BuildAntlrGrammar",
|
|
16
25
|
"CreateAntlrParser",
|
|
17
26
|
"Error",
|
|
27
|
+
"InsignificantWhitespaceAntlrVisitorMixin",
|
|
18
28
|
"Location",
|
|
19
29
|
"PythonError",
|
|
20
30
|
"Region",
|
|
31
|
+
"SignificantWhitespaceAntlrVisitorMixin",
|
|
21
32
|
"__version__",
|
|
22
33
|
]
|
|
23
34
|
|
{dbrownell_parserlib-0.6.0 → dbrownell_parserlib-0.7.0}/src/dbrownell_ParserLib/antlr/__init__.py
RENAMED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# noqa: D104
|
|
2
2
|
from dbrownell_ParserLib.antlr.build_antlr_grammar import BuildAntlrGrammar
|
|
3
3
|
from dbrownell_ParserLib.antlr.antlr_parser import AntlrParser, AntlrParserException, CreateAntlrParser
|
|
4
|
+
from dbrownell_ParserLib.antlr.antlr_visitor_mixins import (
|
|
5
|
+
AntlrVisitorMixinBase,
|
|
6
|
+
InsignificantWhitespaceAntlrVisitorMixin,
|
|
7
|
+
SignificantWhitespaceAntlrVisitorMixin,
|
|
8
|
+
)
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
# ----------------------------------------------------------------------
|
|
7
12
|
__all__ = [
|
|
8
13
|
"AntlrParser",
|
|
9
14
|
"AntlrParserException",
|
|
15
|
+
"AntlrVisitorMixinBase",
|
|
10
16
|
"BuildAntlrGrammar",
|
|
11
17
|
"CreateAntlrParser",
|
|
18
|
+
"InsignificantWhitespaceAntlrVisitorMixin",
|
|
19
|
+
"SignificantWhitespaceAntlrVisitorMixin",
|
|
12
20
|
]
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Various ANTLR visitor mixins that can be used to add functionality to the generated visitor classes."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import cast, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
import antlr4
|
|
7
|
+
|
|
8
|
+
from dbrownell_ParserLib.region import Location, Region
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ----------------------------------------------------------------------
|
|
16
|
+
class AntlrVisitorMixinBase(ABC):
|
|
17
|
+
"""Base class for visitor mixins. This class is not meant to be used directly, but rather to be inherited by other mixin classes."""
|
|
18
|
+
|
|
19
|
+
# ----------------------------------------------------------------------
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
filename: Path,
|
|
23
|
+
on_progress_func: Callable[[int], None],
|
|
24
|
+
*,
|
|
25
|
+
is_included_file: bool,
|
|
26
|
+
) -> None:
|
|
27
|
+
self.filename = filename
|
|
28
|
+
self.is_included_file = is_included_file
|
|
29
|
+
|
|
30
|
+
# Protected data
|
|
31
|
+
self._on_progress_func = on_progress_func
|
|
32
|
+
self._stack: list[object] = []
|
|
33
|
+
|
|
34
|
+
# Private data
|
|
35
|
+
self._current_line: int = 0
|
|
36
|
+
|
|
37
|
+
# ----------------------------------------------------------------------
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def CreateRegion(
|
|
40
|
+
self,
|
|
41
|
+
ctx: antlr4.ParserRuleContext,
|
|
42
|
+
) -> Region:
|
|
43
|
+
"""Create a `Region` from the given context."""
|
|
44
|
+
|
|
45
|
+
raise NotImplementedError() # pragma: no cover
|
|
46
|
+
|
|
47
|
+
# ----------------------------------------------------------------------
|
|
48
|
+
def GetChildren(self, ctx: antlr4.ParserRuleContext) -> list[object]:
|
|
49
|
+
"""Return the results of visiting the children of the given context."""
|
|
50
|
+
|
|
51
|
+
prev_num_stack_items = len(self._stack)
|
|
52
|
+
|
|
53
|
+
cast(antlr4.ParseTreeVisitor, self).visitChildren(ctx)
|
|
54
|
+
|
|
55
|
+
results = self._stack[prev_num_stack_items:]
|
|
56
|
+
del self._stack[prev_num_stack_items:]
|
|
57
|
+
|
|
58
|
+
return results
|
|
59
|
+
|
|
60
|
+
# ----------------------------------------------------------------------
|
|
61
|
+
# | Protected Methods
|
|
62
|
+
def _OnProgress(self, end_line: int) -> None:
|
|
63
|
+
if end_line > self._current_line:
|
|
64
|
+
self._current_line = end_line
|
|
65
|
+
self._on_progress_func(end_line)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ----------------------------------------------------------------------
|
|
69
|
+
class InsignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
|
|
70
|
+
"""Mixin that adds functionality used for grammars that ignore insignificant whitespace."""
|
|
71
|
+
|
|
72
|
+
# ----------------------------------------------------------------------
|
|
73
|
+
def CreateRegion(
|
|
74
|
+
self,
|
|
75
|
+
ctx: antlr4.ParserRuleContext,
|
|
76
|
+
) -> Region:
|
|
77
|
+
"""Create a `Region` from the given context."""
|
|
78
|
+
|
|
79
|
+
start_token = ctx.start
|
|
80
|
+
stop_token = ctx.stop
|
|
81
|
+
|
|
82
|
+
if start_token is None or stop_token is None:
|
|
83
|
+
msg = "Context does not have start or stop token"
|
|
84
|
+
raise ValueError(msg)
|
|
85
|
+
|
|
86
|
+
return Region(
|
|
87
|
+
self.filename,
|
|
88
|
+
Location(start_token.line, start_token.column),
|
|
89
|
+
Location(stop_token.line, stop_token.column + len(stop_token.text)),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ----------------------------------------------------------------------
|
|
94
|
+
class SignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
|
|
95
|
+
"""Mixin that adds functionality used for grammars that treat whitespace as significant."""
|
|
96
|
+
|
|
97
|
+
# ----------------------------------------------------------------------
|
|
98
|
+
def __init__(
|
|
99
|
+
self,
|
|
100
|
+
dedent_token: int,
|
|
101
|
+
newline_token: int,
|
|
102
|
+
newline_token_string: str,
|
|
103
|
+
) -> None:
|
|
104
|
+
self._dedent_token = dedent_token
|
|
105
|
+
self._newline_token = newline_token
|
|
106
|
+
self._newline_token_string = newline_token_string
|
|
107
|
+
|
|
108
|
+
# ----------------------------------------------------------------------
|
|
109
|
+
def CreateRegion( # noqa: D102
|
|
110
|
+
self,
|
|
111
|
+
ctx: antlr4.ParserRuleContext,
|
|
112
|
+
) -> Region:
|
|
113
|
+
assert isinstance(ctx.start, antlr4.Token), ctx.start
|
|
114
|
+
assert isinstance(ctx.stop, antlr4.Token), ctx.stop
|
|
115
|
+
|
|
116
|
+
if ctx.stop.type == self._dedent_token:
|
|
117
|
+
stop_line = ctx.stop.line
|
|
118
|
+
stop_col = ctx.stop.column
|
|
119
|
+
|
|
120
|
+
elif ctx.stop.type == self._newline_token and ctx.stop.text == self._newline_token_string:
|
|
121
|
+
if ctx.stop.line == ctx.start.line:
|
|
122
|
+
# This is the scenario where the statement is followed by a dedent followed by another
|
|
123
|
+
# statement. We don't want the range of this item to overlap with the range of the
|
|
124
|
+
# next item, so use the values as they are, even though it means that a statement
|
|
125
|
+
# that terminates with a newline will not have the newline here.
|
|
126
|
+
stop_line = ctx.stop.line
|
|
127
|
+
stop_col = ctx.stop.column
|
|
128
|
+
else:
|
|
129
|
+
stop_line = ctx.stop.line
|
|
130
|
+
stop_col = ctx.stop.column if ctx.stop.column == 0 else ctx.start.column
|
|
131
|
+
|
|
132
|
+
else:
|
|
133
|
+
stop_line = ctx.stop.line
|
|
134
|
+
|
|
135
|
+
content = ctx.stop.text
|
|
136
|
+
lines = content.split("\n")
|
|
137
|
+
|
|
138
|
+
if ctx.stop.type == self._newline_token:
|
|
139
|
+
assert content.startswith("\n"), content
|
|
140
|
+
assert len(lines) == 2, lines # noqa: PLR2004
|
|
141
|
+
|
|
142
|
+
stop_col = len(lines[-1])
|
|
143
|
+
|
|
144
|
+
if stop_line == ctx.stop.line:
|
|
145
|
+
stop_col += ctx.stop.column
|
|
146
|
+
|
|
147
|
+
stop_line += len(lines) - 1
|
|
148
|
+
|
|
149
|
+
self._OnProgress(stop_line)
|
|
150
|
+
|
|
151
|
+
return Region(
|
|
152
|
+
self.filename,
|
|
153
|
+
Location(ctx.start.line, ctx.start.column + 1),
|
|
154
|
+
Location(stop_line, stop_col),
|
|
155
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|