Fixed #43 : BnfNodeParser: I can recognize when multiple level of ISA
Fixed #44 : BnfNodeParser: I must simplify results when multiple levels of ISA Fixed #45 : Dynamic variables cannot be parsed at restart Fixed #46 : Concepts variables values are transformed into list by default Fixed #47 : SheerkaAdmin. Add min, max, mean time when restoring files
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
# define adjectives
|
||||||
|
push_ontology("english")
|
||||||
|
|
||||||
|
def concept adjective
|
||||||
|
def concept color
|
||||||
|
set_isa(color, adjective)
|
||||||
|
|
||||||
|
def concept red
|
||||||
|
def concept blue
|
||||||
|
def concept orange
|
||||||
|
def concept yellow
|
||||||
|
def concept green
|
||||||
|
def concept indigo
|
||||||
|
def concept violet
|
||||||
|
def concept cyan
|
||||||
|
def concept magenta
|
||||||
|
def concept black
|
||||||
|
def concept white
|
||||||
|
def concept grey
|
||||||
|
|
||||||
|
set_isa(red, color)
|
||||||
|
set_isa(blue, color)
|
||||||
|
set_isa(orange, color)
|
||||||
|
set_isa(yellow, color)
|
||||||
|
set_isa(green, color)
|
||||||
|
set_isa(indigo, color)
|
||||||
|
set_isa(violet, color)
|
||||||
|
set_isa(cyan, color)
|
||||||
|
set_isa(magenta, color)
|
||||||
|
set_isa(black, color)
|
||||||
|
set_isa(white, color)
|
||||||
|
set_isa(grey, color)
|
||||||
|
|
||||||
|
def concept qualify x from bnf adjective x as set_attr(x, c:adjective:, adjective) ret x
|
||||||
|
def concept qualify x from bnf x 'is' adjective as set_attr(x, c:adjective:, adjective) ret x
|
||||||
@@ -27,15 +27,19 @@ def concept x has a y as hasa(x,y) pre is_question()
|
|||||||
def concept x has an y as hasa(x,y) pre is_question()
|
def concept x has an y as hasa(x,y) pre is_question()
|
||||||
# no need to auto eval as it's a question
|
# no need to auto eval as it's a question
|
||||||
|
|
||||||
|
# AND
|
||||||
def concept x and y as x and y pre is_question()
|
def concept x and y as x and y pre is_question()
|
||||||
set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')
|
set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')
|
||||||
set_is_less_than(__PRECEDENCE, c:q:, c:x and y:, 'Sya')
|
set_is_less_than(__PRECEDENCE, c:q:, c:x and y:, 'Sya')
|
||||||
|
|
||||||
|
# OR
|
||||||
def concept x or y as x or y pre is_question()
|
def concept x or y as x or y pre is_question()
|
||||||
set_is_lesser(__PRECEDENCE, c:x or y:, 'Sya')
|
set_is_lesser(__PRECEDENCE, c:x or y:, 'Sya')
|
||||||
set_is_greater_than(__PRECEDENCE, c:x and y:, c:x or y:, 'Sya')
|
set_is_greater_than(__PRECEDENCE, c:x and y:, c:x or y:, 'Sya')
|
||||||
set_is_less_than(__PRECEDENCE, c:q:, c:x or y:, 'Sya')
|
set_is_less_than(__PRECEDENCE, c:q:, c:x or y:, 'Sya')
|
||||||
|
|
||||||
|
def concept the x ret memory(x)
|
||||||
|
|
||||||
# default
|
# default
|
||||||
def concept male
|
def concept male
|
||||||
def concept female
|
def concept female
|
||||||
@@ -46,6 +50,10 @@ woman is a female
|
|||||||
def concept human
|
def concept human
|
||||||
man is a human
|
man is a human
|
||||||
woman is a human
|
woman is a human
|
||||||
|
def concept boy
|
||||||
|
def concept boys
|
||||||
|
def concept girl
|
||||||
|
def concept girls
|
||||||
|
|
||||||
# days of the week
|
# days of the week
|
||||||
def concept monday
|
def concept monday
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#import default
|
#import default
|
||||||
#import python
|
#import python
|
||||||
#import numbers
|
#import numbers
|
||||||
|
#import adjectives
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# define numbers
|
# define numbers
|
||||||
|
push_ontology("english")
|
||||||
def concept one as 1
|
def concept one as 1
|
||||||
def concept two as 2
|
def concept two as 2
|
||||||
def concept three as 3
|
def concept three as 3
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
push_ontology("english")
|
||||||
def concept x is a string pre is_question() as isinstance(x, str)
|
def concept x is a string pre is_question() as isinstance(x, str)
|
||||||
def concept x is a int pre is_question() as isinstance(x, int)
|
|
||||||
def concept x is a integer pre is_question() as isinstance(x, int)
|
def concept x is a integer pre is_question() as isinstance(x, int)
|
||||||
def concept x starts with y pre is_question() where x is a string as x.startswith(y)
|
def concept x starts with y pre is_question() where x is a string as x.startswith(y)
|
||||||
def concept sha256 from bnf r'[a-f0-9]{64}'
|
def concept sha256 from bnf r'[a-f0-9]{64}'
|
||||||
|
|||||||
+2
-3
@@ -82,7 +82,7 @@ def get_concept_attrs(concept):
|
|||||||
|
|
||||||
# create a class attribute
|
# create a class attribute
|
||||||
with all_attributes_lock:
|
with all_attributes_lock:
|
||||||
all_attributes = [k for k in concept.__dict__ if k[0] != "_" and k[0] != "#"]
|
all_attributes = [var_name for var_name, var_value in concept.get_metadata().variables]
|
||||||
if concept.id and concept.key not in BuiltinDynamicAttrs:
|
if concept.id and concept.key not in BuiltinDynamicAttrs:
|
||||||
ALL_ATTRIBUTES[concept.id] = all_attributes
|
ALL_ATTRIBUTES[concept.id] = all_attributes
|
||||||
return all_attributes
|
return all_attributes
|
||||||
@@ -91,7 +91,7 @@ def get_concept_attrs(concept):
|
|||||||
def freeze_concept_attrs(concept):
|
def freeze_concept_attrs(concept):
|
||||||
with all_attributes_lock:
|
with all_attributes_lock:
|
||||||
if concept.key not in BuiltinDynamicAttrs:
|
if concept.key not in BuiltinDynamicAttrs:
|
||||||
ALL_ATTRIBUTES[concept.id] = [k for k in concept.__dict__ if k[0] != "_" and k[0] != "#"]
|
ALL_ATTRIBUTES[concept.id] = [var_name for var_name, var_value in concept.get_metadata().variables]
|
||||||
|
|
||||||
|
|
||||||
def copy_concepts_attrs():
|
def copy_concepts_attrs():
|
||||||
@@ -501,7 +501,6 @@ class Concept:
|
|||||||
|
|
||||||
def variables(self):
|
def variables(self):
|
||||||
return {k: v for k, v in self.values().items() if not k[0] == "#"}
|
return {k: v for k, v in self.values().items() if not k[0] == "#"}
|
||||||
# return dict([(k, v) for k, v in self.values.items() if isinstance(k, str)])
|
|
||||||
|
|
||||||
def set_hint(self, name, value):
|
def set_hint(self, name, value):
|
||||||
self._hints[name] = value
|
self._hints[name] = value
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ class SheerkaAdmin(BaseService):
|
|||||||
|
|
||||||
def restore_from_file(file_name):
|
def restore_from_file(file_name):
|
||||||
_nb_lines, _nb_instructions, _nb_lines_in_error = 0, 0, 0
|
_nb_lines, _nb_instructions, _nb_lines_in_error = 0, 0, 0
|
||||||
|
_min_time, _max_time = None, None
|
||||||
file_path = path.join(path.dirname(sys.argv[0]), file_name)
|
file_path = path.join(path.dirname(sys.argv[0]), file_name)
|
||||||
if not path.exists(file_path):
|
if not path.exists(file_path):
|
||||||
print(f"\u001b[31mFile '{file_path}' is not found !\u001b[0m")
|
print(f"\u001b[31mFile '{file_path}' is not found !\u001b[0m")
|
||||||
@@ -90,11 +91,15 @@ class SheerkaAdmin(BaseService):
|
|||||||
|
|
||||||
if line.startswith("#import "):
|
if line.startswith("#import "):
|
||||||
to_import = "_concepts_" + line[8:] + ".txt"
|
to_import = "_concepts_" + line[8:] + ".txt"
|
||||||
print(f"Importing {to_import}")
|
print(f" ==== Importing {to_import} ==== ")
|
||||||
res = restore_from_file(to_import)
|
res = restore_from_file(to_import)
|
||||||
_nb_lines += res[0]
|
_nb_lines += res[0]
|
||||||
_nb_instructions += res[1]
|
_nb_instructions += res[1]
|
||||||
_nb_lines_in_error += res[2]
|
_nb_lines_in_error += res[2]
|
||||||
|
if _min_time is None or res[3] < _min_time:
|
||||||
|
_min_time = res[3]
|
||||||
|
if _max_time is None or res[4] > _max_time:
|
||||||
|
_max_time = res[4]
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if line == "" or line.startswith("#"):
|
if line == "" or line.startswith("#"):
|
||||||
@@ -102,12 +107,20 @@ class SheerkaAdmin(BaseService):
|
|||||||
|
|
||||||
print(line)
|
print(line)
|
||||||
_nb_instructions += 1
|
_nb_instructions += 1
|
||||||
|
stop_watch = time.time_ns()
|
||||||
res = self.sheerka.evaluate_user_input(line)
|
res = self.sheerka.evaluate_user_input(line)
|
||||||
|
user_input_elapsed = time.time_ns() - stop_watch
|
||||||
|
|
||||||
|
if _min_time is None or user_input_elapsed < _min_time:
|
||||||
|
_min_time = user_input_elapsed
|
||||||
|
if _max_time is None or user_input_elapsed > _max_time:
|
||||||
|
_max_time = user_input_elapsed
|
||||||
|
|
||||||
if len(res) > 1 or not res[0].status:
|
if len(res) > 1 or not res[0].status:
|
||||||
_nb_lines_in_error += 1
|
_nb_lines_in_error += 1
|
||||||
print("\u001b[31mError detected !\u001b[0m")
|
print("\u001b[31mError detected !\u001b[0m")
|
||||||
|
|
||||||
return _nb_lines, _nb_instructions, _nb_lines_in_error
|
return _nb_lines, _nb_instructions, _nb_lines_in_error, _min_time, _max_time
|
||||||
|
|
||||||
if not concept_file.startswith("_concepts"):
|
if not concept_file.startswith("_concepts"):
|
||||||
concept_file = f"_concepts_{concept_file}.txt"
|
concept_file = f"_concepts_{concept_file}.txt"
|
||||||
@@ -119,7 +132,7 @@ class SheerkaAdmin(BaseService):
|
|||||||
enable_process_return_values_previous_value = self.sheerka.enable_process_return_values
|
enable_process_return_values_previous_value = self.sheerka.enable_process_return_values
|
||||||
self.sheerka.enable_process_return_values = False
|
self.sheerka.enable_process_return_values = False
|
||||||
|
|
||||||
nb_lines, nb_instructions, nb_lines_in_error = restore_from_file(concept_file)
|
nb_lines, nb_instructions, nb_lines_in_error, min_time, max_time = restore_from_file(concept_file)
|
||||||
|
|
||||||
self.sheerka.enable_process_return_values = enable_process_return_values_previous_value
|
self.sheerka.enable_process_return_values = enable_process_return_values_previous_value
|
||||||
self.sheerka.save_execution_context = True
|
self.sheerka.save_execution_context = True
|
||||||
@@ -128,8 +141,13 @@ class SheerkaAdmin(BaseService):
|
|||||||
|
|
||||||
nano_sec = stop - start
|
nano_sec = stop - start
|
||||||
dt = nano_sec / 1e6
|
dt = nano_sec / 1e6
|
||||||
elapsed = f"{dt} ms" if dt < 1000 else f"{dt / 1000} s"
|
elapsed = f"{dt:.3f} ms" if dt < 1000 else f"{dt / 1000:.3f} s"
|
||||||
print(f"Imported {nb_lines} line(s) in {elapsed}.")
|
min_str = f"{min_time / 1e6:.3f} ms"
|
||||||
|
max_str = f"{max_time / 1e6:.3f} ms"
|
||||||
|
mean_time = dt / nb_lines
|
||||||
|
mean_str = f"{mean_time:.3f} ms" if mean_time < 1000 else f"{mean_time / 1000:.3f} s"
|
||||||
|
|
||||||
|
print(f"Imported {nb_lines} line(s) in {elapsed}. min={min_str}, max={max_str}, mean={mean_str}")
|
||||||
print(f"{nb_instructions} instruction(s).")
|
print(f"{nb_instructions} instruction(s).")
|
||||||
if nb_lines_in_error > 0:
|
if nb_lines_in_error > 0:
|
||||||
print(f"\u001b[31m{nb_lines_in_error} errors(s) found.\u001b[0m")
|
print(f"\u001b[31m{nb_lines_in_error} errors(s) found.\u001b[0m")
|
||||||
@@ -153,6 +171,7 @@ class SheerkaAdmin(BaseService):
|
|||||||
"key": item.key,
|
"key": item.key,
|
||||||
"definition": item.get_metadata().definition,
|
"definition": item.get_metadata().definition,
|
||||||
"type": item.get_metadata().definition_type,
|
"type": item.get_metadata().definition_type,
|
||||||
|
"hash": item.get_definition_hash(),
|
||||||
"body": item.get_metadata().body,
|
"body": item.get_metadata().body,
|
||||||
"where": item.get_metadata().where,
|
"where": item.get_metadata().where,
|
||||||
"pre": item.get_metadata().pre,
|
"pre": item.get_metadata().pre,
|
||||||
|
|||||||
@@ -397,6 +397,17 @@ class SheerkaConceptManager(BaseService):
|
|||||||
ensure_concept(concept)
|
ensure_concept(concept)
|
||||||
|
|
||||||
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
||||||
|
|
||||||
|
if (old_value := concept.get_value(attr)) is not NotInit:
|
||||||
|
if old_value == value:
|
||||||
|
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||||
|
|
||||||
|
if isinstance(old_value, list):
|
||||||
|
old_value.append(value)
|
||||||
|
value = old_value
|
||||||
|
else:
|
||||||
|
value = [old_value, value]
|
||||||
|
|
||||||
concept.set_value(attr, value)
|
concept.set_value(attr, value)
|
||||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||||
|
|
||||||
@@ -892,11 +903,14 @@ class SheerkaConceptManager(BaseService):
|
|||||||
else:
|
else:
|
||||||
concepts = [concept]
|
concepts = [concept]
|
||||||
|
|
||||||
for concept in concepts:
|
for c in concepts:
|
||||||
ensure_bnf(context, concept) # need to make sure that it cannot fail
|
if sheerka.isaset(context, c):
|
||||||
keywords = SheerkaConceptManager.get_first_tokens(sheerka, concept)
|
to_resolve.add(c.str_id)
|
||||||
for keyword in keywords:
|
else:
|
||||||
(to_resolve if keyword.startswith("c:|") else resolved).add(keyword)
|
ensure_bnf(context, c) # need to make sure that it cannot fail
|
||||||
|
keywords = SheerkaConceptManager.get_first_tokens(sheerka, c)
|
||||||
|
for keyword in keywords:
|
||||||
|
(to_resolve if keyword.startswith("c:|") else resolved).add(keyword)
|
||||||
|
|
||||||
for concept_to_resolve_str in to_resolve:
|
for concept_to_resolve_str in to_resolve:
|
||||||
res = resolve_concepts(concept_to_resolve_str)
|
res = resolve_concepts(concept_to_resolve_str)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from core.sheerka.ExecutionContext import ExecutionContext
|
|||||||
from core.sheerka.services.sheerka_service import BaseService
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
from core.utils import CONSOLE_COLORS_MAP as CCM, CONSOLE_COLUMNS, PRIMITIVES_TYPES
|
from core.utils import CONSOLE_COLORS_MAP as CCM, CONSOLE_COLUMNS, PRIMITIVES_TYPES
|
||||||
from core.utils import as_bag
|
from core.utils import as_bag
|
||||||
|
from evaluators.MultipleSuccessEvaluator import MultipleSuccessEvaluator
|
||||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode, UnrecognizedTokensNode
|
from parsers.BaseNodeParser import SourceCodeWithConceptNode, UnrecognizedTokensNode
|
||||||
|
|
||||||
pp = pprint.PrettyPrinter(indent=2, width=CONSOLE_COLUMNS)
|
pp = pprint.PrettyPrinter(indent=2, width=CONSOLE_COLUMNS)
|
||||||
@@ -349,6 +350,7 @@ class SheerkaDebugManager(BaseService):
|
|||||||
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "exception")
|
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "exception")
|
||||||
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "trace")
|
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "trace")
|
||||||
self.register_debug_vars(SyaNodeParser.NAME, "parse", "*")
|
self.register_debug_vars(SyaNodeParser.NAME, "parse", "*")
|
||||||
|
self.register_debug_vars(MultipleSuccessEvaluator.NAME, "matches", "return_values")
|
||||||
|
|
||||||
def initialize_deferred(self, context, is_first_time):
|
def initialize_deferred(self, context, is_first_time):
|
||||||
self.restore_state()
|
self.restore_state()
|
||||||
|
|||||||
@@ -368,7 +368,8 @@ class SheerkaExecute(BaseService):
|
|||||||
if pi is NotFound: # when CacheManager.cache_only is True
|
if pi is NotFound: # when CacheManager.cache_only is True
|
||||||
pi = ParserInput(text)
|
pi = ParserInput(text)
|
||||||
self.pi_cache.put(text, pi)
|
self.pi_cache.put(text, pi)
|
||||||
return ParserInput(text, tokens=pi.tokens, length=pi.length) # new instance, but no need to tokenize the text again
|
return ParserInput(text, tokens=pi.tokens,
|
||||||
|
length=pi.length) # new instance, but no need to tokenize the text again
|
||||||
|
|
||||||
key = text or core.utils.get_text_from_tokens(tokens)
|
key = text or core.utils.get_text_from_tokens(tokens)
|
||||||
pi = ParserInput(key, tokens=tokens, length=len(tokens))
|
pi = ParserInput(key, tokens=tokens, length=len(tokens))
|
||||||
@@ -705,9 +706,8 @@ class SheerkaExecute(BaseService):
|
|||||||
# disable all parsers but the requested ones
|
# disable all parsers but the requested ones
|
||||||
if parsers != "all":
|
if parsers != "all":
|
||||||
sub_context.preprocess_parsers = parsers
|
sub_context.preprocess_parsers = parsers
|
||||||
# sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
|
else:
|
||||||
# for parser in parsers:
|
sub_context.preprocess_parsers = None
|
||||||
# sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
|
|
||||||
|
|
||||||
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE, Keywords.WHEN):
|
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE, Keywords.WHEN):
|
||||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class MultipleSuccessEvaluator(AllReturnValuesEvaluator):
|
|||||||
So we cannot decide whether it's a MultipleSameSuccess or not
|
So we cannot decide whether it's a MultipleSameSuccess or not
|
||||||
All parser in error will be discarded
|
All parser in error will be discarded
|
||||||
Cannot match if there is at least one evaluator in error
|
Cannot match if there is at least one evaluator in error
|
||||||
|
Cannot match if there is at least one successful parser
|
||||||
"""
|
"""
|
||||||
NAME = "MultipleSuccess"
|
NAME = "MultipleSuccess"
|
||||||
|
|
||||||
@@ -25,28 +26,50 @@ class MultipleSuccessEvaluator(AllReturnValuesEvaluator):
|
|||||||
nb_evaluators_in_success = 0
|
nb_evaluators_in_success = 0
|
||||||
to_process = False
|
to_process = False
|
||||||
|
|
||||||
|
debugger = context.get_debugger(MultipleSuccessEvaluator.NAME, "matches")
|
||||||
|
debugger.debug_entering(return_value=return_values)
|
||||||
|
|
||||||
for ret in return_values:
|
for ret in return_values:
|
||||||
if ret.status and ret.who.startswith(BaseParser.PREFIX):
|
if ret.status and ret.who.startswith(BaseParser.PREFIX):
|
||||||
|
reason = "a successful parser found"
|
||||||
|
debugger.debug_log(f"Failed because {reason}. ret={ret}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elif ret.who.startswith(BaseEvaluator.PREFIX) and not ret.status:
|
elif ret.who.startswith(BaseEvaluator.PREFIX) and not ret.status:
|
||||||
|
reason = "a failed evaluator found"
|
||||||
|
debugger.debug_log(f"Failed because {reason}. ret={ret}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
|
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
|
||||||
to_process = True
|
to_process = True
|
||||||
self.eaten.append(ret)
|
self.eaten.append(ret)
|
||||||
|
debugger.debug_log(f"BuiltinConcepts.REDUCE_REQUESTED is found. {to_process=}")
|
||||||
|
|
||||||
elif ret.status and ret.who.startswith(BaseEvaluator.PREFIX):
|
elif ret.status and ret.who.startswith(BaseEvaluator.PREFIX):
|
||||||
if self.already_seen(context, ret):
|
if self.already_seen(context, ret):
|
||||||
|
reason = "of duplicate return value"
|
||||||
|
debugger.debug_log(f"Failed because {reason}. ret={ret}")
|
||||||
return False
|
return False
|
||||||
nb_evaluators_in_success += 1
|
nb_evaluators_in_success += 1
|
||||||
self.successful_return_values.append(ret)
|
self.successful_return_values.append(ret)
|
||||||
self.eaten.append(ret)
|
self.eaten.append(ret)
|
||||||
|
debugger.debug_log(f"Eating and keeping {ret=}. {nb_evaluators_in_success=}")
|
||||||
|
|
||||||
elif not ret.status and ret.who.startswith(BaseParser.PREFIX):
|
elif not ret.status and ret.who.startswith(BaseParser.PREFIX):
|
||||||
self.eaten.append(ret)
|
self.eaten.append(ret)
|
||||||
|
debugger.debug_log(f"Eating {ret=}.")
|
||||||
|
|
||||||
# else:
|
# else:
|
||||||
# other concepts. We do not care if there are successful or not
|
# other concepts. We do not care if there are successful or not
|
||||||
# They won't be part of result nor part of the parent
|
# They won't be part of result nor part of the parent
|
||||||
# --> So they will be handled by other evaluators
|
# --> So they will be handled by other evaluators
|
||||||
|
|
||||||
return to_process and nb_evaluators_in_success > 1
|
res = to_process and nb_evaluators_in_success > 1
|
||||||
|
if not res:
|
||||||
|
reason = "not to_process and nb_evaluators_in_success > 1"
|
||||||
|
debugger.debug_log(f"Failed because '{reason}', {to_process=}, {nb_evaluators_in_success=}")
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
def eval(self, context, return_values):
|
def eval(self, context, return_values):
|
||||||
context.log(f"{len(self.successful_return_values)} successful return values, {len(self.eaten)} item(s) eaten",
|
context.log(f"{len(self.successful_return_values)} successful return values, {len(self.eaten)} item(s) eaten",
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ class NonTerminalNode(ParseTreeNode):
|
|||||||
res = f"{self.parsing_expression.concept}=>" if isinstance(self.parsing_expression, ConceptExpression) else ""
|
res = f"{self.parsing_expression.concept}=>" if isinstance(self.parsing_expression, ConceptExpression) else ""
|
||||||
return res + ".".join([c.get_debug() for c in self.children])
|
return res + ".".join([c.get_debug() for c in self.children])
|
||||||
|
|
||||||
|
def get_depth(self):
|
||||||
|
if isinstance(self.parsing_expression, ConceptExpression):
|
||||||
|
return 1 + max([c.get_depth() for c in self.children])
|
||||||
|
else:
|
||||||
|
return max([c.get_depth() for c in self.children])
|
||||||
|
|
||||||
|
|
||||||
class TerminalNode(ParseTreeNode):
|
class TerminalNode(ParseTreeNode):
|
||||||
"""
|
"""
|
||||||
@@ -150,6 +156,9 @@ class TerminalNode(ParseTreeNode):
|
|||||||
def get_debug(self):
|
def get_debug(self):
|
||||||
return str(self.value)
|
return str(self.value)
|
||||||
|
|
||||||
|
def get_depth(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
class MultiNode:
|
class MultiNode:
|
||||||
""""
|
""""
|
||||||
@@ -246,6 +255,12 @@ class ParsingContext:
|
|||||||
res = f"ParsingContext('{self.node.get_debug()}', pos={self.pos})"
|
res = f"ParsingContext('{self.node.get_debug()}', pos={self.pos})"
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def get_depth(self):
|
||||||
|
if isinstance(self.node, list):
|
||||||
|
return max([n.get_depth() for n in self.node])
|
||||||
|
else:
|
||||||
|
return self.node.get_depth()
|
||||||
|
|
||||||
|
|
||||||
class ParsingExpression:
|
class ParsingExpression:
|
||||||
log_sink = []
|
log_sink = []
|
||||||
@@ -738,8 +753,9 @@ class UnOrderedChoice(ParsingExpression):
|
|||||||
|
|
||||||
if parser_helper.debugger.is_enabled():
|
if parser_helper.debugger.is_enabled():
|
||||||
debug_prefix = self.debug_prefix("UnOrderedChoice", parser_helper)
|
debug_prefix = self.debug_prefix("UnOrderedChoice", parser_helper)
|
||||||
debug_text = {"pos": parser_helper.pos, "text": self.debug_remaining_text(parser_helper)}
|
debug_vars = {"pos": parser_helper.pos, "text": self.debug_remaining_text(parser_helper)}
|
||||||
parser_helper.debug_concept(debug_prefix, raw=f"{CCM['green']}{debug_text}{CCM['reset']}")
|
debug_text = self.debug_to_raw(debug_vars)
|
||||||
|
parser_helper.debug_concept(debug_prefix, color="cyan", raw=debug_text)
|
||||||
|
|
||||||
debug_text = ""
|
debug_text = ""
|
||||||
for e in self.nodes:
|
for e in self.nodes:
|
||||||
@@ -772,16 +788,52 @@ class UnOrderedChoice(ParsingExpression):
|
|||||||
|
|
||||||
parser_helper.seek(parsing_contexts[0].pos)
|
parser_helper.seek(parsing_contexts[0].pos)
|
||||||
|
|
||||||
if len(parsing_contexts) == 1:
|
# Try to simplify the parsing_context
|
||||||
return parsing_contexts[0].node
|
simplified_parsing_contexts = self.simplify(parsing_contexts)
|
||||||
|
|
||||||
|
if parser_helper.debugger.is_enabled() and len(simplified_parsing_contexts) != len(parsing_contexts):
|
||||||
|
parser_helper.debug_concept(debug_prefix, simplified=simplified_parsing_contexts)
|
||||||
|
|
||||||
|
if len(simplified_parsing_contexts) == 1:
|
||||||
|
return simplified_parsing_contexts[0].node
|
||||||
else:
|
else:
|
||||||
parsing_contexts.sort(key=attrgetter("pos"), reverse=True)
|
simplified_parsing_contexts.sort(key=attrgetter("pos"), reverse=True)
|
||||||
return MultiNode(parsing_contexts)
|
return MultiNode(simplified_parsing_contexts)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
to_str = "# ".join(repr(n) for n in self.elements)
|
to_str = "# ".join(repr(n) for n in self.elements)
|
||||||
return self.add_rule_name_if_needed(f"({to_str})")
|
return self.add_rule_name_if_needed(f"({to_str})")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def simplify(parsing_contexts: List[ParsingContext]):
|
||||||
|
"""
|
||||||
|
Try to remove redundant parsing context
|
||||||
|
for example, if
|
||||||
|
color is an adjective
|
||||||
|
red is an adjective
|
||||||
|
red is a color
|
||||||
|
when parsing 'red' we will receive two parsing context
|
||||||
|
one for 'red'
|
||||||
|
one for 'color' -> 'red'
|
||||||
|
|
||||||
|
The second one should be discarded
|
||||||
|
:param parsing_contexts:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if len(parsing_contexts) == 1:
|
||||||
|
return parsing_contexts
|
||||||
|
|
||||||
|
by_target = {}
|
||||||
|
for pc in parsing_contexts:
|
||||||
|
by_target.setdefault(pc.node.source, []).append((pc, pc.get_depth()))
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for k, tuple_pc_pc_depth in by_target.items():
|
||||||
|
min_depth = min([pc_depth for pc, pc_depth in tuple_pc_pc_depth])
|
||||||
|
res.extend([pc for pc, pc_depth in tuple_pc_pc_depth if pc_depth == min_depth])
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
class Optional(ParsingExpression):
|
class Optional(ParsingExpression):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class TestUsingFileBasedSheerka(BaseTest):
|
|||||||
TestUsingFileBasedSheerka.ontologies_created.clear()
|
TestUsingFileBasedSheerka.ontologies_created.clear()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def new_sheerka_instance(cache_only):
|
def new_sheerka_instance(cache_only=False):
|
||||||
sheerka = Sheerka(cache_only=cache_only)
|
sheerka = Sheerka(cache_only=cache_only)
|
||||||
sheerka.initialize(SHEERKA_TEST_FOLDER,
|
sheerka.initialize(SHEERKA_TEST_FOLDER,
|
||||||
save_execution_context=False,
|
save_execution_context=False,
|
||||||
|
|||||||
@@ -798,6 +798,34 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
assert sheerka.get_attr(foo, prop) == bar
|
assert sheerka.get_attr(foo, prop) == bar
|
||||||
|
|
||||||
|
def test_i_setting_twice_the_same_property_creates_a_list(self):
|
||||||
|
sheerka, context = self.init_concepts()
|
||||||
|
foo = Concept("foo")
|
||||||
|
prop = Concept("property")
|
||||||
|
bar = Concept("bar")
|
||||||
|
baz = Concept("baz")
|
||||||
|
qux = Concept("qux")
|
||||||
|
|
||||||
|
res = sheerka.set_attr(foo, prop, bar)
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||||
|
assert sheerka.get_attr(foo, prop) == bar
|
||||||
|
|
||||||
|
res = sheerka.set_attr(foo, prop, bar) # again, same value as no effect
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||||
|
assert sheerka.get_attr(foo, prop) == bar
|
||||||
|
|
||||||
|
res = sheerka.set_attr(foo, prop, baz)
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||||
|
assert sheerka.get_attr(foo, prop) == [bar, baz]
|
||||||
|
|
||||||
|
res = sheerka.set_attr(foo, prop, qux)
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||||
|
assert sheerka.get_attr(foo, prop) == [bar, baz, qux]
|
||||||
|
|
||||||
def test_i_cannot_remove_a_concept_which_has_reference(self):
|
def test_i_cannot_remove_a_concept_which_has_reference(self):
|
||||||
sheerka, context, one, twenty_one = self.init_test().with_concepts(
|
sheerka, context, one, twenty_one = self.init_test().with_concepts(
|
||||||
Concept("one"),
|
Concept("one"),
|
||||||
@@ -1067,6 +1095,27 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
|||||||
'hundred': ['1005', '1007'],
|
'hundred': ['1005', '1007'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def test_i_can_resolve_when_concepts_have_multiple_levels_of_sets(self):
|
||||||
|
sheerka, context, adjective, color, red, qualified_table = self.init_concepts(
|
||||||
|
"adjective",
|
||||||
|
"color",
|
||||||
|
"red",
|
||||||
|
Concept("qualified table", definition="adjective 'table'"),
|
||||||
|
)
|
||||||
|
|
||||||
|
sheerka.set_isa(context, color, adjective)
|
||||||
|
sheerka.set_isa(context, red, color)
|
||||||
|
|
||||||
|
by_first_token = compute_concepts_by_first_token(context, [adjective, color, red, qualified_table]).body
|
||||||
|
resolved_ret_val = resolve_concepts_by_first_keyword(context, by_first_token)
|
||||||
|
|
||||||
|
assert resolved_ret_val.status
|
||||||
|
assert resolved_ret_val.body == {
|
||||||
|
'adjective': ['1001'],
|
||||||
|
'color': ['1002'],
|
||||||
|
'red': ['1003', '1004'],
|
||||||
|
}
|
||||||
|
|
||||||
def test_concepts_are_defined_once(self):
|
def test_concepts_are_defined_once(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
context = self.get_context(sheerka)
|
context = self.get_context(sheerka)
|
||||||
|
|||||||
@@ -120,6 +120,14 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
|||||||
assert new.get_value("a") == 10
|
assert new.get_value("a") == 10
|
||||||
assert new.get_value("b") == "value"
|
assert new.get_value("b") == "value"
|
||||||
|
|
||||||
|
def test_i_can_instantiate_concepts_when_variables_are_defined_in_constructor(self):
|
||||||
|
sheerka, context, foo = self.init_test().with_concepts(
|
||||||
|
Concept(name="foo", variables=[("x", "default value for x"), ("y", None)]),
|
||||||
|
create_new=True).unpack()
|
||||||
|
|
||||||
|
new = sheerka.new(foo.key)
|
||||||
|
assert new.values() == {"x": NotInit, "y": NotInit} # default values are not used ?
|
||||||
|
|
||||||
def test_i_can_instantiate_multiple_when_same_key(self):
|
def test_i_can_instantiate_multiple_when_same_key(self):
|
||||||
sheerka, context, *concepts = self.init_test().with_concepts(
|
sheerka, context, *concepts = self.init_test().with_concepts(
|
||||||
Concept("foo", body="foo1"),
|
Concept("foo", body="foo1"),
|
||||||
|
|||||||
@@ -386,8 +386,10 @@ def test_i_can_deep_copy_a_concept():
|
|||||||
desc="concept2_desc",
|
desc="concept2_desc",
|
||||||
id="concept2_ids",
|
id="concept2_ids",
|
||||||
props={"prop_name": concept1},
|
props={"prop_name": concept1},
|
||||||
variables=[("var1", "default_value1"), ("var2", "default_value2")],
|
variables=[("var21", "default_value21"), ("var22", "default_value22")],
|
||||||
bound_body="var1")
|
bound_body="var1")
|
||||||
|
concept2.set_value("var21", "default_value21")
|
||||||
|
concept2.set_value("var22", "default_value22")
|
||||||
|
|
||||||
concept = Concept(name="my_name",
|
concept = Concept(name="my_name",
|
||||||
is_builtin=True,
|
is_builtin=True,
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
|||||||
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||||
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
|
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
|
||||||
from evaluators.PythonEvaluator import PythonEvalError
|
from evaluators.PythonEvaluator import PythonEvalError
|
||||||
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
|
|
||||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, CB
|
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, CB
|
||||||
|
|
||||||
@@ -1299,7 +1297,7 @@ as:
|
|||||||
|
|
||||||
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
|
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
|
||||||
|
|
||||||
def test_i_can_implement_implement_the_concept_and(self):
|
def test_i_can_implement_the_concept_and(self):
|
||||||
init = [
|
init = [
|
||||||
"def concept x and y as x and y",
|
"def concept x and y as x and y",
|
||||||
"set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')",
|
"set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')",
|
||||||
@@ -1310,4 +1308,3 @@ as:
|
|||||||
|
|
||||||
assert len(res) == 1
|
assert len(res) == 1
|
||||||
assert res[0].status
|
assert res[0].status
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from core.builtin_concepts_ids import BuiltinConcepts
|
from core.builtin_concepts_ids import BuiltinConcepts
|
||||||
|
from core.concept import get_concept_attrs, Concept, ALL_ATTRIBUTES
|
||||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||||
from parsers.BnfNodeParser import OrderedChoice, StrMatch, Sequence, ConceptExpression, Optional
|
from parsers.BnfNodeParser import OrderedChoice, StrMatch, Sequence, ConceptExpression, Optional
|
||||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||||
@@ -86,7 +87,7 @@ class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
|||||||
"set_isa(thirties, number)",
|
"set_isa(thirties, number)",
|
||||||
])
|
])
|
||||||
|
|
||||||
sheerka = self.get_sheerka() # another instance
|
sheerka = self.new_sheerka_instance()
|
||||||
|
|
||||||
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
|
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
|
||||||
assert sheerka.evaluate_user_input("eval thirty one")[0].body == 31
|
assert sheerka.evaluate_user_input("eval thirty one")[0].body == 31
|
||||||
@@ -95,10 +96,29 @@ class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
|||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
sheerka.evaluate_user_input("push_ontology('test')")
|
sheerka.evaluate_user_input("push_ontology('test')")
|
||||||
|
|
||||||
sheerka = self.new_sheerka_instance(False)
|
sheerka = self.new_sheerka_instance()
|
||||||
|
|
||||||
res = sheerka.evaluate_user_input("pop_ontology()")
|
res = sheerka.evaluate_user_input("pop_ontology()")
|
||||||
|
|
||||||
assert len(res) == 1
|
assert len(res) == 1
|
||||||
assert res[0].status
|
assert res[0].status
|
||||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.ONTOLOGY_REMOVED)
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.ONTOLOGY_REMOVED)
|
||||||
|
|
||||||
|
def test_i_can_read_concept_with_dynamic_variables_at_restart(self):
|
||||||
|
sheerka = self.init_scenario([
|
||||||
|
"def concept foo",
|
||||||
|
"def concept prop_name",
|
||||||
|
"def concept prop_value",
|
||||||
|
"eval foo",
|
||||||
|
"set_attr(foo, prop_name, prop_value)",
|
||||||
|
])
|
||||||
|
|
||||||
|
ALL_ATTRIBUTES.clear()
|
||||||
|
|
||||||
|
res = sheerka.evaluate_user_input("in_memory()")
|
||||||
|
res = sheerka.evaluate_user_input("memory(foo)")
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
|
||||||
|
assert get_concept_attrs(Concept("foo")) == []
|
||||||
|
assert get_concept_attrs(res[0].body) == ['c:prop_name|1002:']
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ name : foo
|
|||||||
key : foo
|
key : foo
|
||||||
definition: None
|
definition: None
|
||||||
type : None
|
type : None
|
||||||
|
hash : 16f7fbb8bc509b8c652edaf3d0c0457d15a37f0a862fbe03fa357b0c77249c46
|
||||||
body : 1
|
body : 1
|
||||||
where : None
|
where : None
|
||||||
pre : None
|
pre : None
|
||||||
@@ -44,6 +45,7 @@ name : foo
|
|||||||
key : foo
|
key : foo
|
||||||
definition: None
|
definition: None
|
||||||
type : None
|
type : None
|
||||||
|
hash : 7036cd5ffa9294d2e1dc9bf9c9bbe2783ace5cf7f423bfce9b28c8d33c0d1d0c
|
||||||
body : 2
|
body : 2
|
||||||
where : None
|
where : None
|
||||||
pre : None
|
pre : None
|
||||||
|
|||||||
@@ -1889,6 +1889,44 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
|||||||
assert isinstance(resolved.nodes[1], VariableExpression)
|
assert isinstance(resolved.nodes[1], VariableExpression)
|
||||||
assert resolved.nodes[0].nodes == []
|
assert resolved.nodes[0].nodes == []
|
||||||
|
|
||||||
|
def test_i_can_simplify_unordered_choices_that_refer_to_the_same_isa(self):
|
||||||
|
my_map = {
|
||||||
|
"light_red": Concept("light red"),
|
||||||
|
"dark_red": Concept("dark red"),
|
||||||
|
"red colors": Concept("red colors"),
|
||||||
|
"color": Concept("color"),
|
||||||
|
"adjective": Concept("adjective"),
|
||||||
|
"qualified table": Concept("qualified table", definition="adjective 'table'"),
|
||||||
|
}
|
||||||
|
|
||||||
|
sheerka, context, parser = self.init_parser(my_map, init_from_sheerka=True, create_new=True)
|
||||||
|
sheerka.set_isa(context, my_map["light_red"], my_map["adjective"])
|
||||||
|
sheerka.set_isa(context, my_map["dark_red"], my_map["adjective"])
|
||||||
|
sheerka.set_isa(context, my_map["light_red"], my_map["color"])
|
||||||
|
sheerka.set_isa(context, my_map["dark_red"], my_map["color"])
|
||||||
|
sheerka.set_isa(context, my_map["light_red"], my_map["red colors"])
|
||||||
|
sheerka.set_isa(context, my_map["dark_red"], my_map["red colors"])
|
||||||
|
sheerka.set_isa(context, my_map["color"], my_map["adjective"])
|
||||||
|
sheerka.set_isa(context, my_map["red colors"], my_map["color"])
|
||||||
|
sheerka.set_isa(context, my_map["red colors"], my_map["adjective"])
|
||||||
|
|
||||||
|
text = "light red table"
|
||||||
|
|
||||||
|
expected = CNC("qualified table",
|
||||||
|
source=text,
|
||||||
|
body=DoNotResolve(text),
|
||||||
|
adjective=CC("adjective",
|
||||||
|
source="light red",
|
||||||
|
body=CC("light_red", source="light red"),
|
||||||
|
light_red=CC("light_red", source="light red")))
|
||||||
|
expected_array = compute_expected_array(my_map, text, [expected])
|
||||||
|
|
||||||
|
res = parser.parse(context, ParserInput(text))
|
||||||
|
# there should be only one result !!
|
||||||
|
assert not isinstance(res, list)
|
||||||
|
assert res.status
|
||||||
|
compare_with_test_object(res.value.value, expected_array)
|
||||||
|
|
||||||
# @pytest.mark.parametrize("parser_input, expected", [
|
# @pytest.mark.parametrize("parser_input, expected", [
|
||||||
# ("one", [
|
# ("one", [
|
||||||
# (True, [CNC("bnf_one", source="one", one="one", body="one")]),
|
# (True, [CNC("bnf_one", source="one", one="one", body="one")]),
|
||||||
|
|||||||
Reference in New Issue
Block a user