Refactored Concept class for better separation of metadata, compiled and values

This commit is contained in:
2020-01-17 17:27:54 +01:00
parent 3789ef25d1
commit a7b239c167
27 changed files with 614 additions and 349 deletions
+44 -37
View File
@@ -571,40 +571,41 @@ class Sheerka(Concept):
"""
steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
for part_key in ConceptParts:
if part_key in concept.cached_asts:
if part_key in concept.compiled:
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
# I refuse empty strings for performance matters, I don't want to handle useless NOPConcepts
if source is None or not isinstance(source, str):
continue
if source.strip() == "":
concept.compiled[part_key] = DoNotResolve(source)
else:
with context.push(desc=f"Initializing AST for {part_key}") as sub_context:
with context.push(desc=f"Initializing compiled for {part_key}") as sub_context:
sub_context.log_new(logger)
sub_context.add_inputs(source=source)
to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=source))
res = self.execute(sub_context, to_parse, steps, logger)
concept.cached_asts[part_key] = res
concept.compiled[part_key] = res
sub_context.add_values(return_values=res)
for prop in concept.props:
if prop in concept.cached_asts:
for prop, default_value in concept.metadata.props:
if prop in concept.compiled:
continue
value = concept.props[prop].value
if value:
if isinstance(value, Concept):
concept.cached_asts[prop] = value
else:
to_parse = self.ret(
context.who,
True,
self.new(BuiltinConcepts.USER_INPUT, body=value))
with context.push(desc=f"Initializing AST for property {prop}") as sub_context:
sub_context.log_new(logger)
res = self.execute(context, to_parse, steps)
concept.cached_asts[prop] = res
sub_context.add_values(return_values=res)
if default_value is None or not isinstance(default_value, str):
continue
if default_value.strip() == "":
concept.compiled[prop] = DoNotResolve(default_value)
else:
with context.push(desc=f"Initializing AST for property {prop}") as sub_context:
sub_context.log_new(logger)
sub_context.add_inputs(source=default_value)
to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=default_value))
res = self.execute(context, to_parse, steps)
concept.compiled[prop] = res
sub_context.add_values(return_values=res)
# Updates the cache of concepts when possible
if concept.key in self.concepts_cache:
@@ -613,7 +614,7 @@ class Sheerka(Concept):
# TODO : manage when there are multiple entries
pass
else:
self.concepts_cache[concept.key].cached_asts = concept.cached_asts
self.concepts_cache[concept.key].compiled = concept.compiled
def evaluate_concept(self, context, concept: Concept, logger=None):
"""
@@ -706,8 +707,8 @@ class Sheerka(Concept):
for metadata_to_eval in all_metadata_to_eval:
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]
for prop_name in (p for p in concept.props if p in concept.compiled):
prop_ast = concept.compiled[prop_name]
if isinstance(prop_ast, list):
resolved = _resolve_list(context.sheerka, prop_ast, prop_name, None)
@@ -719,13 +720,13 @@ class Sheerka(Concept):
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:
metadata_ast = concept.cached_asts[part_key]
if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.compiled[part_key]
resolved = _resolve(metadata_ast, part_key, concept)
if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return resolved
else:
setattr(concept.metadata, metadata_to_eval, resolved)
concept.values[part_key] = resolved
#
# TODO : Validate the POST condition
@@ -789,7 +790,8 @@ class Sheerka(Concept):
unknown_concept = Concept()
template = self.concepts_cache[str(BuiltinConcepts.UNKNOWN_CONCEPT)]
unknown_concept.update_from(template)
unknown_concept.metadata.body = concept_key
unknown_concept.set_metadata_value(ConceptParts.BODY, concept_key)
unknown_concept.metadata.is_evaluated = True
return unknown_concept
def new(self, concept_key, **kwargs):
@@ -812,13 +814,13 @@ class Sheerka(Concept):
concept_key != BuiltinConcepts.UNKNOWN_CONCEPT:
return template
if not isinstance(template, list):
if isinstance(template, list):
# if template is a list, it means that there a multiple concepts under the same key
concepts = [self.new_from_template(t, concept_key, **kwargs) for t in template]
return concepts
else:
return self.new_from_template(template, concept_key, **kwargs)
# if template is a list, it means that there a multiple concepts under the same key
concepts = [self.new_from_template(t, concept_key, **kwargs) for t in template]
return concepts
def new_from_template(self, template, key, **kwargs):
# manage singleton
if template.metadata.is_unique:
@@ -828,18 +830,23 @@ class Sheerka(Concept):
concept = self.builtin_cache[key]() if key in self.builtin_cache else Concept()
concept.update_from(template)
# update the properties
if len(kwargs) == 0:
return concept
# update the properties, values, attributes
# Not quite sure that this is the correct process order
for k, v in kwargs.items():
if k in concept.props:
concept.set_prop(k, v)
elif k in PROPERTIES_FOR_NEW:
setattr(concept.metadata, k, v)
concept.values[ConceptParts(k)] = v
elif hasattr(concept, k):
setattr(concept, k, v)
else:
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
# TODO : add the concept to the list of known concepts (self.instances)
concept.metadata.is_evaluated = True
return concept
def ret(self, who: str, status: bool, value, message=None, parents=None):
@@ -880,7 +887,7 @@ class Sheerka(Concept):
return self.value(body_to_use)
def values(self, objs):
def get_values(self, objs):
if not (isinstance(objs, list) or
self.isinstance(objs, BuiltinConcepts.LIST) or
self.isinstance(objs, BuiltinConcepts.ENUMERATION)):