-
-
Notifications
You must be signed in to change notification settings - Fork 832
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5319aaf
commit a9189eb
Showing
2 changed files
with
351 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
from itertools import ( | ||
chain, | ||
) | ||
|
||
from vyper.exceptions import ( | ||
CompilerPanic, | ||
) | ||
|
||
|
||
class VyperNode: | ||
__slots__ = ('node_id', 'source_code', 'col_offset', 'lineno') | ||
ignored_fields = ('ctx', ) | ||
only_empty_fields = () | ||
|
||
@classmethod | ||
def get_slots(cls): | ||
return chain.from_iterable( | ||
getattr(klass, '__slots__', []) | ||
for klass in cls.__class__.mro(cls) | ||
) | ||
|
||
def __init__(self, **kwargs): | ||
|
||
for field_name, value in kwargs.items(): | ||
if field_name in self.get_slots(): | ||
setattr(self, field_name, value) | ||
# elif value: | ||
# raise CompilerPanic( | ||
# f'Unsupported non-empty value field_name: {field_name}, ' | ||
# f' class: {type(self)} value: {value}' | ||
# ) | ||
|
||
|
||
class Module(VyperNode): | ||
__slots__ = ('body', ) | ||
|
||
|
||
class Name(VyperNode): | ||
__slots__ = ('id', ) | ||
|
||
|
||
class Subscript(VyperNode): | ||
__slots__ = ('slice', 'value') | ||
|
||
|
||
class Index(VyperNode): | ||
__slots__ = ('value', ) | ||
|
||
|
||
class arg(VyperNode): | ||
__slots__ = ('arg', 'annotation') | ||
|
||
|
||
class Tuple(VyperNode): | ||
__slots__ = ('elts', ) | ||
|
||
|
||
class FunctionDef(VyperNode): | ||
__slots__ = ('args', 'body', 'returns', 'name', 'decorator_list', 'pos') | ||
|
||
|
||
class arguments(VyperNode): | ||
__slots__ = ('args', 'defaults', 'default') | ||
only_empty_fields = ('vararg', 'kwonlyargs', 'kwarg', 'kw_defaults') | ||
|
||
|
||
class Import(VyperNode): | ||
pass | ||
|
||
|
||
class Call(VyperNode): | ||
__slots__ = ('func', 'args', 'keywords', 'keyword') | ||
|
||
|
||
class keyword(VyperNode): | ||
__slots__ = ('arg', 'value') | ||
|
||
|
||
class Str(VyperNode): | ||
__slots__ = ('s', ) | ||
|
||
|
||
class Compare(VyperNode): | ||
__slots__ = ('comparators', 'ops', 'left', 'right') | ||
|
||
|
||
class Num(VyperNode): | ||
__slots__ = ('n', ) | ||
|
||
|
||
class NameConstant(VyperNode): | ||
__slots__ = ('value', ) | ||
|
||
|
||
class Attribute(VyperNode): | ||
__slots__ = ('attr', 'value',) | ||
|
||
|
||
class Op(VyperNode): | ||
__slots__ = ('op', 'left', 'right') | ||
|
||
|
||
class BinOp(Op): | ||
pass | ||
|
||
|
||
class BoolOp(Op): | ||
pass | ||
|
||
|
||
class UnaryOp(Op): | ||
operand = ('operand', ) | ||
|
||
|
||
class List(VyperNode): | ||
__slots__ = ('elts', ) | ||
|
||
|
||
class Dict(VyperNode): | ||
__slots__ = ('keys', 'values') | ||
|
||
|
||
class Bytes(VyperNode): | ||
__slots__ = ('s', ) | ||
|
||
|
||
class Add(VyperNode): | ||
pass | ||
|
||
|
||
class Sub(VyperNode): | ||
pass | ||
|
||
|
||
class Mult(VyperNode): | ||
pass | ||
|
||
|
||
class Div(VyperNode): | ||
pass | ||
|
||
|
||
class Mod(VyperNode): | ||
pass | ||
|
||
|
||
class Pow(VyperNode): | ||
pass | ||
|
||
|
||
class In(VyperNode): | ||
pass | ||
|
||
|
||
class Gt(VyperNode): | ||
pass | ||
|
||
|
||
class GtE(VyperNode): | ||
pass | ||
|
||
|
||
class LtE(VyperNode): | ||
pass | ||
|
||
|
||
class Lt(VyperNode): | ||
pass | ||
|
||
|
||
class Eq(VyperNode): | ||
pass | ||
|
||
|
||
class NotEq(VyperNode): | ||
pass | ||
|
||
|
||
class And(VyperNode): | ||
pass | ||
|
||
|
||
class Or(VyperNode): | ||
pass | ||
|
||
|
||
class Not(VyperNode): | ||
pass | ||
|
||
|
||
class USub(VyperNode): | ||
pass | ||
|
||
|
||
class Expr(VyperNode): | ||
__slots__ = ('value', ) | ||
|
||
|
||
class Pass(VyperNode): | ||
pass | ||
|
||
|
||
class AnnAssign(VyperNode): | ||
__slots__ = ('target', 'annotation', 'value', 'simple') | ||
|
||
|
||
class Assign(VyperNode): | ||
__slots__ = ('targets', 'value') | ||
|
||
|
||
class If(VyperNode): | ||
__slots__ = ('test', 'body', 'orelse') | ||
|
||
|
||
class Assert(VyperNode): | ||
__slots__ = ('test', 'msg') | ||
|
||
|
||
class For(VyperNode): | ||
__slots__ = ('iter', 'target', 'orelse', 'body') | ||
|
||
|
||
class AugAssign(VyperNode): | ||
__slots__ = ('op', 'target', 'value') | ||
|
||
|
||
class Break(VyperNode): | ||
pass | ||
|
||
|
||
class Continue(VyperNode): | ||
pass | ||
|
||
|
||
class Return(VyperNode): | ||
__slots__ = ('value', ) | ||
|
||
|
||
class Delete(VyperNode): | ||
pass | ||
|
||
|
||
class stmt(VyperNode): | ||
pass | ||
|
||
|
||
class ClassDef(VyperNode): | ||
__slots__ = ('class_type', 'name', 'body') | ||
|
||
|
||
class ImportFrom(VyperNode): | ||
pass | ||
|
||
|
||
class Raise(VyperNode): | ||
pass | ||
|
||
|
||
class Slice(VyperNode): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import ast as python_ast | ||
|
||
import vyper.ast as vyper_ast | ||
from vyper.exceptions import ( | ||
ParserException, | ||
SyntaxException, | ||
) | ||
from vyper.parser.parser_utils import ( | ||
annotate_and_optimize_ast, | ||
) | ||
from vyper.parser.pre_parser import ( | ||
pre_parse, | ||
) | ||
|
||
|
||
def parse_python_ast(source_code, node): | ||
if isinstance(node, list): | ||
o = [] | ||
for n in node: | ||
o.append( | ||
parse_python_ast( | ||
source_code=source_code, | ||
node=n, | ||
) | ||
) | ||
return o | ||
elif isinstance(node, python_ast.AST): | ||
class_name = node.__class__.__name__ | ||
if hasattr(vyper_ast, class_name): | ||
vyper_class = getattr(vyper_ast, class_name) | ||
init_kwargs = { | ||
'col_offset': getattr(node, 'col_offset', None), | ||
'lineno': getattr(node, 'lineno', None), | ||
'node_id': node.node_id | ||
} | ||
if isinstance(node, python_ast.ClassDef): | ||
init_kwargs['class_type'] = node.class_type | ||
for field_name in node._fields: | ||
val = getattr(node, field_name) | ||
if field_name in vyper_class.ignored_fields: | ||
continue | ||
elif val and field_name in vyper_class.only_empty_fields: | ||
raise SyntaxException( | ||
f'"{field_name}" is an unsupported attribute field ' | ||
f'on Python AST "{class_name}" class.', node | ||
) | ||
else: | ||
init_kwargs[field_name] = parse_python_ast( | ||
source_code=source_code, | ||
node=val, | ||
) | ||
return vyper_class(**init_kwargs) | ||
else: | ||
raise SyntaxException( | ||
f'Invalid syntax (unsupported "{class_name}" Python AST node).', node | ||
) | ||
else: | ||
return node | ||
|
||
|
||
def parse_to_ast(source_code): | ||
class_types, reformatted_code = pre_parse(source_code) | ||
if '\x00' in reformatted_code: | ||
raise ParserException('No null bytes (\\x00) allowed in the source code.') | ||
py_ast = python_ast.parse(reformatted_code) | ||
annotate_and_optimize_ast(py_ast, source_code, class_types) | ||
# Convert to Vyper AST. | ||
vyper_ast = parse_python_ast( | ||
source_code=source_code, | ||
node=py_ast, | ||
) | ||
return vyper_ast.body | ||
|
||
|
||
def ast_to_dict(node): | ||
skip_list = ('source_code', ) | ||
if isinstance(node, vyper_ast.VyperNode): | ||
o = { | ||
f: ast_to_dict(getattr(node, f)) | ||
for f in node.get_slots() | ||
if f not in skip_list | ||
} | ||
o.update({'ast_type': node.__class__.__name__}) | ||
return o | ||
elif isinstance(node, list): | ||
return [ | ||
ast_to_dict(x) | ||
for x in node | ||
] | ||
else: | ||
return node |