Skip to content

Commit be5d758

Browse files
authored
[parserconfig] add memoization parameter/option and directive (#377)
There is no left recursion without memoization.
1 parent ab321ad commit be5d758

File tree

5 files changed

+20
-10
lines changed

5 files changed

+20
-10
lines changed

grammar/tatsu.ebnf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ directive
4242
~
4343
'::' ~ value:(regex|string|'None'|'False'|`None`)
4444
|
45-
name:('nameguard' | 'ignorecase' | 'left_recursion' | 'parseinfo')
45+
name:('nameguard' | 'ignorecase' | 'left_recursion' | 'parseinfo' | 'memoization')
4646
~
4747
('::' ~ value:boolean|value:`True`)
4848
|

tatsu/bootstrap.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(self, text, /, config: ParserConfig | None = None, **settings):
3636
namechars='',
3737
parseinfo=True,
3838
comments='(?sm)[(][*](?:.|\\n)*?[*][)]',
39-
eol_comments='(?sm)*#[^\\n]*$',
39+
eol_comments='(?m)#[^\\n]*$',
4040
keywords=KEYWORDS,
4141
start='start',
4242
)
@@ -50,7 +50,7 @@ def __init__(self, /, config: ParserConfig | None = None, **settings):
5050
config = ParserConfig.new(
5151
config,
5252
owner=self,
53-
whitespace='\\s+',
53+
whitespace='(?m)\\s+',
5454
nameguard=None,
5555
ignorecase=False,
5656
namechars='',
@@ -172,10 +172,12 @@ def _directive_(self):
172172
self._token('left_recursion')
173173
with self._option():
174174
self._token('parseinfo')
175+
with self._option():
176+
self._token('memoization')
175177
self._error(
176178
'expecting one of: '
177179
"'ignorecase' 'left_recursion'"
178-
"'nameguard' 'parseinfo'"
180+
"'memoization' 'nameguard' 'parseinfo'"
179181
)
180182
self.name_last_node('name')
181183
self._cut()
@@ -219,8 +221,8 @@ def _directive_(self):
219221
'expecting one of: '
220222
"'comments' 'eol_comments' 'grammar'"
221223
"'ignorecase' 'left_recursion'"
222-
"'namechars' 'nameguard' 'parseinfo'"
223-
"'whitespace'"
224+
"'memoization' 'namechars' 'nameguard'"
225+
"'parseinfo' 'whitespace'"
224226
)
225227
self._cut()
226228
self._define(['name', 'value'], [])

tatsu/contexts.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,10 @@ def _cut(self):
420420
self._cut_stack[-1] = True
421421

422422
def _memoization(self):
423-
return self.memoize_lookaheads or self._lookahead == 0
423+
return self.config.memoization and (
424+
self.memoize_lookaheads or
425+
self._lookahead == 0
426+
)
424427

425428
def _rulestack(self):
426429
rulestack = [r.name for r in reversed(self._rule_stack)]

tatsu/grammars.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ def nodecount(self):
10691069

10701070
def _to_str(self, lean=False):
10711071
regex_directives = {'comments', 'eol_comments', 'whitespace'}
1072-
ustr_directives = {'comments', 'grammar'}
1072+
str_directives = {'comments', 'grammar'}
10731073
string_directives = {'namechars'}
10741074

10751075
directives = ''
@@ -1081,7 +1081,7 @@ def _to_str(self, lean=False):
10811081
repr(value)
10821082
if directive in string_directives
10831083
else str(value)
1084-
if directive in ustr_directives
1084+
if directive in str_directives
10851085
else value
10861086
),
10871087
)

tatsu/infos.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ class ParserConfig:
4040
semantics: type | None = None
4141

4242
comment_recovery: bool = False
43+
44+
memoization: bool = True
4345
memoize_lookaheads: bool = True
46+
memo_cache_size: int = MEMO_CACHE_SIZE
4447

4548
colorize: bool = False
4649
trace: bool = False
@@ -62,7 +65,6 @@ class ParserConfig:
6265
whitespace: str | None = _undefined_str
6366

6467
parseinfo: bool = False
65-
memo_cache_size: int = MEMO_CACHE_SIZE
6668

6769
def __post_init__(self): # pylint: disable=W0235
6870
if self.ignorecase:
@@ -83,6 +85,9 @@ def __post_init__(self): # pylint: disable=W0235
8385
if self.whitespace:
8486
cached_re_compile(self.whitespace)
8587

88+
if not self.memoization:
89+
self.left_recursion = False
90+
8691
@classmethod
8792
def new(
8893
cls,

0 commit comments

Comments
 (0)