Fixed RET functionnality misbehaviour
This commit is contained in:
@@ -14,3 +14,4 @@ clean:
|
|||||||
rm -rf tests/prof
|
rm -rf tests/prof
|
||||||
find . -name '.pytest_cache' -exec rm -rf {} +
|
find . -name '.pytest_cache' -exec rm -rf {} +
|
||||||
find . -name '__pycache__' -exec rm -rf {} +
|
find . -name '__pycache__' -exec rm -rf {} +
|
||||||
|
find . -name 'debug.txt' -exec rm -rf {} +
|
||||||
|
|||||||
@@ -82,3 +82,5 @@ last_created_concept() is number
|
|||||||
def concept history as history()
|
def concept history as history()
|
||||||
def concept plus from a plus b as a + b
|
def concept plus from a plus b as a + b
|
||||||
def concept mult from a mult b as a * b
|
def concept mult from a mult b as a * b
|
||||||
|
def concept explain as get_results() | filter("id == 0") | recurse(2)
|
||||||
|
def concept explain last as get_last_results() | filter("id == 0") | recurse(2)
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
def concept one as 1
|
||||||
|
def concept two as 2
|
||||||
|
def concept plus from a plus b as a + b
|
||||||
|
def concept explain as get_results() | filter("id == 0") | recurse(2)
|
||||||
|
def concept explain last as get_last_results() | filter("id == 0") | recurse(2)
|
||||||
@@ -3,7 +3,8 @@ import time
|
|||||||
from core.builtin_concepts import BuiltinConcepts
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
|
|
||||||
CONCEPTS_FILE = "_concepts.txt"
|
CONCEPTS_FILE = "_concepts_lite.txt"
|
||||||
|
CONCEPTS_FILE_ALL_CONCEPTS = "_concepts.txt"
|
||||||
|
|
||||||
|
|
||||||
class SheerkaAdmin(BaseService):
|
class SheerkaAdmin(BaseService):
|
||||||
@@ -37,15 +38,19 @@ class SheerkaAdmin(BaseService):
|
|||||||
|
|
||||||
return self.sheerka.cache_manager.caches[name].cache.copy()
|
return self.sheerka.cache_manager.caches[name].cache.copy()
|
||||||
|
|
||||||
def restore(self):
|
def restore(self, concept_file=CONCEPTS_FILE):
|
||||||
"""
|
"""
|
||||||
Restore the state with all previous valid concept definitions
|
Restore the state with all previous valid concept definitions
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if concept_file == "full":
|
||||||
|
concept_file = CONCEPTS_FILE_ALL_CONCEPTS
|
||||||
|
|
||||||
try:
|
try:
|
||||||
start = time.time_ns()
|
start = time.time_ns()
|
||||||
self.sheerka.during_restore = True
|
self.sheerka.during_restore = True
|
||||||
with open(CONCEPTS_FILE, "r") as f:
|
with open(concept_file, "r") as f:
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line == "" or line.startswith("#"):
|
if line == "" or line.startswith("#"):
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def apply_ret(concept):
|
||||||
|
"""
|
||||||
|
Check if a concept has its RET part defined
|
||||||
|
If True, returns it
|
||||||
|
:param concept:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return concept.get_value(ConceptParts.RET) if ConceptParts.RET in concept.values else concept
|
||||||
|
|
||||||
def manage_infinite_recursion(self, context):
|
def manage_infinite_recursion(self, context):
|
||||||
"""
|
"""
|
||||||
We look for the fist parent that has a body that means something
|
We look for the fist parent that has a body that means something
|
||||||
@@ -189,7 +199,7 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
evaluated = self.evaluate_concept(sub_context, to_resolve)
|
evaluated = self.evaluate_concept(sub_context, to_resolve)
|
||||||
sub_context.add_values(return_values=evaluated)
|
sub_context.add_values(return_values=evaluated)
|
||||||
if evaluated.key == to_resolve.key:
|
if evaluated.key == to_resolve.key:
|
||||||
return evaluated
|
return self.apply_ret(evaluated)
|
||||||
else:
|
else:
|
||||||
error = evaluated
|
error = evaluated
|
||||||
|
|
||||||
@@ -324,9 +334,9 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
concept.init_key() # only does it if needed
|
concept.init_key() # only does it if needed
|
||||||
concept.metadata.is_evaluated = "body" in all_metadata_to_eval
|
concept.metadata.is_evaluated = "body" in all_metadata_to_eval
|
||||||
|
|
||||||
# # update the cache for concepts with no variable
|
# update the cache for concepts with no variable
|
||||||
# if len(concept.metadata.variables) == 0:
|
if len(concept.metadata.variables) == 0:
|
||||||
# self.sheerka.cache_manager.put(self.sheerka.CONCEPTS_BY_ID_ENTRY, concept.id, concept)
|
self.sheerka.cache_manager.put(self.sheerka.CONCEPTS_BY_ID_ENTRY, concept.id, concept)
|
||||||
|
|
||||||
return concept
|
return concept
|
||||||
|
|
||||||
|
|||||||
@@ -434,11 +434,22 @@ class SheerkaFilter(BaseService):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def pipe_inspect(self, iterable, path, when=None):
|
def pipe_inspect(self, iterable, path, when=None):
|
||||||
compiled = self.get_compiled("inspect", path)
|
"""
|
||||||
|
Follow the path
|
||||||
|
:param iterable:
|
||||||
|
:param path:
|
||||||
|
:param when:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# quick and dirty implementation as it does not handle dictionaries items
|
||||||
for item in iterable:
|
for item in iterable:
|
||||||
try:
|
try:
|
||||||
|
props = path.split(".")
|
||||||
|
for prop in props:
|
||||||
|
compiled = self.get_compiled("inspect", prop)
|
||||||
context = {} if is_primitive(item) else as_bag(item)
|
context = {} if is_primitive(item) else as_bag(item)
|
||||||
context["self"] = item
|
item = eval(compiled, context)
|
||||||
yield eval(compiled, context)
|
|
||||||
|
yield item
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
yield ex
|
yield ex
|
||||||
|
|||||||
@@ -6,6 +6,16 @@ import re
|
|||||||
from core.tokenizer import TokenKind
|
from core.tokenizer import TokenKind
|
||||||
|
|
||||||
|
|
||||||
|
def my_debug(*args):
|
||||||
|
with open("debug.txt", "a") as f:
|
||||||
|
for arg in args:
|
||||||
|
if isinstance(arg, list):
|
||||||
|
for item in arg:
|
||||||
|
f.write(f"{item}\n")
|
||||||
|
else:
|
||||||
|
f.write(f"{arg}\n")
|
||||||
|
|
||||||
|
|
||||||
def sysarg_to_string(argv):
|
def sysarg_to_string(argv):
|
||||||
"""
|
"""
|
||||||
Transform a list of strings into a single string
|
Transform a list of strings into a single string
|
||||||
|
|||||||
@@ -83,11 +83,12 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
props_found.add(p)
|
props_found.add(p)
|
||||||
|
|
||||||
# add variables by order of appearance when possible
|
# add variables by order of appearance when possible
|
||||||
for token in def_concept_node.name.tokens:
|
for name_part in name_to_use:
|
||||||
if token.value in props_found:
|
if name_part in props_found:
|
||||||
concept.def_var(token.value, None)
|
concept.def_var(name_part, None)
|
||||||
|
|
||||||
# add the remaining properties
|
# add the remaining properties
|
||||||
|
# They mainly come from BNF definition
|
||||||
for p in props_found:
|
for p in props_found:
|
||||||
if p not in concept.values:
|
if p not in concept.values:
|
||||||
concept.def_var(p, None)
|
concept.def_var(p, None)
|
||||||
@@ -112,7 +113,7 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_name_to_use(node):
|
def get_name_to_use(node):
|
||||||
source = node.definition if node.definition_type == DEFINITION_TYPE_DEF else node.name
|
source = node.definition if node.definition_type == DEFINITION_TYPE_DEF else node.name
|
||||||
return [part.value for part in core.utils.strip_tokens(source.tokens, True)]
|
return [part.str_value for part in core.utils.strip_tokens(source.tokens, True)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_variables(sheerka, ret_value, concept_name):
|
def get_variables(sheerka, ret_value, concept_name):
|
||||||
|
|||||||
@@ -196,6 +196,19 @@ class ConceptNode(LexerNode):
|
|||||||
clone = ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying)
|
clone = ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
|
def as_bag(self):
|
||||||
|
"""
|
||||||
|
Creates a dictionary with the useful properties of the ConceptNode
|
||||||
|
see Concept.as_bag() for extra informations
|
||||||
|
"""
|
||||||
|
bag = {}
|
||||||
|
for k, v in self.__dict__.items():
|
||||||
|
bag[k] = v
|
||||||
|
|
||||||
|
# if isinstance(self.concept, Concept):
|
||||||
|
# bag["compiled"] = self.concept.compiled
|
||||||
|
return bag
|
||||||
|
|
||||||
|
|
||||||
class SourceCodeNode(LexerNode):
|
class SourceCodeNode(LexerNode):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ from parsers.BaseParser import BaseParser
|
|||||||
PARSERS = ["AtomNode", "SyaNode", "Python"]
|
PARSERS = ["AtomNode", "SyaNode", "Python"]
|
||||||
|
|
||||||
|
|
||||||
# def debug(obj):
|
|
||||||
# with open("debug.txt", "a") as f:
|
|
||||||
# f.write(f"{obj}\n")
|
|
||||||
|
|
||||||
def debug(obj):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ParsingContext:
|
class ParsingContext:
|
||||||
"""
|
"""
|
||||||
@@ -185,7 +177,6 @@ class ParsingExpression:
|
|||||||
return hash((self.rule_name, self.elements))
|
return hash((self.rule_name, self.elements))
|
||||||
|
|
||||||
def parse(self, parser):
|
def parse(self, parser):
|
||||||
debug(self)
|
|
||||||
# TODO : add memoization
|
# TODO : add memoization
|
||||||
return self._parse(parser)
|
return self._parse(parser)
|
||||||
|
|
||||||
@@ -590,7 +581,6 @@ class StrMatch(Match):
|
|||||||
parser_helper.next_token(self.skip_white_space)
|
parser_helper.next_token(self.skip_white_space)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
debug(f"Failed to match {self}. {token=}")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -811,7 +801,6 @@ class BnfConceptParserHelper:
|
|||||||
self.token = self.parser.parser_input.tokens[self.pos]
|
self.token = self.parser.parser_input.tokens[self.pos]
|
||||||
|
|
||||||
# parse
|
# parse
|
||||||
debug(f"parsing {parsing_expression} against '{self.parser.parser_input.text}'")
|
|
||||||
node = parsing_expression.parse(self)
|
node = parsing_expression.parse(self)
|
||||||
|
|
||||||
if isinstance(node, MultiNode):
|
if isinstance(node, MultiNode):
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Obj:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class ObjWithAsBag:
|
class ObjWithAsBag:
|
||||||
prop1: str
|
prop1: str
|
||||||
prop2: str
|
prop2: object
|
||||||
|
|
||||||
def as_bag(self):
|
def as_bag(self):
|
||||||
return {
|
return {
|
||||||
@@ -227,3 +227,7 @@ class TestSheerkaFilter(TestUsingMemoryBasedSheerka):
|
|||||||
res = lst | Pipe(filter_service.pipe_inspect)("second_prop")
|
res = lst | Pipe(filter_service.pipe_inspect)("second_prop")
|
||||||
|
|
||||||
assert list(res) == ["b", "d"]
|
assert list(res) == ["b", "d"]
|
||||||
|
|
||||||
|
lst = [ObjWithAsBag("a", ObjWithAsBag("b", ObjWithAsBag("c", "d")))]
|
||||||
|
res = lst | Pipe(filter_service.pipe_inspect)("second_prop.second_prop.second_prop")
|
||||||
|
assert list(res) == ["d"]
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
def_concept.post = self.get_concept_part(post)
|
def_concept.post = self.get_concept_part(post)
|
||||||
if ret:
|
if ret:
|
||||||
def_concept.ret = self.get_concept_part(ret)
|
def_concept.ret = self.get_concept_part(ret)
|
||||||
|
|
||||||
if bnf_def:
|
if bnf_def:
|
||||||
def_concept.definition = bnf_def
|
def_concept.definition = bnf_def
|
||||||
def_concept.definition_type = DEFINITION_TYPE_BNF
|
def_concept.definition_type = DEFINITION_TYPE_BNF
|
||||||
@@ -174,6 +175,15 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
assert AddConceptEvaluator.get_variables(context.sheerka, ret_val, ["a", "b"]) == ["a"]
|
assert AddConceptEvaluator.get_variables(context.sheerka, ret_val, ["a", "b"]) == ["a"]
|
||||||
|
|
||||||
|
def test_i_can_get_variables_when_keywords(self):
|
||||||
|
sheerka, context = self.init_concepts()
|
||||||
|
|
||||||
|
def_concept = self.get_def_concept("condition pre").value.value
|
||||||
|
name_to_use = AddConceptEvaluator.get_name_to_use(def_concept)
|
||||||
|
concept_part = self.get_concept_part("pre")
|
||||||
|
|
||||||
|
assert AddConceptEvaluator.get_variables(context.sheerka, concept_part, name_to_use) == ["pre"]
|
||||||
|
|
||||||
def test_i_cannot_get_variables_from_python_node_when_name_has_only_one_token(self):
|
def test_i_cannot_get_variables_from_python_node_when_name_has_only_one_token(self):
|
||||||
ret_val = self.get_concept_part("isinstance(a, str)")
|
ret_val = self.get_concept_part("isinstance(a, str)")
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
|
|||||||
@@ -44,3 +44,4 @@ class TestRetEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
res = RetEvaluator().eval(context, ret_value)
|
res = RetEvaluator().eval(context, ret_value)
|
||||||
assert res.status
|
assert res.status
|
||||||
assert sheerka.isinstance(res.body, expected)
|
assert sheerka.isinstance(res.body, expected)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from core.builtin_concepts import BuiltinConcepts
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit
|
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit, CC
|
||||||
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||||
from evaluators.PythonEvaluator import PythonEvalError
|
from evaluators.PythonEvaluator import PythonEvalError
|
||||||
from parsers.BaseNodeParser import SyaAssociativity
|
from parsers.BaseNodeParser import SyaAssociativity
|
||||||
@@ -976,6 +976,28 @@ as:
|
|||||||
assert res[0].status
|
assert res[0].status
|
||||||
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
||||||
|
|
||||||
|
def test_i_can_evaluate_sya_and_ret_concepts(self):
|
||||||
|
init = [
|
||||||
|
"def concept one as 1",
|
||||||
|
"def concept plus from a plus b as a + b",
|
||||||
|
"def concept the a ret a"
|
||||||
|
]
|
||||||
|
|
||||||
|
sheerka = self.init_scenario(init)
|
||||||
|
the = sheerka.get_by_name("the a")
|
||||||
|
|
||||||
|
# res = sheerka.evaluate_user_input("one plus the one")
|
||||||
|
# assert res[0].status
|
||||||
|
# plus = res[0].body
|
||||||
|
# assert isinstance(plus, Concept)
|
||||||
|
# assert plus.name == "plus"
|
||||||
|
# assert plus.compiled["a"] == sheerka.new("one")
|
||||||
|
# assert plus.compiled["b"] == CC(the, a=sheerka.new("one"))
|
||||||
|
|
||||||
|
res = sheerka.evaluate_user_input("eval one plus the one")
|
||||||
|
assert res[0].status
|
||||||
|
assert res[0].body == 2
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
||||||
def test_i_can_def_several_concepts(self):
|
def test_i_can_def_several_concepts(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user