Browse Source

Standalone generator working again. Updated examples

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.5.6
Erez Shinan 6 years ago
parent
commit
d77f93c818
2 changed files with 157 additions and 172 deletions
  1. +155
    -170
      examples/standalone/json_parser.py
  2. +2
    -2
      lark/parse_tree_builder.py

+ 155
- 170
examples/standalone/json_parser.py View File

@@ -1,4 +1,4 @@
# The file was automatically generated by Lark v0.5.2
# The file was automatically generated by Lark v0.5.5
#
#
# Lark Stand-alone Generator Tool
@@ -92,11 +92,12 @@ class ParseError(Exception):
pass

class UnexpectedToken(ParseError):
def __init__(self, token, expected, seq, index):
def __init__(self, token, expected, seq, index, considered_rules=None):
self.token = token
self.expected = expected
self.line = getattr(token, 'line', '?')
self.column = getattr(token, 'column', '?')
self.considered_rules = considered_rules

try:
context = ' '.join(['%r(%s)' % (t.value, t.type) for t in seq[index:index+5]])
@@ -115,7 +116,7 @@ class UnexpectedToken(ParseError):
class Tree(object):
def __init__(self, data, children):
self.data = data
self.children = list(children)
self.children = children

def __repr__(self):
return 'Tree(%s, %s)' % (self.data, self.children)
@@ -125,14 +126,14 @@ class Tree(object):

def _pretty(self, level, indent_str):
if len(self.children) == 1 and not isinstance(self.children[0], Tree):
return [ indent_str*level, self._pretty_label(), '\t', '%s' % self.children[0], '\n']
return [ indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n']

l = [ indent_str*level, self._pretty_label(), '\n' ]
for n in self.children:
if isinstance(n, Tree):
l += n._pretty(level+1, indent_str)
else:
l += [ indent_str*(level+1), '%s' % n, '\n' ]
l += [ indent_str*(level+1), '%s' % (n,), '\n' ]

return l

@@ -289,9 +290,11 @@ class LexError(Exception):
pass

class UnexpectedInput(LexError):
def __init__(self, seq, lex_pos, line, column, allowed=None):
def __init__(self, seq, lex_pos, line, column, allowed=None, considered_rules=None):
context = seq[lex_pos:lex_pos+5]
message = "No token defined for: '%s' in %r at line %d col %d" % (seq[lex_pos], context, line, column)
if allowed:
message += '\n\nExpecting: %s\n' % allowed

super(UnexpectedInput, self).__init__(message)

@@ -299,6 +302,7 @@ class UnexpectedInput(LexError):
self.column = column
self.context = context
self.allowed = allowed
self.considered_rules = considered_rules

class Token(Str):
def __new__(cls, type_, value, pos_in_stream=None, line=None, column=None):
@@ -358,9 +362,10 @@ class _Lex:

def lex(self, stream, newline_types, ignore_types):
newline_types = list(newline_types)
newline_types = list(newline_types)
ignore_types = list(ignore_types)
line_ctr = LineCounter()

t = None
while True:
lexer = self.lexer
for mre, type_from_index in lexer.mres:
@@ -372,9 +377,16 @@ class _Lex:
t = Token(type_, value, line_ctr.char_pos, line_ctr.line, line_ctr.column)
if t.type in lexer.callback:
t = lexer.callback[t.type](t)
lexer = yield t
yield t
else:
if type_ in lexer.callback:
t = Token(type_, value, line_ctr.char_pos, line_ctr.line, line_ctr.column)
lexer.callback[type_](t)

line_ctr.feed(value, type_ in newline_types)
if t:
t.end_line = line_ctr.line
t.end_column = line_ctr.column
break
else:
if line_ctr.char_pos < len(stream):
@@ -396,15 +408,9 @@ class UnlessCallback:



class NodeBuilder:
def __init__(self, tree_class, name):
self.tree_class = tree_class
self.name = name

def __call__(self, children):
return self.tree_class(self.name, children)
from functools import partial

class Expand1:
class ExpandSingleChild:
def __init__(self, node_builder):
self.node_builder = node_builder

@@ -414,57 +420,17 @@ class Expand1:
else:
return self.node_builder(children)

class Factory:
def __init__(self, cls, *args):
self.cls = cls
self.args = args

def __call__(self, node_builder):
return self.cls(node_builder, *self.args)


class TokenWrapper:
class CreateToken:
"Used for fixing the results of scanless parsing"

def __init__(self, node_builder, token_name):
def __init__(self, token_name, node_builder):
self.node_builder = node_builder
self.token_name = token_name

def __call__(self, children):
return self.node_builder( [Token(self.token_name, ''.join(children))] )

def identity(node_builder):
return node_builder


class ChildFilter:
def __init__(self, node_builder, to_include):
self.node_builder = node_builder
self.to_include = to_include

def __call__(self, children):
filtered = []
for i, to_expand in self.to_include:
if to_expand:
filtered += children[i].children
else:
filtered.append(children[i])

return self.node_builder(filtered)

def create_rule_handler(expansion, keep_all_tokens, filter_out):
# if not keep_all_tokens:
to_include = [(i, not is_terminal(sym) and sym.startswith('_'))
for i, sym in enumerate(expansion)
if keep_all_tokens
or not ((is_terminal(sym) and sym.startswith('_')) or sym in filter_out)
]

if len(to_include) < len(expansion) or any(to_expand for i, to_expand in to_include):
return Factory(ChildFilter, to_include)

# else, if no filtering required..
return identity

class PropagatePositions:
def __init__(self, node_builder):
@@ -483,12 +449,40 @@ class PropagatePositions:
for a in reversed(children):
with suppress(AttributeError):
res.end_line = a.end_line
res.end_col = a.end_col
res.end_column = a.end_column
break

return res


class ChildFilter:
def __init__(self, to_include, node_builder):
self.node_builder = node_builder
self.to_include = to_include

def __call__(self, children):
filtered = []
for i, to_expand in self.to_include:
if to_expand:
if filtered:
filtered += children[i].children
else: # Optimize for left-recursion
filtered = children[i].children
else:
filtered.append(children[i])

return self.node_builder(filtered)

def _should_expand(sym):
return not is_terminal(sym) and sym.startswith('_')

def maybe_create_child_filter(expansion, filter_out):
to_include = [(i, _should_expand(sym)) for i, sym in enumerate(expansion) if sym not in filter_out]

if len(to_include) < len(expansion) or any(to_expand for i, to_expand in to_include):
return partial(ChildFilter, to_include)


class Callback(object):
pass

@@ -503,22 +497,20 @@ class ParseTreeBuilder:
self.user_aliases = {}

def _init_builders(self, rules):
filter_out = set()
for rule in rules:
if rule.options and rule.options.filter_out:
assert rule.origin.startswith('_') # Just to make sure
filter_out.add(rule.origin)
filter_out = {rule.origin for rule in rules if rule.options and rule.options.filter_out}
filter_out |= {sym for rule in rules for sym in rule.expansion if is_terminal(sym) and sym.startswith('_')}
assert all(x.startswith('_') for x in filter_out)

for rule in rules:
options = rule.options
keep_all_tokens = self.always_keep_all_tokens or (options.keep_all_tokens if options else False)
expand1 = options.expand1 if options else False
expand_single_child = options.expand1 if options else False
create_token = options.create_token if options else False

wrapper_chain = filter(None, [
(expand1 and not rule.alias) and Expand1,
create_token and Factory(TokenWrapper, create_token),
create_rule_handler(rule.expansion, keep_all_tokens, filter_out),
create_token and partial(CreateToken, create_token),
(expand_single_child and not rule.alias) and ExpandSingleChild,
maybe_create_child_filter(rule.expansion, () if keep_all_tokens else filter_out),
self.propagate_positions and PropagatePositions,
])

@@ -535,7 +527,7 @@ class ParseTreeBuilder:
try:
f = transformer._get_func(user_callback_name)
except AttributeError:
f = NodeBuilder(self.tree_class, user_callback_name)
f = partial(self.tree_class, user_callback_name)

self.user_aliases[rule] = rule.alias
rule.alias = internal_callback_name
@@ -595,9 +587,7 @@ class _Parser:
value_stack.append(value)

# Main LALR-parser loop
try:
token = next(stream)
i += 1
for i, token in enumerate(stream):
while True:
action, arg = get_action(token.type)
assert arg != self.end_state
@@ -606,12 +596,9 @@ class _Parser:
state_stack.append(arg)
value_stack.append(token)
if set_state: set_state(arg)
token = next(stream)
i += 1
break # next token
else:
reduce(arg)
except StopIteration:
pass

while True:
_action, arg = get_action('$END')
@@ -665,27 +652,25 @@ Shift = 0
Reduce = 1
import re
MRES = (
[('(?P<SIGNED_NUMBER>(?:(?:\\+|\\-))?(?:(?:(?:[0-9])+(?:e|E)(?:(?:\\+|\\-))?(?:[0-9])+|(?:(?:[0-9])+\\.(?:(?:[0-9])+)?|\\.(?:[0-9])+)(?:(?:e|E)(?:(?:\\+|\\-))?(?:[0-9])+)?)|(?:[0-9])+))|(?P<ESCAPED_STRING>\\"(?:(?:\\\\\\"|[^"]))*\\")|(?P<WS>(?:[ \t\x0c'
'\r\n'
'])+)|(?P<__FALSE1>false)|(?P<__NULL2>null)|(?P<__TRUE0>true)|(?P<__COLON>\\:)|(?P<__COMMA>\\,)|(?P<__LBRACE>\\{)|(?P<__LSQB>\\[)|(?P<__RBRACE>\\})|(?P<__RSQB>\\])',
{1: 'SIGNED_NUMBER',
2: 'ESCAPED_STRING',
3: 'WS',
4: '__FALSE1',
5: '__NULL2',
6: '__TRUE0',
7: '__COLON',
8: '__COMMA',
9: '__LBRACE',
10: '__LSQB',
11: '__RBRACE',
12: '__RSQB'})]
[(u'(?P<SIGNED_NUMBER>(?:(?:\\+|\\-))?(?:(?:(?:[0-9])+(?:e|E)(?:(?:\\+|\\-))?(?:[0-9])+|(?:(?:[0-9])+\\.(?:(?:[0-9])+)?|\\.(?:[0-9])+)(?:(?:e|E)(?:(?:\\+|\\-))?(?:[0-9])+)?)|(?:[0-9])+))|(?P<ESCAPED_STRING>\\"(?:(?:\\\\\\"|[^"]))*\\")|(?P<WS>(?:[ \t\x0c\r\n])+)|(?P<__FALSE1>false)|(?P<__NULL2>null)|(?P<__TRUE0>true)|(?P<__COLON>\\:)|(?P<__COMMA>\\,)|(?P<__LBRACE>\\{)|(?P<__LSQB>\\[)|(?P<__RBRACE>\\})|(?P<__RSQB>\\])',
{1: u'SIGNED_NUMBER',
2: u'ESCAPED_STRING',
3: u'WS',
4: u'__FALSE1',
5: u'__NULL2',
6: u'__TRUE0',
7: u'__COLON',
8: u'__COMMA',
9: u'__LBRACE',
10: u'__LSQB',
11: u'__RBRACE',
12: u'__RSQB'})]
)
LEXER_CALLBACK = (
{}
)
NEWLINE_TYPES = ['WS']
IGNORE_TYPES = ['WS']
NEWLINE_TYPES = [u'WS']
IGNORE_TYPES = [u'WS']
class LexerRegexps: pass
lexer_regexps = LexerRegexps()
lexer_regexps.mres = [(re.compile(p), d) for p, d in MRES]
@@ -695,93 +680,93 @@ lexer = _Lex(lexer_regexps)
def lex(stream):
return lexer.lex(stream, NEWLINE_TYPES, IGNORE_TYPES)
RULES = {
0: Rule('start', ['value'], None, RuleOptions(False, True, None, None, False)),
1: Rule('value', ['object'], None, RuleOptions(False, True, None, None, False)),
2: Rule('value', ['array'], None, RuleOptions(False, True, None, None, False)),
3: Rule('value', ['string'], None, RuleOptions(False, True, None, None, False)),
4: Rule('value', ['SIGNED_NUMBER'], 'number', RuleOptions(False, True, None, None, False)),
5: Rule('value', ['__TRUE0'], 'true', RuleOptions(False, True, None, None, False)),
6: Rule('value', ['__FALSE1'], 'false', RuleOptions(False, True, None, None, False)),
7: Rule('value', ['__NULL2'], 'null', RuleOptions(False, True, None, None, False)),
8: Rule('array', ['__LSQB', 'value', '__anon_star_0', '__RSQB'], None, RuleOptions(False, False, None, None, False)),
9: Rule('array', ['__LSQB', 'value', '__RSQB'], None, RuleOptions(False, False, None, None, False)),
10: Rule('array', ['__LSQB', '__RSQB'], None, RuleOptions(False, False, None, None, False)),
11: Rule('object', ['__LBRACE', 'pair', '__anon_star_1', '__RBRACE'], None, RuleOptions(False, False, None, None, False)),
12: Rule('object', ['__LBRACE', 'pair', '__RBRACE'], None, RuleOptions(False, False, None, None, False)),
13: Rule('object', ['__LBRACE', '__RBRACE'], None, RuleOptions(False, False, None, None, False)),
14: Rule('pair', ['string', '__COLON', 'value'], None, RuleOptions(False, False, None, None, False)),
15: Rule('string', ['ESCAPED_STRING'], None, RuleOptions(False, False, None, None, False)),
16: Rule('__anon_star_0', ['__COMMA', 'value'], None, None),
17: Rule('__anon_star_0', ['__anon_star_0', '__COMMA', 'value'], None, None),
18: Rule('__anon_star_1', ['__COMMA', 'pair'], None, None),
19: Rule('__anon_star_1', ['__anon_star_1', '__COMMA', 'pair'], None, None),
0: Rule(u'start', [u'value'], None, RuleOptions(False, True, None, None, False)),
1: Rule(u'value', [u'string'], None, RuleOptions(False, True, None, None, False)),
2: Rule(u'value', [u'__TRUE0'], u'true', RuleOptions(False, True, None, None, False)),
3: Rule(u'value', [u'array'], None, RuleOptions(False, True, None, None, False)),
4: Rule(u'value', [u'__NULL2'], u'null', RuleOptions(False, True, None, None, False)),
5: Rule(u'value', [u'SIGNED_NUMBER'], u'number', RuleOptions(False, True, None, None, False)),
6: Rule(u'value', [u'object'], None, RuleOptions(False, True, None, None, False)),
7: Rule(u'value', [u'__FALSE1'], u'false', RuleOptions(False, True, None, None, False)),
8: Rule(u'array', ['__LSQB', u'value', '__RSQB'], None, RuleOptions(False, False, None, None, False)),
9: Rule(u'array', ['__LSQB', u'value', '__anon_star_0', '__RSQB'], None, RuleOptions(False, False, None, None, False)),
10: Rule(u'array', ['__LSQB', '__RSQB'], None, RuleOptions(False, False, None, None, False)),
11: Rule(u'object', ['__LBRACE', u'pair', '__anon_star_1', '__RBRACE'], None, RuleOptions(False, False, None, None, False)),
12: Rule(u'object', ['__LBRACE', '__RBRACE'], None, RuleOptions(False, False, None, None, False)),
13: Rule(u'object', ['__LBRACE', u'pair', '__RBRACE'], None, RuleOptions(False, False, None, None, False)),
14: Rule(u'pair', [u'string', '__COLON', u'value'], None, RuleOptions(False, False, None, None, False)),
15: Rule(u'string', [u'ESCAPED_STRING'], None, RuleOptions(False, False, None, None, False)),
16: Rule('__anon_star_0', ['__anon_star_0', '__COMMA', u'value'], None, None),
17: Rule('__anon_star_0', ['__COMMA', u'value'], None, None),
18: Rule('__anon_star_1', ['__COMMA', u'pair'], None, None),
19: Rule('__anon_star_1', ['__anon_star_1', '__COMMA', u'pair'], None, None),
}
parse_tree_builder = ParseTreeBuilder(RULES.values(), Tree)
class ParseTable: pass
parse_table = ParseTable()
STATES = {
0: {0: (0, 1), 1: (0, 2), 2: (0, 3), 3: (0, 4), 4: (0, 5), 5: (0, 6), 6: (0, 7), 7: (0, 8), 8: (0, 9), 9: (0, 10), 10: (0, 11), 11: (0, 12)},
1: {12: (1, 5), 13: (1, 5), 14: (1, 5), 15: (1, 5)},
2: {9: (0, 10), 14: (0, 13), 16: (0, 14), 11: (0, 15)},
3: {12: (1, 2), 13: (1, 2), 14: (1, 2), 15: (1, 2)},
4: {12: (1, 1), 13: (1, 1), 14: (1, 1), 15: (1, 1)},
5: {12: (0, 16)},
6: {7: (0, 17), 0: (0, 1), 1: (0, 2), 2: (0, 3), 3: (0, 4), 5: (0, 6), 6: (0, 7), 8: (0, 9), 9: (0, 10), 15: (0, 18), 10: (0, 11), 11: (0, 12)},
7: {12: (1, 4), 13: (1, 4), 14: (1, 4), 15: (1, 4)},
8: {12: (1, 0)},
9: {12: (1, 7), 13: (1, 7), 14: (1, 7), 15: (1, 7)},
10: {12: (1, 15), 17: (1, 15), 13: (1, 15), 14: (1, 15), 15: (1, 15)},
11: {12: (1, 6), 13: (1, 6), 14: (1, 6), 15: (1, 6)},
12: {12: (1, 3), 13: (1, 3), 14: (1, 3), 15: (1, 3)},
13: {13: (1, 13), 12: (1, 13), 14: (1, 13), 15: (1, 13)},
14: {14: (0, 19), 13: (0, 20), 18: (0, 21)},
15: {17: (0, 22)},
16: {},
17: {19: (0, 23), 15: (0, 24), 13: (0, 25)},
18: {13: (1, 10), 12: (1, 10), 14: (1, 10), 15: (1, 10)},
19: {13: (1, 12), 12: (1, 12), 14: (1, 12), 15: (1, 12)},
20: {9: (0, 10), 11: (0, 15), 16: (0, 26)},
21: {14: (0, 27), 13: (0, 28)},
22: {5: (0, 6), 1: (0, 2), 0: (0, 1), 8: (0, 9), 2: (0, 3), 3: (0, 4), 9: (0, 10), 6: (0, 7), 10: (0, 11), 11: (0, 12), 7: (0, 29)},
23: {15: (0, 30), 13: (0, 31)},
24: {13: (1, 9), 12: (1, 9), 14: (1, 9), 15: (1, 9)},
25: {5: (0, 6), 1: (0, 2), 0: (0, 1), 8: (0, 9), 2: (0, 3), 3: (0, 4), 7: (0, 32), 9: (0, 10), 6: (0, 7), 10: (0, 11), 11: (0, 12)},
26: {13: (1, 18), 14: (1, 18)},
27: {13: (1, 11), 12: (1, 11), 14: (1, 11), 15: (1, 11)},
28: {16: (0, 33), 9: (0, 10), 11: (0, 15)},
29: {13: (1, 14), 14: (1, 14)},
30: {13: (1, 8), 12: (1, 8), 14: (1, 8), 15: (1, 8)},
31: {5: (0, 6), 1: (0, 2), 0: (0, 1), 7: (0, 34), 8: (0, 9), 2: (0, 3), 3: (0, 4), 9: (0, 10), 6: (0, 7), 10: (0, 11), 11: (0, 12)},
32: {15: (1, 16), 13: (1, 16)},
33: {13: (1, 19), 14: (1, 19)},
34: {15: (1, 17), 13: (1, 17)},
0: {0: (1, 4), 1: (1, 4), 2: (1, 4), 3: (1, 4)},
1: {1: (1, 14), 2: (1, 14)},
2: {0: (0, 29), 1: (0, 32), 4: (0, 9)},
3: {1: (0, 13), 2: (0, 12)},
4: {0: (1, 1), 1: (1, 1), 2: (1, 1), 3: (1, 1)},
5: {0: (1, 10), 1: (1, 10), 2: (1, 10), 3: (1, 10)},
6: {2: (0, 15), 5: (0, 27), 6: (0, 16), 7: (0, 26)},
7: {5: (0, 34), 6: (0, 16), 7: (0, 26)},
8: {0: (1, 2), 1: (1, 2), 2: (1, 2), 3: (1, 2)},
9: {0: (0, 11), 1: (0, 22)},
10: {0: (1, 6), 1: (1, 6), 2: (1, 6), 3: (1, 6)},
11: {0: (1, 9), 1: (1, 9), 2: (1, 9), 3: (1, 9)},
12: {0: (1, 11), 1: (1, 11), 2: (1, 11), 3: (1, 11)},
13: {5: (0, 20), 6: (0, 16), 7: (0, 26)},
14: {6: (0, 16), 7: (0, 4), 8: (0, 6), 9: (0, 31), 10: (0, 24), 11: (0, 10), 12: (0, 21), 13: (0, 17), 14: (0, 33), 15: (0, 0), 16: (0, 19), 17: (0, 8)},
15: {0: (1, 12), 1: (1, 12), 2: (1, 12), 3: (1, 12)},
16: {0: (1, 15), 1: (1, 15), 2: (1, 15), 3: (1, 15), 18: (1, 15)},
17: {3: (1, 0)},
18: {},
19: {0: (1, 3), 1: (1, 3), 2: (1, 3), 3: (1, 3)},
20: {1: (1, 19), 2: (1, 19)},
21: {0: (1, 5), 1: (1, 5), 2: (1, 5), 3: (1, 5)},
22: {6: (0, 16), 7: (0, 4), 8: (0, 6), 9: (0, 31), 10: (0, 24), 11: (0, 10), 12: (0, 21), 13: (0, 30), 15: (0, 0), 16: (0, 19), 17: (0, 8)},
23: {6: (0, 16), 7: (0, 4), 8: (0, 6), 9: (0, 31), 10: (0, 24), 11: (0, 10), 12: (0, 21), 13: (0, 1), 15: (0, 0), 16: (0, 19), 17: (0, 8)},
24: {0: (0, 5), 6: (0, 16), 7: (0, 4), 8: (0, 6), 9: (0, 31), 10: (0, 24), 11: (0, 10), 12: (0, 21), 13: (0, 2), 15: (0, 0), 16: (0, 19), 17: (0, 8)},
25: {0: (1, 13), 1: (1, 13), 2: (1, 13), 3: (1, 13)},
26: {18: (0, 23)},
27: {1: (0, 7), 2: (0, 25), 19: (0, 3)},
28: {0: (1, 17), 1: (1, 17)},
29: {0: (1, 8), 1: (1, 8), 2: (1, 8), 3: (1, 8)},
30: {0: (1, 16), 1: (1, 16)},
31: {0: (1, 7), 1: (1, 7), 2: (1, 7), 3: (1, 7)},
32: {6: (0, 16), 7: (0, 4), 8: (0, 6), 9: (0, 31), 10: (0, 24), 11: (0, 10), 12: (0, 21), 13: (0, 28), 15: (0, 0), 16: (0, 19), 17: (0, 8)},
33: {3: (0, 18)},
34: {1: (1, 18), 2: (1, 18)},
}
TOKEN_TYPES = (
{0: '__TRUE0',
1: '__LBRACE',
2: 'array',
3: 'object',
4: 'start',
5: '__LSQB',
6: 'SIGNED_NUMBER',
7: 'value',
8: '__NULL2',
9: 'ESCAPED_STRING',
10: '__FALSE1',
11: 'string',
12: '$END',
13: '__COMMA',
14: '__RBRACE',
15: '__RSQB',
16: 'pair',
17: '__COLON',
18: '__anon_star_1',
19: '__anon_star_0'}
{0: '__RSQB',
1: '__COMMA',
2: '__RBRACE',
3: '$END',
4: '__anon_star_0',
5: u'pair',
6: u'ESCAPED_STRING',
7: u'string',
8: '__LBRACE',
9: u'__FALSE1',
10: '__LSQB',
11: u'object',
12: u'SIGNED_NUMBER',
13: u'value',
14: 'start',
15: u'__NULL2',
16: u'array',
17: u'__TRUE0',
18: '__COLON',
19: '__anon_star_1'}
)
parse_table.states = {s: {TOKEN_TYPES[t]: (a, RULES[x] if a is Reduce else x) for t, (a, x) in acts.items()}
for s, acts in STATES.items()}
parse_table.start_state = 0
parse_table.end_state = 16
parse_table.start_state = 14
parse_table.end_state = 18
class Lark_StandAlone:
def __init__(self, transformer=None, postlex=None):
callback = parse_tree_builder.create_callback(transformer=transformer)


+ 2
- 2
lark/parse_tree_builder.py View File

@@ -1,11 +1,11 @@
from functools import partial

from .common import is_terminal, GrammarError
from .utils import suppress
from .lexer import Token
from .grammar import Rule

###{standalone
from functools import partial


class ExpandSingleChild:
def __init__(self, node_builder):


Loading…
Cancel
Save