Skip to content

Commit aaf508b

Browse files
authored
Merge pull request #1356 from lark-parser/standalone_interactive
Standalone: Added support for interactive parser.
2 parents 44483c9 + c611d56 commit aaf508b

File tree

4 files changed

+46
-1
lines changed

4 files changed

+46
-1
lines changed

lark/parsers/lalr_interactive_parser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from lark.exceptions import UnexpectedToken
88
from lark.lexer import Token, LexerThread
99

10+
###{standalone
1011

1112
class InteractiveParser:
1213
"""InteractiveParser gives you advanced control over parsing and error handling when parsing with LALR.
@@ -152,3 +153,5 @@ def as_mutable(self):
152153
"""Convert to an ``InteractiveParser``."""
153154
p = copy(self)
154155
return InteractiveParser(p.parser, p.parser_state, p.lexer_thread)
156+
157+
###}

lark/tools/standalone.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#
2525
#
2626

27+
from copy import deepcopy
2728
from abc import ABC, abstractmethod
2829
from types import ModuleType
2930
from typing import (
@@ -65,6 +66,7 @@
6566
'parsers/lalr_analysis.py',
6667
'parsers/lalr_parser_state.py',
6768
'parsers/lalr_parser.py',
69+
'parsers/lalr_interactive_parser.py',
6870
'parser_frontends.py',
6971
'lark.py',
7072
'indenter.py',

tests/test_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2542,7 +2542,7 @@ def test_parser_interactive_parser(self):
25422542

25432543
res = ip.feed_eof(ip.lexer_thread.state.last_token)
25442544
self.assertEqual(res, Tree('start', ['a', 'b']))
2545-
self.assertRaises(UnexpectedToken ,ip.feed_eof)
2545+
self.assertRaises(UnexpectedToken, ip.feed_eof)
25462546

25472547
self.assertRaises(UnexpectedToken, ip_copy.feed_token, Token('A', 'a'))
25482548
ip_copy.feed_token(Token('B', 'b'))

tests/test_tools.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,46 @@ def test_simple(self):
5151
l = _Lark()
5252
x = l.parse('12 elephants')
5353

54+
def test_interactive(self):
55+
grammar = """
56+
start: A+ B*
57+
A: "a"
58+
B: "b"
59+
"""
60+
context = self._create_standalone(grammar)
61+
parser: Lark = context['Lark_StandAlone']()
62+
63+
ip = parser.parse_interactive()
64+
65+
UnexpectedToken = context['UnexpectedToken']
66+
Token = context['Token']
67+
68+
self.assertRaises(UnexpectedToken, ip.feed_eof)
69+
self.assertRaises(TypeError, ip.exhaust_lexer)
70+
ip.feed_token(Token('A', 'a'))
71+
res = ip.feed_eof()
72+
self.assertEqual(res, Tree('start', ['a']))
73+
74+
ip = parser.parse_interactive("ab")
75+
76+
ip.exhaust_lexer()
77+
78+
ip_copy = ip.copy()
79+
self.assertEqual(ip_copy.parser_state, ip.parser_state)
80+
self.assertEqual(ip_copy.lexer_thread.state, ip.lexer_thread.state)
81+
self.assertIsNot(ip_copy.parser_state, ip.parser_state)
82+
self.assertIsNot(ip_copy.lexer_thread.state, ip.lexer_thread.state)
83+
self.assertIsNot(ip_copy.lexer_thread.state.line_ctr, ip.lexer_thread.state.line_ctr)
84+
85+
res = ip.feed_eof(ip.lexer_thread.state.last_token)
86+
self.assertEqual(res, Tree('start', ['a', 'b']))
87+
self.assertRaises(UnexpectedToken, ip.feed_eof)
88+
89+
self.assertRaises(UnexpectedToken, ip_copy.feed_token, Token('A', 'a'))
90+
ip_copy.feed_token(Token('B', 'b'))
91+
res = ip_copy.feed_eof()
92+
self.assertEqual(res, Tree('start', ['a', 'b', 'b']))
93+
5494
def test_contextual(self):
5595
grammar = """
5696
start: a b

0 commit comments

Comments
 (0)