Last active
May 22, 2018 10:58
-
-
Save akimach/029674d66766db21abf49602b2345999 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 | |
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