Skip to content

Commit

Permalink
Standalone: Added support for interactive parser.
Browse files Browse the repository at this point in the history
parse_interactive and on_error are now working
  • Loading branch information
erezsh committed Oct 22, 2023
1 parent 44483c9 commit 8168545
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lark/parsers/lalr_interactive_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from lark.exceptions import UnexpectedToken
from lark.lexer import Token, LexerThread

###{standalone

class InteractiveParser:
"""InteractiveParser gives you advanced control over parsing and error handling when parsing with LALR.
Expand Down Expand Up @@ -152,3 +153,5 @@ def as_mutable(self):
"""Convert to an ``InteractiveParser``."""
p = copy(self)
return InteractiveParser(p.parser, p.parser_state, p.lexer_thread)

###}
2 changes: 2 additions & 0 deletions lark/tools/standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#
#

from copy import deepcopy
from abc import ABC, abstractmethod
from types import ModuleType
from typing import (
Expand Down Expand Up @@ -65,6 +66,7 @@
'parsers/lalr_analysis.py',
'parsers/lalr_parser_state.py',
'parsers/lalr_parser.py',
'parsers/lalr_interactive_parser.py',
'parser_frontends.py',
'lark.py',
'indenter.py',
Expand Down
40 changes: 40 additions & 0 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,46 @@ def test_simple(self):
l = _Lark()
x = l.parse('12 elephants')

def test_interactive(self):
grammar = """
start: A+ B*
A: "a"
B: "b"
"""
context = self._create_standalone(grammar)
parser: Lark = context['Lark_StandAlone']()

ip = parser.parse_interactive()

UnexpectedToken = context['UnexpectedToken']
Token = context['Token']

self.assertRaises(UnexpectedToken, ip.feed_eof)
self.assertRaises(TypeError, ip.exhaust_lexer)
ip.feed_token(Token('A', 'a'))
res = ip.feed_eof()
self.assertEqual(res, Tree('start', ['a']))

ip = parser.parse_interactive("ab")

ip.exhaust_lexer()

ip_copy = ip.copy()
self.assertEqual(ip_copy.parser_state, ip.parser_state)
self.assertEqual(ip_copy.lexer_thread.state, ip.lexer_thread.state)
self.assertIsNot(ip_copy.parser_state, ip.parser_state)
self.assertIsNot(ip_copy.lexer_thread.state, ip.lexer_thread.state)
self.assertIsNot(ip_copy.lexer_thread.state.line_ctr, ip.lexer_thread.state.line_ctr)

res = ip.feed_eof(ip.lexer_thread.state.last_token)
self.assertEqual(res, Tree('start', ['a', 'b']))
self.assertRaises(UnexpectedToken ,ip.feed_eof)

self.assertRaises(UnexpectedToken, ip_copy.feed_token, Token('A', 'a'))
ip_copy.feed_token(Token('B', 'b'))
res = ip_copy.feed_eof()
self.assertEqual(res, Tree('start', ['a', 'b', 'b']))

def test_contextual(self):
grammar = """
start: a b
Expand Down

0 comments on commit 8168545

Please sign in to comment.