You must now use 'eval' to get the body of a concept

This commit is contained in:
2019-12-24 16:58:09 +01:00
parent 5c90b07e1a
commit 44e4b75cf8
37 changed files with 1003 additions and 383 deletions
+8
View File
@@ -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
+4 -3
View File
@@ -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])
-45
View File
@@ -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)
+38
View File
@@ -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
+46 -15
View File
@@ -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
+42
View File
@@ -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)
+20 -17
View File
@@ -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)
+40
View File
@@ -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]
+10 -1
View File
@@ -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
+15 -24
View File
@@ -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