dbrownell-parserlib 0.8.2__tar.gz → 0.8.4__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.2 → dbrownell_parserlib-0.8.4}/PKG-INFO +151 -3
  2. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/README.md +150 -2
  3. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/pyproject.toml +1 -1
  4. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/__init__.py +0 -0
  5. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/antlr/__init__.py +0 -0
  6. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/antlr/antlr_parser.py +0 -0
  7. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/antlr/antlr_visitor_mixins.py +0 -0
  8. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/__init__.py +0 -0
  9. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/antlr/build_antlr_grammar/antlr-4.13.2-complete.jar +0 -0
  10. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/errors.py +0 -0
  11. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/expression.py +0 -0
  12. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/location.py +0 -0
  13. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/py.typed +0 -0
  14. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/region.py +0 -0
  15. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/src/dbrownell_ParserLib/terminal_expression.py +0 -0
  16. {dbrownell_parserlib-0.8.2 → dbrownell_parserlib-0.8.4}/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.2
3
+ Version: 0.8.4
4
4
  Summary: Functionality useful when creating parsers.
5
5
  Author: Dave Brownell
6
6
  Author-email: Dave Brownell <github@DavidBrownell.com>
@@ -47,10 +47,158 @@ Description-Content-Type: text/markdown
47
47
  - [License](#license)
48
48
 
49
49
  ## Overview
50
- TODO: Complete this section
50
+ `dbrownell_ParserLib` is a Python library that provides utility functionality for creating parsers, with a primary focus on [ANTLR](https://antlr.org) (Another Tool for Language Recognition) integration. The library simplifies the process of building parsers that produce strongly-typed abstract syntax trees (ASTs) with comprehensive source location tracking.
51
+
52
+ ### Key Features
53
+ - **ANTLR Integration**: Streamlined wrapper around ANTLR for Python, handling grammar compilation and parser generation
54
+ - **AST Representation**: Expression-based AST nodes with automatic parent-child relationship management
55
+ - **Source Location Tracking**: Every AST node tracks its source file location (filename, line, column ranges) for detailed error reporting
56
+ - **Visitor Pattern**: Flexible visitor pattern implementation with fine-grained traversal control
57
+ - **Error Handling**: Rich error objects that associate messages with source locations and extract Python exception tracebacks
58
+ - **Multi-threaded Parsing**: Built-in support for parsing multiple files concurrently
59
+ - **Workspace Support**: Parse entire directory trees with customizable file filtering
60
+ - **Whitespace Handling**: Mixins for both insignificant and significant whitespace grammars (e.g., Python-like indentation)
51
61
 
52
62
  ### How to use `dbrownell_ParserLib`
53
- TODO: Complete this section
63
+
64
+ The typical workflow for creating a parser with this library involves the following steps. For detailed examples, see the test files in the repository, particularly the end-to-end tests that demonstrate complete parsing workflows.
65
+
66
+
67
+ #### 1. Define an ANTLR Grammar
68
+ Create a `.g4` grammar file defining your language syntax:
69
+
70
+ ```antlr
71
+ grammar Calculator;
72
+
73
+ expr : expr ('*'|'/') expr # BinaryOp
74
+ | expr ('+'|'-') expr # BinaryOp
75
+ | INT # Number
76
+ ;
77
+
78
+ INT : [0-9]+ ;
79
+ WS : [ \t\n\r]+ -> skip ;
80
+ ```
81
+
82
+ #### 2. Build the Grammar
83
+ Use `BuildAntlrGrammar` to generate the lexer and parser:
84
+
85
+ ```python
86
+ from pathlib import Path
87
+
88
+ from dbrownell_ParserLib import BuildAntlrGrammar
89
+
90
+
91
+ BuildAntlrGrammar(
92
+ dm, # DoneManager instance
93
+ Path("Calculator.g4"),
94
+ Path("output_dir"),
95
+ )
96
+ ```
97
+
98
+ #### 3. Create Custom Visitor
99
+ Implement a visitor that converts ANTLR parse trees to Expression objects:
100
+
101
+ ```python
102
+ from dataclasses import dataclass
103
+
104
+ from dbrownell_ParserLib import (
105
+ Expression,
106
+ InsignificantWhitespaceAntlrVisitorMixin,
107
+ TerminalExpression,
108
+ )
109
+
110
+ from CalculatorVisitor import CalculatorVisitor as GeneratedVisitor
111
+
112
+
113
+ @dataclass(eq=False)
114
+ class BinaryExpression(Expression):
115
+ left: Expression
116
+ operator: TerminalExpression[str]
117
+ right: Expression
118
+
119
+ def _GenerateAcceptDetails(self):
120
+ yield "left", self.left
121
+ yield "operator", self.operator
122
+ yield "right", self.right
123
+
124
+
125
+ class CalculatorVisitor(InsignificantWhitespaceAntlrVisitorMixin, GeneratedVisitor):
126
+ def visitExpr(self, ctx):
127
+ children = self.GetChildren(ctx)
128
+ assert len(children) == 2, children
129
+
130
+ self._stack.append(
131
+ BinaryExpression(
132
+ self.CreateRegion(ctx),
133
+ children[0],
134
+ TerminalExpression[str](self.CreateRegion(ctx.children[1]), ctx.children[1].getText()),
135
+
136
+ children[1],
137
+ )
138
+ )
139
+
140
+ def visitNumber(self, ctx):
141
+ self._stack.append(
142
+ TerminalExpression(self.CreateRegion(ctx), int(ctx.getText()))
143
+ )
144
+ ```
145
+
146
+ #### 4. Create Parser Instance
147
+ Use `CreateAntlrParser` to build a callable parser:
148
+
149
+ ```python
150
+ from dbrownell_ParserLib import CreateAntlrParser
151
+
152
+
153
+ parser = CreateAntlrParser(
154
+ CalculatorLexer,
155
+ CalculatorParser,
156
+ CalculatorVisitor,
157
+ lambda p: p.expr(), # Entry point rule
158
+ )
159
+ ```
160
+
161
+ #### 5. Parse Files
162
+ Parse single files, multiple files, or entire workspaces:
163
+
164
+ ```python
165
+ from dbrownell_ParserLib import Error
166
+
167
+
168
+ # Parse a single file
169
+ results = parser(dm, Path("input.txt"), None)
170
+
171
+ # Parse multiple files
172
+ results = parser(dm, [Path("file1.txt"), Path("file2.txt")], None)
173
+
174
+ # Check results
175
+ for filepath, result in results.items():
176
+ if isinstance(result, Error):
177
+ print(f"Parse error in {filepath}: {result}")
178
+ else:
179
+ # result is the visitor containing the parsed AST
180
+ ast = result._stack[0]
181
+ # Process the AST
182
+ ```
183
+
184
+ #### 6. Traverse the AST
185
+ Use the visitor pattern to process your AST:
186
+
187
+ ```python
188
+ from contextlib import contextmanager
189
+
190
+ from dbrownell_ParserLib import ExpressionVisitorHelper, VisitResult
191
+
192
+
193
+ class EvaluatorVisitor(ExpressionVisitorHelper):
194
+ @contextmanager
195
+ def OnBinaryExpression(self, expression):
196
+ # Process binary expressions
197
+ yield VisitResult.Continue
198
+
199
+
200
+ ast.Accept(EvaluatorVisitor())
201
+ ```
54
202
 
55
203
  <!-- Content below this delimiter will be copied to the generated README.md file. DO NOT REMOVE THIS COMMENT, as it will cause regeneration to fail. -->
56
204
 
@@ -25,10 +25,158 @@
25
25
  - [License](#license)
26
26
 
27
27
  ## Overview
28
- TODO: Complete this section
28
+ `dbrownell_ParserLib` is a Python library that provides utility functionality for creating parsers, with a primary focus on [ANTLR](https://antlr.org) (Another Tool for Language Recognition) integration. The library simplifies the process of building parsers that produce strongly-typed abstract syntax trees (ASTs) with comprehensive source location tracking.
29
+
30
+ ### Key Features
31
+ - **ANTLR Integration**: Streamlined wrapper around ANTLR for Python, handling grammar compilation and parser generation
32
+ - **AST Representation**: Expression-based AST nodes with automatic parent-child relationship management
33
+ - **Source Location Tracking**: Every AST node tracks its source file location (filename, line, column ranges) for detailed error reporting
34
+ - **Visitor Pattern**: Flexible visitor pattern implementation with fine-grained traversal control
35
+ - **Error Handling**: Rich error objects that associate messages with source locations and extract Python exception tracebacks
36
+ - **Multi-threaded Parsing**: Built-in support for parsing multiple files concurrently
37
+ - **Workspace Support**: Parse entire directory trees with customizable file filtering
38
+ - **Whitespace Handling**: Mixins for both insignificant and significant whitespace grammars (e.g., Python-like indentation)
29
39
 
30
40
  ### How to use `dbrownell_ParserLib`
31
- TODO: Complete this section
41
+
42
+ The typical workflow for creating a parser with this library involves the following steps. For detailed examples, see the test files in the repository, particularly the end-to-end tests that demonstrate complete parsing workflows.
43
+
44
+
45
+ #### 1. Define an ANTLR Grammar
46
+ Create a `.g4` grammar file defining your language syntax:
47
+
48
+ ```antlr
49
+ grammar Calculator;
50
+
51
+ expr : expr ('*'|'/') expr # BinaryOp
52
+ | expr ('+'|'-') expr # BinaryOp
53
+ | INT # Number
54
+ ;
55
+
56
+ INT : [0-9]+ ;
57
+ WS : [ \t\n\r]+ -> skip ;
58
+ ```
59
+
60
+ #### 2. Build the Grammar
61
+ Use `BuildAntlrGrammar` to generate the lexer and parser:
62
+
63
+ ```python
64
+ from pathlib import Path
65
+
66
+ from dbrownell_ParserLib import BuildAntlrGrammar
67
+
68
+
69
+ BuildAntlrGrammar(
70
+ dm, # DoneManager instance
71
+ Path("Calculator.g4"),
72
+ Path("output_dir"),
73
+ )
74
+ ```
75
+
76
+ #### 3. Create Custom Visitor
77
+ Implement a visitor that converts ANTLR parse trees to Expression objects:
78
+
79
+ ```python
80
+ from dataclasses import dataclass
81
+
82
+ from dbrownell_ParserLib import (
83
+ Expression,
84
+ InsignificantWhitespaceAntlrVisitorMixin,
85
+ TerminalExpression,
86
+ )
87
+
88
+ from CalculatorVisitor import CalculatorVisitor as GeneratedVisitor
89
+
90
+
91
+ @dataclass(eq=False)
92
+ class BinaryExpression(Expression):
93
+ left: Expression
94
+ operator: TerminalExpression[str]
95
+ right: Expression
96
+
97
+ def _GenerateAcceptDetails(self):
98
+ yield "left", self.left
99
+ yield "operator", self.operator
100
+ yield "right", self.right
101
+
102
+
103
+ class CalculatorVisitor(InsignificantWhitespaceAntlrVisitorMixin, GeneratedVisitor):
104
+ def visitExpr(self, ctx):
105
+ children = self.GetChildren(ctx)
106
+ assert len(children) == 2, children
107
+
108
+ self._stack.append(
109
+ BinaryExpression(
110
+ self.CreateRegion(ctx),
111
+ children[0],
112
+ TerminalExpression[str](self.CreateRegion(ctx.children[1]), ctx.children[1].getText()),
113
+
114
+ children[1],
115
+ )
116
+ )
117
+
118
+ def visitNumber(self, ctx):
119
+ self._stack.append(
120
+ TerminalExpression(self.CreateRegion(ctx), int(ctx.getText()))
121
+ )
122
+ ```
123
+
124
+ #### 4. Create Parser Instance
125
+ Use `CreateAntlrParser` to build a callable parser:
126
+
127
+ ```python
128
+ from dbrownell_ParserLib import CreateAntlrParser
129
+
130
+
131
+ parser = CreateAntlrParser(
132
+ CalculatorLexer,
133
+ CalculatorParser,
134
+ CalculatorVisitor,
135
+ lambda p: p.expr(), # Entry point rule
136
+ )
137
+ ```
138
+
139
+ #### 5. Parse Files
140
+ Parse single files, multiple files, or entire workspaces:
141
+
142
+ ```python
143
+ from dbrownell_ParserLib import Error
144
+
145
+
146
+ # Parse a single file
147
+ results = parser(dm, Path("input.txt"), None)
148
+
149
+ # Parse multiple files
150
+ results = parser(dm, [Path("file1.txt"), Path("file2.txt")], None)
151
+
152
+ # Check results
153
+ for filepath, result in results.items():
154
+ if isinstance(result, Error):
155
+ print(f"Parse error in {filepath}: {result}")
156
+ else:
157
+ # result is the visitor containing the parsed AST
158
+ ast = result._stack[0]
159
+ # Process the AST
160
+ ```
161
+
162
+ #### 6. Traverse the AST
163
+ Use the visitor pattern to process your AST:
164
+
165
+ ```python
166
+ from contextlib import contextmanager
167
+
168
+ from dbrownell_ParserLib import ExpressionVisitorHelper, VisitResult
169
+
170
+
171
+ class EvaluatorVisitor(ExpressionVisitorHelper):
172
+ @contextmanager
173
+ def OnBinaryExpression(self, expression):
174
+ # Process binary expressions
175
+ yield VisitResult.Continue
176
+
177
+
178
+ ast.Accept(EvaluatorVisitor())
179
+ ```
32
180
 
33
181
  <!-- Content below this delimiter will be copied to the generated README.md file. DO NOT REMOVE THIS COMMENT, as it will cause regeneration to fail. -->
34
182
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dbrownell-parserlib"
3
- version = "0.8.2"
3
+ version = "0.8.4"
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: