Implemented a first and basic version of a Rete rule engine
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import pytest
|
||||
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.rule import Rule, RuleMetadata
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.DefRuleEvaluator import DefRuleEvaluator
|
||||
from parsers.DefRuleParser import DefFormatRuleNode, DefRuleParser, DefExecRuleNode
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestDefRuleEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@staticmethod
|
||||
def get_ret_val_from_rule(rule_def):
|
||||
tokens = {k: list(Tokenizer(k.value + " " + v, yield_eof=False)) for k, v in rule_def.items()}
|
||||
for v in tokens.values():
|
||||
del v[1]
|
||||
|
||||
node = DefFormatRuleNode(tokens)
|
||||
return ReturnValueConcept("parsers.FormatRule", True, ParserResultConcept(value=node))
|
||||
|
||||
@pytest.mark.parametrize("ret_val, expected", [
|
||||
(ReturnValueConcept("name", True, ParserResultConcept(value=DefFormatRuleNode({}))), True),
|
||||
(ReturnValueConcept("name", True, ParserResultConcept(value=DefExecRuleNode({}))), True),
|
||||
(ReturnValueConcept("name", True, ParserResultConcept(value="other object")), False),
|
||||
(ReturnValueConcept("name", False, ParserResultConcept(value=DefFormatRuleNode({}))), False),
|
||||
(ReturnValueConcept("name", False, DefFormatRuleNode({})), False),
|
||||
])
|
||||
def test_i_can_match(self, ret_val, expected):
|
||||
context = self.get_context()
|
||||
assert DefRuleEvaluator().matches(context, ret_val) == expected
|
||||
|
||||
@pytest.mark.parametrize("text, expected_action_type, expected_name", [
|
||||
("when True print 'hello world'", "print", None),
|
||||
("when True then 'hello world'", "exec", None),
|
||||
("def rule rule name as when True print 'hello world'", "print", "rule name"),
|
||||
("def rule rule name as when True then 'hello world'", "exec", "rule name"),
|
||||
])
|
||||
def test_i_can_eval(self, text, expected_action_type, expected_name):
|
||||
sheerka, context = self.init_concepts()
|
||||
ret_val = DefRuleParser().parse(context, ParserInput(text))
|
||||
|
||||
res = DefRuleEvaluator().eval(context, ret_val)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_RULE)
|
||||
assert isinstance(res.body.body, Rule)
|
||||
assert res.body.body.metadata == RuleMetadata(expected_action_type,
|
||||
expected_name,
|
||||
"True",
|
||||
"'hello world'",
|
||||
id=res.body.body.metadata.id, # no need to compare the id
|
||||
is_compiled=True,
|
||||
is_enabled=True)
|
||||
rule = res.body.body
|
||||
assert rule.compiled_predicates is not None
|
||||
assert rule.compiled_action is not None
|
||||
assert rule.rete_disjunctions is not None
|
||||
@@ -1,51 +0,0 @@
|
||||
import pytest
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.rule import Rule, RuleMetadata
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.FormatRuleEvaluator import FormatRuleEvaluator
|
||||
from parsers.DefFormatRuleParser import FormatRuleNode, DefFormatRuleParser
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestFormatRuleEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@staticmethod
|
||||
def get_ret_val_from_rule(rule_def):
|
||||
tokens = {k: list(Tokenizer(k.value + " " + v, yield_eof=False)) for k, v in rule_def.items()}
|
||||
for v in tokens.values():
|
||||
del v[1]
|
||||
|
||||
node = FormatRuleNode(tokens)
|
||||
return ReturnValueConcept("parsers.FormatRule", True, ParserResultConcept(value=node))
|
||||
|
||||
@pytest.mark.parametrize("ret_val, expected", [
|
||||
(ReturnValueConcept("name", True, ParserResultConcept(value=FormatRuleNode({}))), True),
|
||||
(ReturnValueConcept("name", True, ParserResultConcept(value="other object")), False),
|
||||
(ReturnValueConcept("name", False, ParserResultConcept(value=FormatRuleNode({}))), False),
|
||||
(ReturnValueConcept("name", False, FormatRuleNode({})), False),
|
||||
])
|
||||
def test_i_can_match(self, ret_val, expected):
|
||||
context = self.get_context()
|
||||
assert FormatRuleEvaluator().matches(context, ret_val) == expected
|
||||
|
||||
def test_i_can_eval(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
text = "when isinstance(value, __EXPLANATION) print list(value)"
|
||||
ret_val = DefFormatRuleParser().parse(context, ParserInput(text))
|
||||
|
||||
res = FormatRuleEvaluator().eval(context, ret_val)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_RULE)
|
||||
assert isinstance(res.body.body, Rule)
|
||||
assert res.body.body.metadata == RuleMetadata("print",
|
||||
None,
|
||||
"isinstance(value, __EXPLANATION)",
|
||||
"list(value)",
|
||||
id=res.body.body.metadata.id, # no need to compare the id
|
||||
is_compiled=True,
|
||||
is_enabled=True)
|
||||
assert res.body.body.compiled_predicate is not None
|
||||
assert res.body.body.compiled_action is not None
|
||||
@@ -87,6 +87,6 @@ class TestLexerNodeEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
assert wrapper.source == "foo + 1"
|
||||
|
||||
assert return_value == PythonNode('foo + 1', ast.parse("__C__foo__C__ + 1", mode="eval"))
|
||||
assert return_value == PythonNode('__C__foo__C__ + 1', ast.parse("__C__foo__C__ + 1", mode="eval"), "foo + 1")
|
||||
assert return_value.objects == {"__C__foo__C__": foo}
|
||||
assert result.parents == [ret_val]
|
||||
|
||||
@@ -3,6 +3,7 @@ import ast
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.builtin_helpers import CreateObjectIdentifiers
|
||||
from core.concept import Concept, CB
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
@@ -26,7 +27,7 @@ def return_return_value(status):
|
||||
def get_source_code_node(source_code, concepts=None):
|
||||
if concepts:
|
||||
for concept_name, concept in sorted(concepts.items(), key=lambda kv: len(kv[0]), reverse=True):
|
||||
identifier = "__C__" + PythonWithConceptsParser.sanitize(concept.name)
|
||||
identifier = "__C__" + CreateObjectIdentifiers.sanitize(concept.name)
|
||||
if concept.id:
|
||||
identifier += "__" + concept.id
|
||||
identifier += "__C__"
|
||||
|
||||
Reference in New Issue
Block a user