Commit d622d9c7 authored by Eckhart Arnold's avatar Eckhart Arnold
Browse files

more tests for trace.py

parent d9caeac2
......@@ -307,7 +307,7 @@ class Parser:
self.tag_name = self.ptype # type: str
self.cycle_detection = set() # type: Set[ApplyFunc]
# this indirection is required for Cython-compatibility
self.__parse = self._parse # type: ParseFunc
self._parse_proxy = self._parse # type: ParseFunc
# self.proxied = None # type: Optional[ParseFunc]
try:
self._grammar = GRAMMAR_PLACEHOLDER # type: Grammar
......@@ -391,7 +391,7 @@ class Parser:
# finally, the actual parser call!
try:
node, rest = self.__parse(text)
node, rest = self._parse_proxy(text)
except ParserError as pe:
# catching up with parsing after an error occurred
gap = len(text) - len(pe.rest)
......@@ -511,7 +511,7 @@ class Parser:
tracing debugger. See module `trace`.
"""
if proxy is None:
self.__parse = self._parse
self._parse_proxy = self._parse
else:
if type(proxy) != type(self._parse):
# assume that proxy is a function
......@@ -519,7 +519,7 @@ class Parser:
else:
# if proxy is a method it must be a method of self
assert proxy.__self__ == self
self.__parse = cast(ParseFunc, proxy)
self._parse_proxy = cast(ParseFunc, proxy)
@property
def grammar(self) -> 'Grammar':
......@@ -1698,6 +1698,7 @@ class NaryParser(MetaParser):
Error.RESUME_NOTICE)
self._grammar.tree__.add_error(err_node, notice)
def sub_parsers(self) -> Tuple['Parser', ...]:
return self.parsers
......@@ -1909,6 +1910,8 @@ def mandatory_violation(grammar: Grammar,
error = Error(msg, location, Error.MANDATORY_CONTINUATION_AT_EOF
if (failed_on_lookahead and not text_) else Error.MANDATORY_CONTINUATION)
grammar.tree__.add_error(err_node, error)
if reloc >= 0:
grammar.most_recent_error__ = ParserError(None, text_, error, first_throw=True)
return error, err_node, text_[i:]
......
......@@ -26,7 +26,7 @@ Grammar-object.
from typing import Tuple, Optional, List, Iterable, Union
from DHParser.error import Error
from DHParser.error import Error, line_col
from DHParser.stringview import StringView
from DHParser.syntaxtree import Node, REGEXP_PTYPE, TOKEN_PTYPE, WHITESPACE_PTYPE, PLACEHOLDER
from DHParser.log import HistoryRecord
......@@ -72,10 +72,10 @@ def trace_history(self: Parser, text: StringView) -> Tuple[Optional[Node], Strin
except ParserError as pe:
grammar.call_stack__.pop()
if self == grammar.start_parser__:
rest = text[pe.error.pos:]
lc = line_col(grammar.document_lbreaks__, pe.error.pos)
# TODO: get the call stack from when the error occured, here
grammar.history__.append(HistoryRecord(
grammar.call_stack__, pe.node, pe.rest, grammar.line_col__(rest), [pe.error]))
grammar.history__.append(
HistoryRecord(grammar.call_stack__, pe.node, pe.rest, lc, [pe.error]))
raise pe
# Mind that memoized parser calls will not appear in the history record!
......
......@@ -31,6 +31,15 @@ from DHParser import grammar_provider, all_descendants, \
set_config_value, resume_notices_on
def get_history(name) -> str:
history_fname = os.path.join(log_dir() or '', name + "_full_parser.log.html")
import webbrowser
webbrowser.open(history_fname)
with open(history_fname, 'r', encoding='utf-8') as f:
history_file = f.read()
return history_file
class TestTrace:
def setup(self):
start_logging()
......@@ -42,14 +51,6 @@ class TestTrace:
os.remove(os.path.join(LOG_DIR, fname))
os.rmdir(LOG_DIR)
def get_history(self, name) -> str:
history_fname = os.path.join(log_dir() or '', name + "_full_parser.log.html")
# import webbrowser
# webbrowser.open(history_fname)
with open(history_fname, 'r', encoding='utf-8') as f:
history_file = f.read()
return history_file
def test_trace_simple(self):
lang = """
expr = term { ("+"|"-") term }
......@@ -62,7 +63,7 @@ class TestTrace:
st = gr('2*(3+4)')
assert(str(st)) == '2*(3+4)'
log_parsing_history(gr, 'trace_simple')
history = self.get_history('trace_simple')
history = get_history('trace_simple')
assert history.count('<tr>') == 25
def test_trace_stopped_early(self):
......@@ -77,7 +78,7 @@ class TestTrace:
st = gr('2*(3+4)...')
# print(st.as_sxpr(compact=True))
log_parsing_history(gr, 'trace_simple')
history = self.get_history('trace_simple')
history = get_history('trace_simple')
assert history.count('<tr>') == 26
def test_trace_drop(self):
......@@ -101,7 +102,7 @@ class TestTrace:
serialization = st.serialize()
assert '*' not in serialization # same for '/', '+', '-'
log_parsing_history(gr, 'trace_drop')
history_file = self.get_history('trace_drop')
history_file = get_history('trace_drop')
assert "DROP" in history_file
assert "FAIL" in history_file
assert "MATCH" in history_file
......@@ -138,6 +139,30 @@ class TestTrace:
assert not gr.history_tracking__
class TestErrorReporting:
def setup(self):
start_logging()
def teardown(self):
LOG_DIR = log_dir()
if os.path.exists(LOG_DIR) and os.path.isdir(LOG_DIR):
for fname in os.listdir(LOG_DIR):
os.remove(os.path.join(LOG_DIR, fname))
os.rmdir(LOG_DIR)
def test_trace_skip_clause(self):
lang = """
document = series | /.*/
@series_skip = /(?=[A-Z])/
series = "A" "B" §"C" "D"
"""
gr = grammar_provider(lang)()
set_tracer(all_descendants(gr.root_parser__), trace_history)
st = gr('AB_D')
print(st.errors)
log_parsing_history(gr, 'trace_skip_clause')
get_history('trace_skip_clause')
if __name__ == "__main__":
from DHParser.testing import runner
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment