diff --git a/src/parsers/BnfParser.py b/src/parsers/BnfParser.py index 3067f0a..333d369 100644 --- a/src/parsers/BnfParser.py +++ b/src/parsers/BnfParser.py @@ -249,7 +249,7 @@ class BnfParser(BaseParser): # (for example of recursive bnf definition) if self.context.obj and hasattr(self.context.obj, "name"): if concept_name == str(self.context.obj.name): - return ConceptExpression(concept_name) + return self.eat_rule_name_if_needed(ConceptExpression(concept_name)) concept = self.context.get_concept(concept_name) if not self.sheerka.is_known(concept): @@ -264,7 +264,7 @@ class BnfParser(BaseParser): expr = ConceptGroupExpression(concept) if self.sheerka.isaset(self.context, concept) \ else ConceptExpression(concept) expr.rule_name = concept.name - return expr + return self.eat_rule_name_if_needed(expr) ret = StrMatch(core.utils.strip_quotes(token.value)) self.next_token() diff --git a/src/parsers/DefaultParser.py b/src/parsers/DefaultParser.py index 1adda35..032b7ae 100644 --- a/src/parsers/DefaultParser.py +++ b/src/parsers/DefaultParser.py @@ -58,7 +58,7 @@ class NameNode(DefaultParserNode): if not first: name += " " - name += token.value[1:-1] if token.type == TokenKind.STRING else token.value + name += token.value[1:-1] if token.type == TokenKind.STRING else str(token.value) first = False return name diff --git a/tests/non_reg/test_sheerka_non_reg.py b/tests/non_reg/test_sheerka_non_reg.py index 3691918..b948eac 100644 --- a/tests/non_reg/test_sheerka_non_reg.py +++ b/tests/non_reg/test_sheerka_non_reg.py @@ -11,6 +11,16 @@ from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka class TestSheerkaNonReg(TestUsingFileBasedSheerka): + def init_scenario(self, init_expressions): + sheerka = self.get_sheerka() + + for expression in init_expressions: + res = sheerka.evaluate_user_input(expression) + assert len(res) == 1, f"Failed to execute '{expression}'" + assert res[0].status, f"Error while executing '{expression}'" + + return sheerka + @pytest.mark.parametrize("text, expected", [ ("1 + 1", 2), ("sheerka.test()", 'I have access to Sheerka !') @@ -522,8 +532,6 @@ as: assert res[0].body == 21 def test_i_can_mix_concept_of_concept(self): - sheerka = self.get_sheerka() - definitions = [ "def concept one as 1", "def concept two as 2", @@ -531,8 +539,7 @@ as: "def concept a plus b as a + b" ] - for definition in definitions: - sheerka.evaluate_user_input(definition) + sheerka = self.init_scenario(definitions) res = sheerka.evaluate_user_input("eval 1 plus 2") assert len(res) == 1 @@ -584,14 +591,28 @@ as: assert res[0].status assert res[0].body == 43 + def test_i_can_use_bnf_alias(self): + definitions = [ + "def concept two as 2", + "def concept number", + "two isa number", + "def concept plus_one from bnf number=n1 'plus_one' as n1 + 1", + ] + + sheerka = self.init_scenario(definitions) + + res = sheerka.evaluate_user_input("eval two plus_one") + assert len(res) == 1 + assert res[0].status + assert res[0].body == 3 + @pytest.mark.xfail - def test_i_can_evaluate_concept_of_concept_when_multiple_choices(self): + def test_i_can_recognize_composition_of_concept(self): sheerka = self.get_sheerka() definitions = [ "def concept little a where a", "def concept blue a where a", - "def concept little blue a where a", "def concept house" ] @@ -610,6 +631,24 @@ as: assert res[1].status assert res[1].body == "little blue(house)" + @pytest.mark.xfail + def test_i_can_recognize_composition_of_concept_with_priority(self): + sheerka = self.get_sheerka() + + definitions = [ + "def concept a plus b where a,b", + "def concept a times b where a,b", + "modify concept 1001 set priority = 1", + "modify concept 1002 set priority = 2", + ] + + for definition in definitions: + sheerka.evaluate_user_input(definition) + + res = sheerka.evaluate_user_input("1 plus 2 times 3") + assert res[0].status + # check that the priority is applied + def test_i_can_say_that_a_concept_isa_another_concept(self): sheerka = self.get_sheerka() sheerka.evaluate_user_input("def concept foo") @@ -790,6 +829,27 @@ as: assert not res[0].status assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) + @pytest.mark.xfail + def test_i_can_manage_missing_variables_from_bnf_parsing(self): + definitions = [ + "def concept one as 1", + "def concept number", + "one isa number", + "def concept hundreds from bnf number=n1 'hundred' ('and' number=n2)? where n1<10 and n2<100 as n1 * 100 + n2", + ] + + sheerka = self.init_scenario(definitions) + + res = sheerka.evaluate_user_input("one hundred") + assert len(res) == 1 + assert res[0].status + assert sheerka.isinstance(res[0].body, "hundreds") + + res = sheerka.evaluate_user_input("eval one hundred") + assert len(res) == 1 + assert res[0].status + assert res[0].body == "100" + def test_i_can_say_than_bnf_concept_isa_another_concept(self): sheerka = self.get_sheerka() sheerka.evaluate_user_input("def concept number") diff --git a/tests/parsers/test_BnfParser.py b/tests/parsers/test_BnfParser.py index f6a9aa7..43298e4 100644 --- a/tests/parsers/test_BnfParser.py +++ b/tests/parsers/test_BnfParser.py @@ -16,9 +16,9 @@ class ClassWithName: self.name = name -def c(name): +def c(name, rule_name=None): concept = Concept(name).init_key() - return ConceptExpression(concept, rule_name=name) + return ConceptExpression(concept, rule_name=rule_name or name) eof_token = Token(TokenKind.EOF, "", 0, 0, 0) @@ -94,6 +94,7 @@ class TestBnfParser(TestUsingMemoryBasedSheerka): ("foo | bar?", OrderedChoice(c("foo"), Optional(c("bar")))), ("'str' = var", Sequence(StrMatch("str"), StrMatch("="), c("var"))), ("'str''='var", Sequence(StrMatch("str"), StrMatch("="), c("var"))), + ("foo=f", c("foo", "f")), ]) def test_i_can_parse_regex_with_concept(self, expression, expected): foo = Concept("foo") @@ -111,10 +112,11 @@ class TestBnfParser(TestUsingMemoryBasedSheerka): assert res.value.value == expected assert res.value.source == expression - def test_i_can_parse_regex_with_concept_when_the_concept_is_still_under_definition(self): - expression = "foo" - expected = ConceptExpression("foo") - + @pytest.mark.parametrize("expression, expected", [ + ("foo", ConceptExpression("foo")), + ("foo=f", ConceptExpression("foo", rule_name="f")), + ]) + def test_i_can_parse_regex_with_concept_when_the_concept_is_still_under_definition(self, expression, expected): context = self.get_context() context.obj = ClassWithName("foo")