Fixed #100 : SheerkaAdmin: Add builtins() command

Fixed #99 : SheerkaQueryManager: I can manage contains predicate when filtering objects
Fixed #97 : ERROR: list indices must be integers or slices, not Concept
Fixed #96 : SequenceNodeParser: SequenceNodeParser must correctly handle concept definition
Fixed #95 : ResolveAmbiguity must not remove concepts that do not require evaluation
Fixed #94 : Concepts with the same key are lost when new ontology
Fixed #93 : Introduce BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED
Fixed #92 : ExpressionParser: Implement compile_disjunctions()
Fixed #91 : Implement get_concepts_complexity(context, concepts, concept_parts)
Fixed #90 : ResolveAmbiguity : where predicate is not used to resolve ambiguity
Fixed #89 : ResolveAmbiguityEvaluator: Concepts embedded in ConceptNode are not resolved
Fixed #88: SyaNodeParser: Parse multiple parameters when some of the are not recognized
Fixed #87: SyaNodeParser : Parse the multiple parameters
This commit is contained in:
2021-07-31 08:52:00 +02:00
parent 7dcaa9c111
commit e69745adc8
70 changed files with 1561 additions and 455 deletions
+37 -31
View File
@@ -98,22 +98,24 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
@classmethod
def setup_class(cls):
init_test_helper = cls().init_test(cache_only=False, ontology="#TestBnfNodeParser#")
test_instance = cls()
init_test_helper = test_instance.init_test(cache_only=False, ontology="#TestBnfNodeParser#")
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
for i, concept_name in enumerate(cmap):
cmap[concept_name] = updated[i]
# end of initialisation
global_truth_context = test_instance.get_context(sheerka, global_truth=True)
sheerka = TestBnfNodeParser.sheerka
sheerka.set_isa(context, cmap["one"], cmap["number"])
sheerka.set_isa(context, cmap["two"], cmap["number"])
sheerka.set_isa(context, cmap["three"], cmap["number"])
sheerka.set_isa(context, cmap["four"], cmap["number"])
sheerka.set_isa(context, cmap["thirty"], cmap["number"])
sheerka.set_isa(context, cmap["forty"], cmap["number"])
sheerka.set_isa(context, cmap["fifty"], cmap["number"])
sheerka.set_isa(context, cmap["one hundred"], cmap["number"])
sheerka.set_isa(context, cmap["hundreds"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["one"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["two"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["three"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["four"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["thirty"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["forty"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["fifty"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["one hundred"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["hundreds"], cmap["number"])
# Pay attention. 'twenties (t1 and t2) are not set as 'number'
@@ -122,28 +124,28 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
where="number < 10",
body="thirty + number").def_var("thirty").def_var("number"))
cmap["thirties"] = sheerka.create_new_concept(context, thirties).body.body
sheerka.set_isa(context, sheerka.new("thirties"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("thirties"), sheerka.new("number"))
forties = cls.update_bnf(context, Concept("forties",
definition="forty number",
where="number < 10",
body="forty + number").def_var("forty").def_var("number"))
cmap["forties"] = sheerka.create_new_concept(context, forties).body.body
sheerka.set_isa(context, sheerka.new("forties"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("forties"), sheerka.new("number"))
fifties = cls.update_bnf(context, Concept("fifties",
definition="fifty number",
where="number < 10",
body="fifty + number").def_var("fifty").def_var("number"))
cmap["fifties"] = sheerka.create_new_concept(context, fifties).body.body
sheerka.set_isa(context, sheerka.new("fifties"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("fifties"), sheerka.new("number"))
thousands = cls.update_bnf(context, Concept("thousands",
definition="number 'thousand'",
where="number < 999",
body="number * 1000").def_var("number"))
cmap["thousands"] = sheerka.create_new_concept(context, thousands).body.body
sheerka.set_isa(context, sheerka.new("thousands"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("thousands"), sheerka.new("number"))
cls.shared_ontology = sheerka.get_ontology(context)
sheerka.pop_ontology(context)
@@ -1217,10 +1219,11 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
"twenties": self.bnf_concept("twenties", Sequence(ConceptExpression("twenty"), ConceptExpression("number")))
}
sheerka, context, parser = self.init_parser(my_map)
global_truth_context = self.get_context(sheerka, global_truth=True)
parser.context = context
parser.sheerka = sheerka
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(context, sheerka.new("twenty"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), my_map["number"])
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
@@ -1251,9 +1254,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
sheerka, context, parser = self.init_parser(my_map, singleton=True)
parser.context = context
parser.sheerka = sheerka
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(context, sheerka.new("two"), my_map["number"])
sheerka.set_isa(context, sheerka.new("hundreds"), my_map["number"])
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("two"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("hundreds"), my_map["number"])
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
parsing_expression = parser.get_parsing_expression(context, my_map["hundreds"])
@@ -1281,9 +1285,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
sheerka, context, parser = self.init_parser(my_map, singleton=True)
parser.context = context
parser.sheerka = sheerka
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(context, sheerka.new("twenty"), my_map["number"])
sheerka.set_isa(context, sheerka.new("twenties"), my_map["number"]) # <- twenties is also a number
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("twenties"), my_map["number"]) # <- twenties is also a number
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
@@ -1900,15 +1905,16 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
}
sheerka, context, parser = self.init_parser(my_map, init_from_sheerka=True, create_new=True)
sheerka.set_isa(context, my_map["light_red"], my_map["adjective"])
sheerka.set_isa(context, my_map["dark_red"], my_map["adjective"])
sheerka.set_isa(context, my_map["light_red"], my_map["color"])
sheerka.set_isa(context, my_map["dark_red"], my_map["color"])
sheerka.set_isa(context, my_map["light_red"], my_map["red colors"])
sheerka.set_isa(context, my_map["dark_red"], my_map["red colors"])
sheerka.set_isa(context, my_map["color"], my_map["adjective"])
sheerka.set_isa(context, my_map["red colors"], my_map["color"])
sheerka.set_isa(context, my_map["red colors"], my_map["adjective"])
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["adjective"])
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["adjective"])
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["color"])
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["color"])
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["red colors"])
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["red colors"])
sheerka.set_isa(global_truth_context, my_map["color"], my_map["adjective"])
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["color"])
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["adjective"])
text = "light red table"
+1
View File
@@ -144,6 +144,7 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert concept_found == foo
assert not concept_found.get_hints().need_validation
assert concept_found.get_hints().is_evaluated
assert not concept_found.get_hints().is_instance
def test_i_can_parse_concept_with_concept_tokens(self):
sheerka, context, one, two, plus = self.init_concepts(
+85 -1
View File
@@ -4,7 +4,7 @@ from core.builtin_concepts import BuiltinConcepts
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import TokenKind
from parsers.BaseExpressionParser import TrueifyVisitor, IsAQuestionVisitor, LeftPartNotFoundError, \
ParenthesisMismatchError
ParenthesisMismatchError, compile_disjunctions, NotNode, AndNode, OrNode
from parsers.BaseParser import UnexpectedEofParsingError, UnexpectedTokenParsingError
from parsers.LogicalOperatorParser import LogicalOperatorParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -12,6 +12,46 @@ from tests.parsers.parsers_utils import EXPR, OR, AND, NOT, \
get_expr_node_from_test_node
class DoNotCompareStartStopContextManager:
def __init__(self):
self.original_not_eq = None
self.original_and_eq = None
self.original_or_eq = None
@staticmethod
def not_eq(self, other):
if not isinstance(other, NotNode):
return False
return self.node == other.node
@staticmethod
def and_eq(self, other):
if not isinstance(other, AndNode):
return False
return self.parts == other.parts
@staticmethod
def or_eq(self, other):
if not isinstance(other, OrNode):
return False
return self.parts == other.parts
def __enter__(self):
self.original_not_eq = NotNode.__eq__
self.original_and_eq = AndNode.__eq__
self.original_or_eq = OrNode.__eq__
NotNode.__eq__ = self.not_eq
AndNode.__eq__ = self.and_eq
OrNode.__eq__ = self.or_eq
def __exit__(self, *args):
NotNode.__eq__ = self.original_not_eq
AndNode.__eq__ = self.original_and_eq
OrNode.__eq__ = self.original_or_eq
class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
def init_parser(self):
@@ -175,6 +215,50 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
assert IsAQuestionVisitor().visit(expr_node) == expected
@pytest.mark.parametrize("expression, expected", [
("a", [EXPR("a")]),
("a and b and c", [AND(EXPR("a"), EXPR("b"), EXPR("c"))]),
("a or b or c", [EXPR("a"),
EXPR("b"),
EXPR("c")]),
("a and b or c", [AND(EXPR("a"), EXPR("b")), EXPR("c")]),
("a or b and c", [EXPR("a"),
AND(EXPR("b"), EXPR("c"))]),
("(a or b) and c", [AND(EXPR("a"), EXPR("c")),
AND(EXPR("b"), EXPR("c"))]),
("a or (b or c) and d", [EXPR("a"),
AND(EXPR("b"), EXPR("d")),
AND(EXPR("c"), EXPR("d"))]),
("not a", [NOT(EXPR("a"))]),
("not (a and b)", [NOT(AND(EXPR("a"), EXPR("b")))]),
("not (a or b)", [AND(NOT(EXPR("a")), NOT(EXPR("b")))]),
("(a or b) and not (c or d)", [AND(EXPR("a"), NOT(EXPR("c")), NOT(EXPR("d"))),
AND(EXPR("b"), NOT(EXPR("c")), NOT(EXPR("d")))]),
("(a or b) or not (c or d)", [EXPR("a"),
EXPR("b"),
AND(NOT(EXPR("c")), NOT(EXPR("d")))]),
("(a and b) and not (c or d)", [AND(EXPR("a"), EXPR("b"), NOT(EXPR("c")), NOT(EXPR("d")))]),
("(a and b) or not (c or d)", [AND(EXPR("a"), EXPR("b")),
AND(NOT(EXPR("c")), NOT(EXPR("d")))]),
("a and (b and c)", [AND(EXPR("a"), EXPR("b"), EXPR("c"))]),
("a or (b or c)", [EXPR("a"),
EXPR("b"),
EXPR("c")]),
])
def test_i_can_compile_disjunction(self, expression, expected):
sheerka, context, parser = self.init_parser()
resolved_expected = [get_expr_node_from_test_node(expression, e) for e in expected]
expr_node = parser.parse(context, ParserInput(expression)).body.body
with DoNotCompareStartStopContextManager():
res = compile_disjunctions(expr_node)
assert res == resolved_expected
# @pytest.mark.parametrize("expression, expected", [
# ("foo", "foo"),
# ("one two", "one two"),
+17
View File
@@ -258,6 +258,23 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
compare_with_test_object(lexer_nodes, expected_array)
@pytest.mark.parametrize("concept", [
Concept("foo x", body="1").def_var("x"),
Concept("foo"),
])
def test_i_can_parse_token_concepts(self, concept):
concepts_map = {
"foo": concept,
}
sheerka, context, parser = self.init_parser(concepts_map, create_new=True, use_sheerka=True)
res = parser.parse(context, ParserInput(f"c:{concept.name}:"))
assert res.status
concept_found = res.body.body[0].concept
assert concept_found.get_hints().is_evaluated
assert not concept_found.get_hints().is_instance
@pytest.mark.parametrize("text", [
"foo",
f"foo one",
+81
View File
@@ -709,6 +709,65 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
self.compare_results(res, expected_sequences, cmap, expression)
@pytest.mark.parametrize("expression, expected", [
("suffixed2 a b", ['a', 'b', "suffixed2"]),
("suffixed3 a b c", ['a', 'b', 'c', "suffixed3"]),
("a b prefixed2", ['a', 'b', "prefixed2"]),
("a b c prefixed3", ['a', 'b', 'c', "prefixed3"]),
("start2 a b stop", ['a', 'b', "start2"]),
("start3 a b c stop", ['a', 'b', 'c', "start3"]),
])
def test_i_can_post_fix_when_multiple_parameters_are_expected(self, expression, expected):
concepts_map = {
"a": Concept("a"),
"b": Concept("b"),
"c": Concept("c"),
"suffixed2": Concept("suffixed2 x y").def_var("x").def_var("y"),
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
"prefixed2": Concept("x y prefixed2").def_var("x").def_var("y"),
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
"start2": Concept("start2 x y stop").def_var("x").def_var("y"),
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
}
sheerka, context, parser = self.init_parser(concepts_map, None)
res = parser.infix_to_postfix(context, ParserInput(expression))
expected_array = compute_expected_array(concepts_map, expression, expected)
assert len(res) == 1
transformed_out = get_test_obj(res[0].out, expected_array)
assert transformed_out == expected_array
@pytest.mark.parametrize("expression, expected", [
("suffixed3 x y z", ['x', 'y', 'z', "suffixed3"]),
("suffixed3 a y z", ['a', 'y', 'z', "suffixed3"]),
("suffixed3 x a z", ['x ', 'a', ' z', "suffixed3"]), # this one was not managed by the second chance
("suffixed3 x y a", ['x', 'y', 'a', "suffixed3"]),
("x y z prefixed3", ['x', 'y', 'z', "prefixed3"]),
("a y z prefixed3", ['a', 'y', 'z', "prefixed3"]),
("x a z prefixed3", ['x ', 'a', ' z', "prefixed3"]),
("x y a prefixed3", ['x', 'y', 'a', "prefixed3"]),
("start3 x y z stop", ['x', 'y', 'z', "start3"]),
("start3 a y z stop", ['a', 'y', 'z', "start3"]),
("start3 x a z stop", ['x ', 'a', ' z ', "start3"]),
("start3 x y a stop", ['x', 'y', 'a', "start3"]),
])
def test_i_can_post_fix_when_multiple_parameters_are_expected_but_unrecognized_tokens(self, expression, expected):
concepts_map = {
"a": Concept("a"),
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
}
sheerka, context, parser = self.init_parser(concepts_map, None)
res = parser.infix_to_postfix(context, ParserInput(expression))
expected_array = compute_expected_array(concepts_map, expression, expected)
assert len(res) == 1
transformed_out = get_test_obj(res[0].out, expected_array)
assert transformed_out == expected_array
@pytest.mark.parametrize("expression, expected", [
("(", ("(", 0)),
("one plus ( 1 + ", ("(", 4)),
@@ -1080,6 +1139,28 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
assert isinstance(concept_plus_b[0].body.body, PythonNode)
assert concept_suffixed_a == cmap["two"]
@pytest.mark.parametrize("text, expected", [
("suffixed3 a b c", [("x", "a"), ("y", "b"), ("z", "c")]),
("a b c prefixed3", [("x", "a"), ("y", "b"), ("z", "c")]),
("start3 a b c stop", [("x", "a"), ("y", "b"), ("z", "c")]),
])
def test_i_can_parse_when_multiple_parameters_are_expected(self, text, expected):
concepts_map = {
"a": Concept("a"),
"b": Concept("b"),
"c": Concept("c"),
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
}
sheerka, context, parser = self.init_parser(concepts_map, None)
res = parser.parse(context, ParserInput(text))
lexer_nodes = res.body.body
assert res.status
assert lexer_nodes[0].concept.get_metadata().variables == expected
@pytest.mark.parametrize("text", [
"function(suffixed one)",
"function(one plus two mult three)",
+6 -12
View File
@@ -433,6 +433,10 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
compare_with_test_object(actual_nodes, expected_array)
def test_i_can_parse_when_multiple_atom_and_sya(self):
"""
Testing that the ambiguity between hello_atom and hello_sya is correctly managed
:return:
"""
sheerka, context, parser = self.init_parser()
expression = "two hello one three"
nodes = get_input_nodes_from(concepts_map, expression,
@@ -440,25 +444,15 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
parser_input = ParserResultConcept("parsers.xxx", source=expression, value=nodes)
res = parser.parse(context, parser_input)
assert len(res) == 2
assert res[0].status
assert res[1].status
assert res.status
actual_nodes0 = res[0].body.body
actual_nodes0 = res.body.body
expected_0 = compute_expected_array(concepts_map, expression, [
CN("two", start=0, end=0),
CN("hello_atom", source="hello one", start=2, end=4),
CN("three", start=6, end=6)])
compare_with_test_object(actual_nodes0, expected_0)
actual_nodes1 = res[1].body.body
expected_1 = compute_expected_array(concepts_map, expression, [
CN("two", start=0, end=0),
CNC("hello_sya", "hello one", start=2, end=4, a="one"),
CN("three", start=6, end=6)],
exclude_body=True)
compare_with_test_object(actual_nodes1, expected_1)
def test_i_can_parse_when_multiple_sya_concepts(self):
sheerka, context, parser = self.init_parser()
expression = "greetings two"