Skip to content

Instantly share code, notes, and snippets.

@akimach
Last active May 22, 2018 10:58
Show Gist options
  • Save akimach/029674d66766db21abf49602b2345999 to your computer and use it in GitHub Desktop.
Save akimach/029674d66766db21abf49602b2345999 to your computer and use it in GitHub Desktop.
import ast
import builtins
def make_stmts(exps):
exps = [simplify(exp) for exp in exps]
if len(exps) == 1:
return exps[0]
else:
return ["stmts", *exps]
def simplify(exp):
def to_s(exp):
return exp.__class__.__name__
if type(exp) == ast.Num:
return ["lit", exp.n]
if type(exp) == ast.Str:
return ["lit", exp.s]
if type(exp) == ast.BinOp:
return [to_s(exp.op), simplify(exp.left), simplify(exp.right)]
if type(exp) == ast.Call:
r = [simplify(arg) for arg in exp.args]
return ["func_call", exp.func.id, *r]
if type(exp) == ast.Assign:
r = simplify(exp.value)
return ["var_assign", exp.targets[0].id, r]
if type(exp) == ast.Expr:
return simplify(exp.value)
if type(exp) == ast.Name:
if type(exp.ctx) == ast.Load:
return ["var_ref", exp.id]
if type(exp) == ast.If:
op = to_s(exp.test.ops[0])
test = exp.test
left = simplify(test.left)
comparator = simplify(test.comparators[0])
body = make_stmts(exp.body)
orelse = make_stmts(exp.orelse)
return ["if", [op, left, comparator], body, orelse]
if type(exp) == ast.While:
op = to_s(exp.test.ops[0])
test = exp.test
left = simplify(test.left)
comparator = simplify(test.comparators[0])
body = make_stmts(exp.body)
orelse = make_stmts(exp.orelse)
return ["while", [op, left, comparator], body, orelse]
if type(exp) == ast.FunctionDef:
name = exp.name
params = [arg.arg for arg in exp.args.args]
body = make_stmts(exp.body)
return ["func_def", name, params, body]
if type(exp) == ast.Return:
return ["Return", simplify(exp.value)]
print("unsupported node: ", exp)
def minpython_parse(src):
trees = ast.parse(src).body
return make_stmts(trees)
def minpython_call(mhd, args):
return getattr(builtins, mhd)(*args)
def evaluate(tree, env):
if tree[0] == "lit":
return tree[1]
if tree[0] == "Return":
return evaluate(tree[1], env)
if tree[0] == "Add":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
return left + right
if tree[0] == "Sub":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
return left - right
if tree[0] == "Mult":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
return left * right
if tree[0] == "Div":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
return left / right
if tree[0] == "func_call":
args = []
for t in tree[2:]:
args.append(evaluate(t, env))
mhd = env[tree[1]]
if mhd[0] == "builtin":
return minpython_call(mhd[1], args)
else:
params = mhd[1]
body = mhd[2]
new_env = {}
for param, arg in zip(params, args):
new_env[param] = arg
return evaluate(body, new_env)
if tree[0] == "var_assign":
env[tree[1]] = evaluate(tree[2], env)
if tree[0] == "var_ref":
return env[tree[1]]
if tree[0] == "if":
if evaluate(tree[1], env):
evaluate(tree[2], env)
else:
evaluate(tree[3], env)
if tree[0] == "Eq":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
if left == right:
return True
else:
return False
if tree[0] == "Gt":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
if left > right:
return True
else:
return False
if tree[0] == "Lt":
left = evaluate(tree[1], env)
right = evaluate(tree[2], env)
if left < right:
return True
else:
return False
if tree[0] == "while":
while evaluate(tree[1], env):
evaluate(tree[2], env)
else:
evaluate(tree[2], env)
if tree[0] == "func_def":
env[tree[1]] = ["user_defined", tree[2], tree[3]]
if tree[0] == "stmts":
last = None
for t in tree[1:]:
last = evaluate(t, env)
return last
src = """
(1 + 3) / (8 - 2 * 2)
x = 1
y = 2 + x
print(y)
if 0 == 0:
print(42)
else:
print(43)
i = 0
while i < 10:
print(i)
i = i + 1
def add(x, y):
return x + y
print(add(1, 1))
"""
tree = minpython_parse(src)
env = {"print": ["builtin", "print"], }
evaluate(tree, env)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment