Refactored to use a single implementation for concept evaluation
This commit is contained in:
+68
-28
@@ -1,6 +1,6 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept
|
||||
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors
|
||||
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_DIGEST
|
||||
from parsers.BaseParser import BaseParser
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
|
||||
@@ -11,7 +11,10 @@ from core.sheerka_logger import console_handler, get_logger
|
||||
|
||||
import logging
|
||||
|
||||
concept_evaluation_steps = [BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EVALUATION]
|
||||
CONCEPT_EVALUATION_STEPS = [
|
||||
BuiltinConcepts.BEFORE_EVALUATION,
|
||||
BuiltinConcepts.EVALUATION,
|
||||
BuiltinConcepts.AFTER_EVALUATION]
|
||||
CONCEPT_LEXER_PARSER_CLASS = "parsers.ConceptLexerParser.ConceptLexerParser"
|
||||
DEBUG_TAB_SIZE = 4
|
||||
|
||||
@@ -416,17 +419,21 @@ class Sheerka(Concept):
|
||||
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
|
||||
# I refuse empty strings for performance, I don't want to handle useless NOPConcepts
|
||||
# I refuse empty strings for performance matters, I don't want to handle useless NOPConcepts
|
||||
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, logger)
|
||||
|
||||
for prop in concept.props:
|
||||
to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=concept.props[prop].value))
|
||||
concept.cached_asts[prop] = self.execute(context, to_parse, steps)
|
||||
if concept.props[prop].value:
|
||||
to_parse = self.ret(
|
||||
context.who,
|
||||
True,
|
||||
self.new(BuiltinConcepts.USER_INPUT, body=concept.props[prop].value))
|
||||
concept.cached_asts[prop] = self.execute(context, to_parse, steps)
|
||||
|
||||
# updates the code of the reference when possible
|
||||
# Updates the cache of concepts when possible
|
||||
if concept.key in self.concepts_cache:
|
||||
entry = self.concepts_cache[concept.key]
|
||||
if isinstance(entry, list):
|
||||
@@ -435,32 +442,69 @@ 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, logger=None):
|
||||
def evaluate_concept(self, context, concept: Concept, logger=None):
|
||||
"""
|
||||
Evaluation a concept
|
||||
It means that if the where clause is True, will evaluate the body
|
||||
:param context:
|
||||
:param concept:
|
||||
:param properties_to_eval:
|
||||
:param logger:
|
||||
:return:
|
||||
:return: value of the evaluation or error
|
||||
"""
|
||||
|
||||
if concept.metadata.is_evaluated:
|
||||
return concept
|
||||
|
||||
def _resolve(resolve_context, return_value):
|
||||
r = self.execute(resolve_context, return_value, CONCEPT_EVALUATION_STEPS, logger or self.log)
|
||||
return core.builtin_helpers.expect_one(context, r)
|
||||
|
||||
# WHERE condition should already be validated by the parser.
|
||||
# It's a mandatory condition for the concept before it can be recognized
|
||||
|
||||
#
|
||||
# TODO : Validate the PRE condition
|
||||
#
|
||||
|
||||
if len(concept.cached_asts) == 0:
|
||||
self.initialize_concept_asts(context, concept, logger)
|
||||
|
||||
if properties_to_eval is None:
|
||||
properties_to_eval = ["where", "pre", "post", "body", "props"]
|
||||
# to make sure of the order, it don't use ConceptParts.get_parts()
|
||||
# props must be evaluated first
|
||||
properties_to_eval = ["props", "where", "pre", "post", "body"]
|
||||
|
||||
for prop in properties_to_eval:
|
||||
if prop == "props":
|
||||
pass
|
||||
for prop_to_eval in properties_to_eval:
|
||||
if prop_to_eval == "props":
|
||||
for prop_name in (p for p in concept.props if p in concept.cached_asts):
|
||||
sub_context = context.push(desc=f"Evaluating property '{prop_name}'")
|
||||
res = _resolve(sub_context, concept.cached_asts[prop_name])
|
||||
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)
|
||||
else:
|
||||
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, logger)
|
||||
res = core.builtin_helpers.expect_one(context, res)
|
||||
setattr(concept.metadata, prop, res.value)
|
||||
part_key = ConceptParts(prop_to_eval)
|
||||
if part_key in concept.cached_asts and concept.cached_asts[part_key] is not None:
|
||||
sub_context = context.push(desc=f"Evaluating '{part_key}'", obj=concept)
|
||||
res = _resolve(sub_context, concept.cached_asts[part_key])
|
||||
if res.status:
|
||||
setattr(concept.metadata, prop_to_eval, res.value)
|
||||
else:
|
||||
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
|
||||
body=res.value,
|
||||
concept=concept,
|
||||
property_name=part_key)
|
||||
|
||||
#
|
||||
# TODO : Validate the POST condition
|
||||
#
|
||||
|
||||
concept.init_key() # only does it if needed
|
||||
concept.metadata.is_evaluated = True
|
||||
return concept
|
||||
|
||||
def add_in_cache(self, concept: Concept):
|
||||
"""
|
||||
@@ -601,16 +645,16 @@ class Sheerka(Concept):
|
||||
return (self.value(obj) for obj in objs)
|
||||
|
||||
def is_success(self, obj):
|
||||
if isinstance(obj, bool):
|
||||
if isinstance(obj, bool): # quick win
|
||||
return obj
|
||||
|
||||
if self.isinstance(obj, BuiltinConcepts.RETURN_VALUE):
|
||||
if isinstance(obj, ReturnValueConcept):
|
||||
return obj.status
|
||||
|
||||
if self.isinstance(obj, BuiltinConcepts.ERROR):
|
||||
if isinstance(obj, Concept) and obj.metadata.is_builtin and obj.key in BuiltinErrors:
|
||||
return False
|
||||
|
||||
return False
|
||||
return obj
|
||||
|
||||
def isinstance(self, a, b):
|
||||
"""
|
||||
@@ -724,10 +768,6 @@ class Sheerka(Concept):
|
||||
log_format = "%(message)s"
|
||||
log_level = logging.INFO
|
||||
|
||||
# logging.root.setLevel(log_level)
|
||||
# fmt = logging.Formatter(log_format, None, "%")
|
||||
# console_handler.setFormatter(fmt)
|
||||
|
||||
logging.basicConfig(format=log_format, level=log_level, handlers=[console_handler])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user