Commit 0e289db1 authored by Eckhart Arnold's avatar Eckhart Arnold
Browse files

small corrections; test for load_compiler_suite

parent c3899a9a
...@@ -28,4 +28,4 @@ from .versionnumber import __version__ ...@@ -28,4 +28,4 @@ from .versionnumber import __version__
__author__ = "Eckhart Arnold <arnold@badw.de>" __author__ = "Eckhart Arnold <arnold@badw.de>"
__copyright__ = "http://www.apache.org/licenses/LICENSE-2.0" __copyright__ = "http://www.apache.org/licenses/LICENSE-2.0"
__all__ = ['toolkit', 'syntaxtree', 'parsers', 'ebnf', 'dsl'] # __all__ = ['toolkit', 'syntaxtree', 'parsers', 'ebnf', 'dsl'] # flat namespace
...@@ -39,7 +39,7 @@ __all__ = ['GrammarError', ...@@ -39,7 +39,7 @@ __all__ = ['GrammarError',
'load_compiler_suite', 'load_compiler_suite',
'compileDSL', 'compileDSL',
'compileEBNF', 'compileEBNF',
'compile_parser', 'parser_factory',
'compile_on_disk'] 'compile_on_disk']
...@@ -172,7 +172,7 @@ def compileDSL(text_or_file, scanner, dsl_grammar, ast_transformation, compiler) ...@@ -172,7 +172,7 @@ def compileDSL(text_or_file, scanner, dsl_grammar, ast_transformation, compiler)
compilation error. compilation error.
Raises: Raises:
CompilationError if any errors occured during compilation CompilationError if any errors occurred during compilation
""" """
assert isinstance(text_or_file, str) assert isinstance(text_or_file, str)
assert isinstance(compiler, CompilerBase) assert isinstance(compiler, CompilerBase)
...@@ -194,25 +194,27 @@ def compileEBNF(ebnf_src, branding = "DSL"): ...@@ -194,25 +194,27 @@ def compileEBNF(ebnf_src, branding = "DSL"):
Args: Args:
ebnf_src(str): Either the file name of an EBNF grammar or ebnf_src(str): Either the file name of an EBNF grammar or
the EBNF grammar itself as a string. the EBNF grammar itself as a string.
branding (str or bool): Branding name for the compiler branding (str): Branding name for the compiler suite source
suite source code. code.
Returns: Returns:
The complete compiler suite skeleton as Python source code. The complete compiler suite skeleton as Python source code.
Raises:
CompilationError if any errors occurred during compilation
""" """
grammar = get_ebnf_grammar() grammar = get_ebnf_grammar()
if branding == True: branding = "DSL" compiler = get_ebnf_compiler(branding , ebnf_src)
compiler = get_ebnf_compiler(branding or "DSL", ebnf_src)
grammar_src = compileDSL(ebnf_src, nil_scanner, grammar, EBNFTransformer, compiler) grammar_src = compileDSL(ebnf_src, nil_scanner, grammar, EBNFTransformer, compiler)
src = [DHPARSER_IMPORTS, src = ["#/usr/bin/python\n",
compiler.gen_scanner_skeleton(), SECTION_MARKER.format(marker=SYMBOLS_SECTION), DHPARSER_IMPORTS,
grammar_src, SECTION_MARKER.format(marker=SCANNER_SECTION), compiler.gen_scanner_skeleton(),
compiler.gen_transformer_skeleton(), SECTION_MARKER.format(marker=PARSER_SECTION), grammar_src,
compiler.gen_compiler_skeleton(), SECTION_MARKER.format(marker=AST_SECTION), compiler.gen_transformer_skeleton(),
DHPARSER_MAIN.format(NAME=branding)] SECTION_MARKER.format(marker=COMPILER_SECTION), compiler.gen_compiler_skeleton(),
SECTION_MARKER.format(marker=SYMBOLS_SECTION), DHPARSER_MAIN.format(NAME=branding)]
return '\n'.join(src) return '\n'.join(src)
def compile_parser(ebnf_src, branding="DSL"): def parser_factory(ebnf_src, branding="DSL"):
"""Compiles an EBNF grammar and returns a grammar-parser factory """Compiles an EBNF grammar and returns a grammar-parser factory
function for that grammar. function for that grammar.
...@@ -250,19 +252,18 @@ def load_compiler_suite(compiler_suite): ...@@ -250,19 +252,18 @@ def load_compiler_suite(compiler_suite):
'Please delete or repair file manually.') 'Please delete or repair file manually.')
# TODO: Compile in one step and pick parts from namespace later ? # TODO: Compile in one step and pick parts from namespace later ?
scanner = compile_python_object(imports + scanner_py, 'get_\w*_scanner$') scanner = compile_python_object(imports + scanner_py, 'get_\w*_scanner$')
parser = compile_python_object(imports + parser_py, 'get_\w*_grammar$')
ast = compile_python_object(imports + ast_py, 'get_\w*_transformer$') ast = compile_python_object(imports + ast_py, 'get_\w*_transformer$')
compiler = compile_python_object(imports + compiler_py, 'get_\w*_compiler$')
else: else:
# assume source is an ebnf grammar # assume source is an ebnf grammar. Is there really any reasonable application case for this?
with logging(False): with logging(False):
parser_py, errors, AST = compile_source(source, None, compile_py, errors, AST = compile_source(source, None,
get_ebnf_grammar(), get_ebnf_transformer(), get_ebnf_compiler()) get_ebnf_grammar(), get_ebnf_transformer(), get_ebnf_compiler())
if errors: if errors:
raise GrammarError('\n\n'.join(errors), source) raise GrammarError('\n\n'.join(errors), source)
scanner = get_ebnf_scanner scanner = get_ebnf_scanner
ast = get_ebnf_transformer ast = get_ebnf_transformer
compiler = get_ebnf_compiler compiler = compile_python_object(imports + compiler_py, 'get_\w*_compiler$')
parser = compile_python_object(DHPARSER_IMPORTS + parser_py, 'get_\w*_grammar$')
return scanner, parser, ast, compiler return scanner, parser, ast, compiler
......
...@@ -20,11 +20,15 @@ See the License for the specific language governing permissions and ...@@ -20,11 +20,15 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
""" """
import inspect
import os import os
import sys import sys
sys.path.extend(['../', './']) sys.path.extend(['../', './'])
from DHParser.dsl import compile_on_disk, run_compiler, compileDSL, compileEBNF, compile_parser from DHParser.parsers import GrammarBase, CompilerBase
from DHParser.ebnf import get_ebnf_compiler, get_ebnf_scanner, get_ebnf_transformer
from DHParser.dsl import compile_on_disk, run_compiler, compileDSL, compileEBNF, parser_factory, \
load_compiler_suite
ARITHMETIC_EBNF = """ ARITHMETIC_EBNF = """
...@@ -44,9 +48,9 @@ class TestCompileFunctions: ...@@ -44,9 +48,9 @@ class TestCompileFunctions:
parser_src = compileEBNF(ARITHMETIC_EBNF, branding="CustomDSL") parser_src = compileEBNF(ARITHMETIC_EBNF, branding="CustomDSL")
assert isinstance(parser_src, str), str(type(parser_src)) assert isinstance(parser_src, str), str(type(parser_src))
assert parser_src.find('get_CustomDSL') >= 0 assert parser_src.find('get_CustomDSL') >= 0
parser_factory = compile_parser(ARITHMETIC_EBNF, branding="TestDSL") factory = parser_factory(ARITHMETIC_EBNF, branding="TestDSL")
assert callable(parser_factory) assert callable(factory)
parser = parser_factory() parser = factory()
result = parser("5 + 3 * 4") result = parser("5 + 3 * 4")
assert not result.error_flag assert not result.error_flag
result = parser("5A + 4B ** 4C") result = parser("5A + 4B ** 4C")
...@@ -78,6 +82,18 @@ class TestCompilerGeneration: ...@@ -78,6 +82,18 @@ class TestCompilerGeneration:
os.remove(name) os.remove(name)
pass pass
def test_load_compiler_suite(self):
src = compileEBNF(self.trivial_lang, "Trivial")
scanner, parser, transformer, compiler = load_compiler_suite(src)
scanner = scanner()
parser = parser()
transformer = transformer()
compiler = compiler()
assert callable(scanner)
assert isinstance(parser, GrammarBase)
assert callable(transformer)
assert isinstance(compiler, CompilerBase)
def test_compiling_functions(self): def test_compiling_functions(self):
# test if cutting and reassembling of compiler suite works: # test if cutting and reassembling of compiler suite works:
errors = compile_on_disk(self.grammar_name) errors = compile_on_disk(self.grammar_name)
......
...@@ -28,7 +28,7 @@ sys.path.extend(['../', './']) ...@@ -28,7 +28,7 @@ sys.path.extend(['../', './'])
from DHParser.toolkit import is_logging from DHParser.toolkit import is_logging
from DHParser.parsers import compile_source, Retrieve, WHITESPACE_KEYWORD, nil_scanner from DHParser.parsers import compile_source, Retrieve, WHITESPACE_KEYWORD, nil_scanner
from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, EBNFTransformer, get_ebnf_compiler from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, EBNFTransformer, get_ebnf_compiler
from DHParser.dsl import compileEBNF, compileDSL, compile_parser from DHParser.dsl import compileEBNF, compileDSL, parser_factory
class TestDirectives: class TestDirectives:
...@@ -42,7 +42,7 @@ class TestDirectives: ...@@ -42,7 +42,7 @@ class TestDirectives:
def test_whitespace_linefeed(self): def test_whitespace_linefeed(self):
lang = "@ whitespace = linefeed\n" + self.mini_language lang = "@ whitespace = linefeed\n" + self.mini_language
MinilangParser = compile_parser(lang) MinilangParser = parser_factory(lang)
parser = MinilangParser() parser = MinilangParser()
assert parser assert parser
syntax_tree = parser("3 + 4 * 12") syntax_tree = parser("3 + 4 * 12")
...@@ -58,7 +58,7 @@ class TestDirectives: ...@@ -58,7 +58,7 @@ class TestDirectives:
def test_whitespace_vertical(self): def test_whitespace_vertical(self):
lang = "@ whitespace = vertical\n" + self.mini_language lang = "@ whitespace = vertical\n" + self.mini_language
parser = compile_parser(lang)() parser = parser_factory(lang)()
assert parser assert parser
syntax_tree = parser("3 + 4 * 12") syntax_tree = parser("3 + 4 * 12")
assert not syntax_tree.collect_errors() assert not syntax_tree.collect_errors()
...@@ -71,7 +71,7 @@ class TestDirectives: ...@@ -71,7 +71,7 @@ class TestDirectives:
def test_whitespace_horizontal(self): def test_whitespace_horizontal(self):
lang = "@ whitespace = horizontal\n" + self.mini_language lang = "@ whitespace = horizontal\n" + self.mini_language
parser = compile_parser(lang)() parser = parser_factory(lang)()
assert parser assert parser
syntax_tree = parser("3 + 4 * 12") syntax_tree = parser("3 + 4 * 12")
assert not syntax_tree.collect_errors() assert not syntax_tree.collect_errors()
...@@ -131,8 +131,8 @@ class TestPopRetrieve: ...@@ -131,8 +131,8 @@ class TestPopRetrieve:
""" """
def setup(self): def setup(self):
self.minilang_parser = compile_parser(self.mini_language)() self.minilang_parser = parser_factory(self.mini_language)()
self.minilang_parser2 = compile_parser(self.mini_lang2)() self.minilang_parser2 = parser_factory(self.mini_lang2)()
@staticmethod @staticmethod
def opening_delimiter(node, name): def opening_delimiter(node, name):
......
...@@ -28,7 +28,7 @@ from DHParser.syntaxtree import no_operation, traverse, remove_expendables, \ ...@@ -28,7 +28,7 @@ from DHParser.syntaxtree import no_operation, traverse, remove_expendables, \
replace_by_single_child, reduce_single_child, flatten replace_by_single_child, reduce_single_child, flatten
from DHParser.parsers import compile_source from DHParser.parsers import compile_source
from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler
from DHParser.dsl import compile_parser, DHPARSER_IMPORTS from DHParser.dsl import parser_factory, DHPARSER_IMPORTS
ARITHMETIC_EBNF = """ ARITHMETIC_EBNF = """
...@@ -72,7 +72,7 @@ class TestInfiLoopsAndRecursion: ...@@ -72,7 +72,7 @@ class TestInfiLoopsAndRecursion:
def test_direct_left_recursion(self): def test_direct_left_recursion(self):
minilang = ARITHMETIC_EBNF minilang = ARITHMETIC_EBNF
snippet = "5 + 3 * 4" snippet = "5 + 3 * 4"
parser = compile_parser(minilang)() parser = parser_factory(minilang)()
assert parser assert parser
syntax_tree = parser(snippet) syntax_tree = parser(snippet)
assert not syntax_tree.collect_errors() assert not syntax_tree.collect_errors()
...@@ -87,7 +87,7 @@ class TestInfiLoopsAndRecursion: ...@@ -87,7 +87,7 @@ class TestInfiLoopsAndRecursion:
def test_inifinite_loops(self): def test_inifinite_loops(self):
minilang = """not_forever = { // } \n""" minilang = """not_forever = { // } \n"""
snippet = " " snippet = " "
parser = compile_parser(minilang)() parser = parser_factory(minilang)()
syntax_tree = parser(snippet) syntax_tree = parser(snippet)
assert syntax_tree.error_flag assert syntax_tree.error_flag
# print(syntax_tree.collect_errors()) # print(syntax_tree.collect_errors())
......
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