import core.utils from core.builtin_concepts import BuiltinConcepts, ErrorConcept from core.concept import Concept, DEFINITION_TYPE_DEF, ensure_concept, DEFINITION_TYPE_BNF from core.sheerka.services.sheerka_service import BaseService from sdp.sheerkaDataProvider import SheerkaDataProviderDuplicateKeyError BNF_NODE_PARSER_CLASS = "parsers.BnfNodeParser_Old.BnfNodeParser" BASE_NODE_PARSER_CLASS = "parsers.BaseNodeParser.BaseNodeParser" class SheerkaCreateNewConcept(BaseService): """ Manage the creation of a new concept """ NAME = "CreateNewConcept" def __init__(self, sheerka): super().__init__(sheerka) self.bnp = core.utils.get_class(BASE_NODE_PARSER_CLASS) # BaseNodeParser def initialize(self): self.sheerka.bind_service_method(self.create_new_concept, True) def create_new_concept(self, context, concept: Concept): """ Adds a new concept to the system :param context: :param concept: DefConceptNode :return: digest of the new concept """ ensure_concept(concept) sheerka = self.sheerka concept.init_key() init_bnf_ret_value = None cache_manager = sheerka.cache_manager if cache_manager.exists(sheerka.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash()): error = SheerkaDataProviderDuplicateKeyError(sheerka.CONCEPTS_BY_KEY_ENTRY + "." + concept.key, concept) return sheerka.ret( self.NAME, False, sheerka.new(BuiltinConcepts.ALREADY_DEFINED, body=concept), error.args[0]) # set id before saving in db sheerka.set_id_if_needed(concept, False) # compute new concepts_by_first_keyword init_ret_value = self.bnp.get_concepts_by_first_token(context, [concept], True) if not init_ret_value.status: return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value)) concepts_by_first_keyword = init_ret_value.body # computes resolved concepts_by_first_keyword init_ret_value = self.bnp.resolve_concepts_by_first_keyword(context, concepts_by_first_keyword) if not init_ret_value.status: return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value)) resolved_concepts_by_first_keyword = init_ret_value.body # if everything is fine concept.freeze_definition_hash() cache_manager.add_concept(concept) cache_manager.put(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, concepts_by_first_keyword) cache_manager.put(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, resolved_concepts_by_first_keyword) if concept.metadata.definition_type == DEFINITION_TYPE_DEF and concept.metadata.definition != concept.name: # allow search by definition when definition relevant cache_manager.put(self.sheerka.CONCEPTS_BY_NAME_ENTRY, concept.metadata.definition, concept) # update references for ref in self.compute_references(concept): cache_manager.put(sheerka.CONCEPTS_REFERENCES_ENTRY, ref, concept.id) # TODO : this line seems to be useless # The grammar is never reset if concept.bnf and init_bnf_ret_value is not None and init_bnf_ret_value.status: sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY) # process the return if needed ret = sheerka.ret(self.NAME, True, sheerka.new(BuiltinConcepts.NEW_CONCEPT, body=concept)) return ret def compute_references(self, concept): """ We need to keep a track of all concepts used by the current concept So that if one of these are modified, we can modify the current concept accordingly :param concept: :return: """ refs = set() if concept.metadata.definition_type == DEFINITION_TYPE_BNF: from parsers.BnfNodeParser import BnfNodeConceptExpressionVisitor other_concepts_visitor = BnfNodeConceptExpressionVisitor() other_concepts_visitor.visit(concept.bnf) for concept in other_concepts_visitor.references: if isinstance(concept, str): concept = self.sheerka.get_by_key(concept) refs.add(concept.id) return refs