Fixed #49 : ExpressionParser: Implement ExpressionParser
This commit is contained in:
@@ -2,7 +2,7 @@ import ast
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
||||
from core.concept import Concept, DEFINITION_TYPE_DEF, DoNotResolve
|
||||
from core.global_symbols import RULE_COMPARISON_CONTEXT, NotFound, EVENT_RULE_DELETED
|
||||
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
|
||||
@@ -21,6 +21,7 @@ from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkarete.common import V
|
||||
from sheerkarete.conditions import Condition, AndConditions
|
||||
from sheerkarete.network import ReteNetwork
|
||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, get_test_obj, get_rete_conditions
|
||||
@@ -1029,7 +1030,7 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
),
|
||||
])
|
||||
def test_i_can_get_rete_conditions(self, expression, expected_as_str):
|
||||
sheerka, context, = self.init_test().unpack()
|
||||
sheerka, context = self.init_test().unpack()
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
|
||||
@@ -1041,7 +1042,142 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
visitor = ReteConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert conditions == expected
|
||||
assert conditions == [expected]
|
||||
|
||||
# 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 = conditions
|
||||
network.add_rule(rule)
|
||||
|
||||
network.add_obj("__ret", ReturnValueConcept("Test", True, None))
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
@pytest.mark.parametrize("test_name, expression, variable_name, expected_as_str", [
|
||||
(
|
||||
"recognize by name",
|
||||
"recognize(__ret.body, greetings)",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'"]
|
||||
),
|
||||
(
|
||||
"recognize by id",
|
||||
"recognize(__ret.body, c:|1001:)",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|id|'1001'"]
|
||||
),
|
||||
(
|
||||
"recognize by name using c_str",
|
||||
"recognize(__ret.body, c:greetings:)",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and variable sheerka",
|
||||
"recognize(__ret.body, greetings, a=sheerka)",
|
||||
"sheerka",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'__sheerka__'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and str variable",
|
||||
"recognize(__ret.body, greetings, a='my friend')",
|
||||
"'my friend'",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'my friend'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and concept variable",
|
||||
"recognize(__ret.body, greetings, a=foo)",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a.name|'foo'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and add other conditions (str)",
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == 'my friend'",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'my friend'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and add other conditions (sheerka)",
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == sheerka",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'kodjo'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and add other conditions (concept)",
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == foo",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'kodjo'"]
|
||||
),
|
||||
])
|
||||
def test_i_can_get_rete_conditions_from_recognized(self, test_name, expression, variable_name, expected_as_str):
|
||||
sheerka, context, greetings, foo = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
).unpack()
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = ReteConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert conditions == [expected]
|
||||
|
||||
# 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 = conditions
|
||||
network.add_rule(rule)
|
||||
|
||||
variable = foo if variable_name == "foo" else variable_name
|
||||
to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable)
|
||||
network.add_obj("__ret", ReturnValueConcept("Test", True, to_recognize))
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
|
||||
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||
|
||||
@@ -8,13 +8,14 @@ from core.concept import Concept, ConceptParts, DoNotResolve, AllConceptParts
|
||||
from core.rule import Rule
|
||||
from core.tokenizer import Tokenizer, TokenKind, Token
|
||||
from core.utils import get_text_from_tokens, tokens_index, str_concept
|
||||
from parsers.BaseExpressionParser import NameExprNode, AndNode, OrNode, NotNode, VariableNode, ComparisonNode, \
|
||||
ComparisonType, \
|
||||
FunctionParameter
|
||||
from parsers.BaseNodeParser import UnrecognizedTokensNode, SourceCodeNode, RuleNode, ConceptNode, \
|
||||
SourceCodeWithConceptNode
|
||||
from parsers.FunctionParser import FunctionNode
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.SyaNodeParser import SyaConceptParserHelper
|
||||
from parsers.BaseExpressionParser import NameExprNode, AndNode, OrNode, NotNode, VariableNode, ComparisonNode, ComparisonType, \
|
||||
FunctionParameter
|
||||
from sheerkarete.common import V
|
||||
from sheerkarete.conditions import Condition, AndConditions
|
||||
|
||||
@@ -1304,17 +1305,22 @@ def get_rete_conditions(*conditions_as_string):
|
||||
"identifier|__name__|'True'" -> Condition(identifier, '__name__', 'True') # the string 'True'
|
||||
"identifier|__name__|True" -> Condition(identifier, '__name__', True) # the bool True
|
||||
"""
|
||||
|
||||
def get_value(obj):
|
||||
if obj.startswith("#"):
|
||||
return V(obj[1:])
|
||||
if obj.startswith("'"):
|
||||
return obj[1:-1]
|
||||
if obj in ("True", "False"):
|
||||
return obj == "True"
|
||||
return int(obj)
|
||||
|
||||
res = []
|
||||
for as_string in conditions_as_string:
|
||||
identifier, attribute, value = as_string.split("|")
|
||||
if identifier.startswith("#"):
|
||||
identifier = V(identifier[1:])
|
||||
if value.startswith("'"):
|
||||
value = value[1:-1]
|
||||
elif value in ("True", "False"):
|
||||
value = (value == "True")
|
||||
else:
|
||||
value = int(value)
|
||||
parts = as_string.split("|")
|
||||
identifier = get_value(parts[0])
|
||||
attribute = parts[1]
|
||||
value = get_value(parts[2])
|
||||
|
||||
res.append(Condition(identifier, attribute, value))
|
||||
return AndConditions(res)
|
||||
|
||||
@@ -56,6 +56,7 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
("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")]))),
|
||||
("__ret", VAR("__ret")),
|
||||
#("func1().func2()", [])
|
||||
])
|
||||
def test_i_can_parse_input(self, expression, expected):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
|
||||
@@ -65,16 +65,28 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
|
||||
assert len(network.pnodes) == 1
|
||||
assert network.pnodes[0].rules == [rule1, rule2]
|
||||
|
||||
def test_i_can_update_conditions_attributes_by_id_when_constraint_on__name__(self):
|
||||
def test_i_can_update_conditions_attributes_by_id_when_constraints(self):
|
||||
network = ReteNetwork()
|
||||
conditions = [Condition(V("x"), "__name__", "fact_name"),
|
||||
Condition(V("x"), "attr1", "value1"),
|
||||
Condition(V("x"), "attr2", "value1")]
|
||||
Condition(V("x"), "body", V("y")),
|
||||
Condition(V("y"), "__is_concept__", True),
|
||||
Condition(V("y"), "name", "SubConcept"),
|
||||
Condition(V("x"), "value", V("z")),
|
||||
Condition(V("z"), "status", False),
|
||||
Condition(V("z"), "body", V("zz")),
|
||||
Condition(V("zz"), "sub_value", "sub_value"),
|
||||
]
|
||||
|
||||
rule = RuleForTestingRete(AndConditions(conditions))
|
||||
network.add_rule(rule)
|
||||
|
||||
assert network.attributes_by_id == {"fact_name": ["__name__", "attr1", "attr2"]}
|
||||
assert network.attributes_by_id == {
|
||||
"fact_name": ["__name__", "attr1", "body", "value"],
|
||||
"fact_name.body": ["__is_concept__", "name"],
|
||||
"fact_name.value": ["status", "body"],
|
||||
"fact_name.value.body": ["sub_value"],
|
||||
}
|
||||
|
||||
def test_adding_obj_when_no_rule_has_no_effect(self):
|
||||
network = ReteNetwork()
|
||||
@@ -193,20 +205,11 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
|
||||
WME("f-00000", "__name__", "__ret"),
|
||||
WME("f-00000", "status", True),
|
||||
WME("f-00000", "body", "f-00000.body"),
|
||||
WME("f-00000.body", "id", "1003"),
|
||||
WME("f-00000.body", "name", "greetings"),
|
||||
WME("f-00000.body", "key", "hello __var__0"),
|
||||
WME("f-00000.body", "a", "f-00000.body.a"),
|
||||
WME("f-00000.body", "self", ret.body),
|
||||
WME("f-00000.body.a", "id", "1002"),
|
||||
WME("f-00000.body.a", "name", "the x"),
|
||||
WME("f-00000.body.a", "key", "the __var__0"),
|
||||
WME("f-00000.body.a", "x", "f-00000.body.a.x"),
|
||||
WME("f-00000.body.a", "self", the_boy),
|
||||
WME("f-00000.body.a.x", "id", "1001"),
|
||||
WME("f-00000.body.a.x", "name", "boy"),
|
||||
WME("f-00000.body.a.x", "key", "boy"),
|
||||
WME("f-00000.body.a.x", "self", boy),
|
||||
}
|
||||
|
||||
# sanity check that the WME produced match the condition
|
||||
@@ -649,7 +652,8 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
|
||||
assert len(rule.rete_p_nodes) > 0
|
||||
|
||||
def test_format_rule_is_not_added_to_rete_network_when_it_is_created(self):
|
||||
sheerka, context, rule = self.init_test().with_format_rules(("rule_name", "id.attr == 'value'", 'True')).unpack()
|
||||
sheerka, context, rule = self.init_test().with_format_rules(
|
||||
("rule_name", "id.attr == 'value'", 'True')).unpack()
|
||||
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
rete_network = evaluation_service.network
|
||||
|
||||
|
||||
Reference in New Issue
Block a user