from core.ast.nodes import python_to_concept from core.builtin_concepts import ParserResultConcept, ReturnValueConcept from core.builtin_helpers import get_names from core.concept import Concept from evaluators.BaseEvaluator import OneReturnValueEvaluator from parsers.BaseParser import NotInitializedNode from parsers.ConceptLexerParser import ParsingExpression, ParsingExpressionVisitor from parsers.DefaultParser import DefConceptNode from parsers.PythonParser import PythonNode class ConceptOrRuleNameVisitor(ParsingExpressionVisitor): """ Gets the concepts referenced by BNF If a rule_name is given, it will also be considered as a potential property """ def __init__(self): self.names = set() def visit_ConceptMatch(self, node): if node.rule_name: self.names.add(node.rule_name) elif isinstance(node.concept, Concept): self.names.add(node.concept.name) else: self.names.add(node.concept) def visit_all(self, node): if node.rule_name: self.names.add(node.rule_name) class AddConceptEvaluator(OneReturnValueEvaluator): """ Used to add a new concept """ NAME = "AddNewConcept" def __init__(self): super().__init__(self.NAME, 50) def matches(self, context, return_value): return return_value.status and \ isinstance(return_value.value, ParserResultConcept) and \ isinstance(return_value.value.value, DefConceptNode) def eval(self, context, return_value): context.log(self.log, "Adding a new concept", self.name) def_concept_node = return_value.value.value sheerka = context.sheerka # validate the node props_found = set() concept = Concept(def_concept_node.name) for prop in ("definition", "where", "pre", "post", "body"): # put back the sources part_ret_val = getattr(def_concept_node, prop) if not isinstance(part_ret_val, ReturnValueConcept) or not part_ret_val.status: continue # Nothing to do is not initialized # update the parts source = self.get_source(part_ret_val) setattr(concept.metadata, prop, source) # try to find what can be a property concept_name = [part.value for part in def_concept_node.name.tokens] for p in self.get_props(sheerka, part_ret_val, concept_name): props_found.add(p) # add props order by appearance when possible for token in def_concept_node.name.tokens: if token.value in props_found: concept.set_prop(token.value, None) # add the remaining properties for p in props_found: if p not in concept.props: concept.set_prop(p, None) # finish initialisation concept.init_key(def_concept_node.name.tokens) concept.add_codes(def_concept_node.get_asts()) if not isinstance(def_concept_node.definition, NotInitializedNode) and \ sheerka.is_success(def_concept_node.definition): concept.bnf = def_concept_node.definition.value.value ret = sheerka.create_new_concept(context, concept) if not ret.status: error_cause = sheerka.value(ret.body) context.log(self.log, f"Failed to add concept '{concept.name}'. Reason: {error_cause}", self.name) return sheerka.ret(self.name, ret.status, ret.value, parents=[return_value]) @staticmethod def get_source(ret_value): return ret_value.value.source @staticmethod def get_props(sheerka, ret_value, concept_name): """ Try to find out the variables This function can only be a draft, as there may be tons of different situations I guess that it can only be complete when will we have access to Sheerka memory """ # # Case of python code # if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, PythonNode): python_node = ret_value.value.value as_concept_node = python_to_concept(python_node.ast_) variables = get_names(sheerka, as_concept_node) variables = filter(lambda x: x in concept_name, variables) return list(variables) # # case of concept # if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, Concept): return list(ret_value.value.value.props.keys()) # # case of BNF # if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, ParsingExpression): visitor = ConceptOrRuleNameVisitor() visitor.visit(ret_value.value.value) return sorted(list(visitor.names)) return []