<commit_before>#! /usr/bin/env python

"""
Python grammar, the AST classes contain those arguments as properties.

module Python version "$Revision: 62047 $"
{
    mod = Module(stmt* body)
        | Interactive(stmt* body)
        | Expression(expr body)

    stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list)
          | ClassDef(identifier name, expr* bases, stmt* body, expr *decorator_list)
          | Return(expr? value)

          | Delete(expr* targets)
          | Assign(expr* targets, expr value)
          | AugAssign(expr target, operator op, expr value)

          | Print(expr? dest, expr* values, int nl)

          | For(expr target, expr iter, stmt* body, stmt* orelse)
          | While(expr test, stmt* body, stmt* orelse)
          | If(expr test, stmt* body, stmt* orelse)
          | With(expr context_expr, expr? optional_vars, stmt* body)

          | Raise(expr? type, expr? inst, expr? tback)
          | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
          | TryFinally(stmt* body, stmt* finalbody)
          | Assert(expr test, expr? msg)

          | Import(alias* names)
          | ImportFrom(identifier module, alias* names, int? level)

          | Exec(expr body, expr? globals, expr? locals)

          | Global(identifier* names)
          | Expr(expr value)
          | Pass | Break | Continue

    expr = BoolOp(boolop op, expr* values)
         | BinOp(expr left, operator op, expr right)
         | UnaryOp(unaryop op, expr operand)
         | Lambda(arguments args, expr body)
         | IfExp(expr test, expr body, expr orelse)
         | Dict(expr* keys, expr* values)
         | ListComp(expr elt, comprehension* generators)
         | GeneratorExp(expr elt, comprehension* generators)
         | Yield(expr? value)
         | Compare(expr left, cmpop* ops, expr* comparators)
         | Call(expr func, expr* args, keyword* keywords, expr? starargs, expr? kwargs)
         | Repr(expr value)
         | Num(object n)
         | Str(string s)

         | Attribute(expr value, identifier attr, expr_context ctx)
         | Subscript(expr value, slice slice, expr_context ctx)
         | Name(identifier id, expr_context ctx)
         | List(expr* elts, expr_context ctx)
         | Tuple(expr* elts, expr_context ctx)

    expr_context = Load | Store | Del | AugLoad | AugStore | Param

    slice = Ellipsis
          | Slice(expr? lower, expr? upper, expr? step)
          | ExtSlice(slice* dims)
          | Index(expr value)

    boolop = And | Or

    operator = Add | Sub | Mult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv

    unaryop = Invert | Not | UAdd | USub

    cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn

    comprehension = (expr target, expr iter, expr* ifs)

    excepthandler = ExceptHandler(expr? type, expr? name, stmt* body)

    arguments = (expr* args, identifier? vararg, identifier? kwarg, expr* defaults)
    keyword = (identifier arg, expr value)

    alias = (identifier name, identifier? asname)
}
"""

import ast
import inspect
from optparse import OptionParser

def scope(func):
    func.scope = True
    return func

class JSError(Exception):
    pass

class JS(object):

    name_map = {
        'self'   : 'this',
        'True'   : 'true',
        'False'  : 'false',
        'None'  : 'null',

        'int' : '_int',
        'float' : '_float',

        # ideally we should check, that this name is available:
        'py_builtins' : '___py_hard_to_collide',
    }

    builtin = set([
        'NotImplementedError',
        'ZeroDivisionError',
        'AssertionError',
        'AttributeError',
        'RuntimeError',
        'ImportError',
        'TypeError',
        'ValueError',
        'NameError',
        'IndexError',
        'KeyError',
        'StopIteration',

        '_int',
        '_float',
        'max',
        'min',
        'sum',
    ])

    bool_op = {
        'And'    : '&&',
        'Or'     : '||',
    }

    unary_op = {
        'Invert' : '~',
        'Not'    : '!',
        'UAdd'   : '+',
        'USub'   : '-',
    }

    binary_op = {
        'Add'    : '+',
        'Sub'    : '-',
        'Mult'   : '*',
        'Div'    : '/',
        'Mod'    : '%',
        'LShift' : '<<',
        'RShift' : '>>',
        'BitOr'  : '|',
        'BitXor' : '^',
        'BitAnd' : '&',
    }

    comparison_op = {
            'Eq'    : "==",
            'NotEq' : "!=",
            'Lt'    : "<",
            'LtE'   : "<=",
            'Gt'    : ">",
            'GtE'   : ">=",
            'Is'    : "===",
            'IsNot' : "is not", # Not implemented yet
        }

    def __init__(self):
        self.dummy = 0
        self.classes = ['dict', 'list', 'tuple']
        # This is the name of the class that we are currently in:
        self._class_name = None

        # This lists all variables in the local scope:
        self._scope = []
        #~ self._classes = {'object':None}
        self._classes = {}

    def new_dummy(self):
        dummy = "__dummy%d__" % self.dummy
        self.dummy += 1
        return dummy

    def name(self, node):
        return node.__class__.__name__

    def get_bool_op(self, node):
        return self.bool_op[node.op.__class__.__name__]

    def get_unary_op(self, node):
        return self.unary_op[node.op.__class__.__name__]

    def get_binary_op(self, node):
        return self.binary_op[node.op.__class__.__name__]

    def get_comparison_op(self, node):
        return self.comparison_op[node.__class__.__name__]

    #This python code taken from pypy:
    #License for files in the pypy/ directory 
    #==================================================
    #
    #Except when otherwise stated (look for LICENSE files in directories or
    #information at the beginning of each file) all software and
    #documentation in the 'pypy' directories is licensed as follows: 
    #
    #    The MIT License
    #
    #    Permission is hereby granted, free of charge, to any person 
    #    obtaining a copy of this software and associated documentation 
    #    files (the "Software"), to deal in the Software without 
    #    restriction, including without limitation the rights to use, 
    #    copy, modify, merge, publish, distribute, sublicense, and/or 
    #    sell copies of the Software, and to permit persons to whom the 
    #    Software is furnished to do so, subject to the following conditions:
    #
    #    The above copyright notice and this permission notice shall be included 
    #    in all copies or substantial portions of the Software.
    #
    #    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
    #    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    #    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
    #    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    #    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    #    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    #    DEALINGS IN THE SOFTWARE.
    #
    #
    #PyPy Copyright holders 2003-2010
    #----------------------------------- 
    #
    #Except when otherwise stated (look for LICENSE files or information at
    #the beginning of each file) the files in the 'pypy' directory are each
    #copyrighted by one or more of the following people and organizations:    
    #
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    boria
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #
    #    Heinrich-Heine University, Germany 
    #    Open End AB (formerly AB Strakt), Sweden
    #    merlinux GmbH, Germany 
    #    tismerysoft GmbH, Germany 
    #    Logilab Paris, France 
    #    DFKI GmbH, Germany 
    #    Impara, Germany
    #    Change Maker, Sweden 
    #
    def mro(self, cls):
        order = []
        if cls == 'object':return ['object']
        orderlists = [self.mro(base.id) for base in self._classes[cls].bases if base.id!='object']
        orderlists.append([cls] + list(c.id for c in self._classes[cls].bases if c.id!='object'))
        while orderlists:
            for candidatelist in orderlists:
                candidate = candidatelist[0]
                if self.blockinglist(candidate, orderlists) is None:
                    break    # good candidate
            else:
                self.mro_error(orderlists)  # no candidate found
            assert candidate not in order
            order.append(candidate)
            for i in range(len(orderlists)-1, -1, -1):
                if orderlists[i][0] == candidate:
                    del orderlists[i][0]
                    if len(orderlists[i]) == 0:
                        del orderlists[i]
        order.append('object')
        return order

    def blockinglist(self,candidate, orderlists):
        for lst in orderlists:
            if candidate in lst[1:]:
                return lst
        return None  # good candidate

    def mro_error(self,orderlists):
        cycle = []
        candidate = orderlists[0][0]
        while candidate not in cycle:
            cycle.append(candidate)
            nextblockinglist = self.blockinglist(candidate, orderlists)
            candidate = nextblockinglist[0]
        # avoid the only use of list.index in the PyPy code base:
        i = 0
        for c in cycle:
            if c == candidate:
                break
            i += 1
        del cycle[:i]
        cycle.append(candidate)
        cycle.reverse()
        #~ names = [cls.__name__ for cls in cycle]
        raise TypeError, "Cycle among base classes: " + ' < '.join(cycle)

    def mronames(self,cls):
        #~ names = [cls.__name__ for cls in mro(cls)]
        #~ return names
        return self.mro(cls)

    def visit(self, node, scope=None):
        try:
            visitor = getattr(self, 'visit_' + self.name(node))
        except AttributeError:
            raise JSError("syntax not supported (%s)" % node)

        if hasattr(visitor, 'statement'):
            return visitor(node, scope)
        else:
            return visitor(node)

    def indent(self, stmts):
        return [ "    " + stmt for stmt in stmts ]

    def visit_Module(self, node):
        module = []

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

        return module

    @scope
    def visit_FunctionDef(self, node):
        is_static = False
        if node.decorator_list:
            if len(node.decorator_list) == 1 and \
                    isinstance(node.decorator_list[0], ast.Name) and \
                    node.decorator_list[0].id == "JavaScript":
                pass # this is our own decorator
            elif self._class_name and \
                    len(node.decorator_list) == 1 and \
                    isinstance(node.decorator_list[0], ast.Name) and \
                    node.decorator_list[0].id == "staticmethod":
                is_static = True
            else:
                raise JSError("decorators are not supported")

        if self._class_name:
            if node.args.vararg is not None:
                raise JSError("star arguments are not supported")

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

            if node.decorator_list and not is_static:
                raise JSError("decorators are not supported")

            defaults = [None]*(len(node.args.args) - len(node.args.defaults)) + node.args.defaults

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

            for arg, default in zip(node.args.args, defaults):
                if not isinstance(arg, ast.Name):
                    raise JSError("tuples in argument list are not supported")

                js_args.append(arg.id)

                if default is not None:
                    js_defaults.append("%(id)s = typeof(%(id)s) != 'undefined' ? %(id)s : %(def)s;\n" % { 'id': arg.id, 'def': self.visit(default) })

            if self._class_name:
                prep = "_%s.prototype.%s = function(" % \
                        (self._class_name, node.name)
                if not is_static:
                    if not (js_args[0] == "self"):
                        raise NotImplementedError("The first argument must be 'self'.")
                    del js_args[0]
            else:
                prep = "function %s(" % node.name
            js = [prep + ", ".join(js_args) + ") {"]

            js.extend(self.indent(js_defaults))

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

            js.append('}')

            #If method is static, we also add it directly to the class
            if is_static:
                js.append("%s.%s = _%s.prototype.%s;" % \
                        (self._class_name, node.name, self._class_name, node.name))

            self._scope = []
            return js
        else:
            defaults = [None]*(len(node.args.args) - len(node.args.defaults)) + node.args.defaults

            args = []
            defaults2 = []
            for arg, default in zip(node.args.args, defaults):
                if not isinstance(arg, ast.Name):
                    raise JSError("tuples in argument list are not supported")
                if default:
                    defaults2.append("%s: %s" % (arg.id, self.visit(default)))
                args.append(arg.id)
            defaults = "{" + ", ".join(defaults2) + "}"
            args = ", ".join(args)
            js = ["var %s = $def(%s, function(%s) {" % (node.name,
                defaults, args)]
            self._scope = [arg.id for arg in node.args.args]
            for stmt in node.body:
                js.extend(self.indent(self.visit(stmt)))
            return js + ["});"]

    @scope
    def visit_ClassDef(self, node):
        js = []
        bases = [self.visit(n) for n in node.bases]
        assert len(bases) >= 1
        bases = ", ".join(bases)
        class_name = node.name
        #self._classes remembers all classes defined
        self._classes[class_name] = node
        js.append("function %s() {" % class_name)
        js.append("    t = new _%s();" % class_name)
        js.append("    _%s.prototype.__init__.apply(t,arguments);" % class_name)
        js.append("    return t;")
        js.append("}")
        js.append("function _%s() {" % class_name)
        js.append("}")
        js.append("_%s.__name__ = '%s';" % (class_name, class_name))
        js.append("_%s.prototype.__class__ = _%s;" % (class_name, class_name))
        from ast import dump
        methods = []
        all_attributes = set()
        self._class_name = class_name
        for stmt in node.body:
            if isinstance(stmt, ast.FunctionDef):
                methods.append(stmt)
                all_attributes.add(stmt.name)
            if isinstance(stmt, ast.Assign):
                value = self.visit(stmt.value)
                for t in stmt.targets:
                    all_attributes.add(t.id )
                    var = self.visit(t)
                    js.append("%s.%s = %s;" % (class_name, var, value))
                    js.append("_%s.prototype.%s = %s.%s;" % (class_name, var, class_name, var))
            else:
                js.extend(self.visit(stmt))
        self._class_name = None
        #TODO: take care of super keyword
#        print self.mro(class_name)
        for cls in self.mro(class_name)[1:-1]:
            base_node = self._classes[cls]
            for stmt in base_node.body:
                if isinstance(stmt, ast.FunctionDef) and not stmt.name in all_attributes:
                    all_attributes.add(stmt.name)
                    js.append("_%s.prototype.%s = _%s.prototype.%s;" % (class_name, stmt.name, cls, stmt.name))
                    if len(stmt.decorator_list) == 1 and \
                    isinstance(stmt.decorator_list[0], ast.Name) and \
                    stmt.decorator_list[0].id == "staticmethod":
                        js.append("%s.%s = _%s.prototype.%s;" % (class_name, stmt.name, cls, stmt.name))
                elif isinstance(stmt, ast.Assign):
                    for t in stmt.targets:
                        if not t.id in all_attributes:
                            all_attributes.add(t.id)
                            js.append("_%s.prototype.%s = %s.%s;" % (class_name, t.id, cls, t.id))

        methods_names = [m.name for m in methods]
        if not "__init__" in methods_names:
            # if the user didn't define __init__(), we have to add it ourselves
            # because we call it from the constructor above
            js.append("_%s.prototype.__init__ = function() {" % class_name)<commit_msg>Fixed tests after replacing mro with code from pypy<commit_after>#! /usr/bin/env python

"""
Python grammar, the AST classes contain those arguments as properties.

module Python version "$Revision: 62047 $"
{
    mod = Module(stmt* body)
        | Interactive(stmt* body)
        | Expression(expr body)

    stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list)
          | ClassDef(identifier name, expr* bases, stmt* body, expr *decorator_list)
          | Return(expr? value)

          | Delete(expr* targets)
          | Assign(expr* targets, expr value)
          | AugAssign(expr target, operator op, expr value)

          | Print(expr? dest, expr* values, int nl)

          | For(expr target, expr iter, stmt* body, stmt* orelse)
          | While(expr test, stmt* body, stmt* orelse)
          | If(expr test, stmt* body, stmt* orelse)
          | With(expr context_expr, expr? optional_vars, stmt* body)

          | Raise(expr? type, expr? inst, expr? tback)
          | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
          | TryFinally(stmt* body, stmt* finalbody)
          | Assert(expr test, expr? msg)

          | Import(alias* names)
          | ImportFrom(identifier module, alias* names, int? level)

          | Exec(expr body, expr? globals, expr? locals)

          | Global(identifier* names)
          | Expr(expr value)
          | Pass | Break | Continue

    expr = BoolOp(boolop op, expr* values)
         | BinOp(expr left, operator op, expr right)
         | UnaryOp(unaryop op, expr operand)
         | Lambda(arguments args, expr body)
         | IfExp(expr test, expr body, expr orelse)
         | Dict(expr* keys, expr* values)
         | ListComp(expr elt, comprehension* generators)
         | GeneratorExp(expr elt, comprehension* generators)
         | Yield(expr? value)
         | Compare(expr left, cmpop* ops, expr* comparators)
         | Call(expr func, expr* args, keyword* keywords, expr? starargs, expr? kwargs)
         | Repr(expr value)
         | Num(object n)
         | Str(string s)

         | Attribute(expr value, identifier attr, expr_context ctx)
         | Subscript(expr value, slice slice, expr_context ctx)
         | Name(identifier id, expr_context ctx)
         | List(expr* elts, expr_context ctx)
         | Tuple(expr* elts, expr_context ctx)

    expr_context = Load | Store | Del | AugLoad | AugStore | Param

    slice = Ellipsis
          | Slice(expr? lower, expr? upper, expr? step)
          | ExtSlice(slice* dims)
          | Index(expr value)

    boolop = And | Or

    operator = Add | Sub | Mult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv

    unaryop = Invert | Not | UAdd | USub

    cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn

    comprehension = (expr target, expr iter, expr* ifs)

    excepthandler = ExceptHandler(expr? type, expr? name, stmt* body)

    arguments = (expr* args, identifier? vararg, identifier? kwarg, expr* defaults)
    keyword = (identifier arg, expr value)

    alias = (identifier name, identifier? asname)
}
"""

import ast
import inspect
from optparse import OptionParser

def scope(func):
    func.scope = True
    return func

class JSError(Exception):
    pass

class JS(object):

    name_map = {
        'self'   : 'this',
        'True'   : 'true',
        'False'  : 'false',
        'None'  : 'null',

        'int' : '_int',
        'float' : '_float',

        # ideally we should check, that this name is available:
        'py_builtins' : '___py_hard_to_collide',
    }

    builtin = set([
        'NotImplementedError',
        'ZeroDivisionError',
        'AssertionError',
        'AttributeError',
        'RuntimeError',
        'ImportError',
        'TypeError',
        'ValueError',
        'NameError',
        'IndexError',
        'KeyError',
        'StopIteration',

        '_int',
        '_float',
        'max',
        'min',
        'sum',
    ])

    bool_op = {
        'And'    : '&&',
        'Or'     : '||',
    }

    unary_op = {
        'Invert' : '~',
        'Not'    : '!',
        'UAdd'   : '+',
        'USub'   : '-',
    }

    binary_op = {
        'Add'    : '+',
        'Sub'    : '-',
        'Mult'   : '*',
        'Div'    : '/',
        'Mod'    : '%',
        'LShift' : '<<',
        'RShift' : '>>',
        'BitOr'  : '|',
        'BitXor' : '^',
        'BitAnd' : '&',
    }

    comparison_op = {
            'Eq'    : "==",
            'NotEq' : "!=",
            'Lt'    : "<",
            'LtE'   : "<=",
            'Gt'    : ">",
            'GtE'   : ">=",
            'Is'    : "===",
            'IsNot' : "is not", # Not implemented yet
        }

    def __init__(self):
        self.dummy = 0
        self.classes = ['dict', 'list', 'tuple']
        # This is the name of the class that we are currently in:
        self._class_name = None

        # This lists all variables in the local scope:
        self._scope = []
        self._classes = {'object':None}
        #~ self._classes = {}

    def new_dummy(self):
        dummy = "__dummy%d__" % self.dummy
        self.dummy += 1
        return dummy

    def name(self, node):
        return node.__class__.__name__

    def get_bool_op(self, node):
        return self.bool_op[node.op.__class__.__name__]

    def get_unary_op(self, node):
        return self.unary_op[node.op.__class__.__name__]

    def get_binary_op(self, node):
        return self.binary_op[node.op.__class__.__name__]

    def get_comparison_op(self, node):
        return self.comparison_op[node.__class__.__name__]

    #This python code taken from pypy:
    #License for files in the pypy/ directory 
    #==================================================
    #
    #Except when otherwise stated (look for LICENSE files in directories or
    #information at the beginning of each file) all software and
    #documentation in the 'pypy' directories is licensed as follows: 
    #
    #    The MIT License
    #
    #    Permission is hereby granted, free of charge, to any person 
    #    obtaining a copy of this software and associated documentation 
    #    files (the "Software"), to deal in the Software without 
    #    restriction, including without limitation the rights to use, 
    #    copy, modify, merge, publish, distribute, sublicense, and/or 
    #    sell copies of the Software, and to permit persons to whom the 
    #    Software is furnished to do so, subject to the following conditions:
    #
    #    The above copyright notice and this permission notice shall be included 
    #    in all copies or substantial portions of the Software.
    #
    #    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
    #    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    #    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
    #    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    #    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    #    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    #    DEALINGS IN THE SOFTWARE.
    #
    #
    #PyPy Copyright holders 2003-2010
    #----------------------------------- 
    #
    #Except when otherwise stated (look for LICENSE files or information at
    #the beginning of each file) the files in the 'pypy' directory are each
    #copyrighted by one or more of the following people and organizations:    
    #
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    boria
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #    <NAME>
    #
    #    Heinrich-Heine University, Germany 
    #    Open End AB (formerly AB Strakt), Sweden
    #    merlinux GmbH, Germany 
    #    tismerysoft GmbH, Germany 
    #    Logilab Paris, France 
    #    DFKI GmbH, Germany 
    #    Impara, Germany
    #    Change Maker, Sweden 
    #
    def mro(self, cls):
        order = []
        if cls == 'object':return ['object']
        orderlists = [self.mro(base.id) for base in self._classes[cls].bases if base]
        orderlists.append([cls] + list(c.id for c in self._classes[cls].bases if c))
        while orderlists:
            for candidatelist in orderlists:
                candidate = candidatelist[0]
                if self.blockinglist(candidate, orderlists) is None:
                    break    # good candidate
            else:
                self.mro_error(orderlists)  # no candidate found
            assert candidate not in order
            order.append(candidate)
            for i in range(len(orderlists)-1, -1, -1):
                if orderlists[i][0] == candidate:
                    del orderlists[i][0]
                    if len(orderlists[i]) == 0:
                        del orderlists[i]
        #~ order.append('object')
        return order

    def blockinglist(self,candidate, orderlists):
        for lst in orderlists:
            if candidate in lst[1:]:
                return lst
        return None  # good candidate

    def mro_error(self,orderlists):
        cycle = []
        candidate = orderlists[0][0]
        while candidate not in cycle:
            cycle.append(candidate)
            nextblockinglist = self.blockinglist(candidate, orderlists)
            candidate = nextblockinglist[0]
        # avoid the only use of list.index in the PyPy code base:
        i = 0
        for c in cycle:
            if c == candidate:
                break
            i += 1
        del cycle[:i]
        cycle.append(candidate)
        cycle.reverse()
        #~ names = [cls.__name__ for cls in cycle]
        raise TypeError, "Cycle among base classes: " + ' < '.join(cycle)

    def mronames(self,cls):
        #~ names = [cls.__name__ for cls in mro(cls)]
        #~ return names
        return self.mro(cls)

    def visit(self, node, scope=None):
        try:
            visitor = getattr(self, 'visit_' + self.name(node))
        except AttributeError:
            raise JSError("syntax not supported (%s)" % node)

        if hasattr(visitor, 'statement'):
            return visitor(node, scope)
        else:
            return visitor(node)

    def indent(self, stmts):
        return [ "    " + stmt for stmt in stmts ]

    def visit_Module(self, node):
        module = []

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

        return module

    @scope
    def visit_FunctionDef(self, node):
        is_static = False
        if node.decorator_list:
            if len(node.decorator_list) == 1 and \
                    isinstance(node.decorator_list[0], ast.Name) and \
                    node.decorator_list[0].id == "JavaScript":
                pass # this is our own decorator
            elif self._class_name and \
                    len(node.decorator_list) == 1 and \
                    isinstance(node.decorator_list[0], ast.Name) and \
                    node.decorator_list[0].id == "staticmethod":
                is_static = True
            else:
                raise JSError("decorators are not supported")

        if self._class_name:
            if node.args.vararg is not None:
                raise JSError("star arguments are not supported")

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

            if node.decorator_list and not is_static:
                raise JSError("decorators are not supported")

            defaults = [None]*(len(node.args.args) - len(node.args.defaults)) + node.args.defaults

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

            for arg, default in zip(node.args.args, defaults):
                if not isinstance(arg, ast.Name):
                    raise JSError("tuples in argument list are not supported")

                js_args.append(arg.id)

                if default is not None:
                    js_defaults.append("%(id)s = typeof(%(id)s) != 'undefined' ? %(id)s : %(def)s;\n" % { 'id': arg.id, 'def': self.visit(default) })

            if self._class_name:
                prep = "_%s.prototype.%s = function(" % \
                        (self._class_name, node.name)
                if not is_static:
                    if not (js_args[0] == "self"):
                        raise NotImplementedError("The first argument must be 'self'.")
                    del js_args[0]
            else:
                prep = "function %s(" % node.name
            js = [prep + ", ".join(js_args) + ") {"]

            js.extend(self.indent(js_defaults))

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

            js.append('}')

            #If method is static, we also add it directly to the class
            if is_static:
                js.append("%s.%s = _%s.prototype.%s;" % \
                        (self._class_name, node.name, self._class_name, node.name))

            self._scope = []
            return js
        else:
            defaults = [None]*(len(node.args.args) - len(node.args.defaults)) + node.args.defaults

            args = []
            defaults2 = []
            for arg, default in zip(node.args.args, defaults):
                if not isinstance(arg, ast.Name):
                    raise JSError("tuples in argument list are not supported")
                if default:
                    defaults2.append("%s: %s" % (arg.id, self.visit(default)))
                args.append(arg.id)
            defaults = "{" + ", ".join(defaults2) + "}"
            args = ", ".join(args)
            js = ["var %s = $def(%s, function(%s) {" % (node.name,
                defaults, args)]
            self._scope = [arg.id for arg in node.args.args]
            for stmt in node.body:
                js.extend(self.indent(self.visit(stmt)))
            return js + ["});"]

    @scope
    def visit_ClassDef(self, node):
        js = []
        bases = [self.visit(n) for n in node.bases]
        assert len(bases) >= 1
        bases = ", ".join(bases)
        class_name = node.name
        #self._classes remembers all classes defined
        self._classes[class_name] = node
        js.append("function %s() {" % class_name)
        js.append("    t = new _%s();" % class_name)
        js.append("    _%s.prototype.__init__.apply(t,arguments);" % class_name)
        js.append("    return t;")
        js.append("}")
        js.append("function _%s() {" % class_name)
        js.append("}")
        js.append("_%s.__name__ = '%s';" % (class_name, class_name))
        js.append("_%s.prototype.__class__ = _%s;" % (class_name, class_name))
        from ast import dump
        methods = []
        all_attributes = set()
        self._class_name = class_name
        for stmt in node.body:
            if isinstance(stmt, ast.FunctionDef):
                methods.append(stmt)
                all_attributes.add(stmt.name)
            if isinstance(stmt, ast.Assign):
                value = self.visit(stmt.value)
                for t in stmt.targets:
                    all_attributes.add(t.id )
                    var = self.visit(t)
                    js.append("%s.%s = %s;" % (class_name, var, value))
                    js.append("_%s.prototype.%s = %s.%s;" % (class_name, var, class_name, var))
            else:
                js.extend(self.visit(stmt))
        self._class_name = None
        #TODO: take care of super keyword
        #~ print self.mro(class_name)
        for cls in self.mro(class_name)[1:-1]:
            base_node = self._classes[cls]
            for stmt in base_node.body:
                if isinstance(stmt, ast.FunctionDef) and not stmt.name in all_attributes:
                    all_attributes.add(stmt.name)
                    js.append("_%s.prototype.%s = _%s.prototype.%s;" % (class_name, stmt.name, cls, stmt.name))
                    if len(stmt.decorator_list) == 1 and \
                    isinstance(stmt.decorator_list[0], ast.Name) and \
                    stmt.decorator_list[0].id == "staticmethod":
                        js.append("%s.%s = _%s.prototype.%s;" % (class_name, stmt.name, cls, stmt.name))
                elif isinstance(stmt, ast.Assign):
                    for t in stmt.targets:
                        if not t.id in all_attributes:
                            all_attributes.add(t.id)
                            js.append("_%s.prototype.%s = %s.%s;" % (class_name, t.id, cls, t.id))

        methods_names = [m.name for m in methods]
        if not "__init__" in methods_names:
            # if the user didn't define __init__(), we have to add it ourselves
            # because we call it from the constructor above
            js.append("_%s.prototype.__init__ = function() {" % class_name)
{'fraction_non_alphanumeric': 0.12243362955121598, 'fraction_numerical': 0.0025071733013900884, 'mean_word_length': 1.7066274598507125, 'pattern_counts': {'":': 6, '<': 159, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4251703', 'n_tokens_mistral': 11107, 'n_tokens_neox': 10655, 'n_words': 2901}