Implemented FunctionParser
This commit is contained in:
+121
-5
@@ -6,14 +6,16 @@ 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.sheerka.services.SheerkaExecute import SheerkaExecute
|
||||
from core.tokenizer import Keywords
|
||||
# from evaluators.BaseEvaluator import BaseEvaluator
|
||||
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode
|
||||
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode
|
||||
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]
|
||||
PARSERS = ["EmptyString", "ShortTermMemory", "AtomNode", "BnfNode", "SyaNode", "Python"]
|
||||
|
||||
|
||||
def is_same_success(context, return_values):
|
||||
@@ -342,6 +344,37 @@ def parse_unrecognized(context, source, parsers, who=None, prop=None, filter_fun
|
||||
return no_python
|
||||
|
||||
|
||||
def parse_function(context, source, tokens=None, start=0):
|
||||
"""
|
||||
Helper function to parse what is supposed to be a function
|
||||
:param context:
|
||||
:param source:
|
||||
:param tokens:
|
||||
:param start: start index for the source code node
|
||||
:return:
|
||||
"""
|
||||
sheerka = context.sheerka
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
parser = FunctionParser()
|
||||
desc = f"Parsing function '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE, source, desc=desc) as sub_context:
|
||||
sheerka_execution = sheerka.services[SheerkaExecute.NAME]
|
||||
res = parser.parse(sub_context, sheerka_execution.get_parser_input(source, tokens))
|
||||
|
||||
if not isinstance(res, list):
|
||||
res = [res]
|
||||
|
||||
for r in [r for r in res if sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT)]:
|
||||
r.body.body.start += start
|
||||
r.body.body.end += start
|
||||
if isinstance(r.body.body, SourceCodeWithConceptNode):
|
||||
for n in [r.body.body.first, r.body.body.last] + r.body.body.nodes:
|
||||
n.start += start
|
||||
n.end += start
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def evaluate(context,
|
||||
source,
|
||||
evaluators="all",
|
||||
@@ -415,7 +448,12 @@ def get_lexer_nodes(return_values, start, tokens):
|
||||
|
||||
end = start + len(tokens) - 1
|
||||
lexer_nodes.append(
|
||||
[SourceCodeNode(ret_val.body.body, start, end, tokens, ret_val.body.source, ret_val)])
|
||||
[SourceCodeNode(start,
|
||||
end,
|
||||
tokens,
|
||||
ret_val.body.source,
|
||||
python_node=ret_val.body.body,
|
||||
return_value=ret_val)])
|
||||
|
||||
elif ret_val.who == "parsers.ExactConcept":
|
||||
concepts = ret_val.body.body if hasattr(ret_val.body.body, "__iter__") else [ret_val.body.body]
|
||||
@@ -479,6 +517,81 @@ def get_lexer_nodes_from_unrecognized(context, unrecognized_tokens_node, parsers
|
||||
return get_lexer_nodes(res.body.body, unrecognized_tokens_node.start, unrecognized_tokens_node.tokens)
|
||||
|
||||
|
||||
def update_compiled(context, concept, errors, parsers=None):
|
||||
"""
|
||||
recursively iterate thru concept.compiled to replace LexerNode into concepts or list of ReturnValueConcept
|
||||
When parsing using a LexerNodeParser (SyaNodeParser, BnfNodeParser...)
|
||||
the result will be a LexerNode.
|
||||
In the specific case of a ConceptNode, the compiled variables will also be LexerNode (UnrecognizedTokensNode...)
|
||||
This function iterate thru the compile to transform these nodes into concept of compiled AST
|
||||
:param context:
|
||||
:param concept:
|
||||
:param errors: a list the must be initialized by the caller
|
||||
:param parsers: to customize the parsers to use
|
||||
:return:
|
||||
"""
|
||||
|
||||
sheerka = context.sheerka
|
||||
parsers = parsers or PARSERS
|
||||
|
||||
def _validate_concept(c):
|
||||
"""
|
||||
Recursively browse the compiled properties in order to find unrecognized
|
||||
:param c:
|
||||
:return:
|
||||
"""
|
||||
for k, v in c.compiled.items():
|
||||
if isinstance(v, Concept):
|
||||
_validate_concept(v)
|
||||
|
||||
elif isinstance(v, SourceCodeWithConceptNode):
|
||||
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
|
||||
parser_helper = PythonWithConceptsParser()
|
||||
res = parser_helper.parse_nodes(context, v.get_all_nodes())
|
||||
if res.status:
|
||||
c.compiled[k] = [res]
|
||||
else:
|
||||
errors.append(sheerka.new(BuiltinConcepts.ERROR, body=f"Cannot parse '{v.source}'"))
|
||||
|
||||
elif isinstance(v, UnrecognizedTokensNode):
|
||||
res = parse_unrecognized(context, v.source, parsers)
|
||||
res = only_successful(context, res) # only key successful parsers
|
||||
if res.status:
|
||||
c.compiled[k] = res.body.body
|
||||
else:
|
||||
errors.append(sheerka.new(BuiltinConcepts.ERROR, body=f"Cannot parse '{v.source}'"))
|
||||
|
||||
def _get_source(compiled, var_name):
|
||||
if var_name not in compiled:
|
||||
return None
|
||||
if not isinstance(compiled[var_name], list):
|
||||
return None
|
||||
if not len(compiled[var_name]) == 1:
|
||||
return None
|
||||
if not sheerka.isinstance(compiled[var_name][0], BuiltinConcepts.RETURN_VALUE):
|
||||
return None
|
||||
if not sheerka.isinstance(compiled[var_name][0].body, BuiltinConcepts.PARSER_RESULT):
|
||||
return None
|
||||
if compiled[var_name][0].body.name == "parsers.ShortTermMemory":
|
||||
return None
|
||||
|
||||
return compiled[var_name][0].body.source
|
||||
|
||||
_validate_concept(concept)
|
||||
|
||||
# Special case where the values of the variables are the names of the variable
|
||||
# example : Concept("a plus b").def_var("a").def_var("b")
|
||||
# and the user has entered 'a plus b'
|
||||
# Chances are that we are talking about the concept itself, and not an instantiation (like '10 plus 2')
|
||||
# This means that 'a' and 'b' don't have any real value
|
||||
if len(concept.metadata.variables) > 0:
|
||||
for name, value in concept.metadata.variables:
|
||||
if _get_source(concept.compiled, name) != name:
|
||||
break
|
||||
else:
|
||||
concept.metadata.is_evaluated = True
|
||||
|
||||
|
||||
def get_names(sheerka, concept_node):
|
||||
"""
|
||||
Finds all the names referenced by the concept_node
|
||||
@@ -603,10 +716,11 @@ def remove_from_ret_val(sheerka, return_values, concept_key):
|
||||
return return_values
|
||||
|
||||
|
||||
def set_is_evaluated(concepts):
|
||||
def set_is_evaluated(concepts, check_nb_variables=False):
|
||||
"""
|
||||
set is_evaluated to True
|
||||
:param concepts:
|
||||
:param check_nb_variables: only set is_evaluated if the concept has variables
|
||||
:return:
|
||||
"""
|
||||
if concepts is None:
|
||||
@@ -614,6 +728,8 @@ def set_is_evaluated(concepts):
|
||||
|
||||
if hasattr(concepts, "__iter__"):
|
||||
for c in concepts:
|
||||
c.metadata.is_evaluated = True
|
||||
if not check_nb_variables or check_nb_variables and len(c.metadata.variables) > 0:
|
||||
c.metadata.is_evaluated = True
|
||||
else:
|
||||
concepts.metadata.is_evaluated = True
|
||||
if not check_nb_variables or check_nb_variables and len(concepts.metadata.variables) > 0:
|
||||
concepts.metadata.is_evaluated = True
|
||||
|
||||
Reference in New Issue
Block a user