from core.concept import Concept, ConceptParts from core.error import ErrorObj class BuiltinConcepts: """ List of builtin concepts that do no need any specific implementation Please note that the value of the enum is informal. It is not used in the system For example, the concept 'NODE' DOES NOT have the key, the id or whatever 200 The key if the name of the concept The id is a sequential number given just before the concept is saved in sdp The values of the enum is not used the code """ SHEERKA = "__SHEERKA" # processing instructions during sheerka.execute() or sheerka.evaluate_concept() # The instructions may alter how the actions work DEBUG = "__DEBUG" # activate all debug information EVAL_BODY_REQUESTED = "__EVAL_BODY_REQUESTED" # to evaluate the body EVAL_WHERE_REQUESTED = "__EVAL_WHERE_REQUESTED" # to evaluate the where clause RETURN_BODY_REQUESTED = "__RETURN_BODY_REQUESTED" # returns the body of the concept instead of the concept itself REDUCE_REQUESTED = "__REDUCE_REQUESTED" # remove meaningless error when possible EVAL_UNTIL_SUCCESS_REQUESTED = "__EVAL_UNTIL_SUCCESS_REQUESTED" # PythonEvaluator tries combination until True is found EVAL_QUESTION_REQUESTED = "__EVAL_QUESTION_REQUESTED" # the user input must be treated as question # possible actions during sheerka.execute() or sheerka.evaluate_rules() INIT_SHEERKA = "__INIT_SHEERKA" # PROCESS_INPUT = "__PROCESS_INPUT" # Processing user input or other input PROCESSING = "__PROCESSING" # Processing user input or other input BEFORE_PARSING = "__BEFORE_PARSING" # activated before evaluation by the parsers PARSING = "__PARSING" # activated during the parsing. It contains the text to parse AFTER_PARSING = "__AFTER_PARSING" # after parsing BEFORE_EVALUATION = "__BEFORE_EVALUATION" # before evaluation EVALUATION = "__EVALUATION" # activated when the parsing process seems to be finished AFTER_EVALUATION = "__AFTER_EVALUATION" # activated when the parsing process seems to be finished BEFORE_RENDERING = "__BEFORE_RENDERING" # activate before the output is rendered RENDERING = "__RENDERING" # rendering the response from sheerka AFTER_RENDERING = "__AFTER_RENDERING" # rendering the response from sheerka EVALUATE_SOURCE = "__EVALUATE_SOURCE" # EVALUATE_CONCEPT = "__EVALUATE_CONCEPT" # a concept will be evaluated EVALUATING_CONCEPT = "__EVALUATING_CONCEPT" # a concept will be evaluated EVALUATING_ATTRIBUTE = "__EVALUATING_ATTRIBUTE" # VALIDATE_CONCEPT = "__VALIDATE_CONCEPT" VALIDATING_CONCEPT = "__VALIDATING_CONCEPT" INIT_COMPILED = "__INIT_COMPILED" INIT_BNF = "__INIT_BNF" MANAGE_INFINITE_RECURSION = "__MANAGE_INFINITE_RECURSION" PARSE_CODE = "__PARSE_CODE" EXEC_CODE = "__EXEC_CODE" # to use when executing Python or other language compiled code TESTING = "__TESTING" EVALUATOR_PRE_PROCESS = "__EVALUATOR_PRE_PROCESS" # used modify / tweak behaviour of evaluators EVALUATING_RULES = "__EVALUATING_RULES" # builtin attributes ISA = "__ISA" # when a concept is an instance of another one HASA = "__HASA" # when a concept has/owns another concept AUTO_EVAL = "__AUTO_EVAL" # when the concept must be auto evaluated # object USER_INPUT = "__USER_INPUT" # represent an input from an user SUCCESS = "__SUCCESS" ERROR = "__ERROR" UNKNOWN_CONCEPT = "__UNKNOWN_CONCEPT" # the request concept is not recognized CANNOT_RESOLVE_CONCEPT = "__CANNOT_RESOLVE_CONCEPT" # when too many concepts with the same name RETURN_VALUE = "__RETURN_VALUE" # a value is returned CONCEPT_TOO_LONG = "__CONCEPT_TOO_LONG" # concept cannot be processed by exactConcept parser NEW_CONCEPT = "__NEW_CONCEPT" # when a new concept is added UNKNOWN_PROPERTY = "__UNKNOWN_PROPERTY" # when requesting for a unknown property PARSER_RESULT = "__PARSER_RESULT" TOO_MANY_SUCCESS = "__TOO_MANY_SUCCESS" # when expecting a limited number of successful return value TOO_MANY_ERRORS = "__TOO_MANY_ERRORS" # when expecting a limited number of successful return value ONLY_SUCCESSFUL = "__ONLY_SUCCESSFUL" # filter the result, only keep successful ones MULTIPLE_ERRORS = "__MULTIPLE_ERRORS" # filter the result, only keep evaluator in error NOT_FOR_ME = "__NOT_FOR_ME" # a parser recognize that the entry is not meant for it IS_EMPTY = "__IS_EMPTY" # when a set is empty NO_RESULT = "__NO_RESULT" # no return value returned INVALID_RETURN_VALUE = "__INVALID_RETURN_VALUE" # the return value of an evaluator is not correct CONCEPT_ALREADY_DEFINED = "__CONCEPT_ALREADY_DEFINED" # when you try to add the same object twice (a concept or whatever) PROPERTY_ALREADY_DEFINED = "__PROPERTY_ALREADY_DEFINED" # When you try to add the same element in a property NOP = "__NOP" # no operation concept. Does nothing CONCEPT_EVAL_ERROR = "__CONCEPT_EVAL_ERROR" # cannot evaluate a property or metadata of a concept ENUMERATION = "__ENUMERATION" # represents a list or a set LIST = "__LIST" # represents a list FILTERED = "__FILTERED" # represents the result of a filtering CONCEPT_ALREADY_IN_SET = "__CONCEPT_ALREADY_IN_SET" NOT_A_SET = "__NOT_A_SET" # the concept has no entry in sets CONDITION_FAILED = "__CONDITION_FAILED" # failed to validate where clause during evaluation CHICKEN_AND_EGG = "__CHICKEN_AND_EGG" # infinite recursion when declaring concept EXPLANATION = "__EXPLANATION" PRECEDENCE = "__PRECEDENCE" # use to set priority among concepts when parsing ASSOCIATIVITY = "__ASSOCIATIVITY" # use to set priority among concepts when parsing NOT_FOUND = "__NOT_FOUND" # when the wanted resource is not found FORMAT_INSTRUCTIONS = "__FORMAT_INSTRUCTIONS" # to express how to print the concept NOT_IMPLEMENTED = "__NOT_IMPLEMENTED" # instead of raise an error PYTHON_SECURITY_ERROR = "__PYTHON_SECURITY_ERROR" # when trying to execute statement when only expression is allowed INVALID_LESSER_OPERATION = "__INVALID_LESSER_OPERATION" INVALID_GREATEST_OPERATION = "__INVALID_GREATEST_OPERATION" NEW_RULE = "__NEW_RULE" UNKNOWN_RULE = "__UNKNOWN_RULE" NODE = "__NODE" GENERIC_NODE = "__GENERIC_NODE" IDENTIFIER_NODE = "__IDENTIFIER_NODE" # formatting TO_LIST = "__TO_LIST" TO_DICT = "__TO_DICT" AllBuiltinConcepts = [v for n, v in BuiltinConcepts.__dict__.items() if not n.startswith("__")] BuiltinUnique = [ BuiltinConcepts.EVAL_BODY_REQUESTED, BuiltinConcepts.EVAL_WHERE_REQUESTED, BuiltinConcepts.RETURN_BODY_REQUESTED, BuiltinConcepts.REDUCE_REQUESTED, BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED, BuiltinConcepts.EVAL_QUESTION_REQUESTED, BuiltinConcepts.INIT_SHEERKA, BuiltinConcepts.PROCESS_INPUT, BuiltinConcepts.PROCESSING, BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING, BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EVALUATION, BuiltinConcepts.BEFORE_RENDERING, BuiltinConcepts.RENDERING, BuiltinConcepts.AFTER_RENDERING, BuiltinConcepts.EVALUATE_CONCEPT, BuiltinConcepts.EVALUATING_CONCEPT, BuiltinConcepts.EVALUATING_ATTRIBUTE, BuiltinConcepts.VALIDATE_CONCEPT, BuiltinConcepts.VALIDATING_CONCEPT, BuiltinConcepts.INIT_COMPILED, BuiltinConcepts.INIT_BNF, BuiltinConcepts.MANAGE_INFINITE_RECURSION, BuiltinConcepts.PARSE_CODE, BuiltinConcepts.EXEC_CODE, BuiltinConcepts.TESTING, BuiltinConcepts.ISA, BuiltinConcepts.AUTO_EVAL, BuiltinConcepts.INVALID_LESSER_OPERATION, BuiltinConcepts.INVALID_GREATEST_OPERATION, ] BuiltinErrors = [ BuiltinConcepts.ERROR, BuiltinConcepts.UNKNOWN_CONCEPT, BuiltinConcepts.CANNOT_RESOLVE_CONCEPT, BuiltinConcepts.CONCEPT_TOO_LONG, BuiltinConcepts.UNKNOWN_PROPERTY, BuiltinConcepts.TOO_MANY_SUCCESS, BuiltinConcepts.TOO_MANY_ERRORS, BuiltinConcepts.MULTIPLE_ERRORS, BuiltinConcepts.INVALID_RETURN_VALUE, BuiltinConcepts.CONCEPT_ALREADY_DEFINED, BuiltinConcepts.PROPERTY_ALREADY_DEFINED, BuiltinConcepts.CONCEPT_EVAL_ERROR, BuiltinConcepts.CONCEPT_ALREADY_IN_SET, BuiltinConcepts.NOT_A_SET, BuiltinConcepts.CONDITION_FAILED, BuiltinConcepts.CHICKEN_AND_EGG, BuiltinConcepts.NOT_FOUND, BuiltinConcepts.INVALID_LESSER_OPERATION, BuiltinConcepts.INVALID_GREATEST_OPERATION, ] BuiltinContainers = [ BuiltinConcepts.PARSER_RESULT, BuiltinConcepts.ONLY_SUCCESSFUL, BuiltinConcepts.FILTERED, BuiltinConcepts.EXPLANATION, BuiltinConcepts.TO_LIST, BuiltinConcepts.TO_DICT, ] """ Some concepts have a specific implementation It's mainly to ease the usage """ class UserInputConcept(Concept): ALL_ATTRIBUTES = ["text", "user_name"] def __init__(self, text=None, user_name=None): Concept.__init__(self, BuiltinConcepts.USER_INPUT, True, False, BuiltinConcepts.USER_INPUT, bound_body="text") self.set_value("text", text) self.set_value("user_name", user_name) self._metadata.is_evaluated = True def __repr__(self): return f"({self.id}){self.name}: '{self.body}'" class ErrorConcept(Concept, ErrorObj): ALL_ATTRIBUTES = ["error"] def __init__(self, error=None, concept_id=None): Concept.__init__(self, BuiltinConcepts.ERROR, True, False, BuiltinConcepts.ERROR, id=concept_id, bound_body="error") self.set_value("error", error) self._metadata.is_evaluated = True def __repr__(self): return f"({self.id}){self.name}: {self.body}" class UnknownConcept(Concept, ErrorObj): ALL_ATTRIBUTES = ["concept_ref"] def __init__(self, concept_ref=None): Concept.__init__(self, BuiltinConcepts.UNKNOWN_CONCEPT, True, False, BuiltinConcepts.UNKNOWN_CONCEPT, bound_body="concept_ref") self.set_value("concept_ref", concept_ref) self._metadata.is_evaluated = True def __repr__(self): return f"({self.id}){self.name}: {self.body}" class ReturnValueConcept(Concept): """ This class represents the result of a data flow processing It's the main input for the evaluators """ ALL_ATTRIBUTES = ["who", "status", "value", "parents", "message"] def __init__(self, who=None, status=None, value=None, parents=None, message=None, concept_id=None): Concept.__init__(self, BuiltinConcepts.RETURN_VALUE, True, False, BuiltinConcepts.RETURN_VALUE, id=concept_id, bound_body="value") self.set_value("who", who) self.set_value("status", status) self.set_value("value", value) self.set_value("parents", parents) self.set_value("message", message) self._metadata.is_evaluated = True def __repr__(self): return f"ReturnValue(who={self.who}, status={self.status}, value={self.value}, message={self.message})" def __eq__(self, other): if id(self) == id(other): return True if not isinstance(other, ReturnValueConcept): return False return self.who == other.who and \ self.status == other.status and \ self.value == other.value def __hash__(self): if hasattr(self.value, "__iter__") and not isinstance(self.value, str): value_hash = hash(tuple(self.value)) else: value_hash = hash(self.value) return hash((self.who, self.status, value_hash)) class UnknownPropertyConcept(Concept, ErrorObj): """ This error is raised when, during sheerka.new(), an unknown property is asked """ ALL_ATTRIBUTES = ["property_name", "concept"] def __init__(self, property_name=None, concept=None): Concept.__init__(self, BuiltinConcepts.UNKNOWN_PROPERTY, True, False, BuiltinConcepts.UNKNOWN_PROPERTY, bound_body="property_name") self.set_value("property_name", property_name) self.set_value("concept", concept) self._metadata.is_evaluated = True def __repr__(self): return f"UnknownProperty(property={self.property_name}, concept={self.concept})" class ParserResultConcept(Concept): """ Result of a parsing """ ALL_ATTRIBUTES = ["parser", "source", "tokens", "value", "try_parsed"] def __init__(self, parser=None, source=None, tokens=None, value=None, try_parsed=None, concept_id=None): Concept.__init__(self, BuiltinConcepts.PARSER_RESULT, True, False, BuiltinConcepts.PARSER_RESULT, id=concept_id, bound_body="value") self.set_value("parser", parser) self.set_value("source", source) self.set_value("tokens", tokens) self.set_value("value", value) self.set_value("try_parsed", try_parsed) self._metadata.is_evaluated = True def __repr__(self): text = f"ParserResult(parser={self.parser}" text += f", source='{self.source}')" if self.source else f", body='{self.value}')" return text def __eq__(self, other): if not isinstance(other, ParserResultConcept): return False self_parser_name = self.get_parser_name(self.parser) other_parser_name = self.get_parser_name(other.parser) return self.source == other.source and \ self_parser_name == other_parser_name and \ self.value == other.value def __hash__(self): return hash(self._metadata.name) @staticmethod def get_parser_name(parser): from parsers.BaseParser import BaseParser return parser.name if isinstance(parser, BaseParser) else str(parser) class InvalidReturnValueConcept(Concept, ErrorObj): """ Error returned when an evaluator is not correctly coded The accepted return value are ReturnValueConcept, list of ReturnValueConcept or None """ ALL_ATTRIBUTES = ["return_value", "evaluator"] def __init__(self, return_value=None, evaluator=None): super().__init__( BuiltinConcepts.INVALID_RETURN_VALUE, True, False, BuiltinConcepts.INVALID_RETURN_VALUE, bound_body="return_value") self.set_value("return_value", return_value) self.set_value("evaluator", evaluator) self._metadata.is_evaluated = True class ConceptEvalError(Concept, ErrorObj): ALL_ATTRIBUTES = ["error", "concept", "property_name"] def __init__(self, error=None, concept=None, property_name=None): super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR, True, False, BuiltinConcepts.CONCEPT_EVAL_ERROR, bound_body="error") self.set_value("error", error) self.set_value("concept", concept) self.set_value("property_name", property_name) self._metadata.is_evaluated = True def __repr__(self): return f"ConceptEvalError(error={self.error}, concept={self.concept}, property={self.property_name})" class ListConcept(Concept): ALL_ATTRIBUTES = ["items"] def __init__(self, items=None): Concept.__init__(self, BuiltinConcepts.LIST, True, False, BuiltinConcepts.LIST, bound_body="items") self.set_value("items", items or []) self._metadata.is_evaluated = True def append(self, obj): self.body.append(obj) class FilteredConcept(Concept): ALL_ATTRIBUTES = ["filtered", "iterable", "predicate"] def __init__(self, filtered=None, iterable=None, predicate=None): Concept.__init__(self, BuiltinConcepts.FILTERED, True, False, BuiltinConcepts.FILTERED, bound_body="filtered") self.set_value("filtered", filtered) self.set_value("iterable", iterable) self.set_value("predicate", predicate) self._metadata.is_evaluated = True class ConceptAlreadyInSet(Concept, ErrorObj): ALL_ATTRIBUTES = ["concept", "concept_set"] def __init__(self, concept=None, concept_set=None): Concept.__init__(self, BuiltinConcepts.CONCEPT_ALREADY_IN_SET, True, False, BuiltinConcepts.CONCEPT_ALREADY_IN_SET, bound_body="concept") self.set_value("concept", concept) self.set_value("concept_set", concept_set) self._metadata.is_evaluated = True def __repr__(self): return f"ConceptAlreadyInSet(concept={self.concept}, concept_set={self.concept_set})" class PropertyAlreadyDefined(Concept, ErrorObj): ALL_ATTRIBUTES = ["property_name", "property_value", "concept"] def __init__(self, property_name=None, property_value=None, concept=None): Concept.__init__(self, BuiltinConcepts.PROPERTY_ALREADY_DEFINED, True, False, BuiltinConcepts.PROPERTY_ALREADY_DEFINED, bound_body="property_name") self.set_value("property_name", property_name) self.set_value("property_value", property_value) self.set_value("concept", concept) self._metadata.is_evaluated = True def __repr__(self): return f"PropertyAlreadyDefined(property={self.property_name}, value={self.property_value}, concept={self.concept})" class ConditionFailed(Concept, ErrorObj): ALL_ATTRIBUTES = ["condition", "concept", "prop", "reason"] def __init__(self, condition=None, concept=None, prop=None, reason=None): Concept.__init__(self, BuiltinConcepts.CONDITION_FAILED, True, False, BuiltinConcepts.CONDITION_FAILED, bound_body="condition") self.set_value("condition", condition) self.set_value("concept", concept) self.set_value("prop", prop) self.set_value("reason", reason) self._metadata.is_evaluated = True def __repr__(self): return f"ConditionFailed(condition='{self.body}', concept='{self.concept}', prop='{self.prop}')" class NotForMeConcept(Concept): # Not considered as an error ? ALL_ATTRIBUTES = ["source", "reason"] def __init__(self, source=None, reason=None): Concept.__init__(self, BuiltinConcepts.NOT_FOR_ME, True, False, BuiltinConcepts.NOT_FOR_ME, bound_body="source") self.set_value("source", source) self.set_value("reason", reason) self._metadata.is_evaluated = True def __repr__(self): return f"NotForMeConcept(source={self.body}, reason={self.get_value('reason')})" class ExplanationConcept(Concept): ALL_ATTRIBUTES = ["digest", "command", "title", "instructions", "execution_result"] def __init__(self, digest=None, command=None, title=None, instructions=None, execution_result=None): Concept.__init__(self, BuiltinConcepts.EXPLANATION, True, False, BuiltinConcepts.EXPLANATION, bound_body="execution_result") self.set_value("digest", digest) # event digest self.set_value("command", command) # explain command parameters self.set_value("title", title) # a title to the explanation self.set_value("instructions", instructions) # instructions for SheerkaPrint self.set_value("execution_result", execution_result) # list of results self._metadata.is_evaluated = True class PythonSecurityError(Concept, ErrorObj): ALL_ATTRIBUTES = ["prop", "source_code", "source", "line", "column"] def __init__(self, prop=None, source_code=None, source=None, line=None, column=None): Concept.__init__(self, BuiltinConcepts.PYTHON_SECURITY_ERROR, True, False, BuiltinConcepts.PYTHON_SECURITY_ERROR, bound_body="source_code") self.set_value("prop", prop) # property or variable that was evaluated self.set_value("source", source) # origin of the source code (eg. file name) self.set_value("line", line) # line number self.set_value("column", column) # column number self.set_value("source_code", source_code) # code being executed self._metadata.is_evaluated = True class NotFound(Concept, ErrorObj): ALL_ATTRIBUTES = [] def __init__(self, body=None): Concept.__init__(self, BuiltinConcepts.NOT_FOUND, True, False, BuiltinConcepts.NOT_FOUND) self.set_value(ConceptParts.BODY, body) def __repr__(self): return f"({self._metadata.id}){self._metadata.name}, body={self.get_value(ConceptParts.BODY)}" class ToListConcept(Concept): ALL_ATTRIBUTES = ["items", "recursion_depth", "recurse_on", "tab"] def __init__(self, items=None, recursion_depth=None, recurse_on=None, tab=None): Concept.__init__(self, BuiltinConcepts.TO_LIST, True, False, BuiltinConcepts.TO_LIST, bound_body="items") self.set_value("items", items) # items to display self.set_value("recursion_depth", recursion_depth) # recursion depth when showing children self.set_value("recurse_on", recurse_on) # which sub items should we display self.set_value("tab", tab) # customise tab (content and length) self._metadata.is_evaluated = True