109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts
|
|
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
|
|
|
from parsers.ConceptLexerParser import ConceptNode, NonTerminalNode, ConceptMatch, UnrecognizedTokensNode
|
|
|
|
|
|
class ConceptNodeEvaluator(OneReturnValueEvaluator):
|
|
"""
|
|
After a BNF is recognized, generates the concept or the list concepts
|
|
"""
|
|
|
|
NAME = "ConceptNode"
|
|
|
|
def __init__(self):
|
|
super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 60) # more than the ConceptNodeEvaluator
|
|
|
|
def matches(self, context, return_value):
|
|
if not return_value.status:
|
|
return False
|
|
|
|
if not isinstance(return_value.value, ParserResultConcept):
|
|
return False
|
|
|
|
return (
|
|
isinstance(return_value.value.value, ConceptNode) or
|
|
isinstance(return_value.value.value, UnrecognizedTokensNode) or
|
|
(
|
|
hasattr(return_value.value.value, "__iter__") and
|
|
len(return_value.value.value) > 0 and
|
|
(
|
|
isinstance(return_value.value.value[0], ConceptNode) or
|
|
isinstance(return_value.value.value[0], UnrecognizedTokensNode)
|
|
)
|
|
)
|
|
)
|
|
|
|
def eval(self, context, return_value):
|
|
"""
|
|
From a concept node, creates a new concept
|
|
and makes sure that the properties are correctly set
|
|
"""
|
|
sheerka = context.sheerka
|
|
nodes = return_value.value.value
|
|
if not hasattr(nodes, "__iter__"):
|
|
nodes = [nodes]
|
|
|
|
concepts = []
|
|
error_found = False
|
|
for node in nodes:
|
|
if isinstance(node, ConceptNode):
|
|
concept = sheerka.new(node.concept.key)
|
|
concept = self.update_concept(sheerka, concept, node.underlying)
|
|
concepts.append(concept)
|
|
else:
|
|
error_found = True
|
|
|
|
if len(concepts) == 1:
|
|
return sheerka.ret(
|
|
self.name,
|
|
not error_found,
|
|
concepts[0],
|
|
parents=[return_value])
|
|
|
|
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.NOT_FOR_ME), parents=[return_value])
|
|
|
|
def update_concept(self, sheerka, concept, underlying, init_empty_body=True):
|
|
"""
|
|
Updates the properties of the concept
|
|
Goes in recursion if the property is a concept
|
|
"""
|
|
|
|
def _add_prop(c, prop_name, value):
|
|
"""
|
|
Adds a new entry,
|
|
makes a list if the property already exists
|
|
"""
|
|
if prop_name not in c.props or c.props[prop_name].value is None:
|
|
c.set_prop(prop_name, value)
|
|
else:
|
|
previous_value = c.props[prop_name].value
|
|
if isinstance(previous_value, list):
|
|
previous_value.append(value)
|
|
else:
|
|
new_value = [previous_value, value]
|
|
c.set_prop(prop_name, new_value)
|
|
|
|
parsing_expression = underlying.parsing_expression
|
|
|
|
if parsing_expression.rule_name:
|
|
_add_prop(concept, parsing_expression.rule_name, underlying.source)
|
|
|
|
# the update of the body must come BEFORE the recursion
|
|
if init_empty_body and concept.body is None:
|
|
concept.metadata.body = underlying.source
|
|
|
|
if isinstance(underlying, NonTerminalNode):
|
|
for child in underlying.children:
|
|
if isinstance(child.parsing_expression, ConceptMatch):
|
|
new_concept = sheerka.new(child.parsing_expression.concept.key)
|
|
_add_prop(concept, child.parsing_expression.rule_name, new_concept)
|
|
if sheerka.isinstance(new_concept, BuiltinConcepts.UNKNOWN_CONCEPT):
|
|
continue
|
|
else:
|
|
self.update_concept(sheerka, new_concept, child.children[0], init_empty_body)
|
|
else:
|
|
self.update_concept(sheerka, concept, child, init_empty_body)
|
|
|
|
return concept
|