Refactored to use cached_asts in Concepts, rather than setting up a value directly
This commit is contained in:
@@ -293,3 +293,16 @@ class Property:
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.name, self.value))
|
||||
|
||||
|
||||
@dataclass()
|
||||
class DoNotResolve:
|
||||
"""
|
||||
This class is used to that the metadata (or the prop) of the concept must not be evaluated
|
||||
thru sheerka.execute
|
||||
|
||||
For example, if you want to set a value to the BODY that will not change when
|
||||
when the concept will be evaluated,
|
||||
set concept.cached_asts[BODY] to DoNotResolve(value)
|
||||
"""
|
||||
value: object
|
||||
|
||||
+78
-34
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user