Fixed #131 : Implement ExprToConditions
Fixed #130 : ArithmeticOperatorParser Fixed #129 : python_wrapper : create_namespace Fixed #128 : ExpressionParser: Cannot parse func(x) infixed concept 'xxx'
This commit is contained in:
@@ -2,6 +2,7 @@ import ast
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept, ReturnValueConcept
|
||||
from core.builtin_helpers import evaluate_from_source, expect_one
|
||||
from core.concept import Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF, freeze_concept_attrs
|
||||
from core.rule import ACTION_TYPE_EXEC, ACTION_TYPE_PRINT, Rule
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
@@ -306,3 +307,17 @@ class BaseTest:
|
||||
|
||||
# the see the logs, do not forget to add
|
||||
# logs = sheerka.get_debugger_logs()
|
||||
|
||||
@staticmethod
|
||||
def evaluate_from_source(context, source, is_question=False):
|
||||
res = evaluate_from_source(context,
|
||||
source,
|
||||
desc=None,
|
||||
eval_body=not is_question,
|
||||
eval_where=False,
|
||||
is_question=is_question,
|
||||
expect_success=False,
|
||||
stm=None)
|
||||
res = expect_one(context, res)
|
||||
assert res.status
|
||||
return res.body
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer, TokenKind
|
||||
from core.tokenizer import TokenKind, Tokenizer
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text, start, end, expected", [
|
||||
@@ -141,3 +142,37 @@ def test_i_can_get_the_token_after(text, skip_whitespace, expected):
|
||||
parser_input = ParserInput(text).reset()
|
||||
parser_input.next_token()
|
||||
assert parser_input.the_token_after(skip_whitespace).repr_value == expected
|
||||
|
||||
|
||||
def test_i_can_define_a_sub_part():
|
||||
text = "Hello Koffi the great guy."
|
||||
tokens = list(Tokenizer(text))
|
||||
|
||||
parser_input = ParserInput(None, tokens, 2, 6)
|
||||
assert repr(parser_input) == "ParserInput(from_tokens'Koffi the great')"
|
||||
|
||||
parser_input.reset()
|
||||
assert repr(parser_input) == "ParserInput(from_tokens'Koffi the great')"
|
||||
res = []
|
||||
while parser_input.next_token():
|
||||
res.append(f"{parser_input.token.repr_value}")
|
||||
|
||||
assert res == ["Koffi", "the", "great"]
|
||||
assert repr(parser_input) == "ParserInput(from_tokens'Koffi the great')"
|
||||
|
||||
|
||||
def test_i_can_define_parse_input_from_tokens():
|
||||
text = "Hello Koffi the great guy."
|
||||
tokens = list(Tokenizer(text))
|
||||
|
||||
parser_input = ParserInput(None, tokens)
|
||||
assert repr(parser_input) == "ParserInput(from_tokens'Hello Koffi the great guy.')"
|
||||
|
||||
parser_input.reset()
|
||||
assert repr(parser_input) == "ParserInput(from_tokens'Hello Koffi the great guy.')"
|
||||
res = []
|
||||
while parser_input.next_token():
|
||||
res.append(f"{parser_input.token.repr_value}")
|
||||
|
||||
assert res == ["Hello", "Koffi", "the", "great", "guy", "."]
|
||||
assert repr(parser_input) == "ParserInput(from_tokens'Hello Koffi the great guy.')"
|
||||
|
||||
@@ -1017,7 +1017,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
"one",
|
||||
"number",
|
||||
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
|
||||
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
evaluator = SheerkaEvaluateConcept(sheerka)
|
||||
|
||||
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
|
||||
@@ -1026,7 +1026,6 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
assert concept.get_compiled()["y"][0].body.body.get_hints().use_copy
|
||||
|
||||
# get the body
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
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
|
||||
|
||||
@@ -7,10 +7,11 @@ from core.rule import Rule, ACTION_TYPE_EXEC
|
||||
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
|
||||
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules, LOW_PRIORITY_RULES, DISABLED_RULES
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, CompiledCondition, PythonConditionExprVisitor
|
||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, CompiledCondition
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.PythonParser import PythonParser
|
||||
from sheerkapython.ExprToConditions import ExprToConditionsVisitor
|
||||
from sheerkapython.python_wrapper import Expando
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
@@ -114,6 +115,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
res = service.evaluate_rules(context, [r1, r2, r3], {}, set())
|
||||
assert res == {True: [r1, r3], False: [r2]}
|
||||
|
||||
@pytest.mark.skip("recognize is not supported yet")
|
||||
@pytest.mark.parametrize("predicate", [
|
||||
"recognize(__ret.body, greetings)",
|
||||
"recognize(__ret.body, c:|1001:)",
|
||||
@@ -134,6 +136,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
|
||||
assert res == {True: [rule]}
|
||||
|
||||
@pytest.mark.skip("recognize is not supported yet")
|
||||
@pytest.mark.parametrize("recognized_by", [
|
||||
RECOGNIZED_BY_ID,
|
||||
RECOGNIZED_BY_NAME,
|
||||
@@ -157,6 +160,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
|
||||
assert res == {True: [rule]}
|
||||
|
||||
@pytest.mark.skip("recognize is not supported yet")
|
||||
@pytest.mark.parametrize("recognized_by", [
|
||||
RECOGNIZED_BY_ID,
|
||||
RECOGNIZED_BY_NAME,
|
||||
@@ -180,6 +184,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
|
||||
assert res == {True: [rule]}
|
||||
|
||||
@pytest.mark.skip("recognize is not supported yet")
|
||||
def test_i_can_evaluate_concept_rules_when_variable_is_an_expando(self):
|
||||
sheerka, context, greetings, rule = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
@@ -208,6 +213,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
res = service.evaluate_rules(context, [rule], {"__ret": ret2}, set())
|
||||
assert res == {True: [rule]}
|
||||
|
||||
@pytest.mark.skip("recognize is not supported yet")
|
||||
def test_i_can_evaluate_concept_rule_with_the_same_name_when_the_second_concept_is_declared_after(self):
|
||||
sheerka, context, g1, rule, g2 = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
@@ -255,11 +261,11 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
expression = "isinstance(a, int)"
|
||||
parser = ExpressionParser()
|
||||
parser = ExpressionParser(auto_compile=False)
|
||||
ret_val = parser.parse(context, ParserInput(expression))
|
||||
parsed = ret_val.body.body
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
visitor = ExprToConditionsVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
missing_vars = set()
|
||||
|
||||
@@ -96,17 +96,17 @@ class TestSheerkaQueryManager(TestUsingMemoryBasedSheerka):
|
||||
Concept("foo", body="b").auto_init(),
|
||||
B("a31", "a32")]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, "self.prop1 == 'a21'") == [lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, "self.prop2 >= 1") == [lst[0], lst[1], lst[2]]
|
||||
assert sheerka.filter_objects(context, lst, "get_type(self) == 'foo' ") == [lst[4], lst[6]]
|
||||
assert sheerka.filter_objects(context, lst, "self.fake_prop1 == 'a21' ") == [lst[5]]
|
||||
assert sheerka.filter_objects(context, lst, "hasattr(self, 'fake_prop1')") == [lst[5], lst[7]]
|
||||
assert sheerka.filter_objects(context, lst, predicate="self.prop1 == 'a21'") == [lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, predicate="self.prop2 >= 1") == [lst[0], lst[1], lst[2]]
|
||||
assert sheerka.filter_objects(context, lst, predicate="get_type(self) == 'foo' ") == [lst[4], lst[6]]
|
||||
assert sheerka.filter_objects(context, lst, predicate="self.fake_prop1 == 'a21' ") == [lst[5]]
|
||||
assert sheerka.filter_objects(context, lst, predicate="hasattr(self, 'fake_prop1')") == [lst[5], lst[7]]
|
||||
|
||||
def test_i_can_filter_object_using_predicate_and_sheerka_objects(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
lst = [foo, bar, A("a21", 3.14)]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, "self == bar") == [lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, predicate="self == bar") == [lst[1]]
|
||||
|
||||
def test_i_can_filter_objects_using_concept(self):
|
||||
sheerka, context, foo, bar, isa = self.init_concepts(
|
||||
@@ -116,7 +116,7 @@ class TestSheerkaQueryManager(TestUsingMemoryBasedSheerka):
|
||||
create_new=True)
|
||||
|
||||
lst = [foo, A("a21", 3.14), bar, B("a21", 3.14)]
|
||||
assert sheerka.filter_objects(context, lst, "self is a concept") == [foo, bar]
|
||||
assert sheerka.filter_objects(context, lst, predicate="self is a concept") == [foo, bar]
|
||||
|
||||
def test_i_can_filter_objects_when_no_kwargs_and_no_predicate(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
@@ -124,6 +124,25 @@ class TestSheerkaQueryManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert sheerka.filter_objects(context, lst) == lst
|
||||
|
||||
def test_i_can_filter_objects_after_applying_a_mapping(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10),
|
||||
A("a21", 3.14)]
|
||||
|
||||
res = sheerka.filter_objects(context, lst, mapping=lambda o: o.prop1, predicate="self[1] == '1'")
|
||||
assert res == [A("a11", 10)]
|
||||
|
||||
def test_i_can_filter_objects_using_concept_after_applying_a_mapping(self):
|
||||
sheerka, context, foo, bar, isa = self.init_concepts(
|
||||
"foo",
|
||||
"bar",
|
||||
Concept("x is a concept", body="isinstance(x, Concept)", pre="is_question()").def_var("x"),
|
||||
create_new=True)
|
||||
|
||||
lst = [foo, A(foo, 3.14), bar, A(bar, 3.14)]
|
||||
res = sheerka.filter_objects(context, lst, mapping=lambda o: o.prop1, predicate="self is a concept")
|
||||
assert res == [lst[1], lst[3]]
|
||||
|
||||
def test_i_must_select_object_property_using_string(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
|
||||
@@ -170,7 +170,6 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
||||
rule = service.init_rule(context, rule)
|
||||
|
||||
assert len(rule.error_sink["when"]) > 0
|
||||
assert sheerka.has_error(context, rule.error_sink["when"][0])
|
||||
assert "print" not in rule.error_sink
|
||||
assert "then" not in rule.error_sink
|
||||
assert rule.metadata.is_compiled
|
||||
@@ -362,7 +361,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
).unpack()
|
||||
parser = ExpressionParser()
|
||||
parser = ExpressionParser(old_style=True)
|
||||
expected_conditions = get_rete_conditions(*expected)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,11 @@ import os
|
||||
import pytest
|
||||
|
||||
from conftest import SHEERKA_TEST_FOLDER
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, UnknownConcept
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UnknownConcept, UserInputConcept
|
||||
from core.builtin_concepts_ids import AllBuiltinConcepts
|
||||
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts, get_concept_attrs
|
||||
from core.concept import Concept, ConceptParts, PROPERTIES_TO_SERIALIZE, get_concept_attrs
|
||||
from core.global_symbols import NotInit
|
||||
from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS
|
||||
from core.sheerka.Sheerka import BASE_NODE_PARSER_CLASS, Sheerka
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager, ValueNotFound
|
||||
from core.tokenizer import Token, TokenKind
|
||||
from parsers.PythonParser import PythonErrorNode
|
||||
@@ -541,6 +541,18 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
errors_found = sheerka.get_errors(context, ret_val, source="error source")
|
||||
assert errors_found == [python_error]
|
||||
|
||||
def test_i_can_filter_error_by_exception_name(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
from evaluators.PythonEvaluator import PythonEvalError
|
||||
name_error = NameError("foo")
|
||||
python_eval_error = PythonEvalError(name_error, "foo", None, None)
|
||||
error = sheerka.err([python_eval_error])
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
|
||||
errors_found = sheerka.get_errors(context, ret_val, __type="NameError")
|
||||
assert errors_found == [name_error]
|
||||
|
||||
def test_i_can_filter_error_on_multiple_criteria(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from core.tokenizer import Tokenizer, Token, TokenKind, LexerError
|
||||
|
||||
def test_i_can_tokenize():
|
||||
source = "+*-/{}[]() ,;:.?\n\n\r\r\r\nidentifier_0\t \t10.15 10 'string\n' \"another string\"=|&<>c:name:"
|
||||
source += "$£€!_identifier°~_^\\`==#__var__10r/regex\nregex/r:xxx|1:"
|
||||
source += "$£€!_identifier°~_^\\`==#__var__10r/regex\nregex/r:xxx|1:**//%"
|
||||
tokens = list(Tokenizer(source))
|
||||
assert tokens[0] == Token(TokenKind.PLUS, "+", 0, 1, 1)
|
||||
assert tokens[1] == Token(TokenKind.STAR, "*", 1, 1, 2)
|
||||
@@ -58,8 +58,11 @@ def test_i_can_tokenize():
|
||||
assert tokens[48] == Token(TokenKind.VAR_DEF, '__var__10', 112, 6, 55)
|
||||
assert tokens[49] == Token(TokenKind.REGEX, '/regex\nregex/', 121, 6, 64)
|
||||
assert tokens[50] == Token(TokenKind.RULE, ("xxx", "1"), 135, 7, 7)
|
||||
assert tokens[51] == Token(TokenKind.STARSTAR, "**", 143, 7, 15)
|
||||
assert tokens[52] == Token(TokenKind.SLASHSLASH, "//", 145, 7, 17)
|
||||
assert tokens[53] == Token(TokenKind.PERCENT, "%", 147, 7, 19)
|
||||
|
||||
assert tokens[51] == Token(TokenKind.EOF, '', 143, 7, 15)
|
||||
assert tokens[54] == Token(TokenKind.EOF, '', 148, 7, 20)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
|
||||
@@ -7,7 +7,7 @@ from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import evaluate_expression
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import NotFound, NotInit, Removed
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer, Keywords
|
||||
from core.tokenizer import Keywords, Token, TokenKind, Tokenizer
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -512,3 +512,24 @@ def test_i_can_replace_after():
|
||||
with pytest.raises(KeyError):
|
||||
my_list3 = ["a", "b", "c", "d"]
|
||||
core.utils.replace_after(my_list3, "x", my_new_items)
|
||||
|
||||
|
||||
def test_i_can_tokens_index():
|
||||
tokens = list(Tokenizer("a b c d e"))
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
core.utils.tokens_index(tokens, None)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
core.utils.tokens_index(tokens, [])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
core.utils.tokens_index(tokens, list(Tokenizer("f", yield_eof=False)))
|
||||
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer("a", yield_eof=False))) == 0
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer("b", yield_eof=False))) == 2
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer("b c", yield_eof=False))) == 2
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer(" ", yield_eof=False))) == 1
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer(" ", yield_eof=False)), skip=2) == 5
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer(" ", yield_eof=False)), start_from_end=True) == 7
|
||||
assert core.utils.tokens_index(tokens, list(Tokenizer(" ", yield_eof=False)), skip=2, start_from_end=True) == 3
|
||||
|
||||
@@ -343,7 +343,7 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert created_concept.get_metadata().variables == [('n1', None), ('one', None), ('two', None), ('n2', None)]
|
||||
assert created_concept.get_metadata().parameters == ['n1', 'n2']
|
||||
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unamed_ordered_choice(self):
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unnamed_ordered_choice(self):
|
||||
sheerka, context, one, two, three = self.init_concepts("one", "two", "three", create_new=True)
|
||||
text = "def concept choice from bnf (one|two) 'or' (two|three) 'or' (two|three)=c3"
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
|
||||
@@ -382,7 +382,7 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert created_concept.get_metadata().variables == [('n1', None), ('n2', None)]
|
||||
assert created_concept.get_metadata().parameters == ['n1', 'n2']
|
||||
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unamed_unordered_choice(self):
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unnamed_unordered_choice(self):
|
||||
# as it's not possible to directly defined UnorderedChoice, we test isa concept
|
||||
sheerka, context, one, two, number = self.init_concepts("one", "two", "number", create_new=True)
|
||||
global_truth_context = self.get_context(global_truth=True)
|
||||
|
||||
@@ -55,6 +55,7 @@ class TestExpressionEvaluator(TestUsingMemoryBasedSheerka):
|
||||
"one",
|
||||
"number",
|
||||
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
evaluator = ExpressionEvaluator()
|
||||
|
||||
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
|
||||
@@ -72,6 +73,7 @@ class TestExpressionEvaluator(TestUsingMemoryBasedSheerka):
|
||||
"one",
|
||||
"number",
|
||||
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
evaluator = ExpressionEvaluator()
|
||||
|
||||
parsed_return_value = ExpressionParser().parse(context, ParserInput("self is a number"))
|
||||
|
||||
@@ -27,17 +27,17 @@ class TestPrepareEvalCommon(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_update_process_when_evaluating_a_concept(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
|
||||
eval_context = context.push(BuiltinConcepts.EVALUATING_CONCEPT, foo, desc=f"some desc")
|
||||
parsing_prop_context = eval_context.push(BuiltinConcepts.PARSING, {"prop": ConceptParts.BODY})
|
||||
level1 = parsing_prop_context.push(BuiltinConcepts.TESTING, "some stuff")
|
||||
level2 = level1.push(BuiltinConcepts.TESTING, "some stuff") # another level for the fun
|
||||
eval_ctx = context.push(BuiltinConcepts.EVALUATING_CONCEPT, foo, desc=f"some desc")
|
||||
parsing_prop_ctx = eval_ctx.push(BuiltinConcepts.PARSE_CODE, {"concept": foo, "prop": ConceptParts.BODY})
|
||||
level1_ctx = parsing_prop_ctx.push(BuiltinConcepts.TESTING, "some stuff")
|
||||
level2_ctx = level1_ctx.push(BuiltinConcepts.TESTING, "some stuff") # another level for the fun
|
||||
|
||||
PrepareEvalCommon.update_context_hints(level2, "prop_name", ["to_put_in_context"])
|
||||
PrepareEvalCommon.update_context_hints(level2_ctx, "prop_name", ["to_put_in_context"])
|
||||
assert not context.in_context("to_put_in_context")
|
||||
assert not eval_context.in_context("to_put_in_context")
|
||||
assert not parsing_prop_context.in_context("to_put_in_context")
|
||||
assert not level1.in_context("to_put_in_context")
|
||||
assert not level2.in_context("to_put_in_context")
|
||||
assert not eval_ctx.in_context("to_put_in_context")
|
||||
assert not parsing_prop_ctx.in_context("to_put_in_context")
|
||||
assert not level1_ctx.in_context("to_put_in_context")
|
||||
assert not level2_ctx.in_context("to_put_in_context")
|
||||
assert foo.get_compiled_context_hints() == {ConceptParts.BODY: ["to_put_in_context"]}
|
||||
|
||||
def test_i_can_update_for_the_correct_variable(self):
|
||||
@@ -45,15 +45,15 @@ class TestPrepareEvalCommon(TestUsingMemoryBasedSheerka):
|
||||
# use this name, rather than the attribute being parsed
|
||||
sheerka, context, foo = self.init_concepts(Concept("foo").def_var("var_name"))
|
||||
|
||||
eval_context = context.push(BuiltinConcepts.EVALUATING_CONCEPT, foo, desc=f"some desc")
|
||||
parsing_prop_context = eval_context.push(BuiltinConcepts.PARSING, {"prop": ConceptParts.BODY})
|
||||
level1 = parsing_prop_context.push(BuiltinConcepts.TESTING, "some stuff")
|
||||
level2 = level1.push(BuiltinConcepts.TESTING, "some stuff") # another level for the fun
|
||||
eval_ctx = context.push(BuiltinConcepts.EVALUATING_CONCEPT, foo, desc=f"some desc")
|
||||
parsing_prop_ctx = eval_ctx.push(BuiltinConcepts.PARSE_CODE, {"concept": foo, "prop": ConceptParts.BODY})
|
||||
level1_ctx = parsing_prop_ctx.push(BuiltinConcepts.TESTING, "some stuff")
|
||||
level2_ctx = level1_ctx.push(BuiltinConcepts.TESTING, "some stuff") # another level for the fun
|
||||
|
||||
PrepareEvalCommon.update_context_hints(level2, "var_name", ["to_put_in_context"])
|
||||
PrepareEvalCommon.update_context_hints(level2_ctx, "var_name", ["to_put_in_context"])
|
||||
assert not context.in_context("to_put_in_context")
|
||||
assert not eval_context.in_context("to_put_in_context")
|
||||
assert not parsing_prop_context.in_context("to_put_in_context")
|
||||
assert not level1.in_context("to_put_in_context")
|
||||
assert not level2.in_context("to_put_in_context")
|
||||
assert not eval_ctx.in_context("to_put_in_context")
|
||||
assert not parsing_prop_ctx.in_context("to_put_in_context")
|
||||
assert not level1_ctx.in_context("to_put_in_context")
|
||||
assert not level2_ctx.in_context("to_put_in_context")
|
||||
assert foo.get_compiled_context_hints() == {"var_name": ["to_put_in_context"]}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
|
||||
from core.concept import Concept
|
||||
from core.concept import Concept, ConceptParts
|
||||
from evaluators.PrepareEvalQuestionEvaluator import PrepareEvalQuestionEvaluator
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
r = ReturnValueConcept
|
||||
@@ -48,3 +47,29 @@ class TestPrepareEvalQuestionEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED in context.protected_hints
|
||||
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.protected_hints
|
||||
assert BuiltinConcepts.RETURN_BODY_REQUESTED in context.protected_hints
|
||||
|
||||
def test_i_can_eval_when_parsing_asts(self):
|
||||
sheerka, context, foo = self.init_concepts(Concept("foo", body="question(q)").def_var("q"))
|
||||
|
||||
parsing_prop_ctx = context.push(BuiltinConcepts.PARSE_CODE, {"concept": foo, "prop": ConceptParts.BODY})
|
||||
level1_ctx = parsing_prop_ctx.push(BuiltinConcepts.TESTING, "some stuff")
|
||||
level2_ctx = level1_ctx.push(BuiltinConcepts.TESTING, "some stuff") # another level for the fun
|
||||
ret_val = r("name", True, UserInputConcept("question(q)"))
|
||||
|
||||
prepare_evaluator = PrepareEvalQuestionEvaluator()
|
||||
prepare_evaluator.matches(level2_ctx, ret_val)
|
||||
res = prepare_evaluator.eval(level2_ctx, ret_val)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.USER_INPUT)
|
||||
assert res.body.body == "q"
|
||||
|
||||
assert BuiltinConcepts.EVAL_QUESTION_REQUESTED not in context.protected_hints
|
||||
assert BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED not in context.protected_hints
|
||||
assert BuiltinConcepts.EVAL_BODY_REQUESTED not in context.protected_hints
|
||||
assert BuiltinConcepts.RETURN_BODY_REQUESTED not in context.protected_hints
|
||||
|
||||
assert foo.get_compiled_context_hints() == {"q": [BuiltinConcepts.EVAL_QUESTION_REQUESTED,
|
||||
BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED,
|
||||
BuiltinConcepts.EVAL_BODY_REQUESTED,
|
||||
BuiltinConcepts.RETURN_BODY_REQUESTED]}
|
||||
|
||||
@@ -11,7 +11,7 @@ from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError
|
||||
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.FunctionParserOld import FunctionParserOld
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import CB, compare_with_test_object
|
||||
@@ -318,7 +318,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
context = self.get_context()
|
||||
context.add_to_short_term_memory("get_obj_name", get_obj_name)
|
||||
|
||||
parsed = FunctionParser().parse(context, ParserInput("get_obj_name(r:|1:)"))
|
||||
parsed = FunctionParserOld().parse(context, ParserInput("get_obj_name(r:|1:)"))
|
||||
python_evaluator = PythonEvaluator()
|
||||
evaluated = python_evaluator.eval(context, parsed)
|
||||
|
||||
@@ -344,7 +344,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
context = self.get_context()
|
||||
context.add_to_short_term_memory("return_return_value", return_return_value)
|
||||
|
||||
parsed = FunctionParser().parse(context, ParserInput(method))
|
||||
parsed = FunctionParserOld().parse(context, ParserInput(method))
|
||||
python_evaluator = PythonEvaluator()
|
||||
evaluated = python_evaluator.eval(context, parsed)
|
||||
ret_val = return_return_value(expected_status)
|
||||
@@ -371,9 +371,9 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@pytest.mark.parametrize("parser, value", [
|
||||
(PythonParser(), "3"),
|
||||
(FunctionParser(), "3"),
|
||||
(FunctionParserOld(), "3"),
|
||||
(PythonParser(), 3),
|
||||
(FunctionParser(), 3),
|
||||
(FunctionParserOld(), 3),
|
||||
])
|
||||
def test_i_can_eval_unresolved_rules(self, parser, value):
|
||||
context = self.get_context()
|
||||
|
||||
@@ -661,7 +661,6 @@ as:
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("twenty one")
|
||||
assert len(res) == 1
|
||||
|
||||
@@ -69,9 +69,9 @@ class TestSheerkaNonRegPipeFunctions(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_collect_properties(self):
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept isa from x is a y def_var x def_var y",
|
||||
"def concept is_a from x is a y def_var x def_var y",
|
||||
"def concept plus from a plus b as a + b",
|
||||
"add_to_memory('x', [one, isa, plus])"
|
||||
"add_to_memory('x', [one, is_a, plus])"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
@@ -80,6 +80,6 @@ class TestSheerkaNonRegPipeFunctions(TestUsingMemoryBasedSheerka):
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.TO_DICT)
|
||||
assert res[0].body.body == {'isa': ['body', 'id', 'key', 'name', 'x', 'y'],
|
||||
assert res[0].body.body == {'is_a': ['body', 'id', 'key', 'name', 'x', 'y'],
|
||||
'one': ['body', 'id', 'key', 'name'],
|
||||
'plus': ['a', 'b', 'body', 'id', 'key', 'name']}
|
||||
|
||||
+236
-60
@@ -8,12 +8,14 @@ from core.concept import AllConceptParts, Concept, ConceptParts, DoNotResolve
|
||||
from core.rule import Rule
|
||||
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, \
|
||||
from parsers.BaseExpressionParser import AndNode, BinaryNode, ComparisonNode, ComparisonType, Comprehension, \
|
||||
FunctionNode, \
|
||||
FunctionParameter, \
|
||||
ListComprehensionNode, ListNode, NameExprNode, \
|
||||
NotNode, OrNode, VariableNode, comma
|
||||
NotNode, OrNode, SequenceNode, VariableNode, t_comma
|
||||
from parsers.BaseNodeParser import ConceptNode, RuleNode, SourceCodeNode, SourceCodeWithConceptNode, \
|
||||
UnrecognizedTokensNode
|
||||
from parsers.FunctionParser import FunctionNode
|
||||
from parsers.FunctionParserOld import FunctionNodeOld
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkapython.python_wrapper import sheerka_globals
|
||||
from sheerkarete.common import V
|
||||
@@ -52,16 +54,29 @@ class ExprTestObj:
|
||||
|
||||
return list(Tokenizer(source, yield_eof=False)), to_skip
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
raise NotImplementedError()
|
||||
|
||||
@staticmethod
|
||||
def safe_get_expr_node(obj, full_text_as_tokens):
|
||||
def safe_get_expr_node(obj, full_text_as_tokens, default_expr_obj):
|
||||
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)
|
||||
obj = default_expr_obj(obj) if isinstance(obj, (str, tuple)) else obj
|
||||
return obj.get_expr_node(full_text_as_tokens, default_expr_obj)
|
||||
|
||||
|
||||
class SEQ(ExprTestObj):
|
||||
""" Test class for SequenceNode"""
|
||||
|
||||
def __init__(self, *parts, source=None):
|
||||
self.parts = parts
|
||||
self.source = source
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
parts = [self.safe_get_expr_node(part, full_text_as_tokens, default_expr_obj) 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 SequenceNode(start, end, full_text_as_tokens[start: end + 1], *parts)
|
||||
|
||||
|
||||
class AND(ExprTestObj):
|
||||
@@ -71,8 +86,8 @@ class AND(ExprTestObj):
|
||||
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]
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
parts = [self.safe_get_expr_node(part, full_text_as_tokens, default_expr_obj) 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)
|
||||
|
||||
@@ -84,8 +99,8 @@ class OR(ExprTestObj):
|
||||
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]
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
parts = [self.safe_get_expr_node(part, full_text_as_tokens, default_expr_obj) 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)
|
||||
|
||||
@@ -96,8 +111,8 @@ class NOT(ExprTestObj):
|
||||
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)
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
part = self.safe_get_expr_node(self.expr, full_text_as_tokens, default_expr_obj)
|
||||
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)
|
||||
@@ -108,7 +123,7 @@ class EXPR(ExprTestObj):
|
||||
"""Test class for NameNode"""
|
||||
source: str
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
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
|
||||
@@ -122,7 +137,7 @@ class VAR(ExprTestObj):
|
||||
full_name: str
|
||||
source: str = None
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
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
|
||||
@@ -133,19 +148,77 @@ class VAR(ExprTestObj):
|
||||
return VariableNode(start, end, full_text_as_tokens[start: end + 1], parts[0], *parts[1:])
|
||||
|
||||
|
||||
class BinaryExprTestObj(ExprTestObj):
|
||||
def __init__(self, *parts: Union[ExprTestObj, str], source=None):
|
||||
self.parts = parts
|
||||
self.source = source
|
||||
|
||||
@staticmethod
|
||||
def get_op_from_name(name):
|
||||
if name == "ADD":
|
||||
return Token(TokenKind.PLUS, "+", -1, -1, -1)
|
||||
elif name == "SUB":
|
||||
return Token(TokenKind.MINUS, "-", -1, -1, -1)
|
||||
elif name == "MULT":
|
||||
return Token(TokenKind.STAR, "*", -1, -1, -1)
|
||||
elif name == "DIV":
|
||||
return Token(TokenKind.SLASH, "/", -1, -1, -1)
|
||||
elif name == "POW":
|
||||
return Token(TokenKind.STARSTAR, "**", -1, -1, -1)
|
||||
elif name == "FDIV":
|
||||
return Token(TokenKind.SLASHSLASH, "//", -1, -1, -1)
|
||||
elif name == "MOD":
|
||||
return Token(TokenKind.PERCENT, "%", -1, -1, -1)
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
op = self.get_op_from_name(type(self).__name__)
|
||||
parts_as_node = [self.safe_get_expr_node(p, full_text_as_tokens, default_expr_obj) for p in self.parts]
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens) if self.source else \
|
||||
self.get_pos(parts_as_node)
|
||||
return BinaryNode(start, end, full_text_as_tokens[start: end + 1], op, *parts_as_node)
|
||||
|
||||
|
||||
class ADD(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
class SUB(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
class MULT(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
class DIV(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
class FDIV(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
class MOD(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
class POW(BinaryExprTestObj):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class CompExprTestObj(ExprTestObj):
|
||||
"""
|
||||
Test object for comparison ==, <=, ...
|
||||
"""
|
||||
left: ExprTestObj
|
||||
right: ExprTestObj
|
||||
left: Union[ExprTestObj, str]
|
||||
right: Union[ExprTestObj, str]
|
||||
source: str = None
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
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)
|
||||
left_node = self.safe_get_expr_node(self.left, full_text_as_tokens, default_expr_obj)
|
||||
right_node = self.safe_get_expr_node(self.right, full_text_as_tokens, default_expr_obj)
|
||||
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)
|
||||
@@ -202,20 +275,20 @@ class L_EXPR(ExprTestObj):
|
||||
self.first = first
|
||||
self.last = last
|
||||
self.items = items
|
||||
self.sep = sep or comma
|
||||
self.sep = sep or t_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)
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
first = self.safe_get_expr_node(self.first, full_text_as_tokens, EXPR)
|
||||
last = self.safe_get_expr_node(self.last, full_text_as_tokens, EXPR)
|
||||
|
||||
items = [self.safe_get_expr_node(item, full_text_as_tokens) for item in self.items]
|
||||
items = [self.safe_get_expr_node(item, full_text_as_tokens, default_expr_obj) for item in self.items]
|
||||
|
||||
if self.source is None:
|
||||
source = self.first if self.first else ""
|
||||
source = first.get_source() if self.first else ""
|
||||
source += f"{self.sep.value} ".join(item.get_source() for item in items)
|
||||
if self.last:
|
||||
source += self.last
|
||||
if last:
|
||||
source += last.get_source()
|
||||
else:
|
||||
source = self.source
|
||||
|
||||
@@ -223,6 +296,52 @@ class L_EXPR(ExprTestObj):
|
||||
return ListNode(start, end, full_text_as_tokens[start: end + 1], first, last, items, self.sep)
|
||||
|
||||
|
||||
class FN(ExprTestObj):
|
||||
"""
|
||||
Test class only
|
||||
It matches with FunctionNode
|
||||
"""
|
||||
|
||||
def __init__(self, name, *parameters, source=None):
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
self.source = source
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
start, end = -1, -1
|
||||
|
||||
if self.parameters and isinstance(self.parameters[0], L_EXPR):
|
||||
params_as_test_obj = self.parameters[0]
|
||||
|
||||
else:
|
||||
nb_left_parenthesis = 0
|
||||
nb_right_parenthesis = 0
|
||||
if self.source:
|
||||
start, end = self.get_pos_from_source(self.source, full_text_as_tokens)
|
||||
for i in range(start):
|
||||
if full_text_as_tokens[i].type == TokenKind.LPAR:
|
||||
nb_left_parenthesis += 1
|
||||
for i in range(end):
|
||||
if full_text_as_tokens[i].type == TokenKind.RPAR:
|
||||
nb_right_parenthesis += 1
|
||||
else:
|
||||
for p in self.parameters:
|
||||
if isinstance(p, str):
|
||||
nb_right_parenthesis += p.count(")")
|
||||
|
||||
first = ("(", nb_left_parenthesis) if nb_left_parenthesis > 0 else "("
|
||||
last = (")", nb_right_parenthesis) if nb_right_parenthesis > 0 else ")"
|
||||
params_as_test_obj = L_EXPR(first, last, *self.parameters)
|
||||
|
||||
name_as_expr = self.safe_get_expr_node(self.name, full_text_as_tokens, default_expr_obj)
|
||||
params_as_expr = self.safe_get_expr_node(params_as_test_obj, full_text_as_tokens, default_expr_obj)
|
||||
|
||||
if start < 1:
|
||||
start, end = self.get_pos([name_as_expr, params_as_expr.last])
|
||||
|
||||
return FunctionNode(start, end, full_text_as_tokens[start:end + 1], name_as_expr, params_as_expr)
|
||||
|
||||
|
||||
@dataclass
|
||||
class LCC:
|
||||
"""
|
||||
@@ -239,7 +358,7 @@ class LC(ExprTestObj): # for List Comprehension node
|
||||
generators: list
|
||||
source: str = None
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
# first transform str into NameExprTestObj (ie EXPR)
|
||||
if isinstance(self.element, str):
|
||||
self.element = EXPR(self.element)
|
||||
@@ -254,13 +373,13 @@ class LC(ExprTestObj): # for List Comprehension node
|
||||
self.generators = comprehensions
|
||||
|
||||
# then transform into ListComprehensionNode
|
||||
element = self.element.get_expr_node(full_text_as_tokens)
|
||||
element = self.element.get_expr_node(full_text_as_tokens, default_expr_obj)
|
||||
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
|
||||
target = comp.target.get_expr_node(full_text_as_tokens, default_expr_obj)
|
||||
iterable = comp.iterable.get_expr_node(full_text_as_tokens, default_expr_obj)
|
||||
if_expr = comp.if_expr.get_expr_node(full_text_as_tokens, default_expr_obj) if comp.if_expr else None
|
||||
comprehensions.append(Comprehension(target, iterable, if_expr))
|
||||
nodes.extend([target, iterable, if_expr])
|
||||
|
||||
@@ -268,14 +387,14 @@ class LC(ExprTestObj): # for List Comprehension node
|
||||
return ListComprehensionNode(start, end, full_text_as_tokens[start: end + 1], element, comprehensions)
|
||||
|
||||
|
||||
class FN(ExprTestObj):
|
||||
class FNOld(ExprTestObj):
|
||||
"""
|
||||
Test class only
|
||||
It matches with FunctionNode but with less constraints
|
||||
It matches with FunctionNodeOld but with less constraints
|
||||
|
||||
Thereby,
|
||||
FN("first", "last", ["param1," ...]) can be compared to
|
||||
FunctionNode(NameExprNode("first"), NameExprNode("second"), [FunctionParameter(NamesNodes("param1"), NamesNodes(", ")])
|
||||
FNOld("first", "last", ["param1," ...]) can be compared to
|
||||
FunctionNodeOld(NameExprNode("first"), NameExprNode("second"), [FunctionParameter(NamesNodes("param1"), NamesNodes(", ")])
|
||||
|
||||
Note that FunctionParameter can easily be defined with a single string
|
||||
* "param" -> FunctionParameter(NameExprNode("param"), None)
|
||||
@@ -308,7 +427,7 @@ class FN(ExprTestObj):
|
||||
if id(self) == id(other):
|
||||
return True
|
||||
|
||||
if isinstance(other, FN):
|
||||
if isinstance(other, FNOld):
|
||||
return self.first == other.first and self.last == other.last and self.parameters == other.parameters
|
||||
|
||||
return False
|
||||
@@ -317,10 +436,10 @@ class FN(ExprTestObj):
|
||||
return hash((self.first, self.last, self.parameters))
|
||||
|
||||
def transform_real_obj(self, other, get_test_obj_delegate):
|
||||
if isinstance(other, FN):
|
||||
if isinstance(other, FNOld):
|
||||
return other
|
||||
|
||||
if isinstance(other, FunctionNode):
|
||||
if isinstance(other, FunctionNodeOld):
|
||||
params = []
|
||||
for self_parameter, other_parameter in zip(self.parameters, other.parameters):
|
||||
if isinstance(self_parameter[0], str):
|
||||
@@ -330,11 +449,11 @@ class FN(ExprTestObj):
|
||||
sep = other_parameter.separator.value if other_parameter.separator else None
|
||||
params.append((value, sep))
|
||||
|
||||
return FN(other.first.value, other.last.value, params)
|
||||
return FNOld(other.first.value, other.last.value, params)
|
||||
|
||||
raise Exception(f"Expecting FunctionNode but received {other=}")
|
||||
raise Exception(f"Expecting FunctionNodeOld but received {other=}")
|
||||
|
||||
def get_expr_node(self, full_text_as_tokens=None):
|
||||
def get_expr_node(self, full_text_as_tokens, default_expr_obj):
|
||||
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)
|
||||
@@ -345,7 +464,7 @@ class FN(ExprTestObj):
|
||||
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)
|
||||
param_as_expr_node = param_value.get_expr_node(full_text_as_tokens, default_expr_obj)
|
||||
|
||||
if sep:
|
||||
sep_tokens = Tokenizer(sep, yield_eof=False)
|
||||
@@ -358,7 +477,7 @@ class FN(ExprTestObj):
|
||||
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 FunctionNodeOld(start, end, full_text_as_tokens[start: end + 1], first, last, parameters)
|
||||
|
||||
|
||||
class HelperWithPos:
|
||||
@@ -697,12 +816,16 @@ class CIO:
|
||||
class RETVAL:
|
||||
"""
|
||||
Class helper for return value for parser result
|
||||
Note that it is designed for ParserResultConcept only
|
||||
Please create another RETVAL or rename this one if extra functionalities are needed
|
||||
"""
|
||||
|
||||
def __init__(self, source, who=None, parser=None):
|
||||
def __init__(self, text, source=None, who=None, parser=None, objects=None):
|
||||
self.text = text
|
||||
self.source = source
|
||||
self.who = who
|
||||
self.parser = parser
|
||||
self.objects = objects
|
||||
|
||||
def __eq__(self, other):
|
||||
if id(self) == id(other):
|
||||
@@ -711,15 +834,19 @@ class RETVAL:
|
||||
if not isinstance(other, RETVAL):
|
||||
return False
|
||||
|
||||
return (self.source == other.source and
|
||||
return (self.text == other.text and
|
||||
self.source == other.source and
|
||||
self.who == other.who and
|
||||
self.parser == other.parser)
|
||||
self.parser == other.parser and
|
||||
self.objects == other.objects)
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.source, self.who))
|
||||
return hash((self.text, self.source, self.who))
|
||||
|
||||
def __repr__(self):
|
||||
txt = f"RV(source='{self.source}'"
|
||||
txt = f"RV(text='{self.text}'"
|
||||
if self.source is not None:
|
||||
txt += f", source={self.source}"
|
||||
if self.who is not None:
|
||||
txt += f", who={self.who}"
|
||||
if self.parser is not None:
|
||||
@@ -738,14 +865,33 @@ class RETVAL:
|
||||
return other
|
||||
|
||||
if isinstance(other, ReturnValueConcept):
|
||||
|
||||
if not isinstance(other.body, ParserResultConcept):
|
||||
raise Exception(f"ParserResultConcept not found body={other.body}")
|
||||
|
||||
parser_result = other.body
|
||||
|
||||
if not isinstance(parser_result.body, PythonNode):
|
||||
raise Exception(f"PythonNode not found parser_result.body={parser_result.body}")
|
||||
python_node = parser_result.body
|
||||
|
||||
other_objects = None
|
||||
if self.objects:
|
||||
other_objects = {}
|
||||
|
||||
if len(self.objects) != len(python_node.objects):
|
||||
raise Exception(f"objects have different size {self.objects=}, other.objects={python_node.objects}")
|
||||
|
||||
try:
|
||||
for k, v in self.objects.items():
|
||||
other_objects[k] = get_test_obj_delegate(python_node.objects[k], v, get_test_obj_delegate)
|
||||
except KeyError as err:
|
||||
raise Exception(f"object {err} is expected but not found")
|
||||
|
||||
return RETVAL(parser_result.source,
|
||||
python_node.source if self.source is not None else None,
|
||||
other.who if self.who is not None else None,
|
||||
parser_result.parser if self.parser is not None else None)
|
||||
parser_result.parser if self.parser is not None else None,
|
||||
other_objects)
|
||||
|
||||
raise Exception(f"Expecting ReturnValueConcept but received {other=}")
|
||||
|
||||
@@ -758,9 +904,10 @@ class SCN(HelperWithPos):
|
||||
SCN == SourceCodeNode if source, start, end (start and end are not validated when None)
|
||||
"""
|
||||
|
||||
def __init__(self, source, start=None, end=None):
|
||||
def __init__(self, source, objects=None, start=None, end=None):
|
||||
super().__init__(start, end)
|
||||
self.source = source
|
||||
self.objects = objects
|
||||
|
||||
def __eq__(self, other):
|
||||
if id(self) == id(other):
|
||||
@@ -779,9 +926,10 @@ class SCN(HelperWithPos):
|
||||
if not isinstance(other, SCN):
|
||||
return False
|
||||
|
||||
return self.source == other.source and \
|
||||
self.start == other.start and \
|
||||
self.end == other.end
|
||||
return (self.source == other.source and
|
||||
self.objects == other.objects and
|
||||
self.start == other.start and
|
||||
self.end == other.end)
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.source, self.start, self.end))
|
||||
@@ -806,7 +954,18 @@ class SCN(HelperWithPos):
|
||||
return other
|
||||
|
||||
if isinstance(other, SourceCodeNode):
|
||||
other_objects = None
|
||||
if self.objects:
|
||||
other_objects = []
|
||||
if not other.python_node:
|
||||
Exception(f"no python node found in SourceCodeNode {other=}")
|
||||
if len(self.objects) != len(other.python_node.objects):
|
||||
Exception(f"objects have different size {self.objects=}, other.objects={other.python_node.objects}")
|
||||
for self_obj, other_obj in zip(self.objects, other.python_node.objects.values()):
|
||||
other_objects.append(to_compare_delegate(other_obj, self_obj, to_compare_delegate))
|
||||
|
||||
return SCN(other.source,
|
||||
other_objects,
|
||||
other.start if self.start is not None else None,
|
||||
other.end if self.end is not None else None)
|
||||
|
||||
@@ -1208,12 +1367,12 @@ comparison_type_mapping = {
|
||||
}
|
||||
|
||||
|
||||
def get_expr_node_from_test_node(full_text, test_node):
|
||||
def get_expr_node_from_test_node(full_text, test_node, default_expr_obj=EXPR):
|
||||
"""
|
||||
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))
|
||||
return test_node.get_expr_node(full_text_as_tokens)
|
||||
return test_node.get_expr_node(full_text_as_tokens, default_expr_obj)
|
||||
|
||||
|
||||
def _index(tokens, expr, index):
|
||||
@@ -1293,7 +1452,13 @@ def get_node(
|
||||
init_empty_body,
|
||||
exclude_body)
|
||||
|
||||
if isinstance(sub_expr, (DoNotResolve, ReturnValueConcept, RETVAL)):
|
||||
if isinstance(sub_expr, (DoNotResolve, ReturnValueConcept)):
|
||||
return sub_expr
|
||||
|
||||
if isinstance(sub_expr, RETVAL):
|
||||
if sub_expr.objects:
|
||||
sub_expr.objects = {k: get_node(concepts_map, expression_as_tokens, v, skip=skip)
|
||||
for k, v in sub_expr.objects.items()}
|
||||
return sub_expr
|
||||
|
||||
if isinstance(sub_expr, SCWC):
|
||||
@@ -1307,6 +1472,8 @@ def get_node(
|
||||
if isinstance(sub_expr, SCN):
|
||||
node = get_node(concepts_map, expression_as_tokens, sub_expr.source, skip=skip)
|
||||
sub_expr.fix_pos(node)
|
||||
if sub_expr.objects:
|
||||
sub_expr.objects = [get_node(concepts_map, expression_as_tokens, c, skip=skip) for c in sub_expr.objects]
|
||||
return sub_expr
|
||||
|
||||
if isinstance(sub_expr, RN):
|
||||
@@ -1315,7 +1482,16 @@ def get_node(
|
||||
sub_expr.end = start + length - 1
|
||||
return sub_expr
|
||||
|
||||
if isinstance(sub_expr, (CNC, CC, CN, CMV, CIO)):
|
||||
if isinstance(sub_expr, CIO):
|
||||
sub_expr.set_concept(concepts_map[sub_expr.concept_name])
|
||||
source = sub_expr.source or sub_expr.concept_name
|
||||
if source:
|
||||
node = get_node(concepts_map, expression_as_tokens, source)
|
||||
sub_expr.start = node.start
|
||||
sub_expr.end = node.end
|
||||
return sub_expr
|
||||
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import pytest
|
||||
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.ArithmericOperatorParser import ArithmeticOperatorParser
|
||||
from parsers.BaseExpressionParser import LeftPartNotFoundError, ParenthesisMismatchError, RightPartNotFoundError
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import ADD, DIV, EXPR, FDIV, FN, LT, MOD, MULT, POW, SEQ, SUB, VAR, \
|
||||
get_expr_node_from_test_node
|
||||
|
||||
|
||||
class TestArithmeticOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def init_parser(self, expr_parser=None, function_parser=None):
|
||||
sheerka, context = self.init_concepts()
|
||||
expr_parser = expr_parser or ExpressionParser(auto_compile=False)
|
||||
parser = ArithmeticOperatorParser(expr_parser=expr_parser, function_parser=function_parser)
|
||||
return sheerka, context, parser
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("one complicated expression", VAR("one complicated expression")),
|
||||
("a + b", ADD(VAR("a"), VAR("b"))),
|
||||
("a - b", SUB("a", "b")),
|
||||
("a * b", MULT("a", "b")),
|
||||
("a / b", DIV("a", "b")),
|
||||
("a // b", FDIV("a", "b")),
|
||||
("a % b", MOD("a", "b")),
|
||||
("a ** b", POW("a", "b")),
|
||||
("a + b * c", ADD("a", MULT("b", "c"))),
|
||||
("a * b + c", ADD(MULT("a", "b"), "c")),
|
||||
("a * b ** c", MULT("a", POW("b", "c"))),
|
||||
("a ** b * c", MULT(POW("a", "b"), "c")),
|
||||
("(a + b) * c", MULT(ADD("a", "b"), "c", source="(a + b) * c")),
|
||||
("a * (b + c)", MULT("a", ADD("b", "c"), source="a * (b + c)")),
|
||||
("func(a, b) * 3", MULT(FN(EXPR("func"), EXPR("a"), EXPR("b")), EXPR("3"))),
|
||||
("3 * func(a, b)", MULT(EXPR("3"), FN(EXPR("func"), EXPR("a"), EXPR("b")))),
|
||||
("a + b + c", ADD("a", "b", "c")),
|
||||
("a - b - c", SUB("a", "b", "c")),
|
||||
("a + b - c - d", SUB(ADD("a", "b"), "c", "d")),
|
||||
("a * b * c + d + e + f", ADD(MULT("a", "b", "c"), "d", "e", "f")),
|
||||
("a + b < c", ADD("a", LT("b", "c"))), # this is possible is function_parser is not set
|
||||
("foo x + y", SEQ(EXPR("foo "), ADD("x", "y"))), # to manager concept call
|
||||
("long name concept x + y + z", SEQ(EXPR("long name concept "), ADD("x", "y", "z"))),
|
||||
("long name concept x + y - z", SEQ(EXPR("long name concept "), SUB(ADD("x", "y"), "z"))),
|
||||
("long name concept x + y * z", SEQ(EXPR("long name concept "), ADD("x", MULT("y", "z")))),
|
||||
("long name concept x * y + z", SEQ(EXPR("long name concept "), ADD(MULT("x", "y"), "z"))),
|
||||
("(foo x) + y", ADD("foo x", "y", source="(foo x) + y")),
|
||||
("a + foo x + y", ADD("a", SEQ(EXPR("foo "), ADD("x", "y")))),
|
||||
("a + b * foo x * y + z", ADD("a", MULT("b", SEQ(EXPR("foo "), ADD(MULT("x", "y"), "z"))))),
|
||||
("a + foo b + c + bar e + f", ADD("a", SEQ(EXPR("foo "), ADD("b", "c", SEQ(EXPR("bar "), ADD("e", "f")))))),
|
||||
("a + foo x", ADD("a", "foo x")),
|
||||
("a + x y bar + b - c", ADD("a", SEQ(EXPR("x y "), SUB(ADD("bar", "b"), "c")))),
|
||||
("a + x + y bar + b - c", ADD("a", "x", SEQ(EXPR("y "), SUB(ADD("bar", "b"), "c")))),
|
||||
("a + x ? y : z + b - c", ADD("a", SEQ(EXPR("x ? y : "), SUB(ADD("z", "b"), "c")))),
|
||||
("twenty one + 3", SEQ(EXPR("twenty "), ADD("one", EXPR("3")))),
|
||||
("(foo x) * (bar y)", MULT("foo x", "bar y", source="(foo x) * (bar y)"))
|
||||
])
|
||||
def test_i_can_parse_input_expression(self, expression, expected):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
parser_input = ParserInput(expression).reset()
|
||||
parser_input.next_token()
|
||||
error_sink = ErrorSink()
|
||||
|
||||
expr = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert not error_sink.has_error
|
||||
|
||||
expected = get_expr_node_from_test_node(expression, expected, default_expr_obj=VAR)
|
||||
assert expr == expected
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("one complicated expression", VAR("one complicated expression")),
|
||||
("a + b", ADD(VAR("a"), VAR("b"))),
|
||||
("func(a, b) * 3", MULT(FN(EXPR("func"), EXPR("a"), EXPR("b")), EXPR("3"))),
|
||||
("3 * func(a, b)", MULT(EXPR("3"), FN(EXPR("func"), EXPR("a"), EXPR("b")))),
|
||||
("a + b < c", ADD("a", EXPR("b < c"))), # the comparison is no longer recognized
|
||||
("foo x + y", SEQ(EXPR("foo "), ADD("x", "y"))), # to manager concept call
|
||||
("long name concept x + y + z", SEQ(EXPR("long name concept "), ADD("x", "y", "z"))),
|
||||
("long name concept x + y - z", SEQ(EXPR("long name concept "), SUB(ADD("x", "y"), "z"))),
|
||||
("long name concept x + y * z", SEQ(EXPR("long name concept "), ADD("x", MULT("y", "z")))),
|
||||
("long name concept x * y + z", SEQ(EXPR("long name concept "), ADD(MULT("x", "y"), "z"))),
|
||||
("(foo x) + y", ADD("foo x", "y", source="(foo x) + y")),
|
||||
("a + foo x + y", ADD("a", SEQ(EXPR("foo "), ADD("x", "y")))),
|
||||
("a + b * foo x * y + z", ADD("a", MULT("b", SEQ(EXPR("foo "), ADD(MULT("x", "y"), "z"))))),
|
||||
("a + foo b + c + bar e + f", ADD("a", SEQ(EXPR("foo "), ADD("b", "c", SEQ(EXPR("bar "), ADD("e", "f")))))),
|
||||
("a + foo x", ADD("a", "foo x")),
|
||||
("a + x y bar + b - c", ADD("a", SEQ(EXPR("x y "), SUB(ADD("bar", "b"), "c")))),
|
||||
("a + x + y bar + b - c", ADD("a", "x", SEQ(EXPR("y "), SUB(ADD("bar", "b"), "c")))),
|
||||
("a + x ? y : z + b - c", ADD("a", SEQ(EXPR("x ? y : "), SUB(ADD("z", "b"), "c")))),
|
||||
("(foo x) * (bar y) + 2", ADD(MULT("foo x", "bar y", source="(foo x) * (bar y)"), EXPR("2"))),
|
||||
])
|
||||
def test_i_can_parse_input_when_function_parser_is_set(self, expression, expected):
|
||||
sheerka, context, parser = self.init_parser(function_parser=FunctionParser())
|
||||
|
||||
parser_input = ParserInput(expression).reset()
|
||||
parser_input.next_token()
|
||||
error_sink = ErrorSink()
|
||||
|
||||
expr = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert not error_sink.has_error
|
||||
|
||||
expected = get_expr_node_from_test_node(expression, expected, default_expr_obj=VAR)
|
||||
assert expr == expected
|
||||
|
||||
@pytest.mark.parametrize("expression, expected_error, expr_is_none", [
|
||||
("a +", [RightPartNotFoundError], False),
|
||||
("+ a", [LeftPartNotFoundError], True),
|
||||
("a ++ b", [RightPartNotFoundError], False),
|
||||
("(a + b", [ParenthesisMismatchError], False),
|
||||
# ("a + b)", [ParenthesisMismatchError], False), # only detected is strict is on
|
||||
|
||||
])
|
||||
def test_i_can_detect_errors(self, expression, expected_error, expr_is_none):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
parser_input = ParserInput(expression).reset()
|
||||
parser_input.next_token()
|
||||
error_sink = ErrorSink()
|
||||
|
||||
expr = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert error_sink.has_error
|
||||
assert (expr is None) == expr_is_none
|
||||
resolved_errors = [type(e) for e in error_sink.sink]
|
||||
assert resolved_errors == expected_error
|
||||
@@ -16,7 +16,7 @@ from parsers.BnfNodeParser import OrderedChoice, ConceptExpression, StrMatch, Se
|
||||
from parsers.DefConceptParser import DefConceptParser, NameNode, SyntaxErrorNode, CannotHandleParsingError
|
||||
from parsers.DefConceptParser import UnexpectedTokenParsingError, DefConceptNode
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.FunctionParserOld import FunctionParserOld
|
||||
from parsers.PythonParser import PythonParser, PythonNode
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, SCWC, compare_with_test_object, CIO
|
||||
@@ -77,7 +77,7 @@ def get_concept_part(part, use_expression=False):
|
||||
status=True,
|
||||
value=ParserResultConcept(
|
||||
source=part.source,
|
||||
parser=FunctionParser(),
|
||||
parser=FunctionParserOld(),
|
||||
value=nodes[0],
|
||||
try_parsed=nodes[0]))
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestDefRuleParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_i_cannot_parse_when_parser_input_is_initialized_from_token(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
res = parser.parse(context, ParserInput("", list(Tokenizer("init from tokens"))))
|
||||
res = parser.parse(context, ParserInput(None, list(Tokenizer("init from tokens"))))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.ExactConceptParser import ExactConceptParser
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept, DEFINITION_TYPE_DEF
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer
|
||||
from parsers.BaseExpressionParser import NameExprNode
|
||||
from parsers.ExactConceptParser import ExactConceptParser, NotSupportedElement
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import CMV, compare_with_test_object
|
||||
|
||||
@@ -189,6 +192,18 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
|
||||
assert concept_found.get_hints().need_validation
|
||||
assert not concept_found.get_hints().is_evaluated
|
||||
|
||||
def test_i_cannot_parse_when_expression_contains_expr_token(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
|
||||
tokens = list(Tokenizer("foo bar baz", yield_eof=False))
|
||||
tokens.append(Token(TokenKind.EXPR, NameExprNode(-1, -1, []), -1, -1, -1))
|
||||
|
||||
ret = ExactConceptParser().parse(context, ParserInput(None, tokens))
|
||||
|
||||
assert not ret.status
|
||||
assert sheerka.isinstance(ret.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
assert isinstance(ret.body.reason, NotSupportedElement)
|
||||
|
||||
def test_i_can_manage_unknown_concept(self):
|
||||
context = self.get_context(self.get_sheerka(singleton=True))
|
||||
source = "def concept hello" # this is not a concept by itself
|
||||
@@ -209,6 +224,22 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
|
||||
assert res.value.reason.body == source
|
||||
assert res.value.body == source
|
||||
|
||||
@pytest.mark.parametrize("text, concept_def", [
|
||||
("foo x", Concept("foo", definition="foo x", definition_type=DEFINITION_TYPE_DEF).def_var("x")),
|
||||
("foo", Concept("foo", definition="'foo' ('a'|'b')=x").def_var("x")),
|
||||
])
|
||||
def test_i_choose_concept_definition_over_concept_instance(self, text, concept_def):
|
||||
sheerka, context, foo = self.init_concepts(concept_def, create_new=True)
|
||||
|
||||
res = ExactConceptParser().parse(context, ParserInput(text))
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
concept_found = res[0].body.body
|
||||
assert concept_found.get_hints().is_evaluated
|
||||
assert not concept_found.get_hints().is_instance
|
||||
|
||||
# def test_i_can_detect_concept_from_tokens(self):
|
||||
# context = self.get_context(self.get_sheerka(singleton=True))
|
||||
# concept = get_concept("hello world", [])
|
||||
|
||||
@@ -3,12 +3,12 @@ import pytest
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from parsers.BaseExpressionParser import VariableNode, ComparisonNode, ExprNode
|
||||
from parsers.BaseParser import ErrorSink, BaseParser
|
||||
from parsers.BaseExpressionParser import ComparisonNode, SequenceNode, VariableNode
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import get_expr_node_from_test_node, VAR, EXPR, FN, AND, NOT, OR, GT, GTE, LT, LTE, EQ, \
|
||||
NEQ, IN, NIN
|
||||
from tests.parsers.parsers_utils import ADD, AND, EQ, EXPR, FN, GT, GTE, IN, LT, LTE, L_EXPR, MULT, NEQ, NIN, NOT, OR, \
|
||||
VAR, get_expr_node_from_test_node
|
||||
|
||||
|
||||
class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
@@ -32,7 +32,7 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("var1 + var2", EXPR("var1 + var2")),
|
||||
("var1 + var2", ADD(VAR("var1"), VAR("var2"))),
|
||||
("variable", VAR("variable")),
|
||||
("var.attr", VAR("var.attr")),
|
||||
("var1 and var2", AND(VAR("var1"), VAR("var2"))),
|
||||
@@ -45,18 +45,22 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
("var1 = var2", EQ(VAR("var1"), VAR("var2"))),
|
||||
("var1 == var2", EQ(VAR("var1"), VAR("var2"))),
|
||||
("var1 != var2", NEQ(VAR("var1"), VAR("var2"))),
|
||||
("var1 in (var2.attr2, var3.attr3)", IN(VAR("var1"), EXPR("var2.attr2, var3.attr3"))),
|
||||
("var1 not in (var2.attr2, var3.attr3)", NIN(VAR("var1"), EXPR("var2.attr2, var3.attr3"))),
|
||||
("var1 in (var2.attr2, var3.attr3)", IN(VAR("var1"), L_EXPR("(", ")", "var2.attr2", "var3.attr3"))),
|
||||
("var1 not in (var2.attr2, var3.attr3)", NIN(VAR("var1"), L_EXPR("(", ")", "var2.attr2", "var3.attr3"))),
|
||||
("var1 < var2 and var3 > var4", AND(LT(VAR("var1"), VAR("var2")), GT(VAR("var3"), VAR("var4")))),
|
||||
("func1(one, 1 + 2, func2(3))", FN("func1(", (")", 1), [(VAR("one"), ", "),
|
||||
(EXPR("1 + 2"), ", "),
|
||||
FN("func2(", ")", [EXPR("3")])])),
|
||||
("func(var.attr)", FN("func(", ")", [VAR("var.attr")])),
|
||||
("func(var1.attr1 and var2.attr2)", FN("func(", ")", [AND(VAR("var1.attr1"), VAR("var2.attr2"))])),
|
||||
("func(var1.attr1 > var2.attr2)", FN("func(", ")", [GT(VAR("var1.attr1"), VAR("var2.attr2"))])),
|
||||
("func1(var1) and func2(var2)", AND(FN("func1(", ")", [VAR("var1")]), FN("func2(", (")", 1), [VAR("var2")]))),
|
||||
("var1 < var2 + var3", LT(VAR("var1"), ADD(VAR("var2"), VAR("var3")))),
|
||||
("func1(one, 1 + 2, func2(3))", FN("func1", "one", "1 + 2", "func2(3)")),
|
||||
("func(var.attr)", FN("func", "var.attr")),
|
||||
("func(var1.attr1 and var2.attr2)", FN("func", "var1.attr1 and var2.attr2")),
|
||||
("func(var1.attr1 > var2.attr2)", FN("func", "var1.attr1 > var2.attr2")),
|
||||
("__ret", VAR("__ret")),
|
||||
# ("func1().func2()", [])
|
||||
("f(x) is another b(y)", EXPR("f(x) is another b(y)")),
|
||||
("var1 + var2 * var3", ADD(VAR("var1"), MULT(VAR("var2"), VAR("var3")))),
|
||||
("(a) + (b)", ADD(VAR("a"), VAR("b"), source="(a) + (b)")),
|
||||
("(a + b) < (c + d)", LT(ADD(VAR("a"), VAR("b")), ADD(VAR("c"), VAR("d")), source="(a + b) < (c + d)")),
|
||||
("(a, b, c)", L_EXPR("(", ")", VAR("a"), VAR("b"), VAR("c"))),
|
||||
("[a, b, c]", L_EXPR("[", "]", VAR("a"), VAR("b"), VAR("c"))),
|
||||
("{a, b, c}", L_EXPR("{", "}", VAR("a"), VAR("b"), VAR("c"))),
|
||||
])
|
||||
def test_i_can_parse_input(self, expression, expected):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
@@ -90,10 +94,11 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert not error_sink.has_error
|
||||
assert parsed == get_expr_node_from_test_node(expression, EXPR("var1 + var2"))
|
||||
assert parsed == get_expr_node_from_test_node(expression, ADD("var1", "var2"), default_expr_obj=VAR)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("ret.status in ('a', 1 , func())", "new_var in ('a', 1 , func())"),
|
||||
("ret.status in ['a', 1 , func()]", "new_var in ['a', 1 , func()]"),
|
||||
("ret.status not in ('a', 1 , func())", "new_var not in ('a', 1 , func())"),
|
||||
("ret.status == 10", "new_var == 10"),
|
||||
("ret.status == 'a'", "new_var == 'a'"),
|
||||
@@ -114,14 +119,12 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
|
||||
|
||||
def test_i_can_compile(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
def test_i_can_clone(self):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source("foo x + 1")
|
||||
expr = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
text = ParserInput("a > b and c < d")
|
||||
res = parser.parse(context, text)
|
||||
assert isinstance(expr, SequenceNode)
|
||||
|
||||
assert res.who == BaseParser.PREFIX + ExpressionParser.NAME
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(res.body.body, ExprNode)
|
||||
assert res.body.body.compiled is not None
|
||||
clone = expr.clone()
|
||||
|
||||
assert expr == clone
|
||||
|
||||
@@ -3,13 +3,11 @@ import pytest
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.BaseParser import ErrorSink, UnexpectedTokenParsingError
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.PythonParser import PythonErrorNode
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, SCN, SCWC, CN, UTN, CNC, RN, FN, get_test_obj, \
|
||||
get_expr_node_from_test_node
|
||||
from tests.parsers.parsers_utils import FN, SCN, SEQ, compute_expected_array, \
|
||||
get_expr_node_from_test_node, get_test_obj
|
||||
|
||||
cmap = {
|
||||
"one": Concept("one"),
|
||||
@@ -24,7 +22,7 @@ class TestFunctionParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
init_test_helper = cls().init_test(cache_only=False, ontology="#TestFunctionParser#")
|
||||
init_test_helper = cls().init_test(cache_only=False, ontology="#TestFunctionParserOld#")
|
||||
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
|
||||
for i, concept_name in enumerate(cmap):
|
||||
cmap[concept_name] = updated[i]
|
||||
@@ -32,7 +30,7 @@ class TestFunctionParser(TestUsingMemoryBasedSheerka):
|
||||
cls.shared_ontology = sheerka.get_ontology(context)
|
||||
sheerka.pop_ontology(context)
|
||||
|
||||
def init_parser(self, my_concepts_map=None, **kwargs):
|
||||
def init_parser(self, my_concepts_map=None, strict=True, **kwargs):
|
||||
if my_concepts_map is None:
|
||||
sheerka, context = self.init_test().unpack()
|
||||
sheerka.add_ontology(context, self.shared_ontology)
|
||||
@@ -41,11 +39,12 @@ class TestFunctionParser(TestUsingMemoryBasedSheerka):
|
||||
for i, pair in enumerate(my_concepts_map):
|
||||
my_concepts_map[pair] = updated[i]
|
||||
|
||||
parser = FunctionParser()
|
||||
expr_parser = kwargs.get("expr_parser", None)
|
||||
parser = FunctionParser(strict, expr_parser=expr_parser)
|
||||
return sheerka, context, parser
|
||||
|
||||
def init_parser_with_source(self, source):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
def init_parser_with_source(self, source, strict=True):
|
||||
sheerka, context, parser = self.init_parser(None, strict)
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(source)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
@@ -70,180 +69,146 @@ class TestFunctionParser(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("func()", FN("func(", ")", [])),
|
||||
("concept(one)", FN("concept(", ")", ["one"])),
|
||||
("func(one)", FN("func(", ")", ["one"])),
|
||||
("func(a long two, 'three', ;:$*)", FN("func(", ")", ["a long two, ", "'three', ", ";:$*"])),
|
||||
("func(func1(one), two, func2(func3(), func4(three)))", FN("func(", (")", 4), [
|
||||
(FN("func1(", ")", ["one"]), ", "),
|
||||
"two, ",
|
||||
(FN("func2(", (")", 3), [
|
||||
(FN("func3(", (")", 1), []), ", "),
|
||||
(FN("func4(", (")", 2), ["three"]), None),
|
||||
]), None)
|
||||
])),
|
||||
("func(r:|1:)", FN("func(", ")", ["r:|1:"]))
|
||||
("func()", FN("func")),
|
||||
("concept(one)", FN("concept", "one")),
|
||||
("func(one)", FN("func", "one")),
|
||||
("func(a long two, 'three', ;:$*)", FN("func", "a long two", "'three'", ";:$*")),
|
||||
("func(func1(one), two, func2(func3(), func4(three)))",
|
||||
FN("func", "func1(one)", "two", "func2(func3(), func4(three))")),
|
||||
("func(r:|1:)", FN("func", "r:|1:")),
|
||||
("func(bar fn(x))", FN("func", "bar fn(x)")),
|
||||
("func([one, two])", FN("func", "[one, two]")),
|
||||
("func((one, two))", FN("func", "(one, two)")),
|
||||
("func({one, two})", FN("func", "{one, two}")),
|
||||
])
|
||||
def test_i_can_parse_function(self, expression, expected):
|
||||
def test_i_can_parse_input_function_when_expr_parser_is_none(self, expression, expected):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert not error_sink.has_error
|
||||
assert parsed == expected
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("func()", SCN("func()")),
|
||||
(" func()", SCN("func()")),
|
||||
("func(one)", SCWC("func(", ")", CN("one"))),
|
||||
("func(one, unknown, two)", SCWC("func(", ")", CN("one"), ", ", UTN("unknown"), (", ", 1), CN("two"))),
|
||||
("func(one, twenty two)", SCWC("func(", ")", "one", ", ", CN("twenties", "twenty two"))),
|
||||
("func(one plus two, three)", SCWC("func(", ")", CNC("plus", a="one", b="two"), ", ", UTN("three"))),
|
||||
("func(func1(one), two)", SCWC("func(", (")", 1), SCWC("func1(", ")", "one"), ", ", "two"))
|
||||
parser.strict = False
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
assert not error_sink.has_error
|
||||
assert parsed == expected
|
||||
|
||||
def test_i_can_parse_input_when_prefixed_depending_on_strict_mode(self):
|
||||
expression = "bar fn(x)"
|
||||
expected = SEQ("bar ", FN("fn", "x"))
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
assert error_sink.has_error
|
||||
assert parsed is None
|
||||
assert isinstance(error_sink.sink[0], UnexpectedTokenParsingError)
|
||||
|
||||
parser.strict = False
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
assert not error_sink.has_error
|
||||
assert parsed == expected
|
||||
|
||||
def test_i_can_parse_input_when_suffixed_depending_on_strict_mode(self):
|
||||
expression = "fn(x) bar"
|
||||
expected = SEQ(FN("fn", "x"), " bar")
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
assert error_sink.has_error
|
||||
assert parsed is None
|
||||
assert isinstance(error_sink.sink[0], UnexpectedTokenParsingError)
|
||||
|
||||
parser.strict = False
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
assert not error_sink.has_error
|
||||
assert parsed == expected
|
||||
|
||||
def test_i_can_parse_input_when_infixed_and_suffixed(self):
|
||||
expression = "foo fn(x) bar"
|
||||
expected = SEQ("foo ", FN("fn", "x"), " bar")
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
parser.strict = False
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
assert not error_sink.has_error
|
||||
assert parsed == expected
|
||||
|
||||
@pytest.mark.parametrize("text, expected, objects", [
|
||||
("func()", SCN("func()"), {}),
|
||||
(" func()", SCN("func()"), {}),
|
||||
("func(one)", SCN("func(one)"), {"__o_00__": "one"}),
|
||||
("func(one, unknown, two)", SCN("func(one, unknown, two)"), {"__o_00__": "one", "__o_01__": "two"}),
|
||||
("func(one, twenty two)", SCN("func(one, twenty two)"), {"__o_00__": "one", "__o_01__": "twenties"}),
|
||||
("func(one plus two, three)", SCN("func(one plus two, three)"), {"__o_00__": "plus"}),
|
||||
("func(func1(one), two)", SCN("func(func1(one), two)"), {"__o_00__": "one", "__o_01__": "two"}),
|
||||
])
|
||||
def test_i_can_parse(self, text, expected):
|
||||
def test_i_can_parse(self, text, expected, objects):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
resolved_expected = compute_expected_array(cmap, text, [expected])[0]
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
parser_result = res.body
|
||||
expression = res.body.body
|
||||
node = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
transformed_expression = get_test_obj(expression, resolved_expected)
|
||||
transformed_expression = get_test_obj(node, resolved_expected)
|
||||
assert transformed_expression == resolved_expected
|
||||
assert expression.python_node is not None
|
||||
assert expression.return_value is not None
|
||||
assert node.python_node is not None
|
||||
assert node.return_value is not None
|
||||
|
||||
def test_i_can_parse_when_multiple_results_when_requested(self):
|
||||
# the previous output was
|
||||
# [
|
||||
# SCWC("func(", ")", "one", ", ", "twenty ", "two"),
|
||||
# SCWC("func(", ")", "one", ", ", CN("twenties", "twenty two"))
|
||||
# ]
|
||||
# But the first one is now filtered out, as it's not a valid python function call
|
||||
sheerka, context, parser = self.init_parser()
|
||||
parser.longest_concepts_only = False
|
||||
text = "func(one, twenty two)"
|
||||
expected = [SCWC("func(", ")", "one", ", ", CN("twenties", "twenty two"))]
|
||||
resolved_expected = compute_expected_array(cmap, text, expected)
|
||||
# compare objects
|
||||
actual_objects = {k: v.id for k, v in node.python_node.objects.items()}
|
||||
expected_objects = {k: cmap[v].id for k, v in objects.items()}
|
||||
assert actual_objects == expected_objects
|
||||
|
||||
results = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert len(results) == 2
|
||||
|
||||
res = results[0]
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||
assert len(res.body.body) == 1
|
||||
assert (res.body.body[0], PythonErrorNode)
|
||||
|
||||
res = results[1]
|
||||
parser_result = res.body
|
||||
expressions = res.body.body
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
transformed_expressions = get_test_obj(expressions, resolved_expected[0])
|
||||
assert transformed_expressions == resolved_expected[0]
|
||||
|
||||
def test_i_can_parse_when_the_parameter_is_not_a_concept(self):
|
||||
"""
|
||||
It's not a concept, but it can be a valid short term memory object
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser()
|
||||
text = "func(unknown_concept)"
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
expected = [SCWC("func(", ")", "unknown_concept")]
|
||||
resolved_expected = compute_expected_array(cmap, text, expected)
|
||||
|
||||
assert res.status
|
||||
parsed = res.body.body
|
||||
transformed_parsed = get_test_obj([parsed], resolved_expected)
|
||||
assert transformed_parsed == resolved_expected
|
||||
|
||||
def test_i_can_parse_when_the_concept_is_not_found(self):
|
||||
"""
|
||||
We do not check yet if it's a valid concept
|
||||
If you find a cheap way to do so, simply remove this test
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser()
|
||||
text = "func(c:|xxx:)"
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert res.status
|
||||
|
||||
def test_i_can_parse_when_rules(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
text = "func(r:|1:)"
|
||||
expected = SCWC("func(", ")", RN("1"))
|
||||
resolved_expected = compute_expected_array(cmap, text, [expected])[0]
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
parser_result = res.body
|
||||
expression = res.body.body
|
||||
transformed_expression = get_test_obj(expression, resolved_expected)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
assert transformed_expression == resolved_expected
|
||||
assert expression.python_node is not None
|
||||
assert expression.return_value is not None
|
||||
|
||||
def test_i_can_parse_when_the_parameter_is_a_dynamic_concept(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "func(ones)"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert res.status
|
||||
assert isinstance(res.body.body, SourceCodeWithConceptNode)
|
||||
assert res.body.body.python_node.source == 'func(__C__ones__1001___PLURAL__C__)'
|
||||
assert "__C__ones__1001___PLURAL__C__" in res.body.body.python_node.objects
|
||||
|
||||
@pytest.mark.parametrize("text, expected_error_type", [
|
||||
("one", BuiltinConcepts.NOT_FOR_ME), # no function found
|
||||
("$*!", BuiltinConcepts.NOT_FOR_ME), # no function found
|
||||
("func(", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
("func(one", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
("func(one, two, ", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
("func(one) and func(two)", BuiltinConcepts.ERROR), # to many function
|
||||
("one func(one)", BuiltinConcepts.NOT_FOR_ME), # function not found ! (as it is not the first)
|
||||
("func(a=b, c)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
|
||||
("func(one two)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
|
||||
])
|
||||
def test_i_cannot_parse(self, text, expected_error_type):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, expected_error_type)
|
||||
|
||||
@pytest.mark.parametrize("sequence, expected", [
|
||||
(None, None),
|
||||
([["a"]], [["a"]]),
|
||||
([["a"], ["b", "c"]], [["a"]]),
|
||||
([["b", "c"], ["a"]], [["a"]]),
|
||||
([["b", "c"], ["a"], ["d", "e"], ["f"]], [["a"], ["f"]]),
|
||||
])
|
||||
def test_i_can_get_the_longest_concept_sequence(self, sequence, expected):
|
||||
assert FunctionParser.get_longest_concepts(sequence) == expected
|
||||
|
||||
def test_concepts_found_are_fully_initialized(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput("func(one plus three)"))
|
||||
concept = res.body.body.nodes[0].concept
|
||||
|
||||
assert res.status
|
||||
assert isinstance(concept.get_compiled()["a"], Concept)
|
||||
|
||||
# three is not recognized,
|
||||
# so it will be transformed into list of ReturnValueConcept that indicate how to recognized it
|
||||
assert isinstance(concept.get_compiled()["b"], list)
|
||||
for item in concept.get_compiled()["b"]:
|
||||
assert sheerka.isinstance(item, BuiltinConcepts.RETURN_VALUE)
|
||||
# @pytest.mark.parametrize("text, expected_error_type", [
|
||||
# ("one", BuiltinConcepts.NOT_FOR_ME), # no function found
|
||||
# ("$*!", BuiltinConcepts.NOT_FOR_ME), # no function found
|
||||
# ("func(", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
# ("func(one", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
# ("func(one, two, ", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
# ("func(one) and func(two)", BuiltinConcepts.ERROR), # to many function
|
||||
# ("one func(one)", BuiltinConcepts.NOT_FOR_ME), # function not found ! (as it is not the first)
|
||||
# ("func(a=b, c)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
|
||||
# ("func(one two)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
|
||||
# ])
|
||||
# def test_i_cannot_parse(self, text, expected_error_type):
|
||||
# sheerka, context, parser = self.init_parser()
|
||||
#
|
||||
# res = parser.parse(context, ParserInput(text))
|
||||
#
|
||||
# assert not res.status
|
||||
# assert sheerka.isinstance(res.body, expected_error_type)
|
||||
#
|
||||
# @pytest.mark.parametrize("sequence, expected", [
|
||||
# (None, None),
|
||||
# ([["a"]], [["a"]]),
|
||||
# ([["a"], ["b", "c"]], [["a"]]),
|
||||
# ([["b", "c"], ["a"]], [["a"]]),
|
||||
# ([["b", "c"], ["a"], ["d", "e"], ["f"]], [["a"], ["f"]]),
|
||||
# ])
|
||||
# def test_i_can_get_the_longest_concept_sequence(self, sequence, expected):
|
||||
# assert FunctionParserOld.get_longest_concepts(sequence) == expected
|
||||
#
|
||||
# def test_concepts_found_are_fully_initialized(self):
|
||||
# sheerka, context, parser = self.init_parser()
|
||||
#
|
||||
# res = parser.parse(context, ParserInput("func(one plus three)"))
|
||||
# concept = res.body.body.nodes[0].concept
|
||||
#
|
||||
# assert res.status
|
||||
# assert isinstance(concept.get_compiled()["a"], Concept)
|
||||
#
|
||||
# # three is not recognized,
|
||||
# # so it will be transformed into list of ReturnValueConcept that indicate how to recognized it
|
||||
# assert isinstance(concept.get_compiled()["b"], list)
|
||||
# for item in concept.get_compiled()["b"]:
|
||||
# assert sheerka.isinstance(item, BuiltinConcepts.RETURN_VALUE)
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.FunctionParserOld import FunctionParserOld
|
||||
from parsers.PythonParser import PythonErrorNode
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, SCN, SCWC, CN, UTN, CNC, RN, FNOld, get_test_obj, \
|
||||
get_expr_node_from_test_node
|
||||
|
||||
cmap = {
|
||||
"one": Concept("one"),
|
||||
"two": Concept("two"),
|
||||
"twenties": Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"),
|
||||
"plus": Concept("a plus b").def_var("a").def_var("b"),
|
||||
}
|
||||
|
||||
|
||||
class TestFunctionParserOld(TestUsingMemoryBasedSheerka):
|
||||
shared_ontology = None
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
init_test_helper = cls().init_test(cache_only=False, ontology="#TestFunctionParserOld#")
|
||||
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
|
||||
for i, concept_name in enumerate(cmap):
|
||||
cmap[concept_name] = updated[i]
|
||||
|
||||
cls.shared_ontology = sheerka.get_ontology(context)
|
||||
sheerka.pop_ontology(context)
|
||||
|
||||
def init_parser(self, my_concepts_map=None, **kwargs):
|
||||
if my_concepts_map is None:
|
||||
sheerka, context = self.init_test().unpack()
|
||||
sheerka.add_ontology(context, self.shared_ontology)
|
||||
else:
|
||||
sheerka, context, *updated = self.init_test().with_concepts(*my_concepts_map.values(), **kwargs).unpack()
|
||||
for i, pair in enumerate(my_concepts_map):
|
||||
my_concepts_map[pair] = updated[i]
|
||||
|
||||
parser = FunctionParserOld()
|
||||
return sheerka, context, parser
|
||||
|
||||
def init_parser_with_source(self, source):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(source)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
return sheerka, context, parser, parser_input, error_sink
|
||||
|
||||
def test_i_can_detect_empty_expression(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
res = parser.parse(context, ParserInput(""))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
|
||||
|
||||
def test_input_must_be_a_parser_input(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
parser.parse(context, "not a parser input") is None
|
||||
|
||||
def test_i_cannot_parse_when_not_a_function(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
res = parser.parse(context, ParserInput("not a function"))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("func()", FNOld("func(", ")", [])),
|
||||
("concept(one)", FNOld("concept(", ")", ["one"])),
|
||||
("func(one)", FNOld("func(", ")", ["one"])),
|
||||
("func(a long two, 'three', ;:$*)", FNOld("func(", ")", ["a long two, ", "'three', ", ";:$*"])),
|
||||
("func(func1(one), two, func2(func3(), func4(three)))", FNOld("func(", (")", 4), [
|
||||
(FNOld("func1(", ")", ["one"]), ", "),
|
||||
"two, ",
|
||||
(FNOld("func2(", (")", 3), [
|
||||
(FNOld("func3(", (")", 1), []), ", "),
|
||||
(FNOld("func4(", (")", 2), ["three"]), None),
|
||||
]), None)
|
||||
])),
|
||||
("func(r:|1:)", FNOld("func(", ")", ["r:|1:"]))
|
||||
])
|
||||
def test_i_can_parse_function(self, expression, expected):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert not error_sink.has_error
|
||||
assert parsed == expected
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("func()", SCN("func()")),
|
||||
(" func()", SCN("func()")),
|
||||
("func(one)", SCWC("func(", ")", CN("one"))),
|
||||
("func(one, unknown, two)", SCWC("func(", ")", CN("one"), ", ", UTN("unknown"), (", ", 1), CN("two"))),
|
||||
("func(one, twenty two)", SCWC("func(", ")", "one", ", ", CN("twenties", "twenty two"))),
|
||||
("func(one plus two, three)", SCWC("func(", ")", CNC("plus", a="one", b="two"), ", ", UTN("three"))),
|
||||
("func(func1(one), two)", SCWC("func(", (")", 1), SCWC("func1(", ")", "one"), ", ", "two"))
|
||||
])
|
||||
def test_i_can_parse(self, text, expected):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
resolved_expected = compute_expected_array(cmap, text, [expected])[0]
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
parser_result = res.body
|
||||
expression = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
transformed_expression = get_test_obj(expression, resolved_expected)
|
||||
assert transformed_expression == resolved_expected
|
||||
assert expression.python_node is not None
|
||||
assert expression.return_value is not None
|
||||
|
||||
def test_i_can_parse_when_multiple_results_when_requested(self):
|
||||
# the previous output was
|
||||
# [
|
||||
# SCWC("func(", ")", "one", ", ", "twenty ", "two"),
|
||||
# SCWC("func(", ")", "one", ", ", CN("twenties", "twenty two"))
|
||||
# ]
|
||||
# But the first one is now filtered out, as it's not a valid python function call
|
||||
sheerka, context, parser = self.init_parser()
|
||||
parser.longest_concepts_only = False
|
||||
text = "func(one, twenty two)"
|
||||
expected = [SCWC("func(", ")", "one", ", ", CN("twenties", "twenty two"))]
|
||||
resolved_expected = compute_expected_array(cmap, text, expected)
|
||||
|
||||
results = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert len(results) == 2
|
||||
|
||||
res = results[0]
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||
assert len(res.body.body) == 1
|
||||
assert (res.body.body[0], PythonErrorNode)
|
||||
|
||||
res = results[1]
|
||||
parser_result = res.body
|
||||
expressions = res.body.body
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
transformed_expressions = get_test_obj(expressions, resolved_expected[0])
|
||||
assert transformed_expressions == resolved_expected[0]
|
||||
|
||||
def test_i_can_parse_when_the_parameter_is_not_a_concept(self):
|
||||
"""
|
||||
It's not a concept, but it can be a valid short term memory object
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser()
|
||||
text = "func(unknown_concept)"
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
expected = [SCWC("func(", ")", "unknown_concept")]
|
||||
resolved_expected = compute_expected_array(cmap, text, expected)
|
||||
|
||||
assert res.status
|
||||
parsed = res.body.body
|
||||
transformed_parsed = get_test_obj([parsed], resolved_expected)
|
||||
assert transformed_parsed == resolved_expected
|
||||
|
||||
def test_i_can_parse_when_the_concept_is_not_found(self):
|
||||
"""
|
||||
We do not check yet if it's a valid concept
|
||||
If you find a cheap way to do so, simply remove this test
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser()
|
||||
text = "func(c:|xxx:)"
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert res.status
|
||||
|
||||
def test_i_can_parse_when_rules(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
text = "func(r:|1:)"
|
||||
expected = SCWC("func(", ")", RN("1"))
|
||||
resolved_expected = compute_expected_array(cmap, text, [expected])[0]
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
parser_result = res.body
|
||||
expression = res.body.body
|
||||
transformed_expression = get_test_obj(expression, resolved_expected)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
assert transformed_expression == resolved_expected
|
||||
assert expression.python_node is not None
|
||||
assert expression.return_value is not None
|
||||
|
||||
def test_i_can_parse_when_the_parameter_is_a_dynamic_concept(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "func(ones)"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert res.status
|
||||
assert isinstance(res.body.body, SourceCodeWithConceptNode)
|
||||
assert res.body.body.python_node.source == 'func(__C__ones__1001___PLURAL__C__)'
|
||||
assert "__C__ones__1001___PLURAL__C__" in res.body.body.python_node.objects
|
||||
|
||||
@pytest.mark.parametrize("text, expected_error_type", [
|
||||
("one", BuiltinConcepts.NOT_FOR_ME), # no function found
|
||||
("$*!", BuiltinConcepts.NOT_FOR_ME), # no function found
|
||||
("func(", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
("func(one", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
("func(one, two, ", BuiltinConcepts.ERROR), # function found, but incomplete
|
||||
("func(one) and func(two)", BuiltinConcepts.ERROR), # to many function
|
||||
("one func(one)", BuiltinConcepts.NOT_FOR_ME), # function not found ! (as it is not the first)
|
||||
("func(a=b, c)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
|
||||
("func(one two)", BuiltinConcepts.ERROR), # function found, but cannot be parsed
|
||||
])
|
||||
def test_i_cannot_parse(self, text, expected_error_type):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, expected_error_type)
|
||||
|
||||
@pytest.mark.parametrize("sequence, expected", [
|
||||
(None, None),
|
||||
([["a"]], [["a"]]),
|
||||
([["a"], ["b", "c"]], [["a"]]),
|
||||
([["b", "c"], ["a"]], [["a"]]),
|
||||
([["b", "c"], ["a"], ["d", "e"], ["f"]], [["a"], ["f"]]),
|
||||
])
|
||||
def test_i_can_get_the_longest_concept_sequence(self, sequence, expected):
|
||||
assert FunctionParserOld.get_longest_concepts(sequence) == expected
|
||||
|
||||
def test_concepts_found_are_fully_initialized(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput("func(one plus three)"))
|
||||
concept = res.body.body.nodes[0].concept
|
||||
|
||||
assert res.status
|
||||
assert isinstance(concept.get_compiled()["a"], Concept)
|
||||
|
||||
# three is not recognized,
|
||||
# so it will be transformed into list of ReturnValueConcept that indicate how to recognized it
|
||||
assert isinstance(concept.get_compiled()["b"], list)
|
||||
for item in concept.get_compiled()["b"]:
|
||||
assert sheerka.isinstance(item, BuiltinConcepts.RETURN_VALUE)
|
||||
@@ -58,10 +58,20 @@ class TestListComprehensionParser(TestUsingMemoryBasedSheerka):
|
||||
error = res.body.body[0]
|
||||
assert isinstance(error, UnexpectedTokenParsingError)
|
||||
|
||||
def test_i_can_parse_a_simple_expression(self):
|
||||
@pytest.mark.parametrize("expression, expected_generator", [
|
||||
("[x for x in ['a', 'b'] if x == 'a']", [(("x", 1), "['a', 'b']", "x == 'a'")]),
|
||||
("[x for x in ('a', 'b') if x == 'a']", [(("x", 1), "('a', 'b')", "x == 'a'")]),
|
||||
("[x for x in {'a', 'b'} if x == 'a']", [(("x", 1), "{'a', 'b'}", "x == 'a'")]),
|
||||
("(x for x in ['a', 'b'] if x == 'a')", [(("x", 1), "['a', 'b']", "x == 'a'")]),
|
||||
("(x for x in ('a', 'b') if x == 'a')", [(("x", 1), "('a', 'b')", "x == 'a'")]),
|
||||
("(x for x in {'a', 'b'} if x == 'a')", [(("x", 1), "{'a', 'b'}", "x == 'a'")]),
|
||||
("{x for x in ['a', 'b'] if x == 'a'}", [(("x", 1), "['a', 'b']", "x == 'a'")]),
|
||||
("{x for x in ('a', 'b') if x == 'a'}", [(("x", 1), "('a', 'b')", "x == 'a'")]),
|
||||
("{x for x in {'a', 'b'} if x == 'a'}", [(("x", 1), "{'a', 'b'}", "x == 'a'")]),
|
||||
])
|
||||
def test_i_can_parse_a_simple_expression(self, expression, expected_generator):
|
||||
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
|
||||
@@ -69,7 +79,7 @@ class TestListComprehensionParser(TestUsingMemoryBasedSheerka):
|
||||
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)
|
||||
expected = LC(L_EXPR(None, None, "x", source="x "), expected_generator, source=expression)
|
||||
to_compare_to = get_expr_node_from_test_node(expression, expected)
|
||||
assert lc_node == to_compare_to
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ or_token = Token(TokenKind.IDENTIFIER, "or", -1, -1, -1)
|
||||
|
||||
|
||||
class TestListParser(TestUsingMemoryBasedSheerka):
|
||||
def init_parser(self, sep=None):
|
||||
def init_parser(self, strict=True, sep=None):
|
||||
sheerka, context = self.init_concepts()
|
||||
parser = ListParser(sep)
|
||||
parser = ListParser(strict, sep)
|
||||
return sheerka, context, parser
|
||||
|
||||
@pytest.mark.parametrize("expression, sep, expected", [
|
||||
@@ -26,12 +26,13 @@ class TestListParser(TestUsingMemoryBasedSheerka):
|
||||
("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("(", ")", "x", "y", "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")),
|
||||
("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)
|
||||
sheerka, context, parser = self.init_parser(strict=False, sep=sep)
|
||||
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
@@ -42,6 +43,24 @@ class TestListParser(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert expressions == expected
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("()", L_EXPR("(", ")")),
|
||||
("(a, b)", L_EXPR("(", ")", EXPR("a"), EXPR("b"))),
|
||||
("a, b", None),
|
||||
])
|
||||
def test_parenthesis_are_mandatory_when_strict(self, expression, expected):
|
||||
sheerka, context, parser = self.init_parser(strict=True)
|
||||
res = parser.parse(context, ParserInput(expression))
|
||||
|
||||
if expected:
|
||||
expected = get_expr_node_from_test_node(expression, expected)
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert res.body.body == expected
|
||||
else:
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
|
||||
@pytest.mark.parametrize("expression, starting", [
|
||||
("(", TokenKind.LPAR),
|
||||
("(x, y", TokenKind.LPAR),
|
||||
|
||||
@@ -3,13 +3,12 @@ import pytest
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import TokenKind
|
||||
from parsers.BaseExpressionParser import TrueifyVisitor, IsAQuestionVisitor, LeftPartNotFoundError, \
|
||||
ParenthesisMismatchError, compile_disjunctions, NotNode, AndNode, OrNode
|
||||
from parsers.BaseExpressionParser import AndNode, IsAQuestionVisitor, LeftPartNotFoundError, NotNode, OrNode, \
|
||||
ParenthesisMismatchError, TrueifyVisitor, compile_disjunctions
|
||||
from parsers.BaseParser import UnexpectedEofParsingError, UnexpectedTokenParsingError
|
||||
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import EXPR, OR, AND, NOT, \
|
||||
get_expr_node_from_test_node
|
||||
from tests.parsers.parsers_utils import AND, EXPR, NOT, OR, get_expr_node_from_test_node
|
||||
|
||||
|
||||
class DoNotCompareStartStopContextManager:
|
||||
@@ -248,6 +247,11 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
("a or (b or c)", [EXPR("a"),
|
||||
EXPR("b"),
|
||||
EXPR("c")]),
|
||||
("a and b and not c", [AND(EXPR("a"), EXPR("b"), NOT(EXPR("c")))]),
|
||||
("not a and b", [AND(NOT(EXPR("a")), EXPR("b"))]),
|
||||
("not a and not b", [AND(NOT(EXPR("a")), NOT(EXPR("b")))]),
|
||||
("not a or not b", [NOT(EXPR("a")),
|
||||
NOT(EXPR("b"))]),
|
||||
])
|
||||
def test_i_can_compile_disjunction(self, expression, expected):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
@@ -258,282 +262,3 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
with DoNotCompareStartStopContextManager():
|
||||
res = compile_disjunctions(expr_node)
|
||||
assert res == resolved_expected
|
||||
|
||||
# @pytest.mark.parametrize("expression, expected", [
|
||||
# ("foo", "foo"),
|
||||
# ("one two", "one two"),
|
||||
# ("foo is a bar", CMV("is a", x='foo', y='bar')),
|
||||
# ("one two is a bar", [CNC("is a", "one two is a bar", x="one two", y="bar")]),
|
||||
# ("foo is an foo bar",
|
||||
# [CNC("is an", "foo is an foo bar", x=DoNotResolve(value='foo'), exclude_body=True)]),
|
||||
# ])
|
||||
# def test_i_can_get_compiled_expr_from_simple_concepts_expressions(self, expression, expected):
|
||||
# concepts_map = {
|
||||
# "foo": Concept("foo"),
|
||||
# "bar": Concept("bar"),
|
||||
# "one two": Concept("one two"),
|
||||
# "is a": Concept("x is a y").def_var("x").def_var("y"),
|
||||
# "is an": Concept("x is an y", definition="('foo'|'bar')=x 'is an' 'foo bar'").def_var("x"),
|
||||
# }
|
||||
# sheerka, context, *concepts = self.init_test().with_concepts(*concepts_map.values(), create_new=True).unpack()
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
|
||||
#
|
||||
# assert len(return_values) == 1
|
||||
# ret = return_values[0]
|
||||
#
|
||||
# if isinstance(expected, list):
|
||||
# expected_nodes = compute_expected_array(concepts_map, expression, expected)
|
||||
# compare_with_test_object(ret.body.body, expected_nodes)
|
||||
# else:
|
||||
# expected_concept = resolve_test_concept(concepts_map, expected)
|
||||
# compare_with_test_object(ret.body.body, expected_concept)
|
||||
|
||||
# @pytest.mark.parametrize("expression", [
|
||||
# "a == 5",
|
||||
# "foo > 5",
|
||||
# "func() == 5",
|
||||
# "not a == 5",
|
||||
# "not foo > 5",
|
||||
# "not func() == 5",
|
||||
# "isinstance(a, int)",
|
||||
# "func()",
|
||||
# "not isinstance(a, int)",
|
||||
# "not func()"
|
||||
# ])
|
||||
# def test_i_can_get_compiled_expr_from_simple_python_expressions(self, expression):
|
||||
# sheerka, context, = self.init_test().unpack()
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
|
||||
#
|
||||
# assert len(return_values) == 1
|
||||
# ret = return_values[0]
|
||||
#
|
||||
# assert ret.status
|
||||
# python_node = ret.body.body.get_python_node()
|
||||
# _ast = ast.parse(expression, mode="eval")
|
||||
# expected_python_node = PythonNode(expression, _ast)
|
||||
# assert python_node == expected_python_node
|
||||
#
|
||||
# @pytest.mark.parametrize("expression", [
|
||||
# "a and not b",
|
||||
# "not b and a",
|
||||
# "__ret and not __ret.status",
|
||||
# ])
|
||||
# def test_i_can_compile_negative_conjunctions_when_pure_python(self, expression):
|
||||
# sheerka, context, *concepts = self.init_concepts("foo")
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
|
||||
#
|
||||
# ast_ = ast.parse(expression, "<source>", 'eval')
|
||||
# expected_python_node = PythonNode(expression, ast_)
|
||||
#
|
||||
# assert len(return_values) == 1
|
||||
# ret = return_values[0]
|
||||
#
|
||||
# assert sheerka.objvalue(ret) == expected_python_node
|
||||
#
|
||||
# @pytest.mark.parametrize("expression, text_to_compile", [
|
||||
# ("foo bar == 5", "__C__foo0bar__1001__C__ == 5"),
|
||||
# ("not foo bar == 5", "not __C__foo0bar__1001__C__ == 5"),
|
||||
# ])
|
||||
# def test_i_can_get_compiled_expr_from_python_and_concept(self, expression, text_to_compile):
|
||||
# sheerka, context, *concepts = self.init_test().with_concepts(Concept("foo bar"), create_new=True).unpack()
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
|
||||
#
|
||||
# assert len(return_values) == 1
|
||||
# ret = return_values[0]
|
||||
#
|
||||
# assert ret.status
|
||||
# python_node = ret.body.body.get_python_node()
|
||||
# _ast = ast.parse(text_to_compile, mode="eval")
|
||||
# expected_python_node = PythonNode(text_to_compile, _ast, expression)
|
||||
# assert python_node == expected_python_node
|
||||
#
|
||||
# def test_i_can_get_compiled_expr_from__mix_of_concepts_and_python(self):
|
||||
# sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
|
||||
# Concept("animal"),
|
||||
# Concept("a cat"),
|
||||
# Concept("dog"),
|
||||
# Concept("pet"),
|
||||
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
|
||||
# Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
|
||||
# create_new=True
|
||||
# ).unpack()
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expression = "not a cat is a pet and not bird is an animal and not x > 5 and not dog is a pet"
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
|
||||
#
|
||||
# to_compile = 'not __C__00var0000is0a000var001__1005__C__'
|
||||
# to_compile += ' and not __C__00var0000is0an0y__1006__C__'
|
||||
# to_compile += ' and not x > 5'
|
||||
# to_compile += ' and not __C__00var0000is0a000var001__1005_1__C__'
|
||||
# ast_ = ast.parse(to_compile, "<source>", 'eval')
|
||||
# expected_python_node = PythonNode(to_compile, ast_, expression)
|
||||
#
|
||||
# assert len(return_values) == 1
|
||||
# ret = return_values[0]
|
||||
# python_node = ret.body.body
|
||||
# assert python_node == expected_python_node
|
||||
# compare_with_test_object(python_node.objects, {
|
||||
# "__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
|
||||
# "__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
|
||||
# "__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
|
||||
# })
|
||||
#
|
||||
# def test_i_can_get_compiled_expr_from_mix(self):
|
||||
# sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
|
||||
# Concept("animal"),
|
||||
# Concept("a cat"),
|
||||
# Concept("dog"),
|
||||
# Concept("pet"),
|
||||
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
|
||||
# Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
|
||||
# create_new=True
|
||||
# ).unpack()
|
||||
#
|
||||
# expression = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
|
||||
#
|
||||
# assert len(return_values) == 1
|
||||
# ret = return_values[0]
|
||||
#
|
||||
# to_compile = '__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1006__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__'
|
||||
# ast_ = ast.parse(to_compile, "<source>", 'eval')
|
||||
# expected_python_node = PythonNode(to_compile, ast_, expression)
|
||||
#
|
||||
# python_node = ret.body.body
|
||||
# assert python_node == expected_python_node
|
||||
# compare_with_test_object(python_node.objects, {
|
||||
# "__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
|
||||
# "__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
|
||||
# "__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
|
||||
# })
|
||||
#
|
||||
# def test_i_can_get_compiled_expr_when_multiple_choices(self):
|
||||
# sheerka, context, *concepts = self.init_test().with_concepts(
|
||||
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
|
||||
# Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
|
||||
# create_new=True
|
||||
# ).unpack()
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expression = "a is a b"
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
|
||||
#
|
||||
# assert len(return_values) == 2
|
||||
#
|
||||
# ret = return_values[0]
|
||||
# compare_with_test_object(sheerka.objvalue(ret)[0].concept, CMV(concepts[0], x="a", y="b"))
|
||||
#
|
||||
# ret = return_values[1]
|
||||
# compare_with_test_object(sheerka.objvalue(ret)[0].concept, CMV(concepts[1], x="a", y="b"))
|
||||
#
|
||||
# def test_i_can_get_compiled_expr_from_mix_when_multiple_choices(self):
|
||||
# sheerka, context, *concepts = self.init_test().with_concepts(
|
||||
# Concept("animal"),
|
||||
# Concept("a cat"),
|
||||
# Concept("dog"),
|
||||
# Concept("pet"),
|
||||
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
|
||||
# Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
|
||||
# Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
|
||||
# create_new=True
|
||||
# ).unpack()
|
||||
#
|
||||
# expression = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
|
||||
#
|
||||
# assert len(return_values) == 4
|
||||
# trimmed_source = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
|
||||
#
|
||||
# current_ret = return_values[0]
|
||||
# python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__"
|
||||
# ast_ = ast.parse(python_source, "<source>", 'eval')
|
||||
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
|
||||
# assert sheerka.objvalue(current_ret) == resolved_expected
|
||||
#
|
||||
# current_ret = return_values[1]
|
||||
# assert sheerka.isinstance(current_ret, BuiltinConcepts.RETURN_VALUE)
|
||||
# python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006__C__"
|
||||
# ast_ = ast.parse(python_source, "<source>", 'eval')
|
||||
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
|
||||
# assert sheerka.objvalue(current_ret) == resolved_expected
|
||||
#
|
||||
# current_ret = return_values[2]
|
||||
# assert sheerka.isinstance(current_ret, BuiltinConcepts.RETURN_VALUE)
|
||||
# python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005__C__"
|
||||
# ast_ = ast.parse(python_source, "<source>", 'eval')
|
||||
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
|
||||
# assert sheerka.objvalue(current_ret) == resolved_expected
|
||||
#
|
||||
# current_ret = return_values[3]
|
||||
# python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006_1__C__"
|
||||
# ast_ = ast.parse(python_source, "<source>", 'eval')
|
||||
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
|
||||
# assert sheerka.objvalue(current_ret) == resolved_expected
|
||||
#
|
||||
# @pytest.mark.skip
|
||||
# @pytest.mark.parametrize("expression, expected_conditions, test_obj", [
|
||||
# (
|
||||
# "__ret",
|
||||
# ["#__x_00__|__name__|'__ret'"],
|
||||
# ReturnValueConcept("Test", True, None)
|
||||
# ),
|
||||
# (
|
||||
# "__ret.status == True",
|
||||
# ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||
# ReturnValueConcept("Test", True, None)
|
||||
# ),
|
||||
# (
|
||||
# "__ret.status",
|
||||
# ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||
# ReturnValueConcept("Test", True, None)
|
||||
# ),
|
||||
# (
|
||||
# "__ret and __ret.status",
|
||||
# ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||
# ReturnValueConcept("Test", True, None)
|
||||
# ),
|
||||
# ])
|
||||
# def test_i_can_get_rete_condition_from_python(self, expression, expected_conditions, test_obj):
|
||||
# sheerka, context, = self.init_test().unpack()
|
||||
# expected_full_condition = get_rete_conditions(*expected_conditions)
|
||||
#
|
||||
# parser = LogicalOperatorParser()
|
||||
# expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
#
|
||||
# nodes = expr_node.parts if isinstance(expr_node, AndNode) else [expr_node]
|
||||
# _, rete_disjunctions = parser.compile_conjunctions(context, nodes, "test")
|
||||
#
|
||||
# assert len(rete_disjunctions) == 1
|
||||
# assert rete_disjunctions == [expected_full_condition]
|
||||
#
|
||||
# # check against a Rete network
|
||||
# network = ReteNetwork()
|
||||
# rule = Rule("test", expression, None)
|
||||
# rule.metadata.id = 9999
|
||||
# rule.metadata.is_compiled = True
|
||||
# rule.metadata.is_enabled = True
|
||||
# rule.rete_disjunctions = rete_disjunctions
|
||||
# network.add_rule(rule)
|
||||
#
|
||||
# network.add_obj("__ret", test_obj)
|
||||
# matches = list(network.matches)
|
||||
# assert len(matches) > 0
|
||||
|
||||
@@ -3,11 +3,11 @@ import pytest
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import TokenKind
|
||||
from parsers.BaseExpressionParser import ParenthesisMismatchError
|
||||
from parsers.BaseParser import UnexpectedTokenParsingError
|
||||
from parsers.RelationalOperatorParser import RelationalOperatorParser
|
||||
from parsers.BaseExpressionParser import ParenthesisMismatchError
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import get_expr_node_from_test_node, VAR, EXPR, EQ, NEQ, GT, GTE, LT, LTE, IN, NIN
|
||||
from tests.parsers.parsers_utils import EQ, EXPR, GT, GTE, IN, LT, LTE, L_EXPR, NEQ, NIN, get_expr_node_from_test_node
|
||||
|
||||
|
||||
class TestRelationalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
@@ -33,15 +33,15 @@ class TestRelationalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
("var_name.attr >= 10", GTE(EXPR("var_name.attr"), EXPR("10"))),
|
||||
("var_name.attr < 10", LT(EXPR("var_name.attr"), EXPR("10"))),
|
||||
("var_name.attr <= 10", LTE(EXPR("var_name.attr"), EXPR("10"))),
|
||||
("var_name.attr in (a, b)", IN(EXPR("var_name.attr"), EXPR("a, b"))),
|
||||
("var_name.attr not in (a, b)", NIN(EXPR("var_name.attr"), EXPR("a, b"))),
|
||||
("var_name.attr in (a, b)", IN(EXPR("var_name.attr"), L_EXPR("(", ")", "a", "b"))),
|
||||
("var_name.attr not in (a, b)", NIN(EXPR("var_name.attr"), L_EXPR("(", ")", "a", "b"))),
|
||||
("var1.attr1 == var2.attr2", EQ(EXPR("var1.attr1"), EXPR("var2.attr2"))),
|
||||
("var1.attr1 == (var2.attr2)", EQ(EXPR("var1.attr1"), EXPR("var2.attr2"))),
|
||||
#("var_name.attr in (a.b, b.c)", IN(EXPR("var_name.attr"), PAREN(EXPR("a.b, b.c"), source="(a.b, b.c)"))),
|
||||
("var_name.attr in (a.b, b.c)", IN(EXPR("var_name.attr"), L_EXPR("(", ")", "a.b", "b.c"))),
|
||||
|
||||
("not a var identifier", EXPR("not a var identifier")),
|
||||
("func()", EXPR("func()")),
|
||||
#("func(a, not an identifier, x >5)", EXPR("func(a, not an identifier, x >5)")),
|
||||
("func(a, not an identifier, x >5)", EXPR("func(a, not an identifier, x >5)")),
|
||||
("(var_name.attr != var_name2.attr2)", NEQ(EXPR("var_name.attr"), EXPR("var_name2.attr2")))
|
||||
])
|
||||
def test_i_can_parse_simple_expressions(self, expression, expected):
|
||||
@@ -61,11 +61,11 @@ class TestRelationalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
("(", BuiltinConcepts.NOT_FOR_ME, TokenKind.LPAR, 0),
|
||||
(")", BuiltinConcepts.NOT_FOR_ME, TokenKind.RPAR, 0),
|
||||
("something (", BuiltinConcepts.NOT_FOR_ME, TokenKind.LPAR, 10),
|
||||
# ("something )", BuiltinConcepts.NOT_FOR_ME, TokenKind.RPAR, 10),
|
||||
("something )", BuiltinConcepts.ERROR, TokenKind.RPAR, 10),
|
||||
("something == (", BuiltinConcepts.ERROR, TokenKind.LPAR, 13),
|
||||
("something == )", BuiltinConcepts.ERROR, TokenKind.RPAR, 13),
|
||||
("something (==", BuiltinConcepts.NOT_FOR_ME, TokenKind.LPAR, 10),
|
||||
# ("something )==", BuiltinConcepts.NOT_FOR_ME, TokenKind.RPAR, 10),
|
||||
("something )==", BuiltinConcepts.ERROR, TokenKind.RPAR, 10),
|
||||
])
|
||||
def test_i_can_detect_unbalanced_parenthesis(self, expression, expected_error, parenthesis_type, index):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -3,13 +3,16 @@ import pytest
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept, DEFINITION_TYPE_DEF
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer
|
||||
from parsers.BaseExpressionParser import NameExprNode
|
||||
from parsers.ExactConceptParser import NotSupportedElement
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import CN, SCN, UTN, compare_with_test_object, compute_expected_array, get_test_obj
|
||||
|
||||
|
||||
class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
def init_parser(self, my_map, create_new=False, singleton=True, use_sheerka=False):
|
||||
def init_parser(self, my_map, create_new=False, use_sheerka=False):
|
||||
sheerka, context, *updated_concepts = self.init_test().with_concepts(
|
||||
*my_map.values(),
|
||||
create_new=create_new).unpack()
|
||||
@@ -105,7 +108,7 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_parse_when_unrecognized(self, text, expected_status, expected):
|
||||
concepts_map = {
|
||||
"prefixed": Concept("a prefixed").def_var("a"),
|
||||
"suffixed": Concept("prefixed a").def_var("a"),
|
||||
"suffixed": Concept("suffixed a").def_var("a"),
|
||||
"infix": Concept("a infix b").def_var("a").def_var("b"),
|
||||
"foo bar": Concept("foo bar"),
|
||||
"one": Concept("one"),
|
||||
@@ -332,7 +335,7 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
"bar": Concept("bar")
|
||||
}
|
||||
|
||||
sheerka, context, parser = self.init_parser(concepts_map, create_new=True, singleton=False)
|
||||
sheerka, context, parser = self.init_parser(concepts_map, create_new=True)
|
||||
list_of_res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert len(list_of_res) == len(expected)
|
||||
@@ -483,3 +486,15 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
concept_found = lexer_nodes[0].concept
|
||||
|
||||
assert concept_found.get_metadata().body == "get_plural_concept_value(self)"
|
||||
|
||||
def test_i_cannot_parse_when_expr_token(self):
|
||||
sheerka, context, parser = self.init_parser({})
|
||||
|
||||
tokens = list(Tokenizer("foo bar baz", yield_eof=False))
|
||||
tokens.append(Token(TokenKind.EXPR, NameExprNode(-1, -1, []), -1, -1, -1))
|
||||
|
||||
ret = parser.parse(context, ParserInput(None, tokens))
|
||||
|
||||
assert not ret.status
|
||||
assert sheerka.isinstance(ret.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
assert isinstance(ret.body.reason, NotSupportedElement)
|
||||
|
||||
@@ -2,21 +2,22 @@ import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.builtin_helpers import get_new_variables_definitions
|
||||
from core.builtin_helpers import get_new_variables_definitions, longest_only
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import CONCEPT_COMPARISON_CONTEXT
|
||||
from core.sheerka.Sheerka import RECOGNIZED_BY_KEY
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer, comparable_tokens
|
||||
from core.utils import get_text_from_tokens
|
||||
from parsers.BaseExpressionParser import FunctionNode, FunctionParameter, NameExprNode
|
||||
from parsers.BaseExpressionParser import BinaryNode, FunctionNode, FunctionNodeOld, FunctionParameter, ListNode, \
|
||||
NameExprNode, VariableNode
|
||||
from parsers.BaseNodeParser import ConceptNode, SourceCodeNode, UnrecognizedTokensNode
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.SyaNodeParser import FunctionDetected, NoSyaConceptFound, NotEnoughParameters, SyaConceptParser, \
|
||||
SyaNodeParser, SyaTokensParser, TokensNotFound, TooManyParameters
|
||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import CC, CN, CNC, RETVAL, SCN, SCWC, UTN, compute_expected_array, get_test_obj, \
|
||||
from tests.parsers.parsers_utils import CC, CIO, CN, CNC, RETVAL, SCN, UTN, compute_expected_array, get_test_obj, \
|
||||
prepare_nodes_comparison
|
||||
|
||||
cmap = {
|
||||
@@ -403,10 +404,9 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert not concept_parser.has_error()
|
||||
assert len(concept_parser.expected) == 0
|
||||
|
||||
expected = CNC("plus", a=CNC("one"), b=SCWC("func(", ")", CN("twenties", source="twenty two")))
|
||||
resolved_expected = compute_expected_array(cmap, expression, [expected])[0]
|
||||
concept_node_as_test_obj = get_test_obj(concept_node, expected)
|
||||
assert concept_node_as_test_obj == resolved_expected
|
||||
expected = CNC("plus", a=CNC("one"), b=SCN("func(twenty two)", [CIO("twenties", source="twenty two")]))
|
||||
actual_as_test, expected_resolved = prepare_nodes_comparison(cmap, expression, concept_node, expected)
|
||||
assert actual_as_test == expected_resolved
|
||||
assert concept_node.concept.get_metadata().variables == [("a", "one"), ("b", "func(twenty two)")]
|
||||
|
||||
def test_i_can_concept_parse_concepts_composition(self):
|
||||
@@ -1366,22 +1366,13 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
expected = [CN(cmap["suffixed"], text, 0, 6)]
|
||||
expected_return_value = RETVAL("1 + 1")
|
||||
expected = [CNC(cmap["suffixed"], text, 0, 6, a=[expected_return_value])]
|
||||
concept_node_as_test_obj = get_test_obj(lexer_nodes, expected)
|
||||
assert concept_node_as_test_obj == expected
|
||||
|
||||
# check the compiled
|
||||
expected_concept = lexer_nodes[0].concept
|
||||
assert len(expected_concept.get_compiled()["a"]) == 1
|
||||
|
||||
return_value_a = expected_concept.get_compiled()["a"][0]
|
||||
assert sheerka.isinstance(return_value_a, BuiltinConcepts.RETURN_VALUE)
|
||||
assert return_value_a.status
|
||||
assert sheerka.isinstance(return_value_a.body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert return_value_a.body.source == "1 + 1"
|
||||
assert isinstance(return_value_a.body.body, PythonNode)
|
||||
|
||||
# check metadata
|
||||
expected_concept = lexer_nodes[0].concept
|
||||
assert expected_concept.get_metadata().variables == [("a", "1 + 1")]
|
||||
|
||||
def test_i_can_parse_when_bnf_concept(self):
|
||||
@@ -1408,6 +1399,33 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
# check metadata
|
||||
assert expected_concept.get_metadata().variables == [("a", "twenty one")]
|
||||
|
||||
@pytest.mark.skip("Not quite sure that this test is relevant")
|
||||
def test_i_can_parse_when_bnf_and_python(self):
|
||||
# twenty one + 1 is not correctly parsed by BNFNode or SequenceNode
|
||||
# Maybe I should just leave it to ExpressionParser instead
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "suffixed twenty one + 1"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
# only care about the result that recognizes 'twenty one'
|
||||
longest = longest_only(context, res)
|
||||
res = longest.body.body[0]
|
||||
|
||||
wrapper = res.body
|
||||
lexer_nodes = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
expected_return_value = RETVAL("twenty one + 1", objects={"__o_00__": CIO("twenties", source="twenty one")})
|
||||
expected = [CNC(cmap["suffixed"], text, 0, 8, a=[expected_return_value])]
|
||||
concept_node_as_test_obj = get_test_obj(lexer_nodes, expected)
|
||||
assert concept_node_as_test_obj == expected
|
||||
|
||||
# check metadata
|
||||
expected_concept = lexer_nodes[0].concept
|
||||
assert expected_concept.get_metadata().variables == [("a", "twenty one + 1")]
|
||||
|
||||
def test_i_can_parse_when_function(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -1419,7 +1437,10 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
expected = [CNC("plus", a=CC("one"), b=[RETVAL("func(twenty two)")], source=text)]
|
||||
expected_ret_val = RETVAL("func(twenty two)",
|
||||
"func(__o_00__)",
|
||||
objects={"__o_00__": CIO("twenties", source="twenty two")})
|
||||
expected = [CNC("plus", a=CC("one"), b=[expected_ret_val], source=text)]
|
||||
_stack, _expected = prepare_nodes_comparison(cmap, text, lexer_nodes, expected)
|
||||
assert _stack == _expected
|
||||
|
||||
@@ -1543,16 +1564,16 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
_stack, _expected = prepare_nodes_comparison(concepts_map, text, lexer_nodes, expected)
|
||||
assert _stack == _expected
|
||||
|
||||
def test_i_can_parse_when_expr_tokens(self):
|
||||
def test_i_can_parse_when_function_old_style_expr_tokens(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "one plus func(twenty two)"
|
||||
tokens = list(Tokenizer(text, yield_eof=False))
|
||||
fun_token = tokens[4]
|
||||
expr = FunctionNode(4, 9, tokens[4:10],
|
||||
NameExprNode(4, 4, tokens[4:5]),
|
||||
NameExprNode(9, 9, tokens[9:10]),
|
||||
[FunctionParameter(NameExprNode(6, 8, tokens[6:9]), None)])
|
||||
expr = FunctionNodeOld(4, 9, tokens[4:10],
|
||||
NameExprNode(4, 5, tokens[4:6]),
|
||||
NameExprNode(9, 9, tokens[9:10]),
|
||||
[FunctionParameter(NameExprNode(6, 8, tokens[6:9]), None)])
|
||||
tokens[4:] = [Token(TokenKind.EXPR, expr, fun_token.index, fun_token.line, fun_token.column)]
|
||||
res = parser.parse(context, ParserInput(None, tokens=tokens))
|
||||
wrapper = res.body
|
||||
@@ -1561,7 +1582,8 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
expected = [CNC("plus", a=CC("one"), b=[RETVAL("func(twenty two)")], source=text)]
|
||||
expected_ret_val = RETVAL("func(twenty two)", objects={"__o_00__": CIO("twenties", source="twenty two")})
|
||||
expected = [CNC("plus", a=CC("one"), b=[expected_ret_val], source=text)]
|
||||
_stack, _expected = prepare_nodes_comparison(cmap, text, lexer_nodes, expected)
|
||||
assert _stack == _expected
|
||||
|
||||
@@ -1569,6 +1591,64 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
expected_concept = lexer_nodes[0].concept
|
||||
assert expected_concept.get_metadata().variables == [("a", "one"), ("b", "func(twenty two)")]
|
||||
|
||||
def test_i_can_parse_when_function_style_expr_tokens(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "one plus func(twenty two)"
|
||||
tokens = list(Tokenizer(text, yield_eof=False))
|
||||
fun_token = tokens[4]
|
||||
expr = FunctionNode(4, 9, tokens[4:10],
|
||||
NameExprNode(4, 4, tokens[4:5]),
|
||||
ListNode(5, 9, tokens[5:10],
|
||||
NameExprNode(5, 5, tokens[5:6]),
|
||||
NameExprNode(9, 9, tokens[9:10]),
|
||||
[NameExprNode(6, 8, tokens[6:9])]))
|
||||
tokens[4:] = [Token(TokenKind.EXPR, expr, fun_token.index, fun_token.line, fun_token.column)]
|
||||
res = parser.parse(context, ParserInput(None, tokens=tokens))
|
||||
wrapper = res.body
|
||||
lexer_nodes = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
expected_ret_val = RETVAL("func(twenty two)", objects={"__o_00__": CIO("twenties", source="twenty two")})
|
||||
expected = [CNC("plus", a=CC("one"), b=[expected_ret_val], source=text)]
|
||||
_stack, _expected = prepare_nodes_comparison(cmap, text, lexer_nodes, expected)
|
||||
assert _stack == _expected
|
||||
|
||||
# check the metadata
|
||||
expected_concept = lexer_nodes[0].concept
|
||||
assert expected_concept.get_metadata().variables == [("a", "one"), ("b", "func(twenty two)")]
|
||||
|
||||
def test_i_can_parse_when_binary_expr_tokens(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "suffixed twenty one + self"
|
||||
tokens = list(Tokenizer(text, yield_eof=False))
|
||||
expr = BinaryNode(2, 8, tokens[2:9], tokens[6],
|
||||
VariableNode(2, 4, tokens[2:5], "twenty one"),
|
||||
VariableNode(8, 8, tokens[8:9], "self"))
|
||||
token_twenty = tokens[2]
|
||||
tokens[2:] = [Token(TokenKind.EXPR, expr, token_twenty.index, token_twenty.line, token_twenty.column)]
|
||||
|
||||
res = parser.parse(context, ParserInput(None, tokens=tokens))
|
||||
wrapper = res.body
|
||||
lexer_nodes = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
expected_ret_val = RETVAL("twenty one + self",
|
||||
source="__o_00__ + self",
|
||||
objects={"__o_00__": CIO("twenties", source="twenty one")})
|
||||
expected = [CNC("suffixed", a=[expected_ret_val], source=text)]
|
||||
_stack, _expected = prepare_nodes_comparison(cmap, text, lexer_nodes, expected)
|
||||
assert _stack == _expected
|
||||
|
||||
# check the metadata
|
||||
expected_concept = lexer_nodes[0].concept
|
||||
assert expected_concept.get_metadata().variables == [("a", "twenty one + self")]
|
||||
|
||||
@pytest.mark.parametrize("text, expected_result", [
|
||||
("one plus two foo bar baz", [CNC("plus", a="one", b="two"), UTN(" foo bar baz")]),
|
||||
("one plus two foo bar", [CNC("plus", a="one", b="two"), UTN(" foo bar")]),
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import OBJECTS_COUNTER_KEY
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind
|
||||
from parsers.BaseExpressionParser import ExprNode, NameExprNode
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.TokenExpressionParser import NoTokenExprFound, TokenExpressionParser
|
||||
from sheerkapython.python_wrapper import Expando
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestTokenExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
def init_parser(self, my_map=None, create_new=False):
|
||||
if my_map is None:
|
||||
my_map = {}
|
||||
|
||||
sheerka, context, *updated_concepts = self.init_test().with_concepts(
|
||||
*my_map.values(),
|
||||
create_new=create_new).unpack()
|
||||
|
||||
parser = TokenExpressionParser()
|
||||
|
||||
return sheerka, context, parser
|
||||
|
||||
@staticmethod
|
||||
def get_parser_input(context, expression):
|
||||
expr_parser = ExpressionParser(auto_compile=False)
|
||||
parsed_ret = expr_parser.parse(context, ParserInput(expression))
|
||||
parsed = parsed_ret.body.body
|
||||
token_expr = Token(TokenKind.EXPR, parsed, 0, 1, 1)
|
||||
return ParserInput(None, [token_expr])
|
||||
|
||||
def test_i_cannot_parse_empty_string(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
res = parser.parse(context, ParserInput(""))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
|
||||
|
||||
def test_i_cannot_parse_when_no_token_expression(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
parser_input = ParserInput("not an ExprNode")
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
assert res.body.body == parser_input
|
||||
assert isinstance(res.body.reason, NoTokenExprFound)
|
||||
|
||||
def test_i_cannot_parse_when_too_many_token_expression(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
expr = NameExprNode(0, 0, [Token(TokenKind.IDENTIFIER, "hello", 0, 1, 1)])
|
||||
token_expr = Token(TokenKind.EXPR, expr, 0, 1, 1)
|
||||
parser_input = ParserInput(None, [token_expr, token_expr])
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
assert res.body.body == parser_input
|
||||
assert isinstance(res.body.reason, NoTokenExprFound)
|
||||
|
||||
def test_i_can_parse_simple_expression(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
parser_input = self.get_parser_input(context, "a + b")
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].who == "parsers.TokenExpr"
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(res[0].body.body, PythonNode)
|
||||
|
||||
def test_i_can_parse_when_concept(self):
|
||||
concepts_map = {"foo": Concept("foo x").def_var("x")}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, True)
|
||||
parser_input = self.get_parser_input(context, "foo a")
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(res[0].body.body, PythonNode)
|
||||
|
||||
python_node = res[0].body.body
|
||||
assert python_node.source == "call_concept(__o_00__, x=a)"
|
||||
|
||||
def test_i_can_parse_when_concept_using_object_counter(self):
|
||||
concepts_map = {"foo": Concept("foo x").def_var("x")}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, True)
|
||||
parser_input = self.get_parser_input(context, "foo a")
|
||||
|
||||
objects_counter_entry = Expando(OBJECTS_COUNTER_KEY, {"value": 10})
|
||||
context.add_to_short_term_memory(OBJECTS_COUNTER_KEY, objects_counter_entry)
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(res[0].body.body, PythonNode)
|
||||
|
||||
python_node = res[0].body.body
|
||||
assert python_node.source == "call_concept(__o_10__, x=a)"
|
||||
|
||||
objects_counter_entry = context.get_from_short_term_memory(OBJECTS_COUNTER_KEY)
|
||||
assert objects_counter_entry.value == 11
|
||||
|
||||
def test_i_can_parse_simple_expression_when_is_question_is_set(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
parser_input = self.get_parser_input(context, "a + b")
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert res.status
|
||||
assert res.who == "parsers.TokenExpr"
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
assert isinstance(res.body.body, ExprNode)
|
||||
assert res.body.body.compiled is not None
|
||||
|
||||
def test_i_can_parse_when_concept_and_is_question_is_set(self):
|
||||
concepts_map = {"isa": Concept("x is a y", pre="is_question()").def_var("x").def_var("y")}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, True)
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
parser_input = self.get_parser_input(context, "a is a b")
|
||||
|
||||
objects_counter_entry = Expando(OBJECTS_COUNTER_KEY, {"value": 10})
|
||||
context.add_to_short_term_memory(OBJECTS_COUNTER_KEY, objects_counter_entry)
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.PARSER_RESULT)
|
||||
assert isinstance(res.body.body, ExprNode)
|
||||
|
||||
expr_node = res.body.body
|
||||
compiled_0 = expr_node.compiled[0]
|
||||
assert compiled_0.return_value.body.body.source == "evaluate_question(__o_10__, x=a, y=b)"
|
||||
|
||||
objects_counter_entry = context.get_from_short_term_memory(OBJECTS_COUNTER_KEY)
|
||||
assert objects_counter_entry.value == 11
|
||||
|
||||
def test_obj_counter_is_not_updated_when_error(self):
|
||||
concepts_map = {}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, True)
|
||||
parser_input = self.get_parser_input(context, "foo a")
|
||||
|
||||
objects_counter_entry = Expando(OBJECTS_COUNTER_KEY, {"value": 10})
|
||||
context.add_to_short_term_memory(OBJECTS_COUNTER_KEY, objects_counter_entry)
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||
|
||||
objects_counter_entry = context.get_from_short_term_memory(OBJECTS_COUNTER_KEY)
|
||||
assert objects_counter_entry.value == 10
|
||||
|
||||
def test_obj_counter_is_not_updated_when_error_and_is_question_is_set(self):
|
||||
concepts_map = {}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, True)
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
parser_input = self.get_parser_input(context, "a is a b")
|
||||
|
||||
objects_counter_entry = Expando(OBJECTS_COUNTER_KEY, {"value": 10})
|
||||
context.add_to_short_term_memory(OBJECTS_COUNTER_KEY, objects_counter_entry)
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||
|
||||
objects_counter_entry = context.get_from_short_term_memory(OBJECTS_COUNTER_KEY)
|
||||
assert objects_counter_entry.value == 10
|
||||
@@ -1,14 +1,14 @@
|
||||
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts
|
||||
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept
|
||||
from core.concept import Concept
|
||||
from core.tokenizer import Tokenizer, TokenKind
|
||||
from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode, SourceCodeNode
|
||||
from core.tokenizer import TokenKind, Tokenizer
|
||||
from parsers.BaseNodeParser import ConceptNode, SourceCodeNode, SourceCodeWithConceptNode, UnrecognizedTokensNode
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
from parsers.UnrecognizedNodeParser import UnrecognizedNodeParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, get_node, CC, UTN, CNC, CN, SCWC, \
|
||||
compare_with_test_object, SCN
|
||||
from tests.parsers.parsers_utils import CC, CN, CNC, SCN, SCWC, UTN, compare_with_test_object, compute_expected_array, \
|
||||
get_node, prepare_nodes_comparison
|
||||
|
||||
|
||||
def get_input_nodes_from(my_concepts_map, full_expr, *args):
|
||||
@@ -281,8 +281,10 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert res.status
|
||||
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
|
||||
assert parser_result.source == expression
|
||||
assert len(actual_nodes) == 1
|
||||
compare_with_test_object(actual_nodes[0], SCN(expression, 0, 4))
|
||||
|
||||
expected = [SCN(expression, start=0, end=4)]
|
||||
actual_as_test, resolved_expected = prepare_nodes_comparison(concepts_map, expression, actual_nodes, expected)
|
||||
assert actual_as_test == resolved_expected
|
||||
|
||||
def test_i_cannot_parse_unrecognized_python_that_looks_like_concept(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -4,7 +4,7 @@ from core.rule import Rule, ACTION_TYPE_EXEC
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.BaseNodeParser import RuleNode
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.FunctionParserOld import FunctionParserOld
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import get_test_obj, CNC, CC, CN, SCN, SCWC, UTN, RN, CB
|
||||
@@ -133,31 +133,31 @@ class TestParsersUtils(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_get_test_obj_when_SCN(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
parser = FunctionParser()
|
||||
parser = FunctionParserOld()
|
||||
scn = parser.parse(context, ParserInput("test()")).body.body
|
||||
|
||||
scn_res = get_test_obj(scn, SCN("", start=0, end=1))
|
||||
assert isinstance(scn_res, SCN)
|
||||
assert scn_res == SCN("test()", 0, 2)
|
||||
assert scn_res == SCN("test()", start=0, end=2)
|
||||
|
||||
# I can discard start and end
|
||||
scn_res = get_test_obj(scn, SCN(""))
|
||||
assert isinstance(scn_res, SCN)
|
||||
assert scn_res == SCN("test()", None, None)
|
||||
assert scn_res == SCN("test()", start=None, end=None)
|
||||
|
||||
def test_i_can_get_test_obj_when_SCWC(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
parser = FunctionParser()
|
||||
parser = FunctionParserOld()
|
||||
scwc = parser.parse(context, ParserInput("test(param1, test2())")).body.body
|
||||
|
||||
scwc_res = get_test_obj(scwc, SCWC(UTN(""), UTN(""), UTN(""), UTN(""), SCN("", 0, 0)))
|
||||
scwc_res = get_test_obj(scwc, SCWC(UTN(""), UTN(""), UTN(""), UTN(""), SCN("", None, 0, 0)))
|
||||
assert isinstance(scwc_res, SCWC)
|
||||
expected = SCWC(UTN("test(", 0, 1),
|
||||
UTN(")", 8, 8),
|
||||
UTN("param1", 2, 2),
|
||||
UTN(", ", 3, 4),
|
||||
SCN("test2()", 5, 7))
|
||||
SCN("test2()", None, 5, 7))
|
||||
expected.start = 0
|
||||
expected.end = 8
|
||||
assert scwc_res == expected
|
||||
|
||||
@@ -0,0 +1,500 @@
|
||||
import ast
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaRuleManager import CompiledCondition
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkapython.ExprToConditions import ExprToConditionsVisitor
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.core.test_SheerkaRuleManager import PYTHON_EVALUATOR_NAME
|
||||
|
||||
|
||||
@dataclass
|
||||
class Obj:
|
||||
value: object
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Obj) and self.value == other.value
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.value)
|
||||
|
||||
|
||||
cmap = {
|
||||
"one": Concept("one", body="1"),
|
||||
"two": Concept("two", body="2"),
|
||||
"three": Concept("three", body="3"),
|
||||
"twenties": Concept("twenties", definition="'twenty' (one|two)=unit", body="20 + unit").def_var("unit"),
|
||||
"equals": Concept("x equals y", pre="is_question()", body="x == y").def_var("x").def_var("y"),
|
||||
"isa1": Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
|
||||
"isa2": Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
|
||||
"isan1": Concept("x is an y", pre="is_question()", body="isa(x , y)").def_var("x").def_var("y"),
|
||||
"isan2": Concept("x is an y", body="set_isa(x, y)").def_var("x").def_var("y"),
|
||||
"foo": Concept("foo"),
|
||||
"bar": Concept("bar"),
|
||||
"baz": Concept("baz"),
|
||||
}
|
||||
|
||||
|
||||
class TestExprToConditionsVisitor(TestUsingMemoryBasedSheerka):
|
||||
shared_ontology = None
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
instance = cls()
|
||||
init_test_helper = instance.init_test(cache_only=False, ontology="#TestExprToConditionsVisitor#")
|
||||
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
|
||||
for i, concept_name in enumerate(cmap):
|
||||
cmap[concept_name] = updated[i]
|
||||
|
||||
global_context = instance.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_context, cmap["baz"], cmap["foo"])
|
||||
|
||||
cls.shared_ontology = sheerka.get_ontology(context)
|
||||
sheerka.pop_ontology(context)
|
||||
|
||||
def initialize_test(self, concepts_map=None):
|
||||
if concepts_map is None:
|
||||
sheerka, context = self.init_test().unpack()
|
||||
sheerka.add_ontology(context, self.shared_ontology)
|
||||
else:
|
||||
sheerka, context, *updated = super().init_test().with_concepts(*concepts_map.values(),
|
||||
create_new=True).unpack()
|
||||
for i, concept_name in enumerate(concepts_map):
|
||||
concepts_map[concept_name] = updated[i]
|
||||
|
||||
return sheerka, context
|
||||
|
||||
@staticmethod
|
||||
def evaluate_conditions(context, conditions, namespace):
|
||||
with context.push(BuiltinConcepts.EXEC_CODE, None) as sub_context:
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
sub_context.deactivate_push()
|
||||
|
||||
evaluation_service = sub_context.sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
return evaluation_service.evaluate_conditions(sub_context, conditions, namespace)
|
||||
|
||||
@staticmethod
|
||||
def get_conditions_from_expression(context, expression, parser=None):
|
||||
parser = parser or ExpressionParser(old_style=False)
|
||||
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
|
||||
known_variables = parser.known_variables if hasattr(parser, "known_variables") else None
|
||||
visitor = ExprToConditionsVisitor(context, known_variables=known_variables)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
return conditions
|
||||
|
||||
@staticmethod
|
||||
def validate_condition(context, expression, condition, e_code, e_objects, e_variables, e_not_variables):
|
||||
sheerka = context.sheerka
|
||||
|
||||
# check what was compiled
|
||||
if e_code is None:
|
||||
# manage cases where we only check for variable existence
|
||||
assert condition.evaluator_type is None
|
||||
assert condition.return_value is None
|
||||
else:
|
||||
ast_ = ast.parse(e_code, "<source>", 'exec' if "\n" in e_code else 'eval')
|
||||
expected_python_node = PythonNode(e_code, ast_, expression)
|
||||
assert condition.evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(condition.return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(condition.return_value) == expected_python_node
|
||||
|
||||
# check the objects
|
||||
if e_objects is not None:
|
||||
resolved_objects = {k: v.id for k, v in condition.objects.items()}
|
||||
resolved_expected_objects = {k: cmap[v].id for k, v in e_objects.items()}
|
||||
assert resolved_objects == resolved_expected_objects
|
||||
|
||||
# check that variables detected
|
||||
if e_variables is not None:
|
||||
assert condition.variables == e_variables
|
||||
|
||||
if e_not_variables is not None:
|
||||
assert condition.not_variables == e_not_variables
|
||||
|
||||
def run_test_cases(self, context, conditions, test_suite):
|
||||
sheerka = context.sheerka
|
||||
|
||||
for test_data in test_suite:
|
||||
namespace, expected_value = test_data
|
||||
for k, v in namespace.items():
|
||||
if isinstance(v, str):
|
||||
try:
|
||||
namespace[k] = self.evaluate_from_source(context, v)
|
||||
except:
|
||||
pass
|
||||
|
||||
res = self.evaluate_conditions(context, conditions, namespace)
|
||||
value = sheerka.objvalue(res[0].body) if res else False
|
||||
assert value == expected_value
|
||||
|
||||
@staticmethod
|
||||
def evaluate_condition(context, expression, condition, objects):
|
||||
with context.push("Testing conditions SheerkaRuleManagerRulesCompilation", expression) as sub_context:
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, objects)
|
||||
|
||||
evaluator = PythonEvaluator()
|
||||
for c in condition.concepts_to_reset:
|
||||
c.get_hints().is_evaluated = False
|
||||
|
||||
return evaluator.eval(sub_context, condition.return_value)
|
||||
|
||||
@pytest.mark.parametrize("expression, e_code, e_variables, e_not_variables, test_suite", [
|
||||
("var", None, {"var"}, set(), [({"var": "value"}, True), ({}, False)]),
|
||||
("True", "True", set(), set(), []),
|
||||
("var.value", None, {"var.value"}, set(), []),
|
||||
("not var", None, set(), {"var"}, [({"var": "value"}, False), ({}, True)]),
|
||||
("not not var", None, {"var"}, set(), []),
|
||||
("var and var2 and not var3", None, {"var", "var2"}, {"var3"}, []),
|
||||
("var and var.value == 3", "var.value == 3", {"var"}, set(), [({"var": Obj(3)}, True)]),
|
||||
("not v2 and v1.value == 3", "v1.value == 3", {"v1"}, {"v2"}, [({"v1": Obj(3)}, True), ({"v2": 0}, False)]),
|
||||
("func(var)", "func(var)", {"var"}, set(), []),
|
||||
("var in []", "var in []", {"var"}, set(), []),
|
||||
("a + b", "a + b", {"a", "b"}, set(), []),
|
||||
("foo x", "__o_00__", set(), set(), []), # foo is not a variable
|
||||
("foo y", "evaluate_question(__o_00__, x=y)", {"y"}, set(), []), # foo is not a variable
|
||||
("bar y", "call_concept(__o_00__, x=y)", {"y"}, set(), []), # bar is not a variable
|
||||
])
|
||||
def test_i_can_parse_and_manage_exists(self, expression, e_code, e_variables, e_not_variables, test_suite):
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts(
|
||||
Concept("foo x", pre="is_question()").def_var("x"),
|
||||
Concept("bar x").def_var("x"),
|
||||
).unpack()
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
condition = conditions[0]
|
||||
|
||||
self.validate_condition(context, expression, condition, e_code, None, e_variables, e_not_variables)
|
||||
self.run_test_cases(context, conditions, test_suite)
|
||||
|
||||
@pytest.mark.parametrize("expression, e_code, e_objects, e_variables, test_suite", [
|
||||
# Concept
|
||||
("1 equals 1", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, True)]),
|
||||
("1 equals 2", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, False)]),
|
||||
("one equals one", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, True)]),
|
||||
("one equals two", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, False)]),
|
||||
("one equals twenty one", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, False)]),
|
||||
("self equals 1", "evaluate_question(__o_00__, x=self)", {"__o_00__": "equals"}, {"self"}, [
|
||||
({"self": 1}, True),
|
||||
({"self": 2}, False)]),
|
||||
("x equals 1", "evaluate_question(__o_00__, x=x)", {"__o_00__": "equals"}, {"x"}, [
|
||||
({"x": 1}, True),
|
||||
({"x": 2}, False)]),
|
||||
("one equals self", "evaluate_question(__o_00__, y=self)", {"__o_00__": "equals"}, {"self"}, [
|
||||
({"self": "one"}, True),
|
||||
({"self": "two"}, False)]),
|
||||
("self equals twenty two", "evaluate_question(__o_00__, x=self)", {"__o_00__": "equals"}, {"self"}, [
|
||||
({"self": "twenty two"}, True),
|
||||
({"self": "two"}, False)]
|
||||
),
|
||||
("x equals 1 and y equals 2",
|
||||
"evaluate_question(__o_00__, x=x) and evaluate_question(__o_01__, x=y)",
|
||||
{"__o_00__": "equals", "__o_01__": "equals"},
|
||||
{"x", "y"},
|
||||
[({"x": 1, "y": 2}, True), ({"x": "0", "y": "0"}, False)]
|
||||
),
|
||||
("x equals y", "__o_00__", {"__o_00__": "equals"}, set(), []),
|
||||
("func(self) equals twenty one",
|
||||
"evaluate_question(__o_00__, x=func(self))",
|
||||
{"__o_00__": "equals"},
|
||||
{"self"},
|
||||
[({"self": "twenty one", "func": lambda x: x}, True)]),
|
||||
("func(self) equals twenty one + 1",
|
||||
"evaluate_question(__o_01__, x=func(self), y=__o_00__ + 1)",
|
||||
{"__o_01__": "equals", "__o_00__": "twenties"},
|
||||
{"self"},
|
||||
[({"self": "22", "func": lambda x: x}, True)]),
|
||||
|
||||
# equality
|
||||
("a == 10", "a == 10", {}, {"a"}, [({"a": 10}, True), ({"a": 20}, False), ({}, False)]),
|
||||
("__ret.status == True", "__ret.status == True", {}, {"__ret"}, []),
|
||||
("self == sheerka", "is_sheerka(self)", {}, {"self"}, [
|
||||
({"self": "sheerka"}, True),
|
||||
({"self": "other"}, False),
|
||||
]),
|
||||
("self == BuiltinConcepts.TO_DICT", "self == BuiltinConcepts.TO_DICT", {}, {"self"}, [
|
||||
({"self": "BuiltinConcepts.TO_DICT"}, True),
|
||||
({"self": "other"}, False),
|
||||
]),
|
||||
|
||||
# other Comparisons
|
||||
("a + self > 10", "a + self > 10", {}, {"a", "self"}, [
|
||||
({"a": 10, "self": 1}, True),
|
||||
({"a": 10, "self": 0}, False),
|
||||
]),
|
||||
("10 < one + self", "10 < __o_00__ + self", {"__o_00__": "one"}, {"self"}, [
|
||||
({"self": 10}, True),
|
||||
({"self": 1}, False),
|
||||
]),
|
||||
("23 < twenty one + self", "23 < __o_00__ + self", {"__o_00__": "twenties"}, {"self"}, [
|
||||
({"self": 10}, True),
|
||||
({"self": 1}, False),
|
||||
]),
|
||||
("a equals b and c equals d",
|
||||
"evaluate_question(__o_00__, x=a, y=b) and evaluate_question(__o_01__, x=c, y=d)",
|
||||
{"__o_00__": "equals", "__o_01__": "equals"},
|
||||
{"a", "b", "c", "d"},
|
||||
[]),
|
||||
|
||||
# simple expressions
|
||||
("True", "True", {}, set(), [({}, True)]),
|
||||
("False", "False", {}, set(), [({}, False)]),
|
||||
("10 + 5", "10 + 5", {}, set(), [({}, 15)]),
|
||||
("a + self", "a + self", {}, {"a", "self"}, [({"a": 10, "self": 5}, 15)]),
|
||||
("a + twenty one", "a + __o_00__", {"__o_00__": "twenties"}, {"a"}, [({"a": 10}, 31)]),
|
||||
|
||||
# functions
|
||||
("isinstance('hello', str)", "isinstance('hello', str)", {}, set(), [({}, True)]),
|
||||
("isinstance(a, str)", "isinstance(a, str)", {}, {"a"}, [({"a": "an_str"}, True), ({"a": 1}, False)]),
|
||||
("f(BuiltinConcepts.TO_DICT)", "f(BuiltinConcepts.TO_DICT)", {}, set(), [({"f": lambda x: x}, "__TO_DICT")])
|
||||
|
||||
])
|
||||
def test_i_can_parse(self, expression, e_code, e_objects, e_variables, test_suite):
|
||||
sheerka, context = self.initialize_test()
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
condition = conditions[0]
|
||||
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
|
||||
self.run_test_cases(context, conditions, test_suite)
|
||||
|
||||
def test_i_can_force_variable(self):
|
||||
sheerka, context = self.initialize_test()
|
||||
parser = ExpressionParser(known_variables={"one"})
|
||||
conditions = self.get_conditions_from_expression(context, "one < two", parser)
|
||||
python_source = conditions[0].return_value.body.body.source
|
||||
assert python_source == "one < __o_00__"
|
||||
|
||||
resolved_objects = {k: v.id for k, v in conditions[0].objects.items()}
|
||||
resolved_expected_objects = {k: cmap[v].id for k, v in {"__o_00__": "two"}.items()}
|
||||
assert resolved_objects == resolved_expected_objects
|
||||
|
||||
def test_i_can_parse_when_variables_are_missing(self):
|
||||
sheerka, context = self.initialize_test()
|
||||
expression = "x equals 1"
|
||||
e_code = "evaluate_question(__o_00__, x=x)"
|
||||
e_objects = {"__o_00__": "equals"}
|
||||
e_variables = {"x"}
|
||||
test_suite = [({}, False), ({"y": 1}, False)]
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
condition = conditions[0]
|
||||
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
|
||||
self.run_test_cases(context, conditions, test_suite)
|
||||
|
||||
def test_question_concept_is_chosen_other_non_question_concept(self):
|
||||
sheerka, context = self.initialize_test()
|
||||
expression = "a is an b"
|
||||
e_code = "evaluate_question(__o_00__, x=a, y=b)"
|
||||
e_objects = {"__o_00__": "isan1"}
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
condition = conditions[0]
|
||||
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, None, None)
|
||||
|
||||
def test_i_can_manage_when_multiple_concepts(self):
|
||||
sheerka, context = self.initialize_test()
|
||||
expression = "a is a b"
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 2
|
||||
|
||||
condition = conditions[0]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "evaluate_question(__o_00__, x=a, y=b)"
|
||||
e_objects = {"__o_00__": "isa1"}
|
||||
e_variables = {"a", "b"}
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
condition = conditions[1]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "evaluate_question(__o_01__, x=a, y=b)"
|
||||
e_objects = {"__o_01__": "isa2"}
|
||||
e_variables = {"a", "b"}
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
# testing
|
||||
|
||||
namespace = {"a": sheerka.new("foo"), "b": sheerka.new("bar")}
|
||||
res = self.evaluate_conditions(context, conditions, namespace)
|
||||
assert len(res) == 2
|
||||
assert isinstance(res[0].value, bool) and not res[0].value
|
||||
assert isinstance(res[1].value, bool) and not res[1].value
|
||||
|
||||
namespace = {"a": sheerka.new("foo"), "b": sheerka.new("foo")}
|
||||
res = self.evaluate_conditions(context, conditions, namespace)
|
||||
assert len(res) == 1
|
||||
assert isinstance(res[0].value, bool) and res[0].value
|
||||
|
||||
namespace = {"a": sheerka.new("baz"), "b": sheerka.new("foo")}
|
||||
res = self.evaluate_conditions(context, conditions, namespace)
|
||||
assert len(res) == 1
|
||||
assert isinstance(res[0].value, bool) and res[0].value
|
||||
|
||||
def test_i_can_manage_or_expressions(self):
|
||||
sheerka, context = self.initialize_test()
|
||||
expression = "isinstance(self, foo) or self is a bar"
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 3
|
||||
|
||||
condition = conditions[0]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "isinstance(self, __o_00__)"
|
||||
e_objects = {"__o_00__": "foo"}
|
||||
e_variables = {"self"}
|
||||
self.validate_condition(context, "isinstance(self, foo)", condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
condition = conditions[1]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "evaluate_question(__o_01__, x=self)"
|
||||
e_objects = {"__o_01__": "isa1"}
|
||||
e_variables = {"self"}
|
||||
self.validate_condition(context, "self is a bar", condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
condition = conditions[2]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "evaluate_question(__o_02__, x=self)"
|
||||
e_objects = {"__o_02__": "isa2"}
|
||||
e_variables = {"self"}
|
||||
self.validate_condition(context, "self is a bar", condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
def test_i_can_manage_multiple_concepts_melt_with_and_expressions(self):
|
||||
sheerka, context = self.initialize_test()
|
||||
expression = "isinstance(self, foo) and self is a bar"
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 2
|
||||
|
||||
condition = conditions[0]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "isinstance(self, __o_00__) and evaluate_question(__o_01__, x=self)"
|
||||
e_objects = {"__o_00__": "foo", "__o_01__": "isa1"}
|
||||
e_variables = {"self"}
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
condition = conditions[1]
|
||||
assert isinstance(condition, CompiledCondition)
|
||||
e_code = "isinstance(self, __o_00__) and evaluate_question(__o_02__, x=self)"
|
||||
e_objects = {"__o_00__": "foo", "__o_02__": "isa2"}
|
||||
e_variables = {"self"}
|
||||
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("self is a 'foo'", {"x is a y"}),
|
||||
("set self is a 'foo'", set()),
|
||||
])
|
||||
def test_i_can_get_concept_to_reset(self, expression, expected):
|
||||
"""
|
||||
When compiled conditions, sometimes there are concepts to reset between two usages
|
||||
:param expression:
|
||||
:param expected:
|
||||
:return:
|
||||
"""
|
||||
concepts_map = {
|
||||
"isa": Concept("x is a y", pre="is_question()").def_var("x").def_var("y"),
|
||||
"set_isa": Concept("set x is a y").def_var("x").def_var("y"),
|
||||
}
|
||||
sheerka, context = self.initialize_test(concepts_map)
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert {c.name for c in conditions[0].concepts_to_reset} == expected
|
||||
|
||||
def test_i_can_reset_concepts_when_multiple_levels(self):
|
||||
"""
|
||||
When compiled conditions, sometimes there are concepts to reset between two usages
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, is_instance, is_int, is_integer = self.init_concepts(
|
||||
Concept("x is an instance of y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
|
||||
Concept("x is a int", pre="is_question()", body="x is an instance of int").def_var("x"),
|
||||
Concept("x is an integer", pre="is_question()", body="x is a int").def_var("x"),
|
||||
)
|
||||
|
||||
expression = "self is an integer"
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert {c.name for c in conditions[0].concepts_to_reset} == {"x is an instance of y",
|
||||
"x is a int",
|
||||
"x is an integer"}
|
||||
|
||||
# So I can evaluate multiple times
|
||||
res = self.evaluate_condition(context, expression, conditions[0], {'self': 10})
|
||||
assert res.status
|
||||
assert sheerka.objvalue(res.body)
|
||||
|
||||
res = self.evaluate_condition(context, expression, conditions[0], {'self': "string"})
|
||||
assert res.status
|
||||
assert not sheerka.objvalue(res.body)
|
||||
|
||||
def test_i_can_reset_concepts_when_multiple_levels_and_concept_node(self):
|
||||
"""
|
||||
When compiled conditions, sometimes there are concepts to reset between two usages
|
||||
:return:
|
||||
"""
|
||||
# in this example, x + 2 is an int won't be parsed as an ExactNodeConcept, but as a ConceptNode
|
||||
sheerka, context, is_int, is_integer = self.init_concepts(
|
||||
Concept("x is a int", pre="is_question()", body="isinstance(x, int)").def_var("x"),
|
||||
Concept("x is an integer", pre="is_question()", body="x + 2 is a int").def_var("x"),
|
||||
create_new=True
|
||||
)
|
||||
|
||||
expression = "self is an integer"
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert set(c.name for c in conditions[0].concepts_to_reset) == {"x is a int",
|
||||
"x is an integer"}
|
||||
|
||||
# So I can evaluate multiple times
|
||||
res = self.evaluate_condition(context, expression, conditions[0], {'self': 10})
|
||||
assert res.status
|
||||
assert sheerka.objvalue(res.body)
|
||||
|
||||
res = self.evaluate_condition(context, expression, conditions[0], {'self': "string"})
|
||||
assert not res.status
|
||||
|
||||
def test_long_name_concepts_are_not_considered_as_variables(self):
|
||||
sheerka, context, one, number = self.init_concepts(
|
||||
"one",
|
||||
"all numbers",
|
||||
)
|
||||
sheerka.set_isa(context, one, number)
|
||||
|
||||
expression = "all numbers < 5"
|
||||
conditions = self.get_conditions_from_expression(context, expression)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert conditions[0].return_value.body.body.source == '__o_00__ < 5'
|
||||
+355
-41
@@ -1,23 +1,23 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaEvaluateConcept import EvaluationHints
|
||||
from core.concept import Concept, DEFINITION_TYPE_DEF
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.ListComprehensionParser import ListComprehensionParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkapython.ExprToPython import PythonExprVisitor
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
class TestPythonExprVisitor(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@staticmethod
|
||||
def get_expr_node(context, expression, parser=None):
|
||||
parser = parser or ExpressionParser()
|
||||
parser = parser or ExpressionParser(old_style=False)
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
@@ -37,6 +37,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
context.add_to_short_term_memory(k, v)
|
||||
|
||||
res = evaluator.eval(context, return_value)
|
||||
|
||||
assert res.status
|
||||
return res.body
|
||||
|
||||
@@ -49,25 +50,63 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
("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"}),
|
||||
("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"})
|
||||
|
||||
{"__o_00__": "foo", "__o_01__": "bar"}),
|
||||
("set_isa(one, number)", "set_isa(__o_00__, __o_01__)", {"__o_00__": "one", "__o_01__": "number"}),
|
||||
("set_isa(twenty two, number)", "set_isa(__o_00__, __o_01__)", {"__o_00__": "twenties", "__o_01__": "number"}),
|
||||
("foo and twenty one", "__o_00__ and __o_01__", {"__o_00__": "foo", "__o_01__": "twenties"}),
|
||||
("func(z) is a 'foo'", "call_concept(__o_00__, x=func(z))", {"__o_00__": "isa"}),
|
||||
("isinstance('hello', str)", "isinstance('hello', str)", {}),
|
||||
("not (a and b)", "not (a and b)", {}),
|
||||
("twenty one is a number", "__o_00__", {"__o_00__": "isa"}),
|
||||
("x is a number", "call_concept(__o_00__, x=x)", {"__o_00__": "isa"}),
|
||||
("y is a number", "call_concept(__o_00__, x=y)", {"__o_00__": "isa"}),
|
||||
("number is a x", "call_concept(__o_00__, y=x)", {"__o_00__": "isa"}),
|
||||
("number is a y", "call_concept(__o_00__, y=y)", {"__o_00__": "isa"}),
|
||||
("x is a y", "__o_00__", {"__o_00__": "isa"}),
|
||||
("foo x + 1", "call_concept(__o_00__, x=x + 1)", {"__o_00__": "foo"}),
|
||||
("twenty two + 3", "__o_00__ + 3", {"__o_00__": "twenties"}),
|
||||
("twenty two * 2 - 1", "__o_00__ * 2 - 1", {"__o_00__": "twenties"}),
|
||||
("x * bar a + 2", "x * call_concept(__o_00__, y=a + 2)", {"__o_00__": "bar"}),
|
||||
("foo x * bar a + 2",
|
||||
"call_concept(__o_01__, x=x * call_concept(__o_00__, y=a + 2))",
|
||||
{"__o_00__": "bar", "__o_01__": "foo"}),
|
||||
("(foo y) * (bar a) + 2",
|
||||
"call_concept(__o_00__, x=y) * call_concept(__o_01__, y=a) + 2",
|
||||
{"__o_00__": "foo", "__o_01__": "bar"}),
|
||||
("func([one, two])", "func([__o_00__, __o_01__])", {"__o_00__": "one", "__o_01__": "two"}),
|
||||
("func([twenty one, two])", "func([__o_00__, __o_01__])", {"__o_00__": "twenties", "__o_01__": "two"}),
|
||||
("func((twenty one, two))", "func((__o_00__, __o_01__))", {"__o_00__": "twenties", "__o_01__": "two"}),
|
||||
("func({twenty one, two})", "func({__o_00__, __o_01__})", {"__o_00__": "twenties", "__o_01__": "two"}),
|
||||
("foo twenty one + self",
|
||||
"call_concept(__o_01__, x=__o_00__ + self)",
|
||||
{"__o_01__": "foo", "__o_00__": "twenties"}),
|
||||
])
|
||||
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"),
|
||||
sheerka, context, foo, bar, isa, one, two, twenties, number = self.init_test().with_concepts(
|
||||
Concept("foo", definition="foo x", definition_type=DEFINITION_TYPE_DEF, body="x").def_var("x"),
|
||||
Concept("bar y", body="y").def_var("y"),
|
||||
Concept("x is a y").def_var("x").def_var("y"),
|
||||
Concept("one", body="1"),
|
||||
Concept("two", body="2"),
|
||||
Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"),
|
||||
Concept("number"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
concepts = {
|
||||
"foo": foo,
|
||||
"bar": bar
|
||||
"bar": bar,
|
||||
"isa": isa,
|
||||
"one": one,
|
||||
"two": two,
|
||||
"twenties": twenties,
|
||||
"number": number
|
||||
}
|
||||
|
||||
node = self.get_expr_node(context, expression)
|
||||
@@ -80,6 +119,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
assert python_node.original_source == expression
|
||||
assert python_node.source == source
|
||||
|
||||
assert len(objects) == len(python_node.objects)
|
||||
for obj_name, obj_value in objects.items():
|
||||
assert obj_name in python_node.objects
|
||||
|
||||
@@ -87,7 +127,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
if isinstance(obj, Concept):
|
||||
assert sheerka.isinstance(obj, concepts[obj_value])
|
||||
assert obj.get_hints().use_copy
|
||||
assert obj.get_hints().is_evaluated
|
||||
# assert obj.get_hints().is_evaluated
|
||||
else:
|
||||
assert False
|
||||
|
||||
@@ -106,8 +146,9 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
}
|
||||
|
||||
node = self.get_expr_node(context, expression)
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
visitor = PythonExprVisitor(context)
|
||||
ret = visitor.compile(node, EvaluationHints(eval_body=True, eval_question=True))
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == 1
|
||||
python_node = ret[0].body.body
|
||||
@@ -125,6 +166,61 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
else:
|
||||
assert False
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("foo w", [
|
||||
("call_concept(__o_00__, x=w)", {"__o_00__": "foo1"}),
|
||||
("call_concept(__o_01__, y=w)", {"__o_01__": "foo2"})
|
||||
]),
|
||||
("foo z + 2", [
|
||||
("call_concept(__o_00__, x=z + 2)", {"__o_00__": "foo1"}),
|
||||
("call_concept(__o_01__, y=z + 2)", {"__o_01__": "foo2"}),
|
||||
]),
|
||||
("foo bar a + 2", [
|
||||
("call_concept(__o_00__, x=call_concept(__o_01__, x=a + 2))", {"__o_00__": "foo1", "__o_01__": "bar1"}),
|
||||
("call_concept(__o_02__, y=call_concept(__o_03__, x=a + 2))", {"__o_02__": "foo2", "__o_03__": "bar1"}),
|
||||
("call_concept(__o_04__, y=call_concept(__o_05__, y=a + 2))", {"__o_04__": "foo2", "__o_05__": "bar2"}),
|
||||
("call_concept(__o_06__, x=call_concept(__o_07__, y=a + 2))", {"__o_06__": "foo1", "__o_07__": "bar2"}),
|
||||
]),
|
||||
])
|
||||
def test_i_can_compile_when_multiple_concept_are_possible(self, expression, expected):
|
||||
sheerka, context, foo1, foo2, bar1, 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()
|
||||
|
||||
concepts = {
|
||||
"foo1": foo1,
|
||||
"foo2": foo2,
|
||||
"bar1": bar1,
|
||||
"bar2": bar2
|
||||
}
|
||||
|
||||
node = self.get_expr_node(context, expression)
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
ret = visitor.compile(node)
|
||||
|
||||
assert len(ret) == len(expected)
|
||||
|
||||
for ret, (source, objects) in zip(ret, expected):
|
||||
python_node = ret.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()
|
||||
|
||||
@@ -193,6 +289,39 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert self.eval(context, ret[0]) == ["a", "b"]
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_element_is_a_concept_using_bnf(self):
|
||||
sheerka, context, one, two, twenties, foo = self.init_test().with_concepts(
|
||||
Concept("one", body="1"),
|
||||
Concept("two", body="2"),
|
||||
Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"),
|
||||
Concept("foo x y", body="{x, y}").def_var("x").def_var("y"),
|
||||
create_new=True,
|
||||
).unpack()
|
||||
|
||||
expression = "[ foo x twenty one 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 == "[ call_concept(__o_00__, x=x) for x 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
|
||||
|
||||
twenty_one = self.evaluate_from_source(context, "twenty one")
|
||||
assert self.eval(context, ret[0]) == [{"a", twenty_one}, {"b", twenty_one}]
|
||||
|
||||
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"),
|
||||
@@ -242,19 +371,56 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
|
||||
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 python_node.source == "[ call_concept(__o_01__, x=x) for x in __o_00__ ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
assert "__o_01__" in python_node.objects
|
||||
|
||||
concept0 = python_node.objects["__o_00__"]
|
||||
concept0 = python_node.objects["__o_01__"]
|
||||
assert sheerka.isinstance(concept0, foo)
|
||||
assert concept0.get_hints().use_copy
|
||||
assert concept0.get_hints().is_evaluated
|
||||
|
||||
concept1 = python_node.objects["__o_01__"]
|
||||
concept1 = python_node.objects["__o_00__"]
|
||||
assert sheerka.isinstance(concept1, "colors")
|
||||
|
||||
assert set(self.eval(context, ret[0])) == {red, blue}
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_target_is_the_name_of_a_concept_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 color for color 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_01__, x=color) for color in __o_00__ ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
assert "__o_01__" in python_node.objects
|
||||
|
||||
concept0 = python_node.objects["__o_01__"]
|
||||
assert sheerka.isinstance(concept0, foo)
|
||||
assert concept0.get_hints().use_copy
|
||||
assert concept0.get_hints().is_evaluated
|
||||
|
||||
concept1 = python_node.objects["__o_00__"]
|
||||
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}
|
||||
|
||||
@@ -264,7 +430,8 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
"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")
|
||||
Concept("x starts with y", body="x.name.startswith(y)", pre="is_question()").def_var("x").def_var("y"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, red, color)
|
||||
@@ -284,7 +451,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
|
||||
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 python_node.source == "[ call_concept(__o_02__, x=x) for x in __o_00__ if evaluate_question(__o_01__, x=x) ]"
|
||||
assert "__o_00__" in python_node.objects
|
||||
assert "__o_01__" in python_node.objects
|
||||
assert "__o_02__" in python_node.objects
|
||||
@@ -312,15 +479,15 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
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"}
|
||||
assert python_node.source == '[ call_concept(__o_04__, x=a) for a in __o_00__ if evaluate_question(__o_02__, x=a) ]'
|
||||
assert object_to_compare == {"__o_04__": "foo x", "__o_00__": "colors", "__o_02__": "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"}
|
||||
assert python_node.source == '[ call_concept(__o_05__, y=a) for a in __o_01__ if evaluate_question(__o_03__, y=a) ]'
|
||||
assert object_to_compare == {"__o_05__": "foo y", "__o_01__": "colors", "__o_03__": "bar y"}
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_missing_concept_parameter(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
@@ -339,7 +506,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
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):
|
||||
def test_i_can_compile_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' ]"
|
||||
@@ -359,7 +526,66 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert self.eval(context, ret[0]) == [("a", "c")]
|
||||
|
||||
def test_i_can_compile_and_when_multiple_results(self):
|
||||
def test_i_can_compile_list_comprehension_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")]
|
||||
|
||||
def test_i_can_compile_list_comprehension_when_multiple_targets(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x y", body="(x, y)").def_var("x").def_var("y")
|
||||
).unpack()
|
||||
|
||||
items = {"one": 1, "two": 2}
|
||||
sheerka.add_to_short_term_memory(None, "items", items)
|
||||
|
||||
expression = "[ foo x y for x, y in items.items() ]"
|
||||
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, y=y) for x, y in items.items() ]"
|
||||
assert "__o_00__" 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
|
||||
|
||||
assert self.eval(context, ret[0]) == [("one", 1), ("two", 2)]
|
||||
|
||||
def test_i_can_compile_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"),
|
||||
@@ -393,30 +619,118 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
|
||||
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")
|
||||
def test_i_can_compile_function_of_function(self):
|
||||
sheerka, context, one, two = self.init_test().with_concepts(
|
||||
Concept("one"),
|
||||
Concept("two"),
|
||||
).unpack()
|
||||
|
||||
expression = "[ w, foo w for w in ['a', 'b'] ]"
|
||||
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
|
||||
expression = "func(func1(func2(one, two)), 'foo')"
|
||||
node = self.get_expr_node(context, expression)
|
||||
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
|
||||
assert python_node.source == "func(func1(func2(__o_00__, __o_01__)), 'foo')"
|
||||
|
||||
concept = python_node.objects["__o_00__"]
|
||||
assert sheerka.isinstance(concept, foo)
|
||||
assert concept.get_hints().use_copy
|
||||
assert concept.get_hints().is_evaluated
|
||||
def test_i_can_compile_function_when_keyword_parameters(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo x", body="x").def_var("x")).unpack()
|
||||
|
||||
assert self.eval(context, ret[0]) == [("a", "a"), ("b", "b")]
|
||||
def func(**kwargs):
|
||||
# Uncomment to test that PythonEvalutor tests until success
|
||||
# if not isinstance(kwargs["y"], str):
|
||||
# raise Exception()
|
||||
return kwargs
|
||||
|
||||
sheerka.add_to_short_term_memory(None, "func", func)
|
||||
|
||||
expression = "func(x=5, y=foo 'a')"
|
||||
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 == "func(x=5, y=__o_00__)"
|
||||
assert python_node.objects["__o_00__"].name == "foo x"
|
||||
|
||||
res = self.eval(context, ret[0])
|
||||
assert res["x"] == 5
|
||||
assert sheerka.isinstance(res["y"], foo)
|
||||
assert res["y"].body == "a"
|
||||
|
||||
def test_i_can_compile_function_when_keyword_parameters_and_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()
|
||||
|
||||
def func(**kwargs):
|
||||
return kwargs
|
||||
|
||||
sheerka.add_to_short_term_memory(None, "func", func)
|
||||
|
||||
expression = "func(foo 'a', y=bar 'b')"
|
||||
|
||||
node = self.get_expr_node(context, expression)
|
||||
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 == "func(__o_00__, y=__o_02__)"
|
||||
assert object_to_compare == {"__o_00__": "foo x", "__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 == "func(__o_01__, y=__o_03__)"
|
||||
assert object_to_compare == {"__o_01__": "foo y", "__o_03__": "bar y"}
|
||||
|
||||
def test_i_can_compile_sequence_with_function_call(self):
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts(
|
||||
Concept("foo x", body="f'x={x}'").def_var("x"),
|
||||
Concept("x bar", body="x").def_var("x"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
def func(x):
|
||||
return x + 1
|
||||
|
||||
sheerka.add_to_short_term_memory(None, "func", func)
|
||||
|
||||
expression = "foo func(self)"
|
||||
|
||||
node = self.get_expr_node(context, expression, parser=FunctionParser(strict=False))
|
||||
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 == "call_concept(__o_00__, x=func(self))"
|
||||
assert python_node.objects["__o_00__"].name == "foo x"
|
||||
|
||||
assert self.eval(context, ret[0], {"self": 1}) == "x=2"
|
||||
|
||||
def test_i_cannot_compile_function_when_invalid_keyword_parameters(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
expression = "func(x=5=2)"
|
||||
node = self.get_expr_node(context, expression)
|
||||
visitor = PythonExprVisitor(context)
|
||||
|
||||
with pytest.raises(SyntaxError):
|
||||
visitor.compile(node)
|
||||
@@ -1,12 +1,13 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.builtin_helpers import ensure_asts
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import SyaAssociativity
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
from core.sheerka.services.SheerkaAdmin import SheerkaAdmin
|
||||
from sheerkapython.python_wrapper import Expando, create_namespace, inject_context, get_sheerka_method, Pipe, \
|
||||
MethodAccessError
|
||||
from sheerkapython.python_wrapper import Expando, MethodAccessError, Pipe, create_namespace, get_sheerka_method, \
|
||||
get_variables_from_concept_asts, inject_context
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@@ -135,6 +136,27 @@ class TestPythonWrapper(TestUsingMemoryBasedSheerka):
|
||||
res = create_namespace(context, "TestPythonWrapper", ["foo"], None, objects, False)
|
||||
assert res == {"foo": objects["foo"]}
|
||||
|
||||
def test_external_value_takes_precedence_over_concept_parameter(self):
|
||||
"""
|
||||
To manage :
|
||||
Concept("x is a y").def_var("x").def_var("y"),
|
||||
"y is a number" -> "call_concept(__o_00__, x=y)"
|
||||
If 'y' is not given, it will use the concept parameter 'y'
|
||||
But if y is given (as a short term memory) it must be prioritized
|
||||
:return:
|
||||
"""
|
||||
sheerka, context = self.init_test().unpack()
|
||||
obj = Concept("x is a y").def_var("x").def_var("y", "concept value").auto_init()
|
||||
context.obj = obj
|
||||
objects = {"y": "object value"}
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["y"], None, objects, False)
|
||||
assert res == {'y': 'concept value'}
|
||||
|
||||
context.add_to_short_term_memory("y", "stm value")
|
||||
res = create_namespace(context, "TestPythonWrapper", ["y"], None, objects, False)
|
||||
assert res == {'y': 'stm value'}
|
||||
|
||||
def test_i_can_get_sheerka_method(self):
|
||||
context = self.get_context()
|
||||
|
||||
@@ -167,3 +189,28 @@ class TestPythonWrapper(TestUsingMemoryBasedSheerka):
|
||||
|
||||
res = get_sheerka_method(context, "TestPythonWrapper", "where", True)
|
||||
assert isinstance(res, Pipe)
|
||||
|
||||
@pytest.mark.parametrize("concept, known_variables, expected", [
|
||||
(Concept("foo").def_var("x", "True"), set(), {}),
|
||||
(Concept("foo").def_var("x"), set(), {}),
|
||||
(Concept("foo").def_var("x", "self"), set(), {"x": {"self"}}),
|
||||
(Concept("foo").def_var("x", "self + a"), set(), {"x": {"self", "a"}}),
|
||||
(Concept("foo").def_var("x", "self + a").def_var("y", "b"), set(), {'x': {'a', 'self'}, 'y': {'b'}}),
|
||||
(Concept("foo", body="x").def_var("x"), set(), {}), # 'x' is a concept var, so it can be resolved
|
||||
(Concept("foo", body="x").def_var("x", "x"), set(), {'x': {'x'}}),
|
||||
(Concept("foo").def_var("x", "func(y)"), set(), {"x": {"y"}}),
|
||||
(Concept("foo").def_var("x", "x"), set(), {'x': {'x'}}),
|
||||
(Concept("foo").def_var("x", "y"), set(), {'x': {'y'}}),
|
||||
(Concept("foo").def_var("x", "x"), {"x"}, {"x": {"x"}}),
|
||||
(Concept("foo").def_var("x"), {"x"}, {}), # var x has no value, there no way to link the two 'x's
|
||||
(Concept("foo", body="x").def_var("x"), {"x"}, {"#body#": {"x"}}),
|
||||
(Concept("foo").def_var("x", "bar"), set(), {}),
|
||||
(Concept("foo").def_var("x", "bar"), {"bar"}, {"x": {"bar"}}),
|
||||
])
|
||||
def test_get_variables_from_concept_asts(self, concept, known_variables, expected):
|
||||
sheerka, context, foo, bar = self.init_concepts(concept, "bar")
|
||||
|
||||
ensure_asts(context, concept)
|
||||
variables = get_variables_from_concept_asts(context, concept, known_variables, parameters_only=False)
|
||||
|
||||
assert variables == expected
|
||||
|
||||
Reference in New Issue
Block a user