示例#1
0
    def visit_GeneratorExp(self, node):
        if not len(node.generators) == 1:
            raise JSError("Compound generator expressions not supported")
        if not isinstance(node.generators[0].target, ast.Name):
            raise JSError("Non-simple targets in generator expressions not supported")

        return "py_builtins.map(function(%s) {return %s;}, %s)" % (node.generators[0].target.id, self.visit(node.elt), self.visit(node.generators[0].iter))
示例#2
0
 def visit_ImportFrom(self, node):
     if node.module == "__future__":
         if len(node.names) == 1 and node.names[0].name == "division":
             self.future_division = True
         else:
             raise JSError("Unknown import from __future__: %s" % node.names[0].name)
     else:
         raise JSError("Import only supports from __future__ import foo")
     return []
示例#3
0
 def visit_Num(self, node):
     if isinstance(node.n, (int, long)):
         if (0 <= node.n <= 9):
             return "$c%s" % str(node.n)
         elif -2**30 < node.n < 2**30:
             return "int(%s)" % str(node.n)
         else:
             raise JSError("Long integer type outside of javascript range")
     elif isinstance(node.n, float):
         return "float(%s)" % node.n
     else:
         raise JSError("Unknown numeric type: %s" % node.n.__class__.__name__)
示例#4
0
    def visit_DeleteSimple(self, node):
        if isinstance(node, ast.Subscript) and isinstance(node.slice, ast.Index):
            js = "%s.PY$__delitem__(%s);" % (self.visit(node.value), self.visit(node.slice))
        elif isinstance(node, ast.Subscript) and isinstance(node.slice, ast.Slice):
            js = "%s.PY$__delslice__(%s, %s);" % (self.visit(node.value), self.visit(node.slice.lower), self.visit(node.slice.upper))
        elif isinstance(node, ast.Attribute):
            js = '%s.PY$__delattr__("%s");' % (self.visit(node.value), node.attr)
        elif isinstance(node, ast.Name):
            raise JSError("Javascript does not support deleting variables. Cannot compile")
        else:
            raise JSError("Unsupported delete type: %s" % node)

        return js
示例#5
0
    def visit_ListComp(self, node):
        if not len(node.generators) == 1:
            raise JSError("Compound list comprehension not supported")
        if isinstance(node.generators[0].target, ast.Name):
            prefix = ""
            name = node.generators[0].target.id
        elif isinstance(node.generators[0].target, ast.Tuple):
            name = self.alloc_var()
            prefix = "".join(["%s = %s.PY$__getitem__(%d); " % (k.id, name, i) for i, k in enumerate(node.generators[0].target.elts)])
        else:
            raise JSError("Non-simple targets in list comprehension not supported")

        body = self.visit(node.elt)
        iterexp = self.visit(node.generators[0].iter)
        return "py_builtins.map(function(%s) {%sreturn %s;}, %s)" % (name, prefix, body, iterexp)
示例#6
0
    def visit_AssignSimple(self, target, value):
        if isinstance(target, (ast.Tuple, ast.List)):
            dummy = self.alloc_var()
            js = ["var %s = %s;" % (dummy, value)]

            for i, target in enumerate(target.elts):
                var = self.visit(target)
                declare = ""
                if isinstance(target, ast.Name):
                    if not (var in self._scope):
                        self._scope.append(var)
                        declare = "var "
                js.append("%s%s = %s.PY$__getitem__(%d);" % (declare, var, dummy, i))
        elif isinstance(target, ast.Subscript) and isinstance(target.slice, ast.Index):
            # found index assignment
            js = ["%s.PY$__setitem__(%s, %s);" % (self.visit(target.value), self.visit(target.slice), value)]
        elif isinstance(target, ast.Subscript) and isinstance(target.slice, ast.Slice):
            # found slice assignmnet
            js = ["%s.PY$__setslice__(%s, %s, %s);" % (self.visit(target.value), self.visit(target.slice.lower), self.visit(target.slice.upper), value)]
        else:
            var = self.visit(target)
            if isinstance(target, ast.Name):
                if not (var in self._scope):
                    self._scope.append(var)
                    declare = "var "
                else:
                    declare = ""
                js = ["%s%s = %s;" % (declare, var, value)]
            elif isinstance(target, ast.Attribute):
                js = ['%s.PY$__setattr__("%s", %s);' % (self.visit(target.value), str(target.attr), value)]
            else:
                raise JSError("Unsupported assignment type")
        return js
示例#7
0
 def visit_UnaryOp(self, node):
     if   isinstance(node.op, ast.USub  ): return "%s.PY$__neg__()"            % (self.visit(node.operand))
     elif isinstance(node.op, ast.UAdd  ): return "%s.PY$__pos__()"            % (self.visit(node.operand))
     elif isinstance(node.op, ast.Invert): return "%s.PY$__invert__()"         % (self.visit(node.operand))
     elif isinstance(node.op, ast.Not   ): return "py_builtins.__not__(%s)" % (self.visit(node.operand))
     else:
         raise JSError("Unsupported unary op %s" % node.op)
示例#8
0
 def enter(self, mode):
     self.modestack.append(mode)
     if mode == "js":
         self.visit_current = self.visit_js
     elif mode == "py":
         self.visit_current = self.visit_py
     else:
         raise JSError("Trying to enter unsupported mode")
示例#9
0
    def visit_AssignSimple(self, left, right):
        target = left
        value = right
        if isinstance(target, (ast.Tuple, ast.List)):
            part = self.alloc_var()
            js = ["var %s = %s;" % (part, value)]

            for i, target in enumerate(target.elts):
                var = self.visit(target)
                declare = ""
                if isinstance(target, ast.Name):
                    if not (var in self._scope):
                        self._scope.append(var)
                        declare = "var "
                js.append("%s%s = %s[%d];" % (declare, var, part, i))
        elif isinstance(target, ast.Subscript) and isinstance(
                target.slice, ast.Index):
            # found index assignment
            if isinstance(target.slice, ast.Str):
                i = self.visit(target.slice)
            else:
                i = '"%s"' % self.visit(target.slice)
            js = [
                "%s[%s] = %s;" %
                (self.visit(target.value), self.visit(target.slice), value)
            ]
        elif isinstance(target, ast.Subscript) and isinstance(
                target.slice, ast.Slice):
            raise JSError("Javascript does not support slice assignments")
        else:
            var = self.visit(target)
            if isinstance(target, ast.Name):
                if not (var in self._scope):
                    self._scope.append(var)
                    declare = "var "
                else:
                    declare = ""
                js = ["%s%s = %s;" % (declare, var, value)]
            elif isinstance(target, ast.Attribute):
                js = [
                    "%s.%s = %s;" %
                    (self.visit(target.value), str(target.attr), value)
                ]
            else:
                raise JSError("Unsupported assignment type")
        return js
示例#10
0
    def visit_TryExcept(self, node):
        if node.orelse:
            raise JSError("Try-Except with else-clause not supported")

        js = []
        js.append("try {")
        for n in node.body:
            js.extend(self.indent(self.visit(n)))
        err = self.alloc_var()
        self._exceptions.append(err)
        js.append("} catch (%s) {" % err)
        catchall = False
        for i, n in enumerate(node.handlers):
            if i > 0:
                pre = "else "
            else:
                pre = ""
            if n.type:
                if isinstance(n.type, ast.Name):
                    js.extend(self.indent(["%sif ($PY.isinstance(%s, %s)) {" % (pre, err, self.visit(n.type))]))
                else:
                    raise JSError("Catching non-simple exceptions not supported")
            else:
                catchall = True
                js.append("%sif (true) {" % (pre))

            if n.name:
                if isinstance(n.name, ast.Name):
                    js.append(self.indent(["var %s = %s;" % (self.visit(n.name), err)])[0])
                else:
                    raise JSError("Catching non-simple exceptions not supported")

            for b in n.body:
                js.extend(self.indent(self.visit(b)))

            js.append("}")

        if not catchall:
            js.append("else { throw %s; }" % err);

        js.append("};")
        self._exceptions.pop()
        return js
示例#11
0
    def visit_ClassDef(self, node):
        js = []
        bases = [self.visit(n) for n in node.bases]
        if not bases:
            bases = ['object']
        if len(bases) == 0:
            raise JSError("Old-style classes not supported")
        elif len(bases) > 1:
            raise JSError("Multiple inheritance not supported")

        class_name = node.name
        #self._classes remembers all classes defined
        self._classes[class_name] = node

        if len(self._class_name) > 0:
            js.append("__inherit(%s, \"%s\");" % (bases[0], class_name))
        else:
            js.append("var %s = __inherit(%s, \"%s\");" % (class_name, bases[0], class_name))

        self._class_name.append(class_name)
        heirar = ".PY$".join(self._class_name + [])
        for stmt in node.body:
            if isinstance(stmt, ast.Assign):
                value = self.visit(stmt.value)
                for t in stmt.targets:
                    var = self.visit(t)
                    js.append("%s.PY$%s = %s;" % (heirar, var, value))
            elif isinstance(stmt, ast.FunctionDef):
                self.heirar = heirar
                js.append("%s.PY$%s = %s;" % (heirar, stmt.name, "\n".join(self.visit(stmt))))
            elif isinstance(stmt, ast.ClassDef):
                js.append("%s.PY$%s = %s;" % (heirar, stmt.name, "\n".join(self.visit(stmt))))
            elif isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
                js.append("\n".join(["/* %s */" % s for s in stmt.value.s.split("\n")]))
            elif isinstance(stmt, ast.Pass):
                # Not required for js
                pass
            else:
                raise JSError("Unsupported class data: %s" % stmt)
        self._class_name.pop()

        return js
示例#12
0
    def visit_Call(self, node):
        func = self.visit(node.func)

        if node.keywords:
            keywords = []
            for kw in node.keywords:
                keywords.append("%s: %s" % (kw.arg, self.visit(kw.value)))
            keywords = "{" + ", ".join(keywords) + "}"
            js_args = ", ".join([self.visit(arg) for arg in node.args])
            return "%s.args([%s], %s)" % (func, js_args, keywords)
        else:
            if node.starargs is not None:
                raise JSError("star arguments are not supported")

            if node.kwargs is not None:
                raise JSError("keyword arguments are not supported")

            js_args = ", ".join([self.visit(arg) for arg in node.args])

            return "%s(%s)" % (func, js_args)
示例#13
0
 def visit_Raise(self, node):
     assert node.inst is None
     assert node.tback is None
     if not node.type:
         return ["throw %s;" % self._exceptions[-1]]
     else:
         if isinstance(node.type, ast.Name):
             return ["throw %s();" % self.visit(node.type)]
         elif isinstance(node.type, ast.Call):
             return ["throw %s;" % self.visit(node.type)]
         else:
             raise JSError("Unknown exception type")
示例#14
0
    def visit_AugAssign(self, node):
        target = self.visit(node.target)
        value = self.visit(node.value)

        if not self.future_division and isinstance(node.op, ast.Div):
            node.op = ast.FloorDiv()

        name = node.op.__class__.__name__
        if name in self.ops_augassign:
            return self.visit_AssignSimple(node.target,
                "%s.PY$__%s__(%s)" % (target, self.ops_augassign[name], value))
        else:
            raise JSError("Unsupported AugAssign type %s" % node.op)
示例#15
0
    def visit_comprehension(self, node):
        if isinstance(node.target, ast.Name):
            var = self.visit(node.target)
        elif isinstance(node.target, ast.Tuple):
            var = self.alloc_var()
        else:
            raise JSError("Unsupported target type in list comprehension")
        iter_var = self.alloc_var()
        res = "var %s; for (var %s = iter(%s); %s = $PY.next(%s); %s !== null) {\n" % (var, iter_var, self.visit(node.iter), var, iter_var, var)
        if isinstance(node.target, ast.Tuple):
            for i, el in enumerate(node.target.elts):
                if isinstance(el, ast.Name):
                    n = self.visit(el)
                else:
                    raise JSError("Invalid tuple element in list comprehension")
                res += "var %s = %s.PY$__getitem__($c%d);\n" % (n, var, i)

        if node.ifs:
            ifexp = []
            for exp in node.ifs:
                ifexp.append("bool(%s) === False" % self.visit(exp))
            res += "if (%s) { continue; }" % (" || ".join(ifexp))
        return res
示例#16
0
    def visit_Slice(self, node):
        if node.step:
            raise JSError("Javascript does not support slicing in steps")

        if node.lower and node.upper:
            return ".slice(%s, %s)" % (self.visit(
                node.lower), self.visit(node.upper))

        if node.lower:
            return "[%s]" % (self.visit(node.lower))

        if node.upper:
            return ".slice(0, %s)" % (self.visit(node.upper))

        raise NotImplementedError("Slice")
示例#17
0
    def visit_BoolOp(self, node):
        assign = self.stack_destiny(["Assign", "FunctionDef", "Print", "Call"], 1) in ["Assign", "Print", "Call"]

        if isinstance(node.op, ast.And):
            op = " && "
        elif isinstance(node.op, ast.Or):
            op = " || "
        else:
            raise JSError("Unknown boolean operation %s" % node.op)

        if assign:
            var = self.alloc_var()
            return "function() { %s; return %s; }()" % (op.join(["js(%s = %s)" % (var, self.visit(val)) for val in node.values]), var)
        else:
            return op.join(["js(%s)" % self.visit(val) for val in node.values])
示例#18
0
    def visit_BinOp(self, node):
        left = self.visit(node.left)
        right = self.visit(node.right)

        if isinstance(node.op, ast.Mod) and isinstance(node.left, ast.Str):
            return "%s.PY$__mod__(%s)" % (left, right)

        if not self.future_division and isinstance(node.op, ast.Div):
            node.op = ast.FloorDiv()

        name = node.op.__class__.__name__

        if name in self.ops_binop:
            return "%s.PY$__%s__(%s)" % (left, self.ops_binop[name], right)
        else:
            raise JSError("Unknown binary operation type %s" % node.op)
示例#19
0
    def visit_For(self, node):
        if not isinstance(node.target, ast.Name):
            raise JSError(
                "argument decomposition in 'for' loop is not supported")

        js = []

        for_target = self.visit(node.target)
        for_iter = self.visit(node.iter)

        iter_dummy = self.alloc_var()
        orelse_dummy = self.alloc_var()
        exc_dummy = self.alloc_var()

        js.append("var %s = iter(%s);" % (iter_dummy, for_iter))
        js.append("var %s = false;" % orelse_dummy)
        js.append("while (1) {")
        js.append("    var %s;" % for_target)
        js.append("    try {")
        js.append("        %s = %s.next();" % (for_target, iter_dummy))
        js.append("    } catch (%s) {" % exc_dummy)
        js.append(
            "        if (py_builtins.isinstance(%s, py_builtins.StopIteration)) {"
            % exc_dummy)
        js.append("            %s = true;" % orelse_dummy)
        js.append("            break;")
        js.append("        } else {")
        js.append("            throw %s;" % exc_dummy)
        js.append("        }")
        js.append("    }")

        for stmt in node.body:
            js.extend(self.indent(self.visit(stmt)))

        js.append("}")

        if node.orelse:
            js.append("if (%s) {" % orelse_dummy)

            for stmt in node.orelse:
                js.extend(self.indent(self.visit(stmt)))

            js.append("}")

        return js
示例#20
0
    def visit_Compare(self, node):
        assert len(node.ops) == 1
        assert len(node.comparators) == 1
        op = node.ops[0]
        comp = node.comparators[0]

        name = op.__class__.__name__

        if name in self.ops_compare:
            return "%s.PY$__%s__(%s)" % (self.visit(node.left), self.ops_compare[name], self.visit(comp))
        elif isinstance(op, ast.In):
            return "%s.PY$__contains__(%s)" % (self.visit(comp), self.visit(node.left))
        elif isinstance(op, ast.Is):
            return "py_builtins.__is__(%s, %s)" % (self.visit(node.left), self.visit(comp))
        elif isinstance(op, ast.NotIn):
            return "py_builtins.__not__(%s.PY$__contains__(%s))" % (self.visit(comp), self.visit(node.left))
        else:
            raise JSError("Unknown comparison type %s" % node.ops[0])
示例#21
0
 def visit_FunctionDef(self, node):
     added = 0
     dec = node.decorator_list
     i = 0
     while i < len(dec):
         if isinstance(dec[i], ast.Call) and isinstance(dec[i].func, ast.Name) and dec[i].func.id == 'JSVar':
             for a in dec[i].args:
                 if isinstance(a, ast.Str):
                     self.jsvars.append(a.s.split("."))
                     added += 1
                 else:
                     raise JSError("JSVar decorator must only be used with string literals")
             del dec[i]
         else:
             i += 1
     res = self.visit(node, False)
     while added:
         self.jsvars.pop()
         added -= 1
     return res
示例#22
0
    def visit_For(self, node):
        if not isinstance(node.target, ast.Name):
            raise JSError(
                "argument decomposition in 'for' loop is not supported")

        js = []

        for_target = self.visit(node.target)
        for_iter = self.visit(node.iter)

        iter_dummy = self.alloc_var()
        orelse_dummy = self.alloc_var()
        exc_dummy = self.alloc_var()

        if isinstance(node.iter, ast.Call) and isinstance(
                node.iter.func,
                ast.Name) and node.iter.func.id == "range" and not node.orelse:
            counter = self.visit(node.target)
            end_var = self.alloc_var()
            assert (len(node.iter.args) in (1, 2, 3))
            if len(node.iter.args) == 1:
                start = "0"
                end = self.visit(node.iter.args[0])
                step = "1"
            elif len(node.iter.args) == 2:
                start = self.visit(node.iter.args[0])
                end = self.visit(node.iter.args[1])
                step = "1"
            else:
                start = self.visit(node.iter.args[0])
                end = self.visit(node.iter.args[1])
                step = self.visit(node.iter.args[2])

            js.append("for (%s = %s; %s < %s; %s += %s) {" %
                      (counter, start, counter, end, counter, step))
            for stmt in node.body:
                js.extend(self.indent(self.visit(stmt)))
            js.append("}")
            return js

        js.append("var %s = iter(%s);" % (iter_dummy, for_iter))
        js.append("var %s = false;" % orelse_dummy)
        js.append("while (1) {")
        js.append("    var %s;" % for_target)
        js.append("    try {")
        js.append("        %s = %s.PY$next();" % (for_target, iter_dummy))
        js.append("    } catch (%s) {" % exc_dummy)
        js.append(
            "        if (py_builtins.isinstance(%s, py_builtins.StopIteration)) {"
            % exc_dummy)
        js.append("            %s = true;" % orelse_dummy)
        js.append("            break;")
        js.append("        } else {")
        js.append("            throw %s;" % exc_dummy)
        js.append("        }")
        js.append("    }")

        for stmt in node.body:
            js.extend(self.indent(self.visit(stmt)))

        js.append("}")

        if node.orelse:
            js.append("if (%s) {" % orelse_dummy)

            for stmt in node.orelse:
                js.extend(self.indent(self.visit(stmt)))

            js.append("}")

        return js
示例#23
0
    def visit_FunctionDef(self, node):
        defaults = [None] * (len(node.args.args) - len(node.args.defaults)) + node.args.defaults

        if node.args.kwarg:
            kwarg_name = node.args.kwarg
        else:
            kwarg_name = "__kwargs"

        if node.args.vararg:
            vararg_name = node.args.vararg
        else:
            vararg_name = "__varargs"

        if len(node.args.args) and node.args.args[0].id == "self":
            offset = 1
        else:
            offset = 0

        self._scope = [arg.id for arg in node.args.args]

        inclass = self.stack_destiny(["ClassDef", "FunctionDef"], 2) in ["ClassDef"]

        if inclass:
            js = ["function() {"]
        else:
            js = ["var %s = function() {" % (node.name)]

        if inclass or offset == 1:
            js.extend(self.indent(["var self = this;"]))

        newargs = self.alloc_var()

        js.extend(self.indent(["var %s = __kwargs_get(arguments);" % kwarg_name]))
        js.extend(self.indent(["var %s = __varargs_get(arguments);" % vararg_name]))
        js.extend(self.indent(["var %s = Array.prototype.slice.call(arguments).concat(js(%s));" % (newargs, vararg_name)]))
        for i, arg in enumerate(node.args.args[offset:]):
            if not isinstance(arg, ast.Name):
                raise JSError("tuples in argument list are not supported")

            values = dict(i = i, id = self.visit(arg), kwarg = kwarg_name, newargs = newargs)
            if defaults[i + offset] == None:
                js.extend(self.indent(["var %(id)s = ('%(id)s' in %(kwarg)s) ? %(kwarg)s['%(id)s'] : %(newargs)s[%(i)d];" % values]))
            else:
                values['default'] = self.visit(defaults[i + offset])
                js.extend(self.indent(["var %(id)s = %(newargs)s[%(i)d];" % values]))
                js.extend(self.indent(["if (%(id)s === undefined) { %(id)s = %(kwarg)s.%(id)s === undefined ? %(default)s : %(kwarg)s.%(id)s; };" % values]))

        if node.name in ["__getattr__", "__setattr__"]:
            js.extend(self.indent(["if (typeof %(id)s === 'string') { %(id)s = str(%(id)s); };" % { 'id': node.args.args[1].id }]))

        if node.args.kwarg:
            js.extend(self.indent(["%s = dict(%s);" % (node.args.kwarg, node.args.kwarg)]))

        if node.args.vararg:
            l = len(node.args.args)
            if inclass:
                l -= 1
            js.extend(self.indent(["%s = tuple(%s.slice(%s));" % (node.args.vararg, newargs, l)]))

        for stmt in node.body:
            js.extend(self.indent(self.visit(stmt)))

        self._scope = []
        if not (node.body and isinstance(node.body[-1], ast.Return)):
            js.append("return None;")
        js.append("}")

        for dec in node.decorator_list:
            js.extend(["%s.PY$%s = %s(%s.PY$__getattr__('%s'));" % (self.heirar, node.name, dec.id, self.heirar, node.name)])

        return js
示例#24
0
    def visit_For(self, node):
        if isinstance(node.target, ast.Name):
            for_target = self.visit(node.target)
        elif isinstance(node.target, ast.Tuple):
            for_target = self.alloc_var()
        else:
            raise JSError("Advanced for-loop decomposition not supported")

        js = []

        if isinstance(node.iter, ast.Call) and isinstance(node.iter.func, ast.Name) and node.iter.func.id == "range" and not node.orelse:
            counter  = self.visit(node.target)
            end_var  = self.alloc_var()
            assert(len(node.iter.args) in (1,2,3))
            if len(node.iter.args) == 1:
                start = "$c0"
                end   = self.visit(node.iter.args[0])
                step  = "$c1"
            elif len(node.iter.args) == 2:
                start = self.visit(node.iter.args[0])
                end   = self.visit(node.iter.args[1])
                step  = "$c1"
            else:
                start = self.visit(node.iter.args[0])
                end   = self.visit(node.iter.args[1])
                step  = self.visit(node.iter.args[2])

            js.append("%s = %s;" % (end_var, end))
            if step <> "$c1":
                step_var = self.alloc_var()
                js.append("%s = %s;" % (step_var, step));
            else:
                step_var = step
            js.append("for (%s = %s; %s.PY$__lt__(%s) == true; %s = %s.PY$__add__(%s)) {" % (counter, start, counter, end_var, counter, counter, step_var))
            for stmt in node.body:
                js.extend(self.indent(self.visit(stmt)))
            js.append("}")
            return js


        for_iter = self.visit(node.iter)

        iter_dummy = self.alloc_var()
        exc_dummy = self.alloc_var()

        js.append("try {")
        js.append("  var %s;" % for_target)
        for_init = "var %s = iter(%s)" % (iter_dummy, for_iter)
        for_iter = "%s = %s.PY$next()" % (for_target, iter_dummy)
        for_cond = ""
        js.append("  for (%s; %s; %s) {" % (for_init, for_iter, for_cond))
        if isinstance(node.target, ast.Tuple):
            js.append("    %s;" % "; ".join(["var %s = %s.PY$__getitem__(%s)" % (x.id, for_target, i) for i, x in enumerate(node.target.elts)]))

        for stmt in node.body:
            js.extend(self.indent(self.visit(stmt)))

        js.append("  }")

        js.append("} catch (%s) {" % exc_dummy)
        js.append("  if (%s !== $PY.StopIter && !$PY.isinstance(%s, py_builtins.StopIteration))" % (exc_dummy, exc_dummy))
        js.append("    throw %s;" % exc_dummy)
        if node.orelse:
            js.append("  else {")
            for stmt in node.orelse:
                js.extend(self.indent(self.visit(stmt)))
            js.append("  }")
        js.append("}")

        return js
示例#25
0
 def visit_FunctionDef(self, node):
     raise JSError(
         "Javascript compiler does not support function definitions")
示例#26
0
 def visit_ClassDef(self, node):
     raise JSError("Javascript compiler does not support class definitions")