Fixed #109 : Mix python and concept. List comprehension
Fixed #110 : SheerkaDebugManager: add list_debug_settings Fixed #111 : SheerkaDebugManager: Implement ListDebugLogger Fixed #112 : SyaNodeParser: rewrite this parser Fixed #113 : Sheerka.: Add enable_parser_caching to disable parsers caching Fixed #114 : SyaNodeParser : Implement fast cache to resolve unrecognized tokens requests Fixed #115 : BnfNodeParser : Implement fast cache to resolve unrecognized tokens requests Fixed #116 : SequenceNodeParser : Implement fast cache to resolve unrecognized tokens requests Fixed #117 : ResolveMultiplePluralAmbiguityEvaluator: Resolve Multiple plural ambiguity
This commit is contained in:
+10
-2
@@ -1,12 +1,13 @@
|
||||
import ast
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept, ReturnValueConcept
|
||||
from core.concept import Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF, freeze_concept_attrs
|
||||
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
|
||||
from core.rule import ACTION_TYPE_EXEC, ACTION_TYPE_PRINT, Rule
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
from core.sheerka.Sheerka import Sheerka
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.SheerkaDebugManager import ListDebugLogger
|
||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager
|
||||
from parsers.BnfDefinitionParser import BnfDefinitionParser
|
||||
from parsers.BnfNodeParser import StrMatch
|
||||
@@ -290,3 +291,10 @@ class BaseTest:
|
||||
@staticmethod
|
||||
def successful_return_values(return_values):
|
||||
return [ret_val for ret_val in return_values if ret_val.status]
|
||||
|
||||
@staticmethod
|
||||
def activate_debug(context, pattern="Sya.*.*"):
|
||||
sheerka = context.sheerka
|
||||
sheerka.set_debug(context, True)
|
||||
sheerka.set_debug_var(context, pattern)
|
||||
sheerka.set_debug_logger_definition(ListDebugLogger)
|
||||
|
||||
@@ -73,6 +73,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
item_container = f"debug_{item_type}_settings"
|
||||
assert getattr(service, item_container) == [DebugItem(
|
||||
item_type,
|
||||
item,
|
||||
service_name,
|
||||
method_name,
|
||||
@@ -89,7 +90,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
service.add_or_update_debug_item(context, "vars", item="item")
|
||||
assert service.debug_vars_settings == [
|
||||
DebugItem("item", None, None, None, False, None, False, True)
|
||||
DebugItem("vars", "item", None, None, None, False, None, False, True)
|
||||
]
|
||||
|
||||
def test_i_can_update_debug_item(self):
|
||||
@@ -101,8 +102,8 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
service.add_or_update_debug_item(context, "vars", "item", "service_name", "method_name", enabled=False)
|
||||
|
||||
assert service.debug_vars_settings == [
|
||||
DebugItem("item", "service_name", "method_name", None, False, None, False, False),
|
||||
DebugItem("item2", "service_name", "method_name", None, False, None, False, True),
|
||||
DebugItem("vars", "item", "service_name", "method_name", None, False, None, False, False),
|
||||
DebugItem("vars", "item2", "service_name", "method_name", None, False, None, False, True),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("settings, expected", [
|
||||
@@ -407,7 +408,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
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)
|
||||
DebugItem("vars", "my_var", "s", "m", 1, True, 10, False, True)
|
||||
]
|
||||
assert service.debug_concepts_settings == []
|
||||
assert service.debug_rules_settings == []
|
||||
@@ -418,7 +419,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
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)
|
||||
DebugItem("rules", "my_rule", "s", "m", 1, True, 10, False, True)
|
||||
]
|
||||
assert service.debug_concepts_settings == []
|
||||
assert service.debug_vars_settings == []
|
||||
@@ -429,7 +430,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
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)
|
||||
DebugItem("concepts", "my_concept", "s", "m", 1, True, 10, False, True)
|
||||
]
|
||||
assert service.debug_rules_settings == []
|
||||
assert service.debug_vars_settings == []
|
||||
@@ -449,11 +450,11 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert another_service.activated
|
||||
assert another_service.debug_vars_settings == [
|
||||
DebugItem('var', 'service_name', None, None, False, None, False, True)]
|
||||
DebugItem("vars", 'var', 'service_name', None, None, False, None, False, True)]
|
||||
assert another_service.debug_rules_settings == [
|
||||
DebugItem('1', None, None, None, False, None, False, True)]
|
||||
DebugItem("rules", '1', None, None, None, False, None, False, True)]
|
||||
assert another_service.debug_concepts_settings == [
|
||||
DebugItem('1001', None, None, None, False, None, False, True)]
|
||||
DebugItem("concepts", '1001', None, None, None, False, None, False, True)]
|
||||
|
||||
def test_i_can_inspect_concept_all_attributes(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
@@ -766,9 +767,12 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
sheerka.pop_ontology(context)
|
||||
assert service.activated
|
||||
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)]
|
||||
assert service.debug_vars_settings == [
|
||||
DebugItem("vars", "v_name", "v_service", "v_method", 1, True, 1, False, True)]
|
||||
assert service.debug_rules_settings == [
|
||||
DebugItem("rules", "r_name", "r_service", "r_method", 2, True, 2, False, True)]
|
||||
assert service.debug_concepts_settings == [
|
||||
DebugItem("concepts", "c_name", "c_serv", "c_method", 3, True, 3, False, True)]
|
||||
|
||||
def test_i_can_register_debug_item(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
|
||||
@@ -4,7 +4,7 @@ from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserRes
|
||||
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, \
|
||||
DEFINITION_TYPE_DEF
|
||||
from core.global_symbols import NotInit, NotFound
|
||||
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
|
||||
from core.sheerka.services.SheerkaEvaluateConcept import EvaluationHints, SheerkaEvaluateConcept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
from parsers.BaseParser import BaseParser
|
||||
@@ -13,7 +13,7 @@ from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val
|
||||
from tests.evaluators.EvaluatorTestsUtils import exact, pr_ret_val, python_ret_val
|
||||
from tests.parsers.parsers_utils import CB, compare_with_test_object
|
||||
|
||||
|
||||
@@ -487,7 +487,9 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
eval_where=True,
|
||||
)
|
||||
|
||||
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept, eval_body=False)
|
||||
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True),
|
||||
concept,
|
||||
hints=EvaluationHints(eval_body=False))
|
||||
|
||||
if expected:
|
||||
assert evaluated.key == concept.key
|
||||
@@ -532,13 +534,13 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
)
|
||||
|
||||
foo_instance = sheerka.new("foo")
|
||||
evaluated = sheerka.evaluate_concept(context, foo_instance, eval_body=False)
|
||||
evaluated = sheerka.evaluate_concept(context, foo_instance, hints=EvaluationHints(eval_body=False))
|
||||
|
||||
assert ConceptParts.BODY in evaluated.get_compiled()
|
||||
assert evaluated.body == NotInit
|
||||
assert not evaluated.get_hints().is_evaluated
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, foo_instance, eval_body=True) # evaluate the body this time
|
||||
evaluated = sheerka.evaluate_concept(context, foo_instance, hints=EvaluationHints(eval_body=True)) # evaluate the body this time
|
||||
assert isinstance(evaluated.body, bool) and evaluated.body
|
||||
|
||||
def test_i_can_apply_intermediate_where_condition_using_python(self):
|
||||
@@ -811,7 +813,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
Concept("bar", pre="print('10')"), # print won't be executed
|
||||
)
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True)
|
||||
evaluated = sheerka.evaluate_concept(context, foo, hints=EvaluationHints(eval_body=True))
|
||||
captured = capsys.readouterr()
|
||||
assert evaluated.key == foo.key
|
||||
assert captured.out == "10\n"
|
||||
@@ -828,7 +830,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
Concept("foo", pre="in_context('foo')", body="print('10')"),
|
||||
)
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
|
||||
evaluated = sheerka.evaluate_concept(context, concept, hints=EvaluationHints(eval_body=True))
|
||||
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
|
||||
assert evaluated.body == "in_context('foo')"
|
||||
assert evaluated.concept == concept
|
||||
@@ -898,7 +900,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
def test_is_evaluated_is_correctly_set(self, concept, expected):
|
||||
sheerka, context, concept = self.init_concepts(concept)
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
|
||||
evaluated = sheerka.evaluate_concept(context, concept, hints=EvaluationHints(eval_body=True))
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert concept.get_hints().is_evaluated == expected
|
||||
@@ -919,24 +921,24 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
res = sheerka.evaluate_concept(context, bar)
|
||||
assert sheerka.isinstance(res, "bar")
|
||||
|
||||
res = sheerka.evaluate_concept(context, bar, eval_body=True)
|
||||
res = sheerka.evaluate_concept(context, bar, hints=EvaluationHints(eval_body=True))
|
||||
assert sheerka.isinstance(res, "foo")
|
||||
|
||||
# And the result is still the same after a second call
|
||||
assert bar.get_hints().is_evaluated
|
||||
res = sheerka.evaluate_concept(context, bar, eval_body=True)
|
||||
res = sheerka.evaluate_concept(context, bar, hints=EvaluationHints(eval_body=True))
|
||||
assert sheerka.isinstance(res, "foo")
|
||||
|
||||
def test_ret_is_evaluated_only_is_body_is_requested(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="__NOT_FOUND"))
|
||||
|
||||
res = sheerka.evaluate_concept(context, bar, eval_body=False)
|
||||
res = sheerka.evaluate_concept(context, bar, hints=EvaluationHints(eval_body=False))
|
||||
assert res.id == bar.id
|
||||
|
||||
def test_i_can_eval_concept_with_rules(self):
|
||||
sheerka, context, foo = self.init_concepts(Concept("foo a", body="a.name").def_var("a", "r:|1:"))
|
||||
|
||||
res = sheerka.evaluate_concept(context, foo, eval_body=True)
|
||||
res = sheerka.evaluate_concept(context, foo, hints=EvaluationHints(eval_body=True))
|
||||
assert res.body == "Print return values"
|
||||
|
||||
def test_i_can_manage_python_concept_infinite_recursion_when_initializing_ast(self):
|
||||
@@ -957,18 +959,18 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
evaluator = SheerkaEvaluateConcept(sheerka)
|
||||
|
||||
# 'def concept foo as foo'
|
||||
return_values = [pr_ret_val(foo, parser="ExactConcept"), python_ret_val("foo")]
|
||||
return_values = [pr_ret_val(foo, parser=exact), python_ret_val("foo")]
|
||||
|
||||
res = evaluator.get_recursive_definitions(context, foo, return_values)
|
||||
|
||||
assert list(res) == [BaseParser.get_name("ExactConcept")]
|
||||
assert list(r.name for r in res) == [BaseParser.get_name("ExactConcept")]
|
||||
|
||||
def test_i_can_detect_when_no_recursive_definition(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
evaluator = SheerkaEvaluateConcept(sheerka)
|
||||
|
||||
# 'def concept foo as bar'
|
||||
return_values = [pr_ret_val(bar, parser="ExactConcept"), python_ret_val("foo")]
|
||||
return_values = [pr_ret_val(bar, parser=exact), python_ret_val("foo")]
|
||||
|
||||
res = evaluator.get_recursive_definitions(context, foo, return_values)
|
||||
|
||||
@@ -980,7 +982,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
evaluator = SheerkaEvaluateConcept(sheerka)
|
||||
|
||||
# i dunno how to construct the return value
|
||||
return_values = [pr_ret_val(q, parser="ExactConcept")]
|
||||
return_values = [pr_ret_val(q, parser=exact)]
|
||||
|
||||
res = evaluator.get_recursive_definitions(context, q, return_values)
|
||||
|
||||
@@ -1004,7 +1006,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
|
||||
|
||||
# get the body
|
||||
evaluated = evaluator.evaluate_concept(context, concept, eval_body=True)
|
||||
evaluated = evaluator.evaluate_concept(context, concept, hints=EvaluationHints(eval_body=True))
|
||||
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
|
||||
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
|
||||
assert not evaluated.get_value("x").get_hints().use_copy
|
||||
@@ -1025,7 +1027,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
|
||||
# get the body
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
evaluated = evaluator.evaluate_concept(context, concept, eval_body=True)
|
||||
evaluated = evaluator.evaluate_concept(context, concept, hints=EvaluationHints(eval_body=True))
|
||||
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
|
||||
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
|
||||
assert not evaluated.get_value("x").get_hints().use_copy
|
||||
@@ -1043,7 +1045,9 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
|
||||
# Sanity check for normal behaviour
|
||||
to_evaluate1 = parsed_ret_val.body.body[0].concept.copy()
|
||||
evaluated1 = sheerka.evaluate_concept(context, to_evaluate1, eval_body=True, validation_only=False)
|
||||
evaluated1 = sheerka.evaluate_concept(context,
|
||||
to_evaluate1,
|
||||
hints=EvaluationHints(eval_body=True, expression_only=False))
|
||||
|
||||
assert sheerka.isinstance(evaluated1, shirt)
|
||||
assert evaluated1.get_value("body_ax_is_evaluated") == True
|
||||
@@ -1053,7 +1057,9 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
|
||||
# check validation_only behaviour
|
||||
to_evaluate2 = parsed_ret_val.body.body[0].concept.copy()
|
||||
evaluated2 = sheerka.evaluate_concept(context, to_evaluate2, eval_body=True, validation_only=True)
|
||||
evaluated2 = sheerka.evaluate_concept(context,
|
||||
to_evaluate2,
|
||||
hints=EvaluationHints(eval_body=True, expression_only=True))
|
||||
|
||||
assert sheerka.isinstance(evaluated2, shirt)
|
||||
assert evaluated2.get_value("body_ax_is_evaluated") == NotInit
|
||||
@@ -1073,7 +1079,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
|
||||
to_evaluate = parsed_ret_val.body.body[0].concept
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, to_evaluate, eval_body=False)
|
||||
evaluated = sheerka.evaluate_concept(context, to_evaluate, hints=EvaluationHints(eval_body=False))
|
||||
|
||||
assert sheerka.isinstance(evaluated, a_x)
|
||||
assert "x" in evaluated.get_compiled()
|
||||
@@ -1085,7 +1091,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
# sanity check
|
||||
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
|
||||
to_evaluate = parsed_ret_val.body.body[0].concept
|
||||
evaluated = sheerka.evaluate_concept(context, to_evaluate, eval_body=True)
|
||||
evaluated = sheerka.evaluate_concept(context, to_evaluate, hints=EvaluationHints(eval_body=True))
|
||||
|
||||
assert sheerka.isinstance(evaluated, shirt)
|
||||
assert evaluated.get_value("body_ax_is_evaluated") == True
|
||||
@@ -1095,7 +1101,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
def test_concept_is_not_evaluated_when_method_access_error(self):
|
||||
sheerka, context, foo = self.init_concepts(Concept("foo", body="set_attr(self, 'prop_name', 'prop_value')"))
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True, validation_only=True)
|
||||
evaluated = sheerka.evaluate_concept(context, foo, hints=EvaluationHints(eval_body=True, expression_only=True))
|
||||
|
||||
assert sheerka.isinstance(evaluated, foo)
|
||||
assert not foo.get_hints().is_evaluated
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
import ast
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts, ParserResultConcept
|
||||
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept, ReturnValueConcept
|
||||
from core.concept import Concept
|
||||
from evaluators.BaseEvaluator import BaseEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.BaseNodeParser import ConceptNode
|
||||
from parsers.ExactConceptParser import ExactConceptParser
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
|
||||
reduced_requested = ReturnValueConcept("Sheerka", True, Concept(name=BuiltinConcepts.REDUCE_REQUESTED,
|
||||
key=BuiltinConcepts.REDUCE_REQUESTED))
|
||||
|
||||
sequence = SequenceNodeParser()
|
||||
sya = SyaNodeParser()
|
||||
exact = ExactConceptParser()
|
||||
python = PythonParser()
|
||||
|
||||
|
||||
def ret_val(value="value", who="who", status=True):
|
||||
"""
|
||||
@@ -21,7 +29,7 @@ def ret_val(value="value", who="who", status=True):
|
||||
return ReturnValueConcept(who, status, value)
|
||||
|
||||
|
||||
def p_ret_val(value="value", parser="parser", status=True):
|
||||
def p_ret_val(value="value", parser=exact, status=True):
|
||||
"""
|
||||
ReturnValueConcept from parser
|
||||
:param value:
|
||||
@@ -29,7 +37,7 @@ def p_ret_val(value="value", parser="parser", status=True):
|
||||
:param status:
|
||||
:return:
|
||||
"""
|
||||
return ReturnValueConcept(BaseParser.get_name(parser), status, value)
|
||||
return ReturnValueConcept(parser.name, status, value)
|
||||
|
||||
|
||||
def e_ret_val(value="value", evaluator="evaluator", status=True):
|
||||
@@ -43,7 +51,7 @@ def e_ret_val(value="value", evaluator="evaluator", status=True):
|
||||
return ReturnValueConcept(BaseEvaluator.PREFIX + evaluator, status, value)
|
||||
|
||||
|
||||
def p_ret_val_false(value="value", parser="parser"):
|
||||
def p_ret_val_false(value="value", parser=exact):
|
||||
"""
|
||||
Failed ReturnValueConcept from parser
|
||||
:param value:
|
||||
@@ -53,7 +61,7 @@ def p_ret_val_false(value="value", parser="parser"):
|
||||
return p_ret_val(value, parser, status=False)
|
||||
|
||||
|
||||
def p_ret_val_true(value="value", parser="parser"):
|
||||
def p_ret_val_true(value="value", parser=exact):
|
||||
"""
|
||||
Successful ReturnValueConcept from parser
|
||||
:param value:
|
||||
@@ -63,24 +71,24 @@ def p_ret_val_true(value="value", parser="parser"):
|
||||
return p_ret_val(value, parser, status=True)
|
||||
|
||||
|
||||
def e_ret_val_false(value="value", parser="parser"):
|
||||
def e_ret_val_false(value="value", evaluator="evaluator"):
|
||||
"""
|
||||
Failed ReturnValueConcept from evaluator
|
||||
:param value:
|
||||
:param parser:
|
||||
:param evaluator:
|
||||
:return:
|
||||
"""
|
||||
return e_ret_val(value, parser, status=False)
|
||||
return e_ret_val(value, evaluator, status=False)
|
||||
|
||||
|
||||
def e_ret_val_true(value="value", parser="parser"):
|
||||
def e_ret_val_true(value="value", evaluator="evaluator"):
|
||||
"""
|
||||
Successful ReturnValueConcept from evaluator
|
||||
:param value:
|
||||
:param parser:
|
||||
:param evaluator:
|
||||
:return:
|
||||
"""
|
||||
return e_ret_val(value, parser, status=True)
|
||||
return e_ret_val(value, evaluator, status=True)
|
||||
|
||||
|
||||
def e_ret_val_new(key, evaluator="evaluator", status=True, **kwargs):
|
||||
@@ -96,7 +104,7 @@ def e_ret_val_new(key, evaluator="evaluator", status=True, **kwargs):
|
||||
return e_ret_val(body, evaluator, status)
|
||||
|
||||
|
||||
def pr_ret_val(value, parser="parser", source=None, status=True):
|
||||
def pr_ret_val(value, parser=exact, source=None, status=True):
|
||||
"""
|
||||
ParserResult ReturnValue
|
||||
eg: ReturnValue with a ParserResult
|
||||
@@ -107,7 +115,7 @@ def pr_ret_val(value, parser="parser", source=None, status=True):
|
||||
:return:
|
||||
"""
|
||||
source = source or (value.name if isinstance(value, Concept) else "source")
|
||||
parser_result = ParserResultConcept(BaseParser.get_name(parser), source=source, value=value)
|
||||
parser_result = ParserResultConcept(parser, source=source, value=value)
|
||||
return p_ret_val(value=parser_result, parser=parser, status=status)
|
||||
|
||||
|
||||
@@ -117,8 +125,14 @@ def python_ret_val(source):
|
||||
:param source:
|
||||
:return:
|
||||
"""
|
||||
python_node = PythonNode(source.strip(), ast.parse(source.strip(), f"<source>", 'eval'))
|
||||
return pr_ret_val(python_node, parser="Python", source=source)
|
||||
python_node = PythonNode(source.lstrip(), ast.parse(source.strip(), f"<source>", 'eval'))
|
||||
return pr_ret_val(python_node, parser=python, source=source)
|
||||
|
||||
|
||||
def cnode_ret_val(concept, source=None, parser=sya):
|
||||
source = source or concept.name
|
||||
cnode = ConceptNode(concept, 0, 0, source=source)
|
||||
return pr_ret_val([cnode], parser=parser, source=source)
|
||||
|
||||
|
||||
def new_concept(key, **kwargs):
|
||||
@@ -129,3 +143,11 @@ def new_concept(key, **kwargs):
|
||||
|
||||
res.get_hints().is_evaluated = True
|
||||
return res
|
||||
|
||||
|
||||
def new_plural(name):
|
||||
name_stripped_s = name.lstrip("s")
|
||||
single = Concept(name_stripped_s)
|
||||
concept = Concept(key=name, name=name, id=f"{name}:{BuiltinConcepts.PLURAL}", is_builtin=False, is_unique=False)
|
||||
concept.set_prop(BuiltinConcepts.PLURAL, single)
|
||||
return concept
|
||||
|
||||
@@ -449,6 +449,18 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert sheerka.get_property(created_concept, BuiltinConcepts.ISA) == {sheerka.new(BuiltinConcepts.AUTO_EVAL)}
|
||||
|
||||
def test_i_can_eval_when_variable_are_forced(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
definition = "def concept foo from [z for x in y] def_var x def_var y def_var z"
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(definition))
|
||||
evaluated = DefConceptEvaluator().eval(context, def_ret_val)
|
||||
|
||||
assert evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
created_concept = evaluated.body.body
|
||||
|
||||
assert created_concept.get_metadata().parameters == ["z", "x", "y"]
|
||||
|
||||
def test_i_cannot_eval_bnf_concept_with_unknown_variable(self):
|
||||
# testing MandatoryVariable
|
||||
context = self.get_context()
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import pytest
|
||||
|
||||
from core.concept import Concept
|
||||
from evaluators.ResolveMultiplePluralAmbiguityEvaluator import ResolveMultiplePluralAmbiguityEvaluator
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.evaluators.EvaluatorTestsUtils import cnode_ret_val, exact, new_plural, pr_ret_val, python_ret_val, sequence, \
|
||||
sya
|
||||
|
||||
|
||||
class TestResolveMultiplePluralAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@pytest.mark.parametrize("return_values, expected", [
|
||||
([python_ret_val("numbers"), cnode_ret_val(new_plural("numbers"), parser=sequence)], True),
|
||||
([python_ret_val("numbers"), cnode_ret_val(new_plural("numbers"), parser=sequence), pr_ret_val("other")], True),
|
||||
([python_ret_val("numbers"), cnode_ret_val(new_plural("numbers"), parser=sya)], False),
|
||||
([python_ret_val("numbers"), cnode_ret_val(Concept("numbers"), parser=sequence)], False),
|
||||
([python_ret_val("numbers"), pr_ret_val(new_plural("numbers"), parser=exact)], False),
|
||||
])
|
||||
def test_i_can_match(self, return_values, expected):
|
||||
context = self.get_context()
|
||||
assert ResolveMultiplePluralAmbiguityEvaluator().matches(context, return_values) == expected
|
||||
|
||||
def test_i_can_eval_when_nothing_in_memory(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
return_values = [
|
||||
python_ret_val("numbers"),
|
||||
cnode_ret_val(new_plural("numbers"), source="source", parser=sequence)
|
||||
]
|
||||
|
||||
evaluator = ResolveMultiplePluralAmbiguityEvaluator()
|
||||
assert evaluator.matches(context, return_values)
|
||||
|
||||
rets = evaluator.eval(context, return_values)
|
||||
assert len(rets) == 1
|
||||
ret = rets[0]
|
||||
assert ret.who == evaluator.name
|
||||
assert ret.status == return_values[1].status
|
||||
assert ret.value == return_values[1].value
|
||||
assert ret.parents == return_values
|
||||
|
||||
def test_i_can_eval_when_plural_in_memory(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
sheerka.add_to_memory(context, "numbers", "something")
|
||||
|
||||
return_values = [
|
||||
python_ret_val("numbers"),
|
||||
cnode_ret_val(new_plural("numbers"), source="source", parser=sequence)
|
||||
]
|
||||
|
||||
evaluator = ResolveMultiplePluralAmbiguityEvaluator()
|
||||
assert evaluator.matches(context, return_values)
|
||||
|
||||
rets = evaluator.eval(context, return_values)
|
||||
assert len(rets) == 1
|
||||
ret = rets[0]
|
||||
assert ret.who == evaluator.name
|
||||
assert ret.status == return_values[0].status
|
||||
assert ret.value == return_values[0].value
|
||||
assert ret.parents == return_values
|
||||
@@ -45,13 +45,35 @@ class TestSheerkaNonRegMemory2(TestUsingMemoryBasedSheerka):
|
||||
assert res[0].status
|
||||
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
||||
|
||||
# def test_i_can_define_plural(self):
|
||||
# init = [
|
||||
# "def concept man",
|
||||
# "def concept men as set_plural(man) ret man auto_eval True",
|
||||
# ]
|
||||
# sheerka = self.init_scenario(init)
|
||||
#
|
||||
# res = sheerka.evaluate_user_input("men")
|
||||
# assert res[0].status
|
||||
def test_i_can_get_sequence_when_evaluation_plural(self):
|
||||
init = [
|
||||
"def concept one",
|
||||
"def concept two",
|
||||
"def concept number",
|
||||
"global_truth(set_isa(one, number))",
|
||||
"global_truth(set_isa(two, number))",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval numbers")
|
||||
|
||||
assert res[0].status
|
||||
assert set(res[0].body) == {sheerka.new("one"), sheerka.new("two")}
|
||||
|
||||
def test_i_can_use_list_comprehension(self):
|
||||
init = [
|
||||
"def concept rex",
|
||||
"def concept rantanplan",
|
||||
"def concept dog",
|
||||
"def concept x is a y as set_isa(x, y)",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
|
||||
res = sheerka.evaluate_user_input("global_truth([ x is a dog for x in [rex, rantanplan]])")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
rex = sheerka.new("rex")
|
||||
dog = sheerka.new("dog")
|
||||
assert sheerka.isa(rex, dog)
|
||||
|
||||
@@ -180,3 +180,24 @@ two: (1002)two
|
||||
captured = capsys.readouterr()
|
||||
assert " : test()" in captured.out
|
||||
assert " : history()" in captured.out
|
||||
|
||||
def test_i_can_list_debug_settings(self, capsys):
|
||||
init = [
|
||||
"set_debug_var('Sya.parsers.*', 45)",
|
||||
"set_debug_concept('c:|1015', '13+')",
|
||||
"set_debug_rule('Out')",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
capsys.readouterr()
|
||||
|
||||
sheerka.enable_process_return_values = True
|
||||
res = sheerka.evaluate_user_input(f"list_debug_settings()")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == """DebugItem(type=vars, setting=Sya.parsers.*, context_id=45, debug_id=None, context_children=False, debug_children=False (enabled=True))
|
||||
DebugItem(type=concepts, setting=c:|1015.*.*, context_id=13, debug_id=None, context_children=True, debug_children=False (enabled=True))
|
||||
DebugItem(type=rules, setting=Out.*.*, context_id=None, debug_id=None, context_children=False, debug_children=False (enabled=True))
|
||||
"""
|
||||
|
||||
+292
-172
@@ -1,24 +1,23 @@
|
||||
import ast
|
||||
from dataclasses import dataclass
|
||||
from typing import Union, List
|
||||
from typing import List, Union
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept
|
||||
from core.builtin_helpers import CreateObjectIdentifiers
|
||||
from core.concept import Concept, ConceptParts, DoNotResolve, AllConceptParts
|
||||
from core.concept import AllConceptParts, Concept, ConceptParts, DoNotResolve
|
||||
from core.rule import Rule
|
||||
from core.tokenizer import Tokenizer, TokenKind, Token
|
||||
from core.utils import get_text_from_tokens, tokens_index, str_concept
|
||||
from parsers.BaseExpressionParser import NameExprNode, AndNode, OrNode, NotNode, VariableNode, ComparisonNode, \
|
||||
ComparisonType, \
|
||||
FunctionParameter
|
||||
from parsers.BaseNodeParser import UnrecognizedTokensNode, SourceCodeNode, RuleNode, ConceptNode, \
|
||||
SourceCodeWithConceptNode
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer
|
||||
from core.utils import get_text_from_tokens, str_concept, tokens_index
|
||||
from parsers.BaseExpressionParser import AndNode, ComparisonNode, ComparisonType, Comprehension, FunctionParameter, \
|
||||
ListComprehensionNode, ListNode, NameExprNode, \
|
||||
NotNode, OrNode, VariableNode, comma
|
||||
from parsers.BaseNodeParser import ConceptNode, RuleNode, SourceCodeNode, SourceCodeWithConceptNode, \
|
||||
UnrecognizedTokensNode
|
||||
from parsers.FunctionParser import FunctionNode
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.SyaNodeParser import SyaConceptParserHelper
|
||||
from sheerkapython.python_wrapper import sheerka_globals
|
||||
from sheerkarete.common import V
|
||||
from sheerkarete.conditions import Condition, AndConditions, NegatedCondition, NegatedConjunctiveConditions
|
||||
from sheerkarete.conditions import AndConditions, Condition, NegatedCondition, NegatedConjunctiveConditions
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -29,104 +28,254 @@ class Obj:
|
||||
parent: object = None
|
||||
|
||||
|
||||
class AND:
|
||||
class ExprTestObj:
|
||||
@staticmethod
|
||||
def get_pos(nodes):
|
||||
start, end = None, None
|
||||
for n in nodes:
|
||||
if start is None or start > n.start:
|
||||
start = n.start
|
||||
if end is None or end < n.end:
|
||||
end = n.end
|
||||
return start, end
|
||||
|
||||
@staticmethod
|
||||
def get_pos_from_source(source, full_text_as_tokens):
|
||||
if isinstance(source, tuple):
|
||||
source, to_skip = source[0], source[1]
|
||||
else:
|
||||
to_skip = 0
|
||||
|
||||
source_as_node = list(Tokenizer(source, yield_eof=False))
|
||||
start = tokens_index(full_text_as_tokens, source_as_node, skip=to_skip)
|
||||
end = start + len(source_as_node) - 1
|
||||
return start, end
|
||||
|
||||
@staticmethod
|
||||
def as_tokens(source):
|
||||
if isinstance(source, tuple):
|
||||
source, to_skip = source
|
||||
else:
|
||||
source, to_skip = source, 0
|
||||
|
||||
return list(Tokenizer(source, yield_eof=False)), to_skip
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def safe_get_expr_node(obj, full_text_as_tokens):
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
obj = EXPR(obj) if isinstance(obj, (str, tuple)) else obj
|
||||
return obj.get_expr_node(full_text_as_tokens)
|
||||
|
||||
|
||||
class AND(ExprTestObj):
|
||||
""" Test class for AndNode"""
|
||||
|
||||
def __init__(self, *parts, source=None):
|
||||
self.parts = parts
|
||||
self.source = source
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
parts = [part.get_expr_node(full_text_as_tokens) for part in self.parts]
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens) if self.source else self.get_pos(parts)
|
||||
return AndNode(start, end, full_text_as_tokens[start: end + 1], *parts)
|
||||
|
||||
class OR:
|
||||
|
||||
class OR(ExprTestObj):
|
||||
""" Test class for OrNode"""
|
||||
|
||||
def __init__(self, *parts, source=None):
|
||||
self.parts = parts
|
||||
self.source = source
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
parts = [part.get_expr_node(full_text_as_tokens) for part in self.parts]
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens) if self.source else self.get_pos(parts)
|
||||
return OrNode(start, end, full_text_as_tokens[start: end + 1], *parts)
|
||||
|
||||
|
||||
@dataclass
|
||||
class NOT:
|
||||
class NOT(ExprTestObj):
|
||||
""" Test class for NotNode"""
|
||||
expr: object
|
||||
expr: ExprTestObj
|
||||
source: str = None
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
part = self.expr.get_expr_node(full_text_as_tokens)
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens) if self.source else (
|
||||
part.start - 2, part.end)
|
||||
return NotNode(start, end, full_text_as_tokens[start: end + 1], part)
|
||||
|
||||
|
||||
@dataclass
|
||||
class EXPR:
|
||||
"""Test class for NameNode. E stands for Expression"""
|
||||
class EXPR(ExprTestObj):
|
||||
"""Test class for NameNode"""
|
||||
source: str
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
value_as_tokens, to_skip = self.as_tokens(self.source)
|
||||
start = tokens_index(full_text_as_tokens, value_as_tokens, to_skip)
|
||||
end = start + len(value_as_tokens) - 1
|
||||
return NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
|
||||
|
||||
@dataclass
|
||||
class VAR:
|
||||
class VAR(ExprTestObj):
|
||||
"""Test class for VarNode"""
|
||||
|
||||
full_name: str
|
||||
source: str = None
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
value_as_tokens = list(Tokenizer(self.source or self.full_name, yield_eof=False))
|
||||
start = tokens_index(full_text_as_tokens, value_as_tokens, 0)
|
||||
end = start + len(value_as_tokens) - 1
|
||||
parts = self.full_name.split(".")
|
||||
if len(parts) == 1:
|
||||
return VariableNode(start, end, full_text_as_tokens[start: end + 1], parts[0])
|
||||
else:
|
||||
return VariableNode(start, end, full_text_as_tokens[start: end + 1], parts[0], *parts[1:])
|
||||
|
||||
|
||||
@dataclass
|
||||
class EQ:
|
||||
left: object
|
||||
right: object
|
||||
class CompExprTestObj(ExprTestObj):
|
||||
"""
|
||||
Test object for comparison ==, <=, ...
|
||||
"""
|
||||
left: ExprTestObj
|
||||
right: ExprTestObj
|
||||
source: str = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class NEQ:
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
node_type = comparison_type_mapping[type(self).__name__]
|
||||
left_node = self.left.get_expr_node(full_text_as_tokens)
|
||||
right_node = self.right.get_expr_node(full_text_as_tokens)
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens) if self.source else \
|
||||
self.get_pos([left_node, right_node])
|
||||
return ComparisonNode(start, end, full_text_as_tokens[start: end + 1], node_type, left_node, right_node)
|
||||
|
||||
|
||||
@dataclass
|
||||
class GT:
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
class EQ(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class GTE:
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
class NEQ(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class LT:
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
class GT(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class LTE:
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
class GTE(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class IN:
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
class LT(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class NIN: # for NOT INT
|
||||
left: object
|
||||
right: object
|
||||
source: str = None
|
||||
class LTE(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class PAREN: # for parenthesis node
|
||||
class IN(CompExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class NIN(CompExprTestObj): # for NOT INT
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class PAREN(ExprTestObj): # for parenthesis node
|
||||
node: object
|
||||
source: str = None
|
||||
|
||||
|
||||
class L_EXPR(ExprTestObj):
|
||||
def __init__(self, first, last, *items, sep=None, source=None):
|
||||
self.first = first
|
||||
self.last = last
|
||||
self.items = items
|
||||
self.sep = sep or comma
|
||||
self.source = source
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
first = self.safe_get_expr_node(self.first, full_text_as_tokens)
|
||||
last = self.safe_get_expr_node(self.last, full_text_as_tokens)
|
||||
|
||||
items = [self.safe_get_expr_node(item, full_text_as_tokens) for item in self.items]
|
||||
|
||||
if self.source is None:
|
||||
source = self.first if self.first else ""
|
||||
source += f"{self.sep.value} ".join(item.get_source() for item in items)
|
||||
if self.last:
|
||||
source += self.last
|
||||
else:
|
||||
source = self.source
|
||||
|
||||
start, end = self.get_pos_from_source(source, full_text_as_tokens)
|
||||
return ListNode(start, end, full_text_as_tokens[start: end + 1], first, last, items, self.sep)
|
||||
|
||||
|
||||
@dataclass
|
||||
class LCC:
|
||||
"""
|
||||
List comprehension comprehension
|
||||
"""
|
||||
target: object
|
||||
iterable: object
|
||||
if_expr: object
|
||||
|
||||
|
||||
@dataclass
|
||||
class LC(ExprTestObj): # for List Comprehension node
|
||||
element: object
|
||||
generators: list
|
||||
source: str = None
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
# first transform str into NameExprTestObj (ie EXPR)
|
||||
if isinstance(self.element, str):
|
||||
self.element = EXPR(self.element)
|
||||
|
||||
comprehensions = []
|
||||
nodes = []
|
||||
for comp in self.generators:
|
||||
target = EXPR(comp[0]) if isinstance(comp[0], (str, tuple)) else comp[0]
|
||||
iterable = EXPR(comp[1]) if isinstance(comp[1], (str, tuple)) else comp[1]
|
||||
if_expr = EXPR(comp[2]) if isinstance(comp[2], (str, tuple)) else comp[2]
|
||||
comprehensions.append(LCC(target, iterable, if_expr))
|
||||
self.generators = comprehensions
|
||||
|
||||
# then transform into ListComprehensionNode
|
||||
element = self.element.get_expr_node(full_text_as_tokens)
|
||||
nodes.append(element)
|
||||
comprehensions = []
|
||||
for comp in self.generators:
|
||||
target = comp.target.get_expr_node(full_text_as_tokens)
|
||||
iterable = comp.iterable.get_expr_node(full_text_as_tokens)
|
||||
if_expr = comp.if_expr.get_expr_node(full_text_as_tokens) if comp.if_expr else None
|
||||
comprehensions.append(Comprehension(target, iterable, if_expr))
|
||||
nodes.extend([target, iterable, if_expr])
|
||||
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens) if self.source else self.get_pos(nodes)
|
||||
return ListComprehensionNode(start, end, full_text_as_tokens[start: end + 1], element, comprehensions)
|
||||
|
||||
|
||||
class CC:
|
||||
"""
|
||||
Concept class for test purpose
|
||||
@@ -320,10 +469,13 @@ class CMV:
|
||||
Test class that only compare the key and the metadata variables
|
||||
"""
|
||||
|
||||
def __init__(self, concept, **kwargs):
|
||||
def __init__(self, concept, source=None, **kwargs):
|
||||
self.concept_key = concept.key if isinstance(concept, Concept) else concept
|
||||
self.concept = concept if isinstance(concept, Concept) else None
|
||||
self.variables = kwargs
|
||||
self.source = source # to use when the key is different from the sub str to search when filling start and stop
|
||||
self.start = None # for debug purpose, indicate where the concept starts
|
||||
self.end = None # for debug purpose, indicate where the concept ends
|
||||
|
||||
def __eq__(self, other):
|
||||
if id(self) == id(other):
|
||||
@@ -352,6 +504,21 @@ class CMV:
|
||||
txt += f", {k}='{v}'"
|
||||
return txt + ")"
|
||||
|
||||
def fix_pos(self, node):
|
||||
start = node.start if hasattr(node, "start") else \
|
||||
node[0] if isinstance(node, tuple) else None
|
||||
end = node.end if hasattr(node, "end") else \
|
||||
node[1] if isinstance(node, tuple) else None
|
||||
|
||||
if start is not None:
|
||||
if self.start is None or start < self.start:
|
||||
self.start = start
|
||||
|
||||
if end is not None:
|
||||
if self.end is None or end > self.end:
|
||||
self.end = end
|
||||
return self
|
||||
|
||||
def transform_real_obj(self, other, get_test_obj_delegate):
|
||||
if isinstance(other, CMV):
|
||||
return other
|
||||
@@ -730,7 +897,7 @@ class CNC(CN):
|
||||
|
||||
self_compile_to_use = self.compiled or compiled
|
||||
|
||||
compiled = get_test_obj_delegate(self_compile_to_use, compiled, get_test_obj_delegate)
|
||||
compiled = get_test_obj_delegate(compiled, self_compile_to_use, get_test_obj_delegate)
|
||||
return CNC(other.concept,
|
||||
other.source if self.source is not None else None,
|
||||
other.start if self.start is not None else None,
|
||||
@@ -865,7 +1032,7 @@ class RN(HelperWithPos):
|
||||
raise Exception(f"Expecting RuleNode but received {other=}")
|
||||
|
||||
|
||||
class FN:
|
||||
class FN(ExprTestObj):
|
||||
"""
|
||||
Test class only
|
||||
It matches with FunctionNode but with less constraints
|
||||
@@ -931,6 +1098,32 @@ class FN:
|
||||
|
||||
raise Exception(f"Expecting FunctionNode but received {other=}")
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
start, end = self.get_pos_from_source(self.first, full_text_as_tokens)
|
||||
first = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
start, end = self.get_pos_from_source(self.last, full_text_as_tokens)
|
||||
last = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
parameters = []
|
||||
for param_value, sep in self.parameters:
|
||||
if isinstance(param_value, str):
|
||||
start, end = self.get_pos_from_source(param_value, full_text_as_tokens)
|
||||
param_as_expr_node = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
else:
|
||||
param_as_expr_node = param_value.get_expr_node(full_text_as_tokens)
|
||||
|
||||
if sep:
|
||||
sep_tokens = Tokenizer(sep, yield_eof=False)
|
||||
start = param_as_expr_node.end + 1
|
||||
end = start + len(list(sep_tokens)) - 1
|
||||
sep_as_expr_node = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
else:
|
||||
sep_as_expr_node = None
|
||||
|
||||
parameters.append(FunctionParameter(param_as_expr_node, sep_as_expr_node))
|
||||
|
||||
start, end = first.start, last.end
|
||||
return FunctionNode(start, end, full_text_as_tokens[start: end + 1], first, last, parameters)
|
||||
|
||||
|
||||
@dataclass()
|
||||
class NEGCOND:
|
||||
@@ -966,94 +1159,7 @@ def get_expr_node_from_test_node(full_text, test_node):
|
||||
Returns EXPR, OR, NOT, AND object to ease the comparison with the real ExprNode
|
||||
"""
|
||||
full_text_as_tokens = list(Tokenizer(full_text, yield_eof=False))
|
||||
|
||||
def get_pos(nodes):
|
||||
start, end = None, None
|
||||
for n in nodes:
|
||||
if start is None or start > n.start:
|
||||
start = n.start
|
||||
if end is None or end < n.end:
|
||||
end = n.end
|
||||
return start, end
|
||||
|
||||
def get_pos_from_source(source):
|
||||
if isinstance(source, tuple):
|
||||
source, to_skip = source[0], source[1]
|
||||
else:
|
||||
to_skip = 0
|
||||
|
||||
source_as_node = list(Tokenizer(source, yield_eof=False))
|
||||
start = tokens_index(full_text_as_tokens, source_as_node, skip=to_skip)
|
||||
end = start + len(source_as_node) - 1
|
||||
return start, end
|
||||
|
||||
def get_expr_node(node):
|
||||
|
||||
if isinstance(node, EXPR):
|
||||
value_as_tokens = list(Tokenizer(node.source, yield_eof=False))
|
||||
start = tokens_index(full_text_as_tokens, value_as_tokens, 0)
|
||||
end = start + len(value_as_tokens) - 1
|
||||
return NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
|
||||
if isinstance(node, AND):
|
||||
parts = [get_expr_node(part) for part in node.parts]
|
||||
start, end = get_pos_from_source(node.source) if node.source else get_pos(parts)
|
||||
return AndNode(start, end, full_text_as_tokens[start: end + 1], *parts)
|
||||
|
||||
if isinstance(node, OR):
|
||||
parts = [get_expr_node(part) for part in node.parts]
|
||||
start, end = get_pos_from_source(node.source) if node.source else get_pos(parts)
|
||||
return OrNode(start, end, full_text_as_tokens[start: end + 1], *parts)
|
||||
|
||||
if isinstance(node, NOT):
|
||||
part = get_expr_node(node.expr)
|
||||
start, end = get_pos_from_source(node.source) if node.source else (part.start - 2, part.end)
|
||||
return NotNode(start, end, full_text_as_tokens[start: end + 1], part)
|
||||
|
||||
if isinstance(node, VAR):
|
||||
value_as_tokens = list(Tokenizer(node.source or node.full_name, yield_eof=False))
|
||||
start = tokens_index(full_text_as_tokens, value_as_tokens, 0)
|
||||
end = start + len(value_as_tokens) - 1
|
||||
parts = node.full_name.split(".")
|
||||
if len(parts) == 1:
|
||||
return VariableNode(start, end, full_text_as_tokens[start: end + 1], parts[0])
|
||||
else:
|
||||
return VariableNode(start, end, full_text_as_tokens[start: end + 1], parts[0], *parts[1:])
|
||||
|
||||
if isinstance(node, (EQ, NEQ, GT, GTE, LT, LTE, IN, NIN)):
|
||||
node_type = comparison_type_mapping[type(node).__name__]
|
||||
left_node, right_node = get_expr_node(node.left), get_expr_node(node.right)
|
||||
start, end = get_pos_from_source(node.source) if node.source else get_pos([left_node, right_node])
|
||||
return ComparisonNode(start, end, full_text_as_tokens[start: end + 1],
|
||||
node_type, left_node, right_node)
|
||||
|
||||
if isinstance(node, FN):
|
||||
start, end = get_pos_from_source(node.first)
|
||||
first = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
start, end = get_pos_from_source(node.last)
|
||||
last = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
parameters = []
|
||||
for param_value, sep in node.parameters:
|
||||
if isinstance(param_value, str):
|
||||
start, end = get_pos_from_source(param_value)
|
||||
param_as_expr_node = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
else:
|
||||
param_as_expr_node = get_expr_node(param_value)
|
||||
|
||||
if sep:
|
||||
sep_tokens = Tokenizer(sep, yield_eof=False)
|
||||
start = param_as_expr_node.end + 1
|
||||
end = start + len(list(sep_tokens)) - 1
|
||||
sep_as_expr_node = NameExprNode(start, end, full_text_as_tokens[start: end + 1])
|
||||
else:
|
||||
sep_as_expr_node = None
|
||||
|
||||
parameters.append(FunctionParameter(param_as_expr_node, sep_as_expr_node))
|
||||
|
||||
start, end = first.start, last.end
|
||||
return FunctionNode(start, end, full_text_as_tokens[start: end + 1], first, last, parameters)
|
||||
|
||||
return get_expr_node(test_node)
|
||||
return test_node.get_expr_node(full_text_as_tokens)
|
||||
|
||||
|
||||
def _index(tokens, expr, index):
|
||||
@@ -1096,15 +1202,15 @@ def compute_debug_array(res):
|
||||
|
||||
|
||||
def get_node(
|
||||
concepts_map,
|
||||
expression_as_tokens,
|
||||
sub_expr,
|
||||
concept_key=None,
|
||||
skip=0,
|
||||
is_bnf=False,
|
||||
sya=False,
|
||||
init_empty_body=False,
|
||||
exclude_body=False):
|
||||
concepts_map,
|
||||
expression_as_tokens,
|
||||
sub_expr,
|
||||
concept_key=None,
|
||||
skip=0,
|
||||
is_bnf=False,
|
||||
sya=False,
|
||||
init_empty_body=False,
|
||||
exclude_body=False):
|
||||
"""
|
||||
Tries to find sub in expression
|
||||
When found, transform it to its correct type
|
||||
@@ -1157,18 +1263,20 @@ def get_node(
|
||||
sub_expr.end = start + length - 1
|
||||
return sub_expr
|
||||
|
||||
if isinstance(sub_expr, (CNC, CC, CN)):
|
||||
concept_node = get_node(
|
||||
concepts_map,
|
||||
expression_as_tokens,
|
||||
sub_expr.source or sub_expr.concept_key,
|
||||
sub_expr.concept_key, sya=sya)
|
||||
if not hasattr(concept_node, "concept"):
|
||||
raise Exception(f"'{sub_expr.concept_key}' is not a concept. Check your map.")
|
||||
concept_found = concept_node.concept
|
||||
sub_expr.concept_key = concept_found.key
|
||||
sub_expr.concept = concept_found
|
||||
sub_expr.fix_pos((concept_node.start, concept_node.end if hasattr(concept_node, "end") else concept_node.start))
|
||||
if isinstance(sub_expr, (CNC, CC, CN, CMV)):
|
||||
if sub_expr.concept is None or sub_expr.start is None or sub_expr.end is None:
|
||||
concept_node = get_node(
|
||||
concepts_map,
|
||||
expression_as_tokens,
|
||||
sub_expr.source or sub_expr.concept_key,
|
||||
sub_expr.concept_key, sya=sya)
|
||||
if not hasattr(concept_node, "concept"):
|
||||
raise Exception(f"'{sub_expr.concept_key}' is not a concept. Check your map.")
|
||||
concept_found = concept_node.concept
|
||||
sub_expr.concept_key = concept_found.key
|
||||
sub_expr.concept = concept_found
|
||||
sub_expr.fix_pos(
|
||||
(concept_node.start, concept_node.end if hasattr(concept_node, "end") else concept_node.start))
|
||||
if hasattr(sub_expr, "compiled"):
|
||||
for k, v in sub_expr.compiled.items():
|
||||
node = get_node(concepts_map, expression_as_tokens, v, sya=sya,
|
||||
@@ -1210,9 +1318,9 @@ def get_node(
|
||||
concept_found = concepts_map.get(concept_key, None)
|
||||
if concept_found:
|
||||
concept_found = Concept().update_from(concept_found) # make a copy when massively used in tests
|
||||
if sya and len(concept_found.get_metadata().variables) > 0 and not is_bnf:
|
||||
return SyaConceptParserHelper(concept_found, start, start + length - 1)
|
||||
elif init_empty_body:
|
||||
# if sya and len(concept_found.get_metadata().variables) > 0 and not is_bnf:
|
||||
# return SyaConceptParserHelper(concept_found, start, start + length - 1)
|
||||
if init_empty_body:
|
||||
node = CNC(concept_found, sub_expr, start, start + length - 1, exclude_body=exclude_body)
|
||||
init_body(node, concept_found, sub_expr)
|
||||
return node
|
||||
@@ -1354,8 +1462,8 @@ def get_test_obj(real_obj, test_obj, get_test_obj_delegate=None):
|
||||
"""
|
||||
From a production object (Concept, ConceptNode, ....)
|
||||
Create a test object (CNC, CC ...) that can be used to validate the unit tests
|
||||
:param test_obj:
|
||||
:param real_obj:
|
||||
:param test_obj: test object used as a template
|
||||
:param get_test_obj_delegate:
|
||||
:return:
|
||||
"""
|
||||
@@ -1367,13 +1475,25 @@ def get_test_obj(real_obj, test_obj, get_test_obj_delegate=None):
|
||||
if isinstance(test_obj, dict):
|
||||
if len(test_obj) != len(real_obj):
|
||||
raise Exception(f"Not the same size ! {real_obj=}, {test_obj=}")
|
||||
|
||||
return {k: get_test_obj(real_obj[k], v) for k, v in test_obj.items()}
|
||||
|
||||
if not hasattr(test_obj, "transform_real_obj"):
|
||||
return real_obj
|
||||
if hasattr(test_obj, "transform_real_obj"):
|
||||
return test_obj.transform_real_obj(real_obj, get_test_obj)
|
||||
|
||||
return test_obj.transform_real_obj(real_obj, get_test_obj)
|
||||
return real_obj
|
||||
|
||||
|
||||
def prepare_nodes_comparison(concepts_map, expression, real_obj, test_obj):
|
||||
if isinstance(real_obj, list):
|
||||
assert len(real_obj) == len(
|
||||
test_obj), f"The two lists do not have the same size {len(real_obj)} != {len(test_obj)}"
|
||||
resolved_test_obj = compute_expected_array(concepts_map, expression, test_obj)
|
||||
real_obj_as_test = [get_test_obj(r, t) for r, t in zip(real_obj, resolved_test_obj)]
|
||||
return real_obj_as_test, resolved_test_obj
|
||||
else:
|
||||
resolved_test_obj = compute_expected_array(concepts_map, expression, [test_obj])[0]
|
||||
real_obj_as_test = get_test_obj(real_obj, resolved_test_obj)
|
||||
return real_obj_as_test, resolved_test_obj
|
||||
|
||||
|
||||
def compare_with_test_object(actual, expected):
|
||||
|
||||
@@ -124,7 +124,7 @@ func(a)
|
||||
assert parser.get_parts(["print", "when"]) is not None
|
||||
assert len(parser.error_sink) == 1
|
||||
assert isinstance(parser.error_sink[0], UnexpectedEofParsingError)
|
||||
assert parser.error_sink[0].message == "While parsing keyword 'print'."
|
||||
assert parser.error_sink[0].message == "while parsing keyword 'print'"
|
||||
|
||||
def test_i_can_double_quoted_strings_are_expanded(self):
|
||||
"""
|
||||
|
||||
@@ -4,19 +4,20 @@ import pytest
|
||||
|
||||
import tests.parsers.parsers_utils
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept, ConceptParts, DoNotResolve, DEFINITION_TYPE_BNF
|
||||
from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF, DoNotResolve
|
||||
from core.global_symbols import NotInit
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaIsAManager import SheerkaIsAManager
|
||||
from parsers.BaseNodeParser import NoMatchingTokenError
|
||||
from parsers.BnfDefinitionParser import BnfDefinitionParser
|
||||
from parsers.BnfNodeParser import StrMatch, TerminalNode, NonTerminalNode, Sequence, OrderedChoice, \
|
||||
Optional, ZeroOrMore, OneOrMore, ConceptExpression, UnOrderedChoice, BnfNodeParser, RegExMatch, \
|
||||
BnfNodeFirstTokenVisitor, Match, RegExDef, VariableExpression
|
||||
from parsers.BnfNodeParser import BnfNodeFirstTokenVisitor, BnfNodeParser, ConceptExpression, Match, NonTerminalNode, \
|
||||
OneOrMore, Optional, OrderedChoice, RegExDef, RegExMatch, Sequence, StrMatch, TerminalNode, UnOrderedChoice, \
|
||||
VariableExpression, ZeroOrMore
|
||||
from tests.BaseTest import BaseTest
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.evaluators.EvaluatorTestsUtils import python_ret_val
|
||||
from tests.parsers.parsers_utils import CNC, CN, UTN, CC, SCN, get_test_obj, compare_with_test_object
|
||||
from tests.parsers.parsers_utils import CC, CMV, CN, CNC, SCN, UTN, compare_with_test_object, get_test_obj
|
||||
|
||||
cmap = {
|
||||
"one": Concept("one"),
|
||||
@@ -1027,7 +1028,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
("one tiny but beautiful shoe",
|
||||
[CNC("foo",
|
||||
"one tiny but beautiful shoe",
|
||||
x=CC("but", source="tiny but beautiful", x="tiny", y="beautiful "))]),
|
||||
x=CMV("but", source="tiny but beautiful", x="tiny ", y="beautiful "))]),
|
||||
])
|
||||
def test_i_can_match_variable_in_between(self, expr, expected):
|
||||
my_map = {
|
||||
@@ -1896,7 +1897,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_i_can_simplify_unordered_choices_that_refer_to_the_same_isa(self):
|
||||
my_map = {
|
||||
"light_red": Concept("light red"),
|
||||
"light_red": Concept("light red", key="light_red"),
|
||||
"dark_red": Concept("dark red"),
|
||||
"red colors": Concept("red colors"),
|
||||
"color": Concept("color"),
|
||||
@@ -1916,6 +1917,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["color"])
|
||||
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["adjective"])
|
||||
|
||||
# hack to ease the tests
|
||||
sheerka.get_by_id(my_map["light_red"].id).get_metadata().key = "light_red"
|
||||
sheerka.om.clear(SheerkaIsAManager.CONCEPTS_IN_GROUPS_ENTRY)
|
||||
|
||||
text = "light red table"
|
||||
|
||||
expected = CNC("qualified table",
|
||||
@@ -1940,7 +1945,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
"isafoo": Concept("x is an foo", body="False", pre="is_question()").def_var("x"),
|
||||
"q": Concept("q ?", body="question(a)").def_var("q")
|
||||
}
|
||||
|
||||
|
||||
# I need the concept isafoo to fool SyaNodeParser when parsing the sub text 'is an hex ?'"
|
||||
# The parser will try to recognize 'is an foo', will fail and will revert the result to UTN()
|
||||
# It's this UTN that need to be properly handled
|
||||
@@ -1953,7 +1958,6 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
assert not res.status
|
||||
|
||||
|
||||
# @pytest.mark.parametrize("parser_input, expected", [
|
||||
# ("one", [
|
||||
# (True, [CNC("bnf_one", source="one", one="one", body="one")]),
|
||||
|
||||
@@ -387,8 +387,8 @@ def concept add one to a as:
|
||||
("def concept name from def", SyntaxErrorNode([], "Empty 'from' declaration.")),
|
||||
("def concept name from def ", SyntaxErrorNode([], "Empty 'from' declaration.")),
|
||||
("def concept name from as True", SyntaxErrorNode([], "Empty 'from' declaration.")),
|
||||
("def concept name from", UnexpectedEofParsingError("While parsing keyword 'from'.")),
|
||||
("def concept name from ", UnexpectedEofParsingError("While parsing keyword 'from'.")),
|
||||
("def concept name from", UnexpectedEofParsingError("while parsing keyword 'from'")),
|
||||
("def concept name from ", UnexpectedEofParsingError("while parsing keyword 'from'")),
|
||||
])
|
||||
def test_i_can_detect_empty_def_declaration(self, text, error):
|
||||
sheerka, context, parser, *concepts = self.init_parser()
|
||||
|
||||
@@ -190,8 +190,8 @@ class TestDefRuleParser(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isinstance(res.body, expected_error)
|
||||
|
||||
@pytest.mark.parametrize("text, error_message", [
|
||||
("def rule rule_name as", "While parsing 'when'."),
|
||||
("def rule rule_name as ", "While parsing 'when'."),
|
||||
("def rule rule_name as", "while parsing 'when'"),
|
||||
("def rule rule_name as ", "while parsing 'when'"),
|
||||
])
|
||||
def test_i_cannot_parse_when_unexpected_eof(self, text, error_message):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind
|
||||
from parsers.BaseExpressionParser import ParenthesisMismatchError
|
||||
from parsers.BaseParser import UnexpectedEofParsingError, UnexpectedTokenParsingError
|
||||
from parsers.ListComprehensionParser import ElementNotFound, FailedToParse, ForNotFound, LeadingParenthesisNotFound, \
|
||||
ListComprehensionParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import LC, L_EXPR, get_expr_node_from_test_node
|
||||
|
||||
|
||||
class TestListComprehensionParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def init_parser(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
parser = ListComprehensionParser(auto_compile=False)
|
||||
return sheerka, context, parser
|
||||
|
||||
@pytest.mark.parametrize("text, reason", [
|
||||
("foo", LeadingParenthesisNotFound()),
|
||||
("[]", ForNotFound()),
|
||||
("[ x ]", ForNotFound()),
|
||||
("[ x for]", FailedToParse("target", 5)),
|
||||
("[ x for x]", UnexpectedEofParsingError("while parsing comprehension")),
|
||||
("[ x for x in ]", UnexpectedEofParsingError("while parsing comprehension")),
|
||||
("[ x for x in lst for]", FailedToParse("target", 13)),
|
||||
("[", UnexpectedEofParsingError("when start parsing")),
|
||||
("[]", ForNotFound()),
|
||||
("[ for x in z ]", ElementNotFound()),
|
||||
("[ x for in z ]", FailedToParse("target", 6)),
|
||||
("[ x for x in ]", UnexpectedEofParsingError("while parsing comprehension")),
|
||||
("[ x for x in z if ]", UnexpectedEofParsingError("while parsing comprehension")),
|
||||
("[ x for x in z", ParenthesisMismatchError(Token(TokenKind.RBRACKET, "]", -1, -1, -1))),
|
||||
("[ x for x in z if t", ParenthesisMismatchError(Token(TokenKind.RBRACKET, "]", -1, -1, -1))),
|
||||
("zzz [ x for x in z if t ]", LeadingParenthesisNotFound()),
|
||||
("[ x for x in z )", ParenthesisMismatchError(Token(TokenKind.RBRACKET, "]", -1, -1, -1))),
|
||||
("[ x for x in z if t )", ParenthesisMismatchError(Token(TokenKind.RBRACKET, "]", -1, -1, -1))),
|
||||
])
|
||||
def test_i_cannot_parse_when_not_for_me(self, text, reason):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
assert res.body.reason == [reason]
|
||||
|
||||
def test_i_cannot_parse_when_trailing_elements(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "[ x for x in z if t ] zzz"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||
assert len(res.body.body) == 1
|
||||
error = res.body.body[0]
|
||||
assert isinstance(error, UnexpectedTokenParsingError)
|
||||
|
||||
def test_i_can_parse_a_simple_expression(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[x for x in ['a', 'b'] if x == 'a']"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
expected = LC(L_EXPR(None, None, "x", source="x "), [(("x", 1), "['a', 'b']", "x == 'a'")], source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
def test_i_can_parse_when_no_if(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[x for x in ['a', 'b']]"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
expected = LC(L_EXPR(None, None, "x", source="x "), [(("x", 1), "['a', 'b']", None)], source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
def test_i_can_parse_when_element_is_a_tuple(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[(x + 1, x + 2) for x in [1, 2]]"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
elt = L_EXPR("(", ")", "x + 1", "x + 2")
|
||||
expected = LC(elt, [(("x", 2), "[1, 2]", None)], source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
def test_i_can_parse_when_element_is_a_tuple_with_missing_parenthesis(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[x + 1, x + 2 for x in [1, 2]]"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
elt = L_EXPR(None, None, "x + 1", "x + 2", source="x + 1, x + 2 ")
|
||||
expected = LC(elt, [(("x", 2), "[1, 2]", None)], source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
def test_i_can_parse_when_element_is_a_context_that_contains_for(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[handle x for me and for you for x in [1, 2]]"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
elt = L_EXPR(None, None, "handle x for me and for you", source="handle x for me and for you ")
|
||||
expected = LC(elt, [(("x", 1), "[1, 2]", None)], source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
def test_i_can_parse_when_multiple_generators(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[(x, y) for x in ['a', 'b'] if x == 'a' for y in ['c', 'd'] if y == 'c']"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
elt = L_EXPR("(", ")", "x", "y")
|
||||
expected = LC(elt,
|
||||
[(("x", 1), "['a', 'b']", "x == 'a'"),
|
||||
(("y", 1), "['c', 'd']", "y == 'c'")],
|
||||
source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
def test_i_can_parse_when_multiple_generators_when_no_if(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expression = "[x, y for x in ['a', 'b'] for y in ['c', 'd'] if y == 'c']"
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
lc_node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
elt = L_EXPR(None, None, "x", "y", source="x, y ")
|
||||
expected = LC(elt,
|
||||
[(("x", 1), "['a', 'b']", None),
|
||||
(("y", 1), "['c', 'd']", "y == 'c'")],
|
||||
source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
assert lc_node == to_compare_to
|
||||
@@ -0,0 +1,69 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind
|
||||
from parsers.BaseExpressionParser import ParenthesisMismatchError, end_parenthesis_mapping
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ListParser import ListParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import EXPR, L_EXPR, get_expr_node_from_test_node
|
||||
|
||||
semi_colon = Token(TokenKind.SEMICOLON, ";", -1, -1, -1)
|
||||
or_token = Token(TokenKind.IDENTIFIER, "or", -1, -1, -1)
|
||||
|
||||
|
||||
class TestListParser(TestUsingMemoryBasedSheerka):
|
||||
def init_parser(self, sep=None):
|
||||
sheerka, context = self.init_concepts()
|
||||
parser = ListParser(sep)
|
||||
return sheerka, context, parser
|
||||
|
||||
@pytest.mark.parametrize("expression, sep, expected", [
|
||||
("()", None, L_EXPR("(", ")")),
|
||||
("(x , foo y,z)", None, L_EXPR("(", ")", EXPR("x"), EXPR("foo y"), EXPR("z"), source="(x , foo y,z)")),
|
||||
("x , foo y,z", None, L_EXPR(None, None, EXPR("x"), EXPR("foo y"), EXPR("z"), source="x , foo y,z")),
|
||||
("x", None, L_EXPR(None, None, EXPR("x"))),
|
||||
("[x, foo y, z]", None, L_EXPR("[", "]", EXPR("x"), EXPR("foo y"), EXPR("z"))),
|
||||
("{x, foo y, z}", None, L_EXPR("{", "}", EXPR("x"), EXPR("foo y"), EXPR("z"))),
|
||||
("(x; y; z)", semi_colon, L_EXPR("(", ")", EXPR("x"), EXPR("y"), EXPR("z"), sep=semi_colon, source="(x; y; z)")),
|
||||
("x; y; z", semi_colon, L_EXPR(None, None, EXPR("x"), EXPR("y"), EXPR("z"), sep=semi_colon, source="x; y; z")),
|
||||
("x or y or z", or_token, L_EXPR(None, None, EXPR("x"), EXPR("y"), EXPR("z"), sep=or_token, source="x or y or z")),
|
||||
])
|
||||
def test_i_can_parse_expression(self, expression, sep, expected):
|
||||
sheerka, context, parser = self.init_parser(sep)
|
||||
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
wrapper = res.body
|
||||
expressions = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert expressions == expected
|
||||
|
||||
@pytest.mark.parametrize("expression, starting", [
|
||||
("(", TokenKind.LPAR),
|
||||
("(x, y", TokenKind.LPAR),
|
||||
("{x, y", TokenKind.LBRACE),
|
||||
("[x, y", TokenKind.LBRACKET),
|
||||
])
|
||||
def test_i_cannot_parse_when_missing_trailing_parenthesis(self, expression, starting):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||
assert res.body.body == [ParenthesisMismatchError(end_parenthesis_mapping[starting])]
|
||||
|
||||
def test_none_is_return_when_empty_parser_input(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
parser_input = ParserInput(" ").reset()
|
||||
parser_input.next_token()
|
||||
error_sink = ErrorSink()
|
||||
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert parsed is None
|
||||
@@ -100,12 +100,12 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
assert expressions == expected
|
||||
|
||||
@pytest.mark.parametrize("expression, expected_errors", [
|
||||
("one or", [UnexpectedEofParsingError("When parsing 'or'")]),
|
||||
("one and", [UnexpectedEofParsingError("When parsing 'and'")]),
|
||||
("and one", [LeftPartNotFoundError()]),
|
||||
("or one", [LeftPartNotFoundError()]),
|
||||
("or", [LeftPartNotFoundError(), UnexpectedEofParsingError("When parsing 'or'")]),
|
||||
("and", [LeftPartNotFoundError(), UnexpectedEofParsingError("When parsing 'and'")]),
|
||||
("one or", [UnexpectedEofParsingError("while parsing 'or'")]),
|
||||
("one and", [UnexpectedEofParsingError("while parsing 'and'")]),
|
||||
("and one", [LeftPartNotFoundError("and", 0)]),
|
||||
("or one", [LeftPartNotFoundError("or", 0)]),
|
||||
("or", [LeftPartNotFoundError("or", 0), UnexpectedEofParsingError("while parsing 'or'")]),
|
||||
("and", [LeftPartNotFoundError("and", 0), UnexpectedEofParsingError("while parsing 'and'")]),
|
||||
])
|
||||
def test_i_can_detect_error(self, expression, expected_errors):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -5,8 +5,7 @@ from core.concept import Concept, DEFINITION_TYPE_DEF
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, CN, SCN, get_test_obj, compare_with_test_object, \
|
||||
UTN
|
||||
from tests.parsers.parsers_utils import CN, SCN, UTN, compare_with_test_object, compute_expected_array, get_test_obj
|
||||
|
||||
|
||||
class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
@@ -463,3 +462,24 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert concept_found.name == "boys"
|
||||
assert concept_found.key == "boys"
|
||||
assert concept_found.get_prop(BuiltinConcepts.PLURAL) == boy
|
||||
|
||||
def test_i_can_set_body_for_plurals_that_are_a_set(self):
|
||||
concepts_map = {
|
||||
"boy": Concept("boy"),
|
||||
"girl": Concept("girl"),
|
||||
"human": Concept("human"),
|
||||
}
|
||||
|
||||
sheerka, context, parser = self.init_parser(concepts_map)
|
||||
global_truth_concept = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_concept, concepts_map["boy"], concepts_map["human"])
|
||||
sheerka.set_isa(global_truth_concept, concepts_map["girl"], concepts_map["human"])
|
||||
|
||||
res = parser.parse(context, ParserInput("humans"))
|
||||
|
||||
assert res.status
|
||||
lexer_nodes = res.body.body
|
||||
assert len(lexer_nodes) == 1
|
||||
concept_found = lexer_nodes[0].concept
|
||||
|
||||
assert concept_found.get_metadata().body == "get_set_elements(c:|1003:)"
|
||||
|
||||
+1370
-1118
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,422 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaEvaluateConcept import EvaluationHints
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.ListComprehensionParser import ListComprehensionParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkapython.ExprToPython import PythonExprVisitor
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@staticmethod
|
||||
def get_expr_node(context, expression, parser=None):
|
||||
parser = parser or ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert not error_sink.has_error
|
||||
|
||||
return parsed
|
||||
|
||||
@staticmethod
|
||||
def eval(context, return_value, namespace=None):
|
||||
evaluator = PythonEvaluator()
|
||||
assert evaluator.matches(context, return_value)
|
||||
|
||||
if namespace:
|
||||
for k, v in namespace.items():
|
||||
context.add_to_short_term_memory(k, v)
|
||||
|
||||
res = evaluator.eval(context, return_value)
|
||||
assert res.status
|
||||
return res.body
|
||||
|
||||
@pytest.mark.parametrize("expression, source, objects", [
|
||||
("foo w", "call_concept(__o_00__, x=w)", {"__o_00__": "foo"}),
|
||||
("foo z + 2", "call_concept(__o_00__, x=z + 2)", {"__o_00__": "foo"}),
|
||||
("foo a and bar b",
|
||||
"call_concept(__o_00__, x=a) and call_concept(__o_01__, y=b)",
|
||||
{"__o_00__": "foo", "__o_01__": "bar"}),
|
||||
("foo a or bar b",
|
||||
"call_concept(__o_00__, x=a) or call_concept(__o_01__, y=b)",
|
||||
{"__o_00__": "foo", "__o_01__": "bar"}),
|
||||
("not foo w", "not call_concept(__o_00__, x=w)", {"__o_00__": "foo"}),
|
||||
("foo a >= bar b",
|
||||
"call_concept(__o_00__, x=a) >= call_concept(__o_01__, y=b)",
|
||||
{"__o_00__": "foo", "__o_01__": "bar"}),
|
||||
("function(foo a, bar b)",
|
||||
"function(call_concept(__o_00__, x=a), call_concept(__o_01__, y=b))",
|
||||
{"__o_00__": "foo", "__o_01__": "bar"})
|
||||
|
||||
])
|
||||
def test_i_can_compile_concept_when_is_question_is_false(self, expression, source, objects):
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x").def_var("x"),
|
||||
Concept("bar y", body="y").def_var("y"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
concepts = {
|
||||
"foo": foo,
|
||||
"bar": bar
|
||||
}
|
||||
|
||||
node = self.get_expr_node(context, expression)
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == source
|
||||
|
||||
for obj_name, obj_value in objects.items():
|
||||
assert obj_name in python_node.objects
|
||||
|
||||
obj = python_node.objects[obj_name]
|
||||
if isinstance(obj, Concept):
|
||||
assert sheerka.isinstance(obj, concepts[obj_value])
|
||||
assert obj.get_hints().use_copy
|
||||
assert obj.get_hints().is_evaluated
|
||||
else:
|
||||
assert False
|
||||
|
||||
@pytest.mark.parametrize("expression, source, objects", [
|
||||
("foo w", "evaluate_question(__o_00__, x=w)", {"__o_00__": "foo"}),
|
||||
("foo z + 2", "evaluate_question(__o_00__, x=z + 2)", {"__o_00__": "foo"}),
|
||||
])
|
||||
def test_i_can_compile_concept_when_is_question_is_true(self, expression, source, objects):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x", pre="is_question()").def_var("x"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
concepts = {
|
||||
"foo": foo
|
||||
}
|
||||
|
||||
node = self.get_expr_node(context, expression)
|
||||
visitor = PythonExprVisitor(context)
|
||||
ret = visitor.compile(node, EvaluationHints(eval_body=True, eval_question=True))
|
||||
|
||||
assert len(ret) == 1
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == source
|
||||
|
||||
for obj_name, obj_value in objects.items():
|
||||
assert obj_name in python_node.objects
|
||||
|
||||
obj = python_node.objects[obj_name]
|
||||
if isinstance(obj, Concept):
|
||||
assert sheerka.isinstance(obj, concepts[obj_value])
|
||||
assert obj.get_hints().use_copy
|
||||
assert obj.get_hints().is_evaluated
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_i_can_compile_simple_list_comprehension(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
expression = "[ x for x in ['a', 'b'] if x == 'a' ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == expression
|
||||
|
||||
assert self.eval(context, ret[0]) == ["a"]
|
||||
|
||||
def test_i_can_compile_simple_list_comprehension_when_no_if(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
expression = "[ x for x in ['a', 'b'] ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == expression
|
||||
|
||||
assert self.eval(context, ret[0]) == ['a', 'b']
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_element_is_a_concept(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x").def_var("x")
|
||||
).unpack()
|
||||
|
||||
expression = "[ foo w for w in ['a', 'b'] ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == "[ call_concept(__o_00__, x=w) for w in ['a', 'b'] ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
|
||||
concept = python_node.objects["__o_00__"]
|
||||
assert sheerka.isinstance(concept, foo)
|
||||
assert concept.get_hints().use_copy
|
||||
assert concept.get_hints().is_evaluated
|
||||
|
||||
assert self.eval(context, ret[0]) == ["a", "b"]
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_concept_with_complex_parameter(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x").def_var("x"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
expression = "[ foo w + 1 for w in [1, 2] ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == "[ call_concept(__o_00__, x=w + 1) for w in [1, 2] ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
|
||||
assert self.eval(context, ret[0]) == [2, 3]
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_iter_is_a_concept(self):
|
||||
sheerka, context, red, blue, color, foo = self.init_test().with_concepts(
|
||||
"red",
|
||||
"blue",
|
||||
"color",
|
||||
Concept("foo x", body="x").def_var("x")
|
||||
).unpack()
|
||||
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, red, color)
|
||||
sheerka.set_isa(global_truth_context, blue, color)
|
||||
|
||||
expression = "[ foo x for x in colors ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == "[ call_concept(__o_00__, x=x) for x in call_concept(__o_01__) ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
assert "__o_01__" in python_node.objects
|
||||
|
||||
concept0 = python_node.objects["__o_00__"]
|
||||
assert sheerka.isinstance(concept0, foo)
|
||||
assert concept0.get_hints().use_copy
|
||||
assert concept0.get_hints().is_evaluated
|
||||
|
||||
concept1 = python_node.objects["__o_01__"]
|
||||
assert sheerka.isinstance(concept1, "colors")
|
||||
assert concept1.get_hints().use_copy
|
||||
assert concept1.get_hints().is_evaluated
|
||||
|
||||
assert set(self.eval(context, ret[0])) == {red, blue}
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_if_expression_is_a_concept(self):
|
||||
sheerka, context, red, blue, color, foo, startswith = self.init_test().with_concepts(
|
||||
"red",
|
||||
"blue",
|
||||
"color",
|
||||
Concept("foo x", body="x").def_var("x"),
|
||||
Concept("x starts with y", body="x.name.startswith(y)", pre="is_question()").def_var("x").def_var("y")
|
||||
).unpack()
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, red, color)
|
||||
sheerka.set_isa(global_truth_context, blue, color)
|
||||
|
||||
expression = "[ foo x for x in colors if x starts with 'b' ]"
|
||||
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == "[ call_concept(__o_00__, x=x) for x in call_concept(__o_01__) if evaluate_question(__o_02__, x=x, y='b') ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
assert "__o_01__" in python_node.objects
|
||||
assert "__o_02__" in python_node.objects
|
||||
assert visitor.obj_counter == 3
|
||||
|
||||
assert set(self.eval(context, ret[0])) == {blue}
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_multiple_concepts(self):
|
||||
sheerka, context, foo1, foo2, bar1, bar2, colors1, colors2, = self.init_test().with_concepts(
|
||||
Concept("foo x").def_var("x"),
|
||||
Concept("foo y", ).def_var("y"),
|
||||
Concept("bar x", pre="is_question()").def_var("x"),
|
||||
Concept("bar y", pre="is_question()").def_var("y"),
|
||||
Concept("colors", body="[1]"),
|
||||
Concept("colors", body="[2]"),
|
||||
).unpack()
|
||||
|
||||
expression = "[ foo a for a in colors if bar a ]"
|
||||
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 8
|
||||
python_node = ret[0].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == '[ call_concept(__o_00__, x=a) for a in call_concept(__o_02__) if evaluate_question(__o_04__, x=a) ]'
|
||||
assert object_to_compare == {"__o_00__": "foo x", "__o_02__": "colors", "__o_04__": "bar x"}
|
||||
|
||||
# ...
|
||||
|
||||
python_node = ret[7].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == '[ call_concept(__o_01__, y=a) for a in call_concept(__o_03__) if evaluate_question(__o_05__, y=a) ]'
|
||||
assert object_to_compare == {"__o_01__": "foo y", "__o_03__": "colors", "__o_05__": "bar y"}
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_missing_concept_parameter(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x y", body="x").def_var("x").def_var("y")
|
||||
).unpack()
|
||||
|
||||
expression = "[ foo x k for x in ['a', 'b'] ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
python_node = ret[0].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == "[ call_concept(__o_00__, x=x, y=k) for x in ['a', 'b'] ]"
|
||||
assert object_to_compare == {"__o_00__": "foo x y"}
|
||||
|
||||
def test_i_can_compile_simple_list_comprehension_when_multiple_for(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
expression = "[ (x, y) for x in ['a', 'b'] if x == 'a' for y in ['c', 'd'] if y == 'c' ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == expression
|
||||
|
||||
assert self.eval(context, ret[0]) == [("a", "c")]
|
||||
|
||||
def test_i_can_compile_and_when_multiple_results(self):
|
||||
sheerka, context, foo, foo2, bar, bar2 = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x").def_var("x"),
|
||||
Concept("foo y", body="y").def_var("y"),
|
||||
Concept("bar x", body="x").def_var("x"),
|
||||
Concept("bar y", body="y").def_var("y"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
node = self.get_expr_node(context, "foo a and bar b")
|
||||
visitor = PythonExprVisitor(context)
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 4
|
||||
python_node = ret[0].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == 'call_concept(__o_00__, x=a) and call_concept(__o_02__, x=b)'
|
||||
assert object_to_compare == {"__o_00__": "foo x", "__o_02__": "bar x"}
|
||||
|
||||
python_node = ret[1].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == 'call_concept(__o_00__, x=a) and call_concept(__o_03__, y=b)'
|
||||
assert object_to_compare == {"__o_00__": "foo x", "__o_03__": "bar y"}
|
||||
|
||||
python_node = ret[2].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == 'call_concept(__o_01__, y=a) and call_concept(__o_02__, x=b)'
|
||||
assert object_to_compare == {"__o_01__": "foo y", "__o_02__": "bar x"}
|
||||
|
||||
python_node = ret[3].body.body
|
||||
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
|
||||
assert python_node.source == 'call_concept(__o_01__, y=a) and call_concept(__o_03__, y=b)'
|
||||
assert object_to_compare == {"__o_01__": "foo y", "__o_03__": "bar y"}
|
||||
|
||||
def test_i_can_compile_when_element_is_missing_its_parenthesis(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x").def_var("x")
|
||||
).unpack()
|
||||
|
||||
expression = "[ w, foo w for w in ['a', 'b'] ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(ret[0].body.body, PythonNode)
|
||||
|
||||
python_node = ret[0].body.body
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == "[ (w, call_concept(__o_00__, x=w)) for w in ['a', 'b'] ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
|
||||
concept = python_node.objects["__o_00__"]
|
||||
assert sheerka.isinstance(concept, foo)
|
||||
assert concept.get_hints().use_copy
|
||||
assert concept.get_hints().is_evaluated
|
||||
|
||||
assert self.eval(context, ret[0]) == [("a", "a"), ("b", "b")]
|
||||
Reference in New Issue
Block a user