class W_DomainError(W_StandardError): classdef = ClassDef("Math::DomainError", W_StandardError.classdef) method_allocate = new_exception_allocate(classdef)
class W_ProcObject(W_Object): classdef = ClassDef("Proc", W_Object.classdef) _immutable_fields_ = [ "bytecode", "w_self", "lexical_scope", "cells[*]", "block", "parent_interp", "top_parent_interp", "regexp_match_cell", "is_lambda" ] def __init__(self, space, bytecode, w_self, lexical_scope, cells, block, parent_interp, top_parent_interp, regexp_match_cell, is_lambda): W_Object.__init__(self, space) self.bytecode = bytecode self.w_self = w_self self.lexical_scope = lexical_scope self.cells = cells self.block = block self.parent_interp = parent_interp self.top_parent_interp = top_parent_interp self.regexp_match_cell = regexp_match_cell self.is_lambda = is_lambda def copy(self, space, w_self=None, lexical_scope=None, is_lambda=False): return W_ProcObject(space, self.bytecode, w_self or self.w_self, lexical_scope or self.lexical_scope, self.cells, self.block, self.parent_interp, self.top_parent_interp, self.regexp_match_cell, is_lambda or self.is_lambda) @classdef.singleton_method("new") def method_new(self, space, block): if block is None: block = space.getexecutioncontext().gettoprubyframe().block if block is None: raise space.error(space.w_ArgumentError, "tried to create Proc object without a block") return block.copy(space) method_allocate = classdef.undefine_allocator() @classdef.method("yield") @classdef.method("===") @classdef.method("[]") @classdef.method("call") def method_call(self, space, args_w, block): from topaz.interpreter import RaiseReturn, RaiseBreak try: return space.invoke_block(self, args_w, block_arg=block) except RaiseReturn as e: if self.is_lambda: return e.w_value else: raise except RaiseBreak as e: if self.is_lambda: return e.w_value else: raise space.error(space.w_LocalJumpError, "break from proc-closure") @classdef.method("lambda?") def method_lambda(self, space): return space.newbool(self.is_lambda) @classdef.method("arity") def method_arity(self, space): return space.newint( self.bytecode.arity(negative_defaults=self.is_lambda)) @classdef.method("binding") def method_binding(self, space): return space.newbinding_fromblock(self) @classdef.method("source_location") def method_source_location(self, space): return space.newarray([ space.newstr_fromstr(self.bytecode.filepath), space.newint(self.bytecode.lineno) ])
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 def ensure_not_closed(self, space): if self.fd < 0: raise space.error(space.w_IOError, "closed stream") def getfd(self): return self.fd @classdef.setup_class def setup_class(cls, space, w_cls): w_stdin = space.send(w_cls, "new", [space.newint(0)]) space.globals.set(space, "$stdin", w_stdin) space.set_const(space.w_object, "STDIN", w_stdin) w_stdout = space.send(w_cls, "new", [space.newint(1)]) space.globals.set(space, "$stdout", w_stdout) space.globals.set(space, "$>", w_stdout) space.globals.set(space, "$/", space.newstr_fromstr("\n")) space.set_const(space.w_object, "STDOUT", w_stdout) w_stderr = space.send(w_cls, "new", [space.newint(2)]) space.globals.set(space, "$stderr", w_stderr) space.set_const(space.w_object, "STDERR", w_stderr) space.set_const(w_cls, "SEEK_CUR", space.newint(os.SEEK_CUR)) space.set_const(w_cls, "SEEK_END", space.newint(os.SEEK_END)) space.set_const(w_cls, "SEEK_SET", space.newint(os.SEEK_SET)) @classdef.singleton_method("allocate") def method_allocate(self, space, args_w): return W_IOObject(space) @classdef.singleton_method("sysopen") def method_sysopen(self, space, w_path, w_mode_str_or_int=None, w_perm=None): perm = 0666 mode = os.O_RDONLY if w_mode_str_or_int is not None: mode = map_filemode(space, w_mode_str_or_int) if w_perm is not None and w_perm is not space.w_nil: perm = space.int_w(w_perm) path = Coerce.path(space, w_path) try: fd = os.open(path, mode, perm) except OSError as e: raise error_for_oserror(space, e) else: return space.newint(fd) @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 = Coerce.int(space, 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 space.error(space.w_NotImplementedError, "encoding for IO.new") elif w_mode_str_or_int is None: mode = None else: raise space.error(space.w_NotImplementedError, "int mode for IO.new") if w_opts is not None: raise space.error(space.w_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): self.ensure_not_closed(space) 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.method("write") def method_write(self, space, w_str): self.ensure_not_closed(space) string = space.str_w(space.send(w_str, "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! self.ensure_not_closed(space) return self @classdef.method("seek", amount="int", whence="int") def method_seek(self, space, amount, whence=os.SEEK_SET): self.ensure_not_closed(space) os.lseek(self.fd, amount, whence) return space.newint(0) @classdef.method("pos") @classdef.method("tell") def method_pos(self, space): self.ensure_not_closed(space) # TODO: this currently truncates large values, switch this to use a # Bignum in those cases return space.newint(int(os.lseek(self.fd, 0, os.SEEK_CUR))) @classdef.method("rewind") def method_rewind(self, space): self.ensure_not_closed(space) os.lseek(self.fd, 0, os.SEEK_SET) return space.newint(0) @classdef.method("print") def method_print(self, space, args_w): self.ensure_not_closed(space) if not args_w: w_last = space.globals.get(space, "$_") if w_last is not None: args_w.append(w_last) w_sep = space.globals.get(space, "$,") if w_sep: sep = space.str_w(space.send(w_sep, "to_s")) else: sep = "" w_end = space.globals.get(space, "$\\") if w_end: end = space.str_w(space.send(w_end, "to_s")) else: end = "" strings = [space.str_w(space.send(w_arg, "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("getc") def method_getc(self, space): self.ensure_not_closed(space) c = os.read(self.fd, 1) if not c: return space.w_nil return space.newstr_fromstr(c) @classdef.singleton_method("pipe") def method_pipe(self, space, block=None): r, w = os.pipe() pipes_w = [ space.send(self, "new", [space.newint(r)]), space.send(self, "new", [space.newint(w)]) ] if block is not None: try: return space.invoke_block(block, pipes_w) finally: for pipe_w in pipes_w: if not space.is_true(space.send(pipe_w, "closed?")): space.send(pipe_w, "close") else: return space.newarray(pipes_w) @classdef.method("reopen") def method_reopen(self, space, w_arg, w_mode=None): self.ensure_not_closed(space) w_io = space.convert_type(w_arg, space.w_io, "to_io", raise_error=False) if w_io is space.w_nil: from topaz.objects.fileobject import W_FileObject args = [w_arg] if w_mode is None else [w_arg, w_mode] w_io = space.send(space.getclassfor(W_FileObject), "new", args) assert isinstance(w_io, W_IOObject) w_io.ensure_not_closed(space) os.close(self.fd) os.dup2(w_io.getfd(), self.fd) return self @classdef.method("to_io") def method_to_io(self): return self @classdef.method("fileno") @classdef.method("to_i") def method_to_i(self, space): self.ensure_not_closed(space) return space.newint(self.fd) @classdef.method("close") def method_close(self, space): self.ensure_not_closed(space) os.close(self.fd) self.fd = -1 return self @classdef.method("closed?") def method_closedp(self, space): return space.newbool(self.fd == -1) @classdef.method("stat") def method_stat(self, space): from topaz.objects.fileobject import W_FileStatObject try: stat_val = os.fstat(self.fd) except OSError as e: raise error_for_oserror(space, e) stat_obj = W_FileStatObject(space) stat_obj.set_stat(stat_val) return stat_obj @classdef.method("isatty") @classdef.method("tty?") def method_isatty(self, space): self.ensure_not_closed(space) return space.newbool(os.isatty(self.fd))
class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) classdef.include_module(Enumerable) def __init__(self, space, items_w, klass=None): W_Object.__init__(self, space, klass) self.items_w = items_w def __deepcopy__(self, memo): obj = super(W_ArrayObject, self).__deepcopy__(memo) obj.items_w = copy.deepcopy(self.items_w, memo) return obj def listview(self, space): return self.items_w @classdef.singleton_method("allocate") def singleton_method_allocate(self, space, args_w): return W_ArrayObject(space, [], self) @classdef.method("initialize_copy", other_w="array") @classdef.method("replace", other_w="array") @check_frozen() def method_replace(self, space, other_w): del self.items_w[:] self.items_w.extend(other_w) return self @classdef.method("[]") @classdef.method("slice") def method_subscript(self, space, w_idx, w_count=None): start, end, as_range, nil = space.subscript_access(len(self.items_w), w_idx, w_count=w_count) if nil: return space.w_nil elif as_range: assert start >= 0 assert end >= 0 return space.newarray(self.items_w[start:end]) else: return self.items_w[start] @classdef.method("[]=") @check_frozen() def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): w_count = None if w_obj: w_count = w_count_or_obj else: w_obj = w_count_or_obj start, end, as_range, nil = space.subscript_access(len(self.items_w), w_idx, w_count=w_count) if w_count and end < start: raise space.error(space.w_IndexError, "negative length (%d)" % (end - start)) elif start < 0: raise space.error( space.w_IndexError, "index %d too small for array; minimum: %d" % (start - len(self.items_w), -len(self.items_w))) elif start >= len(self.items_w): self.items_w += [space.w_nil] * (start - len(self.items_w) + 1) self.items_w[start] = w_obj elif as_range: assert end >= 0 w_converted = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) if w_converted is space.w_nil: rep_w = [w_obj] else: rep_w = space.listview(w_converted) delta = (end - start) - len(rep_w) if delta < 0: self.items_w += [None] * -delta lim = start + len(rep_w) i = len(self.items_w) - 1 while i >= lim: self.items_w[i] = self.items_w[i + delta] i -= 1 elif delta > 0: del self.items_w[start:start + delta] self.items_w[start:start + len(rep_w)] = rep_w else: self.items_w[start] = w_obj return w_obj @classdef.method("slice!") @check_frozen() def method_slice_i(self, space, w_idx, w_count=None): start, end, as_range, nil = space.subscript_access(len(self.items_w), w_idx, w_count=w_count) if nil: return space.w_nil elif as_range: start = min(max(start, 0), len(self.items_w)) end = min(max(end, 0), len(self.items_w)) delta = (end - start) assert delta >= 0 w_items = self.items_w[start:start + delta] del self.items_w[start:start + delta] return space.newarray(w_items) else: w_item = self.items_w[start] del self.items_w[start] return w_item @classdef.method("size") @classdef.method("length") def method_length(self, space): return space.newint(len(self.items_w)) @classdef.method("empty?") def method_emptyp(self, space): return space.newbool(len(self.items_w) == 0) @classdef.method("+", other="array") def method_add(self, space, other): return space.newarray(self.items_w + other) @classdef.method("<<") @check_frozen() def method_lshift(self, space, w_obj): self.items_w.append(w_obj) return self @classdef.method("concat", other="array") @check_frozen() def method_concat(self, space, other): self.items_w += other return self @classdef.method("push") @check_frozen() def method_push(self, space, args_w): self.items_w.extend(args_w) return self @classdef.method("shift") @check_frozen() def method_shift(self, space, w_n=None): if w_n is None: if self.items_w: return self.items_w.pop(0) else: return space.w_nil n = space.int_w(space.convert_type(w_n, space.w_fixnum, "to_int")) if n < 0: raise space.error(space.w_ArgumentError, "negative array size") items_w = self.items_w[:n] del self.items_w[:n] return space.newarray(items_w) @classdef.method("unshift") @check_frozen() def method_unshift(self, space, args_w): for i in xrange(len(args_w) - 1, -1, -1): w_obj = args_w[i] self.items_w.insert(0, w_obj) return self @classdef.method("join") def method_join(self, space, w_sep=None): if not self.items_w: return space.newstr_fromstr("") if w_sep is None: separator = "" elif space.respond_to(w_sep, space.newsymbol("to_str")): separator = space.str_w( space.send(w_sep, space.newsymbol("to_str"))) else: raise space.error( space.w_TypeError, "can't convert %s into String" % space.getclass(w_sep).name) return space.newstr_fromstr( separator.join([ space.str_w(space.send(w_o, space.newsymbol("to_s"))) for w_o in self.items_w ])) @classdef.singleton_method("try_convert") def method_try_convert(self, space, w_obj): if not space.is_kind_of(w_obj, space.w_array): w_obj = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) return w_obj @classdef.method("pop") @check_frozen() def method_pop(self, space, w_num=None): if w_num is None: if self.items_w: return self.items_w.pop() else: return space.w_nil else: num = space.int_w( space.convert_type(w_num, space.w_fixnum, "to_int")) if num < 0: raise space.error(space.w_ArgumentError, "negative array size") else: pop_size = max(0, len(self.items_w) - num) res_w = self.items_w[pop_size:] del self.items_w[pop_size:] return space.newarray(res_w) @classdef.method("delete_at", idx="int") @check_frozen() def method_delete_at(self, space, idx): if idx < 0: idx += len(self.items_w) if idx < 0 or idx >= len(self.items_w): return space.w_nil else: return self.items_w.pop(idx) @classdef.method("last") def method_last(self, space, w_count=None): if w_count is not None: count = Coerce.int(space, w_count) if count < 0: raise space.error(space.w_ArgumentError, "negative array size") start = len(self.items_w) - count if start < 0: start = 0 return space.newarray(self.items_w[start:]) if len(self.items_w) == 0: return space.w_nil else: return self.items_w[len(self.items_w) - 1] @classdef.method("pack") def method_pack(self, space, w_template): template = Coerce.str(space, w_template) result = RPacker(template, space.listview(self)).operate(space) w_result = space.newstr_fromchars(result) if space.is_true(space.send(w_template, space.newsymbol("tainted?"))): space.send(w_result, space.newsymbol("taint")) return w_result @classdef.method("to_ary") def method_to_ary(self, space): return self @classdef.method("clear") @check_frozen() def method_clear(self, space): del self.items_w[:] return self @classdef.method("sort!") @check_frozen() def method_sort_i(self, space, block): RubySorter(space, self.items_w, sortblock=block).sort() return self @classdef.method("sort_by!") @check_frozen() def method_sort_by_i(self, space, block): if block is None: return space.send(self, space.newsymbol("enum_for"), [space.newsymbol("sort_by!")]) RubySortBy(space, self.items_w, sortblock=block).sort() return self @classdef.method("reverse!") @check_frozen() def method_reverse_i(self, space): self.items_w.reverse() return self @classdef.method("rotate!", n="int") @check_frozen() def method_rotate_i(self, space, n=1): length = len(self.items_w) if length == 0: return self if abs(n) >= length: n %= length if n < 0: n += length if n == 0: return self assert n >= 0 self.items_w.extend(self.items_w[:n]) del self.items_w[:n] return self
class W_CodeObject(W_BaseObject): _immutable_fields_ = [ "code", "consts_w[*]", "max_stackdepth", "cellvars[*]", "freevars[*]", "arg_pos[*]", "defaults[*]", "block_arg_pos", "splat_arg_pos", ] classdef = ClassDef("Code", W_BaseObject.classdef, filepath=__file__) def __init__(self, name, filepath, code, max_stackdepth, consts, args, splat_arg, block_arg, defaults, cellvars, freevars, lineno_table): self.name = name self.filepath = filepath self.code = code self.max_stackdepth = max_stackdepth self.consts_w = consts self.defaults = defaults self.cellvars = cellvars self.freevars = freevars self.lineno_table = lineno_table n_args = len(args) arg_pos = [-1] * n_args for idx, arg in enumerate(args): arg_pos[idx] = cellvars.index(arg) self.arg_pos = arg_pos block_arg_pos = -1 if block_arg is not None: block_arg_pos = cellvars.index(block_arg) self.block_arg_pos = block_arg_pos splat_arg_pos = -1 if splat_arg is not None: splat_arg_pos = cellvars.index(splat_arg) self.splat_arg_pos = splat_arg_pos def __deepcopy__(self, memo): obj = super(W_CodeObject, self).__deepcopy__(memo) obj.name = self.name obj.filepath = self.filepath obj.code = self.code obj.max_stackdepth = self.max_stackdepth obj.consts_w = copy.deepcopy(self.consts_w, memo) obj.defaults = copy.deepcopy(self.defaults, memo) obj.cellvars = self.cellvars obj.freevars = self.freevars obj.lineno_table = self.lineno_table obj.arg_pos = self.arg_pos obj.block_arg_pos = self.block_arg_pos obj.splat_arg_pos = self.splat_arg_pos return obj @classdef.method("filepath") def method_filepath(self, space): return space.newstr_fromstr(self.filepath)
class W_LoadError(W_ScriptError): classdef = ClassDef("LoadError", W_ScriptError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_SymbolObject(W_Object): _immutable_fields_ = ["symbol"] classdef = ClassDef("Symbol", W_Object.classdef) classdef.include_module(Comparable) def __init__(self, space, symbol): W_Object.__init__(self, space) self.symbol = symbol def __deepcopy__(self, memo): obj = super(W_SymbolObject, self).__deepcopy__(memo) obj.symbol = self.symbol return obj def symbol_w(self, space): return self.symbol def str_w(self, space): return self.symbol @classdef.singleton_method("all_symbols") def singleton_method_all_symbols(self, space): return space.newarray(space.symbol_cache.values()) @classdef.method("extend") @classdef.method("singleton_class") def method_singleton_class(self, space): raise space.error(space.w_TypeError, "can't define singleton") @classdef.method("to_s") def method_to_s(self, space): return space.newstr_fromstr(self.symbol) @classdef.method("inspect") def method_inspect(self, space): string_format = (not self.symbol or not self.symbol[0].isalpha() or not self.symbol.isalnum()) if string_format: result = [":", '"'] for c in self.symbol: if c == '"': result.append("\\") result.append(c) result.append('"') return space.newstr_fromchars(result) else: return space.newstr_fromstr(":%s" % self.symbol) @classdef.method("length") @classdef.method("size") def method_size(self, space): return space.newint(len(self.symbol)) @classdef.method("empty?") def method_emptyp(self, space): return space.newbool(not self.symbol) @classdef.method("<=>") def method_comparator(self, space, w_other): if not space.is_kind_of(w_other, space.w_symbol): return space.w_nil s1 = self.symbol s2 = space.symbol_w(w_other) if s1 < s2: return space.newint(-1) elif s1 == s2: return space.newint(0) elif s1 > s2: return space.newint(1) @classdef.method("downcase") def method_downcase(self, space): return space.newsymbol(self.symbol.lower()) @classdef.method("upcase") def method_upcase(self, space): return space.newsymbol(self.symbol.upper())
class W_RandomObject(W_Object): classdef = ClassDef("Random", W_Object.classdef, filepath=__file__) def __init__(self, space, seed=0, klass=None): W_Object.__init__(self, space, klass) self.w_seed = None self.random = Random(abs(seed)) @classdef.setup_class def setup_class(cls, space, w_cls): default = space.send(w_cls, space.newsymbol("new")) space.set_const(w_cls, "DEFAULT", default) @classdef.singleton_method("allocate", seed="int") def method_allocate(self, space, seed=0): return W_RandomObject(space, seed, self) @classdef.method("initialize") def method_initialize(self, space, w_seed=None): self.srand(space, w_seed) @classdef.method("seed") def method_seed(self, space): return self.w_seed def srand(self, space, seed=None): previous_seed = self.w_seed if seed is None: seed = self._generate_seed() else: seed = Coerce.int(space, seed) self.w_seed = space.newint(seed) if previous_seed is None: value = space.newfloat(self.random.random()) else: value = previous_seed self.random = Random(abs(seed)) return value @classdef.method("rand") def method_rand(self, space, w_max=None): if w_max is None: return space.newfloat(self.random.random()) elif space.is_kind_of(w_max, space.w_float): return self._rand_float(space, w_max) elif space.is_kind_of(w_max, space.getclassfor(W_RangeObject)): return self._rand_range(space, w_max) else: return self._rand_int(space, w_max) @classdef.singleton_method("rand") def method_singleton_rand(self, space, args_w): default = space.find_const(self, "DEFAULT") return space.send(default, space.newsymbol("rand"), args_w) def _rand_range(self, space, range): random = self.random.random() first = space.send(range, space.newsymbol("first")) last = space.send(range, space.newsymbol("last")) if space.is_true(space.send(range, space.newsymbol("include?"), [last])): last = space.send(last, space.newsymbol("+"), [space.newint(1)]) diff = space.send(last, space.newsymbol("-"), [first]) offset = space.send(diff, space.newsymbol("*"), [space.newfloat(random)]) choice = space.send(offset, space.newsymbol("+"), [first]) if (not space.is_kind_of(first, space.w_float) and not space.is_kind_of(last, space.w_float)): choice = space.send(choice, space.newsymbol("to_i")) return choice def _rand_float(self, space, float): random = self.random.random() max = Coerce.float(space, float) if max <= 0: raise space.error(space.w_ArgumentError, "invalid argument") return space.newfloat(random * max) def _rand_int(self, space, integer): random = self.random.random() max = Coerce.int(space, integer) if max <= 0: raise space.error(space.w_ArgumentError, "invalid argument") else: return space.newint(int(random * max)) def _generate_seed(self): seed = 0 if os.access('/dev/urandom', os.R_OK): file = os.open('/dev/urandom', os.R_OK, 0644) bytes = os.read(file, 4) os.close(file) for b in bytes: seed = seed * 0xff + ord(b) return seed + int(time.time()) + os.getpid()
class W_HashObject(W_Object): classdef = ClassDef("Hash", W_Object.classdef, filepath=__file__) classdef.include_module(Enumerable) def __init__(self, space, klass=None): W_Object.__init__(self, space, klass) self.contents = OrderedDict(space.eq_w, space.hash_w) self.w_default = space.w_nil self.default_proc = None @classdef.singleton_method("allocate") def method_allocate(self, space, args_w): return W_HashObject(space, self) @classdef.singleton_method("try_convert") def method_try_convert(self, space, w_obj): if not space.is_kind_of(w_obj, space.w_hash): w_obj = space.convert_type(w_obj, space.w_hash, "to_hash", raise_error=False) return w_obj @classdef.method("initialize") def method_initialize(self, space, w_default=None, block=None): if w_default is not None: self.w_default = w_default if block is not None: self.default_proc = block @classdef.method("default") def method_default(self, space, w_key=None): if self.default_proc is not None and w_key is not None: return space.invoke_block(self.default_proc, [self, w_key]) else: return self.w_default @classdef.method("default=") @check_frozen() def method_set_default(self, space, w_defl): self.default_proc = None self.w_default = w_defl @classdef.method("default_proc") def method_default_proc(self, space): if self.default_proc is None: return space.w_nil return space.newproc(self.default_proc) @classdef.method("[]") def method_subscript(self, space, w_key): try: return self.contents[w_key] except KeyError: return space.send(self, space.newsymbol("default"), [w_key]) @classdef.method("fetch") def method_fetch(self, space, w_key, w_value=None, block=None): try: return self.contents[w_key] except KeyError: if w_value is not None: return w_value elif block is not None: return space.invoke_block(block, [w_key]) else: raise space.error( space.w_KeyError, "key not found: %s" % space.send(w_key, space.newsymbol("inspect"))) @classdef.method("store") @classdef.method("[]=") @check_frozen() def method_subscript_assign(self, space, w_key, w_value): if (space.is_kind_of(w_key, space.w_string) and not space.is_true( space.send(w_key, space.newsymbol("frozen?")))): w_key = space.send(w_key, space.newsymbol("dup")) w_key = space.send(w_key, space.newsymbol("freeze")) self.contents[w_key] = w_value return w_value @classdef.method("length") @classdef.method("size") def method_size(self, space): return space.newint(len(self.contents)) @classdef.method("empty?") def method_emptyp(self, space): return space.newbool(not bool(self.contents)) @classdef.method("delete") @check_frozen() def method_delete(self, space, w_key, block): w_res = self.contents.pop(w_key, None) if w_res is None: if block: return space.invoke_block(block, [w_key]) w_res = space.w_nil return w_res @classdef.method("clear") @check_frozen() def method_clear(self, space): self.contents.clear() return self @classdef.method("shift") @check_frozen() def method_shift(self, space): if not self.contents: return space.send(self, space.newsymbol("default"), [space.w_nil]) w_key, w_value = self.contents.popitem() return space.newarray([w_key, w_value]) @classdef.method("initialize_copy") @classdef.method("replace") @check_frozen() def method_replace(self, space, w_hash): assert isinstance(w_hash, W_HashObject) self.contents.clear() self.contents.update(w_hash.contents) return self @classdef.method("keys") def method_keys(self, space): return space.newarray(self.contents.keys()) @classdef.method("values") def method_values(self, space): return space.newarray(self.contents.values()) @classdef.method("to_hash") def method_to_hash(self, space): return self @classdef.method("key?") @classdef.method("has_key?") @classdef.method("member?") @classdef.method("include?") def method_includep(self, space, w_key): return space.newbool(w_key in self.contents)
class W_RootObject(W_BaseObject): _attrs_ = [] classdef = ClassDef("Object", W_BaseObject.classdef, filepath=__file__) @classdef.setup_class def setup_class(cls, space, w_cls): space.w_top_self = W_Object(space, w_cls) @classdef.method("object_id") def method_object_id(self, space): return space.send(self, space.newsymbol("__id__")) @classdef.method("singleton_class") def method_singleton_class(self, space): return space.getsingletonclass(self) @classdef.method("extend") def method_extend(self, space, w_mod): if not space.is_kind_of(w_mod, space.w_module) or space.is_kind_of( w_mod, space.w_class): if space.is_kind_of(w_mod, space.w_class): name = "Class" else: name = space.obj_to_s(space.getclass(w_mod)) raise space.error( space.w_TypeError, "wrong argument type %s (expected Module)" % name) self.getsingletonclass(space).extend_object(space, self, w_mod) @classdef.method("inspect") def method_inspect(self, space): return space.send(self, space.newsymbol("to_s")) @classdef.method("to_s") def method_to_s(self, space): return space.newstr_fromstr(space.any_to_s(self)) @classdef.method("===") def method_eqeqeq(self, space, w_other): if self is w_other: return space.w_true return space.send(self, space.newsymbol("=="), [w_other]) @classdef.method("send") def method_send(self, space, args_w, block): return space.send(self, space.newsymbol("__send__"), args_w, block) @classdef.method("nil?") def method_nilp(self, space): return space.w_false @classdef.method("hash") def method_hash(self, space): return space.newint(compute_identity_hash(self)) @classdef.method("instance_variable_get", name="str") def method_instance_variable_get(self, space, name): return space.find_instance_var(self, name) @classdef.method("instance_variable_set", name="str") def method_instance_variable_set(self, space, name, w_value): space.set_instance_var(self, name, w_value) return w_value @classdef.method("method") def method_method(self, space, w_sym): return space.send( space.send(space.getclass(self), space.newsymbol("instance_method"), [w_sym]), space.newsymbol("bind"), [self]) @classdef.method("tap") def method_tap(self, space, block): if block is not None: space.invoke_block(block, [self]) else: raise space.error(space.w_LocalJumpError, "no block given") return self
class W_BaseObject(W_Root): _attrs_ = [] classdef = ClassDef("BasicObject", filepath=__file__) 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 def find_const(self, space, name): raise space.error( space.w_TypeError, "%s is not a class/module" % space.str_w(space.send(self, space.newsymbol("inspect")))) find_included_const = find_local_const = find_const @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, args_w): name = space.symbol_w(w_name) class_name = space.str_w( space.send(self.getclass(space), space.newsymbol("to_s"))) 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, 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, StaticScope(space.getclass(self), None), filename, lineno) else: return space.invoke_block(block.copy(w_self=self), [])
class W_EncodingObject(W_Object): classdef = ClassDef("Encoding", W_Object.classdef, filepath=__file__)
class W_ProcObject(W_Object): classdef = ClassDef("Proc", W_Object.classdef) def __init__(self, space, bytecode, w_self, lexical_scope, cells, block, parent_interp, regexp_match_cell, is_lambda): W_Object.__init__(self, space) self.bytecode = bytecode self.w_self = w_self self.lexical_scope = lexical_scope self.cells = cells self.block = block self.parent_interp = parent_interp self.regexp_match_cell = regexp_match_cell self.is_lambda = is_lambda def copy(self, space, w_self=None, lexical_scope=None, is_lambda=False): return W_ProcObject(space, self.bytecode, w_self or self.w_self, lexical_scope or self.lexical_scope, self.cells, self.block, self.parent_interp, self.regexp_match_cell, is_lambda or self.is_lambda) @classdef.singleton_method("new") def method_new(self, space, block): if block is None: raise space.error(space.w_ArgumentError, "tried to create Proc object without a block") return block.copy(space) method_allocate = classdef.undefine_allocator() @classdef.method("yield") @classdef.method("===") @classdef.method("[]") @classdef.method("call") def method_call(self, space, args_w, block): from topaz.interpreter import RaiseReturn, RaiseBreak try: return space.invoke_block(self, args_w, block_arg=block) except RaiseReturn as e: if self.is_lambda: return e.w_value else: raise except RaiseBreak as e: if self.is_lambda: return e.w_value else: raise space.error(space.w_LocalJumpError, "break from proc-closure") @classdef.method("lambda?") def method_lambda(self, space): return space.newbool(self.is_lambda) @classdef.method("arity") def method_arity(self, space): return space.newint(self.bytecode.arity()) @classdef.method("binding") def method_binding(self, space): return space.newbinding_fromblock(self)
class W_FixnumObject(W_RootObject): _immutable_fields_ = ["intvalue"] classdef = ClassDef("Fixnum", W_IntegerObject.classdef) def __init__(self, space, intvalue): check_regular_int(intvalue) self.intvalue = intvalue def __deepcopy__(self, memo): obj = super(W_FixnumObject, self).__deepcopy__(memo) obj.intvalue = self.intvalue return obj def int_w(self, space): return self.intvalue def bigint_w(self, space): return rbigint.fromint(self.intvalue) def float_w(self, space): return float(self.intvalue) def intmask_w(self, space): return self.intvalue def uintmask_w(self, space): return r_uint(self.intvalue) def longlongmask_w(self, space): return r_longlong(self.intvalue) def ulonglongmask_w(self, space): return r_ulonglong(self.intvalue) def find_instance_var(self, space, name): storage = space.fromcache(FixnumStorage).get_or_create( space, self.intvalue) return storage.find_instance_var(space, name) def set_instance_var(self, space, name, w_value): storage = space.fromcache(FixnumStorage).get_or_create( space, self.intvalue) storage.set_instance_var(space, name, w_value) def set_flag(self, space, name): storage = space.fromcache(FixnumStorage).get_or_create( space, self.intvalue) storage.set_flag(space, name) def unset_flag(self, space, name): storage = space.fromcache(FixnumStorage).get_or_create( space, self.intvalue) storage.unset_flag(space, name) def get_flag(self, space, name): storage = space.fromcache(FixnumStorage).get_or_create( space, self.intvalue) return storage.get_flag(space, name) @classdef.method("extend") @classdef.method("singleton_class") def method_singleton_class(self, space): raise space.error(space.w_TypeError, "can't define singleton") @classdef.method("inspect") @classdef.method("to_s") def method_to_s(self, space): return space.newstr_fromstr(str(self.intvalue)) @classdef.method("to_f") def method_to_f(self, space): return space.newfloat(float(self.intvalue)) @classdef.method("to_i") @classdef.method("to_int") def method_to_i(self, space): return self def new_binop(classdef, name, func): @classdef.method(name) def method(self, space, w_other): if space.is_kind_of(w_other, space.w_fixnum): other = space.int_w(w_other) try: value = ovfcheck(func(self.intvalue, other)) except OverflowError: return space.send(space.newbigint_fromint(self.intvalue), name, [w_other]) else: return space.newint(value) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), name, [w_other]) elif space.is_kind_of(w_other, space.w_float): return space.newfloat( func(self.intvalue, space.float_w(w_other))) else: return W_NumericObject.retry_binop_coercing( space, self, w_other, name) method.__name__ = "method_%s" % func.__name__ return method method_add = new_binop(classdef, "+", operator.add) method_sub = new_binop(classdef, "-", operator.sub) method_mul = new_binop(classdef, "*", operator.mul) def raise_zero_division_error(self, space): raise space.error(space.w_ZeroDivisionError, "divided by 0") def divide(self, space, w_other): if space.is_kind_of(w_other, space.w_fixnum): other = space.int_w(w_other) try: return space.newint(self.intvalue / other) except ZeroDivisionError: self.raise_zero_division_error(space) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), "/", [w_other]) elif space.is_kind_of(w_other, space.w_float): return space.send(space.newfloat(space.float_w(self)), "/", [w_other]) else: return W_NumericObject.retry_binop_coercing( space, self, w_other, "/") @classdef.method("/") def method_divide(self, space, w_other): return self.divide(space, w_other) @classdef.method("div") def method_div(self, space, w_other): if space.is_kind_of(w_other, space.w_float): if space.float_w(w_other) == 0.0: self.raise_zero_division_error(space) else: w_float = space.send(space.newfloat(space.float_w(self)), "/", [w_other]) w_float = space.newfloat( math.floor(Coerce.float(space, w_float))) return space.send(w_float, "to_i") else: return self.divide(space, w_other) @classdef.method("fdiv") def method_fdiv(self, space, w_other): if space.is_kind_of(w_other, space.w_fixnum): other = space.int_w(w_other) try: res = float(self.intvalue) / float(other) except ZeroDivisionError: return space.newfloat( rfloat.copysign(rfloat.INFINITY, float(self.intvalue))) else: return space.newfloat(res) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), "fdiv", [w_other]) elif space.is_kind_of(w_other, space.w_float): other = space.float_w(w_other) try: res = float(self.intvalue) / other except ZeroDivisionError: return space.newfloat( rfloat.copysign(rfloat.INFINITY, float(self.intvalue))) else: return space.newfloat(res) else: return W_NumericObject.retry_binop_coercing( space, self, w_other, "fdiv") @classdef.method("**") def method_pow(self, space, w_other): if space.is_kind_of(w_other, space.w_fixnum): return self.method_pow_int_impl(space, w_other) elif space.getclass(w_other) is space.w_float: return space.send(space.newfloat(float(self.intvalue)), "**", [w_other]) elif space.getclass(w_other) is space.w_bignum: return space.send(space.newbigint_fromint(self.intvalue), "**", [w_other]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Fixnum" % space.obj_to_s(space.getclass(w_other))) def method_pow_int_impl(self, space, w_other): exp = space.int_w(w_other) temp = self.intvalue if exp > 0: ix = 1 try: while exp > 0: if exp & 1: ix = ovfcheck(ix * temp) exp >>= 1 if exp == 0: break temp = ovfcheck(temp * temp) except OverflowError: return space.send(space.newbigint_fromint(self.intvalue), "**", [w_other]) return space.newint(ix) else: return space.send(space.newfloat(float(temp)), "**", [w_other]) @classdef.method("divmod") def method_divmod(self, space, w_other): if space.is_kind_of(w_other, space.w_float): return space.send(self.method_to_f(space), "divmod", [w_other]) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), "divmod", [w_other]) elif space.is_kind_of(w_other, space.w_fixnum): y = space.int_w(w_other) if y == 0: raise space.error(space.w_ZeroDivisionError, "divided by 0") mod = space.int_w(self.method_mod_int_impl(space, y)) div = (self.intvalue - mod) / y return space.newarray( [space.newint(int(round_away(div))), space.newfloat(mod)]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Fixnum" % (space.obj_to_s(space.getclass(w_other)))) @classdef.method("%") @classdef.method("modulo") def method_mod(self, space, w_other): if space.is_kind_of(w_other, space.w_fixnum): return self.method_mod_int_impl(space, space.int_w(w_other)) elif space.is_kind_of(w_other, space.w_float): return space.send(self.method_to_f(space), "%", [w_other]) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), "%", [w_other]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Fixnum" % (space.obj_to_s(space.getclass(w_other)))) def method_mod_int_impl(self, space, other): if other == 0: raise space.error(space.w_ZeroDivisionError, "divided by 0") return space.newint(self.intvalue % other) @classdef.method("<<", other="int") def method_left_shift(self, space, other): if other < 0: return space.newint(self.intvalue >> -other) elif other >= LONG_BIT: return space.send(space.newbigint_fromint(self.intvalue), "<<", [space.newint(other)]) else: try: value = ovfcheck(self.intvalue << other) except OverflowError: return space.send(space.newbigint_fromint(self.intvalue), "<<", [space.newint(other)]) else: return space.newint(value) @classdef.method(">>", other="int") def method_right_shift(self, space, other): if other < 0: return space.newint(self.intvalue << -other) else: return space.newint(self.intvalue >> other) def new_bitwise_op(classdef, name, func): @classdef.method(name) def method(self, space, w_other): w_other = space.convert_type(w_other, space.w_integer, "to_int") if space.is_kind_of(w_other, space.w_fixnum): other = space.int_w(w_other) return space.newint(func(self.intvalue, other)) elif space.is_kind_of(w_other, space.w_bignum): return space.send(space.newbigint_fromint(self.intvalue), name, [w_other]) else: return W_NumericObject.retry_binop_coercing( space, self, w_other, name) method.__name__ = "method_%s" % func.__name__ return method method_and = new_bitwise_op(classdef, "&", operator.and_) method_or = new_bitwise_op(classdef, "|", operator.or_) method_xor = new_bitwise_op(classdef, "^", operator.xor) @classdef.method("~") def method_invert(self, space): return space.newint(~self.intvalue) @classdef.method("==") @classdef.method("equal?") def method_eq(self, space, w_other): if isinstance(w_other, W_FixnumObject): return space.newbool( self.comparator(space, space.int_w(w_other)) == 0) elif isinstance(w_other, W_FloatObject): return space.newbool( self.comparator(space, space.float_w(w_other)) == 0) else: return space.send(w_other, "==", [self]) @classdef.method("!=") def method_ne(self, space, w_other): return space.newbool( space.send(self, "==", [w_other]) is space.w_false) def new_bool_op(classdef, name, func): @classdef.method(name) def method(self, space, w_other): if space.is_kind_of(w_other, space.w_float): return space.newbool( func(self.intvalue, space.float_w(w_other))) elif space.is_kind_of(w_other, space.w_fixnum): return space.newbool(func(self.intvalue, space.int_w(w_other))) else: return W_NumericObject.retry_binop_coercing(space, self, w_other, name, raise_error=True) method.__name__ = "method_%s" % func.__name__ return method method_lt = new_bool_op(classdef, "<", operator.lt) method_lte = new_bool_op(classdef, "<=", operator.le) method_gt = new_bool_op(classdef, ">", operator.gt) method_gte = new_bool_op(classdef, ">=", operator.ge) @classdef.method("<=>") def method_comparator(self, space, w_other): if isinstance(w_other, W_FixnumObject): return space.newint(self.comparator(space, space.int_w(w_other))) elif isinstance(w_other, W_FloatObject): return space.newint(self.comparator(space, space.float_w(w_other))) else: return space.w_nil @specialize.argtype(2) def comparator(self, space, other): if self.intvalue < other: return -1 elif self.intvalue == other: return 0 elif self.intvalue > other: return 1 return 1 @classdef.method("hash") def method_hash(self, space): return self if IS_WINDOWS: @classdef.method("size") def method_size(self, space): # RPython translation is always 32bit on Windows return space.newint(4) else: @classdef.method("size") def method_size(self, space): return space.newint(rffi.sizeof(lltype.typeOf(self.intvalue))) @classdef.method("coerce") def method_coerce(self, space, w_other): if space.getclass(w_other) is space.getclass(self): return space.newarray([w_other, self]) else: return space.newarray([space.send(self, "Float", [w_other]), self]) @classdef.method("chr") def method_chr(self, space): if self.intvalue > 255 or self.intvalue < 0: raise space.error(space.w_RangeError, "%d out of char range" % self.intvalue) else: return space.newstr_fromstr(chr(self.intvalue)) @classdef.method("[]", idx="int") def method_subscript(self, space, idx): if not 0 <= idx < LONG_BIT: return space.newint(0) return space.newint(int(bool(self.intvalue & (1 << idx))))
class W_EOFError(W_IOError): classdef = ClassDef("EOFError", W_IOError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_BignumObject(W_IntegerObject): classdef = ClassDef("Bignum", W_IntegerObject.classdef, filepath=__file__) def __init__(self, space, bigint): W_IntegerObject.__init__(self, space) self.bigint = bigint @staticmethod def newbigint_fromint(space, intvalue): return W_BignumObject(space, rbigint.fromint(intvalue)) @staticmethod def newbigint_fromfloat(space, floatvalue): return W_BignumObject(space, rbigint.fromfloat(floatvalue)) @staticmethod def newbigint_fromrbigint(space, bigint): return W_BignumObject(space, bigint) def int_w(self, space): return self.bigint.toint() def bigint_w(self, space): return self.bigint def float_w(self, space): return self.bigint.tofloat() @classdef.method("to_s") def method_to_s(self, space): return space.newstr_fromstr(self.bigint.str()) @classdef.method("to_f") def method_to_f(self, space): return space.newfloat(self.bigint.tofloat()) @classdef.method("+", other="bigint") def method_plus(self, space, other): return space.newbigint_fromrbigint(self.bigint.add(other)) @classdef.method("-", other="bigint") def method_sub(self, space, other): return space.newbigint_fromrbigint(self.bigint.sub(other)) @classdef.method("*", other="bigint") def method_times(self, space, other): return space.newbigint_fromrbigint(self.bigint.mul(other)) def floordiv(self, space, other): try: result = self.bigint.div(other) except ZeroDivisionError: raise space.error(space.w_ZeroDivisionError, "divided by 0") try: return space.newint(result.toint()) except OverflowError: return space.newbigint_fromrbigint(result) @classdef.method("/") def method_divide(self, space, w_other): if space.is_kind_of(w_other, space.w_fixnum): return self.floordiv(space, rbigint.fromint(space.int_w(w_other))) elif space.is_kind_of(w_other, space.w_bignum): return self.floordiv(space, space.bigint_w(w_other)) elif space.is_kind_of(w_other, space.w_float): return space.send(space.newfloat(space.float_w(self)), space.newsymbol("/"), [w_other]) else: return W_NumericObject.retry_binop_coercing( space, self, w_other, "/") @classdef.method("<<", other="int") def method_left_shift(self, space, other): return space.newbigint_fromrbigint(self.bigint.lshift(other)) @classdef.method("&", other="bigint") def method_and(self, space, other): return space.newbigint_fromrbigint(self.bigint.and_(other)) @classdef.method("|", other="bigint") def method_or(self, space, other): return space.newbigint_fromrbigint(self.bigint.or_(other)) @classdef.method("^", other="bigint") def method_xor(self, space, other): return space.newbigint_fromrbigint(self.bigint.xor(other)) @classdef.method("==", other="bigint") def method_eq(self, space, other): return space.newbool(self.bigint.eq(other)) @classdef.method("<=>", other="bigint") def method_comparator(self, space, other): if self.bigint.gt(other): return space.newint(1) elif self.bigint.eq(other): return space.newint(0) elif self.bigint.lt(other): return space.newint(-1) @classdef.method("hash") def method_hash(self, space): return space.newint(self.bigint.hash()) @classdef.method("coerce") def method_coerce(self, space, w_other): if isinstance(w_other, W_BignumObject): return space.newarray([w_other, self]) elif space.getclass(w_other) is space.w_fixnum: return space.newarray([ space.newbigint_fromint(space.int_w(w_other)), self, ]) else: raise space.error( space.w_TypeError, "can't coerce %s to Bignum" % space.obj_to_s(space.getclass(w_other))) @classdef.method("**") def method_pow(self, space, w_other): if space.getclass(w_other) is space.w_fixnum or space.getclass( w_other) is space.w_bignum: exp = space.bigint_w(w_other) negative_exponent = False if exp.sign < 0: negative_exponent = True exp = exp.abs() result = self.bigint.pow(exp, None) if negative_exponent: return space.newfloat(1.0 / result.tofloat()) else: return space.newbigint_fromrbigint(result) elif space.getclass(w_other) is space.w_float: try: float_value = space.float_w(self) except OverflowError: return space.newfloat(INFINITY) return space.send(space.newfloat(float_value), space.newsymbol("**"), [w_other]) else: raise space.error( space.w_TypeError, "%s can't be coerced into Bignum" % space.obj_to_s(space.getclass(w_other)))
class W_FiberError(W_StandardError): classdef = ClassDef("FiberError", W_StandardError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_TypeError(W_ExceptionObject): classdef = ClassDef("TypeError", W_StandardError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_SystemStackError(W_ExceptionObject): classdef = ClassDef("SystemStackError", W_ExceptionObject.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_NoMethodError(W_NameError): classdef = ClassDef("NoMethodError", W_NameError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_StringObject(W_Object): classdef = ClassDef("String", W_Object.classdef) classdef.include_module(Comparable) def __init__(self, space, storage, strategy, klass=None): W_Object.__init__(self, space, klass) 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 @jit.look_inside_iff(lambda space, strs_w: jit.isconstant(len(strs_w))) def newstr_fromstrs(space, strs_w): total_length = 0 for w_item in strs_w: assert isinstance(w_item, W_StringObject) total_length += w_item.length() storage = newlist_hint(total_length) for w_item in strs_w: assert isinstance(w_item, W_StringObject) w_item.strategy.extend_into(w_item.str_storage, storage) return space.newstr_fromchars(storage) @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 symbol_w(self, space): return self.str_w(space) 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 W_StringObject(space, self.strategy.copy(self.str_storage), self.strategy) 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.singleton_method("allocate") def singleton_method_allocate(self, space, w_s=None): strategy = space.fromcache(ConstantStringStrategy) storage = strategy.erase("") return W_StringObject(space, storage, strategy, self) @classdef.singleton_method("try_convert") def method_try_convert(self, space, w_obj): if not space.is_kind_of(w_obj, space.w_string): w_obj = space.convert_type(w_obj, space.w_string, "to_str", raise_error=False) return w_obj @classdef.method("initialize") def method_initialize(self, space, w_s=None): if w_s is not None: w_s = space.convert_type(w_s, space.w_string, "to_str") assert isinstance(w_s, W_StringObject) self.strategy = w_s.strategy self.str_storage = w_s.strategy.copy(w_s.str_storage) @classdef.method("initialize_copy") def method_initialize_copy(self, space, w_other): assert isinstance(w_other, W_StringObject) self.strategy = w_other.strategy self.str_storage = w_other.strategy.copy(w_other.str_storage) return self @classdef.method("to_str") @classdef.method("to_s") def method_to_s(self, space): return self @classdef.method("ord") def method_ord(self, space): if self.length() == 0: raise space.error(space.w_ArgumentError, "empty string") return space.newint(ord(self.strategy.getitem(self.str_storage, 0))) @classdef.method("inspect") def method_inspect(self, space): return space.newstr_fromstr('"%s"' % self.str_w(space)) @classdef.method("+") def method_plus(self, space, w_obj): if space.is_kind_of(w_obj, space.w_string): w_other = w_obj else: w_other = space.convert_type(w_obj, space.w_string, "to_str") 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("*", times="int") def method_times(self, space, times): if times < 0: raise space.error(space.w_ArgumentError, "negative argument") return self.strategy.mul(space, self.str_storage, times) @classdef.method("<<") @classdef.method("concat") @check_frozen() 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("[]") @classdef.method("slice") 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, "to_str") and space.respond_to( w_other, "<=>"): tmp = space.send(w_other, "<=>", [self]) if tmp is not space.w_nil: return space.newint(-space.int_w(tmp)) return space.w_nil @classdef.method("to_sym") @classdef.method("intern") def method_to_sym(self, space): return space.newsymbol(space.str_w(self)) @classdef.method("clear") @check_frozen() 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) def search_context(self, space, ctx): try: return rsre_core.search_context(ctx) except rsre_core.Error, e: raise space.error(space.w_RuntimeError, e.msg)
class W_NotImplementedError(W_ScriptError): classdef = ClassDef("NotImplementedError", W_ScriptError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_NumericObject(W_Object): classdef = ClassDef("Numeric", W_Object.classdef) classdef.include_module(Comparable) @staticmethod def retry_binop_coercing(space, w_recv, w_arg, binop, raise_error=True): w_ary = None try: w_ary = space.send(w_recv, "coerce", [w_arg]) except RubyError as e: if not space.is_kind_of(e.w_value, space.w_StandardError): raise if raise_error: raise space.error( space.w_ArgumentError, "comparison of %s with %s failed" % (space.obj_to_s(space.getclass(w_recv)), space.obj_to_s(space.getclass(w_arg)))) if space.getclass(w_ary) is space.w_array: ary = space.listview(w_ary) if len(ary) == 2: return space.send(ary[1], binop, ary[:1]) elif raise_error: raise space.error(space.w_TypeError, "coerce must return [x, y]") else: return None @classdef.singleton_method("allocate") def method_allocate(self, space, args_w): return W_NumericObject(space, self) @classdef.method("<=>") def method_comparator(self, space, w_other): if self == w_other: return space.newint(0) else: return space.w_nil @classdef.method("<=") def method_lte(self, space, w_other): w_result = space.send(self, "<=>", [w_other]) return space.newbool(not ( w_result is space.w_nil or space.int_w(w_result) > 0)) @classdef.method("coerce") def method_coerce(self, space, w_other): if space.getclass(w_other) is space.getclass(self): return space.newarray([w_other, self]) else: return space.newarray([space.send(self, "Float", [w_other]), self]) @classdef.method("ceil") def method_ceil(self, space): return space.newint(int(math.ceil(Coerce.float(space, self)))) @classdef.method("floor") def method_floor(self, space): return space.newint(int(math.floor(Coerce.float(space, self)))) @classdef.method("round") def method_round(self, space): return space.newint(int(round_away(Coerce.float(space, self))))
class W_FloatDomainError(W_RangeError): classdef = ClassDef("FloatDomainError", W_RangeError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_FiberObject(W_Object): """ Fibers have a number of possible states: * Has not yet begun execution: self.sthread is None * Currently execution: self.sthread is not None and self is State.get_current() * Suspended execution: self.sthread is not None and self.parent_fiber is None * Suspended execution in the stack of fibers: self.sthread is not None and (self.parent_fiber is None or self is space.w_main_fiber) * Dead: self.sthread is not None and self.sthread.is_empty_handle(self.h) """ classdef = ClassDef("Fiber", W_Object.classdef) def __init__(self, space, klass=None): W_Object.__init__(self, space, klass) self.w_block = None self.sthread = None self.parent_fiber = None def __deepcopy__(self, memo): obj = super(W_FiberObject, self).__deepcopy__(memo) obj.w_block = copy.deepcopy(self.w_block, memo) obj.sthread = copy.deepcopy(self.sthread, memo) obj.parent_fiber = copy.deepcopy(self.parent_fiber, memo) return obj @staticmethod def build_main_fiber(space, ec): w_fiber = W_FiberObject(space) w_fiber.sthread = W_FiberObject.get_sthread(space, ec) return w_fiber @staticmethod def get_sthread(space, ec): sthread = ec.fiber_thread if not sthread: sthread = ec.fiber_thread = SThread(space.config, ec) return sthread @classdef.singleton_method("allocate") def singleton_method_allocate(self, space): return W_FiberObject(space, self) @classdef.singleton_method("yield") def singleton_method_yield(self, space, args_w): current = space.fromcache(State).get_current(space) parent_fiber = current.parent_fiber if parent_fiber is None: raise space.error(space.w_FiberError, "can't yield from root fiber") space.fromcache(State).current = parent_fiber topframeref = space.getexecutioncontext().topframeref current.bottomframe.backref = jit.vref_None if len(args_w) == 0: global_state.w_result = space.w_nil elif len(args_w) == 1: global_state.w_result = args_w[0] else: global_state.w_result = space.newarray(args_w) parent_fiber.h = space.getexecutioncontext().fiber_thread.switch( parent_fiber.h) assert space.fromcache(State).current is current current.bottomframe.backref = space.getexecutioncontext().topframeref space.getexecutioncontext().topframeref = topframeref return get_result() @classdef.method("initialize") @jit.unroll_safe def method_initialize(self, space, block): if block is None: raise space.error(space.w_ArgumentError) self.w_block = block self.bottomframe = space.create_frame( self.w_block.bytecode, w_self=self.w_block.w_self, lexical_scope=self.w_block.lexical_scope, block=self.w_block.block, parent_interp=self.w_block.parent_interp, regexp_match_cell=self.w_block.regexp_match_cell, ) for idx, cell in enumerate(self.w_block.cells): self.bottomframe.cells[len(self.w_block.bytecode.cellvars) + idx] = cell @classdef.method("resume") def method_resume(self, space, args_w): if self.parent_fiber is not None: raise space.error(space.w_FiberError, "double resume") if self.sthread is not None and self.sthread.is_empty_handle(self.h): raise space.error(space.w_FiberError, "dead fiber called") self.parent_fiber = space.fromcache(State).get_current(space) try: global_state.space = space global_state.space.fromcache(State).current = self topframeref = space.getexecutioncontext().topframeref if self.sthread is None: self.bottomframe.handle_block_args(space, self.w_block.bytecode, args_w, self.w_block) sthread = self.get_sthread(space, space.getexecutioncontext()) self.sthread = sthread self.h = sthread.new(new_stacklet_callback) else: if len(args_w) == 1: global_state.w_result = args_w[0] else: global_state.w_result = space.newarray(args_w) self.h = self.sthread.switch(self.h) assert space.fromcache(State).current is self.parent_fiber space.getexecutioncontext().topframeref = topframeref return get_result() finally: self.parent_fiber = None
class W_KeyError(W_IndexError): classdef = ClassDef("KeyError", W_IndexError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_ModuleObject(W_RootObject): _immutable_fields_ = [ "version?", "included_modules?[*]", "klass?", "name?" ] classdef = ClassDef("Module", W_RootObject.classdef, filepath=__file__) def __init__(self, space, name): self.name = name self.klass = None self.version = VersionTag() self.methods_w = {} self.constants_w = {} self.class_variables = CellDict() self.instance_variables = CellDict() self.flags = CellDict() self.included_modules = [] self.descendants = [] def __deepcopy__(self, memo): obj = super(W_ModuleObject, self).__deepcopy__(memo) obj.name = self.name obj.klass = copy.deepcopy(self.klass, memo) obj.version = copy.deepcopy(self.version, memo) obj.methods_w = copy.deepcopy(self.methods_w, memo) obj.constants_w = copy.deepcopy(self.constants_w, memo) obj.class_variables = copy.deepcopy(self.class_variables, memo) obj.instance_variables = copy.deepcopy(self.instance_variables, memo) obj.included_modules = copy.deepcopy(self.included_modules, memo) obj.descendants = copy.deepcopy(self.descendants, memo) return obj def getclass(self, space): if self.klass is not None: return jit.promote(self).klass return W_RootObject.getclass(self, space) def getsingletonclass(self, space): if self.klass is None: self.klass = space.newclass("#<Class:%s>" % self.name, space.w_module, is_singleton=True) return self.klass def mutated(self): self.version = VersionTag() def define_method(self, space, name, method): self.mutated() self.methods_w[name] = method @jit.unroll_safe def find_method(self, space, name): method = self._find_method_pure(space, name, self.version) if method is None: for module in self.included_modules: method = module.find_method(space, name) if method is not None: return method return method @jit.unroll_safe def find_method_super(self, space, name): for module in self.included_modules: method = module.find_method(space, name) if method is not None: return method return None @jit.elidable def _find_method_pure(self, space, method, version): return self.methods_w.get(method, None) def set_const(self, space, name, w_obj): self.mutated() self.constants_w[name] = w_obj def find_const(self, space, name): w_res = self.find_included_const(space, name) if w_res is None: return space.w_object.find_const(space, name) else: return w_res @jit.unroll_safe def find_included_const(self, space, name): w_res = self.find_local_const(space, name) if w_res is None: for w_mod in self.included_modules: w_res = w_mod.find_local_const(space, name) if w_res is not None: break return w_res def find_local_const(self, space, name): return self._find_const_pure(name, self.version) @jit.elidable def _find_const_pure(self, name, version): return self.constants_w.get(name, None) @jit.unroll_safe def set_class_var(self, space, name, w_obj): ancestors = self.ancestors() for idx in xrange(len(ancestors) - 1, -1, -1): module = ancestors[idx] assert isinstance(module, W_ModuleObject) w_res = module.class_variables.get(space, name) if w_res is not None or module is self: module.class_variables.set(space, name, w_obj) if module is self: for descendant in self.descendants: descendant.remove_class_var(space, name) @jit.unroll_safe def find_class_var(self, space, name): w_res = self.class_variables.get(space, name) if w_res is None: ancestors = self.ancestors() for idx in xrange(1, len(ancestors)): module = ancestors[idx] assert isinstance(module, W_ModuleObject) w_res = module.class_variables.get(space, name) if w_res is not None: break return w_res @jit.unroll_safe def remove_class_var(self, space, name): self.class_variables.delete(name) for descendant in self.descendants: descendant.remove_class_var(space, name) def set_instance_var(self, space, name, w_value): return self.instance_variables.set(space, name, w_value) def find_instance_var(self, space, name): return self.instance_variables.get(space, name) or space.w_nil def copy_instance_vars(self, space, w_other): assert isinstance(w_other, W_ModuleObject) for key in w_other.instance_variables: w_value = w_other.instance_variables.get(space, key) self.set_instance_var(space, key, w_value) def set_flag(self, space, name): self.flags.set(space, name, space.w_true) def unset_flag(self, space, name): self.flags.set(space, name, space.w_false) def copy_flags(self, space, w_other): assert isinstance(w_other, W_ModuleObject) for key in w_other.flags: w_value = w_other.flags.get(space, key) if w_value is space.w_true: self.set_flag(space, key) def ancestors(self, include_singleton=True, include_self=True): if include_self: return [self] + self.included_modules else: return self.included_modules[:] @jit.unroll_safe def is_ancestor_of(self, w_cls): if self is w_cls: return True for w_mod in w_cls.included_modules: if self is w_mod: return True if w_cls.superclass is not None: return self.is_ancestor_of(w_cls.superclass) return False def include_module(self, space, w_mod): assert isinstance(w_mod, W_ModuleObject) if w_mod not in self.ancestors(): self.included_modules = [w_mod] + self.included_modules w_mod.included(space, self) def included(self, space, w_mod): self.descendants.append(w_mod) if space.respond_to(self, space.newsymbol("included")): space.send(self, space.newsymbol("included"), [w_mod]) def extend_object(self, space, w_obj, w_mod): if w_mod not in self.ancestors(): self.included_modules = [w_mod] + self.included_modules w_mod.extended(space, w_obj, self) def extended(self, space, w_obj, w_mod): self.descendants.append(w_mod) if space.respond_to(self, space.newsymbol("extended")): space.send(self, space.newsymbol("extended"), [w_obj]) def set_visibility(self, space, names_w, visibility): names = [space.symbol_w(w_name) for w_name in names_w] if names: for name in names: self.set_method_visibility(space, name, visibility) else: self.set_default_visibility(space, visibility) def set_default_visibility(self, space, visibility): pass def set_method_visibility(self, space, name, visibility): pass @classdef.singleton_method("nesting") def singleton_method_nesting(self, space): frame = space.getexecutioncontext().gettoprubyframe() modules_w = [] scope = frame.lexical_scope while scope is not None: modules_w.append(scope.w_mod) scope = scope.backscope return space.newarray(modules_w) @classdef.singleton_method("allocate") def method_allocate(self, space): return W_ModuleObject(space, None) @classdef.method("to_s") def method_to_s(self, space): name = self.name if name is None: return space.newstr_fromstr(space.any_to_s(self)) return space.newstr_fromstr(name) @classdef.method("include") def method_include(self, space, w_mod): space.send(w_mod, space.newsymbol("append_features"), [self]) @classdef.method("append_features") def method_append_features(self, space, w_mod): ancestors = self.ancestors() for idx in xrange(len(ancestors) - 1, -1, -1): w_mod.include_module(space, ancestors[idx]) @classdef.method("define_method", name="symbol") def method_define_method(self, space, name, w_method=None, block=None): if w_method is not None: if space.is_kind_of(w_method, space.w_method): w_method = space.send(w_method, space.newsymbol("unbind")) if space.is_kind_of(w_method, space.w_unbound_method): self.define_method(space, name, DefineMethodMethod(name, w_method)) elif space.is_kind_of(w_method, space.w_proc): self.define_method( space, name, DefineMethodBlock(name, w_method.get_block())) elif block is not None: self.define_method(space, name, DefineMethodBlock(name, block)) else: raise space.error(space.w_ArgumentError, "tried to create Proc object without a block") @classdef.method("attr_accessor") def method_attr_accessor(self, space, args_w): self.method_attr_reader(space, args_w) self.method_attr_writer(space, args_w) @classdef.method("attr_reader") def method_attr_reader(self, space, args_w): for w_arg in args_w: varname = space.symbol_w(w_arg) self.define_method(space, varname, AttributeReader("@" + varname)) @classdef.method("attr_writer") def method_attr_writer(self, space, args_w): for w_arg in args_w: varname = space.symbol_w(w_arg) self.define_method(space, varname + "=", AttributeWriter("@" + varname)) @classdef.method("attr") def method_attr(self, space, args_w): if len(args_w) == 2 and (args_w[1] is space.w_true or args_w[1] is space.w_false): [w_name, w_writable] = args_w if space.is_true(w_writable): self.method_attr_accessor(space, [w_name]) else: self.method_attr_reader(space, [w_name]) else: self.method_attr_reader(space, args_w) @classdef.method("module_function") def method_module_function(self, space, args_w): for w_arg in args_w: name = space.symbol_w(w_arg) self.attach_method( space, name, self._find_method_pure(space, name, self.version)) @classdef.method("private_class_method") def method_private_class_method(self, space, w_name): w_cls = self.getsingletonclass(space) return space.send(w_cls, space.newsymbol("private"), [w_name]) @classdef.method("public_class_method") def method_public_class_method(self, space, w_name): w_cls = self.getsingletonclass(space) return space.send(w_cls, space.newsymbol("public"), [w_name]) @classdef.method("alias_method", new_name="symbol", old_name="symbol") def method_alias_method(self, space, new_name, old_name): self.define_method(space, new_name, self.find_method(space, old_name)) @classdef.method("ancestors") def method_ancestors(self, space): return space.newarray(self.ancestors(include_singleton=False)) @classdef.method("included") def method_included(self, space, w_mod): # TODO: should be private pass @classdef.method("extended") def method_extended(self, space, w_mod): # TODO: should be private pass @classdef.method("name") def method_name(self, space): if self.name is None: return space.w_nil return space.newstr_fromstr(self.name) @classdef.method("private") def method_private(self, space, args_w): self.set_visibility(space, args_w, "private") @classdef.method("public") def method_public(self, space, args_w): self.set_visibility(space, args_w, "public") @classdef.method("protected") def method_protected(self, space, args_w): self.set_visibility(space, args_w, "protected") @classdef.method("private_constant") def method_private_constant(self, space, args_w): pass @classdef.method("constants") def method_constants(self, space): return space.newarray([space.newsymbol(n) for n in self.constants_w]) @classdef.method("const_missing", name="symbol") def method_const_missing(self, space, name): raise space.error(space.w_NameError, "uninitialized constant %s" % name) @classdef.method("class_eval", string="str", filename="str") @classdef.method("module_eval", string="str", filename="str") def method_module_eval(self, space, string=None, filename=None, w_lineno=None, block=None): if string is not None: if filename is None: filename = "module_eval" if w_lineno is not None: lineno = space.int_w(w_lineno) else: lineno = 1 return space.execute(string, self, lexical_scope=StaticScope(self, None), filepath=filename, initial_lineno=lineno) elif block is None: raise space.error(space.w_ArgumentError, "block not supplied") else: space.invoke_block( block.copy(w_self=self, lexical_scope=StaticScope(self, block.lexical_scope)), []) @classdef.method("const_defined?", const="str", inherit="bool") def method_const_definedp(self, space, const, inherit=True): if inherit: return space.newbool(self.find_const(space, const) is not None) else: return space.newbool( self.find_local_const(space, const) is not None) @classdef.method("const_get", const="symbol", inherit="bool") def method_const_get(self, space, const, inherit=True): if inherit: w_res = self.find_const(space, const) else: w_res = self.find_local_const(space, const) if w_res is None: name = space.obj_to_s(self) raise space.error(space.w_NameError, "uninitialized constant %s::%s" % (name, const)) return w_res @classdef.method("const_set", const="symbol") def method_const_set(self, space, const, w_value): space.set_const(self, const, w_value) return w_value @classdef.method("class_variable_defined?", name="symbol") def method_class_variable_definedp(self, space, name): return space.newbool(self.find_class_var(space, name) is not None) @classdef.method("remove_class_variable", name="symbol") def method_remove_class_variable(self, space, name): w_value = self.class_variables.get(space, name) if w_value is not None: self.class_variables.delete(name) return w_value if self.find_class_var(space, name) is not None: raise space.error( space.w_NameError, "cannot remove %s for %s" % (name, space.obj_to_s(self))) raise space.error( space.w_NameError, "class variable %s not defined for %s" % (name, space.obj_to_s(self))) @classdef.method("method_defined?", name="str") def method_method_definedp(self, space, name): return space.newbool(self.find_method(space, name) is not None) @classdef.method("===") def method_eqeqeq(self, space, w_obj): return space.newbool(self.is_ancestor_of(space.getclass(w_obj))) @classdef.method("instance_method", name="symbol") def method_instance_method(self, space, name): return space.newmethod(name, self) @classdef.method("undef_method", name="symbol") def method_undef_method(self, space, name): w_method = self.find_method(space, name) if w_method is None or isinstance(w_method, UndefMethod): cls_name = space.obj_to_s(self) raise space.error( space.w_NameError, "undefined method `%s' for class `%s'" % (name, cls_name)) self.define_method(space, name, UndefMethod(name)) return self @classdef.method("remove_method", name="symbol") def method_remove_method(self, space, name): w_method = self._find_method_pure(space, name, self.version) if w_method is None or isinstance(w_method, UndefMethod): cls_name = space.obj_to_s(self) raise space.error( space.w_NameError, "method `%s' not defined in %s" % (name, cls_name)) self.define_method(space, name, UndefMethod(name)) return self
class W_StopIteration(W_IndexError): classdef = ClassDef("StopIteration", W_IndexError.classdef, filepath=__file__) method_allocate = new_exception_allocate(classdef)
class W_ClassObject(W_ModuleObject): _immutable_fields_ = ["superclass?"] classdef = ClassDef("Class", W_ModuleObject.classdef) def __init__(self, space, name, superclass, is_singleton=False, attached=None): W_ModuleObject.__init__(self, space, name) self.superclass = superclass self.is_singleton = is_singleton self.attached = attached if self.superclass is not None: self.superclass.inherited(space, self) # During bootstrap, we cannot create singleton classes, yet if not self.is_singleton and not space.bootstrap: self.getsingletonclass(space) def __deepcopy__(self, memo): obj = super(W_ClassObject, self).__deepcopy__(memo) obj.is_singleton = self.is_singleton obj.attached = copy.deepcopy(self.attached, memo) obj.superclass = copy.deepcopy(self.superclass, memo) return obj def getsingletonclass(self, space): if self.klass is None or not self.klass.is_singleton: if self.superclass is None: singleton_superclass = space.w_class else: singleton_superclass = self.superclass.getsingletonclass(space) if self.name is None: name = None else: name = "#<Class:%s>" % self.name self.klass = space.newclass(name, singleton_superclass, is_singleton=True, attached=self) return self.klass def find_const(self, space, name): w_res = W_ModuleObject.find_included_const(self, space, name) if w_res is None and self.superclass is not None: w_res = self.superclass.find_const(space, name) return w_res def inherited_constants(self, space): consts = {} for const in W_ModuleObject.local_constants(self, space): consts[const] = None w_cls = self.superclass while w_cls is not None: for const in w_cls.local_constants(space): consts[const] = None w_cls = w_cls.superclass return consts.keys() def find_method(self, space, name): method = W_ModuleObject.find_method(self, space, name) if method is None and self.superclass is not None: method = self.superclass.find_method(space, name) return method def find_method_super(self, space, name): method = W_ModuleObject.find_method_super(self, space, name) if method is None and self.superclass is not None: method = self.superclass.find_method(space, name) return method def methods(self, space, inherit=True): methods = {} for name in W_ModuleObject.methods(self, space, inherit): methods[name] = None if inherit and self.superclass is not None: for name in self.superclass.methods(space, inherit): method = self._find_method_pure(space, name, self.version) if method is None or not isinstance(method, UndefMethod): methods[name] = None return methods.keys() def ancestors(self, include_singleton=True, include_self=True): assert include_self ary = W_ModuleObject.ancestors( self, include_singleton, not (self.is_singleton and not include_singleton)) if self.superclass is not None: ary += self.superclass.ancestors(include_singleton) return ary def inherited(self, space, w_mod): self.descendants.append(w_mod) if not space.bootstrap and space.respond_to(self, "inherited"): space.send(self, "inherited", [w_mod]) def method_removed(self, space, w_name): if self.is_singleton: space.send(self.attached, "singleton_method_removed", [w_name]) else: W_ModuleObject.method_removed(self, space, w_name) def method_added(self, space, w_name): if self.is_singleton: space.send(self.attached, "singleton_method_added", [w_name]) else: W_ModuleObject.method_added(self, space, w_name) def method_undefined(self, space, w_name): if self.is_singleton: space.send(self.attached, "singleton_method_undefined", [w_name]) else: W_ModuleObject.method_undefined(self, space, w_name) @classdef.singleton_method("allocate") def singleton_method_allocate(self, space, args_w): return space.newclass(None, None) @classdef.method("new") def method_new(self, space, args_w, block): w_obj = space.send(self, "allocate", args_w, block) space.send(w_obj, "initialize", args_w, block) return w_obj @classdef.method("allocate") def method_allocate(self, space, args_w): return W_Object(space, self) @classdef.method("initialize") def method_initialize(self, space, w_superclass=None, block=None): if self.superclass is not None or self is space.w_basicobject: raise space.error(space.w_TypeError, "already initialized class") if w_superclass is not None: if not isinstance(w_superclass, W_ClassObject): raise space.error( space.w_TypeError, "superclass must be a Class (%s given)" % space.obj_to_s(space.getclass(w_superclass))) if w_superclass.is_singleton: raise space.error(space.w_TypeError, "can't make subclass of singleton class") else: w_superclass = space.w_object self.superclass = w_superclass self.superclass.inherited(space, self) self.getsingletonclass(space) space.send_super(space.getclassfor(W_ClassObject), self, "initialize", [], block=block) @classdef.method("initialize_copy") def method_initialize_copy(self, space, w_other): if self.superclass is not None or self is space.w_basicobject: raise space.error(space.w_TypeError, "already initialized class") return space.send_super(space.getclassfor(W_ClassObject), self, "initialize_copy", [w_other]) @classdef.method("superclass") def method_superclass(self, space): if self.superclass is not None: return self.superclass if self is space.w_basicobject: return space.w_nil raise space.error(space.w_TypeError, "uninitialized class") @classdef.method("class_variables") def method_class_variables(self, space): return space.newarray( [space.newsymbol(cvar) for cvar in self.class_variables]) @classdef.method("instance_variables") def method_instance_variables(self, space): return space.newarray( [space.newsymbol(ivar) for ivar in self.instance_variables])
class W_EncodingObject(W_Object): classdef = ClassDef("Encoding", W_Object.classdef)