Refactored to use cached_asts in Concepts, rather than setting up a value directly

This commit is contained in:
2020-01-12 10:28:44 +01:00
parent 73a6d4e6c2
commit 51fa9629d0
9 changed files with 256 additions and 167 deletions
+78 -34
View File
@@ -1,5 +1,5 @@
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors, BuiltinUnique
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_NEW
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_NEW, DoNotResolve
from parsers.BaseParser import BaseParser
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
import core.utils
@@ -551,6 +551,9 @@ class Sheerka(Concept):
"""
steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
for part_key in ConceptParts:
if part_key in concept.cached_asts:
continue
source = getattr(concept.metadata, part_key.value)
if source is None or not isinstance(source, str) or source == "":
# the only sources that I am sure to parse are strings
@@ -565,6 +568,9 @@ class Sheerka(Concept):
sub_context.add_values(return_values=res)
for prop in concept.props:
if prop in concept.cached_asts:
continue
value = concept.props[prop].value
if value:
if isinstance(value, Concept):
@@ -604,14 +610,65 @@ class Sheerka(Concept):
if concept.metadata.is_evaluated:
return concept
def _resolve(return_value, desc, obj):
def _resolve(to_resolve, current_prop, current_concept):
if isinstance(to_resolve, DoNotResolve):
return to_resolve.value
desc = f"Evaluating {current_prop} (concept={current_concept})"
context.log(logger, desc, self.evaluate_concept.__name__)
with context.push(desc=desc, obj=obj) as sub_context:
with context.push(desc=desc, obj=current_concept) as sub_context:
sub_context.log_new(logger)
r = self.execute(sub_context, return_value, CONCEPT_EVALUATION_STEPS, logger)
one_r = core.builtin_helpers.expect_one(context, r)
sub_context.add_values(return_values=one_r)
return one_r
# when it's a concept, evaluate it
if isinstance(to_resolve, Concept):
evaluated = self.evaluate_concept(sub_context, to_resolve)
sub_context.add_values(return_values=evaluated)
if evaluated.key == to_resolve.key:
return evaluated
else:
error = evaluated
# otherwise, execute all return values to find out what is the value
else:
r = self.execute(sub_context, to_resolve, CONCEPT_EVALUATION_STEPS, logger)
one_r = core.builtin_helpers.expect_one(context, r)
sub_context.add_values(return_values=one_r)
if one_r.status:
return one_r.value
else:
error = one_r.value
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=error,
concept=concept,
property_name=prop_name)
def _resolve_list(sheerka, list_to_resolve, current_prop, current_concept):
"""When dealing with a list, there are two possibilities"""
# It may be a list of ReturnValueConcept to execute (always the case for metadata)
# or a list of single values (may be the case for properties)
# in this latter case, all values are to be processed one by one and a list should be returned
if len(list_to_resolve) == 0:
return []
if sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE):
return _resolve(list_to_resolve, current_prop, current_concept)
res = []
for to_resolve in list_to_resolve:
# sanity check
if sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE):
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body="Mix between real values and return values",
concept=concept,
property_name=prop_name)
r = _resolve(to_resolve, current_prop, current_concept)
if sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return r
res.append(r)
return res
# WHERE condition should already be validated by the parser.
# It's a mandatory condition for the concept before it can be recognized
@@ -620,9 +677,7 @@ class Sheerka(Concept):
# TODO : Validate the PRE condition
#
if len(concept.cached_asts) == 0:
context.log(logger, "concept asts are not initialized. Initializing.", self.evaluate_concept.__name__)
self.initialize_concept_asts(context, concept, logger)
self.initialize_concept_asts(context, concept, logger)
# to make sure of the order, it don't use ConceptParts.get_parts()
# props must be evaluated first
@@ -632,35 +687,24 @@ class Sheerka(Concept):
if metadata_to_eval == "props":
for prop_name in (p for p in concept.props if p in concept.cached_asts):
prop_ast = concept.cached_asts[prop_name]
if isinstance(concept.cached_asts[prop_name], Concept):
context.log(
logger, f"Evaluation prop={prop_name}, value={prop_ast}", self.evaluate_concept.__name__)
with context.push(f"Evaluation property '{prop_name}', value='{prop_ast}'") as sub_context:
sub_context.log_new(logger)
evaluated = self.evaluate_concept(sub_context, prop_ast)
sub_context.add_values(return_values=evaluated)
concept.set_prop(prop_name, evaluated)
if isinstance(prop_ast, list):
resolved = _resolve_list(context.sheerka, prop_ast, prop_name, None)
else:
res = _resolve(prop_ast, f"Evaluating property '{prop_name}'", None)
if res.status:
concept.set_prop(prop_name, res.value)
else:
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=res.value,
concept=concept,
property_name=prop_name)
resolved = _resolve(prop_ast, prop_name, None)
if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return resolved
else:
concept.set_prop(prop_name, resolved)
else:
part_key = ConceptParts(metadata_to_eval)
if part_key in concept.cached_asts and concept.cached_asts[part_key] is not None:
res = _resolve(concept.cached_asts[part_key], f"Evaluating '{part_key}'", concept)
if res.status:
setattr(concept.metadata, metadata_to_eval, res.value)
metadata_ast = concept.cached_asts[part_key]
resolved = _resolve(metadata_ast, part_key, concept)
if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return resolved
else:
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=res.value,
concept=concept,
property_name=part_key)
setattr(concept.metadata, metadata_to_eval, resolved)
#
# TODO : Validate the POST condition