Last active
August 27, 2020 07:51
-
-
Save everilae/7a3bf3dc1c5a69edf00e76488d5f94f6 to your computer and use it in GitHub Desktop.
Magic Python, for fun and 0 profit
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
import ast | |
_FILENAME = "<undefined>" | |
def magic(source, filename=_FILENAME): | |
a = ast.parse(source) | |
return Magic(filename).visit(a) | |
def macro(f): | |
f._macro = True | |
return f | |
def _is_macro(fun): | |
return getattr(fun, "_macro", False) | |
def _apply_macro(fun, node, *args): | |
return ast.fix_missing_locations(ast.copy_location(fun(*args), node)) | |
class Magic(ast.NodeTransformer): | |
def __init__(self, filename, ns=None): | |
self.ns = ns or {} | |
self.filename = filename | |
def visit_Call(self, node): | |
node = self.generic_visit(node) | |
fun = self.ns.get(getattr(node.func, "id", None)) | |
if _is_macro(fun): | |
node = _apply_macro(fun, node, *node.args) | |
return node | |
def _visit_def(self, node): | |
if node.decorator_list: | |
fun = self.ns.get(getattr(node.decorator_list[0], "id", None)) | |
if _is_macro(fun): | |
node = _apply_macro(fun, node, node) | |
return node | |
def visit_ClassDef(self, node): | |
node = self.generic_visit(node) | |
node = self._visit_def(node) | |
return node | |
def visit_FunctionDef(self, node): | |
node = self.generic_visit(node) | |
node = self._visit_def(node) | |
self.exec(node) | |
return node | |
def visit_Import(self, node): | |
node = self.generic_visit(node) | |
self.exec(node) | |
return node | |
def visit_ImportFrom(self, node): | |
node = self.generic_visit(node) | |
self.exec(node) | |
return node | |
def exec(self, node): | |
exec(compile(ast.Module(body=[node]), self.filename, "exec"), self.ns) | |
#def visit_Module(self, node): | |
# return ast.Module(body=[ | |
# *node.body, | |
# ast.Assign( | |
# targets=[ast.Name(id="__macros__", ctx=ast.Store())], | |
# value=ast.List(elts=[ast.Constant(value=n) for n in self.ns], | |
# ctx=ast.Load()))]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example