Last active
December 10, 2015 16:48
-
-
Save munro/4463356 to your computer and use it in GitHub Desktop.
PyScript
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 json | |
| import operator as op | |
| import inspect | |
| f = open(inspect.getfile(inspect.currentframe())) | |
| code = ast.parse(f.read()) | |
| def tab_over(code): | |
| return '\n'.join([' ' + line for line in \ | |
| filter(op.truth, code.split('\n'))]) | |
| def compile_op(op): | |
| if isinstance(op, ast.Add): | |
| return '+' | |
| if isinstance(op, ast.Sub): | |
| return '-' | |
| if isinstance(op, ast.Gt): | |
| return '>' | |
| if isinstance(op, ast.Lt): | |
| return '-' | |
| if isinstance(op, ast.Eq): | |
| return '===' | |
| if isinstance(op, ast.And): | |
| return '&&' | |
| if isinstance(op, ast.Or): | |
| return '||' | |
| if isinstance(op, ast.Not): | |
| return '!' | |
| if isinstance(op, ast.Mod): | |
| # TODO! String interpolation.... JavaScript doesn't support operator | |
| # overloading | |
| return '%' | |
| if isinstance(op, ast.In): | |
| raise 'Nope, handle this higher up.' | |
| print('----OP %s----' % op.__class__.__name__) | |
| print(ast.dump(op)) | |
| return '----OP %s----' % op.__class__.__name__ | |
| def wrap_expr(fn): | |
| def wrapper(node): | |
| fuck = {'you': ''} | |
| def add_statement(text): | |
| fuck['you'] += text | |
| out = fn(node, add_statement) | |
| # return out if isinstance(out, str) else out[0] | |
| return (out, fuck['you']) \ | |
| if isinstance(out, str) \ | |
| else (out[0], code + fuck['you']) | |
| return wrapper | |
| def is_literal(node): | |
| return any([isinstance(node, t) for t in [ast.Str, ast.Num]]) \ | |
| or (isinstance(node, ast.Name) and (node.id in ['True', 'False'])) | |
| @wrap_expr | |
| def compile_expr(node, add_statement): | |
| def expr(node): | |
| expr, stmt = compile_expr(node) | |
| add_statement(stmt) | |
| return expr | |
| if isinstance(node, ast.List) or isinstance(node, ast.Tuple): | |
| return '[' + ', '.join([expr(elt) for elt in node.elts]) + ']' | |
| if isinstance(node, ast.Dict): | |
| if any([not is_literal(key) for key in node.keys]): | |
| raise 'YOU SUCK! TODO' | |
| return '{\n ' + ',\n'.join([ | |
| '%s: %s' % (expr(key), expr(value)) | |
| for key, value in zip(node.keys, node.values) | |
| ]) + '\n}' | |
| if isinstance(node, ast.Name): | |
| if node.id == 'True': | |
| return 'true' | |
| if node.id == 'False': | |
| return 'false' | |
| return node.id | |
| if isinstance(node, ast.Compare): | |
| def handle_comparator(left, op, right): | |
| if isinstance(op, ast.In): | |
| return '%s.some(function (_v) {\n return _v === %s;\n})' % ( | |
| expr(right), | |
| expr(left), | |
| ) | |
| return expr(left) + ' ' + \ | |
| compile_op(op) + ' ' + \ | |
| expr(right) | |
| return ' && '.join([ | |
| handle_comparator(left, op, right) | |
| for left, op, right in zip( | |
| [node.left] + node.comparators[:-1], | |
| node.ops, | |
| node.comparators, | |
| ) | |
| ]) | |
| if isinstance(node, ast.Num): | |
| return str(node.n) | |
| if isinstance(node, ast.Str): | |
| return json.dumps(node.s) | |
| if isinstance(node, ast.Lambda): | |
| return 'function (%s) {\n return %s;\n}' % ( | |
| ', '.join([expr(arg) for arg in node.args.args]), | |
| tab_over(expr(node.body)).lstrip() | |
| ) | |
| if isinstance(node, ast.Attribute): | |
| # TODO: Handle reserved keywords & invalid methods properly | |
| return expr(node.value) + '.' + node.attr | |
| if isinstance(node, ast.BoolOp): | |
| # TODO: Wtf? why is this a list...? :/ | |
| return expr(node.values[0]) + ' ' + \ | |
| compile_op(node.op) + ' ' + \ | |
| expr(node.values[1]) | |
| if isinstance(node, ast.BinOp): | |
| return expr(node.left) + ' ' + compile_op(node.op) + ' ' + \ | |
| expr(node.right) | |
| if isinstance(node, ast.UnaryOp): | |
| return compile_op(node.op) + expr(node.operand) | |
| if isinstance(node, ast.Call): | |
| return expr(node.func) + '(' + ', '.join( | |
| [expr(arg) for arg in node.args] | |
| ) + ')' | |
| if isinstance(node, ast.Index): | |
| return expr(node.value) | |
| if isinstance(node, ast.IfExp): | |
| return '(%s ? %s : %s)' % ( | |
| expr(node.test), | |
| expr(node.body), | |
| expr(node.orelse), | |
| ) | |
| if isinstance(node, ast.Subscript): | |
| if isinstance(node.slice, ast.Slice): | |
| return '(function (list) {\n var a = %s,\n b = %s;\n return list.slice(a, b < 0 ? list.length - b : b);\n}(%s))' % ( | |
| # ast.dump(node.slice), | |
| expr(node.slice.lower) if node.slice.lower else '0', | |
| expr(node.slice.upper) if node.slice.upper else 'list.length', | |
| expr(node.value), | |
| ) | |
| return '%s[%s]' % (expr(node.value), expr(node.slice)) | |
| if isinstance(node, ast.Slice): | |
| raise 'NOPE' | |
| if isinstance(node, ast.ListComp): | |
| def compile_gen(code, gen): | |
| if isinstance(gen.target, ast.Tuple): | |
| return '%s.map(function (__temp__) {\n%s\n return %s;\n})' % ( | |
| expr(gen.iter), | |
| '\n'.join([ # copy-pasta | |
| ' %s%s = __temp__[%s];' % ( | |
| 'var ' if isinstance(elt, ast.Name) else '', | |
| expr(elt), | |
| str(i), | |
| ) | |
| for i, elt in enumerate(gen.target.elts) | |
| ]), | |
| tab_over(code).lstrip(), | |
| ) | |
| return '%s.map(function (%s) {\n return %s;\n})' % ( | |
| expr(gen.iter), | |
| expr(gen.target), | |
| tab_over(code).lstrip(), | |
| ) | |
| return reduce( | |
| compile_gen, | |
| node.generators, | |
| '%s' % expr(node.elt), | |
| ) + ''.join(['.reduce(function (a, b) {\n return a.concat(b);\n})' for _ in range(len(node.generators) - 1)]) | |
| if isinstance(node, ast.alias): | |
| return (node.asname or node.name) + ' = require(' + \ | |
| json.dumps(node.name) + ')' | |
| print('----EXPR %s----' % node.__class__.__name__) | |
| # print(node) | |
| # print(dir(node)) | |
| print(ast.dump(node)) | |
| return '----EXPR %s----' % node.__class__.__name__ | |
| # print(n) | |
| # print({k : getattr(n, k) for k in n._attributes}) | |
| # print({k : getattr(n, k) for k in n._fields}) | |
| # print(dir(n.func)) | |
| # print('----') | |
| # print(n.func.value) | |
| # print(dir(n.func.value)) | |
| def wrap_statement(fn): | |
| def wrapper(node): | |
| fuck = {'you': ''} | |
| def add_statement(text): | |
| fuck['you'] += text | |
| out = fn(node, add_statement) | |
| return (fuck['you'] and fuck['you'] + '\n') + out | |
| # return out if isinstance(out, str) else out[0] | |
| return (out, fuck['you']) \ | |
| if isinstance(out, str) \ | |
| else (out[0], code + fuck['you']) | |
| return wrapper | |
| # return lambda n, tabs=0: '\n'.join( | |
| # [(' ' if tabs else '') + line for line in fn(n, tabs).split('\n')] | |
| # ) + '\n' | |
| @wrap_statement | |
| def compile_statement(node, add_statement): | |
| # expr = compile_expr | |
| def expr(node): | |
| expr, stmt = compile_expr(node) | |
| add_statement(stmt) | |
| return expr | |
| def sub_statement(body): | |
| return '\n'.join([ | |
| ' ' + line \ | |
| for line \ | |
| in filter(op.truth, '\n'.join( | |
| [compile_statement(sub_node) for sub_node in body] | |
| ).split('\n')) | |
| ]) | |
| if isinstance(node, ast.FunctionDef): | |
| decs = [expr(dec) + '(' for dec in node.decorator_list] | |
| return 'var %s = %sfunction (%s) {\n' % ( | |
| node.name, | |
| ''.join(decs), | |
| ', '.join([arg.id for arg in node.args.args]) | |
| ) + sub_statement(node.body) + '\n}%s' % ( | |
| ''.join(map(lambda x: ')', decs)) # meh | |
| ) + ';' | |
| if isinstance(node, ast.Return): | |
| return 'return ' + expr(node.value) + ';' | |
| if isinstance(node, ast.Expr): | |
| return expr(node.value) + ';' | |
| if isinstance(node, ast.Pass): | |
| return '' | |
| if isinstance(node, ast.Import): | |
| return '\n'.join( | |
| ['var ' + expr(name) + ';' for name in node.names] | |
| ) | |
| if isinstance(node, ast.Assign): | |
| # TODO: HANDLE SCOPING CORRECTLY | |
| if len(node.targets) > 1: | |
| raise 'wtf? when does this happen?' | |
| if isinstance(node.targets[0], ast.Tuple): | |
| return 'var __temp__ = %s;\n' % expr(node.value) + '\n'.join([ | |
| '%s%s = __temp__[%s];' % ( | |
| 'var ' if isinstance(elt, ast.Name) else '', | |
| expr(elt), | |
| str(i), | |
| ) | |
| for i, elt in enumerate(node.targets[0].elts) | |
| ]) | |
| return ( | |
| 'var ' + expr(node.targets[0]) + ' = ' + | |
| expr(node.value) + ';' | |
| ) | |
| if isinstance(node, ast.Print): | |
| return 'console.log(%s);' % ', '.join( | |
| [expr(arg) for arg in node.values] | |
| ) | |
| if isinstance(node, ast.ClassDef): | |
| # decorator_list???? | |
| js = 'function %s(???) {\n' % (node.name) | |
| js += sub_statement(node.body) + '\n' | |
| js += '}\n' | |
| js += '\n'.join( | |
| [node.name + '.prototype = Object.create(' + expr(base) + \ | |
| ');' for base in node.bases] | |
| ) | |
| return js | |
| if isinstance(node, ast.Raise): | |
| return 'throw %s;' % expr(node.type) | |
| def compile_if(node): | |
| js = '\n'.join( | |
| ['if ({test}) {{'.format(test=expr(node.test))] + | |
| [sub_statement(node.body)] + | |
| ['}'] | |
| ) | |
| if len(node.orelse) == 1 and isinstance(node.orelse[0], ast.If): | |
| js += ' else ' + compile_if(node.orelse[0]) | |
| elif len(node.orelse): | |
| js += ' else {\n' + sub_statement(node.orelse) + '\n}' | |
| return js | |
| if isinstance(node, ast.If): | |
| return compile_if(node) | |
| if isinstance(node, ast.AugAssign): | |
| return expr(node.target) + ' ' + compile_op(node.op) + '= ' + \ | |
| expr(node.value) | |
| print('----STMT %s----' % node.__class__.__name__) | |
| print(ast.dump(node)) | |
| return '----STMT %s----' % node.__class__.__name__ | |
| print('\n'.join(filter(op.truth, [compile_statement(node) or '' for node in code.body]))) |
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
| var ast = require("ast"); | |
| var json = require("json"); | |
| var op = require("operator"); | |
| var inspect = require("inspect"); | |
| var f = open(inspect.getfile(inspect.currentframe())); | |
| var code = ast.parse(f.read()); | |
| var tab_over = function (code) { | |
| return "\n".join(filter(op.truth, code.split("\n")).map(function (line) { | |
| return " " + line; | |
| })); | |
| }; | |
| var compile_op = function (op) { | |
| if (isinstance(op, ast.Add)) { | |
| return "+"; | |
| } | |
| if (isinstance(op, ast.Sub)) { | |
| return "-"; | |
| } | |
| if (isinstance(op, ast.Gt)) { | |
| return ">"; | |
| } | |
| if (isinstance(op, ast.Lt)) { | |
| return "-"; | |
| } | |
| if (isinstance(op, ast.Eq)) { | |
| return "==="; | |
| } | |
| if (isinstance(op, ast.And)) { | |
| return "&&"; | |
| } | |
| if (isinstance(op, ast.Or)) { | |
| return "||"; | |
| } | |
| if (isinstance(op, ast.Not)) { | |
| return "!"; | |
| } | |
| if (isinstance(op, ast.Mod)) { | |
| return "%"; | |
| } | |
| if (isinstance(op, ast.In)) { | |
| throw "Nope, handle this higher up."; | |
| } | |
| console.log("----OP %s----" % op.__class__.__name__); | |
| console.log(ast.dump(op)); | |
| return "----OP %s----" % op.__class__.__name__; | |
| }; | |
| var wrap_expr = function (fn) { | |
| var wrapper = function (node) { | |
| var fuck = { | |
| "you": "" | |
| }; | |
| var add_statement = function (text) { | |
| fuck["you"] += text | |
| }; | |
| var out = fn(node, add_statement); | |
| return (isinstance(out, str) ? [out, fuck["you"]] : [out[0], code + fuck["you"]]); | |
| }; | |
| return wrapper; | |
| }; | |
| var is_literal = function (node) { | |
| return any([ast.Str, ast.Num].map(function (t) { | |
| return isinstance(node, t); | |
| })) || isinstance(node, ast.Name) && ["True", "False"].some(function (_v) { | |
| return _v === node.id; | |
| }); | |
| }; | |
| var compile_expr = wrap_expr(function (node, add_statement) { | |
| var expr = function (node) { | |
| var __temp__ = compile_expr(node); | |
| var expr = __temp__[0]; | |
| var stmt = __temp__[1]; | |
| add_statement(stmt); | |
| return expr; | |
| }; | |
| if (isinstance(node, ast.List) || isinstance(node, ast.Tuple)) { | |
| return "[" + ", ".join(node.elts.map(function (elt) { | |
| return expr(elt); | |
| })) + "]"; | |
| } | |
| if (isinstance(node, ast.Dict)) { | |
| if (any(node.keys.map(function (key) { | |
| return !is_literal(key); | |
| }))) { | |
| throw "YOU SUCK! TODO"; | |
| } | |
| return "{\n " + ",\n".join(zip(node.keys, node.values).map(function (__temp__) { | |
| var key = __temp__[0]; | |
| var value = __temp__[1]; | |
| return "%s: %s" % [expr(key), expr(value)]; | |
| })) + "\n}"; | |
| } | |
| if (isinstance(node, ast.Name)) { | |
| if (node.id === "True") { | |
| return "true"; | |
| } | |
| if (node.id === "False") { | |
| return "false"; | |
| } | |
| return node.id; | |
| } | |
| if (isinstance(node, ast.Compare)) { | |
| var handle_comparator = function (left, op, right) { | |
| if (isinstance(op, ast.In)) { | |
| return "%s.some(function (_v) {\n return _v === %s;\n})" % [expr(right), expr(left)]; | |
| } | |
| return expr(left) + " " + compile_op(op) + " " + expr(right); | |
| }; | |
| return " && ".join(zip([node.left] + (function (list) { | |
| var a = 0, | |
| b = -1; | |
| return list.slice(a, b < 0 ? list.length - b : b); | |
| }(node.comparators)), node.ops, node.comparators).map(function (__temp__) { | |
| var left = __temp__[0]; | |
| var op = __temp__[1]; | |
| var right = __temp__[2]; | |
| return handle_comparator(left, op, right); | |
| })); | |
| } | |
| if (isinstance(node, ast.Num)) { | |
| return str(node.n); | |
| } | |
| if (isinstance(node, ast.Str)) { | |
| return json.dumps(node.s); | |
| } | |
| if (isinstance(node, ast.Lambda)) { | |
| return "function (%s) {\n return %s;\n}" % [", ".join(node.args.args.map(function (arg) { | |
| return expr(arg); | |
| })), tab_over(expr(node.body)).lstrip()]; | |
| } | |
| if (isinstance(node, ast.Attribute)) { | |
| return expr(node.value) + "." + node.attr; | |
| } | |
| if (isinstance(node, ast.BoolOp)) { | |
| return expr(node.values[0]) + " " + compile_op(node.op) + " " + expr(node.values[1]); | |
| } | |
| if (isinstance(node, ast.BinOp)) { | |
| return expr(node.left) + " " + compile_op(node.op) + " " + expr(node.right); | |
| } | |
| if (isinstance(node, ast.UnaryOp)) { | |
| return compile_op(node.op) + expr(node.operand); | |
| } | |
| if (isinstance(node, ast.Call)) { | |
| return expr(node.func) + "(" + ", ".join(node.args.map(function (arg) { | |
| return expr(arg); | |
| })) + ")"; | |
| } | |
| if (isinstance(node, ast.Index)) { | |
| return expr(node.value); | |
| } | |
| if (isinstance(node, ast.IfExp)) { | |
| return "(%s ? %s : %s)" % [expr(node.test), expr(node.body), expr(node.orelse)]; | |
| } | |
| if (isinstance(node, ast.Subscript)) { | |
| if (isinstance(node.slice, ast.Slice)) { | |
| return "(function (list) {\n var a = %s,\n b = %s;\n return list.slice(a, b < 0 ? list.length - b : b);\n}(%s))" % [(node.slice.lower ? expr(node.slice.lower) : "0"), (node.slice.upper ? expr(node.slice.upper) : "list.length"), expr(node.value)]; | |
| } | |
| return "%s[%s]" % [expr(node.value), expr(node.slice)]; | |
| } | |
| if (isinstance(node, ast.Slice)) { | |
| throw "NOPE"; | |
| } | |
| if (isinstance(node, ast.ListComp)) { | |
| var compile_gen = function (code, gen) { | |
| if (isinstance(gen.target, ast.Tuple)) { | |
| return "%s.map(function (__temp__) {\n%s\n return %s;\n})" % [expr(gen.iter), "\n".join(enumerate(gen.target.elts).map(function (__temp__) { | |
| var i = __temp__[0]; | |
| var elt = __temp__[1]; | |
| return " %s%s = __temp__[%s];" % [(isinstance(elt, ast.Name) ? "var " : ""), expr(elt), str(i)]; | |
| })), tab_over(code).lstrip()]; | |
| } | |
| return "%s.map(function (%s) {\n return %s;\n})" % [expr(gen.iter), expr(gen.target), tab_over(code).lstrip()]; | |
| }; | |
| return reduce(compile_gen, node.generators, "%s" % expr(node.elt)) + "".join(range(len(node.generators) - 1).map(function (_) { | |
| return ".reduce(function (a, b) {\n return a.concat(b);\n})"; | |
| })); | |
| } | |
| if (isinstance(node, ast.alias)) { | |
| return node.asname || node.name + " = require(" + json.dumps(node.name) + ")"; | |
| } | |
| console.log("----EXPR %s----" % node.__class__.__name__); | |
| console.log(ast.dump(node)); | |
| return "----EXPR %s----" % node.__class__.__name__; | |
| }); | |
| var wrap_statement = function (fn) { | |
| var wrapper = function (node) { | |
| var fuck = { | |
| "you": "" | |
| }; | |
| var add_statement = function (text) { | |
| fuck["you"] += text | |
| }; | |
| var out = fn(node, add_statement); | |
| return fuck["you"] && fuck["you"] + "\n" + out; | |
| return (isinstance(out, str) ? [out, fuck["you"]] : [out[0], code + fuck["you"]]); | |
| }; | |
| return wrapper; | |
| }; | |
| var compile_statement = wrap_statement(function (node, add_statement) { | |
| var expr = function (node) { | |
| var __temp__ = compile_expr(node); | |
| var expr = __temp__[0]; | |
| var stmt = __temp__[1]; | |
| add_statement(stmt); | |
| return expr; | |
| }; | |
| var sub_statement = function (body) { | |
| return "\n".join(filter(op.truth, "\n".join(body.map(function (sub_node) { | |
| return compile_statement(sub_node); | |
| })).split("\n")).map(function (line) { | |
| return " " + line; | |
| })); | |
| }; | |
| if (isinstance(node, ast.FunctionDef)) { | |
| var decs = node.decorator_list.map(function (dec) { | |
| return expr(dec) + "("; | |
| }); | |
| return "var %s = %sfunction (%s) {\n" % [node.name, "".join(decs), ", ".join(node.args.args.map(function (arg) { | |
| return arg.id; | |
| }))] + sub_statement(node.body) + "\n}%s" % "".join(map(function (x) { | |
| return ")"; | |
| }, decs)) + ";"; | |
| } | |
| if (isinstance(node, ast.Return)) { | |
| return "return " + expr(node.value) + ";"; | |
| } | |
| if (isinstance(node, ast.Expr)) { | |
| return expr(node.value) + ";"; | |
| } | |
| if (isinstance(node, ast.Pass)) { | |
| return ""; | |
| } | |
| if (isinstance(node, ast.Import)) { | |
| return "\n".join(node.names.map(function (name) { | |
| return "var " + expr(name) + ";"; | |
| })); | |
| } | |
| if (isinstance(node, ast.Assign)) { | |
| if (len(node.targets) > 1) { | |
| throw "wtf? when does this happen?"; | |
| } | |
| if (isinstance(node.targets[0], ast.Tuple)) { | |
| return "var __temp__ = %s;\n" % expr(node.value) + "\n".join(enumerate(node.targets[0].elts).map(function (__temp__) { | |
| var i = __temp__[0]; | |
| var elt = __temp__[1]; | |
| return "%s%s = __temp__[%s];" % [(isinstance(elt, ast.Name) ? "var " : ""), expr(elt), str(i)]; | |
| })); | |
| } | |
| return "var " + expr(node.targets[0]) + " = " + expr(node.value) + ";"; | |
| } | |
| if (isinstance(node, ast.Print)) { | |
| return "console.log(%s);" % ", ".join(node.values.map(function (arg) { | |
| return expr(arg); | |
| })); | |
| } | |
| if (isinstance(node, ast.ClassDef)) { | |
| var js = "function %s(???) {\n" % node.name; | |
| js += sub_statement(node.body) + "\n" | |
| js += "}\n" | |
| js += "\n".join(node.bases.map(function (base) { | |
| return node.name + ".prototype = Object.create(" + expr(base) + ");"; | |
| })) | |
| return js; | |
| } | |
| if (isinstance(node, ast.Raise)) { | |
| return "throw %s;" % expr(node.type); | |
| } | |
| var compile_if = function (node) { | |
| var js = "\n".join(["if ({test}) {{".format()] + [sub_statement(node.body)] + ["}"]); | |
| if (len(node.orelse) === 1 && isinstance(node.orelse[0], ast.If)) { | |
| js += " else " + compile_if(node.orelse[0]) | |
| } else if (len(node.orelse)) { | |
| js += " else {\n" + sub_statement(node.orelse) + "\n}" | |
| } | |
| return js; | |
| }; | |
| if (isinstance(node, ast.If)) { | |
| return compile_if(node); | |
| } | |
| if (isinstance(node, ast.AugAssign)) { | |
| return expr(node.target) + " " + compile_op(node.op) + "= " + expr(node.value); | |
| } | |
| console.log("----STMT %s----" % node.__class__.__name__); | |
| console.log(ast.dump(node)); | |
| return "----STMT %s----" % node.__class__.__name__; | |
| }); | |
| console.log("\n".join(filter(op.truth, code.body.map(function (node) { | |
| return compile_statement(node) || ""; | |
| })))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment