First implementation of questions management

This commit is contained in:
2020-08-14 08:16:33 +02:00
parent e84b394da2
commit 351c16f946
47 changed files with 1582 additions and 400 deletions
+13 -28
View File
@@ -1,14 +1,11 @@
from core.ast.nodes import python_to_concept
import core.utils
from core.builtin_concepts import ParserResultConcept, ReturnValueConcept, BuiltinConcepts
from core.builtin_helpers import get_names
from core.concept import Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF
from core.tokenizer import TokenKind, Tokenizer
from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.BaseParser import NotInitializedNode
from parsers.BnfNodeParser import ParsingExpression, ParsingExpressionVisitor
from parsers.DefaultParser import DefConceptNode, NameNode
from parsers.PythonParser import PythonNode
import core.utils
class ConceptOrRuleNameVisitor(ParsingExpressionVisitor):
@@ -132,30 +129,6 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
variables = filter(lambda x: x in concept_name, names)
return set(variables)
#
# Case of python code
#
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, PythonNode):
if len(concept_name) > 1:
# tokens from ParserResult or source from python node
variables = set()
tokens = ret_value.value.tokens or list(Tokenizer(ret_value.value.value.source))
tokens = [t.str_value for t in tokens]
for identifier in [i for i in concept_name if str(i).isalnum()]:
if identifier in tokens:
variables.add(identifier)
# python_node = ret_value.value.value
# as_concept_node = python_to_concept(python_node.ast_)
# names = get_names(sheerka, as_concept_node)
# variables = filter(lambda x: x in concept_name, names)
return variables
#
# case of concept
#
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, Concept):
return set(ret_value.value.value.values.keys())
#
# case of BNF
#
@@ -164,4 +137,16 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
visitor.visit(ret_value.value.value)
return set(visitor.names)
#
# other (python code and concept)
#
if isinstance(ret_value.value, ParserResultConcept) and len(concept_name) > 1:
variables = set()
tokens = ret_value.value.tokens or list(Tokenizer(ret_value.value.source, yield_eof=False))
tokens = [t.str_value for t in tokens]
for identifier in [i for i in concept_name if str(i).isalnum()]:
if identifier in tokens:
variables.add(identifier)
return variables
return []
+2 -2
View File
@@ -21,11 +21,11 @@ class ConceptEvaluator(OneReturnValueEvaluator):
self.return_body = return_body
# def init_evaluator(self, context, return_values):
# if BuiltinConcepts.EVAL_BODY_REQUESTED in context.local_hints:
# if BuiltinConcepts.EVAL_BODY_REQUESTED in context.protected_hints:
# self.evaluate_body = True
#
# for r in return_values:
# if r.status and context.sheerka.isinstance(r.body, BuiltinConcepts.RETURN_VALUE_REQUESTED):
# if r.status and context.sheerka.isinstance(r.body, BuiltinConcepts.RETURN_BODY_REQUESTED):
# self.evaluate_body = True
# break
#
@@ -2,12 +2,12 @@ from core.builtin_concepts import BuiltinConcepts
from evaluators.BaseEvaluator import OneReturnValueEvaluator
class PrepareEvalEvaluator(OneReturnValueEvaluator):
class PrepareEvalBodyEvaluator(OneReturnValueEvaluator):
"""
To parse evaluation requests
To recognize when the user input is an (body) evaluation
"""
NAME = "PrepareEval"
NAME = "PrepareEvalBody"
def __init__(self, **kwargs):
super().__init__(self.NAME, [BuiltinConcepts.BEFORE_PARSING], 90)
@@ -33,8 +33,10 @@ class PrepareEvalEvaluator(OneReturnValueEvaluator):
self.name,
True, sheerka.new(BuiltinConcepts.USER_INPUT, body=self.text[5:], user_name=context.event.user_id))
context.global_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.global_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
root = context.get_parents(lambda ec: ec.action == BuiltinConcepts.PROCESS_INPUT)
root = root[0] if root else context
root.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
root.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
root.protected_hints.add(BuiltinConcepts.RETURN_BODY_REQUESTED)
return new_text_to_parse
@@ -0,0 +1,45 @@
from core.builtin_concepts import BuiltinConcepts
from evaluators.BaseEvaluator import OneReturnValueEvaluator
class PrepareEvalQuestionEvaluator(OneReturnValueEvaluator):
"""
To recognize when the user input is a question
"""
NAME = "PrepareEvalQuestion"
def __init__(self, **kwargs):
super().__init__(self.NAME, [BuiltinConcepts.BEFORE_PARSING], 90)
self.question = 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("question(") and text.endswith(")")):
return False
self.question = text[9:-1].strip()
if self.question == "":
return False
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.question, user_name=context.event.user_id))
root = context.get_parents(lambda ec: ec.action == BuiltinConcepts.PROCESS_INPUT)
root = root[0] if root else context
root.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
root.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
root.protected_hints.add(BuiltinConcepts.RETURN_BODY_REQUESTED)
return new_text_to_parse
+10 -15
View File
@@ -12,6 +12,9 @@ from core.sheerka.services.SheerkaFilter import Pipe
from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.PythonParser import PythonNode
TO_DISABLED = ["breakpoint", "callable", "compile", "delattr", "eval", "exec", "exit", "input", "locals", "open",
"print", "quit", "setattr"]
def inject_context(context):
"""
@@ -95,7 +98,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
concepts_entries = None
evaluated = BuiltinConcepts.NOT_INITIALIZED
errors = []
expect_success = BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED in context.local_hints
expect_success = context.in_context(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
for globals_ in all_possible_globals:
try:
# eval
@@ -142,12 +145,13 @@ class PythonEvaluator(OneReturnValueEvaluator):
my_globals = {
"Concept": core.concept.Concept,
"BuiltinConcepts": core.builtin_concepts.BuiltinConcepts,
"in_context": context.in_context
"in_context": context.in_context,
}
if expression_only:
# disable builtin
my_globals["__builtins__"] = None
# disable some builtin
for statement in TO_DISABLED:
my_globals[statement] = None
# has to be the first, to allow override
method_from_sheerka = self.update_globals_with_sheerka_methods(my_globals, context, expression_only)
@@ -164,17 +168,6 @@ class PythonEvaluator(OneReturnValueEvaluator):
@staticmethod
def update_globals_with_sheerka_methods(my_locals, context, expression_only):
# methods_from_sheerka = {}
#
# # Make sure that methods that need the concept are correctly wrapped
# for method_name, method in context.sheerka.sheerka_methods.items():
# if expression_only and method.has_side_effect:
# continue
#
# if method_name in context.sheerka.methods_with_context:
# methods_from_sheerka[method_name] = inject_context(context)(method.method)
# else:
# methods_from_sheerka[method_name] = method.method
methods_from_sheerka = {}
# Add all the methods as a direct access
@@ -238,6 +231,8 @@ class PythonEvaluator(OneReturnValueEvaluator):
elif name in already_known:
context.log(f"Already known. Skipping.", self.name)
continue
elif (concept := context.get_from_short_term_memory(name)) is not None:
context.log(f"Using from STM known.", self.name)
else:
context.log(f"Instantiating new concept with {name}.", self.name)
concept = self.resolve_concept(context, name)
+5 -4
View File
@@ -38,12 +38,13 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
parser_results = {id(r.body.body): r.body for r in ret_vals}
resolved = resolve_ambiguity(context, [r.body.body for r in ret_vals])
if len(resolved) == 0:
ret.append(context.sheerka.ret(self.name, True, [], parents=ret_vals))
ret.append(context.sheerka.ret(self.name, True, BuiltinConcepts.NO_RESULT, parents=ret_vals))
else:
for c in resolved:
ret.append(context.sheerka.ret(self.name, True, parser_results[id(c)], parents=ret_vals))
if len(resolved) < len(ret_vals):
for c in resolved:
ret.append(context.sheerka.ret(self.name, True, parser_results[id(c)], parents=ret_vals))
return ret
return None if len(ret) == 0 else ret
@staticmethod
def get_source(context, return_value):
@@ -3,12 +3,12 @@ from core.concept import Concept
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
class EvalEvaluator(AllReturnValuesEvaluator):
class ReturnBodyEvaluator(AllReturnValuesEvaluator):
"""
Returns the body of all successful concepts
"""
NAME = "Eval"
NAME = "ReturnBody"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 80)
@@ -16,7 +16,7 @@ class EvalEvaluator(AllReturnValuesEvaluator):
def matches(self, context, return_values):
evaluation_parents = context.get_parents(lambda c: c.action == BuiltinConcepts.PROCESSING)
is_root = len(evaluation_parents) <= 1
return context.in_context(BuiltinConcepts.RETURN_VALUE_REQUESTED) and is_root
return context.in_context(BuiltinConcepts.RETURN_BODY_REQUESTED) and is_root
def eval(self, context, return_values):
sheerka = context.sheerka
@@ -26,6 +26,7 @@ class UpdateFunctionsParametersEvaluator(OneReturnValueEvaluator):
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 79)
self.enabled = False
def matches(self, context, return_value):
"""