Fixed BNF parsing issues
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user