First implementation of questions management
This commit is contained in:
+101
-99
@@ -6,9 +6,15 @@ from core.ast.nodes import CallNodeConcept
|
||||
from core.ast.visitors import UnreferencedNamesVisitor
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept, NotInit, ConceptParts
|
||||
from core.tokenizer import Keywords
|
||||
# from evaluators.BaseEvaluator import BaseEvaluator
|
||||
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode
|
||||
from parsers.BaseParser import BaseParser, ErrorNode
|
||||
|
||||
PARSE_STEPS = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
|
||||
EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION,
|
||||
BuiltinConcepts.AFTER_EVALUATION]
|
||||
|
||||
|
||||
def is_same_success(context, return_values):
|
||||
"""
|
||||
@@ -105,7 +111,7 @@ def expect_one(context, return_values):
|
||||
sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=successful_results),
|
||||
parents=return_values)
|
||||
|
||||
# only errors, i cannot help you
|
||||
# number_of_successful == 0, only errors, i cannot help you
|
||||
if context.logger and context.logger.isEnabledFor(logging.DEBUG):
|
||||
context.log(f"Too many errors found by expect_one()", context.who)
|
||||
for s in successful_results:
|
||||
@@ -170,88 +176,11 @@ def only_successful(context, return_values):
|
||||
sheerka.new(BuiltinConcepts.ONLY_SUCCESSFUL, body=successful_results),
|
||||
parents=return_values)
|
||||
|
||||
#
|
||||
# def remove_ambiguity(context, return_values):
|
||||
# """
|
||||
# When multiple concepts are matching, try to find the one(s) which is/are the more accurate
|
||||
# :param context:
|
||||
# :param return_values:
|
||||
# :return:
|
||||
# """
|
||||
# # example :
|
||||
# # Concept("x is a y", PRE=QUESTION)
|
||||
# # Concept("x is a y")
|
||||
# # Concept("x is a command")
|
||||
# # with the source 'foo is a command'
|
||||
# # The first one do not respect the pre condition (assuming that QUESTION is not in context)
|
||||
# # The second one is Ok, but the third is more specific (as it's a concept that explicitly asks for 'command')
|
||||
# # The third one will remain
|
||||
# if not return_values:
|
||||
# return return_values
|
||||
#
|
||||
# sheerka = context.sheerka
|
||||
# by_number_of_vars = {} # sorted by number of variables
|
||||
# to_keep = [] # return values values that are not eligible (ex non parser result)
|
||||
# passed_validation = []
|
||||
#
|
||||
# # sort by number of variables
|
||||
# # The less variables there are, the more accurate is the concept
|
||||
# for r in return_values:
|
||||
# if (r.status and
|
||||
# sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT) and
|
||||
# isinstance(r.body.body, Concept)):
|
||||
# by_number_of_vars.setdefault(len(r.body.body.metadata.variables), []).append(r)
|
||||
# else:
|
||||
# to_keep.append(r)
|
||||
#
|
||||
# # Check the concepts, starting with the ones that have the less variables
|
||||
# # Once a concept with a given number of variables is found, we do not process the concepts with an higher
|
||||
# # number of variables
|
||||
# for nb_vars in sorted(by_number_of_vars.keys()):
|
||||
# for r in by_number_of_vars[nb_vars]:
|
||||
# concept = r.body.body
|
||||
# if concept.metadata.pre is None or concept.metadata.pre.strip() == "":
|
||||
# passed_validation.append(r)
|
||||
# else:
|
||||
# evaluated = context.sheerka.evaluate_concept(context, concept, metadata=["pre"])
|
||||
# if evaluated.key == concept.key and evaluated.get_value(ConceptParts.PRE):
|
||||
# passed_validation.append(r)
|
||||
# if len(passed_validation) > 0:
|
||||
# break
|
||||
#
|
||||
# # Nothing was filtered, return the original return values
|
||||
# if len(passed_validation) + len(to_keep) == len(return_values):
|
||||
# return return_values # nothing to filter
|
||||
#
|
||||
# # All return_values fail, return empty list
|
||||
# if len(passed_validation) == 0:
|
||||
# return sheerka.ret(
|
||||
# context.who,
|
||||
# True,
|
||||
# sheerka.new(BuiltinConcepts.FILTERED,
|
||||
# body=to_keep,
|
||||
# iterable=return_values,
|
||||
# predicate="remove_ambiguity(context, iterable)"),
|
||||
# parents=return_values)
|
||||
#
|
||||
# # Final check, we consider that the concepts that match a PRE condition are better than concepts with no condition
|
||||
# by_condition_complexity = {}
|
||||
# for r in passed_validation:
|
||||
# by_condition_complexity.setdefault(get_condition_complexity(r.body.body, "pre"), []).append(r)
|
||||
#
|
||||
# return sheerka.ret(
|
||||
# context.who,
|
||||
# True,
|
||||
# sheerka.new(BuiltinConcepts.FILTERED,
|
||||
# body=to_keep + by_condition_complexity[max(by_condition_complexity.keys())],
|
||||
# iterable=return_values,
|
||||
# predicate="remove_ambiguity(context, iterable)"),
|
||||
# parents=return_values)
|
||||
|
||||
|
||||
def resolve_ambiguity(context, concepts):
|
||||
"""
|
||||
From the list of concept, elect the one(s) that best suit(s) the context
|
||||
From the list of concepts, elect the one(s) that best suit(s) the context
|
||||
Use the PRE metadata to choose the correct concepts
|
||||
:param context:
|
||||
:param concepts:
|
||||
:return:
|
||||
@@ -265,10 +194,13 @@ def resolve_ambiguity(context, concepts):
|
||||
|
||||
remaining_concepts = []
|
||||
for complexity in sorted(by_complexity.keys(), reverse=True):
|
||||
for c in by_complexity[complexity]:
|
||||
evaluated = context.sheerka.evaluate_concept(context, c, metadata=["pre"])
|
||||
if evaluated.key == c.key:
|
||||
remaining_concepts.append(c)
|
||||
if complexity == 0:
|
||||
remaining_concepts.extend(by_complexity[complexity])
|
||||
else:
|
||||
for c in by_complexity[complexity]:
|
||||
evaluated = context.sheerka.evaluate_concept(context, c, metadata=["pre"])
|
||||
if evaluated.key == c.key:
|
||||
remaining_concepts.append(c)
|
||||
|
||||
if len(remaining_concepts) > 0:
|
||||
break # no need to check concept with lower complexity
|
||||
@@ -349,30 +281,48 @@ def only_parsers_results(context, return_values):
|
||||
parents=return_values)
|
||||
|
||||
|
||||
def parse_unrecognized(context, source, parsers):
|
||||
def parse_unrecognized(context, source, parsers, who=None, prop=None, filter_func=None):
|
||||
"""
|
||||
Try to recognize concepts or code from source using the given parsers
|
||||
:param context:
|
||||
:param source:
|
||||
:param parsers:
|
||||
:param who: who is asking the parsing ?
|
||||
:param prop: Extra info, when parsing a property
|
||||
:param filter_func: filter function to call is provided
|
||||
:return:
|
||||
"""
|
||||
steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
|
||||
sheerka = context.sheerka
|
||||
|
||||
with context.push(BuiltinConcepts.PARSING, source, desc=f"Parsing unrecognized '{source}'") as sub_context:
|
||||
# disable all parsers but the following ones
|
||||
sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
|
||||
for parser in parsers:
|
||||
sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
|
||||
if prop:
|
||||
action_context = {"prop": prop, "source": source}
|
||||
desc = f"Parsing attribute '{prop}'"
|
||||
else:
|
||||
action_context = source
|
||||
desc = f"Parsing '{source}'"
|
||||
|
||||
with context.push(BuiltinConcepts.PARSING, action_context, who=who, desc=desc) as sub_context:
|
||||
# disable all parsers but the requested ones
|
||||
if parsers != "all":
|
||||
sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
|
||||
for parser in parsers:
|
||||
sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
|
||||
|
||||
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
sub_context.add_inputs(source=source)
|
||||
to_parse = sheerka.ret(
|
||||
context.who,
|
||||
True,
|
||||
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
|
||||
res = sheerka.execute(sub_context, to_parse, steps)
|
||||
to_parse = sheerka.ret(context.who,
|
||||
True,
|
||||
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
|
||||
res = sheerka.execute(sub_context, to_parse, PARSE_STEPS)
|
||||
|
||||
if filter_func:
|
||||
res = filter_func(sub_context, res)
|
||||
|
||||
sub_context.add_values(return_values=res)
|
||||
if not hasattr(res, "__iter__"):
|
||||
return res
|
||||
|
||||
# discard Python response if accepted by AtomNode
|
||||
is_concept = False
|
||||
@@ -383,13 +333,65 @@ def parse_unrecognized(context, source, parsers):
|
||||
if not is_concept:
|
||||
return res
|
||||
|
||||
filtered = []
|
||||
no_python = []
|
||||
for r in res:
|
||||
if r.who == "parsers.Python":
|
||||
continue
|
||||
filtered.append(r)
|
||||
no_python.append(r)
|
||||
|
||||
return filtered
|
||||
return no_python
|
||||
|
||||
|
||||
def evaluate(context,
|
||||
source,
|
||||
evaluators="all",
|
||||
desc=None,
|
||||
eval_body=True,
|
||||
eval_where=True,
|
||||
expect_success=False,
|
||||
stm=None):
|
||||
"""
|
||||
|
||||
:param context:
|
||||
:param source:
|
||||
:param evaluators:
|
||||
:param desc:
|
||||
:param eval_body:
|
||||
:param eval_where:
|
||||
:param expect_success:
|
||||
:param stm: short term memories entries
|
||||
:return:
|
||||
"""
|
||||
|
||||
sheerka = context.sheerka
|
||||
desc = desc or f"Eval '{source}'"
|
||||
with context.push(BuiltinConcepts.EVALUATE_SOURCE, source, desc=desc) as sub_context:
|
||||
if eval_body:
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
|
||||
if eval_where:
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
|
||||
|
||||
if expect_success:
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
if stm:
|
||||
for k, v in stm.items():
|
||||
sub_context.add_to_short_term_memory(k, v)
|
||||
|
||||
# disable all evaluators but the requested ones
|
||||
if evaluators != "all":
|
||||
from evaluators.BaseEvaluator import BaseEvaluator
|
||||
sub_context.add_preprocess(BaseEvaluator.PREFIX + "*", enabled=False)
|
||||
for evaluator in evaluators:
|
||||
sub_context.add_preprocess(BaseEvaluator.PREFIX + evaluator, enabled=True)
|
||||
|
||||
user_input = sheerka.ret(context.who, True, sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
|
||||
ret = sheerka.execute(sub_context, [user_input], EVAL_STEPS)
|
||||
sub_context.add_values(return_values=ret)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def get_lexer_nodes(return_values, start, tokens):
|
||||
|
||||
Reference in New Issue
Block a user