from core.builtin_concepts import ParserResultConcept, BuiltinConcepts from evaluators.BaseEvaluator import OneReturnValueEvaluator from parsers.ConceptLexerParser import ConceptNode, NonTerminalNode, ConceptMatch class ConceptNodeEvaluator(OneReturnValueEvaluator): """ After a BNF is recognized, generates the concept or the list concepts """ NAME = "ConceptNode" def __init__(self): super().__init__(self.NAME, 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 ( hasattr(return_value.value.value, "__iter__") and len(return_value.value.value) > 0 and isinstance(return_value.value.value[0], ConceptNode) )) 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 = [] for node in nodes: concept = sheerka.new(node.concept.key) concept = self.update_concept(sheerka, concept, node.underlying) concepts.append(concept) if len(concepts) == 1: return sheerka.ret( self.name, True, concepts[0], parents=[return_value]) raise NotImplementedError("Not yet") 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