Fixed initialisation issue for concepts with BNF definition
This commit is contained in:
+39
-23
@@ -15,6 +15,7 @@ concept_evaluation_steps = [BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EV
|
||||
CONCEPT_LEXER_PARSER_CLASS = "parsers.ConceptLexerParser.ConceptLexerParser"
|
||||
DEBUG_TAB_SIZE = 4
|
||||
|
||||
|
||||
class Sheerka(Concept):
|
||||
"""
|
||||
Main controller for the project
|
||||
@@ -38,10 +39,9 @@ class Sheerka(Concept):
|
||||
# key is the key of the concept (not the name or the id)
|
||||
self.concepts_cache = {}
|
||||
|
||||
#
|
||||
# Cache for all concepts BNF
|
||||
#
|
||||
self.concepts_definitions = {}
|
||||
# cache for concept definitions,
|
||||
# Primarily used for unit test that does not have access to sdp
|
||||
self.concepts_definition_cache = {}
|
||||
|
||||
#
|
||||
# cache for concepts grammars
|
||||
@@ -199,6 +199,7 @@ class Sheerka(Concept):
|
||||
return_values = [return_values]
|
||||
|
||||
for return_value in return_values:
|
||||
# make sure we only parse user input
|
||||
if not return_value.status or not self.isinstance(return_value.body, BuiltinConcepts.USER_INPUT):
|
||||
continue
|
||||
|
||||
@@ -207,7 +208,8 @@ class Sheerka(Concept):
|
||||
if self.log.isEnabledFor(logging.DEBUG):
|
||||
debug_text = "'" + to_parse + "'" if isinstance(to_parse, str) \
|
||||
else "'" + BaseParser.get_text_from_tokens(to_parse) + "' as tokens"
|
||||
# self.log.debug(f"Parsing {debug_text}")
|
||||
execution_context.log(logger or self.log, f"Parsing {debug_text}")
|
||||
|
||||
for parser in self.parsers.values():
|
||||
p = parser(sheerka=self)
|
||||
if logger:
|
||||
@@ -224,17 +226,16 @@ class Sheerka(Concept):
|
||||
|
||||
return result
|
||||
|
||||
def _call_evaluators(self, execution_context, return_values, process_step, evaluation_context=None):
|
||||
"""
|
||||
|
||||
"""
|
||||
def _call_evaluators(self, execution_context, return_values, process_step, evaluation_context=None, logger=None):
|
||||
|
||||
# return_values must be a list
|
||||
if not isinstance(return_values, list):
|
||||
return_values = [return_values]
|
||||
|
||||
# evaluation context are contexts that may modify the behaviour of the execution
|
||||
# They first need to be transformed into return values
|
||||
# Evaluation context are contexts that may modify the behaviour of the execution
|
||||
# For example, a concept to indicate that the value is not wanted
|
||||
# Or a concept to indicate that we want the letter form of the response
|
||||
# But first, they need to be transformed into return values
|
||||
if evaluation_context is None:
|
||||
evaluation_return_values = []
|
||||
else:
|
||||
@@ -250,7 +251,11 @@ class Sheerka(Concept):
|
||||
# The first one to be applied will be the one with the highest priority
|
||||
grouped_evaluators = {}
|
||||
for evaluator in [e() for e in self.evaluators if e.enabled]:
|
||||
if logger:
|
||||
evaluator.log = logger
|
||||
grouped_evaluators.setdefault(evaluator.priority, []).append(evaluator)
|
||||
|
||||
# order the groups by priority, the higher first
|
||||
sorted_priorities = sorted(grouped_evaluators.keys(), reverse=True)
|
||||
|
||||
# process
|
||||
@@ -283,6 +288,7 @@ class Sheerka(Concept):
|
||||
evaluator=evaluator)
|
||||
evaluated_items.append(self.ret("sheerka.process", False, error, parents=[item]))
|
||||
to_delete.append(item)
|
||||
|
||||
# process evaluators that work on all return values
|
||||
else:
|
||||
if evaluator.matches(execution_context, original_items):
|
||||
@@ -326,7 +332,7 @@ class Sheerka(Concept):
|
||||
if step == BuiltinConcepts.PARSING:
|
||||
return_values = self._call_parsers(sub_context, return_values, logger)
|
||||
else:
|
||||
return_values = self._call_evaluators(sub_context, return_values, step)
|
||||
return_values = self._call_evaluators(sub_context, return_values, step, None, logger)
|
||||
|
||||
sub_context.log_result(logger or self.log, return_values)
|
||||
|
||||
@@ -357,6 +363,7 @@ class Sheerka(Concept):
|
||||
init_ret_value = None
|
||||
|
||||
# checks for duplicate concepts
|
||||
# TODO checks if it exists in cache first
|
||||
if self.sdp.exists(self.CONCEPTS_ENTRY, concept.key, concept.get_digest()):
|
||||
error = SheerkaDataProviderDuplicateKeyError(self.CONCEPTS_ENTRY + "." + concept.key, concept)
|
||||
return self.ret(self.create_new_concept.__name__, False, ErrorConcept(error), error.args[0])
|
||||
@@ -366,12 +373,12 @@ class Sheerka(Concept):
|
||||
|
||||
# add the BNF if known
|
||||
if concept.bnf:
|
||||
concepts_definitions = self.concepts_definitions.copy()
|
||||
concepts_definitions = self.get_concept_definition()
|
||||
concepts_definitions[concept] = concept.bnf
|
||||
|
||||
# check if it's a valid BNF or whether it breaks the known rules
|
||||
concept_lexer_parser = self.parsers[CONCEPT_LEXER_PARSER_CLASS](grammars=self.concepts_grammars.copy())
|
||||
sub_context = context.push(self.name, desc="Initializing concept definition")
|
||||
concept_lexer_parser = self.parsers[CONCEPT_LEXER_PARSER_CLASS]()
|
||||
sub_context = context.push(self.name, desc=f"Initializing concept definition for {concept}")
|
||||
sub_context.concepts[concept.key] = concept # the concept is not in the real cache yet
|
||||
init_ret_value = concept_lexer_parser.initialize(sub_context, concepts_definitions)
|
||||
if not init_ret_value.status:
|
||||
@@ -387,8 +394,6 @@ class Sheerka(Concept):
|
||||
|
||||
# Updates the caches
|
||||
self.concepts_cache[concept.key] = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.key)
|
||||
if concepts_definitions is not None:
|
||||
self.concepts_definitions = concepts_definitions
|
||||
if init_ret_value is not None and init_ret_value.status:
|
||||
self.concepts_grammars = init_ret_value.body
|
||||
|
||||
@@ -396,12 +401,13 @@ class Sheerka(Concept):
|
||||
ret = self.ret(self.create_new_concept.__name__, True, self.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
||||
return ret
|
||||
|
||||
def initialize_concept_asts(self, context, concept: Concept):
|
||||
def initialize_concept_asts(self, context, concept: Concept, logger=None):
|
||||
"""
|
||||
Updates the codes of the newly created concept
|
||||
Basically, it runs the parsers on all parts
|
||||
:param concept:
|
||||
:param context:
|
||||
:param logger:
|
||||
:return:
|
||||
"""
|
||||
# steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
|
||||
@@ -414,7 +420,7 @@ class Sheerka(Concept):
|
||||
continue
|
||||
else:
|
||||
to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=source))
|
||||
concept.cached_asts[part_key] = self.execute(context, to_parse, steps)
|
||||
concept.cached_asts[part_key] = self.execute(context, to_parse, steps, logger)
|
||||
|
||||
for prop in concept.props:
|
||||
to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=concept.props[prop].value))
|
||||
@@ -429,18 +435,18 @@ class Sheerka(Concept):
|
||||
else:
|
||||
self.concepts_cache[concept.key].cached_asts = concept.cached_asts
|
||||
|
||||
def eval_concept(self, context, concept: Concept, properties_to_eval=None):
|
||||
def eval_concept(self, context, concept: Concept, properties_to_eval=None, logger=None):
|
||||
"""
|
||||
Evaluation a concept
|
||||
It means that if the where clause is True, will evaluate the body
|
||||
Also chc
|
||||
:param context:
|
||||
:param concept:
|
||||
:param properties_to_eval:
|
||||
:param logger:
|
||||
:return:
|
||||
"""
|
||||
if len(concept.cached_asts) == 0:
|
||||
self.initialize_concept_asts(context, concept)
|
||||
self.initialize_concept_asts(context, concept, logger)
|
||||
|
||||
if properties_to_eval is None:
|
||||
properties_to_eval = ["where", "pre", "post", "body", "props"]
|
||||
@@ -452,7 +458,7 @@ class Sheerka(Concept):
|
||||
part_key = ConceptParts(prop)
|
||||
if concept.cached_asts[part_key] is None:
|
||||
continue
|
||||
res = self.execute(context, concept.cached_asts[part_key], concept_evaluation_steps)
|
||||
res = self.execute(context, concept.cached_asts[part_key], concept_evaluation_steps, logger)
|
||||
res = core.builtin_helpers.expect_one(context, res)
|
||||
setattr(concept.metadata, prop, res.value)
|
||||
|
||||
@@ -661,6 +667,13 @@ class Sheerka(Concept):
|
||||
|
||||
return self.parsers_prefix + name
|
||||
|
||||
def get_concept_definition(self):
|
||||
if self.concepts_definition_cache:
|
||||
return self.concepts_definition_cache
|
||||
|
||||
self.concepts_definition_cache = self.sdp.get_safe(self.CONCEPTS_DEFINITIONS_ENTRY, load_origin=False) or {}
|
||||
return self.concepts_definition_cache
|
||||
|
||||
def concepts(self):
|
||||
res = []
|
||||
lst = self.sdp.list(self.CONCEPTS_ENTRY)
|
||||
@@ -687,6 +700,9 @@ class Sheerka(Concept):
|
||||
else:
|
||||
self.log.info(item)
|
||||
|
||||
def dump_definitions(self):
|
||||
defs = self.sdp.get(self.CONCEPTS_DEFINITIONS_ENTRY)
|
||||
self.log.info(defs)
|
||||
|
||||
@staticmethod
|
||||
def get_builtins_classes_as_dict():
|
||||
|
||||
Reference in New Issue
Block a user