Skip to content

Instantly share code, notes, and snippets.

@duangsuse
Last active March 7, 2023 17:25
Show Gist options
  • Save duangsuse/a3f32c2a733a360e57138170327d6aba to your computer and use it in GitHub Desktop.
Save duangsuse/a3f32c2a733a360e57138170327d6aba to your computer and use it in GitHub Desktop.
bing py代码重构工具
from ipywidgets import interact
import ipywidgets as widgets
from lib2to3.refactor import RefactoringTool,get_all_fix_names as lsFix
import ast,astor,pickle
@interact
def convert(code=widgets.Textarea(value="map({it+1},[0])|{[*it]}, 1|{it+1}", description='Input Code'), fixes=widgets.SelectMultiple(options=lsFix('lib2to3.fixes'), description='Fixes')):
if not fixes:
tree = ast.parse(code)
# 使用自定义的访问器类遍历并修改语法树
tree = RefactorVisitor().visit(tree)
print(s:=astor.to_source(tree), astor.dump_tree(tree.body[0]))
try: return eval(s)
except:pass
tool = RefactoringTool(['lib2to3.fixes.fix_'+k for k in fixes])
try: r=tool.refactor_string(code+'\n', 'input.py'); print(r);return r
except:pass
# 定义一个自定义的节点访问器类,用于替换表达式
class RefactorVisitor(ast.NodeTransformer):
def visit_Set(self, node):
# 如果是花括号包围的表达式
match node.elts:
case [expr]:
return ast.Lambda(args=ast.arguments(args=[ast.arg(arg="it")], defaults=[]), body=expr) #kwonlyargs=[], kw_defaults=[]
case _: return node
def visit_BinOp(self, node):
# 如果是 '|',右边是花括号包围的表达式
match (node.op, node.left, node.right):
case (ast.BitOr(), num, ast.Set(elts=[expr])):
# 创建一个赋值表达式节点(walrus operator)
it = ast.NamedExpr(target=ast.Name(id="it", ctx=ast.Store()), value=self.visit(num))
# 创建一个元组节点,包含赋值表达式和表达式,并用切片操作取最后一个元素(-1)
body = ast.Tuple(elts=[it, expr], ctx=ast.Load())
slice = ast.Index(value=ast.Constant(value=-1))
return ast.Subscript(value=body, slice=slice, ctx=ast.Load())
case _:return node
evals=lambda x:x
class ForLoopInlines(ast.NodeTransformer):
def __init__(o):o.k=''; o.fn={}; o.kr={}
def visit(o, node):
vi=lambda e:[o.visit(pickle.loads(pickle.dumps(e))) for e in e]
incy=lambda t,k:k+str(t.__setitem__(k,r:=t.get(k,0)+1 ) or r)
# 如果for循环中有evals函数
match node:
case ast.Name(k):return ast.Name(k) if k!=o.k else o.v
case ast.For(k, ast.Call(f), body) if f.id == "evals":
# 对参数进行求值,并转换成列表
o.k=k.id; values = list(eval(astor.to_source(node.iter)))
new_nodes = []
# 遍历列表中的每个值
for x in values:
# 复制原始循环体,并替换其中所有出现循环变量的地方为常量
o.v = ast.copy_location(ast.Constant(x), k)
# 将赋值语句和复制后的循环体添加到新节点列表中
new_nodes.extend(vi(body))
# 返回新节点列表作为替换结果
return new_nodes
case ast.Call(f) if (e:=o.fn.get(f.id)):
# 创建一个新的赋值语句节点,将参数赋值给var
assign = [ast.Assign(targets=[ast.Name(k.arg)], value=o.visit(node.args[i])) for i,k in enumerate(e[0].args)]
o.k=e[2]; o.v=ast.Name(incy(o.kr,e[2]))
# 调用=>语句列表,包含赋值和返回
f.i.extend(vi([*assign, *e[1] ]))
return o.v
return super().visit(node)
def pos(o,e):
for e in ast.walk(e):
match e:
case ast.FunctionDef(k,ka, body,[deco]) if deco.id=='evals': o.fn[k]=(ka,body[0:-1], body[-1].value.id)
case ast.Expr(ast.Call(f)) if f.id in o.fn:
a,i=e.i; a.insert(i,ast.Module(body:=[])) #f(f(0)) ins pos
case ast.Call(f) if f.id in o.fn: f.i=body
case ast.Module(st):
for i,s in enumerate(st): s.i=(e.body,i)
# 定义原始代码字符串
code = "f=print\nfor x in evals([1+0,2,3]): f(x+1)"
# 将代码字符串转换成AST对象
tree = ast.parse(code)
tree =ast.parse('@evals\ndef f(x): x+=1; x+=2; return x \nf(f(0))')
# 创建ForLoopExpander对象并应用到AST对象上
expander = ForLoopInlines()
expander.pos(tree)
tree = expander.visit(tree)
# 将修改后的AST对象转换回代码字符串并打印输出
new_code = astor.to_source(tree)
print(new_code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment