71d1b1d1ca
Fixed #103 : Implement PlurialNodeParser Fixed #104 : Implement dynamic concept Fixed #107 : PrepareEvalxxxEvaluator: context hints are lost on a second evaluation
1102 lines
48 KiB
Python
1102 lines
48 KiB
Python
import pytest
|
|
|
|
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
|
|
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, \
|
|
DEFINITION_TYPE_DEF
|
|
from core.global_symbols import NotInit, NotFound
|
|
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
|
|
from core.sheerka.services.SheerkaExecute import ParserInput
|
|
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
|
from parsers.BaseParser import BaseParser
|
|
from parsers.ExactConceptParser import ExactConceptParser
|
|
from parsers.ExpressionParser import ExpressionParser
|
|
from parsers.PythonParser import PythonNode, PythonParser
|
|
from parsers.SyaNodeParser import SyaNodeParser
|
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
|
from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val
|
|
from tests.parsers.parsers_utils import CB, compare_with_test_object
|
|
|
|
|
|
class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
|
|
|
@pytest.mark.parametrize("body, expected", [
|
|
(None, NotInit),
|
|
("", ""),
|
|
("1", 1),
|
|
("1+1", 2),
|
|
("'one'", "one"),
|
|
("'one' + 'two'", "onetwo"),
|
|
("True", True),
|
|
("1 > 2", False),
|
|
])
|
|
def test_i_can_evaluate_a_concept_with_simple_body(self, body, expected):
|
|
sheerka, context, concept = self.init_test(eval_body=True).with_concepts(Concept("foo", body=body)).unpack()
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == expected
|
|
assert evaluated.get_metadata().body == body
|
|
assert evaluated.get_metadata().pre is None
|
|
assert evaluated.get_metadata().post is None
|
|
assert evaluated.get_metadata().where is None
|
|
assert evaluated.variables() == {}
|
|
assert evaluated.get_hints().is_evaluated
|
|
assert len(evaluated.values()) == 0 if body is None else 1
|
|
|
|
assert "foo" in sheerka.services[SheerkaMemory.NAME].registration
|
|
|
|
@pytest.mark.parametrize("expr, expected", [
|
|
("", ""),
|
|
("1", 1),
|
|
("1+1", 2),
|
|
("'one'", "one"),
|
|
("'one' + 'two'", "onetwo"),
|
|
("True", True),
|
|
("1 > 2", False),
|
|
])
|
|
def test_i_can_evaluate_the_other_metadata(self, expr, expected):
|
|
"""
|
|
I only test PRE, it's the same for the others
|
|
:param expr:
|
|
:param expected:
|
|
:return:
|
|
"""
|
|
|
|
sheerka, context, concept = self.init_concepts(Concept("foo", post=expr))
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.get_metadata().body is None
|
|
assert evaluated.get_metadata().post == expr
|
|
assert evaluated.get_metadata().pre is None
|
|
assert evaluated.get_metadata().where is None
|
|
assert evaluated.get_value(ConceptParts.POST) == expected
|
|
assert evaluated.variables() == {}
|
|
assert not evaluated.get_hints().is_evaluated
|
|
assert len(evaluated.values) == 0 if expr is None else 1
|
|
|
|
@pytest.mark.parametrize("expr, expected", [
|
|
(None, NotInit),
|
|
("", ""),
|
|
("1", 1),
|
|
("1+1", 2),
|
|
("'one'", "one"),
|
|
("'one' + 'two'", "onetwo"),
|
|
("True", True),
|
|
("1 > 2", False),
|
|
])
|
|
def test_i_can_evaluate_a_concept_with_variable(self, expr, expected):
|
|
sheerka, context, concept = self.init_concepts(Concept("foo").def_var("a", expr), eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.get_metadata().pre is None
|
|
assert evaluated.get_metadata().pre is None
|
|
assert evaluated.get_metadata().post is None
|
|
assert evaluated.get_metadata().where is None
|
|
assert evaluated.variables() == {"a": expected}
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_i_can_evaluate_when_the_body_is_the_name_of_the_concept(self):
|
|
# to prove that I can distinguish from a string
|
|
sheerka, context, concept = self.init_test(eval_body=True).with_concepts(
|
|
Concept("foo", body="'foo'"),
|
|
create_new=True).unpack()
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == "foo"
|
|
|
|
def test_i_can_evaluate_metadata_using_do_not_resolve(self):
|
|
sheerka, context, concept = self.init_concepts(Concept("foo"), eval_body=True)
|
|
concept.get_compiled()[ConceptParts.BODY] = DoNotResolve("do not resolve")
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.body == "do not resolve"
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_i_can_evaluate_variable_using_do_not_resolve(self):
|
|
sheerka, context, concept = self.init_concepts(Concept("foo").def_var("a"), eval_body=True)
|
|
concept.get_compiled()["a"] = DoNotResolve("do not resolve")
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.get_value("a") == "do not resolve"
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_original_value_is_overridden_when_using_do_no_resolve(self):
|
|
concept = Concept("foo", body="original value").def_var("a", "original value")
|
|
sheerka, context, concept = self.init_concepts(concept, eval_body=True)
|
|
concept.get_compiled()["a"] = DoNotResolve("do not resolve")
|
|
concept.get_compiled()[ConceptParts.BODY] = DoNotResolve("do not resolve")
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.body == "do not resolve"
|
|
assert evaluated.get_value("a") == "do not resolve"
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_variables_are_evaluated_before_body(self):
|
|
sheerka, context, concept = self.init_concepts(Concept("foo", body="a+1").def_var("a", "10"), eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
compare_with_test_object(evaluated, CB(concept, 11))
|
|
|
|
def test_i_can_evaluate_when_another_concept_is_referenced(self):
|
|
sheerka, context, concept_a, concept = self.init_concepts(
|
|
Concept("a"),
|
|
Concept("foo", body="a"),
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
compare_with_test_object(evaluated, CB("foo", CB("a", NotInit)))
|
|
assert evaluated.get_hints().is_evaluated
|
|
assert evaluated.body.get_hints().is_evaluated
|
|
|
|
def test_i_can_evaluate_when_the_referenced_concept_has_a_body(self):
|
|
sheerka, context, concept_a, concept = self.init_concepts(
|
|
Concept("a", body="1"),
|
|
Concept("foo", body="a"),
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
compare_with_test_object(evaluated.body, CB("a", 1))
|
|
assert not concept_a.get_hints().is_evaluated
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_i_can_evaluate_concept_of_concept_when_the_leaf_has_a_body(self):
|
|
sheerka, context, concept_a, concept_b, concept_c, concept_d = self.init_concepts(
|
|
Concept("a", body="'a'"),
|
|
Concept("b", body="a"),
|
|
Concept("c", body="b"),
|
|
Concept("d", body="c"),
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept_d)
|
|
|
|
assert evaluated.key == concept_d.key
|
|
expected = CB("c", CB("b", CB("a", "a")))
|
|
compare_with_test_object(evaluated.body, expected)
|
|
assert sheerka.objvalue(evaluated) == 'a'
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_i_can_evaluate_concept_of_concept_does_not_have_a_body(self):
|
|
sheerka, context, concept_a, concept_b, concept_c, concept_d = self.init_concepts(
|
|
Concept("a"),
|
|
Concept("b", body="a"),
|
|
Concept("c", body="b"),
|
|
Concept("d", body="c"),
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept_d)
|
|
|
|
assert evaluated.key == concept_d.key
|
|
expected = CB("c", CB("b", CB("a", NotInit)))
|
|
compare_with_test_object(evaluated.body, expected)
|
|
compare_with_test_object(sheerka.objvalue(evaluated), CB("a", NotInit))
|
|
assert evaluated.get_hints().is_evaluated
|
|
|
|
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_1(self):
|
|
"""
|
|
The body references a variable.
|
|
The variable reference a concept
|
|
The variable name is also the name of a concept
|
|
:return:
|
|
"""
|
|
sheerka, context, concept_a, concept = self.init_concepts(
|
|
Concept("a"),
|
|
Concept("foo", body="a").def_var("a", "a"),
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
# first, prop a is evaluated to concept_a
|
|
# then body is evaluated to prop a -> concept_a
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == concept_a
|
|
|
|
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_2(self):
|
|
"""
|
|
Same test,
|
|
but the name of the property and the name of the concept are different
|
|
:return:
|
|
"""
|
|
sheerka, context, concept_a = self.init_concepts(Concept(name="a"), eval_body=True)
|
|
|
|
concept = Concept("foo", body="concept_a").def_var("concept_a", "a")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == concept_a
|
|
|
|
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_3(self):
|
|
"""
|
|
The body references a variable.
|
|
The variable reference a concept
|
|
The name of the variable is also the name of a concept, but the variable points to something else
|
|
:return:
|
|
"""
|
|
sheerka, context, concept_a, concept_b = self.init_concepts("a", "b", eval_body=True)
|
|
|
|
concept = Concept("foo", body="a").def_var("a", "b")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == concept_b
|
|
|
|
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_4(self):
|
|
"""
|
|
The body references a variable.
|
|
The variable reference a concept
|
|
:return:
|
|
"""
|
|
sheerka, context, concept_b = self.init_concepts("b", eval_body=True)
|
|
|
|
concept = Concept("foo", body="a").def_var("a", "b")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == concept_b
|
|
|
|
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_with_body(self):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
Concept(name="a", body="1"),
|
|
Concept(name="b", body="2"),
|
|
eval_body=True
|
|
)
|
|
|
|
concept = Concept("foo", body="propA + propB").def_var("propA", "a").def_var("propB", "b")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_can_evaluate_concept_when_variables_is_a_concept(self):
|
|
sheerka, context, concept_a = self.init_concepts(Concept(name="a", body="'a'"), eval_body=True)
|
|
|
|
concept = Concept("foo").def_var("a")
|
|
concept.get_compiled()["a"] = concept_a
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
compare_with_test_object(evaluated.get_value("a"), CB("a", "a"))
|
|
|
|
def test_i_can_evaluate_concept_when_variable_is_a_concept_token(self):
|
|
sheerka, context, concept_a, concept_b = self.init_concepts(
|
|
"a",
|
|
Concept("b").def_var("var_name", "c:a:"), # c:a: means concept 'a'
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept_b)
|
|
|
|
assert evaluated.key == concept_b.key
|
|
assert evaluated.get_value("var_name") == concept_a
|
|
|
|
def test_i_can_evaluate_concept_when_body_isa_concept_token(self):
|
|
sheerka, context, concept_a, concept_b = self.init_concepts(
|
|
"a",
|
|
Concept("b", body="c:a:"), # c:a: means concept 'a'
|
|
eval_body=True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept_b)
|
|
|
|
assert evaluated.key == concept_b.key
|
|
assert evaluated.body == concept_a
|
|
|
|
def test_i_can_evaluate_when_variable_asts_is_a_list(self):
|
|
sheerka = self.get_sheerka()
|
|
foo = Concept("foo", body="1").init_key()
|
|
|
|
concept = Concept("to_eval").def_var("prop")
|
|
concept.get_compiled()["prop"] = [foo, DoNotResolve("1")]
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
|
|
|
variables = evaluated.get_value("prop")
|
|
assert len(variables) == 2
|
|
compare_with_test_object(variables[0], CB("foo", 1))
|
|
assert variables[1] == "1"
|
|
|
|
def test_i_can_evaluate_when_compiled_is_set_up_with_return_value(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
python_node = PythonNode("1 +1 ").init_ast()
|
|
parser_result = ParserResultConcept(parser="who", value=python_node)
|
|
|
|
concept = Concept("to_eval").def_var("prop")
|
|
concept.get_compiled()["prop"] = [ReturnValueConcept("who", True, parser_result)]
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
|
assert evaluated.get_value("prop") == 2
|
|
|
|
# also works when only one return value
|
|
concept = Concept("to_eval").def_var("prop")
|
|
concept.get_compiled()["prop"] = ReturnValueConcept("who", True, parser_result)
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
|
assert evaluated.get_value("prop") == 2
|
|
|
|
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables(self):
|
|
sheerka, context, plus, add = self.init_concepts(
|
|
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
|
|
Concept("add a b", body="a plus b").def_var("a").def_var("b"),
|
|
eval_body=True)
|
|
|
|
add_instance = self.get_concept_instance(sheerka, add, a="1", b="2")
|
|
|
|
evaluated = sheerka.evaluate_concept(context, add_instance)
|
|
|
|
assert evaluated.key == add_instance.key
|
|
assert evaluated.get_hints().is_evaluated
|
|
assert sheerka.objvalue(evaluated) == 3
|
|
|
|
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_and_different_names(self):
|
|
sheerka, context, plus, add = self.init_concepts(
|
|
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
|
|
Concept("add x y", body="x plus y").def_var("x").def_var("y"),
|
|
eval_body=True)
|
|
|
|
add_instance = self.get_concept_instance(sheerka, add, x="1", y="2")
|
|
|
|
evaluated = sheerka.evaluate_concept(context, add_instance)
|
|
|
|
assert evaluated.key == add_instance.key
|
|
assert evaluated.get_hints().is_evaluated
|
|
assert sheerka.objvalue(evaluated) == 3
|
|
|
|
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_multiple_levels(self):
|
|
sheerka, context, plus, add, inc = self.init_concepts(
|
|
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
|
|
Concept("add x y", body="x plus y").def_var("x").def_var("y"),
|
|
Concept("inc number", body="add number 1").def_var("number"),
|
|
eval_body=True)
|
|
|
|
inc_instance = self.get_concept_instance(sheerka, inc, number="1")
|
|
|
|
evaluated = sheerka.evaluate_concept(context, inc_instance)
|
|
|
|
assert evaluated.key == inc_instance.key
|
|
assert evaluated.get_hints().is_evaluated
|
|
assert sheerka.objvalue(evaluated) == 2
|
|
|
|
def test_i_can_evaluate_a_concept_that_references_another_concept_twice(self):
|
|
"""
|
|
Test that a new instance of concept is return when the metadata refers to a concept
|
|
:return:
|
|
"""
|
|
sheerka, context, predicate, foo = self.init_concepts(
|
|
Concept("Sometimes True", body="in_context('a')", pre="is_question()"),
|
|
Concept("foo", pre="Sometimes True"))
|
|
|
|
foo1 = sheerka.new("foo")
|
|
foo1 = sheerka.evaluate_concept(context, foo1) # 'a' is not in context, so it fails
|
|
|
|
context2 = self.get_context(sheerka)
|
|
context2.add_to_protected_hints('a')
|
|
foo2 = sheerka.new("foo")
|
|
foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' is now in context
|
|
|
|
assert sheerka.isinstance(foo1, BuiltinConcepts.CONDITION_FAILED)
|
|
assert sheerka.isinstance(foo2, "foo")
|
|
|
|
def test_i_can_reference_sheerka(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
concept = Concept("foo", body="sheerka.test()").init_key()
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == sheerka.test()
|
|
|
|
def test_variables_values_takes_precedence_over_the_outside_world(self):
|
|
sheerka, context, concept_a, concept_b = self.init_concepts(
|
|
Concept(name="a", body="'concept_a'"),
|
|
Concept(name="b", body="'concept_b'"),
|
|
eval_body=True
|
|
)
|
|
|
|
concept = Concept("foo", body="a")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert evaluated.key == concept.key
|
|
compare_with_test_object(evaluated.body, CB("a", "concept_a")) # this test was already done
|
|
|
|
# so check this one.
|
|
concept = Concept("foo", body="a").def_var("a", "'property_a'")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == 'property_a'
|
|
|
|
# or this one.
|
|
concept = Concept("foo", body="a").def_var("a", "b")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert evaluated.key == concept.key
|
|
compare_with_test_object(evaluated.body, CB("b", "concept_b"))
|
|
|
|
def test_variables_values_takes_precedence(self):
|
|
sheerka, context, concept_a, concept_b = self.init_concepts(
|
|
Concept(name="a", body="'concept_a'"),
|
|
Concept(name="b", body="'concept_b'"),
|
|
eval_body=True
|
|
)
|
|
|
|
concept = Concept("foo", body="a + b").def_var("a", "'prop_a'").init_key()
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == 'prop_aconcept_b'
|
|
|
|
def test_i_can_reference_sub_property_of_a_variable(self):
|
|
sheerka, context, concept_a = self.init_concepts(
|
|
Concept(name="concept_a").def_var("subProp", "'sub_a'"),
|
|
eval_body=True
|
|
)
|
|
|
|
concept = Concept("foo", body="a.subProp").def_var("a", "concept_a")
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
compare_with_test_object(evaluated, CB(concept.key, "sub_a"))
|
|
|
|
def test_i_cannot_evaluate_concept_if_variable_is_in_error(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
concept = Concept(name="concept_a").def_var("subProp", "undef_concept")
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
|
|
|
@pytest.mark.parametrize("where_clause, expected, expected_prop, expected_body", [
|
|
("True", True, None, NotInit),
|
|
("False", False, ConceptParts.WHERE, NotInit),
|
|
("self < 10", False, ConceptParts.WHERE, 10),
|
|
("self < 11", True, None, 10),
|
|
("a < 20", False, "a", NotInit),
|
|
("a > 19", True, None, NotInit),
|
|
("a + self > 20", True, None, 10),
|
|
("a + self < 20", False, ConceptParts.WHERE, 10),
|
|
])
|
|
def test_i_can_evaluate_simple_where(self, where_clause, expected, expected_prop, expected_body):
|
|
# We check that the WHERE condition is correctly evaluated
|
|
# We also check that the body is evaluated only when it's mandatory
|
|
|
|
sheerka, context, concept = self.init_concepts(
|
|
Concept("foo", body="10", where=where_clause).def_var("a", "20"),
|
|
eval_body=False, # to check when the evaluation is forced
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept, eval_body=False)
|
|
|
|
if expected:
|
|
assert evaluated.key == concept.key
|
|
assert concept.body == expected_body
|
|
else:
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
|
|
assert evaluated.body == where_clause
|
|
assert evaluated.concept == concept
|
|
assert evaluated.prop == expected_prop
|
|
assert concept.body == expected_body
|
|
|
|
def test_i_can_evaluate_where_when_using_other_concept(self):
|
|
sheerka, context, foo_true, foo_false = self.init_concepts(
|
|
Concept("foo_true", body="True"),
|
|
Concept("foo_false", body="False"),
|
|
)
|
|
|
|
concept = Concept("foo", where="foo_true")
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
|
|
assert evaluated.key == concept.key
|
|
|
|
concept = Concept("foo", where="foo_false")
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
|
|
assert evaluated.body == "foo_false"
|
|
|
|
concept = Concept("foo", where="foo_false")
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, False), concept)
|
|
assert evaluated.key == concept.key
|
|
|
|
def test_i_can_evaluate_context_hint_multiple_times(self):
|
|
"""
|
|
Previous behaviour (that we want to change)
|
|
When def concept foo as global_truth(xxx) pre yyy
|
|
the context hint for the global truth is set during the initialisation of the ast
|
|
if the body is computed straight away it's ok,
|
|
But if the concept is evaluated a second time, the asts is not computed again, so the context hint is not set
|
|
:return:
|
|
"""
|
|
sheerka, context, foo = self.init_concepts(
|
|
Concept("foo", body="global_truth(in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED))")
|
|
)
|
|
|
|
foo_instance = sheerka.new("foo")
|
|
evaluated = sheerka.evaluate_concept(context, foo_instance, eval_body=False)
|
|
|
|
assert ConceptParts.BODY in evaluated.get_compiled()
|
|
assert evaluated.body == NotInit
|
|
assert not evaluated.get_hints().is_evaluated
|
|
|
|
evaluated = sheerka.evaluate_concept(context, foo_instance, eval_body=True) # evaluate the body this time
|
|
assert isinstance(evaluated.body, bool) and evaluated.body
|
|
|
|
def test_i_can_apply_intermediate_where_condition_using_python(self):
|
|
sheerka, context, one_1, one_str, plus = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("one", body="'one'"),
|
|
Concept("a plus b", body="a + b", where="isinstance(a, int)").def_var("a", "one").def_var("b", "2"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == plus.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_can_apply_intermediate_where_condition_when_multiple_variables_using_python(self):
|
|
sheerka, context, one_1, one_str, two_2, two_str, plus = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("one", body="'one'"),
|
|
Concept("two", body="2"),
|
|
Concept("two", body="'two'"),
|
|
Concept("a plus b",
|
|
body="a + b",
|
|
where="isinstance(a, int) and isinstance(b, int)").def_var("a", "one").def_var("b", "two"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == plus.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_can_apply_intermediate_where_condition_using_other_concepts(self):
|
|
sheerka, context, one_1, one_str, is_an_int, plus = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("one", body="'one'"),
|
|
Concept("x is an int", body="isinstance(x, int)", pre="is_question()").def_var("x"),
|
|
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == plus.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_can_apply_intermediate_where_condition_when_multiple_levels(self):
|
|
sheerka, context, one_1, one_str, is_an_int, is_an_integer, plus = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("one", body="'one'"),
|
|
Concept("x is an int", body="isinstance(x, int)", pre="is_question()").def_var("x"),
|
|
Concept("y is an integer", body="y is an int", pre="is_question()").def_var("y"),
|
|
Concept("a plus b", body="a + b", where="a is an integer").def_var("a", "one").def_var("b", "2"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == plus.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_can_apply_intermediate_where_condition_choosing_the_correct_where_concept(self):
|
|
# in this test, there are two where conditions with the same name
|
|
# We need to use the 'PRE' condition to select the correct one
|
|
sheerka, context, one_1, one_str, is_an_int, is_an_integer, plus = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("one", body="'one'"),
|
|
Concept("x is an int",
|
|
body="isinstance(x, int)",
|
|
pre="in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)").def_var("x"),
|
|
Concept("x is an int", body="False").def_var("x"),
|
|
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == plus.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_can_apply_intermediate_where_condition_when_multiple_variables(self):
|
|
# The test does not work because the and condition is not correctly supported
|
|
# We need the ExpressionParser
|
|
sheerka, context, one_1, one_str, two_2, two_str, is_an_int, plus = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("one", body="'one'"),
|
|
Concept("two", body="2"),
|
|
Concept("two", body="'two'"),
|
|
Concept("x is an int", body="isinstance(x, int)", pre="is_question()").def_var("x"),
|
|
Concept("a plus b",
|
|
body="a + b",
|
|
where="a is an int and isinstance(b, int)").def_var("a", "one").def_var("b", "two"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == plus.key
|
|
assert evaluated.body == 3
|
|
|
|
def test_i_cannot_evaluate_when_intermediate_where_condition_fails(self):
|
|
sheerka, context, one_1, is_an_int, plus = self.init_concepts(
|
|
Concept("one", body="'one'"),
|
|
Concept("x is an int", body="isinstance(x, int)", pre="is_question()").def_var("x"),
|
|
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
|
|
eval_body=True,
|
|
eval_where=True,
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, plus)
|
|
assert evaluated.key == str(BuiltinConcepts.CONDITION_FAILED)
|
|
assert evaluated.body == "a is an int"
|
|
|
|
def test_i_can_enable_disable_where_clause_evaluation(self):
|
|
sheerka, context, concept = self.init_concepts(
|
|
Concept("foo", body="10", where="a > 10").def_var("a", None),
|
|
)
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert evaluated.key == concept.key
|
|
|
|
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
|
|
|
def test_i_can_detect_and_resolve_infinite_recursion_with_numeric_constant(self):
|
|
sheerka, context, one_str, one_digit = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("1", body="one"),
|
|
eval_body=True
|
|
)
|
|
|
|
sheerka.test_only_add_in_cache(one_str)
|
|
sheerka.test_only_add_in_cache(one_digit)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, one_digit)
|
|
assert evaluated.key == one_digit.key
|
|
assert evaluated.body == InfiniteRecursionResolved(1)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, one_str)
|
|
assert evaluated.key == one_str.key
|
|
assert evaluated.body == InfiniteRecursionResolved(1)
|
|
|
|
def test_i_can_detect_and_resolve_infinite_recursion_with_boolean_constant(self):
|
|
sheerka, context, true_str, true_bool = self.init_concepts(
|
|
Concept("true", body="True"),
|
|
Concept("True", body="true"),
|
|
eval_body=True
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, true_str)
|
|
assert evaluated.key == true_str.key
|
|
assert evaluated.body == InfiniteRecursionResolved(True)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, true_bool)
|
|
assert evaluated.key == true_bool.key
|
|
assert evaluated.body == InfiniteRecursionResolved(True)
|
|
|
|
def test_i_can_detect_infinite_recursion_with_constant_with_more_concepts(self):
|
|
sheerka, context, c1, c2, c3, c4 = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("1", body="2"),
|
|
Concept("2", body="3"),
|
|
Concept("3", body="one"),
|
|
eval_body=True
|
|
)
|
|
|
|
for concept, expected in ((c1, 3), (c2, 1), (c3, 2), (c4, 3)):
|
|
evaluated = sheerka.evaluate_concept(context, concept)
|
|
assert evaluated.key == concept.key
|
|
assert evaluated.body == InfiniteRecursionResolved(expected)
|
|
|
|
def test_i_can_detect_infinite_recursion_when_no_constant(self):
|
|
sheerka, context, foo, bar, baz, qux = self.init_concepts(
|
|
Concept("foo", body="bar"),
|
|
Concept("bar", body="baz"),
|
|
Concept("baz", body="qux"),
|
|
Concept("qux", body="foo"),
|
|
eval_body=True
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, foo)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
|
|
assert evaluated.body == {foo, bar, baz, qux}
|
|
|
|
evaluated = sheerka.evaluate_concept(context, bar)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
|
|
assert evaluated.body == {foo, bar, baz, qux}
|
|
|
|
evaluated = sheerka.evaluate_concept(context, baz)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
|
|
assert evaluated.body == {foo, bar, baz, qux}
|
|
|
|
evaluated = sheerka.evaluate_concept(context, qux)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
|
|
assert evaluated.body == {foo, bar, baz, qux}
|
|
|
|
def test_i_can_detect_infinite_recursion(self):
|
|
sheerka, context, foo = self.init_concepts(
|
|
Concept("foo", body="foo"),
|
|
eval_body=True
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, foo)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
|
|
assert evaluated.body == {foo}
|
|
|
|
# def test_i_can_detect_auto_recursion_when_evaluating_another_concept(self):
|
|
# sheerka, context, one_1, one_str, plus = self.init_concepts(
|
|
# Concept("one", body="1"),
|
|
# Concept("one", body="one"),
|
|
# Concept("a plus b", body="a + b", where="isinstance(a, int)").def_var("a", "one").def_var("b", "2")
|
|
# )
|
|
#
|
|
# evaluated = sheerka.evaluate_concept(context, plus, eval_body=True)
|
|
# sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
|
|
|
|
def test_i_can_manage_auto_recursion_when_constant(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
one = Concept("1", body="1")
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), one)
|
|
assert evaluated.key == one.key
|
|
assert evaluated.body == 1
|
|
|
|
def test_i_can_evaluate_thousand_concept(self):
|
|
sheerka, context, thousand, number, forties, forty, one = self.init_concepts(
|
|
Concept("thousand", body="number * 1000").def_var("number"),
|
|
Concept("number"),
|
|
Concept("forties", body="forty + number").def_var("forty").def_var("number"),
|
|
Concept("forty", body="40"),
|
|
Concept("one", body="1"),
|
|
eval_body=True
|
|
)
|
|
|
|
one = sheerka.new("one")
|
|
number2 = sheerka.new("number")
|
|
number2.get_compiled()["one"] = one
|
|
number2.get_compiled()[ConceptParts.BODY] = one
|
|
forties = sheerka.new("forties")
|
|
forties.get_compiled()["forty"] = sheerka.new("forty")
|
|
forties.get_compiled()["number"] = number2
|
|
|
|
number1 = sheerka.new("number")
|
|
number1.get_compiled()["forties"] = forties
|
|
number1.get_compiled()[ConceptParts.BODY] = forties
|
|
|
|
forty_one_thousand = sheerka.new("thousand")
|
|
forty_one_thousand.get_compiled()["number"] = number1
|
|
|
|
evaluated = sheerka.evaluate_concept(context, forty_one_thousand)
|
|
|
|
assert evaluated.body == 41000
|
|
|
|
def test_i_can_evaluate_command(self):
|
|
sheerka, context, command = self.init_concepts(Concept("command", body="a = 10"))
|
|
|
|
evaluated = sheerka.evaluate_concept(context, command)
|
|
assert evaluated.key == command.key
|
|
assert sheerka.get_from_memory(context, "a") == NotFound
|
|
|
|
sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.AUTO_EVAL))
|
|
evaluated = sheerka.evaluate_concept(context, sheerka.new("command"))
|
|
assert evaluated.key == command.key
|
|
assert sheerka.get_from_memory(context, "a").obj == 10
|
|
|
|
def test_python_builtin_function_are_forbidden_in_where_pre_post_ret(self, capsys):
|
|
# I do the test only for PRE, as it will be the same for the other ConceptPart
|
|
sheerka, context, foo, bar = self.init_concepts(
|
|
Concept("foo", body="print('10')"), # print will be executed
|
|
Concept("bar", pre="print('10')"), # print won't be executed
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True)
|
|
captured = capsys.readouterr()
|
|
assert evaluated.key == foo.key
|
|
assert captured.out == "10\n"
|
|
|
|
evaluated = sheerka.evaluate_concept(context, bar)
|
|
captured = capsys.readouterr()
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
|
error = evaluated.body
|
|
assert sheerka.isinstance(error, BuiltinConcepts.ERROR)
|
|
assert captured.out == ""
|
|
|
|
def test_i_can_failed_a_concept_when_pre_clause_is_not_validated(self, capsys):
|
|
sheerka, context, concept = self.init_concepts(
|
|
Concept("foo", pre="in_context('foo')", body="print('10')"),
|
|
)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
|
|
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
|
|
assert evaluated.body == "in_context('foo')"
|
|
assert evaluated.concept == concept
|
|
assert evaluated.prop == ConceptParts.PRE
|
|
|
|
captured = capsys.readouterr()
|
|
assert captured.out == ""
|
|
|
|
@pytest.mark.parametrize("concept, eval_body, expected", [
|
|
(Concept("foo"), False, []),
|
|
(Concept("foo", pre="pre", post="post", ret="ret", where="where"), False, ["#pre#", "#post#"]),
|
|
(Concept("foo", pre="pr", post="p", ret="r", where="w"), True,
|
|
["#pre#", "variables", "#body#", "#ret#", "#post#"]),
|
|
|
|
(Concept("foo", pre="pre", body="body"), False, ["#pre#"]),
|
|
(Concept("foo", pre="pre", body="body"), True, ["#pre#", "variables", "#body#"]),
|
|
(Concept("foo", pre="a").def_var("a"), False, ["variables", "#pre#"]),
|
|
(Concept("foo", pre="self"), False, ["#body#", "#pre#"]),
|
|
(Concept("foo", pre="self + a").def_var("a"), False, ["variables", "#body#", "#pre#"]),
|
|
|
|
(Concept("foo", pre="self + a", ret="ret").def_var("a"), False, ["variables", "#body#", "#pre#"]),
|
|
(Concept("foo", pre="self + a", ret="ret").def_var("a"), True, ["variables", "#body#", "#pre#", "#ret#"]),
|
|
(Concept("foo", body="body"), False, [])
|
|
])
|
|
def test_i_can_compute_metadata_to_eval(self, concept, eval_body, expected):
|
|
sheerka, context, concept = self.init_concepts(concept)
|
|
service = sheerka.services[SheerkaEvaluateConcept.NAME]
|
|
|
|
if eval_body:
|
|
context.add_to_protected_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
|
|
|
service.initialize_concept_asts(context, concept)
|
|
assert service.compute_metadata_to_eval(context, concept) == expected
|
|
|
|
def test_i_can_compute_metadata_to_eval_for_where_and_body(self):
|
|
sheerka = self.get_sheerka()
|
|
service = sheerka.services[SheerkaEvaluateConcept.NAME]
|
|
|
|
context = self.get_context(sheerka, eval_where=True)
|
|
concept = Concept("foo", where="where")
|
|
service.initialize_concept_asts(context, concept)
|
|
assert service.compute_metadata_to_eval(context, concept) == ["#where#"]
|
|
|
|
concept = Concept("foo", where="a").def_var("a")
|
|
service.initialize_concept_asts(context, concept)
|
|
assert service.compute_metadata_to_eval(context, concept) == ["variables", "#where#"]
|
|
|
|
concept = Concept("foo", where="self")
|
|
service.initialize_concept_asts(context, concept)
|
|
assert service.compute_metadata_to_eval(context, concept) == ["#body#", "#where#"]
|
|
|
|
context = self.get_context(sheerka, eval_body=True)
|
|
concept = Concept("foo")
|
|
assert service.compute_metadata_to_eval(context, concept) == ["variables", "#body#"]
|
|
|
|
context = self.get_context(sheerka, eval_body=True)
|
|
concept = Concept("foo").def_var("a")
|
|
assert service.compute_metadata_to_eval(context, concept) == ["variables", "#body#"]
|
|
|
|
context = self.get_context(sheerka, eval_body=True)
|
|
concept = Concept("foo", body="body").def_var("a")
|
|
assert service.compute_metadata_to_eval(context, concept) == ["variables", "#body#"]
|
|
|
|
@pytest.mark.parametrize("concept, expected", [
|
|
(Concept("foo"), True),
|
|
])
|
|
def test_is_evaluated_is_correctly_set(self, concept, expected):
|
|
sheerka, context, concept = self.init_concepts(concept)
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
|
|
|
|
assert evaluated.key == concept.key
|
|
assert concept.get_hints().is_evaluated == expected
|
|
|
|
def test_i_only_compute_the_requested_metadata(self):
|
|
sheerka, context, concept = self.init_concepts(
|
|
Concept("foo", pre="True", post="'post'", ret="'ret'", where="True", body="'body'").def_var("a", "'a'")
|
|
)
|
|
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) # to prove that we do not care
|
|
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) # to prove that we do not care
|
|
|
|
evaluated = sheerka.evaluate_concept(context, concept, metadata=[ConceptParts.PRE])
|
|
assert evaluated.values() == {"a": NotInit, ConceptParts.PRE: True}
|
|
|
|
def test_i_can_manage_ret(self):
|
|
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="foo"))
|
|
|
|
res = sheerka.evaluate_concept(context, bar)
|
|
assert sheerka.isinstance(res, "bar")
|
|
|
|
res = sheerka.evaluate_concept(context, bar, eval_body=True)
|
|
assert sheerka.isinstance(res, "foo")
|
|
|
|
# And the result is still the same after a second call
|
|
assert bar.get_hints().is_evaluated
|
|
res = sheerka.evaluate_concept(context, bar, eval_body=True)
|
|
assert sheerka.isinstance(res, "foo")
|
|
|
|
def test_ret_is_evaluated_only_is_body_is_requested(self):
|
|
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="__NOT_FOUND"))
|
|
|
|
res = sheerka.evaluate_concept(context, bar, eval_body=False)
|
|
assert res.id == bar.id
|
|
|
|
def test_i_can_eval_concept_with_rules(self):
|
|
sheerka, context, foo = self.init_concepts(Concept("foo a", body="a.name").def_var("a", "r:|1:"))
|
|
|
|
res = sheerka.evaluate_concept(context, foo, eval_body=True)
|
|
assert res.body == "Print return values"
|
|
|
|
def test_i_can_manage_python_concept_infinite_recursion_when_initializing_ast(self):
|
|
sheerka, context, foo = self.init_concepts(Concept("a + b", body="a + b").def_var("a").def_var("b"))
|
|
evaluator = SheerkaEvaluateConcept(sheerka)
|
|
|
|
evaluator.initialize_concept_asts(context, foo)
|
|
res = foo.get_compiled()["#body#"]
|
|
|
|
assert len(res) == 1
|
|
assert sheerka.isinstance(res[0], BuiltinConcepts.RETURN_VALUE)
|
|
assert res[0].who == BaseParser.get_name(PythonParser.NAME)
|
|
|
|
# TODO validate that a rule is created
|
|
|
|
def test_can_detect_recursive_definition_with_exact_concept(self):
|
|
sheerka, context, foo = self.init_concepts("foo")
|
|
evaluator = SheerkaEvaluateConcept(sheerka)
|
|
|
|
# 'def concept foo as foo'
|
|
return_values = [pr_ret_val(foo, parser="ExactConcept"), python_ret_val("foo")]
|
|
|
|
res = evaluator.get_recursive_definitions(context, foo, return_values)
|
|
|
|
assert list(res) == [BaseParser.get_name("ExactConcept")]
|
|
|
|
def test_i_can_detect_when_no_recursive_definition(self):
|
|
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
|
evaluator = SheerkaEvaluateConcept(sheerka)
|
|
|
|
# 'def concept foo as bar'
|
|
return_values = [pr_ret_val(bar, parser="ExactConcept"), python_ret_val("foo")]
|
|
|
|
res = evaluator.get_recursive_definitions(context, foo, return_values)
|
|
|
|
assert list(res) == []
|
|
|
|
def test_i_can_detect_when_no_recursive_definition2(self):
|
|
sheerka, context, q = self.init_concepts(
|
|
Concept("q", definition="q ?", definition_type=DEFINITION_TYPE_DEF).def_var("q"))
|
|
evaluator = SheerkaEvaluateConcept(sheerka)
|
|
|
|
# i dunno how to construct the return value
|
|
return_values = [pr_ret_val(q, parser="ExactConcept")]
|
|
|
|
res = evaluator.get_recursive_definitions(context, q, return_values)
|
|
|
|
assert list(res) == []
|
|
|
|
def test_i_do_not_mess_up_use_copy_when_exact_concept(self):
|
|
sheerka, context, one, number, isa = self.init_concepts(
|
|
"one",
|
|
"number",
|
|
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
|
|
|
|
evaluator = SheerkaEvaluateConcept(sheerka)
|
|
|
|
parsed_return_value = ExactConceptParser().parse(context, ParserInput("one is a number"))
|
|
concept = parsed_return_value[0].body.body
|
|
|
|
# just get the compiled
|
|
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
|
evaluated = evaluator.evaluate_concept(context, concept)
|
|
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
|
|
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
|
|
|
|
# get the body
|
|
evaluated = evaluator.evaluate_concept(context, concept, eval_body=True)
|
|
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
|
|
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
|
|
assert not evaluated.get_value("x").get_hints().use_copy
|
|
assert not evaluated.get_value("y").get_hints().use_copy
|
|
|
|
def test_i_do_not_mess_up_use_copy_when_expression_parser(self):
|
|
sheerka, context, one, number, isa = self.init_concepts(
|
|
"one",
|
|
"number",
|
|
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
|
|
|
|
evaluator = SheerkaEvaluateConcept(sheerka)
|
|
|
|
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
|
|
concept = next(iter(parsed_return_value.body.body.compiled[0].return_value.body.body.objects.values()))
|
|
assert concept.get_compiled()["x"][0].body.body.get_hints().use_copy
|
|
assert concept.get_compiled()["y"][0].body.body.get_hints().use_copy
|
|
|
|
# get the body
|
|
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
|
evaluated = evaluator.evaluate_concept(context, concept, eval_body=True)
|
|
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
|
|
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
|
|
assert not evaluated.get_value("x").get_hints().use_copy
|
|
assert not evaluated.get_value("y").get_hints().use_copy
|
|
|
|
def test_i_do_not_evaluate_the_body_when_validation_only_is_set(self):
|
|
sheerka, context, red, shirt, a_x, red_x = self.init_concepts(
|
|
"red",
|
|
Concept("shirt", body="set_attr(self, 'body_shirt_is_evaluated', True)"),
|
|
Concept("a x", body="set_attr(x, 'body_ax_is_evaluated', True)", ret="x").def_var("x"),
|
|
Concept("red x", body="set_attr(x, 'color', 'red')", ret="x").def_var("x"),
|
|
create_new=True)
|
|
|
|
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
|
|
|
|
# Sanity check for normal behaviour
|
|
to_evaluate1 = parsed_ret_val.body.body[0].concept.copy()
|
|
evaluated1 = sheerka.evaluate_concept(context, to_evaluate1, eval_body=True, validation_only=False)
|
|
|
|
assert sheerka.isinstance(evaluated1, shirt)
|
|
assert evaluated1.get_value("body_ax_is_evaluated") == True
|
|
assert evaluated1.get_value("body_shirt_is_evaluated") == True
|
|
assert evaluated1.get_value("color") == "red"
|
|
assert evaluated1.body == sheerka.new(BuiltinConcepts.SUCCESS)
|
|
|
|
# check validation_only behaviour
|
|
to_evaluate2 = parsed_ret_val.body.body[0].concept.copy()
|
|
evaluated2 = sheerka.evaluate_concept(context, to_evaluate2, eval_body=True, validation_only=True)
|
|
|
|
assert sheerka.isinstance(evaluated2, shirt)
|
|
assert evaluated2.get_value("body_ax_is_evaluated") == NotInit
|
|
assert evaluated2.get_value("body_shirt_is_evaluated") == NotInit
|
|
assert evaluated2.get_value("color") == NotInit
|
|
assert evaluated2.body == NotInit
|
|
|
|
def test_methods_with_side_effect_are_not_called_when_eval_body_is_false(self):
|
|
sheerka, context, red, shirt, a_x, red_x = self.init_concepts(
|
|
"red",
|
|
Concept("shirt", body="set_attr(self, 'body_shirt_is_evaluated', True)"),
|
|
Concept("a x", body="set_attr(x, 'body_ax_is_evaluated', True)", ret="x").def_var("x"),
|
|
Concept("red x", body="set_attr(x, 'color', 'red')", ret="x").def_var("x"),
|
|
create_new=True,
|
|
)
|
|
|
|
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
|
|
to_evaluate = parsed_ret_val.body.body[0].concept
|
|
|
|
evaluated = sheerka.evaluate_concept(context, to_evaluate, eval_body=False)
|
|
|
|
assert sheerka.isinstance(evaluated, a_x)
|
|
assert "x" in evaluated.get_compiled()
|
|
assert ConceptParts.BODY in evaluated.get_compiled()
|
|
assert ConceptParts.RET in evaluated.get_compiled()
|
|
assert sheerka.isinstance(evaluated.get_compiled()["x"], red_x)
|
|
assert evaluated.get_compiled()["x"].get_compiled()["x"] == shirt # so, it's not evaluated
|
|
|
|
# sanity check
|
|
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
|
|
to_evaluate = parsed_ret_val.body.body[0].concept
|
|
evaluated = sheerka.evaluate_concept(context, to_evaluate, eval_body=True)
|
|
|
|
assert sheerka.isinstance(evaluated, shirt)
|
|
assert evaluated.get_value("body_ax_is_evaluated") == True
|
|
assert evaluated.get_value("body_shirt_is_evaluated") == True
|
|
assert evaluated.get_value("color") == "red"
|
|
|
|
def test_concept_is_not_evaluated_when_method_access_error(self):
|
|
sheerka, context, foo = self.init_concepts(Concept("foo", body="set_attr(self, 'prop_name', 'prop_value')"))
|
|
|
|
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True, validation_only=True)
|
|
|
|
assert sheerka.isinstance(evaluated, foo)
|
|
assert not foo.get_hints().is_evaluated
|