Added DefaultParser
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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())
|
||||
Reference in New Issue
Block a user