Fixed RET functionnality misbehaviour

This commit is contained in:
2020-07-08 13:35:18 +02:00
parent c4399d631c
commit b768eaa95d
14 changed files with 113 additions and 29 deletions
+1
View File
@@ -14,3 +14,4 @@ clean:
rm -rf tests/prof
find . -name '.pytest_cache' -exec rm -rf {} +
find . -name '__pycache__' -exec rm -rf {} +
find . -name 'debug.txt' -exec rm -rf {} +
+2
View File
@@ -82,3 +82,5 @@ last_created_concept() is number
def concept history as history()
def concept plus from a plus 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)
+5
View File
@@ -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)
+8 -3
View File
@@ -3,7 +3,8 @@ import time
from core.builtin_concepts import BuiltinConcepts
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):
@@ -37,15 +38,19 @@ class SheerkaAdmin(BaseService):
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
:return:
"""
if concept_file == "full":
concept_file = CONCEPTS_FILE_ALL_CONCEPTS
try:
start = time.time_ns()
self.sheerka.during_restore = True
with open(CONCEPTS_FILE, "r") as f:
with open(concept_file, "r") as f:
for line in f.readlines():
line = line.strip()
if line == "" or line.startswith("#"):
@@ -43,6 +43,16 @@ class SheerkaEvaluateConcept(BaseService):
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):
"""
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)
sub_context.add_values(return_values=evaluated)
if evaluated.key == to_resolve.key:
return evaluated
return self.apply_ret(evaluated)
else:
error = evaluated
@@ -324,9 +334,9 @@ class SheerkaEvaluateConcept(BaseService):
concept.init_key() # only does it if needed
concept.metadata.is_evaluated = "body" in all_metadata_to_eval
# # update the cache for concepts with no variable
# if len(concept.metadata.variables) == 0:
# self.sheerka.cache_manager.put(self.sheerka.CONCEPTS_BY_ID_ENTRY, concept.id, concept)
# update the cache for concepts with no variable
if len(concept.metadata.variables) == 0:
self.sheerka.cache_manager.put(self.sheerka.CONCEPTS_BY_ID_ENTRY, concept.id, concept)
return concept
+14 -3
View File
@@ -434,11 +434,22 @@ class SheerkaFilter(BaseService):
pass
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:
try:
props = path.split(".")
for prop in props:
compiled = self.get_compiled("inspect", prop)
context = {} if is_primitive(item) else as_bag(item)
context["self"] = item
yield eval(compiled, context)
item = eval(compiled, context)
yield item
except Exception as ex:
yield ex
+10
View File
@@ -6,6 +6,16 @@ import re
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):
"""
Transform a list of strings into a single string
+5 -4
View File
@@ -83,11 +83,12 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
props_found.add(p)
# add variables by order of appearance when possible
for token in def_concept_node.name.tokens:
if token.value in props_found:
concept.def_var(token.value, None)
for name_part in name_to_use:
if name_part in props_found:
concept.def_var(name_part, None)
# add the remaining properties
# They mainly come from BNF definition
for p in props_found:
if p not in concept.values:
concept.def_var(p, None)
@@ -112,7 +113,7 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
@staticmethod
def get_name_to_use(node):
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
def get_variables(sheerka, ret_value, concept_name):
+13
View File
@@ -196,6 +196,19 @@ class ConceptNode(LexerNode):
clone = ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying)
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):
"""
-11
View File
@@ -23,14 +23,6 @@ from parsers.BaseParser import BaseParser
PARSERS = ["AtomNode", "SyaNode", "Python"]
# def debug(obj):
# with open("debug.txt", "a") as f:
# f.write(f"{obj}\n")
def debug(obj):
pass
@dataclass
class ParsingContext:
"""
@@ -185,7 +177,6 @@ class ParsingExpression:
return hash((self.rule_name, self.elements))
def parse(self, parser):
debug(self)
# TODO : add memoization
return self._parse(parser)
@@ -590,7 +581,6 @@ class StrMatch(Match):
parser_helper.next_token(self.skip_white_space)
return node
debug(f"Failed to match {self}. {token=}")
return None
@@ -811,7 +801,6 @@ class BnfConceptParserHelper:
self.token = self.parser.parser_input.tokens[self.pos]
# parse
debug(f"parsing {parsing_expression} against '{self.parser.parser_input.text}'")
node = parsing_expression.parse(self)
if isinstance(node, MultiNode):
+5 -1
View File
@@ -17,7 +17,7 @@ class Obj:
@dataclass
class ObjWithAsBag:
prop1: str
prop2: str
prop2: object
def as_bag(self):
return {
@@ -227,3 +227,7 @@ class TestSheerkaFilter(TestUsingMemoryBasedSheerka):
res = lst | Pipe(filter_service.pipe_inspect)("second_prop")
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)
if ret:
def_concept.ret = self.get_concept_part(ret)
if bnf_def:
def_concept.definition = bnf_def
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"]
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):
ret_val = self.get_concept_part("isinstance(a, str)")
context = self.get_context()
+1
View File
@@ -44,3 +44,4 @@ class TestRetEvaluator(TestUsingMemoryBasedSheerka):
res = RetEvaluator().eval(context, ret_value)
assert res.status
assert sheerka.isinstance(res.body, expected)
+23 -1
View File
@@ -1,6 +1,6 @@
import pytest
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.PythonEvaluator import PythonEvalError
from parsers.BaseNodeParser import SyaAssociativity
@@ -976,6 +976,28 @@ as:
assert res[0].status
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):
def test_i_can_def_several_concepts(self):