def func_super(self, type_, inst): self.visit( ast_call( ast.FunctionDef( '', ast.arguments( [ast_store('p'), ast_store('i')], None, None, []), [ ast.FunctionDef('tmp', ast.arguments( [], None, None, []), [ ast.Expr( ast_call(ast_load('this.__bind__'), ast_load('i'))), ], []), ast.Assign([ast_load('tmp.prototype')], ast_load('p')), ast.Return(ast_call( ast_load('new'), ast_load('tmp'), )) ], []), ast.Attribute( ast.Subscript( ast_load('self.__mro__'), ast.Index( ast.BinOp( ast_call( ast_load('self.__mro__.indexOf'), type_, ), ast.Sub(), ast.Num(1))), ast.Load()), 'prototype', ast.Load()), inst, ))
def visit_Call(self, node): if node.keywords: raise Exception('keyword arguments are not supported') if node.kwargs is not None: raise Exception('kwargs is not supported') if isinstance(node.func, _ast.Name): func = getattr(self, 'func_%s' % node.func.id, None) if func is not None: # noinspection PyCallingNonCallable return func(*node.args) if not node.starargs: self.visit(node.func) self.group(node.args, infix=', ') else: # Rewrite the call without starargs using apply. if isinstance(node.func, _ast.Attribute): this = node.func.value else: this = ast_load('this') if not node.args: args = node.starargs else: args = ast_call( ast.Attribute(ast.List(node.args, ast.Load()), 'concat', ast.Load()), node.starargs) self.visit( ast_call( ast.Attribute(node.func, 'apply', ast.Load()), this, args, ))
def init_module(self, module_path): for i in range(len(module_path)): self.load_module(module_path[:i + 1]) return ast_call(ast_call(ast_load('JS'), ast.Str('__import__')), ast_call(ast_load('JS'), ast.Str('__module__')), ast.Str('.'.join(module_path)))
def CmpOp_In(self, left, comparator): self.visit(ast_call( ast.FunctionDef( '', ast.arguments([ast_load('l'), ast_load('c')], None, None, []), [ ast.Return( ast.IfExp( ast_call( ast_load('Array.isArray'), ast_load('c'), ), ast.Compare( ast_call( ast_load('Array.prototype.indexOf.call'), ast_load('c'), ast_load('l'), ), [ast.Gt()], [ast.Num(-1)] ), ast_call( ast_load('JS'), ast.Str("l in c"), ) ) ) ], [] ), left, comparator ))
def init_module(self, module_path): for i in range(len(module_path)): self.load_module(module_path[:i + 1]) return ast_call( ast_call(ast_load('JS'), ast.Str('__import__')), ast_call(ast_load('JS'), ast.Str('__module__')), ast.Str('.'.join(module_path)) )
def visit_TryExcept(self, node): if node.orelse: raise NotImplementedError('Try-except else handler not implemented') self.indent() self.output('try') self.block(node.body, context=BlockContext(self.stack[-1])) self.output(' catch($e) ') self.push(BlockContext(self.stack[-1])) if_start = None if_end = None for handler in node.handlers: if handler.type is not None: if handler.name is not None: body = handler.body[:] body.insert(0, ast.Assign( [handler.name], ast_call(ast_load('JS'), ast.Str('$e')) )) else: body = handler.body types = [handler.type] if isinstance(handler.type, _ast.Name) else handler.type conditions = [ ast_call( ast_load('isinstance'), ast_call(ast_load('JS'), ast.Str('$e')), type_, ) for type_ in types ] _if = ast.If( ast.BoolOp(ast.Or(), conditions), body, [] ) if if_start is None: if_start = if_end = _if else: if_end.orelse, if_end = [_if], _if else: if handler is not node.handlers[-1]: raise SyntaxError("default 'except:' must be last") if if_start is None: self.block(handler.body) else: if_end.orelse = handler.body if if_start is not None: self.visit(if_start) self.pop() self.output('\n')
def func_super(self, type_, inst): self.visit( ast_call( ast.FunctionDef( '', ast.arguments([ast_store('p'), ast_store('i')], None, None, []), [ ast.FunctionDef( 'tmp', ast.arguments([], None, None, []), [ ast.Expr( ast_call( ast_load('this.__bind__'), ast_load('i') ) ), ], [] ), ast.Assign( [ast_load('tmp.prototype')], ast_load('p') ), ast.Return( ast_call( ast_load('new'), ast_load('tmp'), ) ) ], [] ), ast.Attribute( ast.Subscript( ast_load('self.__mro__'), ast.Index( ast.BinOp( ast_call( ast_load('self.__mro__.indexOf'), type_, ), ast.Sub(), ast.Num(1) ) ), ast.Load() ), 'prototype', ast.Load() ), inst, ) )
def test_assign_expr_slice(self): assert self.run( [ ast.Assign( [ast_store('test')], ast.List([ast.Num(x) for x in range(10)], ast.Load()) ), ast.FunctionDef( 'f_test', ast.arguments([], None, None, []), [ ast.Return(ast_load('test')), ], [] ), ast.Assign( [ ast.Subscript( ast_call(ast_load('f_test')), ast.Slice(ast.Num(2), ast.Num(8), None), ast.Store() ), ], ast.List([ast.Num(42), ast.Num(43)], ast.Load()) ), ], 'test', list ) == [0, 1, 42, 43, 8, 9]
def build_Assign_Destructuring(self, targets, value): scope = self.stack[-1].scope global_scope = scope.get_global_scope() assignments = [] for target, i in zip(targets.elts, range(len(targets.elts))): if isinstance(target, _ast.Name): if scope.is_global(target.id): global_scope.declare(target.id) else: scope.declare(target.id) target = ast.Name(target.id, ast.Load()) assignments.append( ast.Assign( [target], ast.Subscript( ast_load('v'), ast.Index(ast.Num(i)), ast.Load() ) ) ) return ast_call( ast.FunctionDef( '', ast.arguments([ast_store('v')], None, None, []), assignments + [ ast.Return(ast_load('v')) ], [] ), value )
def visit_ImportFrom(self, node): if node.level: raise NotImplementedError('Relative imports are not supported') module_path = node.module.split('.') import_module = self.init_module(module_path) if len(node.names) > 1 or node.names[0].name == '*': self.visit(ast.Assign( [ast_store('$t1')], import_module )) import_from = ast_load('$t1') else: import_from = import_module if node.names[0].name == '*': name = node.names[0] if name.name == '*': if self.stack[-1].scope.prefix != ['__module__']: raise NotImplementedError('from x import * only implemented at module level') self.visit(ast.For( ast_store('$t2'), import_from, [ ast.Assign( [ ast.Subscript( ast_call(ast_load('JS'), ast.Str('__module__')), ast.Index(ast_load('$t2')), ast.Load() ) ], ast.Subscript( import_from, ast.Index(ast_load('$t2')), ast.Load(), ) ), ], [] )) else: for name in node.names: asname = name.asname if name.asname else name.name self.visit( ast.Assign( [ast_store(asname)], ast.Attribute( import_from, name.name, ast.Load() ) ) )
def visit_Print(self, node): self.indent() self.visit( ast_call( ast_load('console.log'), *node.values ) ) self.finish()
def visit_Call(self, node): if node.keywords: raise Exception('keyword arguments are not supported') if node.kwargs is not None: raise Exception('kwargs is not supported') if isinstance(node.func, _ast.Name): func = getattr(self, 'func_%s' % node.func.id, None) if func is not None: # noinspection PyCallingNonCallable return func(*node.args) if not node.starargs: self.visit(node.func) self.group(node.args, infix=', ') else: # Rewrite the call without starargs using apply. if isinstance(node.func, _ast.Attribute): this = node.func.value else: this = ast_load('this') if not node.args: args = node.starargs else: args = ast_call( ast.Attribute( ast.List(node.args, ast.Load()), 'concat', ast.Load() ), node.starargs ) self.visit( ast_call( ast.Attribute( node.func, 'apply', ast.Load() ), this, args, ) )
def visit_ListComp(self, node): body = [ast.Expr(ast_call(ast_load('$$.push'), node.elt))] for i, generator in reversed( zip(range(len(node.generators)), node.generators)): if not isinstance(generator.target, ast.Name): raise TypeError('dereferencing assignment not supported') if generator.ifs: if len(generator.ifs) > 1: cond = ast.BoolOp(ast.And(), generator.ifs) else: cond = generator.ifs[0] body = [ast.If(cond, body, [])] body = [ ast.Assign([ast_store('$$' + generator.target.id)], generator.iter), ast.For( ast_store('$' + generator.target.id), ast_call( ast_load('range'), ast.Num(0), ast.Attribute(ast_load('$$' + generator.target.id), 'length', ast.Load())), [ ast.Assign( [generator.target], ast.Subscript( ast_load('$$' + generator.target.id), ast.Index(ast_load('$' + generator.target.id)), ast.Load())), ] + body, []) ] self.visit( ast_call( ast.FunctionDef('', ast.arguments([], None, None, []), [ ast.Assign([ast_store('$$')], ast.List([], ast.Load())), ] + body + [ ast.Return(ast_load('$$')), ], []), ))
def test_assign_expr_slice(self): assert self.run([ ast.Assign([ast_store('test')], ast.List([ast.Num(x) for x in range(10)], ast.Load())), ast.FunctionDef('f_test', ast.arguments([], None, None, []), [ ast.Return(ast_load('test')), ], []), ast.Assign([ ast.Subscript(ast_call(ast_load('f_test')), ast.Slice(ast.Num(2), ast.Num(8), None), ast.Store()), ], ast.List([ast.Num(42), ast.Num(43)], ast.Load())), ], 'test', list) == [0, 1, 42, 43, 8, 9]
def run(self, body, expression=None, converter=str): self.v.block(body) if not expression is None: self.v.visit( ast.Expr( ast_call(ast_load('JS'), ast.Str(expression)) ) ) ctx = PyV8.JSContext() with ctx: js_body = str(self.v.stack[-1]) return converter(ctx.eval(js_body))
def visit_ImportFrom(self, node): if node.level: raise NotImplementedError('Relative imports are not supported') module_path = node.module.split('.') import_module = self.init_module(module_path) if len(node.names) > 1 or node.names[0].name == '*': self.visit(ast.Assign([ast_store('$t1')], import_module)) import_from = ast_load('$t1') else: import_from = import_module if node.names[0].name == '*': name = node.names[0] if name.name == '*': if self.stack[-1].scope.prefix != ['__module__']: raise NotImplementedError( 'from x import * only implemented at module level') self.visit( ast.For(ast_store('$t2'), import_from, [ ast.Assign([ ast.Subscript( ast_call(ast_load('JS'), ast.Str('__module__')), ast.Index(ast_load('$t2')), ast.Load()) ], ast.Subscript( import_from, ast.Index(ast_load('$t2')), ast.Load(), )), ], [])) else: for name in node.names: asname = name.asname if name.asname else name.name self.visit( ast.Assign([ast_store(asname)], ast.Attribute(import_from, name.name, ast.Load())))
def test_destructure(self): assert self.run([ ast.Assign([ast_store('test2')], ast_call( ast.FunctionDef('', ast.arguments( [], None, None, []), [ ast.Global(['test1']), ast.Assign([ ast.List([ ast_store('test1'), ast_store('test2'), ], ast.Store()) ], ast.List([ ast.Str('test1'), ast.Str('test2'), ], ast.Load())), ast.Return(ast_load('test2')) ], []))) ], 'test1 + "+" + test2') == 'test1+test2'
def test_destructure(self): assert self.run( [ ast.Assign( [ast_store('test2')], ast_call( ast.FunctionDef( '', ast.arguments([], None, None, []), [ ast.Global(['test1']), ast.Assign( [ ast.List( [ ast_store('test1'), ast_store('test2'), ], ast.Store() ) ], ast.List( [ ast.Str('test1'), ast.Str('test2'), ], ast.Load() ) ), ast.Return(ast_load('test2')) ], [] ) ) ) ], 'test1 + "+" + test2' ) == 'test1+test2'
def visit_FunctionDef(self, node): if node.name: self.stack[-1].scope.declare(node.name) args = [get_arg_id(arg) for arg in node.args.args] if node.args.kwarg is not None: raise Exception('**kwargs not supported') func = FunctionContext(self.stack[-1], args) self.push(func) # Emit vararg if node.args.vararg is not None: self.visit( ast.Assign([ast.Name(node.args.vararg, ast.Store())], ast_call( ast_load('Array.prototype.slice.call'), ast.Name('arguments', ast.Load()), ast.Num(len(args)), ))) # Emit default arguments def_args = node.args.defaults for arg_name, arg_val in zip(args[-len(def_args):], def_args): self.block([ ast.If( ast.Compare( ast_call( ast.Name('type', ast.Load()), ast.Name(arg_name, ast.Load()), ), [ ast.Eq(), ], [ ast.Str('undefined'), ], ), [ ast.Assign([ast.Name(arg_name, ast.Store())], arg_val), ], [], ) ]) # Emit function body self.block(node.body) body = ast_call( ast_load('JS'), ast.Str(str(self.stack.pop())), ) for decorator in node.decorator_list: body = ast_call(decorator, body) if not node.name: self.visit(body) else: self.visit(ast.Assign( [ast_load(node.name)], body, ))
def setUp(self): self.c = ast_call(ast.Name('foo', ast.Load()))
def setUp(self): self.c = ast_call(ast.Name('foo', ast.Load()), 'a', 'b', 'c')
def func_new(self, type_, *args): self.output('(new ') self.visit(ast_call(type_, *args)) self.output(')')
def visit_FunctionDef(self, node): if node.name: self.stack[-1].scope.declare(node.name) args = [arg.id for arg in node.args.args] if node.args.kwarg is not None: raise Exception('**kwargs not supported') func = FunctionContext(self.stack[-1], args) self.push(func) # Emit vararg if node.args.vararg is not None: self.visit( ast.Assign( [ast.Name(node.args.vararg, ast.Store())], ast_call( ast_load('Array.prototype.slice.call'), ast.Name('arguments', ast.Load()), ast.Num(len(args)), ) ) ) # Emit default arguments def_args = node.args.defaults for arg_name, arg_val in zip(args[-len(def_args):], def_args): self.block([ ast.If( ast.Compare( ast_call( ast.Name('type', ast.Load()), ast.Name(arg_name, ast.Load()), ), [ast.Eq(), ], [ast.Str('undefined'), ], ), [ ast.Assign( [ast.Name(arg_name, ast.Store())], arg_val ), ], [], ) ]) # Emit function body self.block(node.body) body = ast_call( ast_load('JS'), ast.Str(str(self.stack.pop())), ) for decorator in node.decorator_list: body = ast_call( decorator, body ) if not node.name: self.visit(body) else: self.visit( ast.Assign( [ast_load(node.name)], body, ) )
def visit_ListComp(self, node): body = [ ast.Expr( ast_call( ast_load('$$.push'), node.elt ) ) ] for i, generator in reversed(zip(range(len(node.generators)), node.generators)): if not isinstance(generator.target, ast.Name): raise TypeError('dereferencing assignment not supported') if generator.ifs: if len(generator.ifs) > 1: cond = ast.BoolOp(ast.And(), generator.ifs) else: cond = generator.ifs[0] body = [ ast.If( cond, body, [] ) ] body = [ ast.Assign( [ast_store('$$' + generator.target.id)], generator.iter ), ast.For( ast_store('$' + generator.target.id), ast_call( ast_load('range'), ast.Num(0), ast.Attribute( ast_load('$$' + generator.target.id), 'length', ast.Load() ) ), [ ast.Assign( [generator.target], ast.Subscript( ast_load('$$' + generator.target.id), ast.Index(ast_load('$' + generator.target.id)), ast.Load() ) ), ] + body, [] ) ] self.visit( ast_call( ast.FunctionDef( '', ast.arguments( [ ], None, None, [] ), [ ast.Assign( [ ast_store('$$') ], ast.List( [], ast.Load() ) ), ] + body + [ ast.Return(ast_load('$$')), ], [] ), ) )
def visit_Print(self, node): self.indent() self.visit(ast_call(ast_load('console.log'), *node.values)) self.finish()
def BinOp_Pow(self, left, right): pow_func = ast_load('Math.pow') self.visit(ast_call(pow_func, left, right))
def BinOp_FloorDiv(self, left, right): floor = ast_load('Math.floor') self.visit(ast_call(floor, ast.BinOp(left, ast.Div(), right)))
def visit_ClassDef(self, node): if len(node.bases) > 1: raise Exception('Multiple inheritance not supported') self.visit(FunctionDef( node.name, arguments([], None, None, []), [ ast.If( ast.UnaryOp( ast.Not(), ast_call( ast_load('isinstance'), ast_load('this'), ast_load('arguments.callee'), ) ), [ ast.Return( ast_call( ast_load('new'), ast_load('arguments.callee'), ast_load('arguments'), ) ) ], [] ), ast.Assign( [ast_store('this.__class__')], ast_load('arguments.callee') ), ast.Expr( ast_call( ast_load('this.__bind__'), ast_load('this'), ), ), ast.If( ast.Compare( ast_call( ast_load('type'), ast_load('this.__init__'), ), [ast.IsNot()], [ast.Str('undefined')], ), [ ast.Expr( ast_call( ast_load('this.__init__.apply'), ast_load('this'), ast.Subscript( ast_load('arguments'), ast.Index(ast.Num(0)), ast.Load() ) ) ), ], [] ) ], [] )) self.push(ClassContext(self.stack[-1], node.name)) scope = self.stack[-1].scope if not node.bases: scope.prefix.pop() self.visit( ast.Assign( [ast_store('prototype')], ast.Dict( [ ast.Str('constructor'), ast.Str('__mro__') ], [ ast_load(node.name), ast.List([ast_load(node.name)], ast.Load()) ] ) ) ) scope.prefix.append('prototype') self.visit( ast.Assign( [ast_store('__bind__')], FunctionDef( '', arguments([ast_load('self')], None, None, []), [ ast.For( ast_store('i'), ast_load('this'), [ ast.If( ast.Compare( ast_call( ast_load('type'), ast.Subscript( ast_load('this'), ast.Index(ast_load('i')), ast.Load(), ) ), [ast.Is()], [ast.Str('function')] ), [ ast.Assign( [ast.Subscript( ast_load('this'), ast.Index(ast_load('i')), ast.Store(), )], ast_call( ast.Attribute( ast.Subscript( ast_load('this'), ast.Index(ast_load('i')), ast.Load(), ), 'bind', ast.Load(), ), ast_load('self'), ast_load('self'), ) ), ], [] ) ], [] ), ], [] ) ) ) else: base = node.bases[0] self.visit( ast.Assign( [ast_store(node.name, 'prototype')], ast_call( FunctionDef( '', arguments([], None, None, []), [ ast.Assign( [ast_store('tmp')], FunctionDef( '', arguments([], None, None, []), [], [] ) ), ast.Assign( [ast_store('tmp', 'prototype')], ast.Attribute(base, 'prototype', ast.Load()), ), ast.Return( ast_call( ast_load('new'), ast_load('tmp'), ) ) ], [] ), ) ) ) self.visit( ast.Assign( [ast_store(node.name, 'prototype.constructor')], ast_load(node.name) ) ) self.visit( ast.Assign( [ast_store(node.name, 'prototype.__base__')], base, ) ) self.visit( ast.Assign( [ast_store(node.name, 'prototype.__mro__')], ast_call( ast_load(node.name, 'prototype.__mro__.concat'), ast_load(node.name), ) ) ) for stmt in node.body: self.visit(stmt) self.pop() if node.decorator_list: arg = ast_load(node.name) for decorator in node.decorator_list: arg = ast_call(decorator, arg) self.visit( ast.Assign( [ast_store(node.name)], arg ) )
def build_Assign_Slice(self, target, value): args = [] if target.slice.lower or target.slice.upper: args.append(target.slice.lower or ast.Num(0)) if target.slice.upper: args.append(target.slice.upper) return ast_call( ast.FunctionDef( '', ast.arguments( [ ast_store('t'), ast_store('v'), ast_store('s'), ast_store('e'), ], None, None, [] ), [ ast.Assign( [ast_store('s')], ast.IfExp( ast.Compare( ast_call( ast_load('type'), ast_load('s') ), [ast.Eq()], [ast.Str('undefined')], ), ast.Num(0), ast.IfExp( ast.Compare( ast_load('s'), [ast.Lt()], [ast.Num(0)], ), ast.BinOp( ast_load('s'), ast.Add(), ast_load('t.length') ), ast_load('s') ) ) ), ast.Assign( [ast_store('e')], ast.IfExp( ast.Compare( ast_call( ast_load('type'), ast_load('e') ), [ast.Eq()], [ast.Str('undefined')], ), ast_load('t.length'), ast.IfExp( ast.Compare( ast_load('e'), [ast.Lt()], [ast.Num(0)], ), ast.BinOp( ast_load('e'), ast.Add(), ast_load('t.length') ), ast_load('e') ) ) ), ast.Expr( ast_call( ast_load('Array.prototype.splice.apply'), ast_load('t'), ast_call( ast.Attribute( ast.List([ ast_load('s'), ast.BinOp( ast_load('e'), ast.Sub(), ast_load('s') ), ], ast.Load()), 'concat', ast.Load(), ), ast_load('v'), ) ) ), ast.Return(ast_load('v')), ], [] ), target.value, value, *args )