Fixed BNF parsing issues

This commit is contained in:
2020-03-10 18:28:11 +01:00
parent b5d56e13f9
commit c9acfa99a1
4 changed files with 77 additions and 15 deletions
+2 -2
View File
@@ -249,7 +249,7 @@ class BnfParser(BaseParser):
# (for example of recursive bnf definition) # (for example of recursive bnf definition)
if self.context.obj and hasattr(self.context.obj, "name"): if self.context.obj and hasattr(self.context.obj, "name"):
if concept_name == str(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) concept = self.context.get_concept(concept_name)
if not self.sheerka.is_known(concept): if not self.sheerka.is_known(concept):
@@ -264,7 +264,7 @@ class BnfParser(BaseParser):
expr = ConceptGroupExpression(concept) if self.sheerka.isaset(self.context, concept) \ expr = ConceptGroupExpression(concept) if self.sheerka.isaset(self.context, concept) \
else ConceptExpression(concept) else ConceptExpression(concept)
expr.rule_name = concept.name expr.rule_name = concept.name
return expr return self.eat_rule_name_if_needed(expr)
ret = StrMatch(core.utils.strip_quotes(token.value)) ret = StrMatch(core.utils.strip_quotes(token.value))
self.next_token() self.next_token()
+1 -1
View File
@@ -58,7 +58,7 @@ class NameNode(DefaultParserNode):
if not first: if not first:
name += " " 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 first = False
return name return name
+66 -6
View File
@@ -11,6 +11,16 @@ from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
class TestSheerkaNonReg(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", [ @pytest.mark.parametrize("text, expected", [
("1 + 1", 2), ("1 + 1", 2),
("sheerka.test()", 'I have access to Sheerka !') ("sheerka.test()", 'I have access to Sheerka !')
@@ -522,8 +532,6 @@ as:
assert res[0].body == 21 assert res[0].body == 21
def test_i_can_mix_concept_of_concept(self): def test_i_can_mix_concept_of_concept(self):
sheerka = self.get_sheerka()
definitions = [ definitions = [
"def concept one as 1", "def concept one as 1",
"def concept two as 2", "def concept two as 2",
@@ -531,8 +539,7 @@ as:
"def concept a plus b as a + b" "def concept a plus b as a + b"
] ]
for definition in definitions: sheerka = self.init_scenario(definitions)
sheerka.evaluate_user_input(definition)
res = sheerka.evaluate_user_input("eval 1 plus 2") res = sheerka.evaluate_user_input("eval 1 plus 2")
assert len(res) == 1 assert len(res) == 1
@@ -584,14 +591,28 @@ as:
assert res[0].status assert res[0].status
assert res[0].body == 43 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 @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() sheerka = self.get_sheerka()
definitions = [ definitions = [
"def concept little a where a", "def concept little a where a",
"def concept blue a where a", "def concept blue a where a",
"def concept little blue a where a",
"def concept house" "def concept house"
] ]
@@ -610,6 +631,24 @@ as:
assert res[1].status assert res[1].status
assert res[1].body == "little blue(house)" 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): def test_i_can_say_that_a_concept_isa_another_concept(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept foo") sheerka.evaluate_user_input("def concept foo")
@@ -790,6 +829,27 @@ as:
assert not res[0].status assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) 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): def test_i_can_say_than_bnf_concept_isa_another_concept(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept number") sheerka.evaluate_user_input("def concept number")
+8 -6
View File
@@ -16,9 +16,9 @@ class ClassWithName:
self.name = name self.name = name
def c(name): def c(name, rule_name=None):
concept = Concept(name).init_key() 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) eof_token = Token(TokenKind.EOF, "", 0, 0, 0)
@@ -94,6 +94,7 @@ class TestBnfParser(TestUsingMemoryBasedSheerka):
("foo | bar?", OrderedChoice(c("foo"), Optional(c("bar")))), ("foo | bar?", OrderedChoice(c("foo"), Optional(c("bar")))),
("'str' = var", Sequence(StrMatch("str"), StrMatch("="), c("var"))), ("'str' = var", Sequence(StrMatch("str"), StrMatch("="), c("var"))),
("'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): def test_i_can_parse_regex_with_concept(self, expression, expected):
foo = Concept("foo") foo = Concept("foo")
@@ -111,10 +112,11 @@ class TestBnfParser(TestUsingMemoryBasedSheerka):
assert res.value.value == expected assert res.value.value == expected
assert res.value.source == expression assert res.value.source == expression
def test_i_can_parse_regex_with_concept_when_the_concept_is_still_under_definition(self): @pytest.mark.parametrize("expression, expected", [
expression = "foo" ("foo", ConceptExpression("foo")),
expected = 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 = self.get_context()
context.obj = ClassWithName("foo") context.obj = ClassWithName("foo")