Fixed #48 : RelationalExpressionParser: Implement relational operator parser
Fixed #49 : ExpressionParser: Implement ExpressionParser Fixed #50 : Implement ReteConditionExprVisitor Fixed #51 : Implement PythonConditionExprVisitor Fixed #52 : SheerkaConceptManager: I can get and set concept property
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import ast
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Union
|
||||
from typing import Union, List
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept
|
||||
from core.builtin_helpers import CreateObjectIdentifiers
|
||||
@@ -18,7 +17,7 @@ from parsers.FunctionParser import FunctionNode
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.SyaNodeParser import SyaConceptParserHelper
|
||||
from sheerkarete.common import V
|
||||
from sheerkarete.conditions import Condition, AndConditions
|
||||
from sheerkarete.conditions import Condition, AndConditions, NegatedCondition, NegatedConjunctiveConditions
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -933,6 +932,16 @@ class FN:
|
||||
raise NotImplementedError(f"FN, {other=}")
|
||||
|
||||
|
||||
@dataclass()
|
||||
class NEGCOND:
|
||||
condition: str
|
||||
|
||||
|
||||
@dataclass()
|
||||
class NCCOND:
|
||||
conditions: List[str]
|
||||
|
||||
|
||||
comparison_type_mapping = {
|
||||
"EQ": ComparisonType.EQUALS,
|
||||
"NEQ": ComparisonType.NOT_EQUAlS,
|
||||
@@ -1295,10 +1304,10 @@ def resolve_test_concept(concept_map, hint):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def get_rete_conditions(*conditions_as_string):
|
||||
def get_rete_conditions(*conditions):
|
||||
"""
|
||||
Transform a list of string into a list of Condition (Rete conditions)
|
||||
:param conditions_as_string: conditions in the form 'identifier|attribute|value'
|
||||
:param conditions: conditions in the form 'identifier|attribute|value'
|
||||
when one argument starts with "#" it means that it's a variables
|
||||
ex : "#__x_00__|__name__|'__ret'" -> Condition(V('#__x_00__'), '__name__', '__ret')
|
||||
|
||||
@@ -1317,13 +1326,17 @@ def get_rete_conditions(*conditions_as_string):
|
||||
return int(obj)
|
||||
|
||||
res = []
|
||||
for as_string in conditions_as_string:
|
||||
if as_string.startswith("$"):
|
||||
fn_match = re.match(r"(?P<function>\w+)\s?\((?P<args>.+)\)", as_string[1:])
|
||||
as_dict = fn_match.groupdict()
|
||||
pass
|
||||
for cond in conditions:
|
||||
if isinstance(cond, Condition):
|
||||
res.append(cond)
|
||||
elif isinstance(cond, NEGCOND):
|
||||
inner_cond = get_rete_conditions(cond.condition).conditions[0]
|
||||
res.append(NegatedCondition(inner_cond.identifier, inner_cond.attribute, inner_cond.value))
|
||||
elif isinstance(cond, NCCOND):
|
||||
inner_conds = get_rete_conditions(*cond.conditions).conditions
|
||||
res.append(NegatedConjunctiveConditions(*inner_conds))
|
||||
else:
|
||||
parts = as_string.split("|")
|
||||
parts = cond.split("|")
|
||||
identifier = get_value(parts[0])
|
||||
attribute = parts[1]
|
||||
value = get_value(parts[2])
|
||||
|
||||
@@ -3,7 +3,7 @@ import pytest
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaRuleManager import RuleCompiledPredicate, FormatAstNode
|
||||
from core.sheerka.services.SheerkaRuleManager import FormatAstNode, CompiledCondition
|
||||
from core.tokenizer import Tokenizer, Keywords
|
||||
from core.utils import tokens_are_matching
|
||||
from parsers.BaseCustomGrammarParser import KeywordNotFound, NameNode, SyntaxErrorNode
|
||||
@@ -80,9 +80,9 @@ class TestDefRuleParser(TestUsingMemoryBasedSheerka):
|
||||
assert len(parsed.tokens) == 2
|
||||
assert tokens_are_matching(parsed.tokens[Keywords.WHEN], Tokenizer("when True"))
|
||||
assert tokens_are_matching(parsed.tokens[Keywords.THEN], Tokenizer("then answer('that is true')"))
|
||||
assert isinstance(parsed.when, list)
|
||||
assert len(parsed.when) == 1
|
||||
assert isinstance(parsed.when[0], RuleCompiledPredicate)
|
||||
assert isinstance(parsed.python, list)
|
||||
assert len(parsed.python) == 1
|
||||
assert isinstance(parsed.python[0], CompiledCondition)
|
||||
assert sheerka.isinstance(parsed.then, BuiltinConcepts.RETURN_VALUE)
|
||||
|
||||
def test_i_can_parse_simple_format_rule_definition(self):
|
||||
@@ -100,9 +100,9 @@ class TestDefRuleParser(TestUsingMemoryBasedSheerka):
|
||||
assert len(parsed.tokens) == 2
|
||||
assert tokens_are_matching(parsed.tokens[Keywords.WHEN], Tokenizer("when True"))
|
||||
assert tokens_are_matching(parsed.tokens[Keywords.PRINT], Tokenizer("print hello world!"))
|
||||
assert isinstance(parsed.when, list)
|
||||
assert len(parsed.when) == 1
|
||||
assert isinstance(parsed.when[0], RuleCompiledPredicate)
|
||||
assert isinstance(parsed.python, list)
|
||||
assert len(parsed.python) == 1
|
||||
assert isinstance(parsed.python[0], CompiledCondition)
|
||||
assert isinstance(parsed.print, FormatAstNode)
|
||||
|
||||
def test_i_can_parse_exec_rule_with_name(self):
|
||||
@@ -121,36 +121,38 @@ class TestDefRuleParser(TestUsingMemoryBasedSheerka):
|
||||
assert len(parsed.tokens) == 2
|
||||
assert tokens_are_matching(parsed.tokens[Keywords.WHEN], Tokenizer("when True"))
|
||||
assert tokens_are_matching(parsed.tokens[Keywords.THEN], Tokenizer("then answer('that is true')"))
|
||||
assert isinstance(parsed.when, list)
|
||||
assert len(parsed.when) == 1
|
||||
assert isinstance(parsed.when[0], RuleCompiledPredicate)
|
||||
assert isinstance(parsed.python, list)
|
||||
assert len(parsed.python) == 1
|
||||
assert isinstance(parsed.python[0], CompiledCondition)
|
||||
assert sheerka.isinstance(parsed.then, BuiltinConcepts.RETURN_VALUE)
|
||||
|
||||
@pytest.mark.skip("Not ready for that")
|
||||
def test_when_is_parsed_in_the_context_of_a_question(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "when foo is a bar print hello world"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
format_rule = res.body.body
|
||||
rules = format_rule.when
|
||||
rules = format_rule.python
|
||||
|
||||
assert res.status
|
||||
assert len(rules) == 1
|
||||
assert isinstance(rules[0], RuleCompiledPredicate)
|
||||
assert rules[0].predicate.body.body.get_metadata().pre == "is_question()"
|
||||
assert isinstance(rules[0], CompiledCondition)
|
||||
assert rules[0].return_value.body.body.get_metadata().pre == "is_question()"
|
||||
|
||||
@pytest.mark.skip("Not ready for that")
|
||||
def test_when_can_support_multiple_possibilities_when_question_only(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
text = "when foo is good print hello world"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
format_rule = res.body.body
|
||||
rules = format_rule.when
|
||||
rules = format_rule.python
|
||||
|
||||
assert res.status
|
||||
assert len(rules) == 2
|
||||
assert rules[0].predicate.body.body.get_metadata().name == "a is good"
|
||||
assert rules[1].predicate.body.body.get_metadata().name == "b is good"
|
||||
assert rules[0].return_value.body.body.get_metadata().name == "a is good"
|
||||
assert rules[1].return_value.body.body.get_metadata().name == "b is good"
|
||||
|
||||
@pytest.mark.parametrize("text, error", [
|
||||
("def", [KeywordNotFound(None, keywords=['rule'])]),
|
||||
@@ -175,7 +177,7 @@ class TestDefRuleParser(TestUsingMemoryBasedSheerka):
|
||||
assert not_for_me.reason == error
|
||||
|
||||
@pytest.mark.parametrize("text, expected_error", [
|
||||
("when x x print 'hello world'", BuiltinConcepts.TOO_MANY_ERRORS),
|
||||
("when x x = False print 'hello world'", BuiltinConcepts.ERROR),
|
||||
|
||||
])
|
||||
def test_i_can_detect_errors(self, text, expected_error):
|
||||
|
||||
@@ -95,10 +95,13 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("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'"),
|
||||
|
||||
])
|
||||
def test_i_can_rebuild_source(self, expression, expected):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
assert ComparisonNode.rebuild_source("new_var", parsed.comp, parsed.right.get_source()) == expected
|
||||
new_source = ComparisonNode.rebuild_source("new_var", parsed.comp, parsed.right.get_source())
|
||||
assert new_source == expected
|
||||
|
||||
Reference in New Issue
Block a user