Пример #1
0
class W_SyntaxError(W_ScriptError):
    classdef = ClassDef("SyntaxError", W_ScriptError.classdef)
    method_allocate = new_exception_allocate(classdef)
Пример #2
0
class W_NotImplementedError(W_ScriptError):
    classdef = ClassDef("NotImplementedError", W_ScriptError.classdef)
    method_allocate = new_exception_allocate(classdef)
Пример #3
0
class W_StringObject(W_Object):
    classdef = ClassDef("String", W_Object.classdef)
    classdef.include_module(Comparable)

    def __init__(self, space, storage, strategy):
        W_Object.__init__(self, space)
        self.str_storage = storage
        self.strategy = strategy

    def __deepcopy__(self, memo):
        obj = super(W_StringObject, self).__deepcopy__(memo)
        obj.str_storage = copy.deepcopy(self.str_storage, memo)
        obj.strategy = copy.deepcopy(self.strategy, memo)
        return obj

    @staticmethod
    def newstr_fromstr(space, strvalue):
        strategy = space.fromcache(ConstantStringStrategy)
        storage = strategy.erase(strvalue)
        return W_StringObject(space, storage, strategy)

    @staticmethod
    def newstr_fromchars(space, chars):
        strategy = space.fromcache(MutableStringStrategy)
        storage = strategy.erase(chars)
        return W_StringObject(space, storage, strategy)

    def str_w(self, space):
        return self.strategy.str_w(self.str_storage)

    def liststr_w(self, space):
        return self.strategy.liststr_w(self.str_storage)

    def length(self):
        return self.strategy.length(self.str_storage)

    def copy(self, space):
        return self.strategy.copy(space, self.str_storage)

    def replace(self, space, chars):
        strategy = space.fromcache(MutableStringStrategy)
        self.str_storage = strategy.erase(chars)
        self.strategy = strategy

    def extend(self, space, w_other):
        self.strategy.to_mutable(space, self)
        strategy = self.strategy
        assert isinstance(strategy, MutableStringStrategy)
        storage = strategy.unerase(self.str_storage)
        w_other.strategy.extend_into(w_other.str_storage, storage)

    def clear(self, space):
        self.strategy.to_mutable(space, self)
        self.strategy.clear(self)

    def tr_trans(self, space, source, replacement, squeeze):
        change_made = False
        string = space.str_w(self)
        new_string = []
        is_negative_set = len(source) > 1 and source[0] == "^"
        if is_negative_set:
            source = source[1:]

        trans_table = create_trans_table(source, replacement, is_negative_set)

        if squeeze:
            last_repl = ""
            for char in string:
                repl = trans_table[ord(char)]
                if last_repl == repl:
                    continue
                if repl != char:
                    last_repl = repl
                    if not change_made:
                        change_made = True
                new_string.append(repl)
        else:
            for char in string:
                repl = trans_table[ord(char)]
                if not change_made and repl != char:
                    change_made = True
                new_string.append(repl)

        return new_string if change_made else None

    @classdef.method("to_str")
    @classdef.method("to_s")
    def method_to_s(self, space):
        return self

    @classdef.method("+")
    def method_plus(self, space, w_other):
        assert isinstance(w_other, W_StringObject)
        total_size = self.length() + w_other.length()
        s = space.newstr_fromchars(newlist_hint(total_size))
        s.extend(space, self)
        s.extend(space, w_other)
        return s

    @classdef.method("<<")
    def method_lshift(self, space, w_other):
        assert isinstance(w_other, W_StringObject)
        self.extend(space, w_other)
        return self

    @classdef.method("size")
    @classdef.method("length")
    def method_length(self, space):
        return space.newint(self.length())

    @classdef.method("hash")
    def method_hash(self, space):
        return space.newint(self.strategy.hash(self.str_storage))

    @classdef.method("[]")
    def method_subscript(self, space, w_idx, w_count=None):
        start, end, as_range, nil = space.subscript_access(self.length(),
                                                           w_idx,
                                                           w_count=w_count)
        if nil:
            return space.w_nil
        elif as_range:
            assert start >= 0
            assert end >= 0
            return self.strategy.getslice(space, self.str_storage, start, end)
        else:
            return space.newstr_fromstr(
                self.strategy.getitem(self.str_storage, start))

    @classdef.method("<=>")
    def method_comparator(self, space, w_other):
        if isinstance(w_other, W_StringObject):
            s1 = space.str_w(self)
            s2 = space.str_w(w_other)
            if s1 < s2:
                return space.newint(-1)
            elif s1 == s2:
                return space.newint(0)
            elif s1 > s2:
                return space.newint(1)
        else:
            if space.respond_to(
                    w_other, space.newsymbol("to_str")) and space.respond_to(
                        w_other, space.newsymbol("<=>")):
                tmp = space.send(w_other, space.newsymbol("<=>"), [self])
                if tmp is not space.w_nil:
                    return space.newint(-space.int_w(tmp))
            return space.w_nil

    @classdef.method("freeze")
    def method_freeze(self, space):
        pass

    @classdef.method("dup")
    def method_dup(self, space):
        return self.copy(space)

    @classdef.method("to_sym")
    @classdef.method("intern")
    def method_to_sym(self, space):
        return space.newsymbol(space.str_w(self))

    @classdef.method("clear")
    def method_clear(self, space):
        self.clear(space)
        return self

    @classdef.method("ljust", integer="int", padstr="str")
    def method_ljust(self, space, integer, padstr=" "):
        if not padstr:
            raise space.error(space.w_ArgumentError, "zero width padding")
        elif integer <= self.length():
            return self.copy(space)
        else:
            pad_len = integer - self.length() - 1
            assert pad_len >= 0
            chars = []
            chars += space.str_w(self)
            for i in xrange(pad_len / len(padstr)):
                chars += padstr
            chars += padstr[:pad_len % len(padstr) + 1]
            return space.newstr_fromchars(chars)

    @classdef.method("split", limit="int")
    def method_split(self, space, w_sep=None, limit=-1):
        if w_sep is None:
            sep = None
        elif isinstance(w_sep, W_StringObject):
            sep = space.str_w(w_sep)
        else:
            raise NotImplementedError("Regexp separators for String#split")
        results = space.str_w(self).split(sep, limit - 1)
        return space.newarray([space.newstr_fromstr(s) for s in results])

    @classdef.method("downcase!")
    def method_downcase(self, space):
        self.strategy.to_mutable(space, self)
        changed = self.strategy.downcase(self.str_storage)
        return self if changed else space.w_nil

    @classdef.method("to_i", radix="int")
    def method_to_i(self, space, radix=10):
        if not 2 <= radix <= 36:
            raise space.error(space.w_ArgumentError,
                              "invalid radix %d" % radix)
        s = space.str_w(self)
        if not s:
            return space.newint(0)
        i = 0
        neg = s[i] == "-"
        if neg:
            i += 1
        val = 0
        while i < len(s):
            c = ord(s[i])
            if ord("a") <= c <= ord("z"):
                digit = c - ord("a") + 10
            elif ord("A") <= c <= ord("Z"):
                digit = c - ord("A") + 10
            elif ord("0") <= c <= ord("9"):
                digit = c - ord("0")
            else:
                break
            if digit >= radix:
                break
            val = val * radix + digit
            i += 1
        if neg:
            val = -val
        return space.newint(val)

    @classdef.method("tr", source="str", replacement="str")
    def method_tr(self, space, source, replacement):
        string = self.copy(space)
        new_string = self.tr_trans(space, source, replacement, False)
        return space.newstr_fromchars(new_string) if new_string else string

    @classdef.method("tr!", source="str", replacement="str")
    def method_tr_i(self, space, source, replacement):
        new_string = self.tr_trans(space, source, replacement, False)
        self.replace(space, new_string)
        return self if new_string else space.w_nil

    @classdef.method("tr_s", source="str", replacement="str")
    def method_tr_s(self, space, source, replacement):
        string = self.copy(space)
        new_string = self.tr_trans(space, source, replacement, True)
        return space.newstr_fromchars(new_string) if new_string else string

    @classdef.method("tr_s!", source="str", replacement="str")
    def method_tr_s_i(self, space, source, replacement):
        new_string = self.tr_trans(space, source, replacement, True)
        self.replace(space, new_string)
        return self if new_string else space.w_nil

    classdef.app_method("""
    def empty?
        self.length == 0
    end
    """)
Пример #4
0
class W_IntegerObject(W_NumericObject):
    classdef = ClassDef("Integer", W_NumericObject.classdef)

    @classdef.method("to_i")
    def method_to_i(self, space):
        return self
Пример #5
0
class W_ThreadObject(W_Object):
    classdef = ClassDef("Thread", W_Object.classdef)
Пример #6
0
class W_EncodingObject(W_Object):
    classdef = ClassDef("Encoding", W_Object.classdef)
Пример #7
0
class W_BaseObject(object):
    __metaclass__ = ObjectMetaclass
    _attrs_ = []

    classdef = ClassDef("BasicObject")

    def __deepcopy__(self, memo):
        obj = object.__new__(self.__class__)
        memo[id(self)] = obj
        return obj

    @classmethod
    def setup_class(cls, space, w_cls):
        pass

    def getclass(self, space):
        return space.getclassobject(self.classdef)

    def is_kind_of(self, space, w_cls):
        return w_cls.is_ancestor_of(self.getclass(space))

    def attach_method(self, space, name, func):
        w_cls = space.getsingletonclass(self)
        w_cls.define_method(space, name, func)

    def is_true(self, space):
        return True

    @classdef.method("initialize")
    def method_initialize(self):
        return self

    @classdef.method("__id__")
    def method___id__(self, space):
        return space.newint(compute_unique_id(self))

    @classdef.method("method_missing")
    def method_method_missing(self, space, w_name):
        name = space.symbol_w(w_name)
        class_name = space.str_w(
            space.send(self.getclass(space), space.newsymbol("name")))
        raise space.error(space.w_NoMethodError,
                          "undefined method `%s' for %s" % (name, class_name))

    @classdef.method("==")
    @classdef.method("equal?")
    def method_eq(self, space, w_other):
        return space.newbool(self is w_other)

    @classdef.method("!")
    def method_not(self, space):
        return space.newbool(not space.is_true(self))

    @classdef.method("!=")
    def method_ne(self, space, w_other):
        return space.newbool(not space.is_true(
            space.send(self, space.newsymbol("=="), [w_other])))

    @classdef.method("__send__", method="str")
    def method_send(self, space, method, args_w, block):
        return space.send(self, space.newsymbol(method), args_w[1:], block)

    @classdef.method("instance_eval", string="str", filename="str")
    def method_instance_eval(self,
                             space,
                             string=None,
                             filename=None,
                             w_lineno=None,
                             block=None):
        if string is not None:
            if filename is None:
                filename = "instance_eval"
            if w_lineno is not None:
                lineno = space.int_w(w_lineno)
            else:
                lineno = 1
            return space.execute(string, self, space.getclass(self), filename,
                                 lineno)
        else:
            space.invoke_block(
                block.copy(w_self=self, w_scope=space.getclass(self)), [])
Пример #8
0
class W_FileObject(W_IOObject):
    classdef = ClassDef("File", W_IOObject.classdef)

    @classmethod
    def setup_class(cls, space, w_cls):
        if sys.platform == "win32":
            w_alt_seperator = space.newstr_fromstr("\\")
            w_fnm_syscase = space.newint(0x08)
        else:
            w_alt_seperator = space.w_nil
            w_fnm_syscase = space.newint(0)
        space.set_const(w_cls, "SEPARATOR", space.newstr_fromstr("/"))
        space.set_const(w_cls, "ALT_SEPARATOR", w_alt_seperator)
        space.set_const(w_cls, "FNM_SYSCASE", w_fnm_syscase)
        space.set_const(w_cls, "RDONLY", space.newint(os.O_RDONLY))
        space.set_const(w_cls, "WRONLY", space.newint(os.O_WRONLY))
        space.set_const(w_cls, "RDWR", space.newint(os.O_RDWR))
        space.set_const(w_cls, "APPEND", space.newint(os.O_APPEND))
        space.set_const(w_cls, "CREAT", space.newint(os.O_CREAT))
        space.set_const(w_cls, "EXCL", space.newint(os.O_EXCL))
        space.set_const(w_cls, "TRUNC", space.newint(os.O_TRUNC))

    @classdef.singleton_method("allocate")
    def method_allocate(self, space, args_w):
        return W_FileObject(space)

    @classdef.method("initialize", filename="str")
    def method_initialize(self,
                          space,
                          filename,
                          w_mode=None,
                          w_perm_or_opt=None,
                          w_opt=None):
        if isinstance(w_perm_or_opt, W_HashObject):
            assert w_opt is None
            perm = 0665
            w_opt = w_perm_or_opt
        elif w_opt is not None:
            perm = space.int_w(w_perm_or_opt)
        else:
            perm = 0665
        if w_mode is None:
            mode = os.O_RDONLY
        elif isinstance(w_mode, W_StringObject):
            mode_str = space.str_w(w_mode)

            if "+" in mode_str:
                mode = os.O_RDWR
                if "w" in mode_str:
                    mode |= os.O_CREAT | os.O_TRUNC
                elif "a" in mode_str:
                    mode |= os.O_CREAT | os.O_APPEND
            elif mode_str == "r":
                mode = os.O_RDONLY
            elif mode_str == "w":
                mode = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
            elif mode_str == "a":
                mode = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
            else:
                raise space.error(space.w_ArgumentError,
                                  "invalid access mode %s" % mode_str)
        else:
            mode = space.int_w(w_mode)
        if w_perm_or_opt is not None or w_opt is not None:
            raise NotImplementedError(
                "options hash or permissions for File.new")
        self.fd = os.open(filename, mode, perm)
        return self

    @classdef.singleton_method("dirname", path="path")
    def method_dirname(self, space, path):
        if "/" not in path:
            return space.newstr_fromstr(".")
        idx = path.rfind("/")
        while idx > 0 and path[idx - 1] == "/":
            idx -= 1
        if idx == 0:
            return space.newstr_fromstr("/")
        assert idx >= 0
        return space.newstr_fromstr(path[:idx])

    @classdef.singleton_method("expand_path", path="path", dir="path")
    def method_expand_path(self, space, path, dir=None):
        if path and path[0] == "~":
            if len(path) >= 2 and path[1] == "/":
                path = os.environ["HOME"] + path[1:]
            elif len(path) < 2:
                return space.newstr_fromstr(os.environ["HOME"])
            else:
                raise NotImplementedError
        elif not path or path[0] != "/":
            if dir is not None:
                dir = space.str_w(
                    W_FileObject.method_expand_path(self, space, dir))
            else:
                dir = os.getcwd()

            path = dir + "/" + path

        items = []
        parts = path.split("/")
        for part in parts:
            if part == "..":
                items.pop()
            elif part and part != ".":
                items.append(part)

        if not items:
            return space.newstr_fromstr("/")
        return space.newstr_fromstr("/" + "/".join(items))

    @classdef.singleton_method("join")
    def singleton_method_join(self, space, args_w):
        sep = space.str_w(space.find_const(self, "SEPARATOR"))
        result = []
        for w_arg in args_w:
            if isinstance(w_arg, W_ArrayObject):
                string = space.str_w(
                    W_FileObject.singleton_method_join(self, space,
                                                       space.listview(w_arg)))
            else:
                string = space.str_w(w_arg)
            if string.startswith(sep):
                while result and result[-1] == sep:
                    result.pop()
            elif result and not result[-1] == sep:
                result += sep
            result += string
        return space.newstr_fromchars(result)

    @classdef.singleton_method("exists?", filename="str")
    @classdef.singleton_method("exist?", filename="str")
    def method_existp(self, space, filename):
        return space.newbool(os.path.exists(filename))

    @classdef.singleton_method("file?", filename="str")
    def method_filep(self, space, filename):
        return space.newbool(os.path.isfile(filename))

    @classdef.singleton_method("directory?", filename="str")
    def method_directoryp(self, space, filename):
        return space.newbool(os.path.isdir(filename))

    @classdef.singleton_method("executable?", filename="str")
    def method_executablep(self, space, filename):
        return space.newbool(
            os.path.isfile(filename) and os.access(filename, os.X_OK))
Пример #9
0
class W_IOObject(W_Object):
    classdef = ClassDef("IO", W_Object.classdef)

    def __init__(self, space):
        W_Object.__init__(self, space)
        self.fd = -1

    def __del__(self):
        # Do not close standard file streams
        if self.fd > 3:
            os.close(self.fd)

    def __deepcopy__(self, memo):
        obj = super(W_IOObject, self).__deepcopy__(memo)
        obj.fd = self.fd
        return obj

    @classmethod
    def setup_class(cls, space, w_cls):
        w_stdin = space.send(w_cls, space.newsymbol("new"), [space.newint(0)])
        space.globals.set("$stdin", w_stdin)
        space.set_const(space.w_object, "STDIN", w_stdin)

        w_stdout = space.send(w_cls, space.newsymbol("new"), [space.newint(1)])
        space.globals.set("$stdout", w_stdout)
        space.globals.set("$>", w_stdout)
        space.set_const(space.w_object, "STDOUT", w_stdout)

        w_stderr = space.send(w_cls, space.newsymbol("new"), [space.newint(2)])
        space.globals.set("$stderr", w_stderr)
        space.set_const(space.w_object, "STDERR", w_stderr)

    @classdef.singleton_method("allocate")
    def method_allocate(self, space, args_w):
        return W_IOObject(space)

    @classdef.method("initialize")
    def method_initialize(self,
                          space,
                          w_fd_or_io,
                          w_mode_str_or_int=None,
                          w_opts=None):
        if isinstance(w_fd_or_io, W_IOObject):
            fd = w_fd_or_io.fd
        else:
            fd = space.int_w(w_fd_or_io)
        if isinstance(w_mode_str_or_int, W_StringObject):
            mode = space.str_w(w_mode_str_or_int)
            if ":" in mode:
                raise NotImplementedError("encoding for IO.new")
        elif w_mode_str_or_int is None:
            mode = None
        else:
            raise NotImplementedError("int mode for IO.new")
        if w_opts is not None:
            raise NotImplementedError("options hash for IO.new")
        if mode is None:
            mode = "r"
        self.fd = fd
        return self

    @classdef.method("read")
    def method_read(self, space, w_length=None, w_str=None):
        if w_length:
            length = space.int_w(w_length)
            if length < 0:
                raise space.error(space.w_ArgumentError,
                                  "negative length %d given" % length)
        else:
            length = -1
        read_bytes = 0
        read_chunks = []
        while length < 0 or read_bytes < length:
            if length > 0:
                max_read = int(length - read_bytes)
            else:
                max_read = 8192
            current_read = os.read(self.fd, max_read)
            if len(current_read) == 0:
                break
            read_bytes += len(current_read)
            read_chunks += current_read
        # Return nil on EOF if length is given
        if read_bytes == 0:
            return space.w_nil
        w_read_str = space.newstr_fromchars(read_chunks)
        if w_str is not None:
            w_str.clear(space)
            w_str.extend(space, w_read_str)
            return w_str
        else:
            return w_read_str

    classdef.app_method("""
    def << s
        write(s)
        return self
    end
    """)

    @classdef.method("write")
    def method_write(self, space, w_str):
        string = space.str_w(space.send(w_str, space.newsymbol("to_s")))
        bytes_written = os.write(self.fd, string)
        return space.newint(bytes_written)

    @classdef.method("flush")
    def method_flush(self, space):
        # We have no internal buffers to flush!
        return self

    @classdef.method("print")
    def method_print(self, space, args_w):
        if not args_w:
            w_last = space.globals.get("$_")
            if w_last:
                args_w.append(w_last)
        w_sep = space.globals.get("$,")
        if w_sep:
            sep = space.str_w(w_sep)
        else:
            sep = ""
        w_end = space.globals.get("$\\")
        if w_end:
            end = space.str_w(w_end)
        else:
            end = ""
        strings = [
            space.str_w(space.send(w_arg, space.newsymbol("to_s")))
            for w_arg in args_w
        ]
        os.write(self.fd, sep.join(strings))
        os.write(self.fd, end)
        return space.w_nil

    @classdef.method("puts")
    def method_puts(self, space, args_w):
        for w_arg in args_w:
            string = space.str_w(space.send(w_arg, space.newsymbol("to_s")))
            os.write(self.fd, string)
            if not string.endswith("\n"):
                os.write(self.fd, "\n")
        return space.w_nil