Exemple #1
0
    def handle_args(self, space, bytecode, args_w, block):
        from topaz.interpreter import Interpreter

        if (len(args_w) < (len(bytecode.arg_pos) - len(bytecode.defaults))
                or (bytecode.splat_arg_pos == -1
                    and len(args_w) > len(bytecode.arg_pos))):
            raise space.error(
                space.w_ArgumentError,
                "wrong number of arguments (%d for %d)" %
                (len(args_w), len(bytecode.arg_pos) - len(bytecode.defaults)))

        for i in xrange(min(len(args_w), len(bytecode.arg_pos))):
            self._set_arg(space, bytecode.arg_pos[i], args_w[i])
        defl_start = len(args_w) - (len(bytecode.arg_pos) -
                                    len(bytecode.defaults))
        for i in xrange(len(bytecode.arg_pos) - len(args_w)):
            bc = bytecode.defaults[i + defl_start]
            w_value = Interpreter().interpret(space, self, bc)
            self._set_arg(space, bytecode.arg_pos[i + len(args_w)], w_value)

        if bytecode.splat_arg_pos != -1:
            if len(bytecode.arg_pos) > len(args_w):
                splat_args_w = []
            else:
                splat_args_w = args_w[len(bytecode.arg_pos):]
            w_splat_args = space.newarray(splat_args_w)
            self._set_arg(space, bytecode.splat_arg_pos, w_splat_args)

        if bytecode.block_arg_pos != -1:
            if block is None:
                w_block = space.w_nil
            else:
                w_block = space.newproc(block)
            self._set_arg(space, bytecode.block_arg_pos, w_block)
Exemple #2
0
 def execute_frame(self, frame, bc):
     return Interpreter().interpret(self, frame, bc)
Exemple #3
0
    def handle_args(self, space, bytecode, args_w, block):
        from topaz.interpreter import Interpreter

        keywords_hash = None
        if len(bytecode.kwarg_names) > 0 or bytecode.kwrest_pos != -1:
            # we only take the hash if we have more than enough arguments
            if len(args_w) > 0 and len(args_w) > (len(bytecode.arg_pos) - len(bytecode.defaults)):
                w_obj = args_w[-1]
                if not space.is_kind_of(w_obj, space.w_hash):
                    w_obj = space.convert_type(w_obj, space.w_hash, "to_hash", reraise_error=True)
                if isinstance(w_obj, W_HashObject):
                    keywords_hash = space.send(w_obj, "clone")
                    assert isinstance(keywords_hash, W_HashObject)

        if len(bytecode.kw_defaults) < len(bytecode.kwarg_names) and not keywords_hash:
            raise space.error(space.w_ArgumentError,
                "missing keywords: %s" % ",".join(bytecode.kwarg_names)
            )

        pre = 0
        post = len(args_w) if keywords_hash is None else len(args_w) - 1

        if (post < (len(bytecode.arg_pos) - len(bytecode.defaults)) or
            (bytecode.splat_arg_pos == -1 and post > len(bytecode.arg_pos))):
            raise space.error(space.w_ArgumentError,
                "wrong number of arguments (%d for %d)" % (len(args_w), len(bytecode.arg_pos) - len(bytecode.defaults))
            )

        if bytecode.default_arg_begin != -1:
            len_pre_args = bytecode.default_arg_begin
        elif bytecode.splat_arg_pos != -1:
            len_pre_args = bytecode.splat_arg_pos
        else:
            len_pre_args = len(bytecode.arg_pos)
        len_post_arg = len(bytecode.arg_pos) - len(bytecode.defaults) - len_pre_args

        # [required args, optional args, splat arg, required args, keywords args, keyword rest, block]
        #  ^                                                      ^
        # pre                                                   post

        # fill post-arguments from back.
        actual_args_len = post
        offset = len(bytecode.arg_pos) - post
        for i in xrange(actual_args_len - 1, actual_args_len - len_post_arg - 1, -1):
            self._set_arg(space, bytecode.arg_pos[i + offset], args_w[i])
            post -= 1
        # [required args, optional args, splat arg, required args, keywords args, keyword rest, block]
        #  ^                                       ^-------------
        # pre                                    post

        # fill arguments from start as far as we can (until we hit post or the
        # end of the default arguments + normal arguments
        for i in xrange(min(post, len_pre_args + len(bytecode.defaults))):
            self._set_arg(space, bytecode.arg_pos[i], args_w[i])
            pre += 1
        # [required args, optional args, splat arg, required args, keywords args, keyword rest, block]
        #  ------------------------^               ^
        #                         pre            post

        given_defaults = pre - len_pre_args
        # fill up remaining default arguments with their default values
        for i in xrange(given_defaults, len(bytecode.defaults)):
            bc = bytecode.defaults[i]
            self.bytecode = bc
            w_value = Interpreter().interpret(space, self, bc)
            self._set_arg(space, bytecode.arg_pos[len_pre_args + i], w_value)

        if bytecode.splat_arg_pos != -1:
            if pre >= post:
                splat_args_w = []
            else:
                splat_args_w = args_w[pre:post]
            w_splat_args = space.newarray(splat_args_w)
            self._set_arg(space, bytecode.splat_arg_pos, w_splat_args)

        for i, name in enumerate(bytecode.kwarg_names):
            w_key = space.newsymbol(name)
            w_value = None
            if keywords_hash is not None:
                try:
                    w_value = keywords_hash.getitem(w_key)
                    keywords_hash.delete(w_key)
                except KeyError:
                    pass
            # kword arguments with defaults come first, so if we get an
            # index error here, we're missing a required keyword argument
            if w_value is None:
                try:
                    bc = bytecode.kw_defaults[i]
                except IndexError:
                    raise space.error(space.w_ArgumentError,
                        "missing keyword: %s" % name
                    )
                self.bytecode = bc
                w_value = Interpreter().interpret(space, self, bc)
            self._set_arg(space, bytecode.cellvars.index(name), w_value)

        self.bytecode = bytecode

        if bytecode.kwrest_pos != -1:
            if keywords_hash is not None:
                self._set_arg(space, bytecode.kwrest_pos, keywords_hash)
            else:
                self._set_arg(space, bytecode.kwrest_pos, space.newhash())
        elif keywords_hash is not None:
            if keywords_hash.size() > 0:
                raise space.error(space.w_ArgumentError,
                    "unknown keywords: %s" % space.str_w(
                        space.send(space.send(keywords_hash, "keys"), "to_s")
                    )
                )

        if bytecode.block_arg_pos != -1:
            if block is None:
                w_block = space.w_nil
            else:
                w_block = block.copy(space)
            self._set_arg(space, bytecode.block_arg_pos, w_block)