@parameters(name='print')
def magic_print(space, args_w):
    print space.str(args_w[0]) def create_module(name, functions):
    name2index = {}
    for i, func in enumerate(functions):
        name2index[func.name] = i
    return W_Module(name, name2index, functions[:]) @unwrap_spec(size='int')
def buffer(space, size):
    return space.newbuf(['\x00'] * size) @unwrap_spec(utf8='utf8')
def buffer_from_utf8(space, utf8):
    return space.newbuf([c for c in utf8]) def len(space, w_obj):
def builtin_isinstance(space, w_obj, w_type):
def builtin_str(space, w_obj): class W_Exception(W_UserObject):
    def __init__(self, w_tp, message):
        W_UserObject.__init__(self, w_tp)
        self.message = message

    def get_message(self, space):
        return space.newtext(self.message)

    def __repr__(self):
        return '<%s %s>' % (self.w_type.name, self.message) def wrap_function(space, f, name=None, exp_name=None):
    if name is None:
        name = f.__name__
    argnames = f.__code__.co_varnames[:f.__code__.co_argcount]
    lines = ['def %s(space, args_w):' % name]
    j = 0
    numargs = 0
    argdefaults = [None] * len(argnames)
    defs = []
    if f.__defaults__ is not None:
        defs = f.__defaults__
        firstdefault = len(argnames) - len(defs)
        for i in range(len(defs)):
            if defs[i] is None:
                argdefaults[i + firstdefault] = space.w_None
            elif isinstance(defs[i], int):
                argdefaults[i + firstdefault] = space.newint(defs[i])
            else:
                raise NotImplementedError(
                    "Default handling not supported for %s" % (defs[i],))

    d = {'orig_' + name: f, 'argdefaults': argdefaults}
    for i, argname in enumerate(argnames):
        extralines = []
        if argname == 'space':
            argval = 'space'
        elif argname == 'args_w':
            argval = 'args_w'
            numargs = -1
            assert i == len(argnames) - 1
        elif argname == 'self':
            if not isinstance(f, types.MethodType):
                raise Exception("self argument, but argument is not a method")
            argval = 'args_w[0]'
            j += 1
            numargs += 1
            msg = "Expected %s object, got %%s" % exp_name
            extralines = [
                '    if not isinstance(arg%d, self_tp):' % i,
                '        raise space.apperr(space.w_typeerror, "%s" %% '
                '(space.type(arg%d).name,))' % (msg, i),
            ]
            d['self_tp'] = f.im_class
        elif argname.startswith('w_'):
            argval = 'args_w[%d]' % j
            j += 1
            numargs += 1
        else:
            if hasattr(f, 'unwrap_spec'):
                spec = f.unwrap_spec.get(argname, None)
            else:
                spec = None
            numargs += 1
            if spec is None:
                raise Exception("No spec found for %s while wrapping %s" %
                                (argname, name))
            if spec == 'utf8':
                argval = 'space.utf8_w(args_w[%d])' % j
                j += 1
            elif spec == 'int':
                argval = 'space.int_w(args_w[%d])' % j
                j += 1
            elif spec == 'list':
                argval = 'space.listview(args_w[%d])' % j
                j += 1
            elif spec == 'dict':
                argval = 'space.dictview(args_w[%d])' % j
                j += 1
            else:
                assert False
        if argdefaults[i] is not None:
            lines.append('    if len(args_w) <= %d:' % (numargs - 1))
            if argname.startswith('w_'):
                lines.append('        arg%d = argdefaults[%d]' % (i, i))
            else:
                lines.append('        arg%d = %r' % (i, f.__defaults__[i - firstdefault]))
            lines.append('    else:')
            lines.append('        arg%d = %s' % (i, argval))
        else:
            lines.append('    arg%d = %s' % (i, argval))
        lines += extralines
    args = ", ".join(['arg%d' % i for i in range(len(argnames))])
    lines.append('    return orig_%s(%s)' % (name, args))
    src = py.code.Source("\n".join(lines))
    exec src.compile() in d
    exported_name = name
    if getattr(f, 'unwrap_parameters', None):
        exported_name = f.unwrap_parameters.get('name', exported_name)
    return W_BuiltinFunction(exported_name, d[name],
        min_args=numargs - len(defs),
        max_args=numargs) def wrap_type(space, tp):
    spec = tp.spec
    if spec.constructor is None:
        allocate = None
    else:
        allocate = wrap_function(space, spec.constructor)
    properties = []
    for name, (get_prop, set_prop) in spec.properties.iteritems():
        if set_prop is not None:
            set_prop = set_prop.im_func
        properties.append(W_Property(name, get_prop.im_func, set_prop))
    for name, meth in spec.methods.iteritems():
        properties.append(wrap_function(space, meth, name=name, exp_name=spec.name))
    if spec.parent_name is None:
        parent = None
    else:
        parent = space.builtin_dict[spec.parent_name]
    w_tp = W_UserType(allocate, spec.name, properties, parent, default_alloc=False)
    if not spec.is_subclassable:
        tp.cls_w_type = w_tp
    return w_tp def get_current_frame(space):
    return W_FrameWrapper(space.interpreter.topframeref) class W_FrameWrapper(W_Root):
    def __init__(self, frameref):
        self.frameref = frameref

    def get_filename(self, space):
        return space.newtext(self.frameref.bytecode.filename) class W_StringBuilder(W_Root):
    def __init__(self, length):
        self._s = StringBuilder(length)

    @unwrap_spec(txt='utf8')
    def append(self, txt):
        self._s.append(txt)

    def build(self, space):
        return space.newtext(self._s.build()) def freeze(space, w_obj):
def thaw(space, w_obj):
def is_frozen(space, w_obj): class W_DictObject(W_Root):
    def __init__(self, key_eq, key_hash, items_w):
        self._items_w = r_dict(key_eq, key_hash)
        for k, v in items_w:
            self._items_w[k] = v

    def str(self, space):
        return '{' + ', '.join([space.str(k) + ': ' + space.str(v)
                                for k, v in self._items_w.items()]) + '}'

    def dictview(self, space):
        return self._items_w

    def len(self, space):
        return len(self._items_w)

    def contains(self, space, w_obj):
        return w_obj in self._items_w

    def getitem(self, space, w_key):
        if w_key not in self._items_w:
            raise space.apperr(space.w_keyerror, space.str(w_key))
        return self._items_w[w_key]

    def get(self, space, w_key, w_default=None):
        if w_key not in self._items_w:
            return w_default
        return self._items_w[w_key]

    def dict_pop(self, space, w_key):
        if w_key not in self._items_w:
            raise space.apperr(space.w_keyerror, space.str(w_key))
        return self._items_w.pop(w_key)

    def setitem(self, space, w_key, w_value):
        self._items_w[w_key] = w_value

    def merge(self, space, w_other):
        other_w = space.dictview(w_other)
        w_res = space.newdict([])
        w_res._items_w.update(self._items_w)
        w_res._items_w.update(other_w)
        return w_res

    def keys(self, space):
        return space.newlist(self._items_w.keys())

    def values(self, space):
        return space.newlist(self._items_w.values()) class W_IntObject(W_Root):
    def __init__(self, intval):
        self._intval = intval

    def str(self, space):
        return str(self._intval)

    def hash(self, space):
        return compute_hash(self._intval)

    def int_w(self, space):
        return self._intval

    def lt(self, space, w_other):
        return self._intval < w_other._intval

    def eq(self, space, w_other):
        try:
            other = space.int_w(w_other)
        except AppError as ae:
            if ae.match(space, space.w_typeerror):
                raise NotImplementedOp
            raise
        return self._intval == other

    def add(self, space, w_other):
        return space.newint(self._intval + w_other._intval)

    def sub(self, space, w_other):
        return space.newint(self._intval - w_other._intval)

    def mul(self, space, w_other):
        return space.newint(self._intval * w_other._intval)

    def truediv(self, space, w_other):
        return space.newint(self._intval // w_other._intval)

    def is_true(self, space):
        return self._intval != 0

    def __repr__(self):
        return '<Int %d>' % self._intval class W_ListObject(W_Root):
    def __init__(self, items_w):
        self._items_w = items_w[:]

    def str(self, space):
        return '[' + ', '.join([space.str(i) for i in self._items_w]) + ']'

    def listview(self, space):
        return self._items_w

    def len(self, space):
        return len(self._items_w)

    def contains(self, space, w_obj):
        for w_item in self._items_w:
            if space.binop_eq(w_obj, w_item):
                return True
        return False

    def unwrap_index(self, space, w_index):
        try:
            i = space.int_w(w_index)
        except AppError as ae:
            if ae.match(space, space.w_typeerror):
                raise space.apperr(space.w_typeerror, 'list index must be int')
            raise
        if i < 0 or i >= len(self._items_w):
            raise space.apperr(space.w_indexerror, 'list index out of range')
        return i

    def getitem(self, space, w_index):
        return self._items_w[self.unwrap_index(space, w_index)]

    def setitem(self, space, w_index, w_value):
        self._items_w[self.unwrap_index(space, w_index)] = w_value

    def iter(self, space):
        return W_ListIterator(self)

    def append(self, space, w_obj):
        self._items_w.append(w_obj)

    def extend(self, space, w_other):
        self._items_w.extend(space.listview(w_other)) class W_StrObject(W_Root):
    def __init__(self, utf8val, lgt=-1):
        assert isinstance(utf8val, str)
        self.utf8val = utf8val
        self.lgt = lgt

    def utf8_w(self, space):
        return self.utf8val

    def str(self, space):
        return self.utf8_w(space)

    def len(self, space):
        if self.lgt == -1:
            # XXX compute it better once utf8 lands
            self.lgt = len(self.utf8val.decode('utf-8'))
        return self.lgt

    def hash(self, space):
        return compute_hash(self.utf8val)

    def eq(self, space, w_other):
        try:
            other = space.utf8_w(w_other)
        except AppError as ae:
            if space.type(ae.w_exception) is space.w_typeerror:
                raise NotImplementedOp
            raise
        return self.utf8val == other

    def is_frozen(self, space):
        return True
from nolang.builtins.io import magic_print
from nolang.module import create_module
from nolang.builtins.buffer import buffer, buffer_from_utf8
from nolang.builtins import builtin
from nolang.builtins.exception import W_Exception
from nolang.builtins.spec import wrap_function, wrap_type
from nolang.builtins.core.reflect import get_current_frame, W_FrameWrapper
from nolang.builtins.core.text import W_StringBuilder
from nolang.builtins.core import freezing
from nolang.objects.dict import W_DictObject
from nolang.objects.int import W_IntObject
from nolang.objects.list import W_ListObject
from nolang.objects.unicode import W_StrObject


def wrap_module(name, functions):
    raise NotImplementedError


def default_builtins(space):
    # XXX all of this should be more streamlined
    reflect_module = create_module('reflect',
                                   [wrap_function(space, get_current_frame)])
    text_module = create_module('text',
        [wrap_type(space, W_StringBuilder)])
    freezing_module = create_module('freezing',

        [wrap_function(space, func) for func in freezing.functions])