From 81b23556338ca06d3c6760d05c55c3b70016748d Mon Sep 17 00:00:00 2001 From: Kodjo Sossouvi Date: Fri, 27 Dec 2019 14:43:36 +0100 Subject: [PATCH] Fixed EvalEvaluator when there is nothing to evaluate --- docs/blog.rst | 20 +++++++++++++++++++- evaluators/EvalEvaluator.py | 27 ++++++++++++++++----------- tests/test_EvalEvaluator.py | 27 ++++++++++++++++++++++++--- tests/test_sheerka_call_evaluators.py | 22 ++++++++++++++++++++++ tests/test_sheerka_non_reg.py | 16 ++++++++++++++++ 5 files changed, 97 insertions(+), 15 deletions(-) diff --git a/docs/blog.rst b/docs/blog.rst index c9cede7..dbbf485 100644 --- a/docs/blog.rst +++ b/docs/blog.rst @@ -749,4 +749,22 @@ The ParsingExpression The [Non]TerminalNode represents what was found. So similarly to the ConceptNode, you will find the start, end and token attributes -That's all for today ! \ No newline at end of file +That's all for today ! + +2019-27-12 +********** + +How to manage variables resolutions +""""""""""""""""""""""""""""""""""" + +I have to admit that I am a little bit stuck with how to manage variable resolution with PythonEvaluator. +What is expected by the expression depends on the expression itself. + +Let's see an example + +:: + + def concept one as 1 + def concept two as 2 + + eval one + two \ No newline at end of file diff --git a/evaluators/EvalEvaluator.py b/evaluators/EvalEvaluator.py index e7ee307..f84703a 100644 --- a/evaluators/EvalEvaluator.py +++ b/evaluators/EvalEvaluator.py @@ -12,8 +12,6 @@ class EvalEvaluator(AllReturnValuesEvaluator): def __init__(self): super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 80) - self.successful_return_value = None - self.to_eval = [] self.eval_requested = None def matches(self, context, return_values): @@ -21,18 +19,25 @@ class EvalEvaluator(AllReturnValuesEvaluator): for ret in return_values: if ret.status and sheerka.isinstance(ret.body, BuiltinConcepts.CONCEPT_EVAL_REQUESTED): self.eval_requested = ret - elif ret.status and isinstance(ret.body, Concept) and ret.body.body: - self.to_eval.append(ret) + return True - return self.eval_requested is not None and len(self.to_eval) > 0 + return False - def eval(self, context, return_value): + def eval(self, context, return_values): sheerka = context.sheerka result = [] - context.log(self.verbose_log, f"{len(self.to_eval)} return value(s) to eval", who=self) - for ret_val in self.to_eval: - context.log(self.verbose_log, f"{ret_val}", who=self) - result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested])) + for ret_val in return_values: + if ret_val.status and isinstance(ret_val.body, Concept) and ret_val.body.body: + context.log(self.verbose_log, f"Evaluating {ret_val}", who=self) + result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested])) - return result + if len(result) > 0: + return result + else: + # suppress the successful BuiltinConcepts.CONCEPT_EVAL_REQUESTED + return sheerka.ret( + self.name, + False, + sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED), + parents=[self.eval_requested]) diff --git a/tests/test_EvalEvaluator.py b/tests/test_EvalEvaluator.py index 63eea63..be633e2 100644 --- a/tests/test_EvalEvaluator.py +++ b/tests/test_EvalEvaluator.py @@ -49,11 +49,32 @@ def test_i_can_match_and_eval(): @pytest.mark.parametrize("return_values, expected", [ ([r(Concept("foo", body="bar")), eval_requested], True), - ([r(Concept("status is false", body="bar"), False), eval_requested], False), - ([r("string_value"), eval_requested], False), - ([r(Concept("no body")), eval_requested], False), + ([r(Concept("status is false", body="bar"), False), eval_requested], True), + ([r("string_value"), eval_requested], True), + ([r(Concept("no body")), eval_requested], True), ([r(Concept("eval requested missing", body="bar"))], False), ]) def test_i_cannot_match_if_eval_request_is_not_present(return_values, expected): context = get_context() assert EvalEvaluator().matches(context, return_values) == expected + + +def test_concept_eval_requested_is_reduced_when_nothing_to_reduce(): + context = get_context() + + return_values = [ + ReturnValueConcept("some_name", True, "not to eval"), + ReturnValueConcept("some_name", True, Concept(name="not to eval")), + ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")), + eval_requested + ] + + evaluator = EvalEvaluator() + assert evaluator.matches(context, return_values) + + evaluated = evaluator.eval(context, return_values) + assert evaluated == ReturnValueConcept( + "evaluators.Eval", + False, + context.sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)) + assert evaluated.parents == [eval_requested] diff --git a/tests/test_sheerka_call_evaluators.py b/tests/test_sheerka_call_evaluators.py index 861c6b6..c42c391 100644 --- a/tests/test_sheerka_call_evaluators.py +++ b/tests/test_sheerka_call_evaluators.py @@ -162,6 +162,28 @@ class EvaluatorAllReduceFooBar(EvaluatorAllWithPriority): return ret +class EvaluatorAllSuppressFooEntry(EvaluatorAllWithPriority): + + def __init__(self): + super().__init__("suppress", 100) + + def matches(self, context, return_values): + super().matches(context, return_values) + return True + + def eval(self, context, return_values): + super().eval(context, return_values) + foo = None + for ret in return_values: + if ret.body.name == "foo": + foo = ret + + if foo: + return context.sheerka.ret(self.name, False, Concept("does not matter"), parents=[foo]) + else: + return None + + def test_that_return_values_is_unchanged_when_no_evaluator(): sheerka = get_sheerka() sheerka.evaluators = [] diff --git a/tests/test_sheerka_non_reg.py b/tests/test_sheerka_non_reg.py index 4d39649..87ed695 100644 --- a/tests/test_sheerka_non_reg.py +++ b/tests/test_sheerka_non_reg.py @@ -400,3 +400,19 @@ def test_i_can_say_that_a_concept_isa_another_concept(): res = sheerka.evaluate_user_input("foo isa bar") assert res[0].status assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS) + + +def test_eval_does_not_break_valid_result(): + sheerka = get_sheerka() + sheerka.evaluate_user_input("def concept one as 1") + sheerka.evaluate_user_input("def concept two as 2") + + res = sheerka.evaluate_user_input("one + two") + assert len(res) == 1 + assert res[0].status + assert res[0].body == 3 + + res = sheerka.evaluate_user_input("eval one + two") + assert len(res) == 1 + assert res[0].status + assert res[0].body == 3