dbrownell-parserlib 0.9.0__tar.gz → 0.10.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.9.0 → dbrownell_parserlib-0.10.0}/PKG-INFO +8 -10
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/README.md +7 -9
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/pyproject.toml +1 -1
- dbrownell_parserlib-0.10.0/src/dbrownell_ParserLib/__init__.py +6 -0
- dbrownell_parserlib-0.10.0/src/dbrownell_ParserLib/antlr/__init__.py +1 -0
- dbrownell_parserlib-0.10.0/src/dbrownell_ParserLib/multiline_strings.py +124 -0
- dbrownell_parserlib-0.9.0/src/dbrownell_ParserLib/__init__.py +0 -44
- dbrownell_parserlib-0.9.0/src/dbrownell_ParserLib/antlr/__init__.py +0 -19
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/antlr/antlr_parser.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/antlr/antlr_visitor_mixins.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/__init__.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/antlr-4.13.2-complete.jar +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/errors.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/expression.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/location.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/py.typed +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/region.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/terminal_expression.py +0 -0
- {dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/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.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Functionality useful when creating parsers.
|
|
5
5
|
Author: Dave Brownell
|
|
6
6
|
Author-email: Dave Brownell <github@DavidBrownell.com>
|
|
@@ -85,7 +85,7 @@ Use `BuildAntlrGrammar` to generate the lexer and parser:
|
|
|
85
85
|
```python
|
|
86
86
|
from pathlib import Path
|
|
87
87
|
|
|
88
|
-
from dbrownell_ParserLib import BuildAntlrGrammar
|
|
88
|
+
from dbrownell_ParserLib.antlr.build_antlr_grammar import BuildAntlrGrammar
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
BuildAntlrGrammar(
|
|
@@ -101,11 +101,9 @@ Implement a visitor that converts ANTLR parse trees to Expression objects:
|
|
|
101
101
|
```python
|
|
102
102
|
from dataclasses import dataclass
|
|
103
103
|
|
|
104
|
-
from dbrownell_ParserLib import
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
TerminalExpression,
|
|
108
|
-
)
|
|
104
|
+
from dbrownell_ParserLib.antlr.antlr_visitor_mixins import InsignificantWhitespaceAntlrVisitorMixin
|
|
105
|
+
from dbrownell_ParserLib.expression import Expression
|
|
106
|
+
from dbrownell_ParserLib.terminal_expression import TerminalExpression
|
|
109
107
|
|
|
110
108
|
from CalculatorVisitor import CalculatorVisitor as GeneratedVisitor
|
|
111
109
|
|
|
@@ -147,7 +145,7 @@ class CalculatorVisitor(InsignificantWhitespaceAntlrVisitorMixin, GeneratedVisit
|
|
|
147
145
|
Use `CreateAntlrParser` to build a callable parser:
|
|
148
146
|
|
|
149
147
|
```python
|
|
150
|
-
from dbrownell_ParserLib import CreateAntlrParser
|
|
148
|
+
from dbrownell_ParserLib.antlr.antlr_parser import CreateAntlrParser
|
|
151
149
|
|
|
152
150
|
|
|
153
151
|
parser = CreateAntlrParser(
|
|
@@ -162,7 +160,7 @@ parser = CreateAntlrParser(
|
|
|
162
160
|
Parse single files, multiple files, or entire workspaces:
|
|
163
161
|
|
|
164
162
|
```python
|
|
165
|
-
from dbrownell_ParserLib import Error
|
|
163
|
+
from dbrownell_ParserLib.errors import Error
|
|
166
164
|
|
|
167
165
|
|
|
168
166
|
# Parse a single file
|
|
@@ -187,7 +185,7 @@ Use the visitor pattern to process your AST:
|
|
|
187
185
|
```python
|
|
188
186
|
from contextlib import contextmanager
|
|
189
187
|
|
|
190
|
-
from dbrownell_ParserLib import ExpressionVisitorHelper, VisitResult
|
|
188
|
+
from dbrownell_ParserLib.visitors import ExpressionVisitorHelper, VisitResult
|
|
191
189
|
|
|
192
190
|
|
|
193
191
|
class EvaluatorVisitor(ExpressionVisitorHelper):
|
|
@@ -63,7 +63,7 @@ Use `BuildAntlrGrammar` to generate the lexer and parser:
|
|
|
63
63
|
```python
|
|
64
64
|
from pathlib import Path
|
|
65
65
|
|
|
66
|
-
from dbrownell_ParserLib import BuildAntlrGrammar
|
|
66
|
+
from dbrownell_ParserLib.antlr.build_antlr_grammar import BuildAntlrGrammar
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
BuildAntlrGrammar(
|
|
@@ -79,11 +79,9 @@ Implement a visitor that converts ANTLR parse trees to Expression objects:
|
|
|
79
79
|
```python
|
|
80
80
|
from dataclasses import dataclass
|
|
81
81
|
|
|
82
|
-
from dbrownell_ParserLib import
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
TerminalExpression,
|
|
86
|
-
)
|
|
82
|
+
from dbrownell_ParserLib.antlr.antlr_visitor_mixins import InsignificantWhitespaceAntlrVisitorMixin
|
|
83
|
+
from dbrownell_ParserLib.expression import Expression
|
|
84
|
+
from dbrownell_ParserLib.terminal_expression import TerminalExpression
|
|
87
85
|
|
|
88
86
|
from CalculatorVisitor import CalculatorVisitor as GeneratedVisitor
|
|
89
87
|
|
|
@@ -125,7 +123,7 @@ class CalculatorVisitor(InsignificantWhitespaceAntlrVisitorMixin, GeneratedVisit
|
|
|
125
123
|
Use `CreateAntlrParser` to build a callable parser:
|
|
126
124
|
|
|
127
125
|
```python
|
|
128
|
-
from dbrownell_ParserLib import CreateAntlrParser
|
|
126
|
+
from dbrownell_ParserLib.antlr.antlr_parser import CreateAntlrParser
|
|
129
127
|
|
|
130
128
|
|
|
131
129
|
parser = CreateAntlrParser(
|
|
@@ -140,7 +138,7 @@ parser = CreateAntlrParser(
|
|
|
140
138
|
Parse single files, multiple files, or entire workspaces:
|
|
141
139
|
|
|
142
140
|
```python
|
|
143
|
-
from dbrownell_ParserLib import Error
|
|
141
|
+
from dbrownell_ParserLib.errors import Error
|
|
144
142
|
|
|
145
143
|
|
|
146
144
|
# Parse a single file
|
|
@@ -165,7 +163,7 @@ Use the visitor pattern to process your AST:
|
|
|
165
163
|
```python
|
|
166
164
|
from contextlib import contextmanager
|
|
167
165
|
|
|
168
|
-
from dbrownell_ParserLib import ExpressionVisitorHelper, VisitResult
|
|
166
|
+
from dbrownell_ParserLib.visitors import ExpressionVisitorHelper, VisitResult
|
|
169
167
|
|
|
170
168
|
|
|
171
169
|
class EvaluatorVisitor(ExpressionVisitorHelper):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dbrownell-parserlib"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.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:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# noqa: D104
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Functionality used when parsing multiline strings."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from dbrownell_ParserLib.errors import CreateErrorType
|
|
6
|
+
from dbrownell_ParserLib.region import Location, Region
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ----------------------------------------------------------------------
|
|
10
|
+
MisalignedMultilineStringError = CreateErrorType(
|
|
11
|
+
"All lines in a multiline string must be vertically aligned with the opening token."
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ----------------------------------------------------------------------
|
|
16
|
+
def ExtractMultilineString(
|
|
17
|
+
content: str,
|
|
18
|
+
opening_token_region: Region,
|
|
19
|
+
opening_token: str = '"""', # noqa: S107
|
|
20
|
+
closing_token: str = '"""', # noqa: S107
|
|
21
|
+
tab_size: int = 4,
|
|
22
|
+
) -> str:
|
|
23
|
+
"""Extract a multiline string from the given content, ensuring that all lines are vertically aligned with the opening token."""
|
|
24
|
+
|
|
25
|
+
assert content.startswith(opening_token), content
|
|
26
|
+
content = content[len(opening_token) :]
|
|
27
|
+
|
|
28
|
+
assert content.endswith(closing_token), content
|
|
29
|
+
content = content[: -len(closing_token)]
|
|
30
|
+
|
|
31
|
+
lines = content.splitlines()
|
|
32
|
+
|
|
33
|
+
# Handle the special case where the multiline string begins at column 1. In this case, the content
|
|
34
|
+
# should end with a newline.
|
|
35
|
+
if content.endswith("\n") and opening_token_region.begin.column == 1:
|
|
36
|
+
lines.append("")
|
|
37
|
+
|
|
38
|
+
# Ensure that there is a newline immediately following the opening token
|
|
39
|
+
if lines[0]:
|
|
40
|
+
# This means that there was content immediately following the opening token when a newline was expected.
|
|
41
|
+
location = Location(
|
|
42
|
+
opening_token_region.begin.line,
|
|
43
|
+
opening_token_region.begin.column + len(opening_token),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
raise MisalignedMultilineStringError.CreateAsException(
|
|
47
|
+
Region(opening_token_region.filename, location, location)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
lines = lines[1:]
|
|
51
|
+
assert lines
|
|
52
|
+
|
|
53
|
+
# Ensure that the closing token is on its own line
|
|
54
|
+
result = _CalcPrefixColumn(lines[-1], tab_size, None)
|
|
55
|
+
|
|
56
|
+
if result.column != opening_token_region.begin.column:
|
|
57
|
+
location = Location(opening_token_region.begin.line + len(lines) + 1, result.column)
|
|
58
|
+
|
|
59
|
+
raise MisalignedMultilineStringError.CreateAsException(
|
|
60
|
+
Region(opening_token_region.filename, location, location)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
lines = lines[:-1]
|
|
64
|
+
|
|
65
|
+
# Process the content
|
|
66
|
+
acceptable_prefix_column_values = {1, opening_token_region.begin.column}
|
|
67
|
+
escaped_closing_token = "".join(f"\\{c}" for c in closing_token)
|
|
68
|
+
|
|
69
|
+
# Ensure that all lines are vertically aligned with the opening token
|
|
70
|
+
for line_index, line in enumerate(lines):
|
|
71
|
+
result = _CalcPrefixColumn(line, tab_size, opening_token_region.begin.column)
|
|
72
|
+
|
|
73
|
+
if result.column not in acceptable_prefix_column_values:
|
|
74
|
+
location = Location(opening_token_region.begin.line + line_index + 1, result.column)
|
|
75
|
+
|
|
76
|
+
raise MisalignedMultilineStringError.CreateAsException(
|
|
77
|
+
Region(opening_token_region.filename, location, location)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
normalized_line = line[result.num_chars :]
|
|
81
|
+
|
|
82
|
+
if normalized_line.isspace():
|
|
83
|
+
normalized_line = ""
|
|
84
|
+
else:
|
|
85
|
+
normalized_line = normalized_line.replace(escaped_closing_token, closing_token)
|
|
86
|
+
|
|
87
|
+
lines[line_index] = normalized_line
|
|
88
|
+
|
|
89
|
+
# Handle the special case where the multiline string consists of all newlines
|
|
90
|
+
if lines and all(not line for line in lines):
|
|
91
|
+
return "".join("\n" * len(lines))
|
|
92
|
+
|
|
93
|
+
return "\n".join(lines)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# ----------------------------------------------------------------------
|
|
97
|
+
# ----------------------------------------------------------------------
|
|
98
|
+
# ----------------------------------------------------------------------
|
|
99
|
+
@dataclass(frozen=True)
|
|
100
|
+
class _CalcPrefixColumnResult:
|
|
101
|
+
column: int
|
|
102
|
+
num_chars: int
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _CalcPrefixColumn(line: str, tab_size: int, max_column: int | None) -> _CalcPrefixColumnResult:
|
|
106
|
+
max_column = max_column or 99999999
|
|
107
|
+
|
|
108
|
+
column = 1
|
|
109
|
+
num_chars = 0
|
|
110
|
+
|
|
111
|
+
for char in line:
|
|
112
|
+
if column >= max_column:
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
if char == " ":
|
|
116
|
+
column += 1
|
|
117
|
+
elif char == "\t":
|
|
118
|
+
column += tab_size
|
|
119
|
+
else:
|
|
120
|
+
break
|
|
121
|
+
|
|
122
|
+
num_chars += 1
|
|
123
|
+
|
|
124
|
+
return _CalcPrefixColumnResult(column, num_chars)
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# noqa: D104
|
|
2
|
-
|
|
3
|
-
from importlib.metadata import version
|
|
4
|
-
|
|
5
|
-
from dbrownell_ParserLib.antlr import (
|
|
6
|
-
AntlrParser,
|
|
7
|
-
AntlrVisitorMixinBase,
|
|
8
|
-
BuildAntlrGrammar,
|
|
9
|
-
CreateAntlrParser,
|
|
10
|
-
InsignificantWhitespaceAntlrVisitorMixin,
|
|
11
|
-
SignificantWhitespaceAntlrVisitorMixin,
|
|
12
|
-
)
|
|
13
|
-
from dbrownell_ParserLib.errors import CreateErrorType, Error, ErrorException, PythonError
|
|
14
|
-
from dbrownell_ParserLib.expression import Expression
|
|
15
|
-
from dbrownell_ParserLib.location import Location
|
|
16
|
-
from dbrownell_ParserLib.region import Region
|
|
17
|
-
from dbrownell_ParserLib.terminal_expression import TerminalExpression
|
|
18
|
-
from dbrownell_ParserLib.visitors import ExpressionVisitor, ExpressionVisitorHelper, VisitResult
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# ----------------------------------------------------------------------
|
|
22
|
-
__all__ = [
|
|
23
|
-
"AntlrParser",
|
|
24
|
-
"AntlrVisitorMixinBase",
|
|
25
|
-
"BuildAntlrGrammar",
|
|
26
|
-
"CreateAntlrParser",
|
|
27
|
-
"CreateErrorType",
|
|
28
|
-
"Error",
|
|
29
|
-
"ErrorException",
|
|
30
|
-
"Expression",
|
|
31
|
-
"ExpressionVisitor",
|
|
32
|
-
"ExpressionVisitorHelper",
|
|
33
|
-
"InsignificantWhitespaceAntlrVisitorMixin",
|
|
34
|
-
"Location",
|
|
35
|
-
"PythonError",
|
|
36
|
-
"Region",
|
|
37
|
-
"SignificantWhitespaceAntlrVisitorMixin",
|
|
38
|
-
"TerminalExpression",
|
|
39
|
-
"VisitResult",
|
|
40
|
-
"__version__",
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
__version__ = version("dbrownell_ParserLib")
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# noqa: D104
|
|
2
|
-
from dbrownell_ParserLib.antlr.build_antlr_grammar import BuildAntlrGrammar
|
|
3
|
-
from dbrownell_ParserLib.antlr.antlr_parser import AntlrParser, CreateAntlrParser
|
|
4
|
-
from dbrownell_ParserLib.antlr.antlr_visitor_mixins import (
|
|
5
|
-
AntlrVisitorMixinBase,
|
|
6
|
-
InsignificantWhitespaceAntlrVisitorMixin,
|
|
7
|
-
SignificantWhitespaceAntlrVisitorMixin,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# ----------------------------------------------------------------------
|
|
12
|
-
__all__ = [
|
|
13
|
-
"AntlrParser",
|
|
14
|
-
"AntlrVisitorMixinBase",
|
|
15
|
-
"BuildAntlrGrammar",
|
|
16
|
-
"CreateAntlrParser",
|
|
17
|
-
"InsignificantWhitespaceAntlrVisitorMixin",
|
|
18
|
-
"SignificantWhitespaceAntlrVisitorMixin",
|
|
19
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/expression.py
RENAMED
|
File without changes
|
{dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/location.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbrownell_parserlib-0.9.0 → dbrownell_parserlib-0.10.0}/src/dbrownell_ParserLib/visitors.py
RENAMED
|
File without changes
|