Working on #98 : Persist attribute value when global_truth is set to true
This commit is contained in:
+9
-10
@@ -13,7 +13,7 @@ PROPERTIES_FOR_DIGEST = ("name", "key",
|
||||
"definition", "definition_type",
|
||||
"is_builtin", "is_unique",
|
||||
"where", "pre", "post", "body", "ret",
|
||||
"desc", "props", "variables")
|
||||
"desc", "props", "variables", "parameters")
|
||||
PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"])
|
||||
PROPERTIES_FOR_NEW = ("where", "pre", "post", "body", "desc")
|
||||
VARIABLE_PREFIX = "__var__"
|
||||
@@ -73,6 +73,7 @@ class ConceptMetadata:
|
||||
id: str # unique identifier for a concept. The id will never be modified (but the key can)
|
||||
props: dict # hashmap of properties, values
|
||||
variables: list # list of concept variables(tuple), with their default values
|
||||
parameters: list # list of variables that are part of the name of the concept
|
||||
full_serialization: bool = False # If True, the full object will be serialized, rather than just the diff
|
||||
all_attributes: List[str] = None # list of instance attributes
|
||||
|
||||
@@ -163,7 +164,8 @@ class Concept:
|
||||
desc,
|
||||
id,
|
||||
props or {},
|
||||
variables or []
|
||||
variables or [],
|
||||
[]
|
||||
)
|
||||
|
||||
self._metadata = metadata
|
||||
@@ -241,8 +243,8 @@ class Concept:
|
||||
# It's just to control what I put in the default value of properties
|
||||
# You can allow more type if it's REALLY needed.
|
||||
# - str are for standard definition
|
||||
# - list of concepts is used by ISA
|
||||
assert default_value is None or isinstance(default_value, str)
|
||||
# - Concept when properly set
|
||||
assert default_value is None or isinstance(default_value, (str, Concept))
|
||||
|
||||
self._metadata.variables.append((var_name, default_value))
|
||||
|
||||
@@ -330,7 +332,6 @@ class Concept:
|
||||
if token.value in variables:
|
||||
key += VARIABLE_PREFIX + str(variables.index(token.value))
|
||||
else:
|
||||
# value = token.value[1:-1] if token.type == TokenKind.STRING else token.value
|
||||
key += token.value.value if token.type == TokenKind.KEYWORD else token.value
|
||||
first = False
|
||||
|
||||
@@ -421,6 +422,8 @@ class Concept:
|
||||
self.def_var(name, value)
|
||||
elif prop == "props":
|
||||
self._metadata.props = core.utils.sheerka_deepcopy(other.get_metadata().props)
|
||||
elif prop == "parameters":
|
||||
self._metadata.parameters = other.get_metadata().parameters.copy()
|
||||
else:
|
||||
setattr(self._metadata, prop, getattr(other.get_metadata(), prop))
|
||||
|
||||
@@ -522,11 +525,7 @@ class Concept:
|
||||
return NotInit
|
||||
|
||||
def values(self):
|
||||
try:
|
||||
values = {k: getattr(self, k) for k in get_concept_attrs(self)}
|
||||
except AttributeError as err:
|
||||
print(f"{err}, {self=}")
|
||||
raise err
|
||||
values = {k: getattr(self, k) if hasattr(self, k) else NotInit for k in get_concept_attrs(self)}
|
||||
|
||||
for prop_name in AllConceptParts:
|
||||
try:
|
||||
|
||||
@@ -21,6 +21,9 @@ from sdp.sheerkaDataProvider import Event
|
||||
|
||||
BASE_NODE_PARSER_CLASS = "parsers.BaseNodeParser.BaseNodeParser"
|
||||
EXIT_COMMANDS = ("quit", "exit", "bye")
|
||||
CONTEXT_HINT_COMMANDS = (("global_truth(", "global_truth"),
|
||||
("question(", "question"),
|
||||
("eval", "eval"))
|
||||
EXECUTE_STEPS = [
|
||||
BuiltinConcepts.BEFORE_PARSING,
|
||||
BuiltinConcepts.PARSING,
|
||||
@@ -493,7 +496,7 @@ class Sheerka(Concept):
|
||||
c.get_hints().recognized_by = rec_by
|
||||
c.get_hints().is_instance = is_inst
|
||||
if is_eval is None:
|
||||
c.get_hints().is_evaluated = len(c.get_metadata().variables) > 0
|
||||
c.get_hints().is_evaluated = len(c.get_metadata().parameters) > 0
|
||||
else:
|
||||
c.get_hints().is_evaluated = is_eval
|
||||
return c
|
||||
@@ -581,7 +584,12 @@ class Sheerka(Concept):
|
||||
# otherwise, create another instance
|
||||
concept = self.builtin_cache[key]() if key in self.builtin_cache else Concept()
|
||||
concept.update_from(template, update_value=False)
|
||||
# concept.freeze_definition_hash()
|
||||
|
||||
# set the default values is needed
|
||||
for var_name, var_value in concept.get_metadata().variables:
|
||||
if isinstance(var_value, Concept):
|
||||
concept.set_value(var_name, var_value)
|
||||
# Note that the concept is not considered as evaluated. The body may need to be computed
|
||||
|
||||
if len(kwargs) == 0:
|
||||
return concept
|
||||
|
||||
@@ -295,7 +295,7 @@ class SheerkaConceptManager(BaseService):
|
||||
# 'props' : {<key>: <value>} of properties to add/update,
|
||||
# 'variables': {<key>: <value>} of variables to add/update,
|
||||
# }
|
||||
# if the <key> already exists, the entry is updated, otherwise a new value is created
|
||||
# for variables, if the <key> already exists, the entry is updated, otherwise a new value is created
|
||||
# for props, if the <key> already exists, a new entry is added to the set
|
||||
#
|
||||
# to_remove = {
|
||||
@@ -391,9 +391,10 @@ class SheerkaConceptManager(BaseService):
|
||||
sheerka.publish(context, EVENT_CONCEPT_DELETED, concept)
|
||||
return sheerka.ret(self.NAME, True, sheerka.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
def set_attr(self, concept, attribute, value):
|
||||
def set_attr(self, context, concept, attribute, value):
|
||||
"""
|
||||
Modifies an attribute of a concept (concept.values)
|
||||
:param context:
|
||||
:param concept:
|
||||
:param attribute:
|
||||
:param value:
|
||||
@@ -402,8 +403,16 @@ class SheerkaConceptManager(BaseService):
|
||||
ensure_concept(concept)
|
||||
|
||||
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
||||
old_value = concept.get_value(attr)
|
||||
|
||||
if (old_value := concept.get_value(attr)) is not NotInit:
|
||||
if context.in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED):
|
||||
old_value = self.sheerka.get_by_id(concept.id).get_value(attr)
|
||||
else:
|
||||
old_value = concept.get_value(attr)
|
||||
|
||||
# Caution, creating a list when a set_attr is called for the second time is not always
|
||||
# what is expected
|
||||
if old_value is not NotInit:
|
||||
if old_value == value:
|
||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
@@ -413,8 +422,15 @@ class SheerkaConceptManager(BaseService):
|
||||
else:
|
||||
value = [old_value, value]
|
||||
|
||||
concept.set_value(attr, value)
|
||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||
if context.in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED):
|
||||
to_add = {"variables": {attr: value}}
|
||||
res = self.sheerka.modify_concept(context, concept, to_add, modify_source=True)
|
||||
concept.set_value(attr, value)
|
||||
return res
|
||||
else:
|
||||
|
||||
concept.set_value(attr, value)
|
||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
def get_attr(self, concept, attribute):
|
||||
"""
|
||||
@@ -857,6 +873,7 @@ class SheerkaConceptManager(BaseService):
|
||||
concept.set_bnf(None)
|
||||
ensure_bnf(context, concept)
|
||||
|
||||
self.recompute_concept_parameters(context, concept)
|
||||
concept.init_key()
|
||||
|
||||
return
|
||||
@@ -1252,3 +1269,27 @@ class SheerkaConceptManager(BaseService):
|
||||
# update the compiled regex
|
||||
self.compiled_concepts_by_regex.clear()
|
||||
self.compiled_concepts_by_regex.extend(compiled_by_first_regex)
|
||||
|
||||
@staticmethod
|
||||
def recompute_concept_parameters(context, concept):
|
||||
concept.get_metadata().parameters.clear()
|
||||
|
||||
if concept.get_metadata().definition_type == DEFINITION_TYPE_DEF:
|
||||
tokens = list(Tokenizer(concept.get_metadata().definition, yield_eof=False))
|
||||
else:
|
||||
tokens = list(Tokenizer(concept.get_metadata().name, yield_eof=False))
|
||||
|
||||
# all variables that appear in the name are concept parameters
|
||||
if len(tokens) > 0:
|
||||
variables = [p[0] for p in concept.get_metadata().variables]
|
||||
for token in [t for t in tokens if t.value in variables]:
|
||||
concept.get_metadata().parameters.append(token.value)
|
||||
|
||||
# for bnf concept, use the visitor to extract parameters
|
||||
if concept.get_bnf():
|
||||
from evaluators.DefConceptEvaluator import ConceptOrRuleVariableVisitor, ParameterVariable
|
||||
visitor = ConceptOrRuleVariableVisitor(context)
|
||||
visitor.visit(concept.get_bnf())
|
||||
for variable in [v for v in visitor.variables if isinstance(v, ParameterVariable)]:
|
||||
if variable.name not in concept.get_metadata().parameters:
|
||||
concept.get_metadata().parameters.append(variable.name)
|
||||
|
||||
@@ -432,15 +432,18 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
if default_value is None:
|
||||
continue
|
||||
|
||||
if not isinstance(default_value, str):
|
||||
raise Exception("Invalid concept init. variable metadata must be a string")
|
||||
if not isinstance(default_value, (str, Concept)):
|
||||
raise Exception("Invalid concept init. variable metadata must be a string (or a concept)")
|
||||
|
||||
concept.get_compiled()[var_name] = self.get_asts(context,
|
||||
self.NAME,
|
||||
default_value,
|
||||
concept,
|
||||
var_name,
|
||||
possible_variables)
|
||||
if isinstance(default_value, Concept):
|
||||
concept.get_compiled()[var_name] = default_value.copy()
|
||||
else:
|
||||
concept.get_compiled()[var_name] = self.get_asts(context,
|
||||
self.NAME,
|
||||
default_value,
|
||||
concept,
|
||||
var_name,
|
||||
possible_variables)
|
||||
|
||||
def resolve(self,
|
||||
context,
|
||||
@@ -740,8 +743,6 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
# TODO : Validate the POST condition
|
||||
#
|
||||
|
||||
concept.init_key() # Necessary for old unit tests. To remove someday
|
||||
|
||||
if ConceptParts.BODY in all_metadata_to_eval and not failed_to_evaluate_body:
|
||||
concept.get_hints().is_evaluated = True
|
||||
|
||||
|
||||
@@ -74,27 +74,63 @@ class CertainVariable(ConceptEvaluatorVariable):
|
||||
return hash(("PossibleVariable", self.name))
|
||||
|
||||
|
||||
@dataclass(eq=True, frozen=True)
|
||||
class ParameterVariable(ConceptEvaluatorVariable):
|
||||
"""
|
||||
A parameter variable (for BNF concepts) are variables that are mandatory for the resolution of the concept
|
||||
|
||||
example:
|
||||
def concept plus from bnf number=n1 plus number=n2 # n1 and n2 are parameters
|
||||
def concept plus from bnf number plus number # number is a parameter
|
||||
def concept inc from bnf (one|two)=n1 plus 1 # n1 is a parameter
|
||||
def concept inc from bnf (one|two) plus 1 # (one|two) is a parameter (but with no associated variable name)
|
||||
"""
|
||||
is_a_variable: bool # True is the parameter has an associated variable name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(("ParameterVariable", self.name, self.is_a_variable))
|
||||
|
||||
|
||||
class ConceptOrRuleVariableVisitor(ParsingExpressionVisitor):
|
||||
"""
|
||||
Gets the concepts referenced by BNF
|
||||
If a rule_name is given, it will also be considered as a potential property
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, context):
|
||||
super().__init__()
|
||||
self.context = context
|
||||
self.variables = []
|
||||
self.counter = 1
|
||||
|
||||
def _get_parameter_name(self, node, prefix):
|
||||
if not node.rule_name:
|
||||
name = f"{prefix}{self.counter}"
|
||||
self.counter += 1
|
||||
is_a_variable = False
|
||||
else:
|
||||
name = node.rule_name
|
||||
is_a_variable = True
|
||||
return name, is_a_variable
|
||||
|
||||
def visit_ConceptExpression(self, node):
|
||||
if node.rule_name:
|
||||
self.variables.append(CertainVariable(node.rule_name))
|
||||
elif isinstance(node.concept, Concept):
|
||||
self.variables.append(CertainVariable(node.concept.name))
|
||||
if isinstance(node.concept, Concept):
|
||||
if self.context.sheerka.isaset(self.context, node.concept):
|
||||
parameter_name, is_a_variable = self._get_parameter_name(node, "__ConceptExpression__")
|
||||
self.variables.append(ParameterVariable(parameter_name, is_a_variable))
|
||||
else:
|
||||
self.variables.append(CertainVariable(node.rule_name or node.concept.name))
|
||||
else:
|
||||
self.variables.append(CertainVariable(node.concept))
|
||||
self.variables.append(CertainVariable(node.rule_name or node.concept))
|
||||
|
||||
def visit_VariableExpression(self, node):
|
||||
self.variables.append(MandatoryVariable(node.rule_name))
|
||||
|
||||
def visit_OrderedChoice(self, node):
|
||||
parameter_name, is_a_variable = self._get_parameter_name(node, "__OrderedChoice__")
|
||||
self.variables.append(ParameterVariable(parameter_name, is_a_variable))
|
||||
self.visit_children(node)
|
||||
|
||||
def visit_all(self, node):
|
||||
if node.rule_name:
|
||||
self.variables.append(CertainVariable(node.rule_name))
|
||||
@@ -127,7 +163,8 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
||||
# validate the node
|
||||
variables_found = set()
|
||||
mandatory_variables = set() # these variable MUST have a match in the name (if the name is not None)
|
||||
certain_variables = []
|
||||
parameter_variables = [] # BNF variables known as concept parameter. Use a list to keep the order
|
||||
certain_variables = [] # names that we know for sure that there are variables
|
||||
skip_variables_resolution = False
|
||||
|
||||
concept = Concept(str(def_concept_node.name))
|
||||
@@ -164,16 +201,23 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
||||
|
||||
# try to find what can be a property
|
||||
for p in self.get_variables(context, part_ret_val, name_to_use):
|
||||
variables_found.add(p.name)
|
||||
if isinstance(p, MandatoryVariable):
|
||||
mandatory_variables.add(p.name)
|
||||
elif isinstance(p, CertainVariable):
|
||||
certain_variables.append(p.name)
|
||||
if isinstance(p, ParameterVariable):
|
||||
parameter_variables.append(p.name)
|
||||
if p.is_a_variable:
|
||||
variables_found.add(p.name)
|
||||
certain_variables.append(p.name)
|
||||
else:
|
||||
variables_found.add(p.name)
|
||||
if isinstance(p, MandatoryVariable):
|
||||
mandatory_variables.add(p.name)
|
||||
elif isinstance(p, CertainVariable):
|
||||
certain_variables.append(p.name)
|
||||
|
||||
# add variables by order of appearance
|
||||
for name_part in [name_part for name_part in name_to_use if str(name_part).isalnum()]:
|
||||
if name_part in variables_found:
|
||||
concept.def_var(name_part, None)
|
||||
concept.get_metadata().parameters.append(name_part)
|
||||
|
||||
# check that all mandatory variables are defined in the name
|
||||
# KSI: 2021-02-17
|
||||
@@ -190,6 +234,10 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
||||
if p not in concept.values():
|
||||
concept.def_var(p, None)
|
||||
|
||||
for p in parameter_variables:
|
||||
if p not in concept.get_metadata().parameters:
|
||||
concept.get_metadata().parameters.append(p)
|
||||
|
||||
# initialize the key
|
||||
key_source = def_concept_node.definition.tokens if \
|
||||
def_concept_node.definition_type == DEFINITION_TYPE_DEF else \
|
||||
@@ -251,7 +299,7 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
||||
# case of BNF
|
||||
#
|
||||
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, ParsingExpression):
|
||||
visitor = ConceptOrRuleVariableVisitor()
|
||||
visitor = ConceptOrRuleVariableVisitor(context)
|
||||
visitor.visit(ret_value.value.value)
|
||||
debugger.debug_var("names", visitor.variables, hint="from BNF")
|
||||
return visitor.variables
|
||||
|
||||
@@ -11,10 +11,10 @@ class BnfDefinitionParser(BaseParser):
|
||||
"""
|
||||
Parser used to transform literal into ParsingExpression
|
||||
example :
|
||||
a | b, c -> Sequence(OrderedChoice(a, b) ,c)
|
||||
a | b c -> Sequence(OrderedChoice(a, b), c)
|
||||
|
||||
'|' (pipe) is used for OrderedChoice
|
||||
',' (comma) is used for Sequence
|
||||
' ' space is used for Sequence
|
||||
'?' (question mark) is used for Optional
|
||||
'*' (star) is used for ZeroOrMore
|
||||
'+' (plus) is used for OneOrMore
|
||||
|
||||
@@ -1165,6 +1165,9 @@ class ParsingExpressionVisitor:
|
||||
if hasattr(self, "visit_all"):
|
||||
self.visit_all(parsing_expression)
|
||||
|
||||
self.visit_children(parsing_expression)
|
||||
|
||||
def visit_children(self, parsing_expression):
|
||||
for node in self.get_nodes(parsing_expression):
|
||||
if isinstance(node, Concept):
|
||||
res = self.visit(ConceptExpression(node.key or node.name))
|
||||
|
||||
@@ -231,7 +231,7 @@ class SequenceNodeParser(BaseNodeParser):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
return len(concept.get_metadata().variables) == 0 \
|
||||
return len(concept.get_metadata().parameters) == 0 \
|
||||
and concept.get_metadata().definition_type != DEFINITION_TYPE_BNF
|
||||
|
||||
def get_concepts(self, token, to_keep, custom=None, to_map=None, strip_quotes=False):
|
||||
|
||||
@@ -199,7 +199,7 @@ class SyaConceptParserHelper:
|
||||
self.expected = temp
|
||||
|
||||
self.eat_token(first_keyword_found) # remove the first token
|
||||
self.tokens.append(first_keyword_found)
|
||||
self.tokens.append(first_keyword_found) # and add it to the list of tokens eaten
|
||||
|
||||
def is_matched(self):
|
||||
return len(self.expected) == 0
|
||||
@@ -554,7 +554,7 @@ class InFixToPostFix:
|
||||
|
||||
def nb_expected_parameters(expected):
|
||||
"""
|
||||
Count the number of successive variables that are expected
|
||||
Count the number of successive variables that are still expected
|
||||
:param expected:
|
||||
:return:
|
||||
"""
|
||||
@@ -1228,10 +1228,10 @@ class SyaNodeParser(BaseNodeParser):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
# We only concepts that has parameter (refuse atoms)
|
||||
# We only considers concepts that has parameter variables (refuse atoms)
|
||||
# Bnf definitions are not supposed to be managed by this parser either
|
||||
return len(
|
||||
concept.get_metadata().variables) > 0 and concept.get_metadata().definition_type != DEFINITION_TYPE_BNF
|
||||
return (concept.get_metadata().definition_type != DEFINITION_TYPE_BNF and
|
||||
len(concept.get_metadata().parameters) > 0)
|
||||
|
||||
def infix_to_postfix(self, context, parser_input: ParserInput):
|
||||
"""
|
||||
@@ -1368,6 +1368,14 @@ class SyaNodeParser(BaseNodeParser):
|
||||
concept = sheerka.new_from_template(item.concept, item.concept.key)
|
||||
concept_metadata = []
|
||||
for param_index in reversed(range(len(concept.get_metadata().variables))):
|
||||
param_name = concept.get_metadata().variables[param_index][0]
|
||||
|
||||
if param_name not in concept.get_metadata().parameters:
|
||||
# This is not a real concept parameter, but a concept variable
|
||||
# just copy its default value
|
||||
concept_metadata.append(concept.get_metadata().variables[param_index])
|
||||
continue
|
||||
|
||||
inner_item = self.postfix_to_item(sheerka, postfixed)
|
||||
if inner_item.start < start:
|
||||
start = inner_item.start
|
||||
@@ -1376,7 +1384,6 @@ class SyaNodeParser(BaseNodeParser):
|
||||
has_unrecognized |= isinstance(inner_item, (UnrecognizedTokensNode, SourceCodeWithConceptNode)) or \
|
||||
hasattr(inner_item, "has_unrecognized") and inner_item.has_unrecognized
|
||||
|
||||
param_name = concept.get_metadata().variables[param_index][0]
|
||||
param_value = inner_item.concept if hasattr(inner_item, "concept") else \
|
||||
[inner_item.return_value] if isinstance(inner_item, SourceCodeNode) else \
|
||||
inner_item
|
||||
|
||||
@@ -7,7 +7,7 @@ from dataclasses import dataclass
|
||||
from prompt_toolkit.completion import Completer, Completion
|
||||
|
||||
from core.concept import Concept
|
||||
from core.sheerka.Sheerka import EXIT_COMMANDS
|
||||
from core.sheerka.Sheerka import EXIT_COMMANDS, CONTEXT_HINT_COMMANDS
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.SheerkaFunctionsParametersHistory import SheerkaFunctionsParametersHistory
|
||||
from core.tokenizer import Tokenizer, TokenKind, LexerError
|
||||
@@ -154,6 +154,9 @@ class SheerkaPromptCompleter(Completer):
|
||||
"builtin",
|
||||
["context"]))
|
||||
|
||||
for name, display in CONTEXT_HINT_COMMANDS:
|
||||
self.builtins.append(CompletionDesc(name, display, "context"))
|
||||
|
||||
self.exit_commands = [CompletionDesc(c, c, "command") for c in EXIT_COMMANDS]
|
||||
self.globals = {k: v.method for k, v in self.sheerka.sheerka_methods.items()}
|
||||
|
||||
@@ -313,11 +316,12 @@ class SheerkaPromptCompleter(Completer):
|
||||
function_name = name + "("
|
||||
signature = inspect.signature(function)
|
||||
params_count = len([p for p in signature.parameters if p not in skip_params])
|
||||
|
||||
if params_count == 0:
|
||||
function_name += ")"
|
||||
|
||||
return CompletionDesc(function_name, name, meta_display)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def inside_function(text, pos):
|
||||
bracket_count = 0
|
||||
|
||||
@@ -6,6 +6,7 @@ from core.concept import Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF, free
|
||||
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
from core.sheerka.Sheerka import Sheerka
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager
|
||||
from parsers.BnfDefinitionParser import BnfDefinitionParser
|
||||
from parsers.BnfNodeParser import StrMatch
|
||||
@@ -47,6 +48,7 @@ class InitTestHelper:
|
||||
raise Exception(f"Error in bnf definition '{c.get_metadata().definition}'",
|
||||
self.sheerka.get_errors(self.context, res))
|
||||
|
||||
self._update_concept_parameters(c)
|
||||
if create_new:
|
||||
self.sheerka.create_new_concept(self.context, c)
|
||||
else:
|
||||
@@ -99,6 +101,12 @@ class InitTestHelper:
|
||||
|
||||
return self
|
||||
|
||||
def _update_concept_parameters(self, concept):
|
||||
if concept.get_metadata().parameters:
|
||||
return
|
||||
|
||||
SheerkaConceptManager.recompute_concept_parameters(self.context, concept)
|
||||
|
||||
|
||||
class BaseTest:
|
||||
def get_sheerka(self, **kwargs) -> Sheerka:
|
||||
|
||||
@@ -4,7 +4,7 @@ from cache.CacheManager import ConceptNotFound
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import ensure_bnf
|
||||
from core.concept import PROPERTIES_TO_SERIALIZE, Concept, DEFINITION_TYPE_DEF, get_concept_attrs, \
|
||||
DEFINITION_TYPE_BNF
|
||||
DEFINITION_TYPE_BNF, ConceptParts
|
||||
from core.global_symbols import NotInit, NotFound, SyaAssociativity, CONCEPT_COMPARISON_CONTEXT
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager, NoModificationFound, ForbiddenAttribute, \
|
||||
UnknownAttribute, CannotRemoveMeta, ValueNotFound, ConceptIsReferenced, NoFirstTokenError
|
||||
@@ -494,13 +494,13 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
to_add = {"meta": {"name": "b bar c d"},
|
||||
"variables": {"c": None, "d": None}}
|
||||
|
||||
to_remove = {"variables": ["a"]}
|
||||
|
||||
res = sheerka.modify_concept(context, foo, to_add, to_remove)
|
||||
res = sheerka.modify_concept(context, foo, to_add)
|
||||
new_concept = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert new_concept.key == "__var__0 bar __var__1 __var__2"
|
||||
assert new_concept.key == "__var__1 bar __var__2 __var__3"
|
||||
assert new_concept.get_metadata().parameters == ["b", "c", "d"]
|
||||
assert new_concept.get_metadata().variables == [("a", None), ("b", None), ("c", None), ("d", None)]
|
||||
|
||||
def test_key_is_modified_when_modifying_the_definition(self):
|
||||
sheerka, context, foo = self.init_concepts(
|
||||
@@ -790,13 +790,101 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
prop = Concept("property")
|
||||
bar = Concept("bar")
|
||||
|
||||
res = sheerka.set_attr(foo, prop, bar)
|
||||
res = sheerka.set_attr(context, foo, prop, bar)
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||
|
||||
assert sheerka.get_attr(foo, prop) == bar
|
||||
|
||||
def test_i_setting_twice_the_same_property_creates_a_list(self):
|
||||
def test_i_can_get_and_set_attribute_when_global_truth_is_set(self):
|
||||
sheerka, context, foo, adjective, color, red, brightness, dark = self.init_test(cache_only=False).with_concepts(
|
||||
"foo",
|
||||
"adjective",
|
||||
"color",
|
||||
"red",
|
||||
"brightness",
|
||||
"dark",
|
||||
create_new=True).unpack()
|
||||
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
|
||||
color_instance = sheerka.new("color", body=sheerka.new("red"))
|
||||
sheerka.set_attr(context, color_instance, brightness, sheerka.new("dark"))
|
||||
sheerka.set_isa(context, color_instance, sheerka.new(adjective))
|
||||
|
||||
adjective_instance = sheerka.new("adjective")
|
||||
adjective_instance.set_value(ConceptParts.BODY, color_instance)
|
||||
|
||||
foo_instance = sheerka.new("foo")
|
||||
res = sheerka.set_attr(global_truth_context, foo_instance, sheerka.new("adjective"), adjective_instance)
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
# foo.adjective is modified
|
||||
resolved_adjective = sheerka.get_attr(foo_instance, sheerka.new("adjective"))
|
||||
assert sheerka.isinstance(resolved_adjective, "adjective")
|
||||
resolved_color = resolved_adjective.body
|
||||
assert sheerka.isinstance(resolved_color, "color")
|
||||
assert sheerka.isa(resolved_color, adjective)
|
||||
assert sheerka.get_attr(resolved_color, brightness) == dark
|
||||
assert resolved_color.body == red
|
||||
|
||||
# foo default variable value is modified
|
||||
adjective_from_default_var = foo_instance.get_metadata().variables[0][1]
|
||||
assert sheerka.isinstance(adjective_from_default_var, "adjective")
|
||||
color_from_default_var = resolved_adjective.body
|
||||
assert sheerka.isinstance(color_from_default_var, "color")
|
||||
assert sheerka.isa(color_from_default_var, adjective)
|
||||
assert sheerka.get_attr(color_from_default_var, brightness) == dark
|
||||
assert color_from_default_var.body == red
|
||||
|
||||
# new instance are update
|
||||
new_instance = sheerka.new("foo")
|
||||
resolved_adjective = sheerka.get_attr(new_instance, sheerka.new("adjective"))
|
||||
assert sheerka.isinstance(resolved_adjective, "adjective")
|
||||
resolved_color = resolved_adjective.body
|
||||
assert sheerka.isinstance(resolved_color, "color")
|
||||
assert sheerka.isa(resolved_color, adjective)
|
||||
assert sheerka.get_attr(resolved_color, brightness) == dark
|
||||
assert resolved_color.body == red
|
||||
# No need to check the default variable value since the attribute is updated
|
||||
|
||||
# make sure it's persisted in DB
|
||||
sheerka.om.commit(context)
|
||||
from_db = sheerka.om.current_sdp().get(service.CONCEPTS_BY_ID_ENTRY, foo.id)
|
||||
# concepts values are never persisted in DB.
|
||||
# only check the default value of the variable
|
||||
adjective_from_default_var = from_db.get_metadata().variables[0][1]
|
||||
assert sheerka.isinstance(adjective_from_default_var, "adjective")
|
||||
color_from_default_var = resolved_adjective.body
|
||||
assert sheerka.isinstance(color_from_default_var, "color")
|
||||
assert sheerka.isa(color_from_default_var, adjective)
|
||||
assert sheerka.get_attr(color_from_default_var, brightness) == dark
|
||||
assert color_from_default_var.body == red
|
||||
|
||||
# check that we can access the values
|
||||
assert foo_instance.values() == {'c:adjective|1002:': adjective_instance}
|
||||
assert new_instance.values() == {'c:adjective|1002:': adjective_instance}
|
||||
assert from_db.values() == {'c:adjective|1002:': NotInit}
|
||||
assert foo.values() == {'c:adjective|1002:': NotInit}
|
||||
|
||||
def test_i_can_set_attr_twice_is_the_second_time_global_truth_is_true(self):
|
||||
sheerka, context, foo, prop, value = self.init_test(cache_only=False).with_concepts(
|
||||
"foo",
|
||||
"prop",
|
||||
"value",
|
||||
create_new=True).unpack()
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
|
||||
foo_instance = sheerka.new("foo")
|
||||
sheerka.set_attr(context, foo_instance, prop, value)
|
||||
|
||||
sheerka.set_attr(global_truth_context, foo_instance, prop, value)
|
||||
|
||||
new_instance = sheerka.new("foo")
|
||||
assert sheerka.get_attr(new_instance, prop) == value
|
||||
|
||||
def test_setting_twice_the_same_property_creates_a_list(self):
|
||||
sheerka, context = self.init_concepts()
|
||||
foo = Concept("foo")
|
||||
prop = Concept("property")
|
||||
@@ -804,22 +892,22 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
baz = Concept("baz")
|
||||
qux = Concept("qux")
|
||||
|
||||
res = sheerka.set_attr(foo, prop, bar)
|
||||
res = sheerka.set_attr(context, foo, prop, bar)
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||
assert sheerka.get_attr(foo, prop) == bar
|
||||
|
||||
res = sheerka.set_attr(foo, prop, bar) # again, same value as no effect
|
||||
res = sheerka.set_attr(context, foo, prop, bar) # again, same value as no effect
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||
assert sheerka.get_attr(foo, prop) == bar
|
||||
|
||||
res = sheerka.set_attr(foo, prop, baz)
|
||||
res = sheerka.set_attr(context, foo, prop, baz)
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||
assert sheerka.get_attr(foo, prop) == [bar, baz]
|
||||
|
||||
res = sheerka.set_attr(foo, prop, qux)
|
||||
res = sheerka.set_attr(context, foo, prop, qux)
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||
assert sheerka.get_attr(foo, prop) == [bar, baz, qux]
|
||||
@@ -1241,7 +1329,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
prop = Concept("property")
|
||||
bar = Concept("bar")
|
||||
|
||||
sheerka.set_attr(foo, prop, bar)
|
||||
sheerka.set_attr(context, foo, prop, bar)
|
||||
assert sheerka.smart_get_attr(foo, prop) == bar
|
||||
|
||||
def test_i_can_smart_get_attr_when_simple_isa(self):
|
||||
@@ -1256,7 +1344,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
adjective_instance = sheerka.new(adjective, body=color_instance)
|
||||
table_instance = sheerka.new(table)
|
||||
sheerka.set_attr(table_instance, adjective, adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, adjective_instance)
|
||||
|
||||
assert sheerka.smart_get_attr(table_instance, color) == color_instance
|
||||
assert sheerka.objvalue(sheerka.smart_get_attr(table_instance, color)) == red
|
||||
@@ -1276,7 +1364,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
color_instance = sheerka.new(color, body=reddish_instance)
|
||||
adjective_instance = sheerka.new(adjective, body=color_instance)
|
||||
table_instance = sheerka.new(table)
|
||||
sheerka.set_attr(table_instance, adjective, adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, adjective_instance)
|
||||
|
||||
assert sheerka.smart_get_attr(table_instance, reddish_instance) == reddish_instance
|
||||
assert sheerka.objvalue(sheerka.smart_get_attr(table_instance, color)) == red
|
||||
@@ -1296,12 +1384,12 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
# add red color
|
||||
red_color_instance = sheerka.new(color, body=red)
|
||||
red_adjective_instance = sheerka.new(adjective, body=red_color_instance)
|
||||
sheerka.set_attr(table_instance, adjective, red_adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, red_adjective_instance)
|
||||
|
||||
# add blue color
|
||||
blue_color_instance = sheerka.new(color, body=blue)
|
||||
blue_adjective_instance = sheerka.new(adjective, body=blue_color_instance)
|
||||
sheerka.set_attr(table_instance, adjective, blue_adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, blue_adjective_instance)
|
||||
|
||||
res = sheerka.smart_get_attr(table_instance, color)
|
||||
assert res == [red_color_instance, blue_color_instance]
|
||||
@@ -1317,7 +1405,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
table_instance = sheerka.new(table)
|
||||
sheerka.set_attr(table_instance, color, color_instance)
|
||||
sheerka.set_attr(context, table_instance, color, color_instance)
|
||||
|
||||
assert sheerka.smart_get_attr(table_instance, adjective) == color_instance
|
||||
|
||||
@@ -1336,9 +1424,9 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
table_instance = sheerka.new(table)
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
sheerka.set_attr(table_instance, color, color_instance)
|
||||
sheerka.set_attr(context, table_instance, color, color_instance)
|
||||
size_instance = sheerka.new(size, body=large)
|
||||
sheerka.set_attr(table_instance, size, size_instance)
|
||||
sheerka.set_attr(context, table_instance, size, size_instance)
|
||||
|
||||
assert sheerka.smart_get_attr(table_instance, adjective) == [color_instance, size_instance]
|
||||
|
||||
@@ -1355,8 +1443,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
adjective_instance = sheerka.new(adjective, body=color_instance)
|
||||
table_instance = sheerka.new(table)
|
||||
sheerka.set_attr(table_instance, adjective, adjective_instance)
|
||||
sheerka.set_attr(table_instance, color, blue) # set direct color value
|
||||
sheerka.set_attr(context, table_instance, adjective, adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, color, blue) # set direct color value
|
||||
|
||||
assert sheerka.smart_get_attr(table_instance, color) == blue
|
||||
|
||||
@@ -1372,8 +1460,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
table_instance = sheerka.new(table)
|
||||
sheerka.set_attr(table_instance, color, color_instance)
|
||||
sheerka.set_attr(table_instance, adjective, blue) # set direct color value
|
||||
sheerka.set_attr(context, table_instance, color, color_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, blue) # set direct color value
|
||||
|
||||
assert sheerka.smart_get_attr(table_instance, adjective) == blue
|
||||
|
||||
@@ -1397,7 +1485,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
adjective_instance = sheerka.new(adjective, body=color_instance)
|
||||
table_instance = sheerka.new(table)
|
||||
sheerka.set_attr(table_instance, adjective, adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, adjective_instance)
|
||||
|
||||
res = sheerka.smart_get_attr(table_instance, color)
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
|
||||
@@ -1417,7 +1505,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
table_instance = sheerka.new(table)
|
||||
color_instance = sheerka.new(color, body=red)
|
||||
adjective_instance = sheerka.new(adjective, body=color_instance)
|
||||
sheerka.set_attr(table_instance, adjective, adjective_instance)
|
||||
sheerka.set_attr(context, table_instance, adjective, adjective_instance)
|
||||
|
||||
res = sheerka.smart_get_attr(table_instance, size)
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
|
||||
|
||||
@@ -533,7 +533,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_inspect_object_with_concept(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
foo.values() # freeze known attributes
|
||||
sheerka.set_attr(foo, "new_var", "var_value")
|
||||
sheerka.set_attr(context, foo, "new_var", "var_value")
|
||||
|
||||
dummy = DummyObj(foo, "value")
|
||||
res = sheerka.inspect(context, dummy)
|
||||
@@ -542,7 +542,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_inspect_object_with_concept_when_as_bag(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
foo.values() # freeze known attributes
|
||||
sheerka.set_attr(foo, "new_var", "var_value")
|
||||
sheerka.set_attr(context, foo, "new_var", "var_value")
|
||||
|
||||
dummy = DummyObj(foo, "value")
|
||||
res = sheerka.inspect(context, dummy, as_bag=True)
|
||||
@@ -557,7 +557,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_inspect_object_with_concept_when_values(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
foo.values() # freeze known attributes
|
||||
sheerka.set_attr(foo, "new_var", "var_value")
|
||||
sheerka.set_attr(context, foo, "new_var", "var_value")
|
||||
|
||||
dummy = DummyObj(foo, "value")
|
||||
res = sheerka.inspect(context, dummy, values=True)
|
||||
@@ -629,7 +629,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_inspect_when_a_property_does_not_exist(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
foo.values() # freeze known attributes
|
||||
sheerka.set_attr(foo, "new_var", "var_value")
|
||||
sheerka.set_attr(context, foo, "new_var", "var_value")
|
||||
|
||||
dummy = DummyObj(foo, "value")
|
||||
res = sheerka.inspect(context, dummy, "#type#", "fake", "a", "b")
|
||||
@@ -641,7 +641,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_inspect_when_properties_are_specified_several_times(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
foo.values() # freeze known attributes
|
||||
sheerka.set_attr(foo, "new_var", "var_value")
|
||||
sheerka.set_attr(context, foo, "new_var", "var_value")
|
||||
|
||||
dummy = DummyObj(foo, "value")
|
||||
res = sheerka.inspect(context, dummy, "#type#", "a", "b", "a")
|
||||
|
||||
@@ -314,7 +314,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_i_can_evaluate_when_variable_asts_is_a_list(self):
|
||||
sheerka = self.get_sheerka()
|
||||
foo = Concept("foo", body="1")
|
||||
foo = Concept("foo", body="1").init_key()
|
||||
|
||||
concept = Concept("to_eval").def_var("prop")
|
||||
concept.get_compiled()["prop"] = [foo, DoNotResolve("1")]
|
||||
@@ -467,14 +467,6 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
||||
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
||||
|
||||
def test_key_is_initialized_by_evaluation(self):
|
||||
sheerka = self.get_sheerka()
|
||||
|
||||
concept = Concept("foo")
|
||||
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
|
||||
|
||||
assert evaluated.key == concept.init_key().key
|
||||
|
||||
@pytest.mark.parametrize("where_clause, expected, expected_prop, expected_body", [
|
||||
("True", True, None, NotInit),
|
||||
("False", False, ConceptParts.WHERE, NotInit),
|
||||
|
||||
@@ -253,7 +253,7 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
|
||||
instantiated_foo = sheerka.new(foo, x="value1")
|
||||
instantiated_one = ensure_evaluated(context, sheerka.new(inner_value))
|
||||
instantiated_value = sheerka.new(value, x=instantiated_one)
|
||||
sheerka.set_attr(instantiated_foo, prop, instantiated_value)
|
||||
sheerka.set_attr(context, instantiated_foo, prop, instantiated_value)
|
||||
|
||||
sheerka.add_to_memory(context, "foo", instantiated_foo)
|
||||
sheerka.om.commit(context)
|
||||
|
||||
@@ -64,10 +64,10 @@ def test_i_can_serialize():
|
||||
:return:
|
||||
"""
|
||||
concept = Concept(
|
||||
name="concept_name",
|
||||
name="concept_name a",
|
||||
is_builtin=True,
|
||||
is_unique=True,
|
||||
key="concept_key",
|
||||
key=None,
|
||||
body="definition of the body",
|
||||
where="definition of the where",
|
||||
pre="definition of the pre",
|
||||
@@ -78,6 +78,8 @@ def test_i_can_serialize():
|
||||
desc="this this the desc",
|
||||
id="123456"
|
||||
).def_var("a", "10").def_var("b", None)
|
||||
concept.get_metadata().parameters = ["a"]
|
||||
concept.init_key()
|
||||
|
||||
to_dict = concept.to_dict()
|
||||
assert to_dict == {
|
||||
@@ -88,14 +90,15 @@ def test_i_can_serialize():
|
||||
'id': '123456',
|
||||
'is_builtin': True,
|
||||
'is_unique': True,
|
||||
'key': 'concept_key',
|
||||
'name': 'concept_name',
|
||||
'key': 'concept_name __var__0',
|
||||
'name': 'concept_name a',
|
||||
'post': 'definition of the post',
|
||||
'pre': 'definition of the pre',
|
||||
'ret': "concept to return",
|
||||
'props': {},
|
||||
'variables': [('a', "10"), ('b', None)],
|
||||
'where': 'definition of the where'
|
||||
'where': 'definition of the where',
|
||||
'parameters': ['a'],
|
||||
}
|
||||
|
||||
|
||||
@@ -302,3 +305,33 @@ def test_i_can_manage_instance_attributes():
|
||||
assert foo.values() == {"x": "value for x", "y": "value for y"}
|
||||
assert foo.get_all_attributes() == ["x", "y"]
|
||||
assert ALL_ATTRIBUTES == {"foo_id": ["x"]}
|
||||
|
||||
|
||||
def test_i_can_init_key_and_compute_parameters():
|
||||
concept = Concept("foo x").def_var("x").init_key()
|
||||
assert concept.key == "foo __var__0"
|
||||
|
||||
concept = Concept("foo").def_var("x").init_key()
|
||||
assert concept.key == "foo"
|
||||
|
||||
concept = Concept("foo a b").def_var("a").def_var("b").init_key()
|
||||
assert concept.key == "foo __var__0 __var__1"
|
||||
|
||||
concept = Concept("foo a b").def_var("b").def_var("a").init_key()
|
||||
assert concept.key == "foo __var__1 __var__0"
|
||||
|
||||
concept = Concept("foo a b").def_var("a").init_key()
|
||||
assert concept.key == "foo __var__0 b"
|
||||
|
||||
concept = Concept("foo a b").def_var("b").init_key()
|
||||
assert concept.key == "foo a __var__0"
|
||||
|
||||
concept = Concept("foo a").def_var("a").def_var("b").init_key()
|
||||
assert concept.key == "foo __var__0"
|
||||
|
||||
concept = Concept("foo b").def_var("a").def_var("b").init_key()
|
||||
assert concept.key == "foo __var__1"
|
||||
|
||||
concept = Concept("plus", definition_type=DEFINITION_TYPE_DEF, definition="a plus b").def_var("a").def_var("b")
|
||||
concept.init_key()
|
||||
assert concept.key == "__var__0 plus __var__1"
|
||||
|
||||
@@ -38,7 +38,6 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert result.value.get_value(ConceptParts.POST) == 4
|
||||
assert result.value.get_value("a") == 5
|
||||
assert result.value.get_value("b") == 6
|
||||
assert result.value.key == "foo"
|
||||
assert result.parents == [item]
|
||||
|
||||
def test_body_is_returned_when_defined_and_requested(self):
|
||||
|
||||
@@ -7,7 +7,7 @@ from core.concept import VARIABLE_PREFIX, Concept, DEFINITION_TYPE_BNF, DEFINITI
|
||||
from core.sheerka.services.SheerkaConceptManager import NoFirstTokenError
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.DefConceptEvaluator import DefConceptEvaluator, PossibleVariable, CertainVariable
|
||||
from evaluators.DefConceptEvaluator import DefConceptEvaluator, PossibleVariable, CertainVariable, ParameterVariable
|
||||
from parsers.BaseParser import BaseParser
|
||||
from parsers.BnfDefinitionParser import BnfDefinitionParser
|
||||
from parsers.BnfNodeParser import Sequence, StrMatch, ZeroOrMore, ConceptExpression, VariableExpression
|
||||
@@ -200,7 +200,7 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
|
||||
concept_definition = def_ret_val.value.body.definition
|
||||
|
||||
expected = [CertainVariable("unit"), CertainVariable("one"), CertainVariable("two")]
|
||||
expected = [ParameterVariable("unit", True), CertainVariable("one"), CertainVariable("two")]
|
||||
assert DefConceptEvaluator.get_variables(context, concept_definition, []) == expected
|
||||
|
||||
def test_i_can_recognize_variables_when_referencing_other_concepts(self):
|
||||
@@ -326,6 +326,84 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert evaluated.body.body.key == "foo2 __var__0"
|
||||
assert evaluated.body.body.get_metadata().variables == [("x", None)]
|
||||
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_named_ordered_choice(self):
|
||||
sheerka, context, one, two = self.init_concepts("one", "two", create_new=True)
|
||||
text = "def concept plus from bnf (one|two)=n1 'plus' (one|two)=n2 as n1 + n2"
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
|
||||
evaluated = DefConceptEvaluator().eval(context, def_ret_val)
|
||||
|
||||
assert evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
created_concept = evaluated.body.body
|
||||
assert created_concept.get_metadata().name == "plus"
|
||||
assert created_concept.get_metadata().key == "plus"
|
||||
assert created_concept.get_metadata().definition == "(one|two)=n1 'plus' (one|two)=n2"
|
||||
assert created_concept.get_metadata().definition_type == "bnf"
|
||||
assert created_concept.get_metadata().variables == [('n1', None), ('one', None), ('two', None), ('n2', None)]
|
||||
assert created_concept.get_metadata().parameters == ['n1', 'n2']
|
||||
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unamed_ordered_choice(self):
|
||||
sheerka, context, one, two, three = self.init_concepts("one", "two", "three", create_new=True)
|
||||
text = "def concept choice from bnf (one|two) 'or' (two|three) 'or' (two|three)=c3"
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
|
||||
evaluated = DefConceptEvaluator().eval(context, def_ret_val)
|
||||
|
||||
assert evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
created_concept = evaluated.body.body
|
||||
assert created_concept.get_metadata().name == "choice"
|
||||
assert created_concept.get_metadata().key == "choice"
|
||||
assert created_concept.get_metadata().definition == "(one|two) 'or' (two|three) 'or' (two|three)=c3"
|
||||
assert created_concept.get_metadata().definition_type == "bnf"
|
||||
assert created_concept.get_metadata().variables == [('one', None), ('two', None), ('three', None), ('c3', None)]
|
||||
assert created_concept.get_metadata().parameters == ['__OrderedChoice__1', '__OrderedChoice__2', "c3"]
|
||||
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unordered_choice(self):
|
||||
# as it's not possible to directly defined UnorderedChoice, we test isa concept
|
||||
sheerka, context, one, two, number = self.init_concepts("one", "two", "number", create_new=True)
|
||||
global_truth_context = self.get_context(global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, one, number)
|
||||
sheerka.set_isa(global_truth_context, two, number)
|
||||
|
||||
text = "def concept plus from bnf number=n1 'plus' number=n2 as n1 + n2"
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
|
||||
evaluated = DefConceptEvaluator().eval(context, def_ret_val)
|
||||
|
||||
assert evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
created_concept = evaluated.body.body
|
||||
assert created_concept.get_metadata().name == "plus"
|
||||
assert created_concept.get_metadata().key == "plus"
|
||||
assert created_concept.get_metadata().definition == "number=n1 'plus' number=n2"
|
||||
assert created_concept.get_metadata().definition_type == "bnf"
|
||||
assert created_concept.get_metadata().variables == [('n1', None), ('n2', None)]
|
||||
assert created_concept.get_metadata().parameters == ['n1', 'n2']
|
||||
|
||||
def test_i_can_eval_when_bnf_with_implicit_variables_from_unamed_unordered_choice(self):
|
||||
# as it's not possible to directly defined UnorderedChoice, we test isa concept
|
||||
sheerka, context, one, two, number = self.init_concepts("one", "two", "number", create_new=True)
|
||||
global_truth_context = self.get_context(global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, one, number)
|
||||
sheerka.set_isa(global_truth_context, two, number)
|
||||
|
||||
text = "def concept plus from bnf number 'plus' number as number[0] + number[1]"
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
|
||||
evaluated = DefConceptEvaluator().eval(context, def_ret_val)
|
||||
|
||||
assert evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
created_concept = evaluated.body.body
|
||||
assert created_concept.get_metadata().name == "plus"
|
||||
assert created_concept.get_metadata().key == "plus"
|
||||
assert created_concept.get_metadata().definition == "number 'plus' number"
|
||||
assert created_concept.get_metadata().definition_type == "bnf"
|
||||
assert created_concept.get_metadata().variables == [('number', None)]
|
||||
assert created_concept.get_metadata().parameters == ['number']
|
||||
|
||||
def test_i_can_eval_when_bnf_concept_with_regex(self):
|
||||
context = self.get_context()
|
||||
def_ret_val = DefConceptParser().parse(context, ParserInput("def concept hello a from bnf r'[a-z]+'=a 'hello'"))
|
||||
@@ -339,6 +417,8 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert created_concept.get_metadata().key == "hello __var__0"
|
||||
assert created_concept.get_metadata().definition == "r'[a-z]+'=a 'hello'"
|
||||
assert created_concept.get_metadata().definition_type == "bnf"
|
||||
assert created_concept.get_metadata().variables == [('a', None)]
|
||||
assert created_concept.get_metadata().parameters == ['a']
|
||||
|
||||
def test_i_can_eval_when_bnf_concept_with_variable(self):
|
||||
context = self.get_context()
|
||||
@@ -355,6 +435,8 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert created_concept.get_metadata().definition_type == "bnf"
|
||||
assert created_concept.get_metadata().variables == [("x", None)]
|
||||
assert created_concept._bnf == Sequence(StrMatch("hello"), VariableExpression("x"))
|
||||
assert created_concept.get_metadata().variables == [('x', None)]
|
||||
assert created_concept.get_metadata().parameters == ['x']
|
||||
|
||||
def test_i_can_eval_when_auto_eval_is_true(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
@@ -94,6 +94,7 @@ as:
|
||||
expected.get_metadata().id = "1001"
|
||||
expected.get_metadata().desc = None
|
||||
expected.get_metadata().variables = [("a", None), ("b", None)]
|
||||
expected.get_metadata().parameters = ["a", "b"]
|
||||
expected.init_key()
|
||||
|
||||
sheerka = self.get_sheerka(cache_only=False)
|
||||
@@ -134,6 +135,7 @@ as:
|
||||
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
|
||||
expected = Concept(name="a xx b", body="a plus b").def_var("a").def_var("b").init_key()
|
||||
expected.get_metadata().id = "1001"
|
||||
expected.get_metadata().parameters = ["a", "b"]
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
@@ -1392,17 +1394,32 @@ as:
|
||||
"set_isa(color, adjective)",
|
||||
"def concept what is the x of y pre is_question() as smart_get_attr(y, x)",
|
||||
"def concept qualify x from bnf adjective x as set_attr(x, c:adjective:, adjective) ret x",
|
||||
"eval a red short",
|
||||
]
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval a red short")
|
||||
res = sheerka.evaluate_user_input("what is the color of the short ?")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == "red"
|
||||
|
||||
res = sheerka.evaluate_user_input("eval a blue short")
|
||||
sheerka.evaluate_user_input("eval a blue short")
|
||||
res = sheerka.evaluate_user_input("what is the color of the short ?")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == "blue"
|
||||
|
||||
def test_i_can_access_a_concept_after_a_global_set_attr(self):
|
||||
init = [
|
||||
"def concept foo",
|
||||
"def concept color",
|
||||
"def concept red",
|
||||
"global_truth(set_attr(foo, color, red))"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
res = sheerka.evaluate_user_input("inspect(foo)")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ name : foo
|
||||
key : foo
|
||||
definition: None
|
||||
type : None
|
||||
hash : 16f7fbb8bc509b8c652edaf3d0c0457d15a37f0a862fbe03fa357b0c77249c46
|
||||
hash : 632c9ac7f3a08777918aeee4bb53712caedc634a863ae39a641f69055ae2e238
|
||||
body : 1
|
||||
where : None
|
||||
pre : None
|
||||
@@ -45,7 +45,7 @@ name : foo
|
||||
key : foo
|
||||
definition: None
|
||||
type : None
|
||||
hash : 7036cd5ffa9294d2e1dc9bf9c9bbe2783ace5cf7f423bfce9b28c8d33c0d1d0c
|
||||
hash : 23a1a8bc5966982471aa19b8452e22d414a55d704431866e198570913d47fd7d
|
||||
body : 2
|
||||
where : None
|
||||
pre : None
|
||||
@@ -71,7 +71,7 @@ name : foo
|
||||
key : foo
|
||||
definition: None
|
||||
type : None
|
||||
hash : 16f7fbb8bc509b8c652edaf3d0c0457d15a37f0a862fbe03fa357b0c77249c46
|
||||
hash : 632c9ac7f3a08777918aeee4bb53712caedc634a863ae39a641f69055ae2e238
|
||||
body : 1
|
||||
where : None
|
||||
pre : None
|
||||
@@ -84,7 +84,7 @@ name : foo
|
||||
key : foo
|
||||
definition: None
|
||||
type : None
|
||||
hash : e8dd1af1b6bc0eca0fb4a87a6fabb16655caa4b7a6ea9dbbd1f887757e6caf89
|
||||
hash : 60e442c59940a2616a3783d2e34f428f4a5ae456a88539bba9a5e87cf77060a6
|
||||
body : 2
|
||||
where : True
|
||||
pre : None
|
||||
|
||||
@@ -5,7 +5,7 @@ from core.concept import Concept, DEFINITION_TYPE_DEF
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from parsers.SequenceNodeParser import SequenceNodeParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import compute_expected_array, CN, CNC, SCN, get_test_obj, compare_with_test_object, \
|
||||
from tests.parsers.parsers_utils import compute_expected_array, CN, SCN, get_test_obj, compare_with_test_object, \
|
||||
UTN
|
||||
|
||||
|
||||
@@ -275,6 +275,26 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert concept_found.get_hints().is_evaluated
|
||||
assert not concept_found.get_hints().is_instance
|
||||
|
||||
def test_i_can_parse_when_variable_is_not_a_parameter(self):
|
||||
concepts_map = {
|
||||
"foo": Concept("foo").def_var("a"), # 'a' is not a parameter (but a property like its color for ex)
|
||||
}
|
||||
|
||||
text, expected = "foo", ["foo"]
|
||||
sheerka, context, parser = self.init_parser(concepts_map, create_new=True, use_sheerka=True)
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
wrapper = res.body
|
||||
lexer_nodes = res.body.body
|
||||
|
||||
assert res.status
|
||||
|
||||
expected_array = compute_expected_array(concepts_map, text, expected)
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
compare_with_test_object(lexer_nodes, expected_array)
|
||||
assert not lexer_nodes[0].concept.get_hints().is_evaluated
|
||||
assert lexer_nodes[0].concept.get_hints().use_copy
|
||||
assert lexer_nodes[0].concept.get_hints().is_instance
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"foo",
|
||||
f"foo one",
|
||||
|
||||
@@ -1114,6 +1114,33 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
# check metadata
|
||||
assert expected_concept.get_metadata().variables == [("a", "twenty one")]
|
||||
|
||||
def test_i_can_parse_when_all_variables_are_not_parameters(self):
|
||||
my_map = {
|
||||
"foo": Concept("foo a").def_var("a", "'default_a'").def_var("b", "'default_b'"), # 'b' is not a parameter
|
||||
"bar": Concept("bar b").def_var("a", "'default_a'").def_var("b", "'default_b'"), # 'a' is not a parameter
|
||||
"baz": Concept("baz")
|
||||
}
|
||||
sheerka, context, parser = self.init_parser(my_map)
|
||||
|
||||
text = "foo baz"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
assert res.status
|
||||
assert len(res.body.body) == 1
|
||||
|
||||
expected_concept = res.body.body[0].concept
|
||||
assert sheerka.isinstance(expected_concept.get_compiled()["a"], "baz")
|
||||
assert "b" not in expected_concept.get_compiled()
|
||||
assert expected_concept.get_metadata().variables == [("a", "baz"), ("b", "'default_b'")]
|
||||
|
||||
text = "bar baz"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
assert res.status
|
||||
assert len(res.body.body) == 1
|
||||
expected_concept = res.body.body[0].concept
|
||||
assert sheerka.isinstance(expected_concept.get_compiled()["b"], "baz")
|
||||
assert "a" not in expected_concept.get_compiled()
|
||||
assert expected_concept.get_metadata().variables == [("a", "'default_a'"), ("b", "baz")]
|
||||
|
||||
def test_i_can_parse_sequences(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
|
||||
@@ -1335,6 +1362,19 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
|
||||
|
||||
def test_i_cannot_parse_concept_when_variable_is_not_a_parameter(self):
|
||||
my_map = {
|
||||
"foo": Concept("foo").def_var("a") # 'a' is not a parameter (but a property like its color for ex)
|
||||
}
|
||||
sheerka, context, parser = self.init_parser(my_map)
|
||||
|
||||
text = "foo"
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
|
||||
assert res.body.body == text
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("function(", ([], "function(")),
|
||||
("before the function(", (["before the "], "function(")),
|
||||
|
||||
Reference in New Issue
Block a user