dbrownell-parserlib 0.8.0__tar.gz → 0.8.2__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 (16) hide show
  1. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/PKG-INFO +1 -1
  2. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/pyproject.toml +1 -1
  3. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/antlr/antlr_parser.py +6 -1
  4. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/antlr/antlr_visitor_mixins.py +58 -46
  5. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/expression.py +1 -1
  6. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/README.md +0 -0
  7. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/__init__.py +0 -0
  8. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/antlr/__init__.py +0 -0
  9. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/__init__.py +0 -0
  10. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/antlr-4.13.2-complete.jar +0 -0
  11. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/errors.py +0 -0
  12. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/location.py +0 -0
  13. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/py.typed +0 -0
  14. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/region.py +0 -0
  15. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/terminal_expression.py +0 -0
  16. {dbrownell_parserlib-0.8.0 → dbrownell_parserlib-0.8.2}/src/dbrownell_ParserLib/visitors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dbrownell-parserlib
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: Functionality useful when creating parsers.
5
5
  Author: Dave Brownell
6
6
  Author-email: Dave Brownell <github@DavidBrownell.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dbrownell-parserlib"
3
- version = "0.8.0"
3
+ version = "0.8.2"
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:
@@ -479,8 +479,13 @@ class _ErrorListener(antlr4.DiagnosticErrorListener):
479
479
  msg: str,
480
480
  e: antlr4.RecognitionException | None,
481
481
  ) -> None:
482
+ if msg.startswith("report"):
483
+ # I don't think that these should be errors
484
+ assert e is None, e
485
+ return
486
+
482
487
  location = Location(line, column + 1)
483
- error = Error(msg, Region(self._source, location, location))
488
+ error = Error(f"Syntax error: {msg}", Region(self._source, location, location))
484
489
  ex = AntlrParserException(error)
485
490
 
486
491
  if e is None:
@@ -1,5 +1,7 @@
1
1
  """Various ANTLR visitor mixins that can be used to add functionality to the generated visitor classes."""
2
2
 
3
+ import re
4
+
3
5
  from abc import ABC, abstractmethod
4
6
  from typing import cast, override, TYPE_CHECKING
5
7
 
@@ -35,14 +37,36 @@ class AntlrVisitorMixinBase(ABC):
35
37
  self._current_line: int = 0
36
38
 
37
39
  # ----------------------------------------------------------------------
38
- @abstractmethod
39
40
  def CreateRegion(
40
41
  self,
41
- ctx: antlr4.ParserRuleContext,
42
+ ctx: antlr4.TerminalNode | antlr4.ParserRuleContext,
42
43
  ) -> Region:
43
44
  """Create a `Region` from the given context."""
44
45
 
45
- raise NotImplementedError() # pragma: no cover
46
+ if isinstance(ctx, antlr4.TerminalNode):
47
+ token = cast(antlr4.Token, ctx.symbol) # ty: ignore[unresolved-attribute]
48
+
49
+ assert token.column is not None
50
+
51
+ start_line = token.line
52
+ start_col = token.column + 1
53
+ end_line = token.line
54
+ end_col = token.column + 1 + len(token.text)
55
+
56
+ assert start_line is not None
57
+ assert end_line is not None
58
+
59
+ region = Region(
60
+ self.filename,
61
+ Location(start_line, start_col),
62
+ Location(end_line, end_col),
63
+ )
64
+ else:
65
+ region = self._CreateRegionFromRule(ctx)
66
+
67
+ self._OnProgress(region.end.line)
68
+
69
+ return region
46
70
 
47
71
  # ----------------------------------------------------------------------
48
72
  def GetChildren(self, ctx: antlr4.ParserRuleContext) -> list[object]:
@@ -64,19 +88,17 @@ class AntlrVisitorMixinBase(ABC):
64
88
  self._current_line = end_line
65
89
  self._on_progress_func(end_line)
66
90
 
91
+ # ----------------------------------------------------------------------
92
+ @abstractmethod
93
+ def _CreateRegionFromRule(self, ctx: antlr4.ParserRuleContext) -> Region: ...
94
+
67
95
 
68
96
  # ----------------------------------------------------------------------
69
97
  class InsignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
70
98
  """Mixin that adds functionality used for grammars that ignore insignificant whitespace."""
71
99
 
72
100
  # ----------------------------------------------------------------------
73
- @override
74
- def CreateRegion(
75
- self,
76
- ctx: antlr4.ParserRuleContext,
77
- ) -> Region:
78
- """Create a `Region` from the given context."""
79
-
101
+ def _CreateRegionFromRule(self, ctx: antlr4.ParserRuleContext) -> Region:
80
102
  start_token = ctx.start
81
103
  stop_token = ctx.stop
82
104
 
@@ -84,10 +106,18 @@ class InsignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
84
106
  msg = "Context does not have start or stop token"
85
107
  raise ValueError(msg)
86
108
 
109
+ start_line = start_token.line
110
+ start_col = start_token.column + 1
111
+ end_line = stop_token.line
112
+ end_col = stop_token.column + 1 + len(stop_token.text)
113
+
114
+ assert start_line is not None
115
+ assert end_line is not None
116
+
87
117
  return Region(
88
118
  self.filename,
89
- Location(start_token.line, start_token.column),
90
- Location(stop_token.line, stop_token.column + len(stop_token.text)),
119
+ Location(start_line, start_col),
120
+ Location(end_line, end_col),
91
121
  )
92
122
 
93
123
 
@@ -106,52 +136,34 @@ class SignificantWhitespaceAntlrVisitorMixin(AntlrVisitorMixinBase):
106
136
  self._newline_token = newline_token
107
137
  self._newline_token_string = newline_token_string
108
138
 
139
+ self._newline_indent_regex = re.compile(r"^\r?\n[ \t]*$")
140
+
109
141
  # ----------------------------------------------------------------------
110
142
  @override
111
- def CreateRegion(
143
+ def _CreateRegionFromRule(
112
144
  self,
113
145
  ctx: antlr4.ParserRuleContext,
114
146
  ) -> Region:
115
147
  assert isinstance(ctx.start, antlr4.Token), ctx.start
116
148
  assert isinstance(ctx.stop, antlr4.Token), ctx.stop
117
149
 
118
- if ctx.stop.type == self._dedent_token:
119
- stop_line = ctx.stop.line
120
- stop_col = ctx.stop.column
121
-
122
- elif ctx.stop.type == self._newline_token and ctx.stop.text == self._newline_token_string:
123
- if ctx.stop.line == ctx.start.line:
124
- # This is the scenario where the statement is followed by a dedent followed by another
125
- # statement. We don't want the range of this item to overlap with the range of the
126
- # next item, so use the values as they are, even though it means that a statement
127
- # that terminates with a newline will not have the newline here.
128
- stop_line = ctx.stop.line
129
- stop_col = ctx.stop.column
130
- else:
131
- stop_line = ctx.stop.line
132
- stop_col = ctx.stop.column if ctx.stop.column == 0 else ctx.start.column
133
-
134
- else:
135
- stop_line = ctx.stop.line
136
-
137
- content = ctx.stop.text
138
- lines = content.split("\n")
139
-
140
- if ctx.stop.type == self._newline_token:
141
- assert content.startswith("\n"), content
142
- assert len(lines) == 2, lines # noqa: PLR2004
143
-
144
- stop_col = len(lines[-1])
145
-
146
- if stop_line == ctx.stop.line:
147
- stop_col += ctx.stop.column
150
+ if ctx.stop.text == self._newline_token_string or self._newline_indent_regex.match(ctx.stop.text):
151
+ assert ctx.stop.line == ctx.start.line or ctx.stop.line - 1 == ctx.start.line, (
152
+ ctx.start.line,
153
+ ctx.stop.line,
154
+ )
148
155
 
149
- stop_line += len(lines) - 1
156
+ stop_line = ctx.start.line
157
+ stop_column = ctx.start.column + 1 + len(ctx.start.text)
150
158
 
151
- self._OnProgress(stop_line)
159
+ return Region(
160
+ self.filename,
161
+ Location(ctx.start.line, ctx.start.column + 1),
162
+ Location(stop_line, stop_column),
163
+ )
152
164
 
153
165
  return Region(
154
166
  self.filename,
155
167
  Location(ctx.start.line, ctx.start.column + 1),
156
- Location(stop_line, stop_col),
168
+ Location(ctx.stop.line, ctx.stop.column + 1),
157
169
  )
@@ -202,7 +202,7 @@ class Expression:
202
202
  # | Protected Types
203
203
  # |
204
204
  # ----------------------------------------------------------------------
205
- _GenerateAcceptDetailsResultType = Generator[tuple[str, list[Self]]]
205
+ _GenerateAcceptDetailsResultType = Generator[tuple[str, Self]]
206
206
  _GetAcceptChildrenResultType = tuple[str, Iterable[Self]] | None
207
207
 
208
208
  # ----------------------------------------------------------------------