Fixed BNF concept evaluations
This commit is contained in:
+17
-30
@@ -60,6 +60,22 @@ class BuiltinConcepts(Enum):
|
||||
return "__" + self.name
|
||||
|
||||
|
||||
BuiltinUnique = [
|
||||
BuiltinConcepts.BEFORE_PARSING,
|
||||
BuiltinConcepts.PARSING,
|
||||
BuiltinConcepts.AFTER_PARSING,
|
||||
BuiltinConcepts.BEFORE_EVALUATION,
|
||||
BuiltinConcepts.EVALUATION,
|
||||
BuiltinConcepts.AFTER_EVALUATION,
|
||||
BuiltinConcepts.BEFORE_RENDERING,
|
||||
BuiltinConcepts.RENDERING,
|
||||
BuiltinConcepts.AFTER_RENDERING,
|
||||
BuiltinConcepts.SUCCESS,
|
||||
BuiltinConcepts.NOP,
|
||||
BuiltinConcepts.CONCEPT_EVAL_REQUESTED,
|
||||
BuiltinConcepts.REDUCE_REQUESTED,
|
||||
]
|
||||
|
||||
BuiltinErrors = [str(e) for e in {
|
||||
BuiltinConcepts.ERROR,
|
||||
BuiltinConcepts.UNKNOWN_CONCEPT,
|
||||
@@ -75,7 +91,7 @@ BuiltinErrors = [str(e) for e in {
|
||||
|
||||
"""
|
||||
Some concepts have a specific implementation
|
||||
It's mainly to a have proper __repr__ implementation, or because they are singleton (is_unique=True)
|
||||
It's mainly to ease the usage
|
||||
"""
|
||||
|
||||
|
||||
@@ -96,11 +112,6 @@ class UserInputConcept(Concept):
|
||||
return f"({self.id}){self.name}: '{self.body}'"
|
||||
|
||||
|
||||
class SuccessConcept(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.SUCCESS, True, True, BuiltinConcepts.SUCCESS)
|
||||
|
||||
|
||||
class ErrorConcept(Concept):
|
||||
def __init__(self, error=None):
|
||||
super().__init__(BuiltinConcepts.ERROR, True, False, BuiltinConcepts.ERROR, error)
|
||||
@@ -256,30 +267,6 @@ class InvalidReturnValueConcept(Concept):
|
||||
self.set_prop("evaluator", evaluator)
|
||||
|
||||
|
||||
class BeforeParsingConcept(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.BEFORE_PARSING, True, True, BuiltinConcepts.BEFORE_PARSING)
|
||||
|
||||
|
||||
class EvaluationConcept(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.EVALUATION, True, True, BuiltinConcepts.EVALUATION)
|
||||
|
||||
|
||||
class AfterEvaluationConcept(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.AFTER_EVALUATION, True, True, BuiltinConcepts.AFTER_EVALUATION)
|
||||
|
||||
|
||||
class ConceptEvalRequested(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.CONCEPT_EVAL_REQUESTED, True, True, BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
|
||||
|
||||
|
||||
class ReduceRequested(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.REDUCE_REQUESTED, True, True, BuiltinConcepts.REDUCE_REQUESTED)
|
||||
|
||||
class ConceptEvalError(Concept):
|
||||
def __init__(self, error=None, concept=None, property_name=None):
|
||||
super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR,
|
||||
|
||||
+94
-50
@@ -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
|
||||
|
||||
@@ -220,6 +220,15 @@ def strip_tokens(tokens, strip_eof=False):
|
||||
return tokens[start: end + 1]
|
||||
|
||||
|
||||
def escape_char(text, to_escape):
|
||||
res = ""
|
||||
|
||||
for c in text:
|
||||
res += ("\\" + c) if c in to_escape else c
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def pp(items):
|
||||
if not hasattr(items, "__iter__"):
|
||||
return str(items)
|
||||
|
||||
Reference in New Issue
Block a user