Files
Sheerka-Old/parsers/PythonParser.py
T
2019-10-29 18:39:51 +01:00

76 lines
2.3 KiB
Python

from parsers.BaseParser import BaseParser, Node, ErrorNode
from dataclasses import dataclass
import ast
import copy
@dataclass()
class PythonErrorNode(ErrorNode):
source: str
exception: Exception
@dataclass()
class PythonNode(Node):
source: str
ast: ast.AST
def __repr__(self):
return "PythonNode(" + ast.dump(self.ast) + ")"
#return "PythonNode(" + self.source + ")"
class PythonParser(BaseParser):
def __init__(self, text, source="<undef>"):
text = text if isinstance(text, str) else self.get_text_from_tokens(text)
text = text.strip()
BaseParser.__init__(self, "PythonParser", text)
self.source = source
def parse(self):
# first, try to parse an expression
res, tree, error = self.try_parse_expression()
if not res:
# then try to parse a statement
res, tree, error = self.try_parse_statement()
if not res:
self.has_error = True
error_node = PythonErrorNode(self.text, error)
self.error_sink.append(error_node)
return error_node
return PythonNode(self.text, tree)
def try_parse_expression(self):
try:
return True, ast.parse(self.text, f"<{self.source}>", 'eval'), None
except Exception as error:
return False, None, error
def try_parse_statement(self):
try:
return True, ast.parse(self.text, f"<{self.source}>", 'exec'), None
except Exception as error:
return False, None, error
def expr_to_expression(self, expr):
expr.lineno = 0
expr.col_offset = 0
result = ast.Expression(expr.value, lineno=0, col_offset=0)
return result
def exec_with_return(self, code):
code_ast = ast.parse(code)
init_ast = copy.deepcopy(code_ast)
init_ast.body = code_ast.body[:-1]
last_ast = copy.deepcopy(code_ast)
last_ast.body = code_ast.body[-1:]
exec(compile(init_ast, "<ast>", "exec"), globals())
if type(last_ast.body[0]) == ast.Expr:
return eval(compile(self.expr_to_expression(last_ast.body[0]), "<ast>", "eval"), globals())
else:
exec(compile(last_ast, "<ast>", "exec"), globals())