Files
Sheerka-Old/src/core/builtin_concepts.py
T

550 lines
20 KiB
Python

from enum import Enum
from core.concept import Concept, ConceptParts
class BuiltinConcepts(Enum):
"""
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 instruction may alter how the actions work
DEBUG = "debug" # activate all debug information
EVAL_BODY_REQUESTED = "eval body" # to evaluate the body
EVAL_WHERE_REQUESTED = "eval where" # to evaluate the where clause
RETURN_BODY_REQUESTED = "return body" # returns the body of the concept instead of the concept itself
REDUCE_REQUESTED = "reduce" # remove meaningless error when possible
EVAL_UNTIL_SUCCESS_REQUESTED = "eval until success" # PythonEvaluator tries combination until True is found
EVAL_QUESTION_REQUESTED = "question" # the user input must be treated as question
# possible actions during sheerka.execute()
INIT_SHEERKA = "init sheerka" #
PROCESS_INPUT = "process input" # Processing user input or other input
PROCESSING = "processing input" # 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 concept attribute" #
VALIDATE_CONCEPT = "validate concept"
VALIDATING_CONCEPT = "validating concept"
INIT_COMPILED = "initializing concept compiled"
INIT_BNF = "initialize bnf"
MANAGE_INFINITE_RECURSION = "manage infinite recursion"
PARSE_CODE = "execute source code"
EXEC_CODE = "execute source code" # to use when executing Python or other language compiled code
TESTING = "testing"
# builtin attributes
ISA = "is a" # when a concept is an instance of another one
AUTO_EVAL = "auto eval" # when the concept must be auto evaluated
# object
USER_INPUT = "user input concept" # represent an input from an user
SUCCESS = "success concept"
ERROR = "error concept"
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 concept" # a value is returned
CONCEPT_TOO_LONG = "concept too long concept" # 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
ALREADY_DEFINED = "already defined" # when you try to add the same object twice (a concept or whatever)
NOP = "no operation" # no operation concept. Does nothing
CONCEPT_EVAL_ERROR = "concept evaluation error" # cannot evaluate a property or metadata of a concept
ENUMERATION = "enum" # 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"
EVALUATOR_PRE_PROCESS = "evaluator pre process" # used modify / tweak behaviour of evaluators
NOT_A_SET = "not a set" # the concept has no entry in sets
CONDITION_FAILED = "where clause 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_INITIALIZED = "not initialized"
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 = "security error" # when trying to execute statement when only expression is allowed
INVALID_LESSER_OPERATION = "Invalid lesser operation"
INVALID_GREATEST_OPERATION = "Invalid greatest operation"
NODE = "node"
GENERIC_NODE = "generic node"
IDENTIFIER_NODE = "identifier node"
def __repr__(self):
return "__" + self.name
def __str__(self):
return "__" + self.name
def __eq__(self, other):
if id(self) == id(other):
return True
if isinstance(other, str):
return str(self) == other
if not isinstance(other, BuiltinConcepts):
return False
return self.value == other.value
def __hash__(self):
return hash(self.value)
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 = [str(e) for e in {
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.ALREADY_DEFINED,
BuiltinConcepts.CONCEPT_EVAL_ERROR,
BuiltinConcepts.CONCEPT_ALREADY_IN_SET,
BuiltinConcepts.NOT_A_SET,
BuiltinConcepts.CONDITION_FAILED,
BuiltinConcepts.CHICKEN_AND_EGG,
BuiltinConcepts.NOT_INITIALIZED,
BuiltinConcepts.NOT_FOUND,
BuiltinConcepts.INVALID_LESSER_OPERATION,
BuiltinConcepts.INVALID_GREATEST_OPERATION,
# DO NOT PUT NOT_INITIALIZED. It's not an error
}]
"""
Some concepts have a specific implementation
It's mainly to ease the usage
"""
class UserInputConcept(Concept):
def __init__(self, text=None, user_name=None):
super().__init__(BuiltinConcepts.USER_INPUT, True, False, BuiltinConcepts.USER_INPUT)
self.set_value(ConceptParts.BODY, text)
self.set_value("user_name", user_name)
self.metadata.is_evaluated = True
@property
def text(self):
return self.body
@property
def user_name(self):
return self.get_value("user_name")
def __repr__(self):
return f"({self.id}){self.name}: '{self.body}'"
class ErrorConcept(Concept):
def __init__(self, error=None):
super().__init__(BuiltinConcepts.ERROR, True, False, BuiltinConcepts.ERROR)
self.set_value(ConceptParts.BODY, error)
self.metadata.is_evaluated = True
def __repr__(self):
return f"({self.id}){self.name}: {self.body}"
class UnknownConcept(Concept):
def __init__(self, metadata=None):
super().__init__(BuiltinConcepts.UNKNOWN_CONCEPT, True, False, BuiltinConcepts.UNKNOWN_CONCEPT)
self.set_value(ConceptParts.BODY, metadata)
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
"""
def __init__(self, who=None, status=None, value=None, message=None, parents=None, concept_id=None):
super().__init__(BuiltinConcepts.RETURN_VALUE, True, False, BuiltinConcepts.RETURN_VALUE)
self.set_value(ConceptParts.BODY, value)
self.set_value("who", who)
self.set_value("status", status)
self.set_value("message", message)
self.set_value("parents", parents)
self.metadata.is_evaluated = True
self.metadata.id = concept_id
@property
def who(self):
return self.get_value("who")
@who.setter
def who(self, value):
self.set_value("who", value)
@property
def status(self):
return self.get_value("status")
@status.setter
def status(self, value):
self.set_value("status", value)
@property
def value(self):
return self.body
@value.setter
def value(self, value):
self.set_value(ConceptParts.BODY, value)
@property
def message(self):
return self.get_value("message")
@message.setter
def message(self, value):
self.set_value("message", value)
@property
def parents(self):
return self.get_value("parents")
@parents.setter
def parents(self, value):
self.set_value("parents", value)
def __repr__(self):
return f"ReturnValue(who={self.who}, status={self.status}, value={self.value}, message={self.message})"
def __eq__(self, other):
if not isinstance(other, ReturnValueConcept):
return False
return self.who == other.who and \
self.status == other.status and \
self.value == other.value and \
self.message == other.message
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):
"""
This error is raised when, during sheerka.new(), an unknown property is asked
"""
def __init__(self, property_name=None, concept=None):
super().__init__(BuiltinConcepts.UNKNOWN_PROPERTY, True, False, BuiltinConcepts.UNKNOWN_PROPERTY)
self.set_value(ConceptParts.BODY, 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})"
@property
def concept(self):
return self.get_value("concept")
@property
def property_name(self):
return self.body
class ParserResultConcept(Concept):
"""
Result of a parsing
"""
def __init__(self, parser=None, source=None, tokens=None, value=None, try_parsed=None):
super().__init__(BuiltinConcepts.PARSER_RESULT, True, False, BuiltinConcepts.PARSER_RESULT)
self.set_value(ConceptParts.BODY, value)
self.set_value("parser", parser)
self.set_value("source", source)
self.set_value("tokens", tokens)
self.set_value("try_parsed", try_parsed) # in case of error, what was found before the error
self.metadata.is_evaluated = True
def __repr__(self):
text = f"ParserResult(parser={self.get_value('parser')}"
source = self.get_value('source')
text += f", source='{source}')" if source else f", body='{self.body}')"
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.body == other.body and \
self.try_parsed == other.try_parsed
def __hash__(self):
return hash(self.metadata.name)
@property
def value(self):
return self.body
@property
def try_parsed(self):
return self.get_value("try_parsed")
@property
def source(self):
return self.get_value("source")
@property
def parser(self):
return self.get_value("parser")
@staticmethod
def get_parser_name(parser):
from parsers.BaseParser import BaseParser
return parser.name if isinstance(parser, BaseParser) else str(parser)
class InvalidReturnValueConcept(Concept):
"""
Error returned when an evaluator is not correctly coded
The accepted return value are
ReturnValueConcept, list of ReturnValueConcept or None
"""
def __init__(self, return_value=None, evaluator=None):
super().__init__(
BuiltinConcepts.INVALID_RETURN_VALUE,
True,
False,
BuiltinConcepts.INVALID_RETURN_VALUE)
self.set_value(ConceptParts.BODY, return_value)
self.set_value("evaluator", evaluator)
self.metadata.is_evaluated = True
class ConceptEvalError(Concept):
def __init__(self, error=None, concept=None, property_name=None):
super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR,
True,
False,
BuiltinConcepts.CONCEPT_EVAL_ERROR)
self.set_value(ConceptParts.BODY, 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})"
@property
def error(self):
return self.body
@property
def concept(self):
return self.get_value("concept")
@property
def property_name(self):
return self.get_value("property_name")
class EnumerationConcept(Concept):
def __init__(self, iteration=None):
super().__init__(BuiltinConcepts.ENUMERATION, True, False, BuiltinConcepts.ENUMERATION)
self.set_value(ConceptParts.BODY, iteration)
self.metadata.is_evaluated = True
class ListConcept(Concept):
def __init__(self, items=None):
super().__init__(BuiltinConcepts.LIST, True, False, BuiltinConcepts.LIST)
self.set_value(ConceptParts.BODY, items or [])
self.metadata.is_evaluated = True
def append(self, obj):
self.body.append(obj)
class FilteredConcept(Concept):
def __init__(self, filtered=None, iterable=None, predicate=None):
super().__init__(BuiltinConcepts.FILTERED, True, False, BuiltinConcepts.FILTERED)
self.set_value(ConceptParts.BODY, filtered)
self.set_value("iterable", iterable)
self.set_value("predicate", predicate)
self.metadata.is_evaluated = True
class ConceptAlreadyInSet(Concept):
def __init__(self, concept=None, concept_set=None):
super().__init__(BuiltinConcepts.CONCEPT_ALREADY_IN_SET,
True,
False,
BuiltinConcepts.CONCEPT_ALREADY_IN_SET)
self.set_value(ConceptParts.BODY, 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})"
@property
def concept(self):
return self.body
@property
def concept_set(self):
return self.get_value("concept_set")
class ConditionFailed(Concept):
def __init__(self, condition=None, concept=None, prop=None):
super().__init__(BuiltinConcepts.CONDITION_FAILED,
True,
False,
BuiltinConcepts.CONDITION_FAILED)
self.set_value(ConceptParts.BODY, condition)
self.set_value("concept", concept)
self.set_value("prop", prop)
self.metadata.is_evaluated = True
def __repr__(self):
return f"ConditionFailed(condition='{self.body}', concept='{self.concept}', prop='{self.prop}')"
class NotForMeConcept(Concept):
def __init__(self, source=None, reason=None):
super().__init__(BuiltinConcepts.NOT_FOR_ME,
True,
False,
BuiltinConcepts.NOT_FOR_ME)
self.set_value(ConceptParts.BODY, 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):
def __init__(self, digest=None, command=None, title=None, instructions=None, execution_result=None):
super().__init__(BuiltinConcepts.EXPLANATION,
True,
False,
BuiltinConcepts.EXPLANATION)
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(ConceptParts.BODY, execution_result) # list of results
self.metadata.is_evaluated = True
class PythonSecurityError(Concept):
def __init__(self, prop=None, source_code=None, source=None, line=None, column=None):
super().__init__(BuiltinConcepts.PYTHON_SECURITY_ERROR,
True,
False,
BuiltinConcepts.PYTHON_SECURITY_ERROR)
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(ConceptParts.BODY, source_code) # code being executed
self.metadata.is_evaluated = True
class NotFound(Concept):
def __init__(self, body=None):
super().__init__(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)}"