Fixed #18 : Parsing and evaluating Python

This commit is contained in:
2023-05-14 12:12:29 +02:00
parent e41094f908
commit 09a0246420
46 changed files with 2084 additions and 165 deletions
+5 -5
View File
@@ -1,6 +1,6 @@
from core.BuiltinConcepts import BuiltinConcepts
from core.ErrorContext import ErrorContext
from core.ExecutionContext import ExecutionContext, ExecutionContextActions
from core.error import ErrorContext
from core.ExecutionContext import ExecutionContext, ContextActions
from core.ReturnValue import ReturnValue
from evaluators.base_evaluator import EvaluatorEvalResult, EvaluatorMatchResult, OneReturnValueEvaluator
from parsers.ParserInput import ParserInput
@@ -10,7 +10,7 @@ class CreateParserInput(OneReturnValueEvaluator):
NAME = "CreateParserInput"
def __init__(self):
super().__init__(self.NAME, ExecutionContextActions.BEFORE_EVALUATION, 50)
super().__init__(self.NAME, ContextActions.BEFORE_PARSING, 50)
def matches(self, context: ExecutionContext, return_value: ReturnValue) -> EvaluatorMatchResult:
if return_value.status and \
@@ -26,5 +26,5 @@ class CreateParserInput(OneReturnValueEvaluator):
return EvaluatorEvalResult([new_ret_val], [return_value])
else:
error = ErrorContext(self.NAME, context, parser_input)
new_ret_val = ReturnValue(self.NAME, False, error, parents=[return_value])
return EvaluatorEvalResult([new_ret_val], [return_value])
error_ret_val = ReturnValue(self.NAME, False, error, parents=[return_value])
return EvaluatorEvalResult([error_ret_val], [return_value])
+31
View File
@@ -0,0 +1,31 @@
from core.BuiltinConcepts import BuiltinConcepts
from core.ExecutionContext import ExecutionContext, ContextActions
from core.ReturnValue import ReturnValue
from core.error import ErrorContext
from evaluators.base_evaluator import EvaluatorEvalResult, EvaluatorMatchResult, OneReturnValueEvaluator
class PythonEvaluator(OneReturnValueEvaluator):
NAME = "PythonEvaluator"
def __init__(self):
super().__init__(self.NAME, ContextActions.EVALUATION, 50)
def matches(self, context: ExecutionContext, return_value: ReturnValue) -> EvaluatorMatchResult:
return EvaluatorMatchResult(return_value.status and
context.sheerka.isinstance(return_value.value, BuiltinConcepts.PYTHON_CODE))
def eval(self, context: ExecutionContext,
evaluation_context: object,
return_value: ReturnValue) -> EvaluatorEvalResult:
sheerka = context.sheerka
fragment = return_value.value.pf
evaluated = sheerka.evaluate_python(context, fragment)
if isinstance(evaluated, ErrorContext):
return EvaluatorEvalResult([ReturnValue(self.name, False, evaluated, parents=[return_value])],
[])
else:
return EvaluatorEvalResult([ReturnValue(self.name, True, evaluated, parents=[return_value])],
[return_value])
+69
View File
@@ -0,0 +1,69 @@
import ast
from dataclasses import dataclass
from common.utils import encode_concept
from core.BuiltinConcepts import BuiltinConcepts
from core.ExecutionContext import ExecutionContext, ContextActions
from core.ReturnValue import ReturnValue
from core.error import ErrorContext, ErrorObj
from core.python_fragment import PythonFragment
from evaluators.base_evaluator import EvaluatorEvalResult, EvaluatorMatchResult, OneReturnValueEvaluator
from parsers.tokenizer import TokenKind
@dataclass()
class PythonErrorNode(ErrorObj):
source: str
exception: Exception
def get_error_msg(self) -> str:
return repr(self.exception)
def __eq__(self, other):
if not isinstance(other, PythonErrorNode):
return False
return self.source == other.source and self.exception == other.exception
def __hash__(self):
return hash((self.source, self.exception))
class PythonParser(OneReturnValueEvaluator):
NAME = "PythonParser"
def __init__(self):
super().__init__(self.NAME, ContextActions.PARSING, 80)
def matches(self, context: ExecutionContext, return_value: ReturnValue) -> EvaluatorMatchResult:
return EvaluatorMatchResult(return_value.status and
context.sheerka.isinstance(return_value.value, BuiltinConcepts.PARSER_INPUT))
def eval(self, context: ExecutionContext,
evaluation_context: object,
return_value: ReturnValue) -> EvaluatorEvalResult:
parser_input = return_value.value.body
tracker = {} # to keep track of concept tokens (c:xxx:)
python_switcher = {TokenKind.CONCEPT: lambda t: encode_concept(t.value),
TokenKind.RULE: lambda t: encode_concept(t.value, "R")}
source_code = parser_input.as_text(python_switcher, tracker).lstrip() # right side spaces must be kept
try:
ast_tree = ast.parse(source_code, f"<user input>", 'eval')
except:
try:
ast_tree = ast.parse(source_code, f"<user input>", 'exec')
except Exception as error:
error_context = ErrorContext(self.NAME, context, PythonErrorNode(parser_input.as_text(), error))
error_ret_val = ReturnValue(self.NAME, False, error_context, [return_value])
return EvaluatorEvalResult([error_ret_val], [])
# Successfully parsed some python code
python_code = context.sheerka.newn(BuiltinConcepts.PYTHON_CODE,
pf=PythonFragment(source_code,
ast_tree,
parser_input.original_text,
tracker))
new = ReturnValue(self.NAME, True, python_code, parents=[return_value])
return EvaluatorEvalResult([new], [return_value])
+2 -2
View File
@@ -1,6 +1,6 @@
from dataclasses import dataclass
from core.ExecutionContext import ExecutionContext, ExecutionContextActions
from core.ExecutionContext import ExecutionContext, ContextActions
from core.ReturnValue import ReturnValue
@@ -21,7 +21,7 @@ class BaseEvaluator:
Base class to evaluate ReturnValues
"""
def __init__(self, name, step: ExecutionContextActions, priority: int, enabled=True):
def __init__(self, name, step: ContextActions, priority: int, enabled=True):
self.name = name
self.step = step
self.priority = priority