You must now use 'eval' to get the body of a concept
This commit is contained in:
@@ -19,6 +19,9 @@ class BaseEvaluator:
|
||||
self.priority = priority
|
||||
self.enabled = enabled
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.name} ({self.priority})"
|
||||
|
||||
|
||||
class OneReturnValueEvaluator(BaseEvaluator):
|
||||
"""
|
||||
@@ -37,8 +40,13 @@ class AllReturnValuesEvaluator(BaseEvaluator):
|
||||
Evaluates the groups of ReturnValues
|
||||
"""
|
||||
|
||||
def __init__(self, name, steps, priority: int, enabled=True):
|
||||
super().__init__(name, steps, priority, enabled)
|
||||
self.eaten = []
|
||||
|
||||
def matches(self, context: ExecutionContext, return_values):
|
||||
pass
|
||||
|
||||
def eval(self, context: ExecutionContext, return_values):
|
||||
pass
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ class ConceptEvaluator(OneReturnValueEvaluator):
|
||||
BuiltinConcepts.AFTER_EVALUATION
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, return_body=False):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 50)
|
||||
self.return_body = return_body
|
||||
|
||||
def matches(self, context, return_value):
|
||||
return return_value.status and \
|
||||
@@ -35,7 +36,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
|
||||
# If we evaluate Concept("foo", body="a").set_prop("a", "'property_a'")
|
||||
# The body should be 'property_a', and not a concept called a in our universe
|
||||
if context.obj and concept.name in context.obj.props:
|
||||
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.NOT_FOR_ME), parents=[return_value])
|
||||
return sheerka.ret(self.name, True, context.obj.props[concept.name].value, parents=[return_value])
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, concept, self.verbose_log)
|
||||
|
||||
@@ -48,7 +49,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
|
||||
evaluated,
|
||||
parents=[return_value])
|
||||
|
||||
if ConceptParts.BODY not in evaluated.cached_asts:
|
||||
if not self.return_body or ConceptParts.BODY not in evaluated.cached_asts:
|
||||
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
|
||||
else:
|
||||
return sheerka.ret(self.name, True, evaluated.body, parents=[return_value])
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from evaluators.AddConceptEvaluator import AddConceptEvaluator
|
||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProviderDuplicateKeyError
|
||||
|
||||
|
||||
class DuplicateConceptEvaluator(AllReturnValuesEvaluator):
|
||||
"""
|
||||
Use to recognize when we tried to add the same concept twice
|
||||
"""
|
||||
|
||||
NAME = "DuplicateConcept"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
|
||||
self.already_defined = None
|
||||
|
||||
def matches(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
parsing = False
|
||||
add_concept_in_error = False
|
||||
only_parsers = True
|
||||
|
||||
for ret in return_values:
|
||||
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
||||
if ret.status:
|
||||
parsing = True
|
||||
elif ret.who == sheerka.get_evaluator_name(AddConceptEvaluator.NAME):
|
||||
if not ret.status and isinstance(ret.value.body, SheerkaDataProviderDuplicateKeyError):
|
||||
add_concept_in_error = True
|
||||
self.already_defined = ret.value.body.obj
|
||||
else:
|
||||
if not ret.who.startswith(BaseParser.PREFIX):
|
||||
only_parsers = False
|
||||
|
||||
return parsing and add_concept_in_error and only_parsers
|
||||
|
||||
def eval(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
return sheerka.ret(
|
||||
self.name,
|
||||
False,
|
||||
sheerka.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=self.already_defined),
|
||||
parents=return_values)
|
||||
@@ -0,0 +1,38 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
||||
|
||||
|
||||
class EvalEvaluator(AllReturnValuesEvaluator):
|
||||
"""
|
||||
Returns the body of all successful concepts
|
||||
"""
|
||||
|
||||
NAME = "Eval"
|
||||
|
||||
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):
|
||||
sheerka = context.sheerka
|
||||
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 self.eval_requested is not None and len(self.to_eval) > 0
|
||||
|
||||
def eval(self, context, return_value):
|
||||
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]))
|
||||
|
||||
return result
|
||||
@@ -1,6 +1,9 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
import core.builtin_helpers
|
||||
from core.concept import Concept
|
||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator, BaseEvaluator
|
||||
from evaluators.ConceptEvaluator import ConceptEvaluator
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
|
||||
|
||||
@@ -15,38 +18,66 @@ class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
|
||||
NAME = "MultipleSameSuccess"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 50)
|
||||
self.success = []
|
||||
|
||||
def matches(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
after_evaluation = False
|
||||
nb_successful_evaluators = 0
|
||||
only_parsers_in_error = True
|
||||
unlisted = False
|
||||
to_process = False
|
||||
|
||||
for ret in return_values:
|
||||
|
||||
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
||||
if ret.status:
|
||||
after_evaluation = True
|
||||
|
||||
if ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
|
||||
to_process = True
|
||||
self.eaten.append(ret)
|
||||
elif ret.who.startswith(BaseEvaluator.PREFIX):
|
||||
if ret.status:
|
||||
nb_successful_evaluators += 1
|
||||
self.success.append(ret)
|
||||
self.eaten.append(ret)
|
||||
elif ret.who.startswith(BaseParser.PREFIX):
|
||||
self.eaten.append(ret)
|
||||
if ret.status:
|
||||
only_parsers_in_error = False
|
||||
else:
|
||||
unlisted = True
|
||||
|
||||
return after_evaluation and nb_successful_evaluators > 1 and only_parsers_in_error and not unlisted
|
||||
return to_process and nb_successful_evaluators > 1 and only_parsers_in_error
|
||||
|
||||
def eval(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
if core.builtin_helpers.is_same_success(sheerka, self.success):
|
||||
reference = sheerka.value(self.success[0].value, allow_none_body=True)
|
||||
return sheerka.ret(self.name, True, reference, parents=return_values)
|
||||
context.log(self.verbose_log, f"{len(self.success)} successful return value(s)", who=self)
|
||||
for s in self.success:
|
||||
context.log(self.verbose_log, f"{s}", who=self)
|
||||
|
||||
if not core.builtin_helpers.is_same_success(sheerka, self.success):
|
||||
return None
|
||||
|
||||
# ######################################
|
||||
# !!!!! W A R N I N G !!!!!!!!
|
||||
# I have a massive issue with how I implement this feature
|
||||
# I have forced an arbitrary order between Concept evaluator and Python evaluator
|
||||
# I gave a random order to the other
|
||||
#
|
||||
# I guess that we need a proper algorithm to elect which return value to use if they have the same result
|
||||
# I guts feeling is that, it will depend on the intent of the user
|
||||
# So it depends on the context
|
||||
|
||||
# try to return a concept if possible
|
||||
# give the priority to the ConceptEvaluator
|
||||
for s in self.success:
|
||||
if isinstance(s.value, Concept) and s.who == ConceptEvaluator().name:
|
||||
return sheerka.ret(self.name, True, s.value, parents=self.eaten)
|
||||
|
||||
# Then the PythonEvaluator
|
||||
for s in self.success:
|
||||
if isinstance(s.value, Concept) and s.who == PythonEvaluator().name:
|
||||
return sheerka.ret(self.name, True, s.value, parents=self.eaten)
|
||||
|
||||
# Then the first concept.
|
||||
# It's not predictable, so I guess that it's not a good implementation choice
|
||||
for s in self.success:
|
||||
if isinstance(s.value, Concept):
|
||||
return sheerka.ret(self.name, True, s.value, parents=self.eaten)
|
||||
|
||||
return sheerka.ret(self.name, True, self.success[0].value, parents=self.eaten)
|
||||
|
||||
return None
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
|
||||
|
||||
class OneErrorEvaluator(AllReturnValuesEvaluator):
|
||||
"""
|
||||
Use to reduce when there is only one evaluator in error
|
||||
The rest of the return values must be parsers in error
|
||||
"""
|
||||
|
||||
NAME = "OneError"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 40)
|
||||
self.return_value_in_error = None
|
||||
|
||||
def matches(self, context, return_values):
|
||||
nb_evaluators_in_error = 0
|
||||
to_process = False
|
||||
|
||||
for ret in return_values:
|
||||
if ret.status and (ret.who.startswith(self.PREFIX) or ret.who.startswith(BaseParser.PREFIX)):
|
||||
return False
|
||||
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
|
||||
to_process = True
|
||||
self.eaten.append(ret)
|
||||
elif not ret.status and ret.who.startswith(self.PREFIX):
|
||||
nb_evaluators_in_error += 1
|
||||
self.return_value_in_error = ret
|
||||
self.eaten.append(ret)
|
||||
elif not ret.status and ret.who.startswith(BaseParser.PREFIX):
|
||||
self.eaten.append(ret)
|
||||
|
||||
return to_process and nb_evaluators_in_error == 1
|
||||
|
||||
def eval(self, context, return_values):
|
||||
context.log(self.verbose_log, f"1 return value in error, {len(self.eaten)} item(s) eaten", who=self)
|
||||
context.log(self.verbose_log, f"{self.return_value_in_error}", who=self)
|
||||
|
||||
sheerka = context.sheerka
|
||||
return sheerka.ret(self.name, False, self.return_value_in_error.value, parents=self.eaten)
|
||||
@@ -14,28 +14,31 @@ class OneSuccessEvaluator(AllReturnValuesEvaluator):
|
||||
NAME = "OneSuccess"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 60) # before MultipleSameSuccess
|
||||
self.successful_return_value = None
|
||||
|
||||
def matches(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
after_evaluation = False
|
||||
nb_successful_evaluators = 0
|
||||
only_parsers = True
|
||||
for ret in return_values:
|
||||
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
||||
if ret.status:
|
||||
after_evaluation = True
|
||||
elif ret.who.startswith(self.PREFIX):
|
||||
if ret.status:
|
||||
nb_successful_evaluators += 1
|
||||
self.successful_return_value = ret
|
||||
else:
|
||||
if not ret.who.startswith(BaseParser.PREFIX):
|
||||
only_parsers = False
|
||||
to_process = False
|
||||
|
||||
return after_evaluation and nb_successful_evaluators == 1 and only_parsers
|
||||
for ret in return_values:
|
||||
if ret.status and ret.who.startswith(BaseParser.PREFIX):
|
||||
return False
|
||||
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
|
||||
to_process = True
|
||||
self.eaten.append(ret)
|
||||
elif ret.status and ret.who.startswith(self.PREFIX):
|
||||
nb_successful_evaluators += 1
|
||||
self.successful_return_value = ret
|
||||
self.eaten.append(ret)
|
||||
elif not ret.status:
|
||||
self.eaten.append(ret)
|
||||
|
||||
return to_process and nb_successful_evaluators == 1
|
||||
|
||||
def eval(self, context, return_values):
|
||||
context.log(self.verbose_log, f"1 successful return value, {len(self.eaten)} item(s) eaten", who=self)
|
||||
context.log(self.verbose_log, f"{self.successful_return_value}", who=self)
|
||||
|
||||
sheerka = context.sheerka
|
||||
return sheerka.ret(self.name, True, self.successful_return_value.value, parents=return_values)
|
||||
return sheerka.ret(self.name, True, self.successful_return_value.value, parents=self.eaten)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
|
||||
|
||||
class PrepareEvalEvaluator(OneReturnValueEvaluator):
|
||||
"""
|
||||
To parse evaluation requests
|
||||
"""
|
||||
|
||||
NAME = "PrepareEval"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.BEFORE_PARSING], 90)
|
||||
self.text = None
|
||||
|
||||
def matches(self, context, return_value):
|
||||
if not (return_value.status and
|
||||
context.sheerka.isinstance(return_value.body, BuiltinConcepts.USER_INPUT) and
|
||||
isinstance(return_value.body.body, str)):
|
||||
return False
|
||||
|
||||
text = return_value.body.body.strip()
|
||||
if not text.startswith("eval "):
|
||||
return False
|
||||
|
||||
self.text = text
|
||||
return True
|
||||
|
||||
def eval(self, context, return_value):
|
||||
sheerka = context.sheerka
|
||||
|
||||
new_text_to_parse = sheerka.ret(
|
||||
self.name,
|
||||
True, sheerka.new(BuiltinConcepts.USER_INPUT, body=self.text[5:], user_name=context.event.user))
|
||||
|
||||
evaluation_requested = sheerka.ret(
|
||||
self.name,
|
||||
True, sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
|
||||
|
||||
return [new_text_to_parse, evaluation_requested]
|
||||
@@ -2,6 +2,7 @@ import copy
|
||||
|
||||
from core.ast.visitors import UnreferencedNamesVisitor
|
||||
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept
|
||||
from core.concept import ConceptParts
|
||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
from parsers.PythonParser import PythonNode
|
||||
import ast
|
||||
@@ -29,6 +30,14 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
||||
try:
|
||||
context.log(self.verbose_log, f"Evaluating python node {node}.", self.name)
|
||||
|
||||
# Do not evaluate if the ast refers to a concept (leave it to ConceptEvaluator)
|
||||
if isinstance(node.ast_, ast.Expression) and isinstance(node.ast_.body, ast.Name):
|
||||
c = context.sheerka.get(node.ast_.body.id)
|
||||
if not context.sheerka.isinstance(c, BuiltinConcepts.UNKNOWN_CONCEPT):
|
||||
context.log(self.verbose_log, "It's a simple concept. Not for me.", self.name)
|
||||
not_for_me = context.sheerka.new(BuiltinConcepts.NOT_FOR_ME, body=node)
|
||||
return sheerka.ret(self.name, False, not_for_me, parents=[return_value])
|
||||
|
||||
my_locals = self.get_locals(context, node.ast_)
|
||||
context.log(self.verbose_log, f"locals={my_locals}", self.name)
|
||||
|
||||
@@ -78,7 +87,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
||||
evaluated = context.sheerka.evaluate_concept(sub_context, concept, self.verbose_log)
|
||||
|
||||
if evaluated.key == concept.key:
|
||||
my_locals[name] = evaluated.body or evaluated
|
||||
my_locals[name] = evaluated.body or evaluated # if ConceptParts.BODY not in evaluated.cached_asts else evaluated
|
||||
|
||||
return my_locals
|
||||
|
||||
|
||||
@@ -17,33 +17,25 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
|
||||
NAME = "TooManySuccess"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
|
||||
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 60)
|
||||
self.success = []
|
||||
|
||||
def matches(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
after_evaluation = False
|
||||
nb_successful_evaluators = 0
|
||||
only_parsers_in_error = True
|
||||
unlisted = False
|
||||
to_process = False
|
||||
|
||||
for ret in return_values:
|
||||
if ret.status and ret.who.startswith(BaseParser.PREFIX):
|
||||
return False
|
||||
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
|
||||
to_process = True
|
||||
self.eaten.append(ret)
|
||||
elif ret.status and ret.who.startswith(self.PREFIX):
|
||||
self.success.append(ret)
|
||||
self.eaten.append(ret)
|
||||
elif not ret.status:
|
||||
self.eaten.append(ret)
|
||||
|
||||
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
||||
if ret.status:
|
||||
after_evaluation = True
|
||||
|
||||
elif ret.who.startswith(BaseEvaluator.PREFIX):
|
||||
if ret.status:
|
||||
nb_successful_evaluators += 1
|
||||
self.success.append(ret)
|
||||
elif ret.who.startswith(BaseParser.PREFIX):
|
||||
if ret.status:
|
||||
only_parsers_in_error = False
|
||||
else:
|
||||
unlisted = True
|
||||
|
||||
return after_evaluation and nb_successful_evaluators > 1 and only_parsers_in_error and not unlisted
|
||||
return to_process and len(self.success) > 1
|
||||
|
||||
def eval(self, context, return_values):
|
||||
sheerka = context.sheerka
|
||||
@@ -56,8 +48,7 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
|
||||
context.log(self.verbose_log,
|
||||
f"Values are different. Raising {BuiltinConcepts.TOO_MANY_SUCCESS}.", self.name)
|
||||
too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success)
|
||||
return sheerka.ret(self.name, False, too_many_success, parents=return_values)
|
||||
return sheerka.ret(self.name, False, too_many_success, parents=self.eaten)
|
||||
|
||||
context.log(self.verbose_log,
|
||||
f"Values are the same. Nothing to do.", self.name)
|
||||
context.log(self.verbose_log, f"Values are the same. Nothing to do.", self.name)
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user