Fixed #49 : I can recognize concept
This commit is contained in:
@@ -9,7 +9,7 @@ from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
|||||||
from core.builtin_helpers import is_a_question, ensure_evaluated, expect_one, evaluate
|
from core.builtin_helpers import is_a_question, ensure_evaluated, expect_one, evaluate
|
||||||
from core.concept import Concept
|
from core.concept import Concept
|
||||||
from core.global_symbols import EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound, ErrorObj, \
|
from core.global_symbols import EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound, ErrorObj, \
|
||||||
EVENT_RULE_CREATED, EVENT_RULE_DELETED
|
EVENT_RULE_CREATED, EVENT_RULE_DELETED, NotInit
|
||||||
from core.rule import Rule, ACTION_TYPE_PRINT
|
from core.rule import Rule, ACTION_TYPE_PRINT
|
||||||
from core.sheerka.Sheerka import RECOGNIZED_BY_NAME, RECOGNIZED_BY_ID
|
from core.sheerka.Sheerka import RECOGNIZED_BY_NAME, RECOGNIZED_BY_ID
|
||||||
from core.sheerka.services.sheerka_service import BaseService, FailedToCompileError
|
from core.sheerka.services.sheerka_service import BaseService, FailedToCompileError
|
||||||
@@ -25,6 +25,7 @@ from sheerkarete.common import V
|
|||||||
from sheerkarete.conditions import AndConditions, Condition
|
from sheerkarete.conditions import AndConditions, Condition
|
||||||
|
|
||||||
CONCEPTS_ONLY_PARSERS = ["ExactConcept", "Bnf", "Sya", "Sequence"]
|
CONCEPTS_ONLY_PARSERS = ["ExactConcept", "Bnf", "Sya", "Sequence"]
|
||||||
|
CONDITIONS_VISITOR_EVALUATORS = ["Python", "Concept"]
|
||||||
|
|
||||||
identifier_regex = re.compile(r"[\w _.]+")
|
identifier_regex = re.compile(r"[\w _.]+")
|
||||||
|
|
||||||
@@ -1134,31 +1135,31 @@ class ReteConditionExprVisitor(ExpressionVisitor):
|
|||||||
self.variables[target] = var_name
|
self.variables[target] = var_name
|
||||||
return var_name
|
return var_name
|
||||||
|
|
||||||
def init_or_get_variable_from_name(self, node: VariableNode, conditions):
|
def init_or_get_variable_from_name(self, variable_path: List[str], conditions):
|
||||||
|
|
||||||
if node.attributes:
|
if len(variable_path) > 1:
|
||||||
left = node.attributes[:-1]
|
left = variable_path[:-1]
|
||||||
right = [node.attributes[-1]]
|
right = [variable_path[-1]]
|
||||||
|
|
||||||
while left:
|
while left:
|
||||||
var_name = node.name + "." + ".".join(left)
|
var_name = ".".join(left)
|
||||||
if var_name in self.variables:
|
if var_name in self.variables:
|
||||||
return V(self.variables[var_name]), ".".join(right)
|
return V(self.variables[var_name]), ".".join(right)
|
||||||
|
|
||||||
right.insert(0, left.pop())
|
right.insert(0, left.pop())
|
||||||
|
|
||||||
if node.name not in self.variables:
|
if variable_path[0] not in self.variables:
|
||||||
var_name = self.add_variable(node.name)
|
var_name = self.add_variable(variable_path[0])
|
||||||
conditions.append(Condition(V(var_name), "__name__", node.name))
|
conditions.append(Condition(V(var_name), "__name__", variable_path[0]))
|
||||||
|
|
||||||
return V(self.variables[node.name]), node.attributes_str
|
return V(self.variables[variable_path[0]]), ".".join(variable_path[1:])
|
||||||
|
|
||||||
def init_or_get_variable_from_attr(self, node: VariableNode, conditions):
|
def init_or_get_variable_from_attr(self, variable_path: List[str], conditions):
|
||||||
path = f"{node.name}.{node.attributes_str}"
|
path = ".".join(variable_path)
|
||||||
if path in self.variables:
|
if path in self.variables:
|
||||||
return self.variables[path]
|
return self.variables[path]
|
||||||
|
|
||||||
root, attr = self.init_or_get_variable_from_name(node, conditions)
|
root, attr = self.init_or_get_variable_from_name(variable_path, conditions)
|
||||||
var_name = self.add_variable(path)
|
var_name = self.add_variable(path)
|
||||||
variable = V(var_name)
|
variable = V(var_name)
|
||||||
conditions.append(Condition(root, attr, variable))
|
conditions.append(Condition(root, attr, variable))
|
||||||
@@ -1173,7 +1174,7 @@ class ReteConditionExprVisitor(ExpressionVisitor):
|
|||||||
|
|
||||||
def visit_VariableNode(self, expr_node):
|
def visit_VariableNode(self, expr_node):
|
||||||
conditions = []
|
conditions = []
|
||||||
var_name, attr = self.init_or_get_variable_from_name(expr_node, conditions)
|
var_name, attr = self.init_or_get_variable_from_name(expr_node.unpack(), conditions)
|
||||||
if expr_node.attributes_str is not None:
|
if expr_node.attributes_str is not None:
|
||||||
conditions.append(Condition(var_name, attr, True))
|
conditions.append(Condition(var_name, attr, True))
|
||||||
return conditions
|
return conditions
|
||||||
@@ -1188,11 +1189,9 @@ class ReteConditionExprVisitor(ExpressionVisitor):
|
|||||||
def visit_ComparisonNode(self, expr_node: ComparisonNode):
|
def visit_ComparisonNode(self, expr_node: ComparisonNode):
|
||||||
if isinstance(expr_node.left, VariableNode):
|
if isinstance(expr_node.left, VariableNode):
|
||||||
conditions = []
|
conditions = []
|
||||||
left, attr = self.init_or_get_variable_from_name(expr_node.left, conditions)
|
|
||||||
|
|
||||||
res = evaluate(self.context,
|
res = evaluate(self.context,
|
||||||
expr_node.right.get_source(),
|
expr_node.right.get_source(),
|
||||||
evaluators="all", # TODO: all is too much
|
evaluators=CONDITIONS_VISITOR_EVALUATORS,
|
||||||
desc=None,
|
desc=None,
|
||||||
eval_body=False,
|
eval_body=False,
|
||||||
eval_where=False,
|
eval_where=False,
|
||||||
@@ -1203,59 +1202,78 @@ class ReteConditionExprVisitor(ExpressionVisitor):
|
|||||||
if not res.status:
|
if not res.status:
|
||||||
return FailedToCompileError([f"Cannot recognize '{expr_node.right.get_source()}'"])
|
return FailedToCompileError([f"Cannot recognize '{expr_node.right.get_source()}'"])
|
||||||
|
|
||||||
value = res.value
|
self.add_to_condition(expr_node.left.unpack(), res.value, conditions)
|
||||||
if (isinstance(value, Expando) and value.get_name() == "sheerka" or
|
|
||||||
isinstance(value, Concept) and value.id == self.context.sheerka.id):
|
|
||||||
conditions.append(Condition(left, attr, "__sheerka__"))
|
|
||||||
else:
|
|
||||||
conditions.append(Condition(left, attr, res.value))
|
|
||||||
return conditions
|
return conditions
|
||||||
else:
|
else:
|
||||||
raise FailedToCompileError([expr_node])
|
raise FailedToCompileError([expr_node])
|
||||||
|
|
||||||
def visit_FunctionNode(self, expr_node: FunctionNode):
|
def visit_FunctionNode(self, expr_node: FunctionNode):
|
||||||
if expr_node.first.value == "recognize(":
|
if expr_node.first.value == "recognize(":
|
||||||
return self.function_recognize_concept(expr_node.parameters[0].value,
|
if not isinstance(expr_node.parameters[0].value, VariableNode):
|
||||||
expr_node.parameters[1].value,
|
return FailedToCompileError([f"Cannot recognize '{expr_node.parameters[0].value}'"])
|
||||||
[p.value for p in expr_node.parameters[2:]])
|
|
||||||
|
|
||||||
def function_recognize_concept(self, variable_path, concept_to_recognize, parameters):
|
return self.recognize_concept(expr_node.parameters[0].value.unpack(),
|
||||||
|
expr_node.parameters[1].value,
|
||||||
|
{})
|
||||||
|
|
||||||
|
def recognize_concept(self, variable_path, concept_to_recognize, concept_variables: dict):
|
||||||
"""
|
"""
|
||||||
Creates Rete conditions to recognize a concept
|
Creates Rete conditions to recognize a concept
|
||||||
:param variable_path: variable holding the information
|
:param variable_path: variable holding the information
|
||||||
:param concept_to_recognize: concept to recognize
|
:param concept_to_recognize: concept to recognize
|
||||||
:param parameters: concept variables values
|
:param concept_variables: concept variables values
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
concept_as_str = concept_to_recognize.get_source()
|
if not isinstance(concept_to_recognize, Concept):
|
||||||
if not concept_as_str:
|
concept_as_str = concept_to_recognize.get_source()
|
||||||
return FailedToCompileError([f"Missing concept in for {variable_path}"])
|
if not concept_as_str:
|
||||||
|
return FailedToCompileError([f"Missing concept in for {variable_path}"])
|
||||||
|
|
||||||
res = evaluate(self.context,
|
res = evaluate(self.context,
|
||||||
concept_as_str,
|
concept_as_str,
|
||||||
evaluators="all", # TODO: all is too much
|
evaluators=CONDITIONS_VISITOR_EVALUATORS,
|
||||||
desc=None,
|
desc=None,
|
||||||
eval_body=False,
|
eval_body=True,
|
||||||
eval_where=False,
|
eval_where=False,
|
||||||
is_question=False,
|
is_question=False,
|
||||||
expect_success=False,
|
expect_success=False,
|
||||||
stm=None)
|
stm=None)
|
||||||
res = expect_one(self.context, res)
|
res = expect_one(self.context, res)
|
||||||
|
|
||||||
if not res.status:
|
if not res.status:
|
||||||
return FailedToCompileError([f"Unknown concept {concept_as_str}"])
|
return FailedToCompileError([f"Unknown concept {concept_as_str}"])
|
||||||
|
concept = res.body
|
||||||
|
else:
|
||||||
|
concept = concept_to_recognize
|
||||||
|
|
||||||
concept_found = res.body
|
|
||||||
conditions = []
|
conditions = []
|
||||||
variable = self.init_or_get_variable_from_attr(variable_path, conditions)
|
variable = self.init_or_get_variable_from_attr(variable_path, conditions)
|
||||||
conditions.append(Condition(variable, "__is_concept__", True))
|
conditions.append(Condition(variable, "__is_concept__", True))
|
||||||
|
|
||||||
if concept_found.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_NAME:
|
if concept.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_NAME:
|
||||||
conditions.append(Condition(variable, "name", concept_found.name))
|
conditions.append(Condition(variable, "name", concept.name))
|
||||||
elif concept_found.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_ID:
|
elif concept.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_ID:
|
||||||
conditions.append(Condition(variable, "id", concept_found.id))
|
conditions.append(Condition(variable, "id", concept.id))
|
||||||
else:
|
else:
|
||||||
conditions.append(Condition(variable, "key", concept_found.key))
|
conditions.append(Condition(variable, "key", concept.key))
|
||||||
|
concept_variables.update({k: v for k, v in concept.variables().items() if v is not NotInit})
|
||||||
|
|
||||||
|
for var_name, var_value in concept_variables.items():
|
||||||
|
new_var_path = variable_path.copy()
|
||||||
|
new_var_path.append(var_name)
|
||||||
|
self.add_to_condition(new_var_path, var_value, conditions)
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
|
def add_to_condition(self, var_path, value, conditions):
|
||||||
|
left, attr = self.init_or_get_variable_from_name(var_path, conditions)
|
||||||
|
|
||||||
|
if (isinstance(value, Expando) and value.get_name() == "sheerka" or
|
||||||
|
isinstance(value, Concept) and value.id == self.context.sheerka.id):
|
||||||
|
conditions.append(Condition(left, attr, "__sheerka__"))
|
||||||
|
elif isinstance(value, Concept):
|
||||||
|
res = self.recognize_concept(var_path, value, {})
|
||||||
|
conditions.extend(res)
|
||||||
|
else:
|
||||||
|
conditions.append(Condition(left, attr, value))
|
||||||
|
|||||||
@@ -287,6 +287,9 @@ class VariableNode(ExprNode):
|
|||||||
else:
|
else:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def unpack(self):
|
||||||
|
return [self.name] + self.attributes
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ComparisonNode(ExprNode):
|
class ComparisonNode(ExprNode):
|
||||||
|
|||||||
@@ -1115,17 +1115,40 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
|||||||
"#__x_01__|name|'greetings'",
|
"#__x_01__|name|'greetings'",
|
||||||
"#__x_01__|a|#__x_02__",
|
"#__x_01__|a|#__x_02__",
|
||||||
"#__x_02__|__is_concept__|True",
|
"#__x_02__|__is_concept__|True",
|
||||||
"#__x_02__|name|'foo'"]
|
"#__x_02__|key|'foo'"]
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"recognize by instance",
|
"recognize by instance",
|
||||||
"recognize(__ret.body, hello sheerka)",
|
"recognize(__ret.body, hello sheerka)",
|
||||||
|
"sheerka",
|
||||||
|
["#__x_00__|__name__|'__ret'",
|
||||||
|
"#__x_00__|body|#__x_01__",
|
||||||
|
"#__x_01__|__is_concept__|True",
|
||||||
|
"#__x_01__|key|'hello __var__0'",
|
||||||
|
"#__x_01__|a|'__sheerka__'"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"recognize by instance",
|
||||||
|
"recognize(__ret.body, hello 'my friend')",
|
||||||
|
"my friend",
|
||||||
|
["#__x_00__|__name__|'__ret'",
|
||||||
|
"#__x_00__|body|#__x_01__",
|
||||||
|
"#__x_01__|__is_concept__|True",
|
||||||
|
"#__x_01__|key|'hello __var__0'",
|
||||||
|
"#__x_01__|a|'my friend'"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"recognize by instance",
|
||||||
|
"recognize(__ret.body, hello foo)",
|
||||||
"foo",
|
"foo",
|
||||||
["#__x_00__|__name__|'__ret'",
|
["#__x_00__|__name__|'__ret'",
|
||||||
"#__x_00__|body|#__x_01__",
|
"#__x_00__|body|#__x_01__",
|
||||||
"#__x_01__|__is_concept__|True",
|
"#__x_01__|__is_concept__|True",
|
||||||
"#__x_01__|key|'hello __var__0'",
|
"#__x_01__|key|'hello __var__0'",
|
||||||
"#__x_01__|a|__sheerka__"]
|
"#__x_01__|a|#__x_02__",
|
||||||
|
"#__x_02__|__is_concept__|True",
|
||||||
|
"#__x_02__|key|'foo'",
|
||||||
|
]
|
||||||
),
|
),
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|||||||
Reference in New Issue
Block a user