import pytest from common.utils import unstr_concept from conftest import NewOntology from helpers import get_concepts from parsers.BnfDefinitionParser import BnfDefinitionParser from parsers.parser_utils import UnexpectedEof, UnexpectedToken from parsers.peg_parser import ConceptExpression, OneOrMore, Optional, OrderedChoice, RegExMatch, Sequence, StrMatch, \ VariableExpression, ZeroOrMore def _cexp(concept_str, rule_name=None): concept_name, concept_id = unstr_concept(concept_str) return ConceptExpression(concept_id, rule_name or concept_name) @pytest.mark.parametrize("expression, expected", [ ("'str'", StrMatch("str")), ("1", StrMatch("1")), (" 1", StrMatch("1")), (",", StrMatch(",")), ("r'str'", RegExMatch("str")), ("'foo'?", Optional(StrMatch("foo"))), ("'foo'*", ZeroOrMore(StrMatch("foo"))), ("'foo'+", OneOrMore(StrMatch("foo"))), ("1 | 2 | 3", OrderedChoice(StrMatch("1"), StrMatch("2"), StrMatch("3"))), ("1|2|3", OrderedChoice(StrMatch("1"), StrMatch("2"), StrMatch("3"))), ("1'|' 2 '|' 3", Sequence(StrMatch("1"), StrMatch("|"), StrMatch("2"), StrMatch("|"), StrMatch("3"))), ("1 2 'foo'", Sequence(StrMatch("1"), StrMatch("2"), StrMatch("foo"))), ("1 2 | 3 4+", OrderedChoice( Sequence(StrMatch("1"), StrMatch("2")), Sequence(StrMatch("3"), OneOrMore(StrMatch("4"))))), ("1 (2 | 3) 4+", Sequence( StrMatch("1"), OrderedChoice(StrMatch("2"), StrMatch("3")), OneOrMore(StrMatch("4")))), ("(1|2)+", OneOrMore(OrderedChoice(StrMatch("1"), StrMatch("2")))), ("(1 2)+", OneOrMore(Sequence(StrMatch("1"), StrMatch("2")))), ("1 *", Sequence(StrMatch("1"), StrMatch("*"))), ("1 ?", Sequence(StrMatch("1"), StrMatch("?"))), ("1 +", Sequence(StrMatch("1"), StrMatch("+"))), ("(1|*) +", Sequence(OrderedChoice(StrMatch("1"), StrMatch("*")), StrMatch("+"))), ("1, :&", Sequence(StrMatch("1"), StrMatch(","), StrMatch(":"), StrMatch("&"))), ("(1 )", StrMatch("1")), ("'str'=var", StrMatch("str", rule_name="var")), ("'foo'?=var", Optional(StrMatch("foo"), rule_name="var")), ("('foo'?)=var", Optional(StrMatch("foo"), rule_name="var")), ("'foo'*=var", ZeroOrMore(StrMatch("foo"), rule_name="var")), ("('foo'*)=var", ZeroOrMore(StrMatch("foo"), rule_name="var")), ("'foo'+=var", OneOrMore(StrMatch("foo"), rule_name="var")), ("('foo'+)=var", OneOrMore(StrMatch("foo"), rule_name="var")), ("'foo'=var?", Optional(StrMatch("foo", rule_name="var"))), ("('foo'=var)?", Optional(StrMatch("foo", rule_name="var"))), ("'foo'=var*", ZeroOrMore(StrMatch("foo", rule_name="var"))), ("('foo'=var)*", ZeroOrMore(StrMatch("foo", rule_name="var"))), ("'foo'=var+", OneOrMore(StrMatch("foo", rule_name="var"))), ("('foo'=var)+", OneOrMore(StrMatch("foo", rule_name="var"))), ("r'str'=var", RegExMatch("str", rule_name="var")), ("r'foo'?=var", Optional(RegExMatch("foo"), rule_name="var")), ("(r'foo'?)=var", Optional(RegExMatch("foo"), rule_name="var")), ("r'foo'*=var", ZeroOrMore(RegExMatch("foo"), rule_name="var")), ("(r'foo'*)=var", ZeroOrMore(RegExMatch("foo"), rule_name="var")), ("r'foo'+=var", OneOrMore(RegExMatch("foo"), rule_name="var")), ("(r'foo'+)=var", OneOrMore(RegExMatch("foo"), rule_name="var")), ("r'foo'=var?", Optional(RegExMatch("foo", rule_name="var"))), ("(r'foo'=var)?", Optional(RegExMatch("foo", rule_name="var"))), ("r'foo'=var*", ZeroOrMore(RegExMatch("foo", rule_name="var"))), ("(r'foo'=var)*", ZeroOrMore(RegExMatch("foo", rule_name="var"))), ("r'foo'=var+", OneOrMore(RegExMatch("foo", rule_name="var"))), ("(r'foo'=var)+", OneOrMore(RegExMatch("foo", rule_name="var"))), ("(1 | 2 | 3)=var", OrderedChoice(StrMatch("1"), StrMatch("2"), StrMatch("3"), rule_name="var")), ("(1 2)=var", Sequence(StrMatch("1"), StrMatch("2"), rule_name="var")), ("(1 2)+=var", OneOrMore(Sequence(StrMatch("1"), StrMatch("2")), rule_name="var")), ("(1 2)=var+", OneOrMore(Sequence(StrMatch("1"), StrMatch("2"), rule_name="var"))), ("(1=a 2=b)=c", Sequence(StrMatch("1", rule_name="a"), StrMatch("2", rule_name="b"), rule_name="c")), ("(1*=a)", ZeroOrMore(StrMatch("1"), rule_name="a")), ("'a'* 'b'+", Sequence(ZeroOrMore(StrMatch("a")), OneOrMore(StrMatch("b")))), ("('a'* 'b'+)", Sequence(ZeroOrMore(StrMatch("a")), OneOrMore(StrMatch("b")))), ("('a'*=x 'b'+=y)=z", Sequence( ZeroOrMore(StrMatch("a"), rule_name="x"), OneOrMore(StrMatch("b"), rule_name="y"), rule_name="z")), ("'--filter'", Sequence(StrMatch("-", skip_whitespace=False), StrMatch("-", skip_whitespace=False), StrMatch("filter"))) ]) def test_i_can_parse_simple_bnf_definition(context, expression, expected): parser = BnfDefinitionParser(context, expression) res = parser.parse() assert res == expected assert not parser.error_sink assert parser.source == expression @pytest.mark.parametrize("expression, expected", [ ("foo", _cexp("c:foo#1001:")), ("foo*", ZeroOrMore(_cexp("c:foo#1001:"))), ("foo 'and' bar+", Sequence(_cexp("c:foo#1001:"), StrMatch("and"), OneOrMore(_cexp("c:bar#1002:")))), ("foo | bar?", OrderedChoice(_cexp("c:foo#1001:"), Optional(_cexp("c:bar#1002:")))), ("'str' = var", Sequence(StrMatch("str"), StrMatch("="), _cexp("c:var#1003:"))), ("'str''='var", Sequence(StrMatch("str"), StrMatch("="), _cexp("c:var#1003:"))), ("foo=f", _cexp("c:foo#1001:", "f")), ("foo=f 'constant'", Sequence(_cexp("c:foo#1001:", "f"), StrMatch("constant"))), ("def 'concept'", Sequence(_cexp("c:def#1004:"), StrMatch("concept"))), ("c:foo:", _cexp("c:foo#1001:")), ("c:#1001:", _cexp("c:foo#1001:")), ]) def test_i_can_parse_bnf_definition_with_concepts(context, expression, expected): with NewOntology(context, "test_i_can_parse_bnf_definition_with_concept"): get_concepts(context, "foo", "bar", "var", "def", use_sheerka=True) parser = BnfDefinitionParser(context, expression) res = parser.parse() assert res == expected assert not parser.error_sink assert parser.source == expression @pytest.mark.parametrize("expression, expected", [ ("x", VariableExpression("x")), ("x bar", Sequence(VariableExpression("x"), _cexp("c:bar#1001:"))), ("bar x", Sequence(_cexp("c:bar#1001:"), VariableExpression("x"))), ("x 'and' bar", Sequence(VariableExpression("x"), StrMatch("and"), _cexp("c:bar#1001:"))), ("x | bar", OrderedChoice(VariableExpression("x"), _cexp("c:bar#1001:"))), ("x*", ZeroOrMore(VariableExpression("x"))), ("x+", OneOrMore(VariableExpression("x"))), ("'str' = x", Sequence(StrMatch("str"), StrMatch("="), VariableExpression("x"))), ("'str''='x", Sequence(StrMatch("str"), StrMatch("="), VariableExpression("x"))), ("foo=x", VariableExpression("x")), ]) def test_i_can_parse_bnf_definition_with_variables(context, expression, expected): with NewOntology(context, "test_i_can_parse_bnf_definition_with_variables"): get_concepts(context, "bar", use_sheerka=True) parser = BnfDefinitionParser(context, expression) res = parser.parse() assert res == expected assert not parser.error_sink assert parser.source == expression def test_i_can_parse_when_the_concept_is_still_under_creation(context): # I want to parse something like # def concept add from bnf add | mult # 'add' is used while being under construction # 'add' must not be detected as a variable parser = BnfDefinitionParser(context, "add | 'mult'", concept_name="add") res = parser.parse() assert res == OrderedChoice(_cexp("c:add:"), StrMatch("mult")) assert not parser.error_sink @pytest.mark.parametrize("expression, error", [ ("1 ", UnexpectedEof), ("1|", UnexpectedEof), ("(1|)", UnexpectedToken), ("1=", UnexpectedToken), ]) def test_i_can_detect_errors(context, expression, error): parser = BnfDefinitionParser(context, expression) res = parser.parse() assert res is None assert len(parser.error_sink) > 0 assert isinstance(parser.error_sink[0], error)