Fixed #49 : I can recognize concept

This commit is contained in:
2021-03-18 16:43:00 +01:00
parent 36515aebb7
commit e1a0b2f46e
3 changed files with 95 additions and 51 deletions
+67 -49
View File
@@ -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.concept import Concept
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.sheerka.Sheerka import RECOGNIZED_BY_NAME, RECOGNIZED_BY_ID
from core.sheerka.services.sheerka_service import BaseService, FailedToCompileError
@@ -25,6 +25,7 @@ from sheerkarete.common import V
from sheerkarete.conditions import AndConditions, Condition
CONCEPTS_ONLY_PARSERS = ["ExactConcept", "Bnf", "Sya", "Sequence"]
CONDITIONS_VISITOR_EVALUATORS = ["Python", "Concept"]
identifier_regex = re.compile(r"[\w _.]+")
@@ -1134,31 +1135,31 @@ class ReteConditionExprVisitor(ExpressionVisitor):
self.variables[target] = 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:
left = node.attributes[:-1]
right = [node.attributes[-1]]
if len(variable_path) > 1:
left = variable_path[:-1]
right = [variable_path[-1]]
while left:
var_name = node.name + "." + ".".join(left)
var_name = ".".join(left)
if var_name in self.variables:
return V(self.variables[var_name]), ".".join(right)
right.insert(0, left.pop())
if node.name not in self.variables:
var_name = self.add_variable(node.name)
conditions.append(Condition(V(var_name), "__name__", node.name))
if variable_path[0] not in self.variables:
var_name = self.add_variable(variable_path[0])
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):
path = f"{node.name}.{node.attributes_str}"
def init_or_get_variable_from_attr(self, variable_path: List[str], conditions):
path = ".".join(variable_path)
if path in self.variables:
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)
variable = V(var_name)
conditions.append(Condition(root, attr, variable))
@@ -1173,7 +1174,7 @@ class ReteConditionExprVisitor(ExpressionVisitor):
def visit_VariableNode(self, expr_node):
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:
conditions.append(Condition(var_name, attr, True))
return conditions
@@ -1188,11 +1189,9 @@ class ReteConditionExprVisitor(ExpressionVisitor):
def visit_ComparisonNode(self, expr_node: ComparisonNode):
if isinstance(expr_node.left, VariableNode):
conditions = []
left, attr = self.init_or_get_variable_from_name(expr_node.left, conditions)
res = evaluate(self.context,
expr_node.right.get_source(),
evaluators="all", # TODO: all is too much
evaluators=CONDITIONS_VISITOR_EVALUATORS,
desc=None,
eval_body=False,
eval_where=False,
@@ -1203,59 +1202,78 @@ class ReteConditionExprVisitor(ExpressionVisitor):
if not res.status:
return FailedToCompileError([f"Cannot recognize '{expr_node.right.get_source()}'"])
value = res.value
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))
self.add_to_condition(expr_node.left.unpack(), res.value, conditions)
return conditions
else:
raise FailedToCompileError([expr_node])
def visit_FunctionNode(self, expr_node: FunctionNode):
if expr_node.first.value == "recognize(":
return self.function_recognize_concept(expr_node.parameters[0].value,
expr_node.parameters[1].value,
[p.value for p in expr_node.parameters[2:]])
if not isinstance(expr_node.parameters[0].value, VariableNode):
return FailedToCompileError([f"Cannot recognize '{expr_node.parameters[0].value}'"])
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
:param variable_path: variable holding the information
:param concept_to_recognize: concept to recognize
:param parameters: concept variables values
:param concept_variables: concept variables values
:return:
"""
concept_as_str = concept_to_recognize.get_source()
if not concept_as_str:
return FailedToCompileError([f"Missing concept in for {variable_path}"])
if not isinstance(concept_to_recognize, Concept):
concept_as_str = concept_to_recognize.get_source()
if not concept_as_str:
return FailedToCompileError([f"Missing concept in for {variable_path}"])
res = evaluate(self.context,
concept_as_str,
evaluators="all", # TODO: all is too much
desc=None,
eval_body=False,
eval_where=False,
is_question=False,
expect_success=False,
stm=None)
res = expect_one(self.context, res)
res = evaluate(self.context,
concept_as_str,
evaluators=CONDITIONS_VISITOR_EVALUATORS,
desc=None,
eval_body=True,
eval_where=False,
is_question=False,
expect_success=False,
stm=None)
res = expect_one(self.context, res)
if not res.status:
return FailedToCompileError([f"Unknown concept {concept_as_str}"])
if not res.status:
return FailedToCompileError([f"Unknown concept {concept_as_str}"])
concept = res.body
else:
concept = concept_to_recognize
concept_found = res.body
conditions = []
variable = self.init_or_get_variable_from_attr(variable_path, conditions)
conditions.append(Condition(variable, "__is_concept__", True))
if concept_found.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_NAME:
conditions.append(Condition(variable, "name", concept_found.name))
elif concept_found.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_ID:
conditions.append(Condition(variable, "id", concept_found.id))
if concept.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_NAME:
conditions.append(Condition(variable, "name", concept.name))
elif concept.get_hint(BuiltinConcepts.RECOGNIZED_BY) == RECOGNIZED_BY_ID:
conditions.append(Condition(variable, "id", concept.id))
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
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))
+3
View File
@@ -287,6 +287,9 @@ class VariableNode(ExprNode):
else:
return self.name
def unpack(self):
return [self.name] + self.attributes
@dataclass
class ComparisonNode(ExprNode):
+25 -2
View File
@@ -1115,17 +1115,40 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
"#__x_01__|name|'greetings'",
"#__x_01__|a|#__x_02__",
"#__x_02__|__is_concept__|True",
"#__x_02__|name|'foo'"]
"#__x_02__|key|'foo'"]
),
(
"recognize by instance",
"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",
["#__x_00__|__name__|'__ret'",
"#__x_00__|body|#__x_01__",
"#__x_01__|__is_concept__|True",
"#__x_01__|key|'hello __var__0'",
"#__x_01__|a|__sheerka__"]
"#__x_01__|a|#__x_02__",
"#__x_02__|__is_concept__|True",
"#__x_02__|key|'foo'",
]
),
])