Added RET keyword

This commit is contained in:
2020-07-07 11:34:40 +02:00
parent 56e1cb4587
commit c4399d631c
21 changed files with 245 additions and 87 deletions
+2
View File
@@ -68,6 +68,7 @@ class BuiltinConcepts(Enum):
EVAL_WHERE_REQUESTED = "eval where requested" # to evaluate the where clause
CONCEPT_VALUE_REQUESTED = "concept value requested" # returns the body of the concept instead of the concept itself
REDUCE_REQUESTED = "reduce requested" # remove meaningless error when possible
EVAL_SUCCESS_REQUESTED = "Try to find a successful evaluation" # PyhtonEvaluator tries combination until True is found
NOT_A_SET = "not a set" # the concept has no entry in sets
WHERE_CLAUSE_FAILED = "where clause failed" # failed to validate where clause during evaluation
CHICKEN_AND_EGG = "chicken and egg" # infinite recursion when declaring concept
@@ -78,6 +79,7 @@ class BuiltinConcepts(Enum):
NOT_INITIALIZED = "not initialized"
NOT_FOUND = "not found" # when the wanted resource is not found
FORMAT_INSTRUCTIONS = "format instructions" # to express how to print the concept
NOT_IMPLEMENTED = "not implemented" # instead of raise an error
NODE = "node"
GENERIC_NODE = "generic node"
+8 -3
View File
@@ -314,11 +314,12 @@ def get_lexer_nodes(return_values, start, tokens):
return lexer_nodes
def ensure_evaluated(context, concept):
def ensure_evaluated(context, concept, eval_body=True):
"""
Evaluate a concept is not already evaluated
:param context:
:param concept:
:param eval_body:
:return:
"""
if concept.metadata.is_evaluated:
@@ -326,11 +327,15 @@ def ensure_evaluated(context, concept):
# do not try to evaluate concept that are not fully initialized
for var in concept.metadata.variables:
if var[0] not in concept.values or concept.get_value(var[0]) == NotInit:
# to code
if var[1] is None and \
var[0] not in concept.compiled and \
(var[0] not in concept.values or concept.get_value(var[0]) == NotInit):
return concept
with context.push(BuiltinConcepts.EVALUATE_CONCEPT, concept, desc=f"Evaluating concept {concept}") as sub_context:
sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
if eval_body:
sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
evaluated = context.sheerka.evaluate_concept(sub_context, concept)
sub_context.add_values(return_values=evaluated)
+5 -1
View File
@@ -12,7 +12,7 @@ from core.tokenizer import Tokenizer, TokenKind
PROPERTIES_FOR_DIGEST = ("name", "key",
"definition", "definition_type",
"is_builtin", "is_unique",
"where", "pre", "post", "body",
"where", "pre", "post", "body", "ret",
"desc", "props", "variables")
PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"])
PROPERTIES_FOR_NEW = ("where", "pre", "post", "body", "desc")
@@ -40,6 +40,7 @@ class ConceptParts(Enum):
PRE = "pre"
POST = "post"
BODY = "body"
RET = "ret"
@staticmethod
def get_parts():
@@ -56,6 +57,7 @@ class ConceptMetadata:
where: str # condition to recognize variables in name
pre: str # list of pre conditions before calling the main function
post: str # list of post conditions after calling the main function
ret: str # variable to return when a concept is recognized
definition: str # regex used to define the concept
definition_type: str # definition can be done with something else than regex
desc: str # possible description for the concept
@@ -82,6 +84,7 @@ class Concept:
where=None,
pre=None,
post=None,
ret=None,
definition=None,
definition_type=None,
desc=None,
@@ -98,6 +101,7 @@ class Concept:
where,
pre,
post,
ret,
definition,
definition_type,
desc,
+2 -2
View File
@@ -1,5 +1,5 @@
# ############################
# from github: nealtodd/decorator.py
# from github gist: nealtodd/decorator.py (https://gist.github.com/nealtodd/2489618)
# ############################
import pstats
@@ -8,7 +8,7 @@ from cProfile import Profile
def profile(sort_args=None, print_args=None):
sort_args = sort_args or ['cumulative']
print_args = print_args or [10]
print_args = print_args or [20]
profiler = Profile()
def decorator(fn):
+2 -1
View File
@@ -365,6 +365,7 @@ class Sheerka(Concept):
self.sdp.reset()
self.locals = {}
# @profile()
def evaluate_user_input(self, text: str, user_name="kodjo"):
"""
Note to KSI: If you try to add execution context to this function,
@@ -676,7 +677,7 @@ class Sheerka(Concept):
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
concept.metadata.is_evaluated = True # because we have manually set the variables
return concept
def ret(self, who: str, status: bool, value, message=None, parents=None):
+17 -33
View File
@@ -22,7 +22,7 @@ class SheerkaDump(BaseService):
def initialize(self):
self.sheerka.bind_service_method(self.dump_desc, "desc")
self.sheerka.bind_service_method(self.dump_state, "state")
self.sheerka.bind_service_method(self.dump_sdp, "dump_sdp")
def dump_desc(self, *concept_names, eval=False):
first = True
@@ -47,17 +47,24 @@ class SheerkaDump(BaseService):
if not first:
self.sheerka.log.info("")
self.sheerka.log.info(f"name : {c.name}")
self.sheerka.log.info(f"key : {c.key}")
self.sheerka.log.info(f"bnf : {c.metadata.definition}")
self.sheerka.log.info(f"body : {c.metadata.body}")
self.sheerka.log.info(f"where : {c.metadata.where}")
self.sheerka.log.info(f"name : {c.name}")
self.sheerka.log.info(f"key : {c.key}")
self.sheerka.log.info(f"definition : {c.metadata.definition}")
self.sheerka.log.info(f"type : {c.metadata.definition_type}")
self.sheerka.log.info(f"body : {c.metadata.body}")
self.sheerka.log.info(f"where : {c.metadata.where}")
self.sheerka.log.info(f"pre : {c.metadata.pre}")
self.sheerka.log.info(f"post : {c.metadata.post}")
self.sheerka.log.info(f"ret : {c.metadata.ret}")
self.sheerka.log.info(f"vars : {c.metadata.variables}")
self.sheerka.log.info(f"props : {c.metadata.props}")
if eval:
self.sheerka.log.info(f"value : {value}")
for v in c.values:
self.sheerka.log.info(f"{v}: {c.get_value(v)}")
if c.values:
for v in c.values:
self.sheerka.log.info(f"{v}: {c.get_value(v)}")
else:
self.sheerka.log.info("No property")
self.sheerka.log.info("No variable")
self.sheerka.log.info(f"digest : {c.get_origin()}")
@@ -67,30 +74,7 @@ class SheerkaDump(BaseService):
first = False
# def dump_history(self, page=20, start=0):
# count = 0
# resolved_page = page if page > 0 else 50
# page_count = 0
#
# while count < page if page > 0 else True:
# history = self.sheerka.history(resolved_page, start + page_count * resolved_page)
# try:
# h = next(history)
# except StopIteration:
# break
#
# while True:
# try:
# if h.result:
# self.sheerka.log.info(h)
# count += 1
# h = next(history)
# except StopIteration:
# break
#
# page_count += 1
def dump_state(self):
def dump_sdp(self):
snapshot = self.sheerka.sdp.get_snapshot(SheerkaDataProvider.HeadFile)
state = self.sheerka.sdp.load_state(snapshot)
self.sheerka.log.info(get_pp().pformat(state.data))
@@ -145,10 +145,12 @@ class SheerkaEvaluateConcept(BaseService):
if self.sheerka.has_id(concept.id):
self.sheerka.get_by_id(concept.id).compiled = concept.compiled
def resolve(self, context, to_resolve, current_prop, current_concept, force_evaluation):
def resolve(self, context, to_resolve, current_prop, current_concept, force_evaluation, expect_success):
def get_path(context_, prop_name):
prefix = context_.path if hasattr(context_, "path") else "<N/A>"
concept_name = f'"{context_.action_context.name}"' if isinstance(context_.action_context, Concept) \
else "'N/A'"
prefix = context_.path if hasattr(context_, "path") else concept_name
value = prop_name.name if isinstance(current_prop, ConceptParts) else prop_name
return prefix + "." + value
@@ -178,6 +180,9 @@ class SheerkaEvaluateConcept(BaseService):
if force_evaluation:
sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
if expect_success:
sub_context.local_hints.add(BuiltinConcepts.EVAL_SUCCESS_REQUESTED)
# when it's a concept, evaluate it
if isinstance(to_resolve, Concept) and \
not context.sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE):
@@ -206,7 +211,7 @@ class SheerkaEvaluateConcept(BaseService):
concept=current_concept,
property_name=current_prop)
def resolve_list(self, context, list_to_resolve, current_prop, current_concept, force_evaluation):
def resolve_list(self, context, list_to_resolve, current_prop, current_concept, force_evaluation, expect_success):
"""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)
@@ -215,7 +220,12 @@ class SheerkaEvaluateConcept(BaseService):
return []
if self.sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE):
return self.resolve(context, list_to_resolve, current_prop, current_concept, force_evaluation)
return self.resolve(context,
list_to_resolve,
current_prop,
current_concept,
force_evaluation,
expect_success)
res = []
for to_resolve in list_to_resolve:
@@ -226,7 +236,7 @@ class SheerkaEvaluateConcept(BaseService):
concept=current_concept,
property_name=current_prop)
r = self.resolve(context, to_resolve, current_prop, current_concept, force_evaluation)
r = self.resolve(context, to_resolve, current_prop, current_concept, force_evaluation, expect_success)
if self.sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return r
res.append(r)
@@ -258,10 +268,10 @@ class SheerkaEvaluateConcept(BaseService):
if isinstance(prop_ast, list):
# Do not send the current concept for the properties
resolved = self.resolve_list(context, prop_ast, var_name, None, True)
resolved = self.resolve_list(context, prop_ast, var_name, None, True, False)
else:
# Do not send the current concept for the properties
resolved = self.resolve(context, prop_ast, var_name, None, True)
resolved = self.resolve(context, prop_ast, var_name, None, True, False)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
resolved.set_value("concept", concept) # since current concept was not sent
@@ -278,10 +288,20 @@ class SheerkaEvaluateConcept(BaseService):
if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.compiled[part_key]
# if part_key is PRE, POST or WHERE, the concepts need to be evaluated
# otherwise the predicates cannot be resolved
# if part_key is PRE, POST or WHERE, the concept need to be evaluated
# if we want the predicates to be resolved => so force_eval = True
# otherwise no need to force
force_concept_eval = False if part_key == ConceptParts.BODY else True
resolved = self.resolve(context, metadata_ast, part_key, concept, force_concept_eval)
# when resolving predicate (where or pre), we need to make sure that PythonEvaluator
# will try every possibilities before returning False
expect_success = part_key in (ConceptParts.WHERE, ConceptParts.PRE)
resolved = self.resolve(context,
metadata_ast,
part_key,
concept,
force_concept_eval,
expect_success)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
return resolved
else:
@@ -312,9 +332,9 @@ class SheerkaEvaluateConcept(BaseService):
def choose_metadata_to_eval(self, context, concept):
if context.in_context(BuiltinConcepts.EVAL_BODY_REQUESTED):
return ["pre", "post", "variables", "body", "where"]
return ["pre", "post", "variables", "body", "where", "ret"]
metadata = ["pre", "post"]
metadata = ["pre", "post", "ret"]
if context.in_context(BuiltinConcepts.EVAL_WHERE_REQUESTED) or concept.metadata.need_validation:
needed = self.needed_metadata(concept, ConceptParts.WHERE)
for e in needed:
+2 -2
View File
@@ -326,13 +326,13 @@ class SheerkaExecute(BaseService):
result = evaluator.eval(sub_context, item)
if result is None:
# match() was successful but nothing was done in eval
# most of the time, it's because checks made in eval were unsuccessful
# most of the time, it's because extra checks are unsuccessful
debug_result.append({"input": item, "return_value": None})
continue
if id(result) == id(item):
# eval was successful, but we don't want to alter the processing flow
debug_result.append({"input": item, "return_value": item})
debug_result.append({"input": item, "return_value": result})
continue
# otherwise, item will be removed and replaced by result
+1
View File
@@ -128,6 +128,7 @@ class Keywords(Enum):
PRE = "pre"
POST = "post"
ISA = "isa"
RET = "ret"
class Tokenizer: