Commit 59047804 authored by Eckhart Arnold's avatar Eckhart Arnold

- bug fixes!!!

parent 6e5b22ea
......@@ -68,8 +68,10 @@ __all__ = ('get_ebnf_preprocessor',
########################################################################
CONFIG_PRESET['add_grammar_source_to_parser_docstring'] = False
CONFIG_PRESET['early_static_analysis'] = True # do a static analysis right after ebnf compilation
# CONFIG_PRESET['static_analysis'] = "early" # do a static analysis right
# # after ebnf compilation
# already set in parse.py - config vars should probably moved to a
# a dedicated global module
########################################################################
#
......@@ -586,7 +588,7 @@ class EBNFCompiler(Compiler):
assert grammar_name == "" or re.match(r'\w+\Z', grammar_name)
if not grammar_name and re.fullmatch(r'[\w/:\\]+', grammar_source):
grammar_name = os.path.splitext(os.path.basename(grammar_source))[0]
self.grammar_name = grammar_name
self.grammar_name = grammar_name or "NameUnknown"
self.grammar_source = load_if_file(grammar_source)
return self
......@@ -922,10 +924,12 @@ class EBNFCompiler(Compiler):
self.definitions.update(definitions)
grammar_python_src = self.assemble_parser(definitions, node)
if get_config_value('early_static_analysis'):
grammar_class = compile_python_object(DHPARSER_IMPORTS + grammar_python_src, self.grammar_name)
if get_config_value('static_analysis') == 'early':
try:
grammar_class = compile_python_object(DHPARSER_IMPORTS + grammar_python_src, self.grammar_name)
_ = grammar_class()
except NameError:
pass # undefined name in the grammar are already cuaght and reported
except GrammarError as error:
for sym, prs, err in error.errors:
symdef_node = self.rules[sym][0]
......
......@@ -92,6 +92,11 @@ __all__ = ('Parser',
########################################################################
CONFIG_PRESET['flatten_tree_while_parsing'] = True
CONFIG_PRESET['static_analysis'] = "early"
# 'early': do static analysis already when compiling and EBNF grammar, see ebnf.py
# 'late': do a static analysis, the first time a grammar class is instantiated
# 'none': no static analysis of the grammar
# TODO: move all presests to a dedicated configuration module
########################################################################
......@@ -799,7 +804,8 @@ class Grammar:
assert 'root_parser__' in self.__dict__
assert self.root_parser__ == self.__dict__['root_parser__']
if self.__class__.static_analysis_pending__:
if self.__class__.static_analysis_pending__ \
and get_config_value('static_analysis') in {'early', 'late'}:
try:
result = self.static_analysis()
if result:
......
......@@ -60,6 +60,7 @@ class ArithmeticGrammar(Grammar):
expression = Forward()
variable = Forward()
source_hash__ = "cf537b22b7a1a2a58c426f99f784285d"
static_analysis_pending__ = True
parser_initialization__ = ["upon instantiation"]
resume_rules__ = {}
COMMENT__ = r''
......
......@@ -58,6 +58,7 @@ class EBNFGrammar(Grammar):
"""
expression = Forward()
source_hash__ = "7ca2bbabfc9bc19ec54e2318bbc4c9c2"
static_analysis_pending__ = True
parser_initialization__ = ["upon instantiation"]
resume_rules__ = {}
COMMENT__ = r'#.*(?:\n|$)'
......
......@@ -58,6 +58,7 @@ class LaTeXGrammar(Grammar):
tabular_config = Forward()
text_element = Forward()
source_hash__ = "dacb1f9ad5b1c18cdc29c7ddb7878959"
static_analysis_pending__ = True
parser_initialization__ = ["upon instantiation"]
resume_rules__ = {}
COMMENT__ = r'%.*'
......
......@@ -59,6 +59,7 @@ class Lyrik_explicit_whitespaceGrammar(Grammar):
r"""Parser for a Lyrik_explicit_whitespace source file.
"""
source_hash__ = "bcb3cee425961a2148941b492e614bd2"
static_analysis_pending__ = True
parser_initialization__ = ["upon instantiation"]
resume_rules__ = {}
COMMENT__ = r''
......
......@@ -25,7 +25,7 @@ from multiprocessing import Pool
sys.path.extend(['../', './'])
from DHParser.toolkit import compile_python_object, re
from DHParser.toolkit import compile_python_object, get_config_value, set_config_value, re
from DHParser.preprocess import nil_preprocessor
from DHParser import compile_source
from DHParser.error import has_errors, Error
......@@ -216,13 +216,19 @@ class TestCompilerErrors:
def test_undefined_symbols(self):
"""Use of undefined symbols should be reported.
"""
save = get_config_value('static_analysis')
set_config_value('static_analysis', 'early')
ebnf = """syntax = { intermediary }
intermediary = "This symbol is " [ badly_spelled ] "!"
bedly_spilled = "wrong" """
result, messages, st = compile_source(ebnf, None, get_ebnf_grammar(),
get_ebnf_transformer(), get_ebnf_compiler('UndefinedSymbols'))
# print(messages)
assert messages
set_config_value('static_analysis', save)
def test_no_error(self):
"""But reserved symbols should not be repoted as undefined.
"""
......@@ -532,7 +538,7 @@ class TestErrorCustomizationErrors:
parser = grammar_provider(lang)()
assert False, "CompilationError because of ambiguous error message exptected!"
except CompilationError as compilation_error:
err = next(compilation_error.errors)
err = compilation_error.errors[0]
assert err.code == Error.AMBIGUOUS_ERROR_HANDLING, str(compilation_error)
def test_unsed_error_customization(self):
......@@ -725,7 +731,17 @@ class TestAllOfResume:
class TestStaticAnalysis:
pass
def test_static_analysis(self):
save = get_config_value('static_analysis')
set_config_value('static_analysis', 'early')
minilang = """forever = { // } \n"""
try:
parser_class = grammar_provider(minilang)
except CompilationError as error:
assert all(e.code == Error.INFINITE_LOOP for e in error.errors)
set_config_value('static_analysis', save)
if __name__ == "__main__":
......
......@@ -114,17 +114,20 @@ class TestInfiLoopsAndRecursion:
def test_infinite_loops(self):
minilang = """forever = { // } \n"""
snippet = " "
try:
parser_class = grammar_provider(minilang)
except CompilationError as error:
assert all(e.code == Error.INFINITE_LOOP for e in error.errors)
print(error)
save = get_config_value('early_static_analysis')
set_config_value('early_static_analysis', False)
parser_class = grammar_provider(minilang)
parser = parser_class()
set_config_value('early_static_analysis', save)
save = get_config_value('static_analysis')
set_config_value('static_analysis', 'late')
provider = grammar_provider(minilang)
try:
parser = provider()
except GrammarError as error:
assert error.errors[0][2].code == Error.INFINITE_LOOP
set_config_value('static_analysis', 'none')
parser = provider()
snippet = " "
syntax_tree = parser(snippet)
assert any(e.code == Error.INFINITE_LOOP for e in syntax_tree.errors)
res = parser.static_analysis()
......@@ -133,7 +136,7 @@ class TestInfiLoopsAndRecursion:
parser = grammar_provider(minilang)()
res = parser.static_analysis()
assert not res
set_config_value('static_analysis', save)
class TestFlowControl:
def setup(self):
......@@ -877,6 +880,8 @@ class TestStaticAnalysis:
"""
def test_static_analysis(self):
save = get_config_value('static_analysis')
set_config_value('static_analysis', 'late')
gr_class = grammar_provider(self.bibtex_grammar, 'BibTex')
try:
gr_instance = gr_class()
......@@ -884,6 +889,7 @@ class TestStaticAnalysis:
affected_parsers = {e[0] for e in error.errors}
assert affected_parsers == {'CONTENT_STRING', 'COMMA_TERMINATED_STRING'}
assert all(e[2].code == Error.INFINITE_LOOP for e in error.errors)
set_config_value('static_analysis', save)
......
Markdown is supported
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