Fixed #100 : SheerkaAdmin: Add builtins() command

Fixed #99 : SheerkaQueryManager: I can manage contains predicate when filtering objects
Fixed #97 : ERROR: list indices must be integers or slices, not Concept
Fixed #96 : SequenceNodeParser: SequenceNodeParser must correctly handle concept definition
Fixed #95 : ResolveAmbiguity must not remove concepts that do not require evaluation
Fixed #94 : Concepts with the same key are lost when new ontology
Fixed #93 : Introduce BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED
Fixed #92 : ExpressionParser: Implement compile_disjunctions()
Fixed #91 : Implement get_concepts_complexity(context, concepts, concept_parts)
Fixed #90 : ResolveAmbiguity : where predicate is not used to resolve ambiguity
Fixed #89 : ResolveAmbiguityEvaluator: Concepts embedded in ConceptNode are not resolved
Fixed #88: SyaNodeParser: Parse multiple parameters when some of the are not recognized
Fixed #87: SyaNodeParser : Parse the multiple parameters
This commit is contained in:
2021-07-31 08:52:00 +02:00
parent 7dcaa9c111
commit e69745adc8
70 changed files with 1561 additions and 455 deletions
+2
View File
@@ -4,3 +4,5 @@ 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 sha256 from bnf r'[a-f0-9]{64}'
def concept sha512 from bnf r'[a-f0-9]{128}'
def concept explain x where isinstance(x, sha256) as get_results_by_digest(x, id=0, depth=2) auto_eval True
+3 -2
View File
@@ -83,18 +83,19 @@ class CacheManager:
self.caches[name] = CacheDefinition(cache, use_ref, None, persist)
def add_concept(self, concept):
def add_concept(self, concept, alt_sdp=None):
"""
We need multiple indexes to retrieve a concept
So the new concept is dispatched into multiple caches
:param concept:
:param alt_sdp: if not found in self.sdp, look in other repositories
:return:
"""
with self._lock:
for name in self.concept_caches:
cache_def = self.caches[name]
key = cache_def.get_key(concept)
cache_def.cache.put(key, concept)
cache_def.cache.put(key, concept, alt_sdp)
self.is_dirty = True
+2
View File
@@ -16,6 +16,7 @@ class BuiltinConcepts:
REDUCE_REQUESTED = "__REDUCE_REQUESTED" # remove meaningless error when possible
EVAL_UNTIL_SUCCESS_REQUESTED = "__EVAL_UNTIL_SUCCESS_REQUESTED" # PythonEvaluator tries combination until True is found
EVAL_QUESTION_REQUESTED = "__EVAL_QUESTION_REQUESTED" # the user input must be treated as question
EVAL_GLOBAL_TRUTH_REQUESTED = "__EVAL_GLOBAL_TRUTH_REQUESTED" # the user input is a global truth
VALIDATION_ONLY_REQUESTED = "__VALIDATION_ONLY_REQUESTED" # Validation mode activated. Never evaluate the body
# possible actions during sheerka.execute() or sheerka.evaluate_rules()
@@ -47,6 +48,7 @@ class BuiltinConcepts:
EXEC_CODE = "__EXEC_CODE" # to use when executing Python or other language compiled code
TESTING = "__TESTING"
EVALUATOR_PRE_PROCESS = "__EVALUATOR_PRE_PROCESS" # used modify / tweak behaviour of evaluators
EVALUATING_PRE_OR_WHERE_CLAUSE = "EVALUATING_PRE_OR_WHERE_CLAUSE" # use in is_question()
# builtin attributes
ISA = "__ISA" # when a concept is an instance of another one
+73 -10
View File
@@ -7,8 +7,10 @@ from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF, concept_part_value
from core.global_symbols import NotInit, NotFound, INIT_AST_PARSERS, DEFAULT_EVALUATORS
from core.rule import Rule
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer, TokenKind
from core.utils import as_bag
from parsers.BaseExpressionParser import compile_disjunctions, AndNode
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode, \
RuleNode, LexerNode
from parsers.BaseParser import ParsingError
@@ -205,7 +207,7 @@ def only_successful(context, return_values):
def resolve_ambiguity(context, concepts):
"""
From the list of concepts, elect the one(s) that best suit(s) the context
Use the PRE metadata to choose the correct concepts
Use the PRE and WHERE metadata to choose the correct concepts
:param context:
:param concepts:
:return:
@@ -214,8 +216,9 @@ def resolve_ambiguity(context, concepts):
# we first sort by condition complexity. The more complex is the PRE condition, the more likely
# the concept matches the context
by_complexity = {}
parts = [concept_part_value(ConceptParts.PRE), concept_part_value(ConceptParts.WHERE)]
for c in concepts:
by_complexity.setdefault(get_condition_complexity(c, concept_part_value(ConceptParts.PRE)), []).append(c)
by_complexity.setdefault(get_concept_complexity(context, c, parts), []).append(c)
remaining_concepts = []
for complexity in sorted(by_complexity.keys(), reverse=True):
@@ -226,14 +229,14 @@ def resolve_ambiguity(context, concepts):
evaluated = context.sheerka.evaluate_concept(context, c,
eval_body=False,
validation_only=True,
metadata=[ConceptParts.PRE])
metadata=[ConceptParts.PRE, ConceptParts.WHERE])
if context.sheerka.is_success(evaluated) or evaluated.key == c.key:
remaining_concepts.append(c)
if len(remaining_concepts) > 0:
break # no need to check concept with lower complexity
if len(remaining_concepts) in (0, 1):
if len(remaining_concepts) < 2:
return remaining_concepts # they all failed the pre conditions or one champ is found
# for concepts with the same condition complexity, we choose the one that has the less number of variables
@@ -246,19 +249,58 @@ def resolve_ambiguity(context, concepts):
return by_number_of_vars[min(by_number_of_vars.keys())]
def get_condition_complexity(concept, concept_part_str):
def get_condition_complexity(context, condition):
if condition is None or condition.strip() == "":
return 0
# # count the number of conjunctions
from parsers.LogicalOperatorParser import LogicalOperatorParser
parser = LogicalOperatorParser()
res = parser.parse(context, ParserInput(condition))
if not res.status:
return 0
disjunctions = compile_disjunctions(res.body.body)
complexity = 0
for conjunction in disjunctions:
node_complexity = len(conjunction.parts) if isinstance(conjunction, AndNode) else 1
if node_complexity > complexity:
complexity = node_complexity
return complexity
def get_concept_complexity(context, concept, concepts_parts):
"""
Need to find a proper algorithm to compute the complexity of a concept metadata
So far, the concept is considered as complex if it has concept_part_str (so far with concept_part_str='pre')
:param context:
:param concept:
:param concept_part_str:
:param concepts_parts:
:return:
"""
value = getattr(concept.get_metadata(), concept_part_str)
if value is None or value.strip() == 0:
return 0
complexity = 0
for i, parts in enumerate(reversed(concepts_parts)):
return 1 # no real computing as of now
for part in parts.split("|"):
value = getattr(concept.get_metadata(), part)
part_complexity = get_condition_complexity(context, value)
if part_complexity > 0:
complexity += part_complexity + (i * 100)
return complexity
def get_concepts_complexity(context, concepts, concepts_parts):
"""
compute the complexity of the concepts, relatively to each others
:param context:
:param concepts: concepts
:param concepts_parts: metadata to use to compute the complexity
:return:
"""
return {c.id or c.name: get_concept_complexity(context, c, concepts_parts) for c in concepts}
def only_parsers_results(context, return_values):
@@ -723,6 +765,27 @@ def set_is_evaluated(concepts, check_nb_variables=False):
concepts.get_hints().is_evaluated = True
def update_concepts_hints(concepts, is_evaluated=None, recognized_by=None, is_instance=None):
if concepts is None:
return
def update_concept_hints(c, _is_evaluated, _recognized_by, _is_instance):
if _is_evaluated is not None:
c.get_hints().is_evaluated = _is_evaluated
if _recognized_by is not None:
c.get_hints().recognized_by = _recognized_by
if _is_instance is not None:
c.get_hints().is_instance = _is_instance
if hasattr(concepts, "__iter__"):
for concept in concepts:
update_concept_hints(concept, is_evaluated, recognized_by, is_instance)
else:
update_concept_hints(concepts, is_evaluated, recognized_by, is_instance)
def ensure_concept(*concepts):
if hasattr(concepts, "__iter__"):
for concept in concepts:
+10 -3
View File
@@ -44,14 +44,16 @@ def concept_part_value(c):
class ConceptHints:
is_evaluated: bool = False # True is the concept is evaluated by sheerka.eval_concept()
need_validation: bool = False # True if the properties of the concept need to be validated
recognized_by: str = None
use_copy: bool = False
recognized_by: str = None # recognized by its name, by its id or its key
use_copy: bool = False # Do not modify, make a copy first
is_instance: bool = True # False if we think we recognize the definition of a concept, not its usage
def copy(self):
return ConceptHints(self.is_evaluated,
self.need_validation,
self.recognized_by,
self.use_copy)
self.use_copy,
self.is_instance)
@dataclass
@@ -624,6 +626,11 @@ class Concept:
return Concept().update_from(self, update_hint=True, update_compiled=True)
def get_concept(self):
"""
Used when there is a mix of Concept and ConceptNode
To quickly get the inner concept
:return:
"""
return self
+1 -1
View File
@@ -96,4 +96,4 @@ INIT_AST_PARSERS = ["ExactConcept",
INIT_AST_QUESTION_PARSERS = ["Expression"]
DEFAULT_EVALUATORS = ["Python", "Concept", "LexerNode", "ValidateConcept", "ResolveAmbiguity"]
DEFAULT_EVALUATORS = ["Python", "Concept", "LexerNode", "Expression", "ValidateConcept", "ResolveAmbiguity"]
+1 -1
View File
@@ -79,7 +79,7 @@ class ExecutionContext:
self.private_hints = set()
self.protected_hints = set()
self.global_hints = set() if global_hints is None else global_hints
self.errors = [] if errors is None else errors # error are global
self.errors = [] if errors is None else errors # errors are global
self.inputs = {} # what were the parameters of the execution context
self.values = {} # what was produced by the execution context
+66 -15
View File
@@ -46,6 +46,7 @@ RULES_EXECUTE_STEPS = [
# It indicate which parameter was used to recognize the concept
RECOGNIZED_BY_ID = "by_id"
RECOGNIZED_BY_NAME = "by_name"
RECOGNIZED_BY_KEY = "by_key"
@dataclass
@@ -53,9 +54,17 @@ class SheerkaMethod:
"""
Wrapper to sheerka method, to indicate if it's safe to call
"""
name: str
service: str
method: object
has_side_effect: bool
def __repr__(self):
return self.name
def __hash__(self):
return hash((self.name, self.service))
class Sheerka(Concept):
"""
@@ -111,16 +120,18 @@ class Sheerka(Concept):
self.methods_with_context = {"test_using_context"} # only the names, the method is defined in sheerka_methods
self.pipe_functions = set()
self.sheerka_methods = {
"test": SheerkaMethod(self.test, False),
"test_using_context": SheerkaMethod(self.test_using_context, False),
"test_dict": SheerkaMethod(self.test_dict, False),
"test_error": SheerkaMethod(self.test_error, False),
"is_sheerka": SheerkaMethod(self.is_sheerka, False),
"objvalue": SheerkaMethod(self.objvalue, False),
"test": SheerkaMethod("test", self.name, self.test, False),
"test_using_context": SheerkaMethod("test_using_context", self.name, self.test_using_context, False),
"test_dict": SheerkaMethod("test_dict", self.name, self.test_dict, False),
"test_error": SheerkaMethod("test_error", self.name, self.test_error, False),
"is_sheerka": SheerkaMethod("is_sheerka", self.name, self.is_sheerka, False),
"objvalue": SheerkaMethod("objvalue", self.name, self.objvalue, False),
}
self.concepts_ids = None
self._global_context_hints = set() # hints to add to every execution contexts before every execution
def __copy__(self):
return self
@@ -135,9 +146,10 @@ class Sheerka(Concept):
def root_folder(self):
return self.om.root_folder
def bind_service_method(self, bound_method, has_side_effect, as_name=None, visible=True):
def bind_service_method(self, service_name, bound_method, has_side_effect, as_name=None, visible=True):
"""
Bind service method to sheerka instance for ease of use ?
:param service_name:
:param bound_method:
:param has_side_effect: False if the method is safe
:param as_name: give another name to the method
@@ -157,7 +169,7 @@ class Sheerka(Concept):
signature = inspect.signature(bound_method)
if len(signature.parameters) > 0 and list(signature.parameters.keys())[0] == "context":
self.methods_with_context.add(as_name)
self.sheerka_methods[as_name] = SheerkaMethod(bound_method, has_side_effect)
self.sheerka_methods[as_name] = SheerkaMethod(as_name, service_name, bound_method, has_side_effect)
if is_pipe_function:
self.pipe_functions.add(as_name)
@@ -368,6 +380,9 @@ class Sheerka(Concept):
text,
desc=f"Evaluating '{text}'") as execution_context:
# adds the global context hints if any
execution_context.global_hints = self._global_context_hints.copy()
user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name))
execution_context.add_inputs(user_input=user_input)
@@ -465,17 +480,35 @@ class Sheerka(Concept):
return None
def fast_resolve(self, key, return_new=True):
def add_recognized_by(c, _recognized_by):
c.get_hints().recognized_by = _recognized_by
def fast_resolve(self, key, return_new=True, force_instance=False):
"""
Resolve a concept, but do not use get_by_name() or get_by_id()
:param key:
:param return_new:
:param force_instance: When set, return an concept instance, not a concept definition
:return:
"""
def update_hints(c, rec_by, is_inst, is_eval):
c.get_hints().recognized_by = rec_by
c.get_hints().is_instance = is_inst
if is_eval is None:
c.get_hints().is_evaluated = len(c.get_metadata().variables) > 0
else:
c.get_hints().is_evaluated = is_eval
return c
def new_instances(concepts, _recognized_by):
def new_instances(concepts, rec_by, is_inst, is_eval):
if hasattr(concepts, "__iter__"):
return [add_recognized_by(self.new_from_template(c, c.key), _recognized_by) for c in concepts]
return [update_hints(self.new_from_template(c, c.key), rec_by, is_inst, is_eval) for c in
concepts]
return add_recognized_by(self.new_from_template(concepts, concepts.key), _recognized_by)
return update_hints(self.new_from_template(concepts, concepts.key), rec_by, is_inst, is_eval)
# ##############
# PREPROCESS
# ##############
# if the entry is a concept token, use its values.
if isinstance(key, Token):
if key.type == TokenKind.RULE: # do not recognize rules !!!
return None
@@ -484,10 +517,15 @@ class Sheerka(Concept):
elif isinstance(key, str) and key.startswith("c:"):
key = core.utils.unstr_concept(key)
# ##############
# Get the concept(s)
# ##############
if isinstance(key, tuple):
if key == (None, None):
return None
is_instance = force_instance
is_evaluated = not force_instance
if key[1]:
concept = self.om.get(self.CONCEPTS_BY_ID_ENTRY, key[1])
recognized_by = RECOGNIZED_BY_ID
@@ -495,12 +533,15 @@ class Sheerka(Concept):
concept = self.om.get(self.CONCEPTS_BY_NAME_ENTRY, key[0])
recognized_by = RECOGNIZED_BY_NAME
else:
is_instance = True
is_evaluated = None
concept = self.om.get(self.CONCEPTS_BY_NAME_ENTRY, key)
recognized_by = RECOGNIZED_BY_NAME
if concept is NotFound:
return None
return new_instances(concept, recognized_by) if return_new else concept
return new_instances(concept, recognized_by, is_instance, is_evaluated) if return_new else concept
def new(self, concept_key, **kwargs):
"""
@@ -632,6 +673,16 @@ class Sheerka(Concept):
if hasattr(service, "reset_state"):
service.reset_state()
def add_to_context(self, concept_key):
concept_key = concept_key.name if isinstance(concept_key, Concept) else concept_key
self._global_context_hints.add(concept_key)
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
def remove_fom_context(self, concept_key):
concept_key = concept_key.name if isinstance(concept_key, Concept) else concept_key
self._global_context_hints.remove(concept_key)
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
def ret(self, who: str, status: bool, value, parents=None):
"""
Creates and returns a ReturnValue concept
+1 -1
View File
@@ -300,7 +300,7 @@ class SheerkaOntologyManager:
:param concept:
:return:
"""
return self.current_cache_manager().add_concept(concept)
return self.current_cache_manager().add_concept(concept, self.ontologies[0].alt_sdp)
def update_concept(self, old, new):
"""
+25 -33
View File
@@ -11,7 +11,7 @@ from core.sheerka.services.SheerkaHistoryManager import SheerkaHistoryManager
from core.sheerka.services.SheerkaMemory import SheerkaMemory
from core.sheerka.services.sheerka_service import BaseService
CONCEPTS_FILE_FULL = "full.sb"
CONCEPTS_FILE_FULL = "full.sb" # .sb for sheerka backup
CONCEPTS_FILE_TO_USE = CONCEPTS_FILE_FULL
@@ -22,24 +22,24 @@ class SheerkaAdmin(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self.caches_names, False)
self.sheerka.bind_service_method(self.cache, False)
self.sheerka.bind_service_method(self.restore, True)
self.sheerka.bind_service_method(self.concepts, False)
self.sheerka.bind_service_method(self.desc, False)
self.sheerka.bind_service_method(self.desc_evaluators, False)
self.sheerka.bind_service_method(self.desc_parsers, False)
self.sheerka.bind_service_method(self.extended_isinstance, False)
self.sheerka.bind_service_method(self.is_container, False)
self.sheerka.bind_service_method(self.format_rules, False)
self.sheerka.bind_service_method(self.exec_rules, False)
self.sheerka.bind_service_method(self.admin_push_ontology, True, as_name="push_ontology")
self.sheerka.bind_service_method(self.admin_pop_ontology, True, as_name="pop_ontology")
self.sheerka.bind_service_method(self.ontologies, False)
self.sheerka.bind_service_method(self.in_memory, False)
self.sheerka.bind_service_method(self.admin_history, False, as_name="history")
self.sheerka.bind_service_method(self.sdp, False)
self.sheerka.bind_service_method(self.atomic_def, False)
self.sheerka.bind_service_method(self.NAME, self.caches_names, False)
self.sheerka.bind_service_method(self.NAME, self.cache, False)
self.sheerka.bind_service_method(self.NAME, self.restore, True)
self.sheerka.bind_service_method(self.NAME, self.concepts, False)
self.sheerka.bind_service_method(self.NAME, self.builtins, False)
self.sheerka.bind_service_method(self.NAME, self.desc, False)
self.sheerka.bind_service_method(self.NAME, self.desc_evaluators, False)
self.sheerka.bind_service_method(self.NAME, self.desc_parsers, False)
self.sheerka.bind_service_method(self.NAME, self.extended_isinstance, False)
self.sheerka.bind_service_method(self.NAME, self.is_container, False)
self.sheerka.bind_service_method(self.NAME, self.format_rules, False)
self.sheerka.bind_service_method(self.NAME, self.exec_rules, False)
self.sheerka.bind_service_method(self.NAME, self.admin_push_ontology, True, as_name="push_ontology")
self.sheerka.bind_service_method(self.NAME, self.admin_pop_ontology, True, as_name="pop_ontology")
self.sheerka.bind_service_method(self.NAME, self.ontologies, False)
self.sheerka.bind_service_method(self.NAME, self.in_memory, False)
self.sheerka.bind_service_method(self.NAME, self.admin_history, False, as_name="history")
self.sheerka.bind_service_method(self.NAME, self.sdp, False)
def caches_names(self):
"""
@@ -138,9 +138,11 @@ class SheerkaAdmin(BaseService):
self.sheerka.save_execution_context = False
enable_process_return_values_previous_value = self.sheerka.enable_process_return_values
self.sheerka.enable_process_return_values = False
self.sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
nb_lines, nb_instructions, nb_lines_in_error, min_time, max_time = restore_from_file(backup_file)
self.sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
self.sheerka.enable_process_return_values = enable_process_return_values_previous_value
self.sheerka.save_execution_context = True
self.sheerka.during_restore = False
@@ -167,6 +169,10 @@ class SheerkaAdmin(BaseService):
concepts = sorted(self.sheerka.om.list(self.sheerka.CONCEPTS_BY_ID_ENTRY), key=lambda item: int(item.id))
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=concepts)
def builtins(self):
builtins = sorted(self.sheerka.sheerka_methods.values(), key=lambda builtin_method: builtin_method.name)
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=builtins)
def desc_evaluators(self):
evaluators = {k: sorted(v[0].items(), reverse=True)
for k, v in self.sheerka.services[SheerkaExecute.NAME].grouped_evaluators_cache.items()}
@@ -241,20 +247,6 @@ class SheerkaAdmin(BaseService):
return self.sheerka.isinstance(a, b)
@staticmethod
def atomic_def(a):
"""
Return the 'atomic definition' of a concept
a concept key stripped from its 'var' tokens
>>> assert atomic_def(Concept('a plus b').def_var("a").def_var("b")) == "plus"
>>> assert atomic_def(Concept('x is a y').def_var("x").def_var("y")) == "is a"
:param a:
:return:
"""
ensure_concept(a)
return a.get_atomic_def()
@staticmethod
def is_container(obj):
"""
@@ -47,12 +47,12 @@ class SheerkaComparisonManager(BaseService):
cache = Cache().auto_configure(self.RESOLVED_COMPARISON_ENTRY)
self.sheerka.om.register_cache(self.RESOLVED_COMPARISON_ENTRY, cache, persist=False)
self.sheerka.bind_service_method(self.set_is_greater_than, True)
self.sheerka.bind_service_method(self.set_is_less_than, True)
self.sheerka.bind_service_method(self.set_is_lesser, True)
self.sheerka.bind_service_method(self.set_is_greatest, True)
self.sheerka.bind_service_method(self.get_partition, False)
self.sheerka.bind_service_method(self.get_weights, False)
self.sheerka.bind_service_method(self.NAME, self.set_is_greater_than, True)
self.sheerka.bind_service_method(self.NAME, self.set_is_less_than, True)
self.sheerka.bind_service_method(self.NAME, self.set_is_lesser, True)
self.sheerka.bind_service_method(self.NAME, self.set_is_greatest, True)
self.sheerka.bind_service_method(self.NAME, self.get_partition, False)
self.sheerka.bind_service_method(self.NAME, self.get_weights, False)
@staticmethod
def _compute_key(prop_name, comparison_context):
@@ -113,26 +113,26 @@ class SheerkaConceptManager(BaseService):
self.compiled_concepts_by_regex = []
def initialize(self):
self.sheerka.bind_service_method(self.create_new_concept, True)
self.sheerka.bind_service_method(self.modify_concept, True)
self.sheerka.bind_service_method(self.remove_concept, True)
self.sheerka.bind_service_method(self.set_id_if_needed, True)
self.sheerka.bind_service_method(self.set_attr, True)
self.sheerka.bind_service_method(self.get_attr, False)
self.sheerka.bind_service_method(self.smart_get_attr, False)
self.sheerka.bind_service_method(self.set_property, True, as_name="set_prop")
self.sheerka.bind_service_method(self.get_property, False, as_name="get_prop")
self.sheerka.bind_service_method(self.get_by_key, False, visible=False)
self.sheerka.bind_service_method(self.get_by_name, False, visible=False)
self.sheerka.bind_service_method(self.get_by_hash, False, visible=False)
self.sheerka.bind_service_method(self.get_by_id, False, visible=False)
self.sheerka.bind_service_method(self.is_not_a_concept_name, False, visible=False)
self.sheerka.bind_service_method(self.is_a_concept_name, False, visible=False)
self.sheerka.bind_service_method(self.get_concepts_by_first_token, False, visible=False)
self.sheerka.bind_service_method(self.get_concepts_by_first_regex, False, visible=False)
self.sheerka.bind_service_method(self.get_concepts_bnf_definitions, False, visible=False)
self.sheerka.bind_service_method(self.clear_bnf_definition, True, visible=False)
self.sheerka.bind_service_method(self.set_precedence, True)
self.sheerka.bind_service_method(self.NAME, self.create_new_concept, True)
self.sheerka.bind_service_method(self.NAME, self.modify_concept, True)
self.sheerka.bind_service_method(self.NAME, self.remove_concept, True)
self.sheerka.bind_service_method(self.NAME, self.set_id_if_needed, True)
self.sheerka.bind_service_method(self.NAME, self.set_attr, True)
self.sheerka.bind_service_method(self.NAME, self.get_attr, False)
self.sheerka.bind_service_method(self.NAME, self.smart_get_attr, False)
self.sheerka.bind_service_method(self.NAME, self.set_property, True, as_name="set_prop")
self.sheerka.bind_service_method(self.NAME, self.get_property, False, as_name="get_prop")
self.sheerka.bind_service_method(self.NAME, self.get_by_key, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_by_name, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_by_hash, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_by_id, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.is_not_a_concept_name, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.is_a_concept_name, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_concepts_by_first_token, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_concepts_by_first_regex, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_concepts_bnf_definitions, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.clear_bnf_definition, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.set_precedence, True)
register_concept_cache = self.sheerka.om.register_concept_cache
@@ -4,7 +4,6 @@ from operator import attrgetter
from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import ensure_concept
from core.concept import Concept
from core.sheerka.Sheerka import Sheerka
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from core.sheerka.services.sheerka_service import BaseService
@@ -28,9 +27,9 @@ class SheerkaConceptsAlgebra(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self.cadd, False)
self.sheerka.bind_service_method(self.csub, False)
self.sheerka.bind_service_method(self.recognize, False)
self.sheerka.bind_service_method(self.NAME, self.cadd, False)
self.sheerka.bind_service_method(self.NAME, self.csub, False)
self.sheerka.bind_service_method(self.NAME, self.recognize, False)
def cadd(self, context, *concepts):
"""
@@ -320,22 +320,22 @@ class SheerkaDebugManager(BaseService):
}
def initialize(self):
self.sheerka.bind_service_method(self.set_debug, True)
self.sheerka.bind_service_method(self.inspect, False)
self.sheerka.bind_service_method(self.get_value, False)
self.sheerka.bind_service_method(self.get_debugger, False)
self.sheerka.bind_service_method(self.reset_debug, False)
self.sheerka.bind_service_method(self.set_debug_var, True)
self.sheerka.bind_service_method(self.set_debug_rule, True)
self.sheerka.bind_service_method(self.set_debug_concept, True)
self.sheerka.bind_service_method(self.list_debug_vars, True)
self.sheerka.bind_service_method(self.list_debug_rules, True)
self.sheerka.bind_service_method(self.list_debug_concepts, True)
self.sheerka.bind_service_method(self.register_debug_vars, True, visible=False)
self.sheerka.bind_service_method(self.register_debug_rules, True, visible=False)
self.sheerka.bind_service_method(self.register_debug_concepts, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.set_debug, True)
self.sheerka.bind_service_method(self.NAME, self.inspect, False)
self.sheerka.bind_service_method(self.NAME, self.get_value, False)
self.sheerka.bind_service_method(self.NAME, self.get_debugger, False)
self.sheerka.bind_service_method(self.NAME, self.reset_debug, False)
self.sheerka.bind_service_method(self.NAME, self.set_debug_var, True)
self.sheerka.bind_service_method(self.NAME, self.set_debug_rule, True)
self.sheerka.bind_service_method(self.NAME, self.set_debug_concept, True)
self.sheerka.bind_service_method(self.NAME, self.list_debug_vars, True)
self.sheerka.bind_service_method(self.NAME, self.list_debug_rules, True)
self.sheerka.bind_service_method(self.NAME, self.list_debug_concepts, True)
self.sheerka.bind_service_method(self.NAME, self.register_debug_vars, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.register_debug_rules, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.register_debug_concepts, True, visible=False)
# self.sheerka.bind_service_method(self.get_debug_settings, False, as_name="debug_settings")
# self.sheerka.bind_service_method(self.NAME,self.get_debug_settings, False, as_name="debug_settings")
# register what can be registered
from parsers.BnfNodeParser import BnfNodeParser
from evaluators.DefConceptEvaluator import DefConceptEvaluator
@@ -919,4 +919,3 @@ class SheerkaDebugManager(BaseService):
del res["self"]
return res
+5 -2
View File
@@ -20,8 +20,11 @@ class SheerkaDump(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self.dump_desc, True, "old_desc") # has_side_effect 'cause concept is evaluated
self.sheerka.bind_service_method(self.dump_sdp, False, "dump_sdp")
self.sheerka.bind_service_method(self.NAME,
self.dump_desc,
True,
"old_desc") # has_side_effect 'cause concept is evaluated
self.sheerka.bind_service_method(self.NAME, self.dump_sdp, False, "dump_sdp")
def dump_desc(self, *concept_names, eval=False):
first = True
@@ -46,10 +46,10 @@ class SheerkaEvaluateConcept(BaseService):
self.rule_evaluator = None
def initialize(self):
self.sheerka.bind_service_method(self.evaluate_concept, True)
self.sheerka.bind_service_method(self.call_concept, True)
self.sheerka.bind_service_method(self.call_concept, False, as_name="evaluate_question")
self.sheerka.bind_service_method(self.set_auto_eval, True)
self.sheerka.bind_service_method(self.NAME, self.evaluate_concept, True)
self.sheerka.bind_service_method(self.NAME, self.call_concept, True)
self.sheerka.bind_service_method(self.NAME, self.call_concept, False, as_name="evaluate_question")
self.sheerka.bind_service_method(self.NAME, self.set_auto_eval, True)
def initialize_deferred(self, context, is_first_time):
self.rule_evaluator = self.sheerka.services[SheerkaEvaluateRules.NAME]
@@ -499,9 +499,7 @@ class SheerkaEvaluateConcept(BaseService):
if current_prop in (ConceptParts.WHERE, ConceptParts.PRE):
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
if current_prop == ConceptParts.WHERE:
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVALUATING_PRE_OR_WHERE_CLAUSE)
# when it's a concept, evaluate it
if isinstance(to_resolve, Concept) and \
@@ -642,6 +640,9 @@ class SheerkaEvaluateConcept(BaseService):
if context.sheerka.isa(concept, context.sheerka.new(BuiltinConcepts.AUTO_EVAL)):
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
if context.in_context(BuiltinConcepts.EVALUATING_PRE_OR_WHERE_CLAUSE):
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
sub_context.add_to_short_term_memory(CURRENT_OBJ, concept)
try:
@@ -764,6 +765,13 @@ class SheerkaEvaluateConcept(BaseService):
:param kwargs:
:return:
"""
if concept.get_hints().use_copy or not concept.get_hints().is_instance:
concept = concept.copy()
concept.get_hints().use_copy = False
concept.get_hints().is_instance = True
concept.get_hints().is_evaluated = False # force evaluation
# TODO : update the variables before calling the concept
evaluated = self.evaluate_concept(context, concept)
if self.sheerka.has_error(context, evaluated):
@@ -18,8 +18,8 @@ class SheerkaEvaluateRules(BaseService):
self.network = ReteNetwork()
def initialize(self):
self.sheerka.bind_service_method(self.evaluate_format_rules, False, visible=False)
self.sheerka.bind_service_method(self.evaluate_exec_rules, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.evaluate_format_rules, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.evaluate_exec_rules, False, visible=False)
self.reset_evaluators()
self.sheerka.subscribe(EVENT_RULE_CREATED, self.on_rule_created)
self.sheerka.subscribe(EVENT_RULE_DELETED, self.on_rule_deleted)
@@ -1,4 +1,5 @@
from threading import RLock
from core.global_symbols import NotFound
from core.sheerka.services.sheerka_service import BaseService
@@ -16,8 +17,8 @@ class SheerkaEventManager(BaseService):
self.subscribers = {}
def initialize(self):
self.sheerka.bind_service_method(self.subscribe, True, visible=False)
self.sheerka.bind_service_method(self.publish, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.subscribe, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.publish, True, visible=False)
def save_state(self, context):
with self._lock:
+6 -6
View File
@@ -221,12 +221,12 @@ class SheerkaExecute(BaseService):
self.rules_eval_service = None
def initialize(self):
self.sheerka.bind_service_method(self.execute, True, visible=False)
self.sheerka.bind_service_method(self.execute_rules, True, visible=False)
self.sheerka.bind_service_method(self.parse_unrecognized, False, visible=False)
self.sheerka.bind_service_method(self.parse_function, False, visible=False)
self.sheerka.bind_service_method(self.parse_python, False, visible=False)
self.sheerka.bind_service_method(self.parse_expression, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.execute, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.execute_rules, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.parse_unrecognized, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.parse_function, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.parse_python, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.parse_expression, False, visible=False)
self.reset_registered_evaluators()
self.reset_registered_parsers()
@@ -11,8 +11,8 @@ class SheerkaHasAManager(BaseService):
super().__init__(sheerka, order=22)
def initialize(self):
self.sheerka.bind_service_method(self.set_hasa, True)
self.sheerka.bind_service_method(self.hasa, True)
self.sheerka.bind_service_method(self.NAME, self.set_hasa, True)
self.sheerka.bind_service_method(self.NAME, self.hasa, True)
def set_hasa(self, context, concept_a, concept_b):
"""
@@ -37,8 +37,13 @@ class SheerkaHasAManager(BaseService):
concept=concept_a))
merged_concepts = merge_sets(concept_a.get_prop(BuiltinConcepts.HASA), {concept_b})
if context.in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED):
to_add = {"props": {BuiltinConcepts.HASA: merged_concepts}}
return self.sheerka.modify_concept(context, concept_a, to_add, modify_source=True)
else:
concept_a.set_prop(BuiltinConcepts.HASA, merged_concepts)
return self.sheerka.ret(self.NAME, True, concept_a)
def hasa(self, concept_a, concept_b):
"""
+12 -8
View File
@@ -19,12 +19,12 @@ class SheerkaIsAManager(BaseService):
super().__init__(sheerka, order=21)
def initialize(self):
self.sheerka.bind_service_method(self.set_isa, True)
self.sheerka.bind_service_method(self.get_set_elements, True) # concepts are evaluated
self.sheerka.bind_service_method(self.add_concept_to_set, True)
self.sheerka.bind_service_method(self.isinset, False)
self.sheerka.bind_service_method(self.isa, False)
self.sheerka.bind_service_method(self.isaset, True) # concept is evaluated, need to change the code
self.sheerka.bind_service_method(self.NAME, self.set_isa, True)
self.sheerka.bind_service_method(self.NAME, self.get_set_elements, True) # concepts are evaluated
self.sheerka.bind_service_method(self.NAME, self.add_concept_to_set, True)
self.sheerka.bind_service_method(self.NAME, self.isinset, False)
self.sheerka.bind_service_method(self.NAME, self.isa, False)
self.sheerka.bind_service_method(self.NAME, self.isaset, True) # concept is evaluated, need to change the code
cache = SetCache().auto_configure(self.CONCEPTS_GROUPS_ENTRY)
self.sheerka.om.register_cache(self.CONCEPTS_GROUPS_ENTRY, cache)
@@ -53,6 +53,8 @@ class SheerkaIsAManager(BaseService):
# KSI 20200709 add the concept, not its 'id' or 'key'
# It will allow conditions handling if concept set has its WHERE or PRE set to something
new_concept_set = merge_sets(concept.get_prop(BuiltinConcepts.ISA), {concept_set})
if context.in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED):
to_add = {"props": {BuiltinConcepts.ISA: new_concept_set}}
res = self.sheerka.modify_concept(context, concept, to_add, modify_source=True)
if not res.status:
@@ -61,8 +63,10 @@ class SheerkaIsAManager(BaseService):
concept = res.body.body
res = self.add_concept_to_set(context, concept, concept_set)
return res
else:
concept.set_prop(BuiltinConcepts.ISA, new_concept_set)
return self.sheerka.ret(self.NAME, True, concept)
def add_concept_to_set(self, context, concept, concept_set):
"""
@@ -270,7 +274,7 @@ class SheerkaIsAManager(BaseService):
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
errors = []
for element_id in ids:
concept = self.sheerka.fast_resolve((None, element_id))
concept = self.sheerka.fast_resolve((None, element_id), force_instance=True)
if concept:
if len(concept.get_metadata().variables) == 0:
evaluated = self.sheerka.evaluate_concept(sub_context, concept)
+25 -14
View File
@@ -36,21 +36,23 @@ class SheerkaMemory(BaseService):
super().__init__(sheerka, order=13)
self.short_term_objects = FastCache()
self.registration = {}
self.enable_memory_registration = True
def initialize(self):
self.sheerka.bind_service_method(self.get_from_short_term_memory, False, visible=False)
self.sheerka.bind_service_method(self.get_all_short_term_memory, False, visible=False)
self.sheerka.bind_service_method(self.add_to_short_term_memory, True, visible=False)
self.sheerka.bind_service_method(self.remove_context, True, as_name="clear_short_term_memory", visible=False)
self.sheerka.bind_service_method(self.add_to_memory, True)
self.sheerka.bind_service_method(self.add_many_to_short_term_memory, True, visible=False)
self.sheerka.bind_service_method(self.get_from_memory, False)
self.sheerka.bind_service_method(self.get_last_from_memory, False)
self.sheerka.bind_service_method(self.register_object, True, visible=False)
self.sheerka.bind_service_method(self.unregister_object, True, visible=False)
self.sheerka.bind_service_method(self.commit_registered_objects, True, visible=False)
self.sheerka.bind_service_method(self.memory, False)
self.sheerka.bind_service_method(self.mem, False)
self.sheerka.bind_service_method(self.NAME, self.get_from_short_term_memory, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_all_short_term_memory, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.add_to_short_term_memory, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.remove_context, True, as_name="clear_short_term_memory",
visible=False)
self.sheerka.bind_service_method(self.NAME, self.add_to_memory, True)
self.sheerka.bind_service_method(self.NAME, self.add_many_to_short_term_memory, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_from_memory, False)
self.sheerka.bind_service_method(self.NAME, self.get_last_from_memory, False)
self.sheerka.bind_service_method(self.NAME, self.register_object, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.unregister_object, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.commit_registered_objects, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.memory, False)
self.sheerka.bind_service_method(self.NAME, self.mem, False)
cache = ListIfNeededCache().auto_configure(self.OBJECTS_ENTRY)
self.sheerka.om.register_cache(self.OBJECTS_ENTRY, cache, persist=True, use_ref=True)
@@ -187,7 +189,7 @@ class SheerkaMemory(BaseService):
:param concept:
:return:
"""
if self.sheerka.during_initialisation or self.sheerka.during_restore:
if not self.enable_memory_registration or self.sheerka.during_initialisation or self.sheerka.during_restore:
return
self.registration[key] = concept
@@ -220,6 +222,8 @@ class SheerkaMemory(BaseService):
:param name:
:return:
"""
self.enable_memory_registration = False
try:
name_to_use = name.name if isinstance(name, Concept) else name
self.unregister_object(context, name_to_use)
@@ -228,6 +232,11 @@ class SheerkaMemory(BaseService):
if obj is not NotFound:
return obj.obj
# only filter if it's a valid predicate
from parsers.BaseExpressionParser import VariableNode, NameExprNode
parsed_ret_val = self.sheerka.parse_expression(context, name_to_use, auto_compile=False)
if parsed_ret_val.status and not isinstance(parsed_ret_val.body.body, (VariableNode, NameExprNode)):
all_objects = self.sheerka.om.list(SheerkaMemory.OBJECTS_ENTRY) # not always a list of list
all_objects_copy = [] # to transform into list of list
for obj in all_objects:
@@ -253,6 +262,8 @@ class SheerkaMemory(BaseService):
return res[0] # only the first, as it should have a better timestamp
return self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"#name": name_to_use})
finally:
self.enable_memory_registration = True
def mem(self):
keys = sorted([k for k in self.sheerka.om.list(SheerkaMemory.OBJECTS_ENTRY)])
+1 -1
View File
@@ -13,7 +13,7 @@ class SheerkaOut(BaseService):
self.out_visitors = [ConsoleVisitor(expand_mode="all_but_first")]
def initialize(self):
self.sheerka.bind_service_method(self.process_return_values, False)
self.sheerka.bind_service_method(self.NAME, self.process_return_values, False)
self.sheerka.register_debug_vars("Visitor", "create_out_tree", "Exception")
self.sheerka.register_debug_vars(SheerkaOut.NAME, "create_out_tree", "out_tree")
@@ -26,13 +26,13 @@ class SheerkaQueryManager(BaseService):
self.rule_evaluator = None
def initialize(self):
self.sheerka.bind_service_method(self.filter_objects, False)
self.sheerka.bind_service_method(self.select_objects, False)
self.sheerka.bind_service_method(self.collect_attributes, False)
self.sheerka.bind_service_method(self.NAME, self.filter_objects, False)
self.sheerka.bind_service_method(self.NAME, self.select_objects, False)
self.sheerka.bind_service_method(self.NAME, self.collect_attributes, False)
self.sheerka.bind_service_method(self.filter_objects, False, as_name="pipe_where")
self.sheerka.bind_service_method(self.select_objects, False, as_name="pipe_select")
self.sheerka.bind_service_method(self.collect_attributes, False, as_name="pipe_props")
self.sheerka.bind_service_method(self.NAME, self.filter_objects, False, as_name="pipe_where")
self.sheerka.bind_service_method(self.NAME, self.select_objects, False, as_name="pipe_select")
self.sheerka.bind_service_method(self.NAME, self.collect_attributes, False, as_name="pipe_props")
self.sheerka.register_debug_vars(SheerkaQueryManager.NAME, "filter_objects", "query")
@@ -59,12 +59,13 @@ class SheerkaQueryManager(BaseService):
if k == "__type":
conditions.append(f"get_type(self) == {current_variable_name}")
elif k == "atomic_def":
conditions.append(f"atomic_def(self) == {current_variable_name}")
elif k in ("__self", "_"):
conditions.append(f"self == {current_variable_name}")
elif k.endswith("_contains"):
prop_name = k[:-9]
conditions.append(f"{current_variable_name} in self.{prop_name}")
else:
conditions.append(f"self.{k} == {current_variable_name}")
@@ -91,6 +92,7 @@ class SheerkaQueryManager(BaseService):
objects = objects.body
debugger.debug_entering(nb_objects=len(objects), predicate=predicate, **kwargs)
local_namespace = {}
query_by_kwargs = self.get_query_by_kwargs(local_namespace, **kwargs)
+1 -2
View File
@@ -1,5 +1,4 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.sheerka_service import BaseService
@@ -10,7 +9,7 @@ class SheerkaQuestion(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self.is_question, False)
self.sheerka.bind_service_method(self.NAME, self.is_question, False)
@staticmethod
def is_question(context):
@@ -31,14 +31,15 @@ class SheerkaResultManager(BaseService):
self.state_vars = ["last_created_concept_id", "last_error_event_id"]
def initialize(self):
self.sheerka.bind_service_method(self.get_results_by_digest, True) # digest is recorded
self.sheerka.bind_service_method(self.get_results_by_command, True) # digest is recorded
self.sheerka.bind_service_method(self.get_last_results, True) # digest is recorded
self.sheerka.bind_service_method(self.get_results, False)
self.sheerka.bind_service_method(self.get_execution_item, False)
self.sheerka.bind_service_method(self.get_last_return_value, False, as_name="last_ret")
self.sheerka.bind_service_method(self.get_last_created_concept, False, as_name="last_created_concept")
self.sheerka.bind_service_method(self.get_last_error, False, as_name="last_err")
self.sheerka.bind_service_method(self.NAME, self.get_results_by_digest, True) # digest is recorded
self.sheerka.bind_service_method(self.NAME, self.get_results_by_command, True) # digest is recorded
self.sheerka.bind_service_method(self.NAME, self.get_last_results, True) # digest is recorded
self.sheerka.bind_service_method(self.NAME, self.get_results, False)
self.sheerka.bind_service_method(self.NAME, self.get_execution_item, False)
self.sheerka.bind_service_method(self.NAME, self.get_last_return_value, False, as_name="last_ret")
self.sheerka.bind_service_method(self.NAME, self.get_last_created_concept, False,
as_name="last_created_concept")
self.sheerka.bind_service_method(self.NAME, self.get_last_error, False, as_name="last_err")
self.sheerka.subscribe(EVENT_USER_INPUT_EVALUATED, self.user_input_evaluated)
self.sheerka.subscribe(EVENT_CONCEPT_CREATED, self.new_concept_created)
@@ -77,6 +78,7 @@ class SheerkaResultManager(BaseService):
"""
if len(kwargs) == 0:
return None
res = []
if "filter" in kwargs:
res.append(kwargs["filter"])
@@ -90,6 +92,10 @@ class SheerkaResultManager(BaseService):
v = '"' + v.translate(str.maketrans({'"': r'\"'})) + '"'
res.append(f"{k} == {v}")
predicate = " and ".join(res)
if predicate.strip() == "":
return None
return compile(ast.parse(predicate, mode="eval"), "<SheerkaResultManager.get_predicate>", mode="eval")
@staticmethod
@@ -380,15 +386,16 @@ class SheerkaResultManager(BaseService):
folder = os.getenv(SHEERKA_BACKUP_FOLDER)
if folder is None:
print(f"{CCM['red']}Cannot backup command. Backup folder (env SHEERKA_BACKUP_FOLDER) is not defined.{CCM['reset']}")
print(
f"{CCM['red']}Cannot backup command. Backup folder (env SHEERKA_BACKUP_FOLDER) is not defined.{CCM['reset']}")
return
file = os.getenv(SHEERKA_BACKUP_FILE)
if file is None:
print(f"{CCM['red']}Cannot backup command. Backup file (env SHEERKA_BACKUP_FILE) is not defined.{CCM['reset']}")
print(
f"{CCM['red']}Cannot backup command. Backup file (env SHEERKA_BACKUP_FILE) is not defined.{CCM['reset']}")
return
full_path = os.path.join(folder, file)
with open(full_path, "a") as f:
f.write(f"{execution_context.event.message}\n")
@@ -82,13 +82,13 @@ class SheerkaRuleManager(BaseService):
self.expression_parser = LogicalOperatorParser()
def initialize(self):
self.sheerka.bind_service_method(self.create_new_rule, True, visible=False)
self.sheerka.bind_service_method(self.remove_rule, True)
self.sheerka.bind_service_method(self.get_rule_by_id, False)
self.sheerka.bind_service_method(self.get_rule_by_name, False)
self.sheerka.bind_service_method(self.get_format_rules, False, visible=False)
self.sheerka.bind_service_method(self.get_exec_rules, False, visible=False)
self.sheerka.bind_service_method(self.resolve_rule, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.create_new_rule, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.remove_rule, True)
self.sheerka.bind_service_method(self.NAME, self.get_rule_by_id, False)
self.sheerka.bind_service_method(self.NAME, self.get_rule_by_name, False)
self.sheerka.bind_service_method(self.NAME, self.get_format_rules, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.get_exec_rules, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.resolve_rule, False, visible=False)
cache = Cache().auto_configure(self.FORMAT_RULE_ENTRY)
self.sheerka.om.register_cache(self.FORMAT_RULE_ENTRY, cache, True, True)
@@ -53,14 +53,14 @@ class SheerkaVariableManager(BaseService):
}
def initialize(self):
self.sheerka.bind_service_method(self.record_var, True, visible=False)
self.sheerka.bind_service_method(self.load_var, False, visible=False)
self.sheerka.bind_service_method(self.record_internal_var, True, visible=False)
self.sheerka.bind_service_method(self.load_internal_var, False, visible=False)
self.sheerka.bind_service_method(self.delete_var, True, visible=False)
self.sheerka.bind_service_method(self.set_var, True)
self.sheerka.bind_service_method(self.get_var, False)
self.sheerka.bind_service_method(self.list_vars, False)
self.sheerka.bind_service_method(self.NAME, self.record_var, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.load_var, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.record_internal_var, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.load_internal_var, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.delete_var, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.set_var, True)
self.sheerka.bind_service_method(self.NAME, self.get_var, False)
self.sheerka.bind_service_method(self.NAME, self.list_vars, False)
cache = Cache().auto_configure(self.VARIABLES_ENTRY)
self.sheerka.om.register_cache(self.VARIABLES_ENTRY, cache, True, True)
+46 -8
View File
@@ -327,6 +327,12 @@ def merge_dictionaries(a, b):
def merge_sets(a, b):
"""
Merge that can handle None
:param a:
:param b:
:return:
"""
if a is None and b is None:
return None
@@ -494,7 +500,7 @@ def unstr_concept(concept_repr, prefix='c:'):
"""
if concept_repr is like :c:key:id:
return the key and the id
>>> assert unstr_concept("c:key:") == "key"
>>> assert unstr_concept("c:key:") == ("key", None)
>>> assert unstr_concept("c:key|id:") == ("key", "id")
>>> assert unstr_concept("c:|id:") == ("None", "id")
>>> assert unstr_concept("c:key|:") == ("key", "None")
@@ -515,28 +521,30 @@ def unstr_concept(concept_repr, prefix='c:'):
key = ""
while i < length:
c = concept_repr[i]
i += 1
if c in (":", "|"):
break
key += c
i += 1
else:
return None, None
if c == ":":
return key if key != "" else None, None
return key if key != "" and i == length else None, None
i += 1
id = ""
c_id = ""
while i < length:
c = concept_repr[i]
i += 1
if c == ":":
break
id += c
i += 1
c_id += c
else:
return None, None
return key if key != "" else None, id if id != "" else None
if i != length:
return None, None
return key if key != "" else None, c_id if c_id != "" else None
def encode_concept(t, wrapper="C"):
@@ -682,6 +690,36 @@ def flatten(list_of_lists):
return functools.reduce(operator.iconcat, list_of_lists, [])
def replace_after(lst: list, start_item, new_items: list):
"""
given a list 'lst', replace all items (starting with 'item') with the new_items
>>> my_new_items =["alpha", "beta", "gamma"]
>>>
>>> my_list1 = ["a", "b", "c", "d"]
>>> replace_after(my_list1, "c", new_items)
>>> assert my_list1 == ["a", "b", "alpha", "beta", "gamma"]
>>>
>>> my_list2 = ["a", "b", "c", "d"]
>>> replace_after(my_list2, "a", new_items)
>>> assert my_list2 == ["alpha", "beta", "gamma"]
>>> # replace_after(lst, "x", new_items) raises a KeyError
:param lst:
:param start_item:
:param new_items:
:return:
"""
for i, current in enumerate(lst):
if current == start_item:
break
else:
raise KeyError(start_item)
del lst[i:]
lst.extend(new_items)
return lst
def get_text_from_tokens(tokens, custom_switcher=None, tracker=None):
"""
Create the source code, from the list of token
+1 -1
View File
@@ -30,7 +30,7 @@ class ExpressionEvaluator(OneReturnValueEvaluator):
success = False
with context.push(BuiltinConcepts.EXEC_CODE, return_value.value.value.source) as sub_context:
# sub condition is created only to add a namespace
# sub_context is created only to add a namespace
requested_vars = set()
for c in conditions:
@@ -0,0 +1,49 @@
from core.builtin_concepts import BuiltinConcepts
from evaluators.BaseEvaluator import OneReturnValueEvaluator
class PrepareEvalGlobalTruthEvaluator(OneReturnValueEvaluator):
"""
To recognize when the user input is a global truth
"""
NAME = "PrepareEvalGlobalTruth"
def __init__(self, **kwargs):
super().__init__(self.NAME, [BuiltinConcepts.BEFORE_PARSING], 90)
self.inner_text = None
def reset(self):
self.inner_text = None
def matches(self, context, return_value):
if not (return_value.status and
context.sheerka.isinstance(return_value.body, BuiltinConcepts.USER_INPUT) and
isinstance(return_value.body.body, str)):
return False
text = return_value.body.body.strip()
if not (text.startswith("global_truth(") and text.endswith(")")):
return False
self.inner_text = text[13:-1].strip()
if self.inner_text == "":
return False
return True
def eval(self, context, return_value):
sheerka = context.sheerka
new_text_to_parse = sheerka.ret(
self.name,
True, sheerka.new(BuiltinConcepts.USER_INPUT, body=self.inner_text, user_name=context.event.user_id))
root = context.get_parents(lambda ec: ec.action in (BuiltinConcepts.EVALUATING_CONCEPT,
BuiltinConcepts.PROCESS_INPUT))
root = root[0] if root else context
root.add_to_protected_hints(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
root.add_to_protected_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
root.add_to_protected_hints(BuiltinConcepts.RETURN_BODY_REQUESTED)
return new_text_to_parse
+28 -6
View File
@@ -2,6 +2,7 @@ from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import resolve_ambiguity
from core.concept import Concept
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
from parsers.BaseNodeParser import ConceptNode
class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
@@ -24,10 +25,12 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
# If they share the same source, that means that there are multiple results for one ParserInput
self.sources = {}
success = False
for ret in [ret for ret in return_values if ret.status]:
for ret in [ret for ret in return_values if
ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.PARSER_RESULT)]:
source = self.get_source(context, ret)
concept_is_instance = self.get_has_concept_instance(ret)
if source:
if source and concept_is_instance:
self.sources.setdefault(source, []).append(ret)
if len(self.sources[source]) > 1:
@@ -39,17 +42,26 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
ret = []
for ret_vals in self.sources.values():
parser_results = {id(r.body.body): r.body for r in ret_vals}
resolved = resolve_ambiguity(context, [r.body.body for r in ret_vals])
presults_concepts_map = {id(self.get_concept(r)): r.body for r in ret_vals}
resolved = resolve_ambiguity(context, [self.get_concept(r) for r in ret_vals])
if len(resolved) == 0:
ret.append(context.sheerka.ret(self.name, True, BuiltinConcepts.NO_RESULT, parents=ret_vals))
else:
if len(resolved) < len(ret_vals):
for c in resolved:
ret.append(context.sheerka.ret(self.name, True, parser_results[id(c)], parents=ret_vals))
ret.append(context.sheerka.ret(self.name, True, presults_concepts_map[id(c)], parents=ret_vals))
return None if len(ret) == 0 else ret
@staticmethod
def get_concept(return_value):
if isinstance(return_value.body.body, Concept):
return return_value.body.body
elif isinstance(return_value.body.body, list) and isinstance(return_value.body.body[0], ConceptNode):
return return_value.body.body[0].concept
return None
@staticmethod
def get_source(context, return_value):
"""
@@ -60,6 +72,16 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
:return:
"""
if context.sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT) and \
isinstance(return_value.body.body, Concept):
(isinstance(return_value.body.body, Concept) or
(isinstance(return_value.body.body, list) and
len(return_value.body.body) == 1) and
isinstance(return_value.body.body[0], ConceptNode)):
return return_value.body.source
return None
def get_has_concept_instance(self, return_value):
concept = self.get_concept(return_value)
if concept is None:
return False
return concept.get_hints().is_instance
+6 -3
View File
@@ -7,7 +7,7 @@ from parsers.BaseParser import BaseParser
class ValidateConceptEvaluator(OneReturnValueEvaluator):
"""
To recognize when the user input is a question
Filter the concept that does not meet its pre and where conditions
"""
NAME = "ValidateConcept"
@@ -40,9 +40,12 @@ class ValidateConceptEvaluator(OneReturnValueEvaluator):
def eval(self, context, return_value):
"""
This evaluator returns None is the concept validates its PRE and POST constraint or if the constraint cannot
be validated
This evaluator returns None if
* the constraint cannot be validated
* the concept is already a copy and it validates its PRE and POST constraint
If the constraint can be validated, but fails, an error is returned
If concept was not a copy and the constraint is validated, an evaluated copy is returned
:param context:
:param return_value:
:return:
+70 -1
View File
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from itertools import product
from typing import List, Union
from core.builtin_concepts_ids import BuiltinConcepts
@@ -453,7 +454,7 @@ class BaseExpressionParser(BaseParser):
return ret
def parse_input(self, context, parser_input, error_sink):
def parse_input(self, context, parser_input: ParserInput, error_sink: list):
raise NotImplementedError
def parse_tokens_stop_condition(self, token, parser_input):
@@ -666,3 +667,71 @@ class IsAQuestionVisitor(ExpressionVisitor):
def is_a_question(self, expr_node):
res = self.visit(expr_node)
return isinstance(res, bool) and res
def compile_disjunctions(expr_node, nest: bool = True):
def get_start_end(items):
start, end = None, None
for item in items:
if start is None or item.start < start:
start = item.start
if end is None or item.end > end:
end = item.end
return start, end
def _compile_disjunctions(node, _nest: bool = True):
if isinstance(node, OrNode):
inner = []
for part in node.parts:
result = _compile_disjunctions(part, _nest=False)
if isinstance(result, tuple):
inner.extend(result)
else:
inner.append(result)
return tuple(inner)
elif isinstance(node, AndNode):
inner = []
for ele in node.parts:
if isinstance(ele, NotNode):
t = _compile_disjunctions(ele),
inner.append(t)
else:
inner.append(_compile_disjunctions(ele))
temp_res = tuple(product(*inner))
all_conjunctions = []
for conjunctions in temp_res:
# first transform 'a and (b and c)' into 'a and b and c'
conjunctions_to_use = []
for item in conjunctions:
if isinstance(item, tuple) and isinstance(item[0], AndNode):
conjunctions_to_use.extend(item[0].parts)
elif isinstance(item, AndNode):
conjunctions_to_use.extend(item.parts)
else:
conjunctions_to_use.append(item)
start, end = get_start_end(conjunctions_to_use)
all_conjunctions.append(AndNode(start, end, expr_node.tokens[start: end + 1], *conjunctions_to_use))
return tuple(all_conjunctions)
elif isinstance(node, NotNode):
inner = _compile_disjunctions(node.node)
if len(inner) == 1:
return node, # do not remove the comma, it's a tuple
temp_res = tuple(NotNode(branch.start, branch.end, [], branch) for branch in inner)
start, end = get_start_end(temp_res)
conjunction = AndNode(start, end, expr_node.tokens[start: end + 1], *temp_res)
return conjunction, # do not remove the comma, it's a tuple
elif _nest:
return node, # do not remove the comma, it's a tuple
else:
return node
return list(_compile_disjunctions(expr_node, nest))
+6
View File
@@ -224,8 +224,14 @@ class ConceptNode(LexerNode):
return f'CN({self.concept})'
def get_concept(self):
"""
Used when there is a mix of Concept and ConceptNode
To quickly get the inner concept
:return:
"""
return self.concept
class SourceCodeNode(LexerNode):
"""
Returned when some source code (like Python source code is recognized)
-20
View File
@@ -250,23 +250,3 @@ class BaseParserInputParser(BaseParser):
end -= 1
return start, end
@staticmethod
def merge_concepts(list_a, b):
if not b:
return list_a
list_b = b if isinstance(b, list) else [b]
if not list_a:
return list_b
by_ids = {c.id for c in list_b}
for c in list_b:
if c.id in by_ids: # and c.metadata.is_evaluated == by_ids[c.id].metadata.is_evaluated:
continue
list_a.append(c)
by_ids.add(c.id)
return list_a
+1 -1
View File
@@ -52,7 +52,7 @@ class RegExDef:
return flags
def serialize(self):
return f"{self.to_match}__!##ZZSEPZZ##!__{self.ignore_case}|{self.multiline}|{self.explicit_flags}"
return f"{self.to_match}__!##ZZSEPZZ##!__{self.ignore_case}|{self.multiline}|{int(self.explicit_flags)}"
def deserialize(self, txt):
parts = txt.split("__!##ZZSEPZZ##!__")
+37 -1
View File
@@ -1,6 +1,7 @@
import core.builtin_helpers
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import VARIABLE_PREFIX
from core.sheerka.Sheerka import RECOGNIZED_BY_KEY
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import TokenKind
from core.utils import str_concept
@@ -43,6 +44,7 @@ class ExactConceptParser(BaseParserInputParser):
body = sheerka.new(BuiltinConcepts.NOT_FOR_ME, body=parser_input.as_text(), reason=too_long)
return sheerka.ret(self.name, False, body)
# First, get the concept using there keys
already_recognized = [] # keep track of the concepts founds
for combination in self.combinations(words):
@@ -75,11 +77,19 @@ class ExactConceptParser(BaseParserInputParser):
value = words[i]
concept.def_var_by_index(index, str_concept(value) if isinstance(value, tuple) else value)
concept.get_hints().need_validation = True
concept.get_hints().recognized_by = RECOGNIZED_BY_KEY
already_recognized.append(concept)
# Also try to recognize concepts by their names
by_name = sheerka.fast_resolve(parser_input.as_text())
core.builtin_helpers.set_is_evaluated(by_name)
if by_name:
core.builtin_helpers.update_concepts_hints(by_name,
# recognized_by=RECOGNIZED_BY_NAME, # keep fast_resolve settings
is_instance=False,
is_evaluated=True)
# merge the two
recognized = self.merge_concepts(already_recognized, by_name)
for c in recognized:
c.get_hints().use_copy = True
@@ -169,6 +179,32 @@ class ExactConceptParser(BaseParserInputParser):
res.append(vars[value] if value in vars else value)
return tuple(res)
@staticmethod
def merge_concepts(concepts_by_key, concepts_by_name):
"""
Merge concepts when the id is the same and there is no variable
:param concepts_by_key:
:param concepts_by_name:
:return:
"""
if not concepts_by_name:
return concepts_by_key
concepts_by_name = concepts_by_name if isinstance(concepts_by_name, list) else [concepts_by_name]
if not concepts_by_key:
return concepts_by_name
by_ids = {c.id for c in concepts_by_key}
for c in concepts_by_name:
if c.id in by_ids:
continue # keep the 'by_key' version to allow evaluation
concepts_by_key.append(c)
by_ids.add(c.id)
return concepts_by_key
def as_return_value(self, context, parser_input, concept):
return ReturnValueConcept(
self.name,
+14 -4
View File
@@ -2,6 +2,7 @@ from dataclasses import dataclass
from core import builtin_helpers
from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import update_concepts_hints
from core.concept import DEFINITION_TYPE_BNF, Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer, TokenKind
@@ -230,7 +231,8 @@ class SequenceNodeParser(BaseNodeParser):
:param concept:
:return:
"""
return len(concept.get_metadata().variables) == 0 and concept.get_metadata().definition_type != DEFINITION_TYPE_BNF
return len(concept.get_metadata().variables) == 0 \
and concept.get_metadata().definition_type != DEFINITION_TYPE_BNF
def get_concepts(self, token, to_keep, custom=None, to_map=None, strip_quotes=False):
@@ -245,11 +247,11 @@ class SequenceNodeParser(BaseNodeParser):
def as_list(a):
if a is None:
return a
return None
return a if isinstance(a, list) else [a]
concepts_by_name = as_list(self.sheerka.resolve(token))
concepts_by_name = as_list(self.sheerka.fast_resolve(token))
concepts_by_first_keyword = new_instances(self.sheerka.get_concepts_by_first_token(token, self._is_eligible))
if concepts_by_name is None:
@@ -339,11 +341,17 @@ class SequenceNodeParser(BaseNodeParser):
It will use the name of the concept, but also its compact form (c::)
:return:
"""
source = self.parser_input.as_text()
concepts = self.sheerka.resolve(source.strip())
concepts = self.sheerka.fast_resolve(source.strip())
if concepts is None:
return None
update_concepts_hints(concepts,
# recognized_by=RECOGNIZED_BY_NAME, # keep fast_resolve settings
is_instance=False,
is_evaluated=True)
concepts = [concepts] if isinstance(concepts, Concept) else concepts
res = []
start, end = self.get_tokens_boundaries(self.parser_input.as_tokens())
@@ -414,6 +422,8 @@ class SequenceNodeParser(BaseNodeParser):
sequences = self.get_concepts_sequences()
if by_name := self.get_by_name():
# note that concepts by names must be appended, not prepended
# In case of conflict, we want to keep the one found by get_concepts_sequences()
sequences.extend(by_name)
parser_helpers = self.get_valid(sequences)
+80 -4
View File
@@ -11,7 +11,7 @@ from core.global_symbols import CONCEPT_COMPARISON_CONTEXT, SyaAssociativity
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Token, TokenKind, Tokenizer
from core.utils import get_n_clones, get_text_from_tokens, NextIdManager
from core.utils import get_n_clones, get_text_from_tokens, NextIdManager, replace_after
from parsers.BaseNodeParser import UnrecognizedTokensNode, ConceptNode, SourceCodeNode, \
SourceCodeWithConceptNode, BaseNodeParser, VariableNode
from parsers.BaseParser import ParsingError
@@ -185,6 +185,19 @@ class SyaConceptParserHelper:
if token.type != TokenKind.WHITESPACE:
self.expected_parameters_before_first_token += 1
# remove useless whitespaces (spaces that are between VAR_DEF)
if len(self.expected) > 2:
temp = [self.expected[0]]
for i in range(1, len(self.expected) - 1):
token = self.expected[i]
if (token.type == TokenKind.WHITESPACE and
self.expected[i - 1].type == TokenKind.VAR_DEF and
self.expected[i + 1].type == TokenKind.VAR_DEF):
continue # skip it
temp.append(token)
temp.append(self.expected[-1])
self.expected = temp
self.eat_token(first_keyword_found) # remove the first token
self.tokens.append(first_keyword_found)
@@ -496,10 +509,19 @@ class InFixToPostFix:
:return:
"""
if len(self.parameters_list) < parser_helper.expected_parameters_before_first_token:
# There is not enough parameters to fill the new concept
# Try to develop the UnrecognizedTokesNode, to see if it can match
developed_param_list = self.develop_parameter_list(self.parameters_list)
if len(developed_param_list) < parser_helper.expected_parameters_before_first_token:
# The new concept expect some prefix parameters, but there's not enough
parser_helper.error = "Not enough prefix parameters"
return
# the developed_param_list does the job. Let's replace the previous values
pivot = self.parameters_list[0]
replace_after(self.parameters_list, pivot, developed_param_list)
replace_after(self.out, pivot, developed_param_list)
if len(self.parameters_list) > parser_helper.expected_parameters_before_first_token:
# There are more parameters than needed by the new concept
# These others parameters are either
@@ -530,6 +552,20 @@ class InFixToPostFix:
:return:
"""
def nb_expected_parameters(expected):
"""
Count the number of successive variables that are expected
:param expected:
:return:
"""
i = 0
for token in expected:
if token.type == TokenKind.VAR_DEF:
i += 1
else:
break
return i
# manage parenthesis that didn't find any match
if self._is_lpar(self.stack[-1]):
self._add_error(ParenthesisMismatchError(self.stack[-1]))
@@ -538,6 +574,16 @@ class InFixToPostFix:
assert len(self._concepts()) != 0 # sanity check
current_concept = self._concepts()[-1]
if (nb_expected := nb_expected_parameters(current_concept.expected)) > len(self.parameters_list):
# There is not enough parameters in the list to fill the concept
# Try to develop the UnrecognizedTokensNode to see if it can match
developed_param_list = self.develop_parameter_list(self.parameters_list)
if nb_expected == len(developed_param_list):
pivot = self.parameters_list[0]
replace_after(self.parameters_list, pivot, developed_param_list)
replace_after(self.out, pivot, developed_param_list)
while len(current_concept.expected) > 0 and current_concept.expected[0].type == TokenKind.VAR_DEF:
# eat everything that was expected
if len(self.parameters_list) == 0:
@@ -640,13 +686,24 @@ class InFixToPostFix:
Helper function that pops the stack and put the item to the output, if needed
:return:
"""
item = self.stack[-1]
# fix the concept is needed
if isinstance(item, SyaConceptParserHelper):
if len(item.expected) > 0:
# make sure the expected parameters of this item are eaten
if 0 < len(item.expected) <= len(self.parameters_list):
if len(item.expected) <= len(self.parameters_list):
self.manage_parameters()
else:
# second chance to match the parameter list when it contains unrecognized token
developed_param_list = self.develop_parameter_list(self.parameters_list)
if len(item.expected) <= len(developed_param_list):
pivot = self.parameters_list[0]
replace_after(self.parameters_list, pivot, developed_param_list)
replace_after(self.out, pivot, developed_param_list)
self.manage_parameters()
item.fix_concept()
self.stack.pop()
@@ -1119,6 +1176,25 @@ class InFixToPostFix:
# clone.forked = self.forked
return clone
@staticmethod
def develop_parameter_list(parameter_list):
"""
given a list of parameter (solely from self.parameter_list)
develop UnrecognizedTokensNode parameter that contains whitespaces
:param parameter_list:
:return:
"""
temp = []
for parameter in parameter_list:
if isinstance(parameter, UnrecognizedTokensNode):
for i, token in [(i, t) for i, t in enumerate(parameter.tokens) if t.type != TokenKind.WHITESPACE]:
temp.append(UnrecognizedTokensNode(parameter.start + i,
parameter.start + i,
[token]))
else:
temp.append(parameter)
return temp
@dataclass()
class PostFixToItem:
@@ -1428,8 +1504,8 @@ class SyaNodeParser(BaseNodeParser):
def _has_sya(items):
for item in items:
if isinstance(item, SourceCodeWithConceptNode):
if _has_sya(item.nodes):
return True
return _has_sya(item.nodes)
if isinstance(item, SyaConceptParserHelper):
return True
return False
+2
View File
@@ -41,6 +41,8 @@ class SheerkaPickler:
self.to_reduce.append(ToReduce(lambda o: isinstance(o, (BaseParser, BaseEvaluator)), lambda o: o.name))
self.to_reduce.append(ToReduce(lambda o: isinstance(o, ParserInput), lambda o: o.as_text()))
self.to_reduce.append(ToReduce(lambda o: isinstance(o, Ontology), lambda o: o.name))
from core.sheerka.Sheerka import SheerkaMethod
self.to_reduce.append(ToReduce(lambda o: isinstance(o, SheerkaMethod), lambda o: o.name))
def flatten(self, obj):
if utils.is_to_discard(obj):
+1 -1
View File
@@ -155,7 +155,7 @@ def resolve_object(context, who, obj):
raise Exception()
if (isinstance(obj, str) and obj.startswith("c:")) or isinstance(obj, Token):
concept = context.sheerka.fast_resolve(obj)
concept = context.sheerka.fast_resolve(obj, force_instance=True)
if concept is None:
return None
+19 -5
View File
@@ -104,7 +104,7 @@ class BaseTest:
def get_sheerka(self, **kwargs) -> Sheerka:
pass
def get_context(self, sheerka=None, eval_body=False, eval_where=False, message=""):
def get_context(self, sheerka=None, eval_body=False, eval_where=False, global_truth=False, message=""):
context = ExecutionContext("test",
Event(message=message),
sheerka or self.get_sheerka(),
@@ -114,20 +114,29 @@ class BaseTest:
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
if eval_where:
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
if global_truth:
context.protected_hints.add(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
return context
@staticmethod
def get_init_test_args(**kwargs):
return {k: v for k, v in kwargs.items() if k in ["cache_only", "ontology", "eval_body", "eval_where"]}
return {k: v for k, v in kwargs.items() if k in ["cache_only",
"ontology",
"eval_body",
"eval_where",
"global_truth"]}
@staticmethod
def get_with_concepts_args(**kwargs):
return {k: v for k, v in kwargs.items() if k in ["create_new"]}
def init_test(self, cache_only=None, ontology=None, eval_body=False, eval_where=False):
def init_test(self, cache_only=None, ontology=None, eval_body=False, eval_where=False, global_truth=False):
sheerka = self.get_sheerka(cache_only=cache_only, ontology=ontology)
context = self.get_context(sheerka=sheerka, eval_body=eval_body, eval_where=eval_where)
context = self.get_context(sheerka=sheerka,
eval_body=eval_body,
eval_where=eval_where,
global_truth=global_truth)
return InitTestHelper(sheerka, context)
@@ -255,14 +264,19 @@ class BaseTest:
concept.get_metadata().variables[k] = v
return concept
def init_scenario(self, init_expressions):
def init_scenario(self, init_expressions, global_truth=False):
sheerka = self.get_sheerka()
if global_truth:
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
for expression in init_expressions:
res = sheerka.evaluate_user_input(expression)
assert len(res) == 1, f"Failed to execute '{expression}'"
assert res[0].status, f"Error while executing '{expression}'"
if global_truth:
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
return sheerka
@staticmethod
+20 -16
View File
@@ -7,9 +7,9 @@ from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
def test_i_can_add_concepts(self):
sheerka, context, man, human, male, driver, licence, car = self.init_concepts(
sheerka, context, man, human, male, driver, licence, car = self.init_test(global_truth=True).with_concepts(
"man", "human", "male",
"driver", "licence", "car")
"driver", "licence", "car").unpack()
sheerka.set_isa(context, sheerka.new("man"), human)
sheerka.set_isa(context, sheerka.new("man"), male)
@@ -23,8 +23,8 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
BuiltinConcepts.HASA: {car, licence}, }
def test_can_add_concepts_when_property_already_exist(self):
sheerka, context, man, human, king, male = self.init_concepts(
"man", "human", "king", "male")
sheerka, context, man, human, king, male = self.init_test(global_truth=True).with_concepts(
"man", "human", "king", "male").unpack()
sheerka.set_isa(context, sheerka.new("man"), human)
sheerka.set_isa(context, sheerka.new("king"), male)
@@ -35,9 +35,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
assert res.get_metadata().props == {BuiltinConcepts.ISA: {male, human}}
def test_i_can_subtract_concepts(self):
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_concepts(
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_test(global_truth=True).with_concepts(
"foo", "bar",
"isa1", "isa2", "has1", "has2")
"isa1", "isa2", "has1", "has2").unpack()
new_foo = sheerka.new("foo")
sheerka.set_isa(context, new_foo, isa1)
@@ -61,9 +61,10 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
BuiltinConcepts.HASA: {hasa2}, }
def test_i_can_recognize_myself_when_using_sdp_repository(self):
sheerka, context, foo, isa1, hasa1, = self.init_test(cache_only=False). \
with_concepts("foo", "isa1", "has1", create_new=True). \
unpack()
sheerka, context, foo, isa1, hasa1, = self.init_test(cache_only=False, global_truth=True).with_concepts(
"foo",
"isa1",
"has1", create_new=True).unpack()
sheerka.om.commit(context)
new_foo = sheerka.new("foo")
@@ -74,7 +75,10 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
assert sheerka.recognize(new_foo, all_scores=True) == [ConceptScore(1, new_foo, new_foo)]
def test_i_can_recognize_myself_when_not_using_sdp_repository(self):
sheerka, context, foo, isa1, hasa1, = self.init_concepts("foo", "isa1", "has1")
sheerka, context, foo, isa1, hasa1, = self.init_test(global_truth=True).with_concepts(
"foo",
"isa1",
"has1").unpack()
new_foo = sheerka.new("foo")
sheerka.set_isa(context, new_foo, isa1)
@@ -100,9 +104,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
assert sheerka.recognize(Concept(), all_scores=True) == []
def test_i_can_recognize_multiple_concepts_with_the_proper_score(self):
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_concepts(
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_test(global_truth=True).with_concepts(
"foo", "bar",
"isa1", "isa2", "has1", "has2")
"isa1", "isa2", "has1", "has2").unpack()
new_foo = sheerka.new("foo")
sheerka.set_isa(context, new_foo, isa1)
@@ -131,9 +135,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
ConceptScore(0.5, sheerka.new("bar"), to_recognize)]
def test_i_can_recognize_if_all_scores_is_disabled(self):
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_concepts(
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_test(global_truth=True).with_concepts(
"foo", "bar",
"isa1", "isa2", "has1", "has2")
"isa1", "isa2", "has1", "has2").unpack()
new_foo = sheerka.new("foo")
sheerka.set_isa(context, new_foo, isa1)
@@ -153,9 +157,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
assert res == ConceptScore(1.0, sheerka.new("bar"), to_recognize)
def test_i_can_recognize_if_all_scores_is_disabled_but_multiple_high_scores(self):
sheerka, context, foo, bar, isa1, hasa1 = self.init_concepts(
sheerka, context, foo, bar, isa1, hasa1 = self.init_test(global_truth=True).with_concepts(
"foo", "bar",
"isa1", "has1")
"isa1", "has1").unpack()
new_foo = sheerka.new("foo")
sheerka.set_isa(context, new_foo, isa1)
+12 -10
View File
@@ -1105,13 +1105,14 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
Concept("hundreds", definition="number hundred"),
)
sheerka.set_isa(context, sheerka.new("one"), number)
sheerka.set_isa(context, sheerka.new("two"), number)
sheerka.set_isa(context, sheerka.new("twenty"), number)
sheerka.set_isa(context, sheerka.new("thirty"), number)
sheerka.set_isa(context, sheerka.new("hundred"), number)
sheerka.set_isa(context, sheerka.new("twenties"), number)
sheerka.set_isa(context, sheerka.new("hundreds"), number)
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, sheerka.new("one"), number)
sheerka.set_isa(global_truth_context, sheerka.new("two"), number)
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), number)
sheerka.set_isa(global_truth_context, sheerka.new("thirty"), number)
sheerka.set_isa(global_truth_context, sheerka.new("hundred"), number)
sheerka.set_isa(global_truth_context, sheerka.new("twenties"), number)
sheerka.set_isa(global_truth_context, sheerka.new("hundreds"), number)
sheerka.clear_bnf_definition() # reset all the grammar to simulate Sheerka restart
@@ -1129,12 +1130,12 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
}
def test_i_can_resolve_when_concepts_have_multiple_levels_of_sets(self):
sheerka, context, adjective, color, red, qualified_table = self.init_concepts(
sheerka, context, adjective, color, red, qualified_table = self.init_test(global_truth=True).with_concepts(
"adjective",
"color",
"red",
Concept("qualified table", definition="adjective 'table'"),
)
).unpack()
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
@@ -1404,7 +1405,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
def test_i_cannot_smart_get_attr_when_attribute_does_not_exist(self):
sheerka, context, adjective, color, red, size, table = self.init_concepts("adjective",
"color",
Concept("red", body="red").auto_init(),
Concept("red",
body="red").auto_init(),
"size",
"table",
create_new=True)
+3 -3
View File
@@ -391,8 +391,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
:return:
"""
sheerka, context, predicate, foo = self.init_concepts(
Concept("Sometimes True", body="in_context('a')"),
Concept("foo", pre="c:Sometimes True:"))
Concept("Sometimes True", body="in_context('a')", pre="is_question()"),
Concept("foo", pre="Sometimes True"))
foo1 = sheerka.new("foo")
foo1 = sheerka.evaluate_concept(context, foo1) # 'a' is not in context, so it fails
@@ -400,7 +400,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
context2 = self.get_context(sheerka)
context2.add_to_protected_hints('a')
foo2 = sheerka.new("foo")
foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' in context + new instance of 'Sometimes True'
foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' is now in context
assert sheerka.isinstance(foo1, BuiltinConcepts.CONDITION_FAILED)
assert sheerka.isinstance(foo2, "foo")
+31 -2
View File
@@ -7,6 +7,33 @@ class TestSheerkaHasAManager(TestUsingMemoryBasedSheerka):
def test_i_can_set_hasa(self):
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
king_instance = sheerka.new("king")
res = sheerka.set_hasa(context, king_instance, kingdom)
assert res.status
# when global truth is not activated, only the current instance is modified
another_king = sheerka.get_by_key("king")
assert not another_king.get_prop(BuiltinConcepts.HASA) == {kingdom}
assert not sheerka.hasa(another_king, kingdom)
def test_i_cannot_set_the_same_attribute_twice(self):
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
king_instance = sheerka.new("king")
sheerka.set_hasa(context, king_instance, kingdom)
res = sheerka.set_hasa(context, king_instance, kingdom)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.PROPERTY_ALREADY_DEFINED)
assert res.body.property_name == BuiltinConcepts.HASA
assert res.body.property_value == kingdom
assert res.body.concept == king_instance
def test_i_can_set_hasa_when_global_truth_is_activated(self):
sheerka, context, king, kingdom = self.init_test(global_truth=True).with_concepts(
"king",
"kingdom").unpack()
res = sheerka.set_hasa(context, sheerka.new("king"), kingdom)
assert res.status
@@ -16,8 +43,10 @@ class TestSheerkaHasAManager(TestUsingMemoryBasedSheerka):
# check that the definition of the concept has been updated
assert sheerka.hasa(sheerka.new("king"), kingdom)
def test_i_cannot_set_the_same_attribute_twice(self):
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
def test_i_cannot_set_the_same_attribute_twice_when_global_truth_is_activated(self):
sheerka, context, king, kingdom = self.init_test(global_truth=True).with_concepts(
"king",
"kingdom").unpack()
sheerka.set_hasa(context, sheerka.new("king"), kingdom)
res = sheerka.set_hasa(context, sheerka.new("king"), kingdom)
+78 -10
View File
@@ -86,15 +86,46 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
def test_isa(self):
sheerka, context, blue, color = self.init_concepts(Concept("blue"), Concept("color"))
assert not sheerka.isa(blue, color)
sheerka.set_isa(context, blue, color)
assert sheerka.isa(blue, color)
blue_instance = sheerka.new("blue")
assert not sheerka.isa(blue_instance, color)
sheerka.set_isa(context, blue_instance, color)
assert sheerka.isa(blue_instance, color)
# isa tests the id of a concept, not it's content
another_color_instance_but_with_a_body = sheerka.new(color, body="a body")
assert sheerka.isa(blue, another_color_instance_but_with_a_body)
assert sheerka.isa(blue_instance, another_color_instance_but_with_a_body)
# isa, when EVAL_GLOBAL_TRUTH_REQUESTED is not activated, only affect the current concept
another_blue_instance = sheerka.new("blue")
assert not sheerka.isa(another_blue_instance, color)
# when EVAL_GLOBAL_TRUTH_REQUESTED is not activated, color is not a set
assert not sheerka.isinset(blue_instance, color)
assert not sheerka.isaset(context, color)
def test_isa_global_truth(self):
sheerka, context, blue, color = self.init_concepts(Concept("blue"), Concept("color"))
blue_instance = sheerka.new("blue")
assert not sheerka.isa(blue_instance, color)
assert not sheerka.isaset(context, color)
assert not sheerka.isinset(blue_instance, color)
context.add_to_private_hints(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
sheerka.set_isa(context, blue_instance, color)
assert sheerka.isa(blue_instance, color)
assert sheerka.isaset(context, color)
assert sheerka.isinset(blue_instance, color)
# all blue instances are now a color
another_blue_instance = sheerka.new("blue")
assert sheerka.isa(another_blue_instance, color)
assert sheerka.isaset(context, color)
assert sheerka.isinset(another_blue_instance, color)
def test_isaset(self):
sheerka, context, group, foo = self.init_concepts(Concept("group"), Concept("foo"))
@@ -246,13 +277,28 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
foo = sheerka.new(foo.key) # new instance
sheerka.set_isa(context, foo, all_foo)
sheerka.set_isa(context, foo, all_bar)
assert foo.get_prop(BuiltinConcepts.ISA) == {all_foo, all_bar}
assert sheerka.isa(foo, all_foo)
assert sheerka.isa(foo, all_bar)
def test_a_concept_can_be_in_multiple_sets_when_global_truth_is_activated(self):
sheerka, context, foo, all_foo, all_bar = self.init_test(global_truth=True).with_concepts(
Concept("foo"),
Concept("all_foo"),
Concept("all_bar"),
create_new=True).unpack()
foo = sheerka.new(foo.key) # new instance
sheerka.set_isa(context, foo, all_foo)
foo = sheerka.new(foo.key) # new instance
sheerka.set_isa(context, foo, all_bar)
assert foo.get_prop(BuiltinConcepts.ISA) == {all_foo, all_bar}
assert sheerka.isa(foo, all_foo)
assert sheerka.isa(foo, all_bar)
assert sheerka.isinset(foo, all_foo)
assert sheerka.isinset(foo, all_bar)
assert sheerka.isaset(context, all_foo)
@@ -270,6 +316,25 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
Concept("baz"),
)
sheerka.set_isa(context, foo, bar)
sheerka.set_isa(context, bar, baz)
assert sheerka.isa(foo, bar)
assert sheerka.isa(bar, baz)
assert sheerka.isa(foo, baz)
def test_i_can_manage_isa_transitivity_when_global_truth_is_activated(self):
"""
if foo isa bar and bar isa baz, then foo isa baz
:return:
"""
sheerka, context, foo, bar, baz = self.init_test(global_truth=True).with_concepts(
Concept("foo"),
Concept("bar"),
Concept("baz"),
).unpack()
sheerka.set_isa(context, sheerka.new("foo"), bar)
sheerka.set_isa(context, sheerka.new("bar"), baz)
@@ -278,11 +343,11 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert sheerka.isa(sheerka.new("foo"), baz)
def test_i_cannot_manage_isa_transitivity_when_using_body(self):
sheerka, context, one, another_one, number = self.init_concepts(
sheerka, context, one, another_one, number = self.init_test(global_truth=True).with_concepts(
"one",
Concept("another one", body="one"),
"number"
)
).unpack()
sheerka.set_isa(context, sheerka.new("one"), number)
@@ -290,7 +355,10 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert not sheerka.isa(another_one, number) # Correct this misbehaviour when BuiltinConcepts.IS is implemented
def test_concepts_in_group_cache_is_updated(self):
sheerka, context, one, two, number = self.init_concepts("one", "two", "number")
sheerka, context, one, two, number = self.init_test(global_truth=True).with_concepts(
"one",
"two",
"number").unpack()
sheerka.set_isa(context, sheerka.new("one"), number)
@@ -315,12 +383,12 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert number.id not in sheerka.get_concepts_bnf_definitions()
def test_i_can_get_and_set_isa_when_multiple_ontology_layers(self):
sheerka, context, foo, group1, group2 = self.init_concepts(
sheerka, context, foo, group1, group2 = self.init_test(global_truth=True).with_concepts(
Concept("foo"),
Concept("group1"),
Concept("group2"),
cache_only=False
)
).unpack()
sheerka.set_isa(context, foo, group1)
@@ -401,7 +469,7 @@ class TestSheerkaSetsManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
}
def test_i_can_set_isa(self):
sheerka, context, foo, bar, group = self.init_test().with_concepts("foo",
sheerka, context, foo, bar, group = self.init_test(global_truth=True).with_concepts("foo",
"bar",
"group",
).unpack()
+9
View File
@@ -116,6 +116,15 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
assert sheerka.memory(context, "self.name == 'foo'") == foo
def test_i_can_use_memory_when_the_entry_does_not_exist(self):
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar", create_new=True).unpack()
sheerka.add_to_memory(context, "foo", foo) # add at least one element
res = sheerka.memory(context, "bar")
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'#name': 'bar'}
def test_i_retrieve_the_last_entry_when_requesting_memory_with_a_query(self):
sheerka, context, foo, bar, foo2 = self.init_concepts("foo", "bar", Concept("foo", body="2"))
+4 -10
View File
@@ -52,22 +52,16 @@ class TestSheerkaQueryManager(TestUsingMemoryBasedSheerka):
assert sheerka.filter_objects(context, lst, prop2={"key": "value"}) == [lst[3]]
# assert sheerka.filter_objects(context, lst, prop1={1, "v"}) == [lst[2]] set are not supported
# complex properties
assert sheerka.filter_objects(context, lst, prop1_contains="a") == [lst[0], lst[1]]
assert sheerka.filter_objects(context, lst, prop1_contains=1) == [lst[2], lst[3]]
def test_i_can_filter_by_object_type(self):
sheerka, context = self.init_test().unpack()
lst = [A("a11", "a12"), Concept("foo", body="a").auto_init(), Concept("foo", body="b").auto_init()]
assert sheerka.filter_objects(context, lst, __type="foo") == [lst[1], lst[2]]
def test_i_can_filter_on_atomic_def(self):
sheerka, context, isa, plus, isa2 = self.init_concepts(
Concept('x is a y').def_var("x").def_var("y"),
Concept('a plus b').def_var("a").def_var("b"),
Concept('u is a v').def_var("u").def_var("v"),
)
lst = [isa, plus, isa2]
assert sheerka.filter_objects(context, lst, atomic_def="is a") == [lst[0], lst[2]]
def test_i_can_filter_on_as_bag_property(self):
sheerka, context = self.init_test().unpack()
lst = [B("a11", "a12"), B("a21", "a22"), B("a31", "a32")]
+22
View File
@@ -253,6 +253,28 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
# a second time, now that bar is already evaluated
assert core.builtin_helpers.ensure_evaluated(context, bar) == foo
@pytest.mark.parametrize("concept, concepts_parts, expected", [
(Concept("foo"), ["where"], 0),
(Concept("foo", where="x"), ["where"], 1),
(Concept("foo", where="x and y"), ["where"], 2),
(Concept("foo", where="x or y"), ["where"], 1),
(Concept("foo", where="x or y and z"), ["where"], 2),
(Concept("foo", where="not w"), ["where"], 1),
(Concept("foo", where=""), ["where"], 0),
(Concept("foo", pre="x"), ["pre", "where"], 101),
(Concept("foo", where="x"), ["pre", "where"], 1),
(Concept("foo", where="x and y", pre="z"), ["pre", "where"], 103),
(Concept("foo", pre="x"), ["pre|where"], 1),
(Concept("foo", where="x"), ["pre|where"], 1),
(Concept("foo", where="x and y", pre="z"), ["pre|where"], 3),
])
def test_i_can_get_concept_complexity(self, concept, concepts_parts, expected):
context = self.get_context()
assert core.builtin_helpers.get_concept_complexity(context, concept, concepts_parts) == expected
# @pytest.mark.parametrize("return_values", [
# None,
# []
+31
View File
@@ -559,6 +559,37 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
ret_val = ReturnValueConcept("Test", True, sheerka.err("an error"))
assert sheerka.get_errors(context, ret_val) == []
def test_i_can_add_and_remove_global_context_hints(self):
sheerka, context = self.init_test().unpack()
sheerka.add_to_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
assert sheerka._global_context_hints == {BuiltinConcepts.EVAL_QUESTION_REQUESTED}
sheerka.remove_fom_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
assert sheerka._global_context_hints == set()
sheerka.add_to_context(sheerka.new(BuiltinConcepts.EVAL_QUESTION_REQUESTED))
assert sheerka._global_context_hints == {BuiltinConcepts.EVAL_QUESTION_REQUESTED}
sheerka.remove_fom_context(sheerka.new(BuiltinConcepts.EVAL_QUESTION_REQUESTED))
assert sheerka._global_context_hints == set()
def test_global_context_hints_are_added_to_every_user_input_execution(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo", pre="in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)")
).unpack()
res = sheerka.evaluate_user_input("eval foo", "testing_user")
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONDITION_FAILED) # sanity check
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
res = sheerka.evaluate_user_input("eval foo", "testing_user")
assert sheerka.isinstance(res[0].value, "foo")
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
res = sheerka.evaluate_user_input("eval foo", "testing_user")
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONDITION_FAILED)
class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
+28 -16
View File
@@ -842,11 +842,9 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
extend_exists=lambda sdp, key: sdp.get("by_id", key))
cache = Cache().auto_configure("by_id")
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
extend_exists=lambda sdp, key: sdp.get("by_key", key))
cache = ListIfNeededCache().auto_configure("by_key")
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
manager.freeze()
@@ -863,11 +861,9 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
extend_exists=lambda sdp, key: sdp.get("by_id", key))
cache = Cache().auto_configure("by_id")
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
extend_exists=lambda sdp, key: sdp.get("by_key", key))
cache = ListIfNeededCache().auto_configure("by_key")
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
manager.freeze()
@@ -887,15 +883,33 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert list(manager.ontologies[0].cache_manager.sdp.state.data.keys()) == ['by_id', 'by_key']
assert manager.ontologies[1].cache_manager.sdp.state.data == {}
def test_i_can_add_the_concepts_with_the_same_key_from_different_layers(self):
sheerka, context, foo_1, foo_2 = self.init_concepts(
Concept("foo x", body="x + 1").def_var("x"),
Concept("foo x", body="x + 2").def_var("x"),
cache_only=False)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
cache = ListIfNeededCache().auto_configure("by_key")
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
manager.freeze()
manager.add_concept(foo_1)
manager.commit(context)
manager.push_ontology("new ontology")
manager.add_concept(foo_2)
manager.commit(context)
assert manager.current_sdp().get("by_key", foo_1.key) == [foo_1, foo_2]
def test_i_can_update_concept_in_default_layer(self):
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
extend_exists=lambda sdp, key: sdp.get("by_id", key))
cache = Cache().auto_configure("by_id")
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
extend_exists=lambda sdp, key: sdp.get("by_key", key))
cache = ListIfNeededCache().auto_configure("by_key")
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
manager.freeze()
@@ -953,11 +967,9 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
extend_exists=lambda sdp, key: sdp.get("by_id", key))
cache = Cache().auto_configure("by_id")
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
extend_exists=lambda sdp, key: sdp.get("by_key", key))
cache = ListIfNeededCache().auto_configure("by_key")
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
manager.freeze()
+18
View File
@@ -193,6 +193,8 @@ def test_i_can_escape():
("c:|id:", None, "id"),
("c:key|:", "key", None),
("c:key|id:x", None, None),
("c:one: plus c:two:", None, None),
("c:one|id: plus c:two:", None, None),
])
def test_i_can_unstr_concept(text, expected_key, expected_id):
k, i = core.utils.unstr_concept(text)
@@ -494,3 +496,19 @@ def test_sheerka_hasattr_get_attr():
assert not core.utils.sheerka_hasattr(concept, "b")
with pytest.raises(AttributeError):
core.utils.sheerka_getattr(concept, "b")
def test_i_can_replace_after():
my_new_items = ["alpha", "beta", "gamma"]
my_list1 = ["a", "b", "c", "d"]
core.utils.replace_after(my_list1, "c", my_new_items)
assert my_list1 == ["a", "b", "alpha", "beta", "gamma"]
my_list2 = ["a", "b", "c", "d"]
core.utils.replace_after(my_list2, "a", my_new_items)
assert my_list2 == ["alpha", "beta", "gamma"]
with pytest.raises(KeyError):
my_list3 = ["a", "b", "c", "d"]
core.utils.replace_after(my_list3, "x", my_new_items)
@@ -1,10 +1,10 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept
from core.tokenizer import Tokenizer
from evaluators.AddConceptInSetEvaluator import AddConceptInSetEvaluator
from parsers.DefConceptParser import IsaConceptNode, NameNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -51,7 +51,20 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
assert res.value.body == "bar"
def test_i_can_add_concept_to_a_set_of_concept(self):
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar", create_new=True).unpack()
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar").unpack()
ret_val = get_isa_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
foo = res.body # get the created instance
assert res.status
assert context.sheerka.isinstance(res.value, foo.key)
assert context.sheerka.isa(foo, bar)
assert foo.get_prop(BuiltinConcepts.ISA) == {bar}
def test_i_can_add_concept_to_a_set_of_concept_when_global_truth_is_activated(self):
sheerka, context, foo, bar = self.init_test(global_truth=True).with_concepts("foo", "bar").unpack()
ret_val = get_isa_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
@@ -65,19 +78,18 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
assert foo.get_prop(BuiltinConcepts.ISA) == {bar}
def test_i_can_add_bnf_concept_to_a_set_of_concept(self):
def test_i_can_add_bnf_concept_to_a_set_of_concept_when_global_truth_is_activated(self):
"""
This test is the reason why I have started the whole eval on demand stuff
Sheerka tries to evaluate the body but it can't (as a and b are not defined)
So 'foo' cannot be put is set
:return:
"""
sheerka, context, one, two, foo, bar = self.init_test().with_concepts(
sheerka, context, one, two, foo, bar = self.init_test(global_truth=True).with_concepts(
"one",
"two",
Concept("foo", definition="(one|two)=a 'plus' (one|two)=b", body="a + b").def_var("a").def_var("b"),
"bar",
create_new=True).unpack()
"bar").unpack()
ret_val = get_isa_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
@@ -103,11 +115,25 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
ret_val = get_isa_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
assert res.status
assert context.sheerka.isinstance(res.value, foo.key)
def test_i_can_add_concept_with_a_body_to_a_set_of_concept_when_global_truth_is_activated(self):
context = self.get_context(global_truth=True)
foo = Concept("foo", body="1")
context.sheerka.create_new_concept(context, foo)
bar = Concept("bar")
context.sheerka.create_new_concept(context, bar)
ret_val = get_isa_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
assert res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.SUCCESS)
def test_i_cannot_add_the_same_concept_twice(self):
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar", create_new=True).unpack()
sheerka, context, foo, bar = self.init_test(global_truth=True).with_concepts("foo", "bar").unpack()
ret_val = get_isa_ret_val("foo", "bar")
AddConceptInSetEvaluator().eval(context, ret_val)
+2 -1
View File
@@ -43,7 +43,8 @@ class TestExpressionEvaluator(TestUsingMemoryBasedSheerka):
assert not res.body
# second time
sheerka.set_isa(context, one, number)
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, one, number)
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
res = evaluator.eval(context, parsed_return_value)
assert res.status
@@ -0,0 +1,49 @@
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
from core.concept import Concept
from evaluators.PrepareEvalGlobalTruthEvaluator import PrepareEvalGlobalTruthEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
r = ReturnValueConcept
class TestPrepareEvalGlobalTruthEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("ret_val, expected", [
(r("name", True, UserInputConcept("global_truth(1 + 1)")), True),
(r("name", True, UserInputConcept(" global_truth(1 + 1) ")), True),
(r("name", True, UserInputConcept("global_truth()")), False),
(r("name", True, UserInputConcept("1+1")), False),
(r("name", True, UserInputConcept("")), False),
(r("name", True, UserInputConcept("global_truth(")), False),
(r("name", True, UserInputConcept(")")), False),
(r("name", True, UserInputConcept([])), False),
(r("name", True, Concept("foo")), False),
(r("name", True, "not a concept"), False),
(r("name", False, UserInputConcept("global_truth(1 + 1)")), False),
])
def test_i_can_match(self, ret_val, expected):
context = self.get_context()
assert PrepareEvalGlobalTruthEvaluator().matches(context, ret_val) == expected
@pytest.mark.parametrize("ret_val, expected", [
(r("name", True, UserInputConcept("global_truth(1 + 1)")), "1 + 1"),
(r("name", True, UserInputConcept(" global_truth( 1 + 1 ) ")), "1 + 1"),
])
def test_i_can_eval(self, ret_val, expected):
context = self.get_context()
sheerka = context.sheerka
prepare_evaluator = PrepareEvalGlobalTruthEvaluator()
prepare_evaluator.matches(context, ret_val)
res = prepare_evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.USER_INPUT)
assert res.body.body == expected
assert BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED in context.protected_hints
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.protected_hints
assert BuiltinConcepts.RETURN_BODY_REQUESTED in context.protected_hints
@@ -1,12 +1,15 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from evaluators.BaseEvaluator import BaseEvaluator
from evaluators.ResolveAmbiguityEvaluator import ResolveAmbiguityEvaluator
from parsers.ExactConceptParser import ExactConceptParser
from parsers.SyaNodeParser import SyaNodeParser
from tests.BaseTest import BaseTest
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
pretval = BaseTest.pretval
@@ -21,6 +24,37 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
context = self.get_context()
assert ResolveAmbiguityEvaluator().matches(context, return_values) == expected
def test_i_can_match_when_the_input_comes_from_an_evaluator(self):
ret_val1 = pretval(Concept("foo"), source="source", parser=BaseEvaluator.get_name("evaluator"))
ret_val2 = pretval(Concept("bar"), source="source", parser=BaseEvaluator.get_name("evaluator"))
return_values = [ret_val1, ret_val2]
context = self.get_context()
assert ResolveAmbiguityEvaluator().matches(context, return_values)
def test_i_can_match_when_concept_nodes(self):
sheerka, context, a, foo_1, foo_2 = self.init_concepts(
Concept("a"),
Concept("foo x").def_var("x"),
Concept("foo y").def_var("y"),
create_new=True
)
return_values = SyaNodeParser().parse(context, ParserInput("foo a"))
assert ResolveAmbiguityEvaluator().matches(context, return_values)
def test_i_can_match_when_concept_node_mixed_with_concept(self):
sheerka, context, a, foo_1, foo_a = self.init_concepts(
Concept("a"),
Concept("foo x").def_var("x"),
Concept("foo a"),
create_new=True
)
sya_return_value = SyaNodeParser().parse(context, ParserInput("foo a"))
assert ResolveAmbiguityEvaluator().matches(context, [sya_return_value, pretval(foo_a, source="foo a")])
def test_i_can_manage_when_no_source(self):
context = self.get_context()
return_values = [BaseTest.retval(Concept("foo"))]
@@ -53,6 +87,44 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
return_values[2],
]
@pytest.mark.parametrize("concepts, expected", [
([Concept("c1"), Concept("c2", where="True")], "c2"),
([Concept("c1"), Concept("c2", pre="True")], "c2"),
([Concept("c1"), Concept("c2", where="False")], "c1"),
([Concept("c1"), Concept("c2", pre="False")], "c1"),
([Concept("c1", pre="True"), Concept("c2", where="True")], "c1"),
([Concept("c1", pre="False"), Concept("c2", where="True")], "c2"),
([Concept("c1", pre="False"), Concept("c2", where="False")], BuiltinConcepts.NO_RESULT),
])
def test_i_can_eval_2(self, concepts, expected):
context = self.get_context()
return_values = [self.pretval(c, source="foo") for c in concepts]
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert len(res) == 1
if expected != BuiltinConcepts.NO_RESULT:
selected_concept = res[0].body.body
assert selected_concept.name == expected
else:
assert res[0].body == BuiltinConcepts.NO_RESULT
@pytest.mark.parametrize("concepts", [
[Concept("c1"), Concept("c2")],
[Concept("c1", pre="True"), Concept("c2", pre="True")],
])
def test_i_can_eval_when_same_complexity(self, concepts):
context = self.get_context()
return_values = [self.pretval(c, "foo") for c in concepts]
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert res is None
def test_i_can_eval_all_fail(self):
context = self.get_context()
return_values = [
@@ -91,3 +163,70 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
res = evaluator.eval(context, return_values)
assert res is None
def test_i_can_eval_to_the_simplest_concept(self):
"""
def concept foo x where x
def concept foo a
When the input is foo a, 'foo x' must be discarded as concept 'foo a' is more accurate
:return:
"""
sheerka, context, a, foo_1, foo_a = self.init_concepts(
Concept("a"),
Concept("foo x").def_var("x"),
Concept("foo a"),
create_new=True
)
sya_return_value = SyaNodeParser().parse(context, ParserInput("foo a"))
exact_concept_return_value = pretval(foo_a, source="foo a")
return_values = [sya_return_value, exact_concept_return_value]
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert len(res) == 1
assert res[0].who == evaluator.name
assert res[0].body == exact_concept_return_value.body
assert res[0].parents == return_values
def test_i_can_eval_to_the_simplest_concept_when_concept_nodes(self):
"""
Same explanation than test_i_can_eval_to_the_simplest_concept()
:return:
"""
sheerka, context, a, b, foo_1, foo_2 = self.init_concepts(
Concept("a"),
Concept("b"),
Concept("foo x y").def_var("x").def_var("y"),
Concept("foo a x").def_var("x"),
create_new=True
)
return_values = SyaNodeParser().parse(context, ParserInput("foo a b"))
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert len(res) == 1
assert res[0].who == evaluator.name
assert sheerka.isinstance(res[0].body.body[0].concept, foo_2)
def test_i_can_eval_when_non_instance_concepts(self):
sheerka, context, foo_1, foo_2 = self.init_concepts(
Concept("foo x", body="1", pre="True").def_var("x"),
Concept("foo x", body="2", pre="True").def_var("x"),
create_new=True
)
exact_parser_return_values = ExactConceptParser().parse(context, ParserInput("c:foo x:"))
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, exact_parser_return_values)
res = evaluator.eval(context, exact_parser_return_values)
assert res is None # means that there is nothing to resolve as the concepts are not instances
@@ -185,14 +185,3 @@ class TestValidateConceptEvaluator(TestUsingMemoryBasedSheerka):
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.FILTERED)
assert res.body.body == ret_val.body.body
def test_i_can_manage_infinite_recursion(self):
sheerka, context, a_and_b = self.init_concepts(
Concept("a and b", where="is_question()", body="a and b").def_var("a").def_var("b"),
create_new=True)
evaluator = ValidateConceptEvaluator()
ret_val = pr_ret_val(a_and_b)
res = evaluator.eval(context, ret_val)
assert res is None # infinite recursion detected, res is None to drop the validator
+25 -23
View File
@@ -362,6 +362,7 @@ as:
])
def test_i_can_mix_concept_with_python_to_define_numbers(self, desc, definitions):
sheerka = self.get_sheerka()
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
for definition in definitions:
sheerka.evaluate_user_input(definition)
@@ -396,6 +397,7 @@ as:
assert len(res) == 1
assert res[0].status
assert res[0].body == 23
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
def test_i_can_mix_bnf_and_isa(self):
"""
@@ -406,8 +408,8 @@ as:
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept two as 2")
sheerka.evaluate_user_input("def concept number")
sheerka.evaluate_user_input("set_isa(one, number)")
sheerka.evaluate_user_input("set_isa(two, number)")
sheerka.evaluate_user_input("global_truth(set_isa(one, number))")
sheerka.evaluate_user_input("global_truth(set_isa(two, number))")
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' number as 20 + number")
res = sheerka.evaluate_user_input("twenty one")
@@ -443,6 +445,7 @@ as:
def test_i_can_mix_bnf_and_isa_2(self):
sheerka = self.get_sheerka()
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
init = [
"def concept one as 1",
@@ -460,6 +463,7 @@ as:
assert len(res) == 1
assert res[0].status
assert res[0].body == 21
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
def test_i_can_use_concepts_defined_with_from(self):
sheerka = self.get_sheerka()
@@ -565,7 +569,7 @@ as:
"def concept plus_one from bnf number=n1 'plus_one' as n1 + 1",
]
sheerka = self.init_scenario(definitions)
sheerka = self.init_scenario(definitions, global_truth=True)
res = sheerka.evaluate_user_input("eval two plus_one")
assert len(res) == 1
@@ -642,8 +646,6 @@ as:
assert res[0].body == 21
def test_i_can_use_where_in_bnf(self):
sheerka, context = self.init_test().unpack()
init = [
"def concept one as 1",
"def concept two as 2",
@@ -656,8 +658,8 @@ as:
"def concept twenties from bnf twenty number where number <= 2 as twenty + number"
]
for exp in init:
sheerka.evaluate_user_input(exp)
sheerka = self.init_scenario(init, global_truth=True)
context = self.get_context(sheerka)
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
@@ -765,7 +767,7 @@ as:
sheerka.evaluate_user_input("def concept two as 2")
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
res = sheerka.evaluate_user_input("set_isa(twenties, number)")
res = sheerka.evaluate_user_input("global_truth(set_isa(twenties, number))")
assert len(res) == 1
assert res[0].status
@@ -946,7 +948,7 @@ as:
"set_isa(twenties, number)",
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
# simulate that sheerka was stopped and restarted
sheerka.clear_bnf_definition()
@@ -967,8 +969,8 @@ as:
res = sheerka.evaluate_user_input("set_isa(last_created_concept(), number)")
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
assert sheerka.isinstance(res[0].body, "one")
assert sheerka.isa(res[0].body, sheerka.new("number"))
def test_i_can_evaluate_sya_and_ret_concepts(self):
init = [
@@ -1001,7 +1003,7 @@ as:
# Since command is a __COMMAND, the body is auto evaluated
# and we return the body, not the concept
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("command")
assert res[0].status
assert res[0].body == "Executed !"
@@ -1016,7 +1018,7 @@ as:
"def concept x is a y as set_isa(x,y)",
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("question(one is a number)") # automatically evaluated
assert len(res) == 1
assert res[0].status
@@ -1042,7 +1044,7 @@ as:
# So the first one should be picked.
# the second concept 'one' 's value is an integer, to make sure that it won't be rejected because of its type
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("def concept x plus y where x is a number as x + y")
assert len(res) == 1
assert res[0].status
@@ -1065,7 +1067,7 @@ as:
"set_is_greater_than(BuiltinConcepts.PRECEDENCE, c:is_a:, c:q:, 'Sya')",
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
@@ -1133,7 +1135,7 @@ as:
res = sheerka.evaluate_user_input("twenty one")
assert len(res) > 1 # not recognized
sheerka.evaluate_user_input("set_isa(one, number)")
sheerka.evaluate_user_input("global_truth(set_isa(one, number))")
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
@@ -1252,9 +1254,9 @@ as:
"def concept two",
"def concept number",
"def concept nb times from bnf number 'times'",
"set_isa(two, number)",
"set_isa(two, number)", # defined after 'nb times'
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("two times")
@@ -1270,7 +1272,7 @@ as:
"def concept cars",
"def concept quantify x from bnf number x as set_attr(x, 'qty', number) ret x"
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("eval two cars")
@@ -1287,7 +1289,7 @@ as:
"def concept cars",
"def concept quantify x from bnf number=n1 x as set_attr(x, 'qty', n1) ret x"
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("eval two cars")
@@ -1317,7 +1319,7 @@ as:
"def concept she ret memory('isa(self, female)')",
"girl"
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
context = self.get_context(sheerka)
res = sheerka.evaluate_user_input("set_attr(she, 'my_attr', 'my value')")
@@ -1337,7 +1339,7 @@ as:
"def concept x attribute y equals z as set_attr(x, y, z)",
"girl"
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
context = self.get_context(sheerka)
res = sheerka.evaluate_user_input("eval she attribute 'my_attr' equals 'my value'")
@@ -1392,7 +1394,7 @@ as:
"def concept qualify x from bnf adjective x as set_attr(x, c:adjective:, adjective) ret x",
"eval a red short",
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("what is the color of the short ?")
assert len(res) == 1
+31 -3
View File
@@ -13,6 +13,34 @@ class TestSheerkaNonRegMemory2(TestUsingMemoryBasedSheerka):
res = sheerka.evaluate_user_input("question(foo is a foo)")
# assert len(res) == 1
# assert res[0].status
# assert res[0].value
assert len(res) == 1
assert res[0].status
assert res[0].value # value is True since 'x is a foo' was chosen
def test_i_can_select_the_correct_concept_vs_bnf(self):
init = [
"def concept one as 1",
"def concept two as 2",
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit",
"def concept twenty two as 'specific occurrence'",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("eval twenty one")
assert res[0].value == 21
res = sheerka.evaluate_user_input("eval twenty two")
assert res[0].value == "specific occurrence" # thanks to ExactConceptParser
def test_i_can_use_global_truth_when_calling_a_concept(self):
init = [
"def concept one",
"def concept number",
"def concept x is a y as set_isa(x, y)",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("global_truth(one is a number)")
assert res[0].status
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
@@ -85,7 +85,7 @@ class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
"set_isa(thirty, number)",
"def concept thirties from bnf thirty number where number < 10 as thirty + number",
"set_isa(thirties, number)",
])
], global_truth=True)
sheerka = self.new_sheerka_instance()
+39
View File
@@ -53,6 +53,45 @@ post : None
ret : None
vars : []
props : {}
"""
def test_i_can_display_multiple_concepts_description_when_concept_definition(self, capsys):
init = [
"def concept foo as 1",
"def concept foo as 2 where True",
]
sheerka = self.init_scenario(init)
capsys.readouterr()
sheerka.enable_process_return_values = True
sheerka.evaluate_user_input("desc(c:foo:)")
captured = capsys.readouterr()
assert captured.out == """id : 1001
name : foo
key : foo
definition: None
type : None
hash : 16f7fbb8bc509b8c652edaf3d0c0457d15a37f0a862fbe03fa357b0c77249c46
body : 1
where : None
pre : None
post : None
ret : None
vars : []
props : {}
id : 1002
name : foo
key : foo
definition: None
type : None
hash : e8dd1af1b6bc0eca0fb4a87a6fabb16655caa4b7a6ea9dbbd1f887757e6caf89
body : 2
where : True
pre : None
post : None
ret : None
vars : []
props : {}
"""
def test_i_can_describe_a_rule(self, capsys):
@@ -35,7 +35,7 @@ class TestSheerkaNonRegPipeFunctions(TestUsingMemoryBasedSheerka):
"add_to_memory('x', [one])"
]
sheerka = self.init_scenario(init)
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("x | where('isa(self, number)')")
assert len(res) == 1
+37 -31
View File
@@ -98,22 +98,24 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
@classmethod
def setup_class(cls):
init_test_helper = cls().init_test(cache_only=False, ontology="#TestBnfNodeParser#")
test_instance = cls()
init_test_helper = test_instance.init_test(cache_only=False, ontology="#TestBnfNodeParser#")
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
for i, concept_name in enumerate(cmap):
cmap[concept_name] = updated[i]
# end of initialisation
global_truth_context = test_instance.get_context(sheerka, global_truth=True)
sheerka = TestBnfNodeParser.sheerka
sheerka.set_isa(context, cmap["one"], cmap["number"])
sheerka.set_isa(context, cmap["two"], cmap["number"])
sheerka.set_isa(context, cmap["three"], cmap["number"])
sheerka.set_isa(context, cmap["four"], cmap["number"])
sheerka.set_isa(context, cmap["thirty"], cmap["number"])
sheerka.set_isa(context, cmap["forty"], cmap["number"])
sheerka.set_isa(context, cmap["fifty"], cmap["number"])
sheerka.set_isa(context, cmap["one hundred"], cmap["number"])
sheerka.set_isa(context, cmap["hundreds"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["one"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["two"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["three"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["four"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["thirty"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["forty"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["fifty"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["one hundred"], cmap["number"])
sheerka.set_isa(global_truth_context, cmap["hundreds"], cmap["number"])
# Pay attention. 'twenties (t1 and t2) are not set as 'number'
@@ -122,28 +124,28 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
where="number < 10",
body="thirty + number").def_var("thirty").def_var("number"))
cmap["thirties"] = sheerka.create_new_concept(context, thirties).body.body
sheerka.set_isa(context, sheerka.new("thirties"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("thirties"), sheerka.new("number"))
forties = cls.update_bnf(context, Concept("forties",
definition="forty number",
where="number < 10",
body="forty + number").def_var("forty").def_var("number"))
cmap["forties"] = sheerka.create_new_concept(context, forties).body.body
sheerka.set_isa(context, sheerka.new("forties"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("forties"), sheerka.new("number"))
fifties = cls.update_bnf(context, Concept("fifties",
definition="fifty number",
where="number < 10",
body="fifty + number").def_var("fifty").def_var("number"))
cmap["fifties"] = sheerka.create_new_concept(context, fifties).body.body
sheerka.set_isa(context, sheerka.new("fifties"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("fifties"), sheerka.new("number"))
thousands = cls.update_bnf(context, Concept("thousands",
definition="number 'thousand'",
where="number < 999",
body="number * 1000").def_var("number"))
cmap["thousands"] = sheerka.create_new_concept(context, thousands).body.body
sheerka.set_isa(context, sheerka.new("thousands"), sheerka.new("number"))
sheerka.set_isa(global_truth_context, sheerka.new("thousands"), sheerka.new("number"))
cls.shared_ontology = sheerka.get_ontology(context)
sheerka.pop_ontology(context)
@@ -1217,10 +1219,11 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
"twenties": self.bnf_concept("twenties", Sequence(ConceptExpression("twenty"), ConceptExpression("number")))
}
sheerka, context, parser = self.init_parser(my_map)
global_truth_context = self.get_context(sheerka, global_truth=True)
parser.context = context
parser.sheerka = sheerka
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(context, sheerka.new("twenty"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), my_map["number"])
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
@@ -1251,9 +1254,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
sheerka, context, parser = self.init_parser(my_map, singleton=True)
parser.context = context
parser.sheerka = sheerka
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(context, sheerka.new("two"), my_map["number"])
sheerka.set_isa(context, sheerka.new("hundreds"), my_map["number"])
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("two"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("hundreds"), my_map["number"])
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
parsing_expression = parser.get_parsing_expression(context, my_map["hundreds"])
@@ -1281,9 +1285,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
sheerka, context, parser = self.init_parser(my_map, singleton=True)
parser.context = context
parser.sheerka = sheerka
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(context, sheerka.new("twenty"), my_map["number"])
sheerka.set_isa(context, sheerka.new("twenties"), my_map["number"]) # <- twenties is also a number
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), my_map["number"])
sheerka.set_isa(global_truth_context, sheerka.new("twenties"), my_map["number"]) # <- twenties is also a number
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
@@ -1900,15 +1905,16 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
}
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"])
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["adjective"])
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["adjective"])
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["color"])
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["color"])
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["red colors"])
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["red colors"])
sheerka.set_isa(global_truth_context, my_map["color"], my_map["adjective"])
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["color"])
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["adjective"])
text = "light red table"
+1
View File
@@ -144,6 +144,7 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert concept_found == foo
assert not concept_found.get_hints().need_validation
assert concept_found.get_hints().is_evaluated
assert not concept_found.get_hints().is_instance
def test_i_can_parse_concept_with_concept_tokens(self):
sheerka, context, one, two, plus = self.init_concepts(
+85 -1
View File
@@ -4,7 +4,7 @@ from core.builtin_concepts import BuiltinConcepts
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import TokenKind
from parsers.BaseExpressionParser import TrueifyVisitor, IsAQuestionVisitor, LeftPartNotFoundError, \
ParenthesisMismatchError
ParenthesisMismatchError, compile_disjunctions, NotNode, AndNode, OrNode
from parsers.BaseParser import UnexpectedEofParsingError, UnexpectedTokenParsingError
from parsers.LogicalOperatorParser import LogicalOperatorParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -12,6 +12,46 @@ from tests.parsers.parsers_utils import EXPR, OR, AND, NOT, \
get_expr_node_from_test_node
class DoNotCompareStartStopContextManager:
def __init__(self):
self.original_not_eq = None
self.original_and_eq = None
self.original_or_eq = None
@staticmethod
def not_eq(self, other):
if not isinstance(other, NotNode):
return False
return self.node == other.node
@staticmethod
def and_eq(self, other):
if not isinstance(other, AndNode):
return False
return self.parts == other.parts
@staticmethod
def or_eq(self, other):
if not isinstance(other, OrNode):
return False
return self.parts == other.parts
def __enter__(self):
self.original_not_eq = NotNode.__eq__
self.original_and_eq = AndNode.__eq__
self.original_or_eq = OrNode.__eq__
NotNode.__eq__ = self.not_eq
AndNode.__eq__ = self.and_eq
OrNode.__eq__ = self.or_eq
def __exit__(self, *args):
NotNode.__eq__ = self.original_not_eq
AndNode.__eq__ = self.original_and_eq
OrNode.__eq__ = self.original_or_eq
class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
def init_parser(self):
@@ -175,6 +215,50 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
assert IsAQuestionVisitor().visit(expr_node) == expected
@pytest.mark.parametrize("expression, expected", [
("a", [EXPR("a")]),
("a and b and c", [AND(EXPR("a"), EXPR("b"), EXPR("c"))]),
("a or b or c", [EXPR("a"),
EXPR("b"),
EXPR("c")]),
("a and b or c", [AND(EXPR("a"), EXPR("b")), EXPR("c")]),
("a or b and c", [EXPR("a"),
AND(EXPR("b"), EXPR("c"))]),
("(a or b) and c", [AND(EXPR("a"), EXPR("c")),
AND(EXPR("b"), EXPR("c"))]),
("a or (b or c) and d", [EXPR("a"),
AND(EXPR("b"), EXPR("d")),
AND(EXPR("c"), EXPR("d"))]),
("not a", [NOT(EXPR("a"))]),
("not (a and b)", [NOT(AND(EXPR("a"), EXPR("b")))]),
("not (a or b)", [AND(NOT(EXPR("a")), NOT(EXPR("b")))]),
("(a or b) and not (c or d)", [AND(EXPR("a"), NOT(EXPR("c")), NOT(EXPR("d"))),
AND(EXPR("b"), NOT(EXPR("c")), NOT(EXPR("d")))]),
("(a or b) or not (c or d)", [EXPR("a"),
EXPR("b"),
AND(NOT(EXPR("c")), NOT(EXPR("d")))]),
("(a and b) and not (c or d)", [AND(EXPR("a"), EXPR("b"), NOT(EXPR("c")), NOT(EXPR("d")))]),
("(a and b) or not (c or d)", [AND(EXPR("a"), EXPR("b")),
AND(NOT(EXPR("c")), NOT(EXPR("d")))]),
("a and (b and c)", [AND(EXPR("a"), EXPR("b"), EXPR("c"))]),
("a or (b or c)", [EXPR("a"),
EXPR("b"),
EXPR("c")]),
])
def test_i_can_compile_disjunction(self, expression, expected):
sheerka, context, parser = self.init_parser()
resolved_expected = [get_expr_node_from_test_node(expression, e) for e in expected]
expr_node = parser.parse(context, ParserInput(expression)).body.body
with DoNotCompareStartStopContextManager():
res = compile_disjunctions(expr_node)
assert res == resolved_expected
# @pytest.mark.parametrize("expression, expected", [
# ("foo", "foo"),
# ("one two", "one two"),
+17
View File
@@ -258,6 +258,23 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
compare_with_test_object(lexer_nodes, expected_array)
@pytest.mark.parametrize("concept", [
Concept("foo x", body="1").def_var("x"),
Concept("foo"),
])
def test_i_can_parse_token_concepts(self, concept):
concepts_map = {
"foo": concept,
}
sheerka, context, parser = self.init_parser(concepts_map, create_new=True, use_sheerka=True)
res = parser.parse(context, ParserInput(f"c:{concept.name}:"))
assert res.status
concept_found = res.body.body[0].concept
assert concept_found.get_hints().is_evaluated
assert not concept_found.get_hints().is_instance
@pytest.mark.parametrize("text", [
"foo",
f"foo one",
+81
View File
@@ -709,6 +709,65 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
self.compare_results(res, expected_sequences, cmap, expression)
@pytest.mark.parametrize("expression, expected", [
("suffixed2 a b", ['a', 'b', "suffixed2"]),
("suffixed3 a b c", ['a', 'b', 'c', "suffixed3"]),
("a b prefixed2", ['a', 'b', "prefixed2"]),
("a b c prefixed3", ['a', 'b', 'c', "prefixed3"]),
("start2 a b stop", ['a', 'b', "start2"]),
("start3 a b c stop", ['a', 'b', 'c', "start3"]),
])
def test_i_can_post_fix_when_multiple_parameters_are_expected(self, expression, expected):
concepts_map = {
"a": Concept("a"),
"b": Concept("b"),
"c": Concept("c"),
"suffixed2": Concept("suffixed2 x y").def_var("x").def_var("y"),
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
"prefixed2": Concept("x y prefixed2").def_var("x").def_var("y"),
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
"start2": Concept("start2 x y stop").def_var("x").def_var("y"),
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
}
sheerka, context, parser = self.init_parser(concepts_map, None)
res = parser.infix_to_postfix(context, ParserInput(expression))
expected_array = compute_expected_array(concepts_map, expression, expected)
assert len(res) == 1
transformed_out = get_test_obj(res[0].out, expected_array)
assert transformed_out == expected_array
@pytest.mark.parametrize("expression, expected", [
("suffixed3 x y z", ['x', 'y', 'z', "suffixed3"]),
("suffixed3 a y z", ['a', 'y', 'z', "suffixed3"]),
("suffixed3 x a z", ['x ', 'a', ' z', "suffixed3"]), # this one was not managed by the second chance
("suffixed3 x y a", ['x', 'y', 'a', "suffixed3"]),
("x y z prefixed3", ['x', 'y', 'z', "prefixed3"]),
("a y z prefixed3", ['a', 'y', 'z', "prefixed3"]),
("x a z prefixed3", ['x ', 'a', ' z', "prefixed3"]),
("x y a prefixed3", ['x', 'y', 'a', "prefixed3"]),
("start3 x y z stop", ['x', 'y', 'z', "start3"]),
("start3 a y z stop", ['a', 'y', 'z', "start3"]),
("start3 x a z stop", ['x ', 'a', ' z ', "start3"]),
("start3 x y a stop", ['x', 'y', 'a', "start3"]),
])
def test_i_can_post_fix_when_multiple_parameters_are_expected_but_unrecognized_tokens(self, expression, expected):
concepts_map = {
"a": Concept("a"),
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
}
sheerka, context, parser = self.init_parser(concepts_map, None)
res = parser.infix_to_postfix(context, ParserInput(expression))
expected_array = compute_expected_array(concepts_map, expression, expected)
assert len(res) == 1
transformed_out = get_test_obj(res[0].out, expected_array)
assert transformed_out == expected_array
@pytest.mark.parametrize("expression, expected", [
("(", ("(", 0)),
("one plus ( 1 + ", ("(", 4)),
@@ -1080,6 +1139,28 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
assert isinstance(concept_plus_b[0].body.body, PythonNode)
assert concept_suffixed_a == cmap["two"]
@pytest.mark.parametrize("text, expected", [
("suffixed3 a b c", [("x", "a"), ("y", "b"), ("z", "c")]),
("a b c prefixed3", [("x", "a"), ("y", "b"), ("z", "c")]),
("start3 a b c stop", [("x", "a"), ("y", "b"), ("z", "c")]),
])
def test_i_can_parse_when_multiple_parameters_are_expected(self, text, expected):
concepts_map = {
"a": Concept("a"),
"b": Concept("b"),
"c": Concept("c"),
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
}
sheerka, context, parser = self.init_parser(concepts_map, None)
res = parser.parse(context, ParserInput(text))
lexer_nodes = res.body.body
assert res.status
assert lexer_nodes[0].concept.get_metadata().variables == expected
@pytest.mark.parametrize("text", [
"function(suffixed one)",
"function(one plus two mult three)",
+6 -12
View File
@@ -433,6 +433,10 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
compare_with_test_object(actual_nodes, expected_array)
def test_i_can_parse_when_multiple_atom_and_sya(self):
"""
Testing that the ambiguity between hello_atom and hello_sya is correctly managed
:return:
"""
sheerka, context, parser = self.init_parser()
expression = "two hello one three"
nodes = get_input_nodes_from(concepts_map, expression,
@@ -440,25 +444,15 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
parser_input = ParserResultConcept("parsers.xxx", source=expression, value=nodes)
res = parser.parse(context, parser_input)
assert len(res) == 2
assert res[0].status
assert res[1].status
assert res.status
actual_nodes0 = res[0].body.body
actual_nodes0 = res.body.body
expected_0 = compute_expected_array(concepts_map, expression, [
CN("two", start=0, end=0),
CN("hello_atom", source="hello one", start=2, end=4),
CN("three", start=6, end=6)])
compare_with_test_object(actual_nodes0, expected_0)
actual_nodes1 = res[1].body.body
expected_1 = compute_expected_array(concepts_map, expression, [
CN("two", start=0, end=0),
CNC("hello_sya", "hello one", start=2, end=4, a="one"),
CN("three", start=6, end=6)],
exclude_body=True)
compare_with_test_object(actual_nodes1, expected_1)
def test_i_can_parse_when_multiple_sya_concepts(self):
sheerka, context, parser = self.init_parser()
expression = "greetings two"