Fixed BNF concept evaluations

This commit is contained in:
2020-01-03 19:19:57 +01:00
parent adcbc6bb2e
commit ffd98d7407
20 changed files with 682 additions and 237 deletions
+94 -50
View File
@@ -1,6 +1,6 @@
from dataclasses import dataclass, field
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors, BuiltinUnique
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_NEW
from parsers.BaseParser import BaseParser
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
@@ -114,6 +114,10 @@ class Sheerka(Concept):
else builtins_classes[str(key)]() if str(key) in builtins_classes \
else Concept(key, True, False, key)
if key in BuiltinUnique:
concept.metadata.is_unique = True
concept.metadata.is_evaluated = True
if not concept.metadata.is_unique and str(key) in builtins_classes:
self.builtin_cache[key] = builtins_classes[str(key)]
@@ -214,7 +218,7 @@ class Sheerka(Concept):
result.append(return_value)
continue
to_parse = self.value(return_value)
to_parse = return_value.body.body # get the underlying text
if self.log.isEnabledFor(logging.DEBUG):
debug_text = "'" + to_parse + "'" if isinstance(to_parse, str) \
@@ -509,14 +513,18 @@ class Sheerka(Concept):
concept.cached_asts[part_key] = self.execute(sub_context, to_parse, steps, logger)
for prop in concept.props:
if concept.props[prop].value:
to_parse = self.ret(
context.who,
True,
self.new(BuiltinConcepts.USER_INPUT, body=concept.props[prop].value))
sub_context = context.push(desc=f"Initializing AST for property {prop}")
sub_context.log_new(logger)
concept.cached_asts[prop] = self.execute(context, to_parse, steps)
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))
sub_context = context.push(desc=f"Initializing AST for property {prop}")
sub_context.log_new(logger)
concept.cached_asts[prop] = self.execute(context, to_parse, steps)
# Updates the cache of concepts when possible
if concept.key in self.concepts_cache:
@@ -545,7 +553,6 @@ class Sheerka(Concept):
def _resolve(return_value, desc, obj):
context.log(logger, desc, self.evaluate_concept.__name__)
sub_context = context.push(desc=desc, obj=obj)
sub_context.add_preprocess(self.get_evaluator_name("Concept"), return_body=True)
sub_context.log_new(logger)
r = self.execute(sub_context, return_value, CONCEPT_EVALUATION_STEPS, logger)
return core.builtin_helpers.expect_one(context, r)
@@ -568,14 +575,23 @@ 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):
res = _resolve(concept.cached_asts[prop_name], f"Evaluating property '{prop_name}'", None)
if res.status:
concept.set_prop(prop_name, res.value)
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__)
sub_context = context.push(f"Evaluation property '{prop_name}', value='{prop_ast}'")
sub_context.log_new(logger)
evaluated = self.evaluate_concept(sub_context, prop_ast)
concept.set_prop(prop_name, evaluated)
else:
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=res.value,
concept=concept,
property_name=prop_name)
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)
else:
part_key = ConceptParts(metadata_to_eval)
@@ -654,41 +670,41 @@ class Sheerka(Concept):
"""
template = self.get(concept_key)
def new_from_template(t, k, **kwargs_):
# manage singleton
if t.metadata.is_unique:
return t
# otherwise, create another instance
concept = self.builtin_cache[k]() if k in self.builtin_cache else Concept()
concept.update_from(t)
# update the properties
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)
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)
return concept
# manage concept not found
if self.isinstance(template, BuiltinConcepts.UNKNOWN_CONCEPT) and \
concept_key != BuiltinConcepts.UNKNOWN_CONCEPT:
return template
if not isinstance(template, list):
return new_from_template(template, concept_key, **kwargs)
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 = [new_from_template(t, concept_key, **kwargs) for t in template]
concepts = [self.new_from_template(t, concept_key, **kwargs) for t in template]
return self.new(BuiltinConcepts.ENUMERATION, body=concepts)
def new_from_template(self, template, key, **kwargs):
# manage singleton
if template.metadata.is_unique:
return template
# otherwise, create another instance
concept = self.builtin_cache[key]() if key in self.builtin_cache else Concept()
concept.update_from(template)
# update the properties
for key, v in kwargs.items():
if key in concept.props:
concept.set_prop(key, v)
elif key in PROPERTIES_FOR_NEW:
setattr(concept.metadata, key, v)
elif hasattr(concept, key):
setattr(concept, key, v)
else:
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=key, concept=concept)
# TODO : add the concept to the list of known concepts (self.instances)
return concept
def ret(self, who: str, status: bool, value, message=None, parents=None):
"""
Creates and returns a ReturnValue concept
@@ -841,17 +857,25 @@ class Sheerka(Concept):
def dump_desc(self, concept_name):
if isinstance(concept_name, Concept):
c = concept_name
concepts = concept_name
else:
c = self.get(concept_name)
if self.isinstance(c, BuiltinConcepts.UNKNOWN_CONCEPT):
concepts = self.get(concept_name)
if self.isinstance(concepts, BuiltinConcepts.UNKNOWN_CONCEPT):
self.log.error("Concept unknown")
return False
self.log.info(f"name : {c.name}")
self.log.info(f"bnf : {c.metadata.definition}")
self.log.info(f"key : {c.key}")
self.log.info(f"body : {c.body}")
if not hasattr(concepts, "__iter__"):
concepts = [concepts]
first = True
for c in concepts:
if not first:
self.log.info("")
self.log.info(f"name : {c.name}")
self.log.info(f"bnf : {c.metadata.definition}")
self.log.info(f"key : {c.key}")
self.log.info(f"body : {c.body}")
first = False
@staticmethod
def get_builtins_classes_as_dict():
@@ -920,6 +944,26 @@ class ExecutionContext:
self.preprocess.add(preprocess)
return self
def new_concept(self, key, **kwargs):
# search in obj
if self.obj:
if self.obj.key == key:
return self.sheerka.new_from_template(self.obj, key, **kwargs)
for prop in self.obj.props:
if prop == key:
value = self.obj.props[prop].value
if isinstance(value, Concept):
return self.sheerka.new_from_template(value, key, **kwargs)
else:
return value
if self.concepts:
for k, c in self.concepts.items():
if k == key:
return self.sheerka.new_from_template(c, key, **kwargs)
return self.sheerka.new(key, **kwargs)
@property
def id(self):
return self._id