Implemented some enhancement request and fixed some bugs
Fixed #2 : Variables are not recognized when inside a rule token Fixed #15 : Rule: rete attributes are lost when a new ontology is created Fixed #14 : ReteNetwork: Format rules must not be added to Rete network Fixed #16 : DefConcept: Variables are not recognized when they are keyword arguments Fixed #4 : Comparison are not correctly set when comparison property is a concept Fixed #14 : Parser: merge FunctionParser.NamesNode and ExpressionParser.NamesNode Fixed #18 : Parser: Add SourceCodeNode test to UnrecognizedNodeParser Fixed #20 : At startup Number concept is saved in db a numerous number of time Fixed #21 : CacheManager: I can remove all elements from a ListIfNeededCache and fill it again Fixed #22 : CacheManager: I can remove all elements from a SetCache and fill it again Fixed #23 : HistoryManager: history() no longer works Fixed #24 : HistoryManager: history() no longer works after creating an exec rule Fixed #25 : SheerkaMemory: Use MemoryObject instead of sheerka.local Fixed #26 : Debugger: add the list all available services.. Fixed #27 : CONCEPTS_GRAMMARS_ENTRY does not seems to be in use any more Fixed #28 : Give order to services
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
#import admin
|
||||
#import default
|
||||
#import python
|
||||
#import numbers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
def concept x is a string pre is_question() as isinstance(x, str)
|
||||
def concept x is a int pre is_question() as isinstance(x, int)
|
||||
def concept x is a integer pre is_question() as isinstance(x, int)
|
||||
def concept x starts with y pre is_question() where x is a string as x.startswith(y)
|
||||
Vendored
+2
-2
@@ -15,7 +15,7 @@ class ListIfNeededCache(BaseCache):
|
||||
if isinstance(self._cache[key], list):
|
||||
self._cache[key].append(value)
|
||||
else:
|
||||
self._cache[key] = [self._cache[key], value]
|
||||
self._cache[key] = value if self._cache[key] is Removed else [self._cache[key], value]
|
||||
else:
|
||||
self._sync(key)
|
||||
|
||||
@@ -28,7 +28,7 @@ class ListIfNeededCache(BaseCache):
|
||||
if isinstance(self._cache[key], list):
|
||||
self._cache[key].append(value)
|
||||
else:
|
||||
self._cache[key] = [self._cache[key], value]
|
||||
self._cache[key] = value if self._cache[key] is Removed else [self._cache[key], value]
|
||||
else:
|
||||
self._cache[key] = value
|
||||
self._add_to_add(key)
|
||||
|
||||
Vendored
+7
-1
@@ -19,8 +19,11 @@ class SetCache(BaseCache):
|
||||
|
||||
def _put(self, key, value, alt_sdp):
|
||||
if key in self._cache:
|
||||
if value in self._cache[key]:
|
||||
if self._cache[key] is Removed:
|
||||
self._cache[key] = {value}
|
||||
elif value in self._cache[key]:
|
||||
return False
|
||||
else:
|
||||
self._cache[key].add(value)
|
||||
else:
|
||||
self._sync(key)
|
||||
@@ -31,6 +34,9 @@ class SetCache(BaseCache):
|
||||
self._cache[key] = sheerka_deepcopy(previous)
|
||||
|
||||
if key in self._cache:
|
||||
if self._cache[key] == Removed:
|
||||
self._cache[key] = {value}
|
||||
else:
|
||||
self._cache[key].add(value)
|
||||
else:
|
||||
self._cache[key] = {value}
|
||||
|
||||
@@ -88,7 +88,11 @@ class UnreferencedVariablesVisitor(UnreferencedNamesVisitor):
|
||||
"""
|
||||
|
||||
def visit_Call(self, node: ast.Call):
|
||||
self.visit_selected(node, ["args"])
|
||||
self.visit_selected(node, ["args", "keywords"])
|
||||
|
||||
def visit_keyword(self, node: ast.keyword):
|
||||
self.names.add(node.arg)
|
||||
self.visit_selected(node, ["value"])
|
||||
|
||||
|
||||
class NamesWithAttributesVisitor(ast.NodeVisitor):
|
||||
|
||||
+3
-113
@@ -7,13 +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
|
||||
from core.rule import Rule
|
||||
from core.sheerka.services.SheerkaExecute import SheerkaExecute
|
||||
from core.tokenizer import Keywords
|
||||
from core.utils import as_bag
|
||||
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode, \
|
||||
RuleNode
|
||||
from parsers.BaseParser import ParsingError
|
||||
from parsers.PythonParser import PythonParser
|
||||
|
||||
PARSE_STEPS = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
|
||||
EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION,
|
||||
@@ -287,109 +284,6 @@ def only_parsers_results(context, return_values):
|
||||
parents=return_values)
|
||||
|
||||
|
||||
def parse_unrecognized(context, source, parsers, who=None, prop=None, filter_func=None):
|
||||
"""
|
||||
Try to recognize concepts or code from source using the given parsers
|
||||
:param context:
|
||||
:param source: ParserInput if possible
|
||||
:param parsers:
|
||||
:param who: who is asking the parsing ?
|
||||
:param prop: Extra info, when parsing a property
|
||||
:param filter_func: Once the result are found, call this function to filter them
|
||||
:return:
|
||||
"""
|
||||
sheerka = context.sheerka
|
||||
|
||||
if prop:
|
||||
action_context = {"prop": prop, "source": source}
|
||||
desc = f"Parsing attribute '{prop}'"
|
||||
else:
|
||||
action_context = source
|
||||
desc = f"Parsing '{source}'"
|
||||
|
||||
with context.push(BuiltinConcepts.PARSING, action_context, who=who, desc=desc) as sub_context:
|
||||
# disable all parsers but the requested ones
|
||||
if parsers != "all":
|
||||
sub_context.preprocess_parsers = parsers
|
||||
# sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
|
||||
# for parser in parsers:
|
||||
# sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
|
||||
|
||||
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE, Keywords.WHEN):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
sub_context.add_inputs(source=source)
|
||||
to_parse = sheerka.ret(context.who,
|
||||
True,
|
||||
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
|
||||
res = sheerka.execute(sub_context, to_parse, PARSE_STEPS)
|
||||
|
||||
if filter_func:
|
||||
res = filter_func(sub_context, res)
|
||||
|
||||
sub_context.add_values(return_values=res)
|
||||
return res
|
||||
|
||||
|
||||
def parse_function(context, source, tokens=None, start=0):
|
||||
"""
|
||||
Helper function that parses what is supposed to be a function
|
||||
:param context:
|
||||
:param source:
|
||||
:param tokens:
|
||||
:param start: start index for the source code node
|
||||
:return:
|
||||
"""
|
||||
sheerka = context.sheerka
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
parser = FunctionParser()
|
||||
desc = f"Parsing function '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE, source, desc=desc) as sub_context:
|
||||
sheerka_execution = sheerka.services[SheerkaExecute.NAME]
|
||||
res = parser.parse(sub_context, sheerka_execution.get_parser_input(source, tokens))
|
||||
|
||||
if not isinstance(res, list):
|
||||
res = [res]
|
||||
|
||||
for r in [r for r in res if sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT)]:
|
||||
r.body.body.start += start
|
||||
r.body.body.end += start
|
||||
if isinstance(r.body.body, SourceCodeWithConceptNode):
|
||||
for n in [r.body.body.first, r.body.body.last] + r.body.body.nodes:
|
||||
n.start += start
|
||||
n.end += start
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def parse_python(context, source, desc=None):
|
||||
"""
|
||||
Helper function that parses what is known to be Python source code
|
||||
:param context:
|
||||
:param source:
|
||||
:param desc: option description when creating the sub context
|
||||
"""
|
||||
desc = desc or f"Compiling python '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE,
|
||||
{"language": "Python", "source": source},
|
||||
desc) as sub_context:
|
||||
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
|
||||
python_parser = PythonParser()
|
||||
return python_parser.parse(sub_context, parser_input)
|
||||
|
||||
|
||||
def parse_expression(context, source, desc=None):
|
||||
"""
|
||||
Helper function to parser expressions with AND, OR and NOT
|
||||
"""
|
||||
desc = desc or f"Parsing expression '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE, source, desc) as sub_context:
|
||||
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
expr_parser = ExpressionParser()
|
||||
return expr_parser.parse(sub_context, parser_input)
|
||||
|
||||
|
||||
def evaluate(context,
|
||||
source,
|
||||
evaluators="all",
|
||||
@@ -588,7 +482,7 @@ def get_lexer_nodes_from_unrecognized(context, unrecognized_tokens_node, parsers
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = parse_unrecognized(context, unrecognized_tokens_node.source, parsers)
|
||||
res = context.sheerka.parse_unrecognized(context, unrecognized_tokens_node.source, parsers)
|
||||
res = only_parsers_results(context, res)
|
||||
|
||||
if not res.status:
|
||||
@@ -633,7 +527,7 @@ def update_compiled(context, concept, errors, parsers=None):
|
||||
errors.append(sheerka.new(BuiltinConcepts.ERROR, body=f"Cannot parse '{v.source}'"))
|
||||
|
||||
elif isinstance(v, UnrecognizedTokensNode):
|
||||
res = parse_unrecognized(context, v.source, parsers)
|
||||
res = context.sheerka.parse_unrecognized(context, v.source, parsers)
|
||||
res = only_successful(context, res) # only key successful parsers
|
||||
if res.status:
|
||||
c.get_compiled()[k] = res.body.body
|
||||
@@ -830,11 +724,7 @@ def is_a_question(context, concept):
|
||||
if pre in (None, NotInit, ""):
|
||||
return False
|
||||
|
||||
parser_input_service = context.sheerka.services[SheerkaExecute.NAME]
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
parser = ExpressionParser()
|
||||
|
||||
res = parser.parse(context, parser_input_service.get_parser_input(pre))
|
||||
res = context.sheerka.parse_expression(context, pre)
|
||||
if not res.status:
|
||||
return False
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ EVENT_ONTOLOGY_DELETED = "evt_o_d"
|
||||
RULE_COMPARISON_CONTEXT = "Rule"
|
||||
CONCEPT_COMPARISON_CONTEXT = "Sya"
|
||||
|
||||
NO_MATCH = "** No Match **"
|
||||
|
||||
|
||||
class CustomType:
|
||||
|
||||
|
||||
@@ -83,6 +83,10 @@ class Rule:
|
||||
copy.metadata.id_is_unresolved = self.metadata.id_is_unresolved
|
||||
# copy.error_sink = self.error_sink # Uncomment this line if necessary
|
||||
|
||||
copy.rete_net = self.rete_net
|
||||
copy.rete_p_nodes = self.rete_p_nodes
|
||||
copy.rete_disjunctions = self.rete_disjunctions
|
||||
|
||||
return copy
|
||||
|
||||
def __copy__(self):
|
||||
|
||||
@@ -4,8 +4,7 @@ import time
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept
|
||||
from core.concept import Concept, get_concept_attrs
|
||||
from core.global_symbols import EVENT_CONTEXT_DISPOSED
|
||||
from core.sheerka.services.SheerkaExecute import NO_MATCH
|
||||
from core.global_symbols import EVENT_CONTEXT_DISPOSED, NO_MATCH
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
from core.utils import CONSOLE_COLORS_MAP as CCM, CONSOLE_COLUMNS
|
||||
from sdp.sheerkaDataProvider import Event
|
||||
|
||||
@@ -6,7 +6,6 @@ from operator import attrgetter
|
||||
import core.builtin_helpers
|
||||
import core.utils
|
||||
from cache.Cache import Cache
|
||||
from cache.DictionaryCache import DictionaryCache
|
||||
from cache.IncCache import IncCache
|
||||
from core.builtin_concepts import ErrorConcept, ReturnValueConcept, UnknownConcept
|
||||
from core.builtin_concepts_ids import BuiltinErrors, BuiltinConcepts
|
||||
@@ -66,9 +65,6 @@ class Sheerka(Concept):
|
||||
CONCEPTS_BY_ID_ENTRY = "ConceptManager:Concepts_By_ID"
|
||||
CONCEPTS_BY_NAME_ENTRY = "ConceptManager:Concepts_By_Name"
|
||||
|
||||
CONCEPTS_SYA_DEFINITION_ENTRY = "Concepts_Sya_Definitions"
|
||||
RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY = "Resolved_Concepts_Sya_Definitions"
|
||||
CONCEPTS_GRAMMARS_ENTRY = "Concepts_Grammars"
|
||||
CHICKEN_AND_EGG_CONCEPTS_ENTRY = "Chicken_And_Egg_Concepts"
|
||||
|
||||
OBJECTS_IDS_ENTRY = "Objects_Ids"
|
||||
@@ -119,7 +115,6 @@ class Sheerka(Concept):
|
||||
"test_error": SheerkaMethod(self.test_error, False),
|
||||
}
|
||||
|
||||
self.locals = {}
|
||||
self.concepts_ids = None
|
||||
|
||||
def __copy__(self):
|
||||
@@ -128,13 +123,6 @@ class Sheerka(Concept):
|
||||
def __deepcopy__(self, memodict={}):
|
||||
return self
|
||||
|
||||
@property
|
||||
def concepts_grammars(self):
|
||||
"""
|
||||
Quick access to BNF grammars
|
||||
"""
|
||||
return self.om.current_cache_manager().caches[self.CONCEPTS_GRAMMARS_ENTRY].cache
|
||||
|
||||
@property
|
||||
def chicken_and_eggs(self):
|
||||
return self.om.current_cache_manager().caches[self.CHICKEN_AND_EGG_CONCEPTS_ENTRY].cache
|
||||
@@ -237,16 +225,6 @@ class Sheerka(Concept):
|
||||
cache = IncCache().auto_configure(self.OBJECTS_IDS_ENTRY)
|
||||
self.om.register_cache(self.OBJECTS_IDS_ENTRY, cache)
|
||||
|
||||
cache = DictionaryCache().auto_configure(self.CONCEPTS_SYA_DEFINITION_ENTRY)
|
||||
self.om.register_cache(self.CONCEPTS_SYA_DEFINITION_ENTRY, cache)
|
||||
self.om.get(self.CONCEPTS_SYA_DEFINITION_ENTRY, None) # to init from sdp
|
||||
|
||||
cache = DictionaryCache().auto_configure(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY)
|
||||
self.om.register_cache(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY, cache, persist=False)
|
||||
|
||||
cache = Cache().auto_configure(self.CONCEPTS_GRAMMARS_ENTRY)
|
||||
self.om.register_cache(self.CONCEPTS_GRAMMARS_ENTRY, cache, persist=False)
|
||||
|
||||
cache = Cache().auto_configure(self.CHICKEN_AND_EGG_CONCEPTS_ENTRY)
|
||||
self.om.register_cache(self.CHICKEN_AND_EGG_CONCEPTS_ENTRY, cache, persist=False)
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from cache.SetCache import SetCache
|
||||
from core.concept import copy_concepts_attrs, load_concepts_attrs
|
||||
from core.global_symbols import NotFound, Removed, EVENT_CONCEPT_CREATED, EVENT_CONCEPT_DELETED, EVENT_RULE_CREATED, \
|
||||
EVENT_RULE_DELETED, EVENT_CONCEPT_ID_DELETED, EVENT_RULE_ID_DELETED
|
||||
from core.utils import sheerka_deepcopy
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProvider
|
||||
|
||||
|
||||
@@ -83,7 +82,6 @@ class Ontology:
|
||||
self.cache_manager = cache_manager
|
||||
self.alt_sdp = alt_sdp
|
||||
self.concepts_attributes = None
|
||||
self.local_variables = None
|
||||
|
||||
def __repr__(self):
|
||||
return f"Ontology('{self.name}')"
|
||||
@@ -253,13 +251,10 @@ class SheerkaOntologyManager:
|
||||
"""
|
||||
# TODO persist these information ?
|
||||
self.current_ontology().concepts_attributes = copy_concepts_attrs()
|
||||
self.current_ontology().local_variables = sheerka_deepcopy(self.sheerka.locals)
|
||||
|
||||
def reset_sheerka_state(self):
|
||||
if self.current_ontology().concepts_attributes is not None:
|
||||
load_concepts_attrs(self.current_ontology().concepts_attributes)
|
||||
if self.current_ontology().local_variables is not None:
|
||||
self.sheerka.locals = self.current_ontology().local_variables
|
||||
|
||||
def current_cache_manager(self) -> CacheManager:
|
||||
return self.ontologies[0].cache_manager
|
||||
|
||||
@@ -5,6 +5,7 @@ from os import path
|
||||
from core.builtin_concepts_ids import BuiltinConcepts, BuiltinContainers
|
||||
from core.builtin_helpers import ensure_concept_or_rule
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaHistoryManager import SheerkaHistoryManager
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
|
||||
@@ -33,6 +34,7 @@ class SheerkaAdmin(BaseService):
|
||||
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")
|
||||
|
||||
def caches_names(self):
|
||||
"""
|
||||
@@ -214,3 +216,7 @@ class SheerkaAdmin(BaseService):
|
||||
res[k] = obj.obj
|
||||
|
||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.TO_DICT, body=res))
|
||||
|
||||
def admin_history(self, depth=10, start=0):
|
||||
history = self.sheerka.services[SheerkaHistoryManager.NAME].history(depth, start)
|
||||
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=history)
|
||||
|
||||
@@ -98,6 +98,8 @@ class SheerkaConceptManager(BaseService):
|
||||
CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "ConceptManager:Concepts_By_First_Keyword"
|
||||
RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "ConceptManager:Resolved_Concepts_By_First_Keyword"
|
||||
|
||||
CONCEPTS_BNF_DEFINITIONS_ENTRY = "ConceptManager:Concepts_BNF_Definitions"
|
||||
|
||||
def __init__(self, sheerka):
|
||||
super().__init__(sheerka, order=11)
|
||||
self.forbidden_meta = {"is_builtin", "key", "id", "props", "variables"}
|
||||
@@ -117,6 +119,8 @@ class SheerkaConceptManager(BaseService):
|
||||
self.sheerka.bind_service_method(self.get_by_id, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.is_not_a_variable, 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_bnf_definitions, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.clear_bnf_definition, True, visible=False)
|
||||
|
||||
register_concept_cache = self.sheerka.om.register_concept_cache
|
||||
|
||||
@@ -141,6 +145,9 @@ class SheerkaConceptManager(BaseService):
|
||||
cache = DictionaryCache().auto_configure(self.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY)
|
||||
self.sheerka.om.register_cache(self.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, cache, persist=False)
|
||||
|
||||
cache = Cache().auto_configure(self.CONCEPTS_BNF_DEFINITIONS_ENTRY)
|
||||
self.sheerka.om.register_cache(self.CONCEPTS_BNF_DEFINITIONS_ENTRY, cache, persist=False)
|
||||
|
||||
def initialize_deferred(self, context, is_first_time):
|
||||
if is_first_time:
|
||||
self.sheerka.om.put(self.sheerka.OBJECTS_IDS_ENTRY, self.USER_CONCEPTS_IDS, 1000)
|
||||
@@ -244,7 +251,7 @@ class SheerkaConceptManager(BaseService):
|
||||
# TODO : this line seems to be useless
|
||||
# The grammar is never reset
|
||||
if concept.get_bnf() and init_bnf_ret_value is not None and init_bnf_ret_value.status:
|
||||
sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY)
|
||||
sheerka.cache_manager.clear(self.CONCEPTS_BNF_DEFINITIONS_ENTRY)
|
||||
|
||||
# publish the new concept
|
||||
sheerka.publish(context, EVENT_CONCEPT_CREATED, concept)
|
||||
@@ -509,7 +516,7 @@ class SheerkaConceptManager(BaseService):
|
||||
|
||||
for concept_id in refs:
|
||||
# remove the grammar entry so that it can be recreated
|
||||
self.sheerka.om.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_id)
|
||||
self.sheerka.om.delete(self.CONCEPTS_BNF_DEFINITIONS_ENTRY, concept_id)
|
||||
|
||||
# reset the bnf definition if needed
|
||||
if modified_concept:
|
||||
@@ -559,6 +566,12 @@ class SheerkaConceptManager(BaseService):
|
||||
"""
|
||||
return self.sheerka.om.get(self.sheerka.CONCEPTS_BY_NAME_ENTRY, name) is NotFound
|
||||
|
||||
def clear_bnf_definition(self, concept_id=None):
|
||||
if concept_id:
|
||||
self.sheerka.om.delete(self.CONCEPTS_BNF_DEFINITIONS_ENTRY, concept_id)
|
||||
else:
|
||||
self.sheerka.om.clear(self.CONCEPTS_BNF_DEFINITIONS_ENTRY)
|
||||
|
||||
@staticmethod
|
||||
def _name_has_changed(to_add):
|
||||
if to_add is None or "meta" not in to_add:
|
||||
@@ -839,3 +852,6 @@ class SheerkaConceptManager(BaseService):
|
||||
|
||||
return core.utils.make_unique(result + custom_concepts,
|
||||
lambda c: c.concept.id if hasattr(c, "concept") else c.id)
|
||||
|
||||
def get_concepts_bnf_definitions(self):
|
||||
return self.sheerka.om.current_cache_manager().caches[self.CONCEPTS_BNF_DEFINITIONS_ENTRY].cache
|
||||
|
||||
@@ -280,6 +280,9 @@ class DebugItem:
|
||||
class SheerkaDebugManager(BaseService):
|
||||
NAME = "Debug"
|
||||
PREFIX = "debug."
|
||||
VARS_DEBUG_TYPE = "vars"
|
||||
RULES_DEBUG_TYPE = "rules"
|
||||
CONCEPTS_DEBUG_TYPE = "concepts"
|
||||
|
||||
children_activation_regex = re.compile(r"(\d+)\+")
|
||||
|
||||
@@ -292,6 +295,10 @@ class SheerkaDebugManager(BaseService):
|
||||
self.debug_vars_settings = []
|
||||
self.debug_rules_settings = []
|
||||
self.debug_concepts_settings = []
|
||||
self.registered_vars = [] # list of all variables that can be debugged
|
||||
self.registered_rules = [] # list of all rules that can be debugged
|
||||
self.registered_concepts = [] # list of all concept that can be debugged
|
||||
|
||||
self.state_vars = [
|
||||
"activated",
|
||||
"explicit", # to remove ?
|
||||
@@ -302,16 +309,43 @@ class SheerkaDebugManager(BaseService):
|
||||
"debug_concepts_settings"
|
||||
]
|
||||
|
||||
self.item_name = {
|
||||
self.VARS_DEBUG_TYPE: "variable",
|
||||
self.RULES_DEBUG_TYPE: "rule",
|
||||
self.CONCEPTS_DEBUG_TYPE: "concept",
|
||||
}
|
||||
|
||||
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_debugger, False)
|
||||
self.sheerka.bind_service_method(self.reset_debug, False)
|
||||
self.sheerka.bind_service_method(self.debug_var, True)
|
||||
self.sheerka.bind_service_method(self.debug_rule, True)
|
||||
self.sheerka.bind_service_method(self.debug_concept, True)
|
||||
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.get_debug_settings, False, as_name="debug_settings")
|
||||
# register what can be registered
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from evaluators.DefConceptEvaluator import DefConceptEvaluator
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
self.register_debug_vars(BnfNodeParser.NAME, "parse", "result")
|
||||
self.register_debug_concepts(BnfNodeParser.NAME, "parse", "*")
|
||||
self.register_debug_vars(DefConceptEvaluator.NAME, "matches", "*")
|
||||
self.register_debug_vars(DefConceptEvaluator.NAME, "eval", "*")
|
||||
self.register_debug_vars(DefConceptEvaluator.NAME, "get_variables", "names")
|
||||
self.register_debug_vars(PythonEvaluator.NAME, "eval", "globals")
|
||||
self.register_debug_vars(PythonEvaluator.NAME, "eval", "ret")
|
||||
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "exception")
|
||||
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "trace")
|
||||
self.register_debug_vars(SyaNodeParser.NAME, "parse", "*")
|
||||
|
||||
def initialize_deferred(self, context, is_first_time):
|
||||
self.restore_state()
|
||||
@@ -334,6 +368,124 @@ class SheerkaDebugManager(BaseService):
|
||||
def restore_state(self):
|
||||
self.restore_values(*self.state_vars)
|
||||
|
||||
def register_debug(self, item_type, service, method, item):
|
||||
"""
|
||||
Register a debug item, in order to east their discovery
|
||||
:param item_type:
|
||||
:param service:
|
||||
:param method:
|
||||
:param item:
|
||||
:return:
|
||||
"""
|
||||
if item_type == self.VARS_DEBUG_TYPE:
|
||||
self.registered_vars.append((service, method, item))
|
||||
elif item_type == self.RULES_DEBUG_TYPE:
|
||||
self.registered_rules.append((service, method, item))
|
||||
elif item_type == self.CONCEPTS_DEBUG_TYPE:
|
||||
self.registered_concepts.append((service, method, item))
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
def register_debug_vars(self, service, method, item):
|
||||
return self.register_debug(self.VARS_DEBUG_TYPE, service, method, item)
|
||||
|
||||
def register_debug_rules(self, service, method, item):
|
||||
return self.register_debug(self.RULES_DEBUG_TYPE, service, method, item)
|
||||
|
||||
def register_debug_concepts(self, service, method, item):
|
||||
return self.register_debug(self.CONCEPTS_DEBUG_TYPE, service, method, item)
|
||||
|
||||
def filter_registered_debug(self, item_type, pattern=None, **kwargs):
|
||||
"""
|
||||
Filter the list of the debug item
|
||||
:param pattern:
|
||||
:param item_type:
|
||||
:return:
|
||||
"""
|
||||
item_name = self.item_name[item_type]
|
||||
service, method_name, item = "*", "*", "*"
|
||||
|
||||
if pattern:
|
||||
tokens = pattern.split(".")
|
||||
service = tokens[0]
|
||||
method_name = "*"
|
||||
item = "*"
|
||||
if len(tokens) > 1:
|
||||
method_name = tokens[1]
|
||||
if len(tokens) > 2:
|
||||
item = tokens[2]
|
||||
|
||||
# override with kwargs
|
||||
service = kwargs.get("service", service)
|
||||
method_name = kwargs.get("method", method_name)
|
||||
item = kwargs.get(item_name, item)
|
||||
|
||||
if item_type == self.VARS_DEBUG_TYPE:
|
||||
lst = self.registered_vars
|
||||
elif item_type == self.RULES_DEBUG_TYPE:
|
||||
lst = self.registered_rules
|
||||
elif item_type == self.CONCEPTS_DEBUG_TYPE:
|
||||
lst = self.registered_concepts
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
for registered in lst:
|
||||
if service != "*" and service != registered[0]:
|
||||
continue
|
||||
if method_name != "*" and method_name != registered[1]:
|
||||
continue
|
||||
if item != "*" and item != registered[2]:
|
||||
continue
|
||||
yield registered
|
||||
|
||||
def list_registered(self, item_type, pattern=None, **kwargs):
|
||||
"""
|
||||
Return a formatted list of available registered debug items
|
||||
:param item_type:
|
||||
:param pattern:
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
pattern = pattern.strip() if pattern is not None else None
|
||||
lst = self.filter_registered_debug(item_type, pattern, **kwargs)
|
||||
|
||||
# for (service, method, item_name)
|
||||
# level == 1 -> print 'service'
|
||||
# level == 2 -> print 'service.method'
|
||||
# level == 2 -> print 'service.method.item_name'
|
||||
if pattern:
|
||||
if not pattern.endswith(".*"):
|
||||
pattern += ".*"
|
||||
tokens = pattern.split(".")
|
||||
level = len(tokens)
|
||||
else:
|
||||
level = 1
|
||||
|
||||
if "service" in kwargs.keys():
|
||||
level = 2
|
||||
elif {"method", "variable", "rule", "concept"}.intersection(set(kwargs.keys())):
|
||||
level = 3
|
||||
|
||||
res = set()
|
||||
for filtered in lst:
|
||||
if level == 1:
|
||||
res.add(filtered[0])
|
||||
elif level == 2:
|
||||
res.add(f"{filtered[0]}.{filtered[1]}")
|
||||
else:
|
||||
res.add(f"{filtered[0]}.{filtered[1]}.{filtered[2]}")
|
||||
|
||||
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=sorted(res))
|
||||
|
||||
def list_debug_vars(self, pattern=None, **kwargs):
|
||||
return self.list_registered(self.VARS_DEBUG_TYPE, pattern, **kwargs)
|
||||
|
||||
def list_debug_rules(self, pattern=None, **kwargs):
|
||||
return self.list_registered(self.RULES_DEBUG_TYPE, pattern, **kwargs)
|
||||
|
||||
def list_debug_concepts(self, pattern=None, **kwargs):
|
||||
return self.list_registered(self.CONCEPTS_DEBUG_TYPE, pattern, **kwargs)
|
||||
|
||||
def set_debug(self, context, value=True):
|
||||
self.activated = value
|
||||
self.sheerka.record_var(context, self.NAME, "activated", self.activated)
|
||||
@@ -491,7 +643,7 @@ class SheerkaDebugManager(BaseService):
|
||||
|
||||
return self.sheerka.ret(SheerkaDebugManager.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
def debug_var(self, context, *args, **kwargs):
|
||||
def set_debug_var(self, context, *args, **kwargs):
|
||||
"""
|
||||
Adds debug item for variables
|
||||
debug_var(<service>.<method>.<var>, <context_id>[+], <debug_id>)
|
||||
@@ -504,7 +656,7 @@ class SheerkaDebugManager(BaseService):
|
||||
i, s, m, c_id, c_children, d, e = self.parse_debug_args("variable", *args, **kwargs)
|
||||
return self.add_or_update_debug_item(context, "vars", i, s, m, c_id, c_children, d, False, e)
|
||||
|
||||
def debug_rule(self, context, *args, **kwargs):
|
||||
def set_debug_rule(self, context, *args, **kwargs):
|
||||
"""
|
||||
Adds debug item for rules
|
||||
debug_var(<service>.<method>.<rule>, <context_id>[+], <debug_id>)
|
||||
@@ -518,7 +670,7 @@ class SheerkaDebugManager(BaseService):
|
||||
i, s, m, c_id, c_children, d, e = self.parse_debug_args("rule", *args, **kwargs)
|
||||
return self.add_or_update_debug_item(context, "rules", i, s, m, c_id, c_children, d, False, e)
|
||||
|
||||
def debug_concept(self, context, *args, **kwargs):
|
||||
def set_debug_concept(self, context, *args, **kwargs):
|
||||
"""
|
||||
Adds debug item for concepts
|
||||
debug_var(<service>.<method>.<concept>, <context_id>[+], <debug_id>)
|
||||
@@ -546,7 +698,7 @@ class SheerkaDebugManager(BaseService):
|
||||
Print
|
||||
:param context:
|
||||
:param args: 1st parameter is what to display, the other are the properties to display
|
||||
:param kwargs: how to display the result
|
||||
:param kwargs: how to display the result (as_bag=True, values=True)
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import expect_one, only_successful, parse_unrecognized, evaluate, ensure_concept
|
||||
from core.builtin_helpers import expect_one, only_successful, evaluate, ensure_concept
|
||||
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, AllConceptParts, \
|
||||
concept_part_value
|
||||
from core.global_symbols import NotInit
|
||||
@@ -282,7 +282,7 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
:return:
|
||||
"""
|
||||
while True:
|
||||
return_value = parse_unrecognized(current_context,
|
||||
return_value = current_context.sheerka.parse_unrecognized(current_context,
|
||||
s,
|
||||
parsers="all",
|
||||
prop=p,
|
||||
|
||||
@@ -26,6 +26,11 @@ class SheerkaEvaluateRules(BaseService):
|
||||
self.sheerka.subscribe(EVENT_RULE_DELETED, self.on_rule_deleted)
|
||||
self.sheerka.subscribe(EVENT_RULE_ID_DELETED, self.on_rule_deleted)
|
||||
|
||||
self.sheerka.register_debug_vars(self.NAME, "evaluate_rules", "results")
|
||||
self.sheerka.register_debug_rules(self.NAME, "evaluate_rule", "*")
|
||||
|
||||
|
||||
|
||||
def reset_evaluators(self):
|
||||
# instantiate evaluators, once for all, only keep when it's enabled
|
||||
evaluators = [e_class() for e_class in self.sheerka.evaluators]
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
import core.utils
|
||||
from cache.FastCache import FastCache
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
||||
from core.global_symbols import NotFound
|
||||
from core.concept import ConceptParts
|
||||
from core.global_symbols import NotFound, NO_MATCH
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
from core.tokenizer import Tokenizer, TokenKind, Token
|
||||
from core.tokenizer import Tokenizer, TokenKind, Token, Keywords
|
||||
|
||||
NO_MATCH = "** No Match **"
|
||||
EVALUATOR_STEPS = [
|
||||
BuiltinConcepts.BEFORE_PARSING,
|
||||
BuiltinConcepts.AFTER_PARSING,
|
||||
BuiltinConcepts.BEFORE_EVALUATION,
|
||||
PARSE_STEPS = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
|
||||
PARSE_AND_EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION,
|
||||
BuiltinConcepts.EVALUATION,
|
||||
BuiltinConcepts.AFTER_EVALUATION,
|
||||
BuiltinConcepts.BEFORE_RENDERING,
|
||||
BuiltinConcepts.AFTER_EVALUATION]
|
||||
ALL_STEPS = PARSE_AND_EVAL_STEPS + [BuiltinConcepts.BEFORE_RENDERING,
|
||||
BuiltinConcepts.RENDERING,
|
||||
BuiltinConcepts.AFTER_RENDERING,
|
||||
BuiltinConcepts.BEFORE_RULES_EVALUATION,
|
||||
BuiltinConcepts.AFTER_RULES_EVALUATION,
|
||||
]
|
||||
BuiltinConcepts.AFTER_RULES_EVALUATION]
|
||||
|
||||
|
||||
class ParserInput:
|
||||
@@ -173,14 +170,15 @@ class SheerkaExecute(BaseService):
|
||||
|
||||
def __init__(self, sheerka):
|
||||
# order must be after SheerkaEvaluateRules because of self.rules_evaluation_service
|
||||
super().__init__(sheerka, order=5)
|
||||
# order must be after ConceptManager because it needs concept bnf definitions
|
||||
super().__init__(sheerka, order=15)
|
||||
self.pi_cache = FastCache(default=lambda key: ParserInput(key), max_size=20)
|
||||
self.instantiated_evaluators = None
|
||||
self.evaluators_by_name = None
|
||||
|
||||
self.instantiated_parsers = None
|
||||
self.parsers_by_name = None
|
||||
self.old_values = []
|
||||
self.preprocessed_items_old_values = []
|
||||
|
||||
# cache for all preregistered evaluator combination
|
||||
# the key is the concatenation of the step and the name of evaluators in the group
|
||||
@@ -202,6 +200,10 @@ class SheerkaExecute(BaseService):
|
||||
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.reset_registered_evaluators()
|
||||
self.reset_registered_parsers()
|
||||
@@ -219,7 +221,7 @@ class SheerkaExecute(BaseService):
|
||||
self.evaluators_by_name = {e.short_name: e for e in self.instantiated_evaluators}
|
||||
|
||||
# get default evaluators by process step
|
||||
for process_step in EVALUATOR_STEPS:
|
||||
for process_step in ALL_STEPS:
|
||||
self.grouped_evaluators_cache[f"{process_step}|__default"] = self.get_grouped(
|
||||
[e for e in self.instantiated_evaluators if process_step in e.steps])
|
||||
|
||||
@@ -270,7 +272,7 @@ class SheerkaExecute(BaseService):
|
||||
if var_name == "preprocess_name":
|
||||
continue
|
||||
if hasattr(item, var_name):
|
||||
self.old_values.append((item, var_name, getattr(item, var_name)))
|
||||
self.preprocessed_items_old_values.append((item, var_name, getattr(item, var_name)))
|
||||
setattr(item, var_name, value)
|
||||
|
||||
def get_evaluators(self, context, process_step):
|
||||
@@ -319,29 +321,23 @@ class SheerkaExecute(BaseService):
|
||||
for priority, parsers_classes in from_cache[0].items()}
|
||||
return grouped_instances, from_cache[1]
|
||||
|
||||
# Normal case, use all registered parsers
|
||||
if not context.preprocess_parsers and not context.preprocess:
|
||||
return get_instances(self.grouped_parsers_cache["__default"])
|
||||
|
||||
# Other case, only use a subset of parsers
|
||||
# This case is heavily used by lexer node parsers, thru parse_unrecognized
|
||||
if context.preprocess_parsers and not context.preprocess:
|
||||
key = "|".join(context.preprocess_parsers)
|
||||
key = self.get_parsers_key(context)
|
||||
if key:
|
||||
try:
|
||||
return get_instances(self.grouped_parsers_cache[key])
|
||||
return key, *get_instances(self.grouped_parsers_cache[key])
|
||||
except KeyError:
|
||||
parsers = [self.parsers_by_name[p] for p in context.preprocess_parsers if p in self.parsers_by_name]
|
||||
self.grouped_parsers_cache[key] = self.get_grouped(parsers, use_classes=True)
|
||||
return get_instances(self.grouped_parsers_cache[key])
|
||||
return key, *get_instances(self.grouped_parsers_cache[key])
|
||||
|
||||
# final case, parsers attributes are modified by the context
|
||||
# else, case where parsers attributes are modified by the context
|
||||
# This a the case when we want to disable a specific parser, or change the order of priority
|
||||
parsers = [self.parsers_by_name[p] for p in context.preprocess_parsers if p in self.parsers_by_name] \
|
||||
if context.preprocess_parsers else self.instantiated_parsers
|
||||
self.preprocess(parsers, context.preprocess)
|
||||
parsers = [p for p in parsers if p.enabled] # only keep those that are still enabled
|
||||
groups, sorted_priorities = self.get_grouped(parsers, use_classes=True)
|
||||
return get_instances((groups, sorted_priorities))
|
||||
return key, *get_instances((groups, sorted_priorities))
|
||||
|
||||
def get_parser_input(self, text, tokens=None):
|
||||
"""
|
||||
@@ -366,6 +362,22 @@ class SheerkaExecute(BaseService):
|
||||
self.pi_cache.put(key, pi)
|
||||
return pi
|
||||
|
||||
@staticmethod
|
||||
def get_parsers_key(context):
|
||||
"""
|
||||
From the context.preprocess_parsers and context.preprocess,
|
||||
try to find a key to store the further results of the parsings
|
||||
:param context:
|
||||
:return:
|
||||
"""
|
||||
if not context.preprocess_parsers and not context.preprocess:
|
||||
return "__default"
|
||||
|
||||
if context.preprocess_parsers and not context.preprocess:
|
||||
return "|".join(context.preprocess_parsers)
|
||||
|
||||
return None
|
||||
|
||||
def call_parsers(self, context, return_values):
|
||||
"""
|
||||
Call all the parsers, ordered by priority
|
||||
@@ -398,7 +410,7 @@ class SheerkaExecute(BaseService):
|
||||
# keep track of the originals user inputs, as they need to be removed at the end
|
||||
user_inputs = to_process[:]
|
||||
|
||||
grouped_parsers, sorted_priorities = self.get_parsers(context)
|
||||
parsers_key, grouped_parsers, sorted_priorities = self.get_parsers(context)
|
||||
|
||||
stop_processing = False
|
||||
for priority in sorted_priorities:
|
||||
@@ -644,10 +656,10 @@ class SheerkaExecute(BaseService):
|
||||
return return_values
|
||||
|
||||
def undo_preprocess(self):
|
||||
for item, var_name, value in self.old_values:
|
||||
for item, var_name, value in self.preprocessed_items_old_values:
|
||||
setattr(item, var_name, value)
|
||||
|
||||
self.old_values.clear()
|
||||
self.preprocessed_items_old_values.clear()
|
||||
|
||||
@staticmethod
|
||||
def matches(parser_or_evaluator_name, preprocessor_name):
|
||||
@@ -655,3 +667,107 @@ class SheerkaExecute(BaseService):
|
||||
return parser_or_evaluator_name.startswith(preprocessor_name[:-1])
|
||||
else:
|
||||
return parser_or_evaluator_name == preprocessor_name
|
||||
|
||||
def parse_unrecognized(self, context, source, parsers, who=None, prop=None, filter_func=None):
|
||||
"""
|
||||
Try to recognize concepts or code from source using the given parsers
|
||||
:param context:
|
||||
:param source: ParserInput if possible
|
||||
:param parsers:
|
||||
:param who: who is asking the parsing ?
|
||||
:param prop: Extra info, when parsing a property
|
||||
:param filter_func: Once the result are found, call this function to filter them
|
||||
:return:
|
||||
"""
|
||||
sheerka = context.sheerka
|
||||
|
||||
if prop:
|
||||
action_context = {"prop": prop, "source": source}
|
||||
desc = f"Parsing attribute '{prop}'"
|
||||
else:
|
||||
action_context = source
|
||||
desc = f"Parsing '{source}'"
|
||||
|
||||
with context.push(BuiltinConcepts.PARSING, action_context, who=who, desc=desc) as sub_context:
|
||||
# disable all parsers but the requested ones
|
||||
if parsers != "all":
|
||||
sub_context.preprocess_parsers = parsers
|
||||
# sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
|
||||
# for parser in parsers:
|
||||
# sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
|
||||
|
||||
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE, Keywords.WHEN):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
sub_context.add_inputs(source=source)
|
||||
to_parse = sheerka.ret(context.who,
|
||||
True,
|
||||
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
|
||||
res = sheerka.execute(sub_context, to_parse, PARSE_STEPS)
|
||||
|
||||
if filter_func:
|
||||
res = filter_func(sub_context, res)
|
||||
|
||||
sub_context.add_values(return_values=res)
|
||||
return res
|
||||
|
||||
def parse_function(self, context, source, tokens=None, start=0):
|
||||
"""
|
||||
Helper function that parses what is supposed to be a function
|
||||
:param context:
|
||||
:param source:
|
||||
:param tokens:
|
||||
:param start: start index for the source code node
|
||||
:return:
|
||||
"""
|
||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode
|
||||
|
||||
sheerka = context.sheerka
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
parser = FunctionParser()
|
||||
desc = f"Parsing function '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE, source, desc=desc) as sub_context:
|
||||
sheerka_execution = sheerka.services[SheerkaExecute.NAME]
|
||||
res = parser.parse(sub_context, sheerka_execution.get_parser_input(source, tokens))
|
||||
|
||||
if not isinstance(res, list):
|
||||
res = [res]
|
||||
|
||||
for r in [r for r in res if sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT)]:
|
||||
r.body.body.start += start
|
||||
r.body.body.end += start
|
||||
|
||||
if isinstance(r.body.body, SourceCodeWithConceptNode):
|
||||
for n in [r.body.body.first, r.body.body.last] + r.body.body.nodes:
|
||||
n.start += start
|
||||
n.end += start
|
||||
|
||||
return res
|
||||
|
||||
def parse_python(self, context, source, desc=None):
|
||||
"""
|
||||
Helper function that parses what is known to be Python source code
|
||||
:param context:
|
||||
:param source:
|
||||
:param desc: option description when creating the sub context
|
||||
"""
|
||||
from parsers.PythonParser import PythonParser
|
||||
|
||||
desc = desc or f"Compiling python '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE,
|
||||
{"language": "Python", "source": source},
|
||||
desc) as sub_context:
|
||||
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
|
||||
python_parser = PythonParser()
|
||||
return python_parser.parse(sub_context, parser_input)
|
||||
|
||||
def parse_expression(self, context, source, desc=None):
|
||||
"""
|
||||
Helper function to parser expressions with AND, OR and NOT
|
||||
"""
|
||||
desc = desc or f"Parsing expression '{source}'"
|
||||
with context.push(BuiltinConcepts.PARSE_CODE, source, desc) as sub_context:
|
||||
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
expr_parser = ExpressionParser()
|
||||
return expr_parser.parse(sub_context, parser_input)
|
||||
|
||||
@@ -35,6 +35,9 @@ class History:
|
||||
|
||||
return self.event == other.event and self.result == other.result
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.event, self.result, self.status))
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
if self._status:
|
||||
@@ -56,9 +59,6 @@ class SheerkaHistoryManager(BaseService):
|
||||
def __init__(self, sheerka):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.history, False)
|
||||
|
||||
def history(self, depth=10, start=0):
|
||||
"""
|
||||
Load history
|
||||
|
||||
@@ -90,7 +90,7 @@ class SheerkaIsAManager(BaseService):
|
||||
self.sheerka.services[SheerkaConceptManager.NAME].update_references(context, concept_set)
|
||||
|
||||
# remove the grammar entry so that it can be recreated
|
||||
self.sheerka.om.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_set.id)
|
||||
self.sheerka.clear_bnf_definition(concept_set.id)
|
||||
|
||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class SheerkaMemory(BaseService):
|
||||
self.sheerka.bind_service_method(self.add_to_memory, True, visible=False)
|
||||
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)
|
||||
@@ -94,6 +95,21 @@ class SheerkaMemory(BaseService):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
last = self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key)
|
||||
if last is NotFound:
|
||||
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
|
||||
return
|
||||
|
||||
if not isinstance(last, list) and last.obj == concept:
|
||||
self.sheerka.om.delete(SheerkaMemory.OBJECTS_ENTRY, key, last)
|
||||
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
|
||||
return
|
||||
|
||||
if isinstance(last, list) and last[-1].obj == concept:
|
||||
self.sheerka.om.delete(SheerkaMemory.OBJECTS_ENTRY, key, last[-1])
|
||||
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
|
||||
return
|
||||
|
||||
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
|
||||
|
||||
def get_from_memory(self, context, key):
|
||||
@@ -101,6 +117,20 @@ class SheerkaMemory(BaseService):
|
||||
"""
|
||||
return self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key)
|
||||
|
||||
def get_last_from_memory(self, context, key):
|
||||
"""
|
||||
Return an object from memory
|
||||
When there are multiple items, returns the last one
|
||||
"""
|
||||
res = self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key)
|
||||
if res is NotFound:
|
||||
return res
|
||||
|
||||
if isinstance(res, list):
|
||||
return res[-1]
|
||||
|
||||
return res
|
||||
|
||||
def register_object(self, context, key, concept):
|
||||
"""
|
||||
Before adding memory_objects to memory, they first need to be registered
|
||||
@@ -114,6 +144,8 @@ class SheerkaMemory(BaseService):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
if self.sheerka.during_initialisation:
|
||||
return
|
||||
self.registration[key] = concept
|
||||
|
||||
def unregister_object(self, context, key):
|
||||
|
||||
@@ -14,6 +14,8 @@ class SheerkaOut(BaseService):
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(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")
|
||||
|
||||
def create_out_tree(self, context, obj):
|
||||
debugger = context.get_debugger("Visitor", "create_out_tree")
|
||||
|
||||
@@ -6,8 +6,7 @@ from typing import Union, Set, List
|
||||
from cache.Cache import Cache
|
||||
from cache.ListIfNeededCache import ListIfNeededCache
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
||||
from core.builtin_helpers import parse_unrecognized, is_a_question, parse_python, \
|
||||
ensure_evaluated, expect_one, parse_expression
|
||||
from core.builtin_helpers import is_a_question, ensure_evaluated, expect_one
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound, ErrorObj, \
|
||||
EVENT_RULE_CREATED, EVENT_RULE_DELETED
|
||||
@@ -765,7 +764,7 @@ class SheerkaRuleManager(BaseService):
|
||||
parsed = []
|
||||
errors = []
|
||||
all_rete_disjunctions = []
|
||||
parsed_expr_ret = parse_expression(context, source)
|
||||
parsed_expr_ret = context.sheerka.parse_expression(context, source)
|
||||
if parsed_expr_ret.status:
|
||||
conjunctions = parsed_expr_ret.body.body.parts if isinstance(parsed_expr_ret.body.body, AndNode) else \
|
||||
[parsed_expr_ret.body.body]
|
||||
@@ -812,7 +811,7 @@ class SheerkaRuleManager(BaseService):
|
||||
return self.sheerka.ret(self.NAME, True, parsed)
|
||||
|
||||
def compile_exec(self, context, source):
|
||||
parsed = parse_unrecognized(context,
|
||||
parsed = context.sheerka.parse_unrecognized(context,
|
||||
source,
|
||||
parsers="all",
|
||||
who=self.NAME,
|
||||
@@ -1014,7 +1013,10 @@ class SheerkaRuleManager(BaseService):
|
||||
return RuleCompiledPredicate(source, action, ConceptEvaluator.NAME, r, c)
|
||||
else:
|
||||
to_parse = PythonCodeEmitter(context, "__ret.status").recognize_concept(c, "__ret.body").get_text()
|
||||
return RuleCompiledPredicate(source, action, PythonEvaluator.NAME, parse_python(context, to_parse),
|
||||
return RuleCompiledPredicate(source,
|
||||
action,
|
||||
PythonEvaluator.NAME,
|
||||
context.sheerka.parse_python(context, to_parse),
|
||||
None)
|
||||
|
||||
res = []
|
||||
|
||||
@@ -23,11 +23,5 @@ class AddToMemoryEvaluator(OneReturnValueEvaluator):
|
||||
return len(context.sheerka.services[SheerkaMemory.NAME].registration) > 0
|
||||
|
||||
def eval(self, context, return_value):
|
||||
if context.sheerka.during_initialisation:
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
service = context.sheerka.services[SheerkaMemory.NAME]
|
||||
service.registration.clear()
|
||||
return None
|
||||
|
||||
context.sheerka.commit_registered_objects(context)
|
||||
return None # no need to have a second pass
|
||||
|
||||
@@ -168,9 +168,16 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
||||
source = ret_value.value.source.as_text() if isinstance(ret_value.value.source,
|
||||
ParserInput) else ret_value.value.source
|
||||
tokens = ret_value.value.tokens or list(Tokenizer(source, yield_eof=False))
|
||||
tokens = [t.str_value for t in tokens]
|
||||
possible_vars = set()
|
||||
for t in tokens:
|
||||
if t.type == TokenKind.RULE:
|
||||
for v in [v for v in t.value if v is not None]:
|
||||
possible_vars.add(v)
|
||||
else:
|
||||
possible_vars.add(t.str_value)
|
||||
|
||||
for identifier in [i for i in concept_name if str(i).isalnum()]:
|
||||
if identifier in tokens:
|
||||
if identifier in possible_vars:
|
||||
variables.add(identifier)
|
||||
debugger.debug_var("names", variables, hint="from concept")
|
||||
return variables
|
||||
|
||||
@@ -11,9 +11,10 @@ from core.concept import ConceptParts, Concept
|
||||
from core.global_symbols import NotInit, NotFound
|
||||
from core.rule import Rule
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
from core.tokenizer import Token, TokenKind
|
||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
from parsers.PythonParser import PythonNode, get_python_node
|
||||
from parsers.PythonParser import PythonNode
|
||||
|
||||
TO_DISABLED = ["breakpoint", "callable", "compile", "delattr", "eval", "exec", "exit", "input", "locals", "open",
|
||||
"print", "quit", "setattr"]
|
||||
@@ -97,7 +98,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
||||
|
||||
debugger = context.get_debugger(PythonEvaluator.NAME, "eval")
|
||||
debugger.debug_entering(node=node)
|
||||
exception_debugger = context.get_debugger("Exceptions", PythonEvaluator.NAME + ".eval")
|
||||
exception_debugger = context.get_debugger("Exceptions", PythonEvaluator.NAME + "-eval")
|
||||
get_trace_back = exception_debugger.is_enabled()
|
||||
|
||||
context.log(f"Evaluating python node {node}.", self.name)
|
||||
@@ -140,8 +141,8 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
||||
context.log("Evaluating using 'exec'.", self.name)
|
||||
evaluated = self.exec_with_return(node.ast_, globals_, my_locals)
|
||||
|
||||
# TODO find a better implementation using SheerkaMemory
|
||||
sheerka.locals.update(my_locals)
|
||||
for k, v in my_locals.items():
|
||||
sheerka.services[SheerkaMemory.NAME].add_to_memory(context, k, v)
|
||||
|
||||
if not expect_success or evaluated:
|
||||
break # in this first version, we stop once a success is found
|
||||
@@ -231,17 +232,18 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
||||
my_globals[name] = Expando("sheerka", bag)
|
||||
continue
|
||||
|
||||
# search in local variables. To remove when local variables will be merged with memory
|
||||
if name in context.sheerka.locals:
|
||||
my_globals[name] = context.sheerka.locals[name]
|
||||
continue
|
||||
|
||||
# search in short term memory
|
||||
if (obj := context.get_from_short_term_memory(name)) is not NotFound:
|
||||
context.log(f"Resolving '{name}'. Using value found in STM.", self.name)
|
||||
my_globals[name] = obj
|
||||
continue
|
||||
|
||||
# search in memory
|
||||
if (obj := context.sheerka.get_last_from_memory(context, name)) is not NotFound:
|
||||
context.log(f"Resolving '{name}'. Using value found in Long Term Memory.", self.name)
|
||||
my_globals[name] = obj.obj
|
||||
continue
|
||||
|
||||
# search in sheerka methods
|
||||
if (method := self.get_sheerka_method(context, name, expression_only)) is not None:
|
||||
my_globals[name] = method
|
||||
|
||||
@@ -231,8 +231,7 @@ class ConceptNode(LexerNode):
|
||||
|
||||
def clone(self):
|
||||
# do we need to clone the concept as well ?
|
||||
clone = ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying)
|
||||
return clone
|
||||
return ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying)
|
||||
|
||||
def as_bag(self):
|
||||
"""
|
||||
@@ -305,6 +304,16 @@ class SourceCodeNode(LexerNode):
|
||||
def get_source_to_parse(self):
|
||||
return self.python_node.source
|
||||
|
||||
def clone(self):
|
||||
clone = SourceCodeNode(
|
||||
self.start,
|
||||
self.end,
|
||||
self.tokens,
|
||||
self.source,
|
||||
self.python_node,
|
||||
self.return_value)
|
||||
return clone
|
||||
|
||||
|
||||
class SourceCodeWithConceptNode(LexerNode):
|
||||
"""
|
||||
@@ -413,6 +422,8 @@ class SourceCodeWithConceptNode(LexerNode):
|
||||
|
||||
def clone(self):
|
||||
clone = SourceCodeWithConceptNode(self.first, self.last, self.nodes.copy(), self.has_unrecognized)
|
||||
clone.python_node = self.python_node
|
||||
clone.return_value = self.return_value
|
||||
return clone
|
||||
|
||||
def to_short_str(self):
|
||||
|
||||
@@ -1189,7 +1189,7 @@ class BnfNodeParser(BaseNodeParser):
|
||||
|
||||
if 'sheerka' in kwargs:
|
||||
sheerka = kwargs.get("sheerka")
|
||||
self.concepts_grammars = sheerka.concepts_grammars
|
||||
self.concepts_grammars = sheerka.get_concepts_bnf_definitions()
|
||||
self.sheerka = sheerka
|
||||
else:
|
||||
self.concepts_grammars = Cache()
|
||||
|
||||
@@ -211,7 +211,7 @@ class DefConceptParser(BaseCustomGrammarParser):
|
||||
return None
|
||||
|
||||
source = self.sheerka.services[SheerkaExecute.NAME].get_parser_input(None, tokens[1:])
|
||||
parsed = core.builtin_helpers.parse_unrecognized(self.context,
|
||||
parsed = self.sheerka.parse_unrecognized(self.context,
|
||||
source,
|
||||
parsers="all",
|
||||
who=self.name,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from itertools import product
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import only_successful, parse_unrecognized, get_inner_body, parse_python, \
|
||||
get_lexer_nodes_using_positions
|
||||
from core.builtin_helpers import only_successful, get_inner_body, get_lexer_nodes_using_positions
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.sheerka_service import FailedToCompileError
|
||||
from core.tokenizer import TokenKind, Tokenizer, Keywords
|
||||
@@ -247,7 +246,7 @@ class ExpressionParser(BaseParser):
|
||||
for conjunction in conjunctions:
|
||||
# try to recognize conjunction, one by one
|
||||
# negative conjunction can be a concept starting with 'not'
|
||||
parsed_ret = parse_unrecognized(
|
||||
parsed_ret = context.sheerka.parse_unrecognized(
|
||||
context,
|
||||
conjunction.get_value(), # we remove the 'NOT' part when needed to ease the recognition
|
||||
parsers="all",
|
||||
@@ -280,7 +279,7 @@ class ExpressionParser(BaseParser):
|
||||
return_values.append(recognized_conjunctions[0])
|
||||
elif len(recognized_conjunctions) == 1 and recognized_conjunctions[0].who == "parsers.Python":
|
||||
# it is a negated python Node. Need to parse again
|
||||
ret = parse_python(context, source=str(conjunctions[0]))
|
||||
ret = context.sheerka.parse_python(context, source=str(conjunctions[0]))
|
||||
if ret.status:
|
||||
return_values.append(ret)
|
||||
else:
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import get_lexer_nodes_from_unrecognized, update_compiled
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import TokenKind, Token
|
||||
from core.tokenizer import TokenKind
|
||||
from core.utils import get_n_clones
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode, UnrecognizedTokensNode
|
||||
from parsers.BaseParser import BaseParser, UnexpectedTokenParsingError, UnexpectedEofParsingError, Node
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
|
||||
from parsers.RuleParser import RuleParser
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
from parsers.expressions import NameExprNode
|
||||
|
||||
# No need to check for Python code as the source code node will resolve to python code anyway
|
||||
# I only look for concepts, so
|
||||
PARSERS = [RuleParser.NAME,
|
||||
SequenceNodeParser.NAME,
|
||||
BnfNodeParser.NAME,
|
||||
@@ -28,49 +26,16 @@ class FunctionParserNode(Node):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass()
|
||||
class NamesNode(FunctionParserNode):
|
||||
start: int # index of the first token
|
||||
end: int # index of the last token
|
||||
tokens: List[Token]
|
||||
|
||||
def __repr__(self):
|
||||
return f"NameNode('{self.str_value()}')"
|
||||
|
||||
def str_value(self):
|
||||
if self.tokens is None:
|
||||
return None
|
||||
|
||||
return "".join([t.str_value for t in self.tokens])
|
||||
|
||||
def to_unrecognized(self):
|
||||
"""
|
||||
UnrecognizedTokensNode with all tokens
|
||||
"""
|
||||
return UnrecognizedTokensNode(self.start, self.end, self.tokens).fix_source()
|
||||
|
||||
def to_str_unrecognized(self):
|
||||
"""
|
||||
UnrecognizedTokensNode with one token, which is a string token of all the tokens
|
||||
"""
|
||||
token = Token(TokenKind.STRING,
|
||||
"'" + self.str_value() + "'",
|
||||
self.tokens[0].index,
|
||||
self.tokens[0].line,
|
||||
self.tokens[0].column)
|
||||
return UnrecognizedTokensNode(self.start, self.end, [token]).fix_source()
|
||||
|
||||
|
||||
@dataclass()
|
||||
class FunctionParameter:
|
||||
"""
|
||||
class the represent result of the parameter parsing
|
||||
"""
|
||||
value: NamesNode # value parsed
|
||||
separator: NamesNode = None # holds the value and the position of the separator
|
||||
value: NameExprNode # value parsed
|
||||
separator: NameExprNode = None # holds the value and the position of the separator
|
||||
|
||||
def add_sep(self, start, end, tokens):
|
||||
self.separator = NamesNode(start, end, tokens)
|
||||
self.separator = NameExprNode(start, end, tokens)
|
||||
|
||||
def value_to_unrecognized(self):
|
||||
return UnrecognizedTokensNode(self.value.start, self.value.end, self.value.tokens).fix_source()
|
||||
@@ -83,8 +48,8 @@ class FunctionParameter:
|
||||
|
||||
@dataclass
|
||||
class FunctionNode(FunctionParserNode):
|
||||
first: NamesNode # beginning of the function (it should represent the name of the function)
|
||||
last: NamesNode # last part of the function (it should be the trailing parenthesis)
|
||||
first: NameExprNode # beginning of the function (it should represent the name of the function)
|
||||
last: NameExprNode # last part of the function (it should be the trailing parenthesis)
|
||||
parameters: list
|
||||
|
||||
|
||||
@@ -95,11 +60,11 @@ class FN(FunctionNode):
|
||||
|
||||
Thereby,
|
||||
FN("first", "last", ["param1," ...]) can be compared to
|
||||
FunctionNode(NamesNode("first"), NamesNode("second"), [FunctionParameter(NamesNodes("param1"), NamesNodes(", ")])
|
||||
FunctionNode(NameExprNode("first"), NameExprNode("second"), [FunctionParameter(NamesNodes("param1"), NamesNodes(", ")])
|
||||
|
||||
Note that FunctionParameter can easily be defined with a single string
|
||||
* "param" -> FunctionParameter(NamesNode("param"), None)
|
||||
* "param, " -> FunctionParameter(NamesNode("param"), NamesNode(", "))
|
||||
* "param" -> FunctionParameter(NameExprNode("param"), None)
|
||||
* "param, " -> FunctionParameter(NameExprNode("param"), NameExprNode(", "))
|
||||
For more complicated situations, you can use a tuple (value, sep) to define the value part and the separator part
|
||||
"""
|
||||
|
||||
@@ -123,14 +88,13 @@ class FN(FunctionNode):
|
||||
return self.first == other.first and self.last == other.last and self.parameters == other.parameters
|
||||
|
||||
if isinstance(other, FunctionNode):
|
||||
if self.first != other.first.str_value() or self.last != other.last.str_value():
|
||||
if self.first != other.first.value or self.last != other.last.value:
|
||||
return False
|
||||
if len(self.parameters) != len(other.parameters):
|
||||
return False
|
||||
for self_parameter, other_parameter in zip(self.parameters, other.parameters):
|
||||
value = other_parameter.value.str_value() if isinstance(self_parameter[0],
|
||||
str) else other_parameter.value
|
||||
sep = other_parameter.separator.str_value() if other_parameter.separator else None
|
||||
value = other_parameter.value.value if isinstance(self_parameter[0], str) else other_parameter.value
|
||||
sep = other_parameter.separator.value if other_parameter.separator else None
|
||||
if self_parameter[0] != value or self_parameter[1] != sep:
|
||||
return False
|
||||
|
||||
@@ -244,7 +208,7 @@ class FunctionParser(BaseParser):
|
||||
[TokenKind.LPAR]))
|
||||
return None
|
||||
|
||||
start_node = NamesNode(start, start + 1, self.parser_input.tokens[start:start + 2])
|
||||
start_node = NameExprNode(start, start + 1, self.parser_input.tokens[start:start + 2])
|
||||
if not self.parser_input.next_token():
|
||||
self.add_error(UnexpectedEofParsingError(f"Unexpected EOF after left parenthesis"))
|
||||
return FunctionNode(start_node, None, None)
|
||||
@@ -261,7 +225,7 @@ class FunctionParser(BaseParser):
|
||||
return FunctionNode(start_node, None, params)
|
||||
|
||||
return FunctionNode(start_node,
|
||||
NamesNode(self.parser_input.pos, self.parser_input.pos, [token]),
|
||||
NameExprNode(self.parser_input.pos, self.parser_input.pos, [token]),
|
||||
params)
|
||||
|
||||
def parse_parameters(self):
|
||||
@@ -319,7 +283,7 @@ class FunctionParser(BaseParser):
|
||||
if not self.parser_input.next_token(skip_whitespace=False):
|
||||
break
|
||||
|
||||
return NamesNode(start_pos, self.parser_input.pos - 1, tokens) if len(tokens) else None
|
||||
return NameExprNode(start_pos, self.parser_input.pos - 1, tokens) if len(tokens) else None
|
||||
|
||||
def to_source_code_node(self, function_node: FunctionNode):
|
||||
python_parser = PythonWithConceptsParser()
|
||||
@@ -350,7 +314,7 @@ class FunctionParser(BaseParser):
|
||||
|
||||
# try to recognize every parameter, one by one
|
||||
for param in function_node.parameters:
|
||||
if isinstance(param.value, NamesNode):
|
||||
if isinstance(param.value, NameExprNode):
|
||||
# try to recognize concepts
|
||||
unrecognized = param.value.to_unrecognized()
|
||||
nodes_sequences = get_lexer_nodes_from_unrecognized(self.context,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import parse_python, CreateObjectIdentifiers
|
||||
from core.builtin_helpers import CreateObjectIdentifiers
|
||||
from parsers.BaseNodeParser import ConceptNode, RuleNode
|
||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode
|
||||
from parsers.BaseParser import BaseParser
|
||||
@@ -71,7 +71,7 @@ class PythonWithConceptsParser(BaseParser):
|
||||
if hasattr(node, "get_python_node"):
|
||||
python_ids_mappings.update(node.get_python_node().objects)
|
||||
|
||||
result = parse_python(context, to_parse, "Trying Python for '" + to_parse + "'")
|
||||
result = context.sheerka.parse_python(context, to_parse, "Trying Python for '" + to_parse + "'")
|
||||
|
||||
if result.status:
|
||||
python_node = result.body.body
|
||||
|
||||
@@ -5,7 +5,6 @@ from typing import List
|
||||
|
||||
from core import builtin_helpers
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import parse_function
|
||||
from core.concept import Concept, DEFINITION_TYPE_BNF
|
||||
from core.global_symbols import CONCEPT_COMPARISON_CONTEXT
|
||||
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager
|
||||
@@ -833,7 +832,7 @@ class InFixToPostFix:
|
||||
|
||||
if self.unrecognized_tokens.parenthesis_count == 0:
|
||||
self.unrecognized_tokens.fix_source()
|
||||
res = parse_function(self.context,
|
||||
res = self.context.sheerka.parse_function(self.context,
|
||||
self.unrecognized_tokens.source,
|
||||
self.unrecognized_tokens.tokens[:],
|
||||
self.unrecognized_tokens.start)
|
||||
|
||||
@@ -2,11 +2,11 @@ from dataclasses import dataclass
|
||||
|
||||
import core.utils
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import only_successful, parse_unrecognized, get_lexer_nodes, update_compiled
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from core.builtin_helpers import only_successful, get_lexer_nodes, update_compiled
|
||||
from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, SourceCodeNode, SourceCodeWithConceptNode
|
||||
from parsers.BaseParser import BaseParser, ParsingError
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
|
||||
PARSERS = ["EmptyString",
|
||||
@@ -56,7 +56,7 @@ class UnrecognizedNodeParser(BaseParser):
|
||||
sequences_found = core.utils.sheerka_product(sequences_found, [res.body])
|
||||
|
||||
elif isinstance(node, UnrecognizedTokensNode):
|
||||
res = parse_unrecognized(context, node.source, PARSERS)
|
||||
res = context.sheerka.parse_unrecognized(context, node.source, PARSERS)
|
||||
res = only_successful(context, res)
|
||||
if res.status:
|
||||
lexer_nodes = get_lexer_nodes(res.body.body, node.start, node.tokens)
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import List, Tuple
|
||||
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer
|
||||
from core.utils import tokens_are_matching
|
||||
from parsers.BaseNodeParser import UnrecognizedTokensNode
|
||||
from parsers.BaseParser import Node, ParsingError
|
||||
|
||||
|
||||
@@ -86,6 +87,23 @@ class NameExprNode(ExprNode):
|
||||
def __hash__(self):
|
||||
return super().__hash__()
|
||||
|
||||
def to_unrecognized(self):
|
||||
"""
|
||||
UnrecognizedTokensNode with all tokens
|
||||
"""
|
||||
return UnrecognizedTokensNode(self.start, self.end, self.tokens).fix_source()
|
||||
|
||||
def to_str_unrecognized(self):
|
||||
"""
|
||||
UnrecognizedTokensNode with one token, which is a string token of all the tokens
|
||||
"""
|
||||
token = Token(TokenKind.STRING,
|
||||
"'" + self.str_value() + "'",
|
||||
self.tokens[0].index,
|
||||
self.tokens[0].line,
|
||||
self.tokens[0].column)
|
||||
return UnrecognizedTokensNode(self.start, self.end, [token]).fix_source()
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class AndNode(ExprNode):
|
||||
|
||||
@@ -2,10 +2,9 @@ import hashlib
|
||||
import json
|
||||
import shutil
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, date
|
||||
from threading import RLock
|
||||
from os import path
|
||||
from threading import RLock
|
||||
|
||||
from core.global_symbols import NotFound
|
||||
from core.sheerka_logger import get_logger
|
||||
@@ -115,16 +114,6 @@ class SheerkaDataProviderDuplicateKeyError(Exception):
|
||||
self.obj = obj
|
||||
|
||||
|
||||
@dataclass
|
||||
class SheerkaDataProviderResult:
|
||||
"""
|
||||
Object that is returned after adding, setting or modifying an entry
|
||||
"""
|
||||
entry: str # entry where the object is put
|
||||
key: str # key to use to retrieve the object
|
||||
digest: str # digest used to store the reference
|
||||
|
||||
|
||||
class SheerkaDataProviderTransaction:
|
||||
|
||||
def __init__(self, sdp, event):
|
||||
@@ -231,6 +220,9 @@ class SheerkaDataProvider:
|
||||
snapshot = self.get_snapshot(SheerkaDataProvider.HeadFile)
|
||||
self.state = self.load_state(snapshot)
|
||||
|
||||
def __repr__(self):
|
||||
return f"SheerkaDataProvider(name={self.name})"
|
||||
|
||||
@staticmethod
|
||||
def get_stream_digest(stream):
|
||||
sha256_hash = hashlib.sha256()
|
||||
|
||||
@@ -8,6 +8,7 @@ from core.sheerka.Sheerka import Sheerka
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from evaluators.BaseEvaluator import BaseEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from parsers.DefRuleParser import DefRuleNode, DefExecRuleNode, DefFormatRuleNode
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkapickle.handlers import BaseHandler, registry
|
||||
|
||||
@@ -213,6 +214,26 @@ class PythonNodeHandler(BaseHandler):
|
||||
return instance
|
||||
|
||||
|
||||
class DefRuleNodeHandler(BaseHandler):
|
||||
def flatten(self, obj, data):
|
||||
pickler = self.context
|
||||
|
||||
data["tokens"] = pickler.flatten(obj.tokens)
|
||||
data["name"] = pickler.flatten(obj.name)
|
||||
return data
|
||||
|
||||
def new(self, data):
|
||||
return DefRuleNode.__new__(DefRuleNode)
|
||||
|
||||
def restore(self, data, instance):
|
||||
pickler = self.context
|
||||
|
||||
instance.__init__(data["source"], objects=pickler.restore(data["objects"]))
|
||||
instance.tokens = pickler.restore(data["tokens"])
|
||||
instance.name = pickler.restore(data["name"])
|
||||
return instance
|
||||
|
||||
|
||||
def initialize_pickle_handlers():
|
||||
registry.register(Concept, ConceptHandler, True)
|
||||
registry.register(UserInputConcept, UserInputHandler, True)
|
||||
@@ -221,3 +242,6 @@ def initialize_pickle_handlers():
|
||||
registry.register(ExecutionContext, ExecutionContextHandler, True)
|
||||
registry.register(Rule, RuleContextHandler, True)
|
||||
registry.register(PythonNode, PythonNodeHandler, True)
|
||||
registry.register(DefRuleNode, DefRuleNodeHandler, True)
|
||||
registry.register(DefExecRuleNode, DefRuleNodeHandler, True) # TODO: fix inheritance that does not work
|
||||
registry.register(DefFormatRuleNode, DefRuleNodeHandler, True) # TODO: fix inheritance that does not work
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Generator, Union
|
||||
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import NotInit
|
||||
from core.rule import Rule
|
||||
from core.rule import Rule, ACTION_TYPE_PRINT
|
||||
from core.utils import as_bag
|
||||
from sheerkarete.alpha import AlphaMemory
|
||||
from sheerkarete.beta import ReteNode, BetaMemory
|
||||
@@ -282,7 +282,9 @@ class ReteNetwork:
|
||||
if rule.id is None:
|
||||
raise ValueError("Rule has no id, cannot add")
|
||||
|
||||
if not rule.metadata.is_enabled or not rule.metadata.is_compiled:
|
||||
if (not rule.metadata.is_enabled or
|
||||
not rule.metadata.is_compiled or
|
||||
rule.metadata.action_type == ACTION_TYPE_PRINT):
|
||||
return
|
||||
|
||||
if rule.rete_net:
|
||||
|
||||
+9
-2
@@ -104,8 +104,12 @@ class BaseTest:
|
||||
def get_sheerka(self, **kwargs) -> Sheerka:
|
||||
pass
|
||||
|
||||
def get_context(self, sheerka=None, eval_body=False, eval_where=False):
|
||||
context = ExecutionContext("test", Event(), sheerka or self.get_sheerka(), BuiltinConcepts.TESTING, None)
|
||||
def get_context(self, sheerka=None, eval_body=False, eval_where=False, message=""):
|
||||
context = ExecutionContext("test",
|
||||
Event(message=message),
|
||||
sheerka or self.get_sheerka(),
|
||||
BuiltinConcepts.TESTING,
|
||||
None)
|
||||
if eval_body:
|
||||
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
if eval_where:
|
||||
@@ -158,6 +162,9 @@ class BaseTest:
|
||||
def init_format_rules(self, *rules, **kwargs):
|
||||
return self.init_test(**kwargs).with_format_rules(*rules, **kwargs).unpack()
|
||||
|
||||
def init_exec_rules(self, *rules, **kwargs):
|
||||
return self.init_test(**kwargs).with_exec_rules(*rules, **kwargs).unpack()
|
||||
|
||||
@staticmethod
|
||||
def get_concept_instance(sheerka, concept, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -15,6 +15,10 @@ class TestUsingMemoryBasedSheerka(BaseTest):
|
||||
while TestUsingMemoryBasedSheerka.sheerka.om.current_ontology().name != self.root_ontology_name:
|
||||
TestUsingMemoryBasedSheerka.sheerka.pop_ontology(self.context)
|
||||
|
||||
for service_name, service in TestUsingMemoryBasedSheerka.sheerka.services.items():
|
||||
if hasattr(service, "reset_state"):
|
||||
service.reset_state()
|
||||
|
||||
@staticmethod
|
||||
def new_sheerka_instance(cache_only):
|
||||
sheerka = Sheerka(cache_only=cache_only)
|
||||
|
||||
+83
-4
@@ -418,7 +418,22 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self):
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_cache_and_then_put_back(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# No remaining value in current cache after deletion
|
||||
# The key must be flagged as Removed
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
cache.put("key", "value")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
|
||||
cache.delete("key", value="value", alt_sdp=alt_sdp) # remove all values
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": "value"}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_one_value(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# But this, there are remaining values in current cache after deletion
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
@@ -431,11 +446,26 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# But this, there are remaining values in current cache after deletion
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
cache.put("key", "value")
|
||||
cache.put("key", "value2")
|
||||
cache.put("key", "value3")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
|
||||
cache.delete("key", value="value", alt_sdp=alt_sdp)
|
||||
assert cache.copy() == {"key": ['value2', 'value3']}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_key_from_remote_repository(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# No remaining value in current cache after deletion
|
||||
# The key must be flagged as Removed
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure("cache_name")
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure(
|
||||
"cache_name")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
|
||||
cache.delete("key", value=None, alt_sdp=alt_sdp)
|
||||
@@ -455,10 +485,23 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_values(self):
|
||||
def test_i_can_delete_when_alt_sdp_a_key_from_remote_repository_and_then_put_back(self):
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure(
|
||||
"cache_name")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
|
||||
cache.delete("key", value=None, alt_sdp=alt_sdp) # remove all values
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": "value"}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_one_value(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# But this, there are remaining values in current cache after deletion
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure("cache_name")
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure(
|
||||
"cache_name")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
|
||||
cache.delete("key", value="value1", alt_sdp=alt_sdp)
|
||||
@@ -492,6 +535,21 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_add == {"key"}
|
||||
assert cache.to_remove == set()
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_and_then_put_back(self):
|
||||
# alt_cache_manager is used because no value in cache or in remote repository
|
||||
# After value deletion, the key is empty
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "value1",
|
||||
extend_exists=lambda cache_name, key: True)
|
||||
|
||||
cache.delete("key", value="value1", alt_sdp=alt_sdp)
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": "value"}
|
||||
assert cache.to_add == {"key"}
|
||||
assert cache.to_remove == set()
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_one_value_remaining(self):
|
||||
# alt_cache_manager is used because no value in cache or in remote repository
|
||||
# After value deletion, one value remains in the cache
|
||||
@@ -567,3 +625,24 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.copy() == {}
|
||||
assert cache.to_add == set()
|
||||
assert cache.to_remove == set()
|
||||
|
||||
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository(self):
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: Removed)).auto_configure("cache_name")
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": "value"}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository_from_alt_sdp(self):
|
||||
# The key is removed in the sub layers
|
||||
# We can put it back
|
||||
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: Removed,
|
||||
extend_exists=lambda cache_name, key: False)
|
||||
|
||||
cache.put("key", "value", alt_sdp=alt_sdp)
|
||||
|
||||
assert cache.copy() == {"key": "value"}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
Vendored
+63
@@ -337,6 +337,20 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_cache_and_then_put_back(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# No remaining value in current cache after deletion
|
||||
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
cache.put("key", "value")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
|
||||
cache.delete("key", value="value", alt_sdp=alt_sdp)
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": {"value"}}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# But there is a value in the current cache after deletion
|
||||
@@ -371,6 +385,19 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_and_then_put_back(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# No remaining value in current cache after deletion
|
||||
# The key must be flagged as Removed
|
||||
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: {"value1", "value2"})).auto_configure("cache_name")
|
||||
|
||||
cache.delete("key", value=None, alt_sdp=FakeSdp(extend_exists=lambda cache_name, key: True))
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": {"value"}}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_values(self):
|
||||
# There is a value in alt_cache_manager,
|
||||
# But there is a value in the current cache after deletion
|
||||
@@ -407,6 +434,21 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.to_add == {"key"}
|
||||
assert cache.to_remove == set()
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_and_then_put_back(self):
|
||||
# alt_cache_manager is used because no value in cache or in remote repository
|
||||
# After value deletion, the key is empty
|
||||
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: {"value1"},
|
||||
extend_exists=lambda cache_name, key: True)
|
||||
|
||||
cache.delete("key", value="value1", alt_sdp=alt_sdp)
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": {"value"}}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_one_value_remaining(self):
|
||||
# alt_cache_manager is used because no value in cache or in remote repository
|
||||
# After value deletion, the key is empty
|
||||
@@ -475,3 +517,24 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
|
||||
assert cache.copy() == {}
|
||||
assert cache.to_add == set()
|
||||
assert cache.to_remove == set()
|
||||
|
||||
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository(self):
|
||||
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: Removed)).auto_configure("cache_name")
|
||||
cache.put("key", "value")
|
||||
|
||||
assert cache.copy() == {"key": {"value"}}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository_from_alt_sdp(self):
|
||||
# The key is removed in the sub layers
|
||||
# We can put it back
|
||||
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
|
||||
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: Removed,
|
||||
extend_exists=lambda cache_name, key: False)
|
||||
|
||||
cache.put("key", "value", alt_sdp=alt_sdp)
|
||||
|
||||
assert cache.copy() == {"key": {"value"}}
|
||||
assert cache.to_remove == set()
|
||||
assert cache.to_add == {"key"}
|
||||
|
||||
@@ -3,7 +3,7 @@ import pytest
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import EVENT_CONCEPT_PRECEDENCE_MODIFIED, CONCEPT_COMPARISON_CONTEXT, \
|
||||
EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT
|
||||
EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound
|
||||
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager, ComparisonObj
|
||||
from core.sheerka.services.SheerkaConceptManager import ChickenAndEggError
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
@@ -657,7 +657,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
|
||||
(["a = z", "z>>", "b<c", "c<d"], {"a": 4, "b": 1, "c": 2, "d": 3, "z": 4}),
|
||||
(["b = a", "c = b", "a > d"], {"a": 2, "b": 2, "c": 2, "d": 1}),
|
||||
(["a = b", "b = c", "a > d"], {"a": 2, "b": 2, "c": 2, "d": 1}),
|
||||
#(["a = b", "b = c", "c > d"], {"a": 2, "b": 2, "c": 2, "d": 1}), # not working
|
||||
# (["a = b", "b = c", "c > d"], {"a": 2, "b": 2, "c": 2, "d": 1}), # not working
|
||||
|
||||
# mix greatest and lesser
|
||||
(["a >>", "b<<", "a > b"], {"a": 2, "b": 0}),
|
||||
@@ -732,3 +732,25 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_LESSER_CONSTRAINT_ERROR)
|
||||
|
||||
def test_i_can_seamlessly_use_concept_name_or_concept_itself_when_builtin_concept_to_define_comparison(self):
|
||||
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
|
||||
|
||||
prec_as_concept = sheerka.new(BuiltinConcepts.PRECEDENCE)
|
||||
sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE, foo, bar)
|
||||
sheerka.set_is_greater_than(context, prec_as_concept, foo, baz)
|
||||
|
||||
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, f"{BuiltinConcepts.PRECEDENCE}|#") == [
|
||||
ComparisonObj(context.event.get_digest(), BuiltinConcepts.PRECEDENCE, foo.str_id, bar.str_id, ">", "#"),
|
||||
ComparisonObj(context.event.get_digest(), BuiltinConcepts.PRECEDENCE, foo.str_id, baz.str_id, ">", "#"),
|
||||
]
|
||||
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, f"{prec_as_concept.str_id}|#") is NotFound
|
||||
|
||||
def test_i_can_seamlessly_use_concept_id_or_concept_itself_to_define_comparison(self):
|
||||
sheerka, context, foo, bar, baz, op = self.init_concepts("foo", "bar", "baz", "op")
|
||||
sheerka.set_is_greater_than(context, op.str_id, foo, bar)
|
||||
sheerka.set_is_greater_than(context, op, foo, baz)
|
||||
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, f"{op.str_id}|#") == [
|
||||
ComparisonObj(context.event.get_digest(), op.str_id, foo.str_id, bar.str_id, ">", "#"),
|
||||
ComparisonObj(context.event.get_digest(), op.str_id, foo.str_id, baz.str_id, ">", "#"),
|
||||
]
|
||||
|
||||
@@ -884,7 +884,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
sheerka.set_isa(context, sheerka.new("twenties"), number)
|
||||
sheerka.set_isa(context, sheerka.new("hundreds"), number)
|
||||
|
||||
sheerka.concepts_grammars.clear() # reset all the grammar to simulate Sheerka restart
|
||||
sheerka.clear_bnf_definition() # reset all the grammar to simulate Sheerka restart
|
||||
|
||||
# cbft : concept_by_first_token (I usually don't use abbreviation)
|
||||
cbft = compute_concepts_by_first_token(context, [number] + concepts).body
|
||||
|
||||
@@ -19,14 +19,32 @@ class DummyObj:
|
||||
|
||||
|
||||
class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
return_value_id = 0
|
||||
rv = None
|
||||
rr = None
|
||||
rc = None
|
||||
|
||||
@classmethod
|
||||
def setup(cls):
|
||||
sheerka = cls().get_sheerka()
|
||||
cls.return_value_id = sheerka.get_by_key("__RETURN_VALUE").id
|
||||
|
||||
def backup_registered(self, service):
|
||||
self.rv = service.registered_vars.copy(),
|
||||
self.rr = service.registered_rules.copy(),
|
||||
self.rc = service.registered_concepts.copy(),
|
||||
service.registered_vars.clear()
|
||||
service.registered_rules.clear()
|
||||
service.registered_concepts.clear()
|
||||
|
||||
def restore_registered(self, service):
|
||||
service.registered_vars.clear()
|
||||
service.registered_rules.clear()
|
||||
service.registered_concepts.clear()
|
||||
service.registered_vars.extend(self.rv)
|
||||
service.registered_vars.extend(self.rr)
|
||||
service.registered_vars.extend(self.rc)
|
||||
|
||||
@pytest.mark.parametrize("item_type", [
|
||||
"vars", "rules", "concepts"
|
||||
])
|
||||
@@ -387,7 +405,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context = self.init_concepts()
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
sheerka.debug_var(context, "s.m.v", "1+", 10, variable="my_var")
|
||||
sheerka.set_debug_var(context, "s.m.v", "1+", 10, variable="my_var")
|
||||
assert service.debug_vars_settings == [
|
||||
DebugItem("my_var", "s", "m", 1, True, 10, False, True)
|
||||
]
|
||||
@@ -398,7 +416,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context = self.init_concepts()
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
sheerka.debug_rule(context, "s.m.v", "1+", 10, rule="my_rule")
|
||||
sheerka.set_debug_rule(context, "s.m.v", "1+", 10, rule="my_rule")
|
||||
assert service.debug_rules_settings == [
|
||||
DebugItem("my_rule", "s", "m", 1, True, 10, False, True)
|
||||
]
|
||||
@@ -409,7 +427,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context = self.init_concepts()
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
sheerka.debug_concept(context, "s.m.v", "1+", 10, concept="my_concept")
|
||||
sheerka.set_debug_concept(context, "s.m.v", "1+", 10, concept="my_concept")
|
||||
assert service.debug_concepts_settings == [
|
||||
DebugItem("my_concept", "s", "m", 1, True, 10, False, True)
|
||||
]
|
||||
@@ -422,9 +440,9 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
root_context = self.get_context(sheerka)
|
||||
|
||||
sheerka.set_debug(root_context, True)
|
||||
sheerka.debug_var(root_context, "service_name.*.var")
|
||||
sheerka.debug_rule(root_context, 1)
|
||||
sheerka.debug_concept(root_context, 1001)
|
||||
sheerka.set_debug_var(root_context, "service_name.*.var")
|
||||
sheerka.set_debug_rule(root_context, 1)
|
||||
sheerka.set_debug_concept(root_context, 1001)
|
||||
|
||||
another_service = SheerkaDebugManager(sheerka)
|
||||
another_service.initialize_deferred(root_context, True)
|
||||
@@ -705,9 +723,9 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
sheerka.push_ontology(context, "new ontology")
|
||||
|
||||
service.set_debug(context)
|
||||
service.debug_var(context, "var_service.var_method.var_name", "1+", 1)
|
||||
service.debug_rule(context, "rule_service.rule_method.rule_name", "2+", 2)
|
||||
service.debug_concept(context, "concept_service.concept_method.concept_name", "3+", 3)
|
||||
service.set_debug_var(context, "var_service.var_method.var_name", "1+", 1)
|
||||
service.set_debug_rule(context, "rule_service.rule_method.rule_name", "2+", 2)
|
||||
service.set_debug_concept(context, "concept_service.concept_method.concept_name", "3+", 3)
|
||||
|
||||
# sanity check
|
||||
assert service.activated
|
||||
@@ -728,17 +746,17 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
service.set_debug(context)
|
||||
service.debug_var(context, "v_service.v_method.v_name", "1+", 1)
|
||||
service.debug_rule(context, "r_service.r_method.r_name", "2+", 2)
|
||||
service.debug_concept(context, "c_serv.c_method.c_name", "3+", 3)
|
||||
service.set_debug_var(context, "v_service.v_method.v_name", "1+", 1)
|
||||
service.set_debug_rule(context, "r_service.r_method.r_name", "2+", 2)
|
||||
service.set_debug_concept(context, "c_serv.c_method.c_name", "3+", 3)
|
||||
|
||||
sheerka.push_ontology(context, "new ontology")
|
||||
|
||||
# modify the state
|
||||
service.set_debug(context, False)
|
||||
service.debug_var(context, "var_service2.var_method2.var_name2", "11+", 11)
|
||||
service.debug_rule(context, "rule_service2.rule_method2.rule_name2", "22+", 22)
|
||||
service.debug_concept(context, "concept_service2.concept_method2.concept_name2", "33+", 33)
|
||||
service.set_debug_var(context, "var_service2.var_method2.var_name2", "11+", 11)
|
||||
service.set_debug_rule(context, "rule_service2.rule_method2.rule_name2", "22+", 22)
|
||||
service.set_debug_concept(context, "concept_service2.concept_method2.concept_name2", "33+", 33)
|
||||
|
||||
# sanity
|
||||
assert not service.activated
|
||||
@@ -752,3 +770,133 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
assert service.debug_vars_settings == [DebugItem("v_name", "v_service", "v_method", 1, True, 1, False, True)]
|
||||
assert service.debug_rules_settings == [DebugItem("r_name", "r_service", "r_method", 2, True, 2, False, True)]
|
||||
assert service.debug_concepts_settings == [DebugItem("c_name", "c_serv", "c_method", 3, True, 3, False, True)]
|
||||
|
||||
def test_i_can_register_debug_item(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
try:
|
||||
self.backup_registered(service)
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service", "method", "var_name")
|
||||
assert service.registered_vars == [("service", "method", "var_name")]
|
||||
|
||||
service.register_debug(service.RULES_DEBUG_TYPE, "service", "method", "rule_name")
|
||||
assert service.registered_rules == [("service", "method", "rule_name")]
|
||||
|
||||
service.register_debug(service.CONCEPTS_DEBUG_TYPE, "service", "method", "concept_name")
|
||||
assert service.registered_concepts == [("service", "method", "concept_name")]
|
||||
finally:
|
||||
self.restore_registered(service)
|
||||
|
||||
def test_i_can_filter_registered_debug_item(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
try:
|
||||
self.backup_registered(service)
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name1")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name2")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name1")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name2")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name1")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name2")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method2", "var_name1")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method2", "var_name2")
|
||||
|
||||
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "service1")) == [
|
||||
("service1", "method1", "var_name1"),
|
||||
("service1", "method1", "var_name2"),
|
||||
("service1", "method2", "var_name1"),
|
||||
("service1", "method2", "var_name2"),
|
||||
]
|
||||
|
||||
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "service1.method2")) == [
|
||||
("service1", "method2", "var_name1"),
|
||||
("service1", "method2", "var_name2"),
|
||||
]
|
||||
|
||||
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "service1.method2.var_name1")) == [
|
||||
("service1", "method2", "var_name1"),
|
||||
]
|
||||
|
||||
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "*.*.var_name1")) == [
|
||||
("service1", "method1", "var_name1"),
|
||||
("service1", "method2", "var_name1"),
|
||||
("service2", "method1", "var_name1"),
|
||||
("service2", "method2", "var_name1"),
|
||||
]
|
||||
|
||||
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "*.method2.*")) == [
|
||||
("service1", "method2", "var_name1"),
|
||||
("service1", "method2", "var_name2"),
|
||||
("service2", "method2", "var_name1"),
|
||||
("service2", "method2", "var_name2"),
|
||||
]
|
||||
|
||||
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, method="method1")) == [
|
||||
("service1", "method1", "var_name1"),
|
||||
("service1", "method1", "var_name2"),
|
||||
("service2", "method1", "var_name1"),
|
||||
("service2", "method1", "var_name2"),
|
||||
]
|
||||
finally:
|
||||
self.restore_registered(service)
|
||||
|
||||
def test_i_can_list_registered_debug(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
service = sheerka.services[SheerkaDebugManager.NAME]
|
||||
|
||||
try:
|
||||
self.backup_registered(service)
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name1")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name2")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name3")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name4")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method3", "var_name5")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method3", "var_name6")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name7")
|
||||
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name8")
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE)
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == ["service1", "service2"]
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE, "service2")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == ["service2.method1", "service2.method3"]
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE, "service2.method3")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == ["service2.method3.var_name5", "service2.method3.var_name6"]
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE, "*.method1")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == [
|
||||
"service1.method1.var_name1",
|
||||
"service1.method1.var_name2",
|
||||
"service2.method1.var_name7",
|
||||
"service2.method1.var_name8",
|
||||
]
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE, method="method1")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == [
|
||||
"service1.method1.var_name1",
|
||||
"service1.method1.var_name2",
|
||||
"service2.method1.var_name7",
|
||||
"service2.method1.var_name8",
|
||||
]
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE, "*.*.var_name7")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == [
|
||||
"service2.method1.var_name7",
|
||||
]
|
||||
|
||||
res = service.list_registered(service.VARS_DEBUG_TYPE, variable="var_name7")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
|
||||
assert list(res.body) == [
|
||||
"service2.method1.var_name7",
|
||||
]
|
||||
finally:
|
||||
self.restore_registered(service)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
|
||||
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, CB, \
|
||||
concept_part_value, DEFINITION_TYPE_DEF
|
||||
from core.global_symbols import NotInit
|
||||
from core.global_symbols import NotInit, NotFound
|
||||
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
from parsers.BaseParser import BaseParser
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val
|
||||
|
||||
@@ -778,12 +776,12 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, command)
|
||||
assert evaluated.key == command.key
|
||||
assert "a" not in sheerka.locals
|
||||
assert sheerka.get_from_memory(context, "a") == NotFound
|
||||
|
||||
sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.AUTO_EVAL))
|
||||
evaluated = sheerka.evaluate_concept(context, sheerka.new("command"))
|
||||
assert evaluated.key == command.key
|
||||
assert "a" in sheerka.locals
|
||||
assert sheerka.get_from_memory(context, "a").obj == 10
|
||||
|
||||
@pytest.mark.parametrize("metadata", [
|
||||
ConceptParts.WHERE,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from core.sheerka.services.SheerkaHistoryManager import hist
|
||||
from core.sheerka.services.SheerkaHistoryManager import hist, SheerkaHistoryManager
|
||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||
|
||||
|
||||
class TestSheerkaHistoryManager(TestUsingFileBasedSheerka):
|
||||
def test_i_can_retrieve_history(self):
|
||||
sheerka = self.get_sheerka()
|
||||
service = sheerka.services[SheerkaHistoryManager.NAME]
|
||||
sheerka.save_execution_context = True
|
||||
|
||||
sheerka.evaluate_user_input("def concept one as 1")
|
||||
@@ -19,7 +20,7 @@ class TestSheerkaHistoryManager(TestUsingFileBasedSheerka):
|
||||
sheerka.evaluate_user_input("def concept five as 5")
|
||||
sheerka.evaluate_user_input("five")
|
||||
|
||||
h = list(sheerka.history(-1)) # all
|
||||
h = list(service.history(-1)) # all
|
||||
assert h == [
|
||||
hist("five", True),
|
||||
hist("def concept five as 5", True),
|
||||
@@ -35,13 +36,13 @@ class TestSheerkaHistoryManager(TestUsingFileBasedSheerka):
|
||||
hist("Initializing Sheerka.", None)
|
||||
]
|
||||
|
||||
h = list(sheerka.history(2))
|
||||
h = list(service.history(2))
|
||||
assert h == [
|
||||
hist("five", True),
|
||||
hist("def concept five as 5", True)
|
||||
]
|
||||
|
||||
h = list(sheerka.history(2, 2))
|
||||
h = list(service.history(2, 2))
|
||||
assert h == [
|
||||
hist("four", True),
|
||||
hist("def concept four as 4", True),
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaIsAManager import SheerkaIsAManager
|
||||
@@ -278,7 +276,7 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
assert [c.id for c in concepts_in_cache] == [one.id]
|
||||
|
||||
# pretend that number has been updated in sheerka.concepts_grammar
|
||||
sheerka.concepts_grammars.put(number.id, "some parsing expression with 'one' only")
|
||||
sheerka.get_concepts_bnf_definitions().put(number.id, "some parsing expression with 'one' only")
|
||||
|
||||
# add another element to number
|
||||
sheerka.set_isa(context, sheerka.new("two"), number)
|
||||
@@ -289,7 +287,7 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
assert {c.id for c in concepts_in_cache} == {one.id, two.id}
|
||||
|
||||
# make sure the bnf definition is also updated
|
||||
assert number.id not in sheerka.concepts_grammars
|
||||
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(
|
||||
|
||||
@@ -88,7 +88,6 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.om.copy(SheerkaMemory.OBJECTS_ENTRY) == {"a": MemoryObject(context.event.get_digest(), foo)}
|
||||
assert id(sheerka.get_from_memory(context, "a").obj) == id(foo)
|
||||
|
||||
|
||||
def test_i_can_use_memory_with_a_string(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
@@ -129,6 +128,69 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert len(sheerka.om.get_all(SheerkaMemory.OBJECTS_ENTRY)) == 0
|
||||
|
||||
def test_adding_the_same_object_with_same_context_has_no_effect_when_one_element(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
service = sheerka.services[SheerkaMemory.NAME]
|
||||
|
||||
sheerka.add_to_memory(context, "item", foo)
|
||||
from_memory = service.get_from_memory(context, "item")
|
||||
|
||||
sheerka.add_to_memory(context, "item", foo)
|
||||
from_memory_again = service.get_from_memory(context, "item")
|
||||
assert from_memory_again == from_memory
|
||||
|
||||
def test_adding_the_same_object_with_same_context_has_no_effect_when_multiple_elements(self):
|
||||
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
|
||||
service = sheerka.services[SheerkaMemory.NAME]
|
||||
|
||||
sheerka.add_to_memory(context, "item", foo)
|
||||
sheerka.add_to_memory(context, "item", bar)
|
||||
sheerka.add_to_memory(context, "item", baz)
|
||||
from_memory = service.get_from_memory(context, "item").copy()
|
||||
|
||||
sheerka.add_to_memory(context, "item", baz)
|
||||
from_memory_again = service.get_from_memory(context, "item")
|
||||
assert from_memory_again == from_memory
|
||||
|
||||
def test_adding_the_same_object_with_a_different_context_updates_event_id_when_one_element(self):
|
||||
sheerka, context1, foo = self.init_concepts("foo")
|
||||
service = sheerka.services[SheerkaMemory.NAME]
|
||||
|
||||
sheerka.add_to_memory(context1, "item", foo)
|
||||
from_memory = service.get_from_memory(context1, "item")
|
||||
|
||||
context2 = self.get_context(self.sheerka, message="another message")
|
||||
sheerka.add_to_memory(context2, "item", foo)
|
||||
from_memory_again = service.get_from_memory(context2, "item")
|
||||
|
||||
assert from_memory_again != from_memory
|
||||
assert not isinstance(from_memory_again, list)
|
||||
|
||||
assert from_memory_again.obj == from_memory.obj
|
||||
assert from_memory_again.event_id == context2.event.get_digest()
|
||||
assert from_memory.event_id == context1.event.get_digest()
|
||||
|
||||
def test_adding_the_same_object_with_a_different_context_updates_event_id_when_multiple_elements(self):
|
||||
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
|
||||
service = sheerka.services[SheerkaMemory.NAME]
|
||||
|
||||
sheerka.add_to_memory(context, "item", foo)
|
||||
sheerka.add_to_memory(context, "item", bar)
|
||||
sheerka.add_to_memory(context, "item", baz)
|
||||
from_memory = service.get_from_memory(context, "item").copy()
|
||||
|
||||
context2 = self.get_context(self.sheerka, message="another message")
|
||||
sheerka.add_to_memory(context2, "item", baz)
|
||||
from_memory_again = service.get_from_memory(context2, "item")
|
||||
|
||||
assert isinstance(from_memory_again, list)
|
||||
assert len(from_memory) == len(from_memory_again)
|
||||
for mo, mo_again in zip(from_memory, from_memory_again[:-1]):
|
||||
assert mo == mo_again
|
||||
|
||||
assert from_memory[-1].obj == from_memory_again[-1].obj
|
||||
assert from_memory[-1].event_id != from_memory_again[-1].event_id
|
||||
|
||||
|
||||
class TestSheerkaMemoryUsingFileBase(TestUsingFileBasedSheerka):
|
||||
def test_i_can_record_memory_objects(self):
|
||||
|
||||
@@ -991,6 +991,18 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
assert isinstance(res[0], AndConditions)
|
||||
assert res[0].conditions == [Condition(V("__x_00__"), "__name__", "__ret")]
|
||||
|
||||
def test_i_can_properly_copy_a_rule(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
service = sheerka.services[SheerkaRuleManager.NAME]
|
||||
|
||||
rule = Rule(ACTION_TYPE_EXEC, "name", "id.attr == 'value'", 'test()')
|
||||
service.init_rule(context, rule)
|
||||
service.create_new_rule(context, rule)
|
||||
|
||||
clone = rule.__deepcopy__({})
|
||||
for k, v in vars(rule).items():
|
||||
assert getattr(clone, k) == getattr(rule, k)
|
||||
|
||||
|
||||
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||
def test_rules_are_initialized_at_startup(self):
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import ast
|
||||
|
||||
import pytest
|
||||
from core.ast_helpers import UnreferencedNamesVisitor, UnreferencedVariablesVisitor
|
||||
|
||||
from core.ast_helpers import UnreferencedNamesVisitor, UnreferencedVariablesVisitor
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ class TestAstHelper(TestUsingMemoryBasedSheerka):
|
||||
("date.today()", {"date"}),
|
||||
("test()", {"test"}),
|
||||
("sheerka.test()", {"sheerka"}),
|
||||
("for i in range(10): pass", set())
|
||||
("for i in range(10): pass", set()),
|
||||
("func(x=a, y=b)", {"func", "a", "b"}),
|
||||
|
||||
])
|
||||
def test_i_can_get_unreferenced_names_from_simple_expressions(self, source, expected):
|
||||
@@ -31,8 +32,8 @@ class TestAstHelper(TestUsingMemoryBasedSheerka):
|
||||
("date.today()", set()),
|
||||
("test()", set()),
|
||||
("sheerka.test()", set()),
|
||||
("for i in range(10): pass", set())
|
||||
|
||||
("for i in range(10): pass", set()),
|
||||
("func(x=a, y=b)", {"a", "b", "x", "y"}),
|
||||
])
|
||||
def test_i_can_get_unreferenced_variables_from_simple_expressions(self, source, expected):
|
||||
context = self.get_context()
|
||||
|
||||
@@ -8,10 +8,8 @@ from core.builtin_concepts_ids import AllBuiltinConcepts
|
||||
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts, get_concept_attrs
|
||||
from core.global_symbols import NotInit
|
||||
from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS
|
||||
from core.sheerka.SheerkaOntologyManager import OntologyAlreadyExists
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.tokenizer import Token, TokenKind
|
||||
|
||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
@@ -370,12 +368,10 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||
|
||||
foo = sheerka.create_new_concept(context, Concept("foo").def_var("a").def_var("b")).body.body
|
||||
sheerka.locals = {"key1": "value1"}
|
||||
|
||||
# sanity check
|
||||
assert sheerka.get_by_name("foo") == foo
|
||||
assert not sheerka.is_known(sheerka.get_by_name("bar"))
|
||||
assert sheerka.locals == {"key1": "value1"}
|
||||
assert get_concept_attrs(foo) == ["a", "b"]
|
||||
|
||||
# record the ontology
|
||||
@@ -386,12 +382,10 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
sheerka.push_ontology(context, "another ontology")
|
||||
foo2 = sheerka.create_new_concept(context, Concept("foo").def_var("a").def_var("b").def_var("c")).body.body
|
||||
bar = sheerka.create_new_concept(context, Concept("bar")).body.body
|
||||
sheerka.locals = {"key2": "value2"}
|
||||
|
||||
# sanity check
|
||||
assert sheerka.get_by_name("foo") == foo2
|
||||
assert sheerka.get_by_name("bar") == bar
|
||||
assert sheerka.locals == {"key2": "value2"}
|
||||
assert get_concept_attrs(foo) == ["a", "b", "c"]
|
||||
|
||||
# put pack the previous ontology
|
||||
@@ -399,14 +393,12 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert sheerka.get_by_name("foo") == foo # not [foo, foo2], foo2 is not seen !!!
|
||||
assert sheerka.get_by_name("bar") == bar
|
||||
assert sheerka.locals == {"key1": "value1"}
|
||||
assert get_concept_attrs(foo) == ["a", "b"]
|
||||
|
||||
# sanity check
|
||||
sheerka.pop_ontology(context)
|
||||
assert sheerka.get_by_name("foo") == foo2
|
||||
assert sheerka.get_by_name("bar") == bar
|
||||
assert sheerka.locals == {"key2": "value2"}
|
||||
assert get_concept_attrs(foo) == ["a", "b", "c"]
|
||||
|
||||
def test_adding_the_same_ontology_twice_has_no_effect(self):
|
||||
|
||||
@@ -151,7 +151,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
|
||||
service = SheerkaExecute(sheerka)
|
||||
service.reset_registered_parsers()
|
||||
|
||||
groups, sorted_priorities = service.get_parsers(context)
|
||||
parsers_key, groups, sorted_priorities = service.get_parsers(context)
|
||||
assert parsers_key == "__default"
|
||||
assert groups == {80: [Enabled80FalseParser()], 90: [Enabled90FalseParser()]}
|
||||
assert sorted_priorities == [90, 80]
|
||||
|
||||
@@ -169,7 +170,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
|
||||
parsers_names = ["Enabled50True", "Enabled70False", "Disabled"]
|
||||
context.preprocess_parsers = parsers_names
|
||||
|
||||
groups, sorted_priorities = service.get_parsers(context)
|
||||
parsers_key, groups, sorted_priorities = service.get_parsers(context)
|
||||
assert parsers_key == "Enabled50True|Enabled70False|Disabled"
|
||||
assert groups == {50: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]}
|
||||
assert sorted_priorities == [70, 50] # Disabled parser does not appear
|
||||
|
||||
@@ -195,7 +197,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
|
||||
context.add_preprocess(BaseParser.get_name("Enabled90False"), enabled=False)
|
||||
context.add_preprocess(BaseParser.get_name("Enabled50True"), priority=80)
|
||||
|
||||
groups, sorted_priorities = service.get_parsers(context)
|
||||
parsers_key, groups, sorted_priorities = service.get_parsers(context)
|
||||
assert parsers_key is None
|
||||
assert groups == {80: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]}
|
||||
assert sorted_priorities == [80, 70] # Disabled parsers does not appear
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import ast
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.concept import VARIABLE_PREFIX, Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.DefConceptEvaluator import DefConceptEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from parsers.BnfDefinitionParser import BnfDefinitionParser
|
||||
from parsers.BnfNodeParser import Sequence, StrMatch, ZeroOrMore, ConceptExpression
|
||||
from parsers.DefConceptParser import DefConceptNode, NameNode
|
||||
from parsers.DefConceptParser import DefConceptNode, NameNode, DefConceptParser
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@@ -244,3 +245,35 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert new_concept.get_metadata().body == 'foo'
|
||||
assert new_concept.values() == {}
|
||||
assert new_concept.get_metadata().variables == []
|
||||
|
||||
def test_i_can_get_variable_when_rule_is_defined(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
def_concept_parser = DefConceptParser()
|
||||
|
||||
parsed_ret_val = def_concept_parser.parse(context, ParserInput("def concept rule x as r:|x:"))
|
||||
assert parsed_ret_val.status # sanity check
|
||||
|
||||
evaluated = DefConceptEvaluator().eval(context, parsed_ret_val)
|
||||
assert evaluated.status
|
||||
assert evaluated.body.body.key == "rule __var__0"
|
||||
assert evaluated.body.body.get_metadata().variables == [("x", None)]
|
||||
|
||||
def test_i_can_recognize_variable_when_keyword_argument(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
def_concept_parser = DefConceptParser()
|
||||
|
||||
parsed_ret_val = def_concept_parser.parse(context, ParserInput("def concept foo1 x as func(param=x)"))
|
||||
assert parsed_ret_val.status # sanity check
|
||||
|
||||
evaluated = DefConceptEvaluator().eval(context, parsed_ret_val)
|
||||
assert evaluated.status
|
||||
assert evaluated.body.body.key == "foo1 __var__0"
|
||||
assert evaluated.body.body.get_metadata().variables == [("x", None)]
|
||||
|
||||
parsed_ret_val = def_concept_parser.parse(context, ParserInput("def concept foo2 x as func(x=value)"))
|
||||
assert parsed_ret_val.status # sanity check
|
||||
|
||||
evaluated = DefConceptEvaluator().eval(context, parsed_ret_val)
|
||||
assert evaluated.status
|
||||
assert evaluated.body.body.key == "foo2 __var__0"
|
||||
assert evaluated.body.body.get_metadata().variables == [("x", None)]
|
||||
|
||||
@@ -12,7 +12,6 @@ from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError, NamesWi
|
||||
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@@ -293,21 +292,6 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert error1.error.args[0] == 'can only concatenate str (not "int") to str'
|
||||
assert error1.concepts == {'foo': 'string'}
|
||||
|
||||
def test_i_can_use_sheerka_locals(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
def func(i):
|
||||
return i + 1
|
||||
|
||||
sheerka.locals["func"] = func
|
||||
|
||||
parsed = PythonParser().parse(context, ParserInput("func(10)"))
|
||||
python_evaluator = PythonEvaluator()
|
||||
evaluated = python_evaluator.eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == 11
|
||||
|
||||
def test_i_can_eval_concept_with_ret(self):
|
||||
sheerka, context, one, the = self.init_concepts("one", Concept("the a", ret="a").def_var("a"))
|
||||
ret_val = get_ret_val_from_source_code(context, "test_using_context(the one)", {
|
||||
@@ -339,6 +323,17 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert evaluated.status
|
||||
assert evaluated.value == "Print return values"
|
||||
|
||||
def test_i_can_update_sheerka_memory_using_assignation(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
parsed = PythonParser().parse(context, ParserInput("a = 10"))
|
||||
python_evaluator = PythonEvaluator()
|
||||
evaluated = python_evaluator.eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
from_memory = sheerka.get_from_memory(context, "a")
|
||||
assert from_memory.obj == 10
|
||||
|
||||
@pytest.mark.parametrize("method, expected_status", [
|
||||
("return_return_value(True)", True),
|
||||
("return_return_value(False)", False),
|
||||
@@ -389,3 +384,13 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == context.sheerka.get_rule_by_id(str(value)).name
|
||||
|
||||
def test_something(self):
|
||||
def func(**kwargs):
|
||||
for k, v in kwargs.items():
|
||||
print(f"{k=}, {v=}")
|
||||
|
||||
to_compile = "func(x=y)"
|
||||
ast_ = ast.parse(to_compile, mode="eval")
|
||||
compiled = compile(ast_, "<test>", mode="eval")
|
||||
eval(compiled, {"x": "hello", "y": "world", "func": func})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, CC
|
||||
from core.global_symbols import NotInit
|
||||
@@ -6,9 +7,7 @@ from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
|
||||
from evaluators.PythonEvaluator import PythonEvalError
|
||||
from parsers.BaseNodeParser import SyaAssociativity
|
||||
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
|
||||
|
||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
@@ -949,7 +948,7 @@ as:
|
||||
sheerka = self.init_scenario(init)
|
||||
|
||||
# simulate that sheerka was stopped and restarted
|
||||
sheerka.om.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY)
|
||||
sheerka.clear_bnf_definition()
|
||||
sheerka.om.get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "twenties").set_compiled({})
|
||||
|
||||
res = sheerka.evaluate_user_input("eval twenty one")
|
||||
@@ -1114,23 +1113,6 @@ as:
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
def test_i_can_eval_concepts_fed_with_functions(self):
|
||||
init = [
|
||||
"def concept inc a as a + 1",
|
||||
"def concept one as 1"
|
||||
]
|
||||
|
||||
def times_five(i):
|
||||
return i * 5
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka.locals["times_five"] = times_five
|
||||
|
||||
res = sheerka.evaluate_user_input("eval inc times_five(one)")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == 6
|
||||
|
||||
def test_i_can_define_a_concept_when_where_clause_contains_the_name_of_the_variable(self):
|
||||
init = [
|
||||
"def concept x is a y as isa(x,y) pre is_question()",
|
||||
@@ -1231,7 +1213,8 @@ as:
|
||||
|
||||
def test_i_can_define_rules_priorities(self):
|
||||
sheerka, context, r1, r2 = self.init_test().with_format_rules(("True", "True"), ("False", "False")).unpack()
|
||||
sheerka.evaluate_user_input("def concept rule x > rule y where isinstance(x, int) and isinstance(y, int) as set_is_greater_than(__PRECEDENCE, r:|x:, r:|y:, 'Rule')")
|
||||
sheerka.evaluate_user_input(
|
||||
"def concept rule x > rule y where isinstance(x, int) and isinstance(y, int) as set_is_greater_than(__PRECEDENCE, r:|x:, r:|y:, 'Rule')")
|
||||
|
||||
res = sheerka.evaluate_user_input(f"eval rule {r1.id} > rule {r2.id}")
|
||||
|
||||
@@ -1242,6 +1225,18 @@ as:
|
||||
weights = sheerka.get_weights(BuiltinConcepts.PRECEDENCE, 'Rule')
|
||||
assert weights[r1.str_id] == weights[r2.str_id] + 1
|
||||
|
||||
def test_i_can_get_history_after_def_rule_parser(self):
|
||||
sheerka = self.get_sheerka()
|
||||
sheerka.save_execution_context = True
|
||||
sheerka.evaluate_user_input("when True then answer('that is true')")
|
||||
res = sheerka.evaluate_user_input("history()")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
l = list(res[0].body.body)
|
||||
assert len(l) > 0
|
||||
sheerka.save_execution_context = False
|
||||
|
||||
|
||||
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
||||
def test_i_can_def_several_concepts(self):
|
||||
|
||||
@@ -122,3 +122,20 @@ __default__
|
||||
assert captured.out == """one: (1001)one
|
||||
two: (1002)two
|
||||
"""
|
||||
|
||||
def test_i_can_retrieve_history(self, capsys):
|
||||
init = [
|
||||
"test()",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
capsys.readouterr()
|
||||
|
||||
sheerka.enable_process_return_values = True
|
||||
res = sheerka.evaluate_user_input(f"history()")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert " : test()" in captured.out
|
||||
assert " : history()" in captured.out
|
||||
|
||||
@@ -1169,7 +1169,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser(init_from_sheerka=True)
|
||||
sheerka.concepts_grammars.clear() # to simulate restart
|
||||
sheerka.clear_bnf_definition() # to simulate restart
|
||||
text = "one thousand"
|
||||
|
||||
one = CC("one", body=DoNotResolve("one"))
|
||||
@@ -1195,7 +1195,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser(init_from_sheerka=True)
|
||||
sheerka.concepts_grammars.clear() # to simulate restart
|
||||
sheerka.clear_bnf_definition() # to simulate restart
|
||||
text = "fifty one thousand"
|
||||
|
||||
one = CC("one", body=DoNotResolve("one"))
|
||||
@@ -1233,7 +1233,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_i_can_parse_one_hundred_thousand(self):
|
||||
sheerka, context, parser = self.init_parser(init_from_sheerka=True)
|
||||
sheerka.concepts_grammars.clear() # to simulate restart
|
||||
sheerka.clear_bnf_definition() # to simulate restart
|
||||
|
||||
text = "one hundred thousand"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
@@ -1244,7 +1244,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_i_can_parse_hundreds_like_expression(self):
|
||||
sheerka, context, parser = self.init_parser(init_from_sheerka=True)
|
||||
sheerka.concepts_grammars.clear()
|
||||
sheerka.clear_bnf_definition() # to simulate restart
|
||||
|
||||
text = "three hundred and thirty two"
|
||||
three = CC("three", body=DoNotResolve("three"))
|
||||
@@ -1280,7 +1280,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_i_can_parse_bnf_concept_mixed_with_isa_after_restart(self):
|
||||
sheerka, context, parser = self.init_parser(init_from_sheerka=True)
|
||||
sheerka.concepts_grammars.clear() # simulate restart
|
||||
sheerka.clear_bnf_definition() # to simulate restart
|
||||
for c in cmap.values():
|
||||
sheerka.get_by_id(c.id).set_bnf(None)
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.rule import Rule
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.BaseNodeParser import SCN, SCWC, CN, UTN, CNC, RN
|
||||
from parsers.FunctionParser import FunctionParser, FN
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array
|
||||
|
||||
|
||||
@@ -968,7 +968,7 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_debug(self, expression, expected_debugs):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
sheerka.set_debug(context, True)
|
||||
sheerka.debug_var(context, "Sya")
|
||||
sheerka.set_debug_var(context, "Sya")
|
||||
res = parser.infix_to_postfix(context, ParserInput(expression))
|
||||
|
||||
assert len(res) == len(expected_debugs)
|
||||
@@ -983,7 +983,7 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_debug_can_pop_using_star(self, settings):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
sheerka.set_debug(context, True)
|
||||
sheerka.debug_var(context, settings)
|
||||
sheerka.set_debug_var(context, settings)
|
||||
res = parser.infix_to_postfix(context, ParserInput("one plus two mult three"))
|
||||
|
||||
debug = [str(di) for di in res[0].debug]
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts
|
||||
from core.concept import Concept, CC
|
||||
from core.tokenizer import Tokenizer, TokenKind
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, scnode, cnode, \
|
||||
utnode, SyaAssociativity, CN, CNC, UTN, SourceCodeWithConceptNode, SCWC, SourceCodeNode
|
||||
utnode, CN, CNC, UTN, SourceCodeWithConceptNode, SCWC, SourceCodeNode
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
from parsers.UnrecognizedNodeParser import UnrecognizedNodeParser
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, get_node
|
||||
|
||||
@@ -208,49 +207,64 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
|
||||
[CNC("twenties", source="twenty two", unit="two")])
|
||||
assert res.body.concept.get_compiled()["b"].get_compiled()["b"][0].body.body == expected_nodes
|
||||
|
||||
# def test_i_can_validate_and_evaluate_a_concept_node_with_python(self):
|
||||
# sheerka, context, parser = self.init_parser()
|
||||
#
|
||||
# node = get_input_nodes_from(
|
||||
# concepts_map,
|
||||
# "one plus 1 + 1",
|
||||
# CNC("plus",
|
||||
# a=UTN("one "),
|
||||
# b=UTN("1 + 1")))[0]
|
||||
#
|
||||
# res = UnrecognizedNodeParser().validate_concept_node(context, node)
|
||||
#
|
||||
# assert res.status
|
||||
# assert res.body.concept == concepts_map["plus"]
|
||||
# assert res.body.concept.get_compiled()["a"] == concepts_map["one"]
|
||||
# assert len(res.body.concept.get_compiled()["b"]) == 1
|
||||
# assert sheerka.isinstance(res.body.concept.get_compiled()["b"][0], BuiltinConcepts.RETURN_VALUE)
|
||||
# assert res.body.concept.get_compiled()["b"][0].status
|
||||
# assert res.body.concept.get_compiled()["b"][0].who == "parsers.Python"
|
||||
# assert res.body.concept.get_compiled()["b"][0].body.source == "1 + 1"
|
||||
#
|
||||
# # # evaluate
|
||||
# # context = self.get_context(sheerka, eval_body=True)
|
||||
# # evaluated = sheerka.evaluate_concept(context, res.body.concept)
|
||||
# # assert evaluated.body == 3
|
||||
def test_i_can_validate_and_evaluate_a_concept_node_with_python(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
node = get_input_nodes_from(
|
||||
concepts_map,
|
||||
"one plus 1 + 1",
|
||||
CNC("plus",
|
||||
a=UTN("one "),
|
||||
b=UTN("1 + 1")))[0]
|
||||
|
||||
res = UnrecognizedNodeParser().validate_concept_node(context, node)
|
||||
|
||||
assert res.status
|
||||
concept_found = res.body.concept
|
||||
compiled = concept_found.get_compiled()
|
||||
assert concept_found == concepts_map["plus"]
|
||||
assert len(compiled["a"]) == 1
|
||||
assert sheerka.isinstance(compiled["a"][0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert compiled["a"][0].body.body[0].concept.id == concepts_map["one"].id
|
||||
|
||||
assert len(compiled["b"]) == 1
|
||||
assert sheerka.isinstance(compiled["b"][0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert compiled["b"][0].status
|
||||
assert compiled["b"][0].who == "parsers.Python"
|
||||
assert compiled["b"][0].body.source == "1 + 1"
|
||||
|
||||
# def test_i_can_validate_and_evaluate_concept_when_bnf_concept(self):
|
||||
# sheerka, context, parser = self.init_parser()
|
||||
# node = get_concept_node(concepts_map, "one plus twenty one", "plus", "one", "twenty one")
|
||||
#
|
||||
# res = UnrecognizedNodeParser().validate_concept_node(context, node)
|
||||
#
|
||||
# assert res.status
|
||||
# assert res.body.concept == concepts_map["plus"]
|
||||
# assert res.body.concept.get_compiled()["a"] == concepts_map["one"]
|
||||
# assert len(res.body.concept.get_compiled()["b"]) == 1
|
||||
# assert res.body.concept.get_compiled()["b"][0].status
|
||||
# assert res.body.concept.get_compiled()["b"][0].who == "parsers.BnfNode"
|
||||
#
|
||||
# # evaluate
|
||||
# context = self.get_context(sheerka, eval_body=True)
|
||||
# evaluated = sheerka.evaluate_concept(context, res.body.concept)
|
||||
# assert evaluated.body == 22
|
||||
context = self.get_context(sheerka, eval_body=True)
|
||||
evaluated = sheerka.evaluate_concept(context, res.body.concept)
|
||||
assert evaluated.body == 3
|
||||
|
||||
def test_i_can_validate_and_evaluate_concept_when_bnf_concept(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
node = get_input_nodes_from(
|
||||
concepts_map,
|
||||
"one plus twenty one",
|
||||
CNC("plus",
|
||||
a=UTN("one "),
|
||||
b=UTN("twenty one")))[0]
|
||||
|
||||
res = UnrecognizedNodeParser().validate_concept_node(context, node)
|
||||
|
||||
assert res.status
|
||||
concept_found = res.body.concept
|
||||
compiled = concept_found.get_compiled()
|
||||
assert concept_found == concepts_map["plus"]
|
||||
assert len(compiled["a"]) == 1
|
||||
assert sheerka.isinstance(compiled["a"][0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert compiled["a"][0].body.body[0].concept.id == concepts_map["one"].id
|
||||
|
||||
assert len(compiled["b"]) == 1
|
||||
assert compiled["b"][0].status
|
||||
assert compiled["b"][0].who == "parsers.Bnf"
|
||||
|
||||
# evaluate
|
||||
context = self.get_context(sheerka, eval_body=True)
|
||||
evaluated = sheerka.evaluate_concept(context, res.body.concept)
|
||||
assert evaluated.body == 22
|
||||
|
||||
def test_i_can_parse_and_evaluate_unrecognized_python_node(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -245,8 +245,10 @@ class TestReteConditions(TestUsingMemoryBasedSheerka):
|
||||
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 2
|
||||
assert matches[0].token.wmes == [wme3, wme2]
|
||||
assert matches[1].token.wmes == [wme1, wme3]
|
||||
# assert matches[0].token.wmes == [wme3, wme2]
|
||||
# assert matches[1].token.wmes == [wme1, wme3]
|
||||
assert len(matches[0].token.wmes) == 2
|
||||
assert len(matches[1].token.wmes) == 2
|
||||
|
||||
def test_i_can_manage_binding_conditions(self):
|
||||
network = ReteNetwork()
|
||||
|
||||
@@ -638,15 +638,26 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
|
||||
network.remove_rule(rule3)
|
||||
assert len(list(p_node3.activations)) == 0
|
||||
|
||||
def test_rule_is_added_to_rete_network_when_it_is_created(self):
|
||||
def test_exec_rule_is_added_to_rete_network_when_it_is_created(self):
|
||||
sheerka, context, rule = self.init_test().with_exec_rules(("rule_name", "id.attr == 'value'", 'True')).unpack()
|
||||
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
rete_network = evaluation_service.network
|
||||
|
||||
assert len(rete_network.pnodes) == 1
|
||||
assert rete_network.pnodes[0].rules[0] == rule
|
||||
assert rule.rete_net == rete_network
|
||||
assert len(rule.rete_p_nodes) > 0
|
||||
|
||||
def test_rule_is_removed_to_rete_network_when_it_is_deleted(self):
|
||||
def test_format_rule_is_not_added_to_rete_network_when_it_is_created(self):
|
||||
sheerka, context, rule = self.init_test().with_format_rules(("rule_name", "id.attr == 'value'", 'True')).unpack()
|
||||
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
rete_network = evaluation_service.network
|
||||
|
||||
assert len(rete_network.pnodes) == 0
|
||||
assert rule.rete_net is None
|
||||
assert len(rule.rete_p_nodes) == 0
|
||||
|
||||
def test_rule_is_removed_from_rete_network_when_it_is_deleted(self):
|
||||
sheerka, context, rule = self.init_test().with_exec_rules(("id.attr == 'value'", 'True')).unpack()
|
||||
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
rete_network = evaluation_service.network
|
||||
@@ -654,6 +665,15 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
|
||||
sheerka.remove_rule(context, rule)
|
||||
assert len(rete_network.pnodes) == 0
|
||||
|
||||
def test_rule_is_removed_from_rete_network_when_it_is_deleted_from_another_ontology(self):
|
||||
sheerka, context, rule = self.init_test().with_exec_rules(("id.attr == 'value'", 'True')).unpack()
|
||||
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
rete_network = evaluation_service.network
|
||||
|
||||
sheerka.push_ontology(context, "new ontology")
|
||||
sheerka.remove_rule(context, rule)
|
||||
assert len(rete_network.pnodes) == 0
|
||||
|
||||
def test_rules_are_removed_upon_ontology_removal(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
service = sheerka.services[SheerkaRuleManager.NAME]
|
||||
|
||||
Reference in New Issue
Block a user