class DataConverter(object): # A rather abstract base class moduledef = ModuleDef('FFI::DataConverter') @moduledef.method('native_type') def native_type(self, space, args_w): # if len(args_w) == 0: # raise space.error(space.w_NotImplementedError, # "native_type method not overridden and no " # "native_type set") if len(args_w) == 0: w_void = space.execute("FFI::Type::VOID") space.set_instance_var(self, '@native_type', w_void) return w_void elif len(args_w) == 1: w_arg_as_type = type_object(space, args_w[0]) space.set_instance_var(self, '@native_type', w_arg_as_type) return w_arg_as_type raise space.error(space.w_ArgumentError, "incorrect arguments") @moduledef.method('to_native') def to_native(self, space, w_value, w_ctx): return w_value @moduledef.method('from_native') def from_native(self, space, w_value, w_ctx): return w_value
class ObjectSpace(object): moduledef = ModuleDef("ObjectSpace", filepath=__file__) @moduledef.function("each_object") def method_each_object(self, space, w_mod, block): if block is None: return space.send(self, space.newsymbol("enum_for"), [space.newsymbol("each_object"), w_mod], block) match_w = [] roots = [gcref for gcref in rgc.get_rpy_roots() if gcref] pending = roots[:] while pending: gcref = pending.pop() if not rgc.get_gcflag_extra(gcref): rgc.toggle_gcflag_extra(gcref) w_obj = try_cast_gcref_to_w_baseobject(gcref) if w_obj is not None and space.is_kind_of(w_obj, w_mod): match_w.append(w_obj) pending.extend(rgc.get_rpy_referents(gcref)) clear_gcflag_extra(roots) for w_obj in match_w: space.invoke_block(block, [w_obj]) return space.newint(len(match_w)) @moduledef.function("garbage_collect") @jit.dont_look_inside def method_garbage_collect(self): rgc.collect()
class Fcntl(object): moduledef = ModuleDef("Fcntl") @moduledef.setup_module def setup_module(space, w_mod): if not IS_WINDOWS: for key, value in fcntl_constants.items(): space.set_const(w_mod, const, space.newint(value))
class Signal(object): moduledef = ModuleDef("Signal") @moduledef.function("trap") def method_trap(self, args_w): pass @moduledef.function("list") def method_list(self, space): w_res = space.newhash() for sig_name, sig_num in SIGNALS.iteritems(): space.send(w_res, "[]=", [space.newstr_fromstr(sig_name), space.newint(sig_num)]) return w_res
class Topaz(object): moduledef = ModuleDef("Topaz") @moduledef.setup_module def setup_module(space, w_mod): space.set_const(w_mod, "FIXNUM_MAX", space.newint(sys.maxint)) @moduledef.function("intmask") def method_intmask(self, space, w_int): if space.is_kind_of(w_int, space.w_fixnum): return w_int elif space.is_kind_of(w_int, space.w_bignum): bigint = space.bigint_w(w_int) return space.newint(intmask(bigint.uintmask())) @moduledef.function("convert_type", method="symbol") def method_convert_type(self, space, w_obj, w_type, method): if not isinstance(w_type, W_ClassObject): raise space.error(space.w_TypeError, "type argument must be a class") return space.convert_type(w_obj, w_type, method) @moduledef.function("try_convert_type", method="symbol") def method_try_convert_type(self, space, w_obj, w_type, method): if not isinstance(w_type, W_ClassObject): raise space.error(space.w_TypeError, "type argument must be a class") return space.convert_type(w_obj, w_type, method, raise_error=False) @moduledef.function("compare") def method_compare(self, space, w_a, w_b, block=None): return space.compare(w_a, w_b, block) @moduledef.function("infect", taint="bool", untrust="bool", freeze="bool") def method_infect(self, space, w_dest, w_src, taint=True, untrust=True, freeze=False): space.infect(w_dest, w_src, taint=taint, untrust=untrust, freeze=freeze) return self
class Process(object): moduledef = ModuleDef("Process") @moduledef.function("euid") def method_euid(self, space): return space.newint(geteuid()) @moduledef.function("pid") def method_pid(self, space): return space.newint(os.getpid()) @moduledef.function("waitpid", pid="int") def method_waitpid(self, space, pid=-1): try: pid, status = os.waitpid(pid, 0) except OSError as e: raise error_for_oserror(space, e) status = WEXITSTATUS(status) w_status = space.send( space.find_const(self, "Status"), "new", [space.newint(pid), space.newint(status)]) space.globals.set(space, "$?", w_status) return space.newint(pid) @moduledef.function("exit", status="int") def method_exit(self, space, status=0): raise space.error(space.w_SystemExit, "exit", [space.newint(status)]) @moduledef.function("exit!", status="int") def method_exit_bang(self, space, status=0): os._exit(status) @moduledef.function("fork") def method_fork(self, space, block): pid = fork() if pid == 0: if block is not None: space.invoke_block(block, []) space.send(self, "exit") else: return space.w_nil else: return space.newint(pid)
class Topaz(object): moduledef = ModuleDef("Topaz", filepath=__file__) @moduledef.setup_module def setup_module(space, w_mod): space.set_const(w_mod, "FIXNUM_MAX", space.newint(sys.maxint)) @moduledef.function("intmask") def method_intmask(self, space, w_int): if space.is_kind_of(w_int, space.w_fixnum): return w_int elif space.is_kind_of(w_int, space.w_bignum): bigint = space.bigint_w(w_int) return space.newint(intmask(bigint.uintmask())) @moduledef.function("convert_type", method="symbol") def method_convert_type(self, space, w_obj, w_type, method): if not isinstance(w_type, W_ClassObject): raise space.error(space.w_TypeError, "type argument must be a class") return space.convert_type(w_obj, w_type, method) @moduledef.function("compare") def method_compare(self, space, w_a, w_b, block=None): return space.compare(w_a, w_b, block)
class Enumerable(object): moduledef = ModuleDef("Enumerable", filepath=__file__)
class Topaz(object): moduledef = ModuleDef("Topaz") @moduledef.setup_module def setup_module(space, w_mod): space.set_const(w_mod, "FIXNUM_MAX", space.newint(sys.maxint)) w_termioconsts = space.newmodule("TermIOConstants", None) space.set_const(w_mod, "TermIOConstants", w_termioconsts) for name, value in all_constants.iteritems(): space.set_const(w_termioconsts, name, space.newint(value)) @moduledef.function("intmask") def method_intmask(self, space, w_int): if space.is_kind_of(w_int, space.w_fixnum): return w_int elif space.is_kind_of(w_int, space.w_bignum): bigint = space.bigint_w(w_int) return space.newint(intmask(bigint.uintmask())) @moduledef.function("convert_type", method="symbol") def method_convert_type(self, space, w_obj, w_type, method): if not isinstance(w_type, W_ClassObject): raise space.error(space.w_TypeError, "type argument must be a class") return space.convert_type(w_obj, w_type, method) @moduledef.function("try_convert_type", method="symbol") def method_try_convert_type(self, space, w_obj, w_type, method): if not isinstance(w_type, W_ClassObject): raise space.error(space.w_TypeError, "type argument must be a class") return space.convert_type(w_obj, w_type, method, raise_error=False) @moduledef.function("compare") def method_compare(self, space, w_a, w_b, block=None): return space.compare(w_a, w_b, block) @moduledef.function("infect", taint="bool", untrust="bool", freeze="bool") def method_infect(self, space, w_dest, w_src, taint=True, untrust=True, freeze=False): space.infect(w_dest, w_src, taint=taint, untrust=untrust, freeze=freeze) return self @moduledef.function("tcsetattr", fd="int", when="int", mode_w="array") def method_tcsetattr(self, space, fd, when, mode_w): cc = [space.str_w(w_char) for w_char in space.listview(mode_w[6])] mode = ( space.int_w(mode_w[0]), # iflag space.int_w(mode_w[1]), # oflag space.int_w(mode_w[2]), # cflag space.int_w(mode_w[3]), # lflag space.int_w(mode_w[4]), # ispeed space.int_w(mode_w[5]), # ospeed cc) try: tcsetattr(fd, when, mode) except OSError as e: raise error_for_oserror(space, e) return self @moduledef.function("tcgetattr", fd="int") def method_tcsetattr(self, space, fd): try: mode = tcgetattr(fd) except OSError as e: raise error_for_oserror(space, e) mode_w = [ space.newint(mode[0]), # iflag space.newint(mode[1]), # oflag space.newint(mode[2]), # cflag space.newint(mode[3]), # lflag space.newint(mode[4]), # ispeed space.newint(mode[5]), # ospeed space.newarray([space.newstr_fromstr(cc) for cc in mode[6]]) ] return space.newarray(mode_w)
class Process(object): moduledef = ModuleDef("Process") @moduledef.setup_module def setup_module(space, w_mod): if rtime.HAS_CLOCK_GETTIME: for name in rtime.ALL_DEFINED_CLOCKS: space.set_const(w_mod, name, space.newint(getattr(rtime, name))) else: space.set_const(w_mod, "CLOCK_PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID) @moduledef.function("euid") def method_euid(self, space): return space.newint(intmask(geteuid())) @moduledef.function("pid") def method_pid(self, space): return space.newint(os.getpid()) @moduledef.function("waitpid", pid="int") def method_waitpid(self, space, pid=-1): try: pid, status = os.waitpid(pid, 0) except OSError as e: raise error_for_oserror(space, e) status = WEXITSTATUS(status) w_status = space.send( space.find_const(self, "Status"), "new", [space.newint(pid), space.newint(status)]) space.globals.set(space, "$?", w_status) return space.newint(pid) @moduledef.function("exit", status="int") def method_exit(self, space, status=0): raise space.error(space.w_SystemExit, "exit", [space.newint(status)]) @moduledef.function("exit!", status="int") def method_exit_bang(self, space, status=0): os._exit(status) @moduledef.function("fork") def method_fork(self, space, block): pid = fork() if pid == 0: if block is not None: space.invoke_block(block, []) space.send(self, "exit") else: return space.w_nil else: return space.newint(pid) @moduledef.function("times") def method_times(self, space): tms = space.find_const(space.find_const(space.w_object, "Struct"), "Tms") return space.send(tms, "new", [space.newfloat(t) for t in list(os.times()[0:4])]) @moduledef.function("kill") def method_kill(self, space, w_signal, args_w): if not args_w: raise space.error( space.w_ArgumentError, "wrong number of arguments (%d for at least 2)" % (len(args_w) + 1)) if space.is_kind_of(w_signal, space.w_fixnum): sig = space.int_w(w_signal) else: s = Coerce.str(space, w_signal) if s.startswith("SIG"): s = s[len("SIG"):] try: sig = SIGNALS[s] except KeyError: raise space.error(space.w_ArgumentError, "unsupported name `SIG%s'" % s) if sig < 0: for w_arg in args_w: pid = Coerce.int(space, w_arg) try: killpg(pid, -sig) except OSError as e: raise error_for_oserror(space, e) else: for w_arg in args_w: pid = Coerce.int(space, w_arg) try: kill(pid, sig) except OSError as e: raise error_for_oserror(space, e) return space.newint(len(args_w)) @moduledef.function("clock_gettime", clockid="int") def method_clock_gettime(self, space, clockid, args_w): if len(args_w) > 1: raise space.error( space.w_ArgumentError, "wrong number of arguments (given %d, expected 1..2)") if len(args_w) == 1: unit = Coerce.symbol(space, args_w[0]) else: unit = "float_second" if rtime.HAS_CLOCK_GETTIME: with lltype.scoped_alloc(rtime.TIMESPEC) as a: if rtime.c_clock_gettime(clockid, a) == 0: sec = rffi.getintfield(a, 'c_tv_sec') nsec = rffi.getintfield(a, 'c_tv_nsec') else: raise error_for_oserror( space, OSError(errno.EINVAL, "clock_gettime")) elif clockid == CLOCK_PROCESS_CPUTIME_ID: r = rtime.clock() sec = int(r) nsec = r * 1000000000 else: raise error_for_oserror(space, OSError(errno.EINVAL, "clock_gettime")) if unit == "float_second": return space.newfloat(sec + nsec * 0.000000001) elif unit == "float_millisecond": return space.newfloat(sec * 1000 + nsec * 0.000001) elif unit == "float_microsecond": return space.newfloat(sec * 1000000 + nsec * 0.001) elif unit == "second": return space.newint(int(sec)) elif unit == "millisecond": return space.newint(int(sec) * 1000) elif unit == "microsecond": return space.newint(sec * 1000000) elif unit == "nanosecond": return space.newint(sec * 1000000000 + nsec) else: raise space.error(space.w_ArgumentError, "unexpected unit: %s" % unit)
class Comparable(object): moduledef = ModuleDef("Comparable", filepath=__file__)
class FFI(object): moduledef = ModuleDef("FFI") @moduledef.setup_module def setup_module(space, w_mod): # setup modules from other files w_Type = space.getclassfor(W_TypeObject) space.set_const(w_mod, 'Type', w_Type) space.set_const(w_Type, 'Builtin', space.getclassfor(W_BuiltinType)) space.set_const(w_mod, 'DynamicLibrary', space.getclassfor(W_DynamicLibraryObject)) space.set_const(w_mod, 'Function', space.getclassfor(W_FFIFunctionObject)) w_FunctionType = space.getclassfor(W_FunctionTypeObject) space.set_const(w_mod, 'FunctionType', w_FunctionType) space.set_const(w_mod, 'FunctionInfo', w_FunctionType) space.set_const(w_mod, 'CallbackInfo', w_FunctionType) space.set_const(w_mod, 'VariadicInvoker', space.getclassfor(W_VariadicInvokerObject)) space.set_const(w_mod, 'AbstractMemory', space.getclassfor(W_AbstractMemoryObject)) space.set_const(w_mod, 'Pointer', space.getclassfor(W_PointerObject)) space.set_const(w_mod, 'MemoryPointer', space.getclassfor(W_MemoryPointerObject)) space.set_const(w_mod, 'DataConverter', space.getmoduleobject(DataConverter.moduledef)) w_native_type = space.newmodule('NativeType') # This assumes that FFI::Type and the type constants already exist for typename in type_names: try: w_ffi_type = space.find_const(w_Type, typename) # setup type constants space.set_const(w_mod, 'TYPE_' + typename, w_ffi_type) # setup NativeType space.set_const(w_native_type, typename, w_ffi_type) except RubyError: pass space.set_const(w_mod, 'NativeType', w_native_type) # setup Platform w_platform = space.newmodule('Platform') w_cpu = space.newstr_fromstr(platform.machine()) space.set_const(w_platform, 'CPU', w_cpu) name_postfix = '_SIZE' for name_prefix in [ 'INT8', 'INT16', 'INT32', 'INT64', 'LONG', 'FLOAT', 'DOUBLE' ]: w_type = space.find_const(w_mod, 'Type') w_tp = space.find_const(w_type, name_prefix) space.set_const(w_platform, name_prefix + name_postfix, space.send(w_tp, 'size')) space.set_const(w_platform, 'ADDRESS_SIZE', space.newint(lltype_sizes[POINTER])) space.set_const(w_mod, 'Platform', w_platform) # setup StructLayout w_struct_layout = space.newclass('StructLayout', None) w_struct_layout_field = space.newclass('Field', None) space.set_const(w_struct_layout, 'Field', w_struct_layout_field) space.set_const(w_mod, 'StructLayout', w_struct_layout) # setup StructByReference w_struct_by_reference = space.newclass('StructByReference', None) space.set_const(w_mod, 'StructByReference', w_struct_by_reference)
class Comparable(object): moduledef = ModuleDef("Comparable")
class Math(object): moduledef = ModuleDef("Math") @moduledef.setup_module def setup_module(space, w_mod): space.set_const(w_mod, "PI", space.newfloat(math.pi)) space.set_const(w_mod, "E", space.newfloat(math.e)) space.set_const(w_mod, "DomainError", space.getclassfor(W_DomainError)) @moduledef.function("acos", value="strictfloat") def method_acos(self, space, value): return space.newfloat(math.acos(value)) @moduledef.function("acosh", value="strictfloat") def method_acosh(self, space, value): try: res = math.acosh(value) except ValueError: raise space.error(space.getclassfor(W_DomainError), 'Numerical argument is out of domain - "acosh"') return space.newfloat(res) @moduledef.function("asin", value="strictfloat") def method_asin(self, space, value): return space.newfloat(math.asin(value)) @moduledef.function("asinh", value="strictfloat") def method_asinh(self, space, value): return space.newfloat(math.asinh(value)) @moduledef.function("atan", value="strictfloat") def method_atan(self, space, value): return space.newfloat(math.atan(value)) @moduledef.function("atan2", value1="strictfloat", value2="strictfloat") def method_atan2(self, space, value1, value2): return space.newfloat(math.atan2(value1, value2)) @moduledef.function("atanh", value="strictfloat") def method_atanh(self, space, value): try: res = math.atanh(value) except ValueError: if value == 1.0 or value == -1.0: # produce an infinity with the right sign res = rfloat.copysign(rfloat.INFINITY, value) else: raise space.error( space.getclassfor(W_DomainError), 'Numerical argument is out of domain - "atanh"') return space.newfloat(res) @moduledef.function("cbrt", value="strictfloat") def method_cbrt(self, space, value): if value < 0: return space.newfloat(-math.pow(-value, 1.0 / 3.0)) else: return space.newfloat(math.pow(value, 1.0 / 3.0)) @moduledef.function("cos", value="strictfloat") def method_cos(self, space, value): return space.newfloat(math.cos(value)) @moduledef.function("cosh", value="strictfloat") def method_cosh(self, space, value): try: res = math.cosh(value) except OverflowError: res = rfloat.copysign(rfloat.INFINITY, value) return space.newfloat(res) @moduledef.function("exp", value="strictfloat") def method_exp(self, space, value): return space.newfloat(math.exp(value)) @moduledef.function("frexp", value="strictfloat") def method_frexp(self, space, value): mant, exp = math.frexp(value) w_mant = space.newfloat(mant) w_exp = space.newint(exp) return space.newarray([w_mant, w_exp]) @moduledef.function("gamma", value="strictfloat") def method_gamma(self, space, value): try: res = rfloat.gamma(value) except ValueError: if value == 0.0: # produce an infinity with the right sign res = rfloat.copysign(rfloat.INFINITY, value) else: raise space.error( space.getclassfor(W_DomainError), 'Numerical argument is out of domain - "gamma"') except OverflowError: res = rfloat.INFINITY return space.newfloat(res) @moduledef.function("lgamma", value="strictfloat") def method_lgamma(self, space, value): try: res = rfloat.lgamma(value) except (ValueError, OverflowError): res = rfloat.INFINITY gamma = (1 if value == -1 or math.isnan(value) else space.float_w( space.send(self, "gamma", [space.newfloat(value)]))) sign = 1 if gamma > 0 else -1 if gamma < 0 else 0 return space.newarray([space.newfloat(res), space.newint(sign)]) @moduledef.function("hypot", value1="strictfloat", value2="strictfloat") def method_hypot(self, space, value1, value2): return space.newfloat(math.hypot(value1, value2)) @moduledef.function("ldexp", value1="strictfloat", value2="int") def method_ldexp(self, space, value1, value2): return space.newfloat(math.ldexp(value1, value2)) @moduledef.function("log", value="strictfloat", base="strictfloat") def method_log(self, space, value, base=math.e): try: res = 0.0 if base == math.e: res = math.log(value) else: res = math.log(value) / math.log(base) except ValueError: if value == 0.0: res = float(-rfloat.INFINITY) else: raise space.error( space.getclassfor(W_DomainError), 'Numerical argument is out of domain - "log"') return space.newfloat(res) @moduledef.function("log10", value="strictfloat") def method_log10(self, space, value): try: res = math.log10(value) except ValueError: if value == 0.0: res = float(-rfloat.INFINITY) else: raise space.error( space.getclassfor(W_DomainError), 'Numerical argument is out of domain - "log10"') return space.newfloat(res) @moduledef.function("log2", value="strictfloat") def method_log2(self, space, value): try: res = math.log(value) / math.log(2) except ValueError: if value == 0.0: res = float(-rfloat.INFINITY) else: raise space.error( space.getclassfor(W_DomainError), 'Numerical argument is out of domain - "log2"') return space.newfloat(res) @moduledef.function("sin", value="strictfloat") def method_sin(self, space, value): return space.newfloat(math.sin(value)) @moduledef.function("sinh", value="strictfloat") def method_sinh(self, space, value): try: res = math.sinh(value) except OverflowError: res = rfloat.copysign(rfloat.INFINITY, value) return space.newfloat(res) @moduledef.function("sqrt", value="strictfloat") def method_sqrt(self, space, value): return space.newfloat(math.sqrt(value)) @moduledef.function("tan", value="strictfloat") def method_tan(self, space, value): try: res = math.tan(value) except ValueError: res = rfloat.NAN return space.newfloat(res) @moduledef.function("tanh", value="strictfloat") def method_tanh(self, space, value): return space.newfloat(math.tanh(value)) @moduledef.function("erf", value="strictfloat") def method_erf(self, space, value): return space.newfloat(rfloat.erf(value)) @moduledef.function("erfc", value="strictfloat") def method_erfc(self, space, value): return space.newfloat(rfloat.erfc(value))
class Enumerable(object): moduledef = ModuleDef("Enumerable")
class Kernel(object): moduledef = ModuleDef("Kernel") @moduledef.method("class") def function_class(self, space): return space.getnonsingletonclass(self) @moduledef.method("singleton_methods", all="bool") def method_singleton_methods(self, space, all=True): methods = [] w_cls = space.getclass(self) if w_cls.is_singleton: methods.extend(w_cls.methods_w.keys()) w_cls = w_cls.superclass if all: while w_cls and w_cls.is_singleton: methods.extend(w_cls.methods_w.keys()) w_cls = w_cls.superclass return space.newarray([space.newsymbol(m) for m in methods]) @moduledef.method("methods", inherit="bool") def method_methods(self, space, inherit=True): w_cls = space.getclass(self) return space.newarray([ space.newsymbol(m) for m in w_cls.methods(space, inherit=inherit) ]) @moduledef.method("private_methods", inherit="bool") def method_private_methods(self, space, inherit=True): w_cls = space.getclass(self) return space.newarray([ space.newsymbol(m) for m in w_cls.methods( space, visibility=W_FunctionObject.PRIVATE, inherit=inherit) ]) @moduledef.method("protected_methods", inherit="bool") def method_protected_methods(self, space, inherit=True): w_cls = space.getclass(self) return space.newarray([ space.newsymbol(m) for m in w_cls.methods( space, visibility=W_FunctionObject.PROTECTED, inherit=inherit) ]) @moduledef.method("public_methods", inherit="bool") def method_public_methods(self, space, inherit=True): w_cls = space.getclass(self) return space.newarray([ space.newsymbol(m) for m in w_cls.methods( space, visibility=W_FunctionObject.PUBLIC, inherit=inherit) ]) @moduledef.method("lambda") def function_lambda(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 lambda object without a block") else: return block.copy(space, is_lambda=True) @moduledef.method("proc") def function_proc(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) @staticmethod def find_feature(space, path): assert path is not None if os.path.isfile(path): return path if not path.endswith(".rb"): path += ".rb" if not (path.startswith("/") or path.startswith("./") or path.startswith("../")): w_load_path = space.globals.get(space, "$LOAD_PATH") for w_base in space.listview(w_load_path): base = Coerce.path(space, w_base) full = os.path.join(base, path) if os.path.isfile(full): path = os.path.join(base, path) break return path @staticmethod def load_feature(space, path, orig_path, wrap=False): if not os.path.exists(path): raise space.error(space.w_LoadError, orig_path) try: f = open_file_as_stream(path, buffering=0) try: contents = f.readall() finally: f.close() except OSError as e: raise error_for_oserror(space, e) if wrap: lexical_scope = StaticScope(space.newmodule("Anonymous"), None) else: lexical_scope = None space.execute(contents, filepath=path, lexical_scope=lexical_scope) @moduledef.function("require", path="path") def function_require(self, space, path): assert path is not None orig_path = path path = Kernel.find_feature(space, path) w_loaded_features = space.globals.get(space, '$"') w_already_loaded = space.send(w_loaded_features, "include?", [space.newstr_fromstr(path)]) if space.is_true(w_already_loaded): return space.w_false Kernel.load_feature(space, path, orig_path) w_loaded_features.method_lshift(space, space.newstr_fromstr(path)) return space.w_true @moduledef.function("load", path="path", wrap="bool") def function_load(self, space, path, wrap=False): assert path is not None orig_path = path path = Kernel.find_feature(space, path) Kernel.load_feature(space, path, orig_path, wrap=wrap) return space.w_true @moduledef.method("fail") @moduledef.method("raise") def method_raise(self, space, w_str_or_exception=None, w_string=None, w_array=None): w_exception = None if w_str_or_exception is None: w_exception = space.globals.get(space, "$!") or space.w_nil if w_exception is space.w_nil: w_exception = space.w_RuntimeError elif isinstance(w_str_or_exception, W_StringObject): w_exception = space.w_RuntimeError w_string = w_str_or_exception else: w_exception = w_str_or_exception if not space.respond_to(w_exception, "exception"): raise space.error(space.w_TypeError, "exception class/object expected") if w_string is not None: w_exc = space.send(w_exception, "exception", [w_string]) else: w_exc = space.send(w_exception, "exception") if w_array is not None: raise space.error(space.w_NotImplementedError, "custom backtrace for Kernel#raise") if not isinstance(w_exc, W_ExceptionObject): raise space.error(space.w_TypeError, "exception object expected") raise RubyError(w_exc) @moduledef.function("exit") def method_exit(self, space, args_w): return space.send(space.getmoduleobject(Process.moduledef), "exit", args_w) @moduledef.function("exit!") def method_exit_bang(self, space, args_w): return space.send(space.getmoduleobject(Process.moduledef), "exit!", args_w) @moduledef.function("abort", msg="str") def method_abort(self, space, msg=None): if msg: os.write(2, msg) return space.send(self, "exit", [space.newint(1)]) @moduledef.function("block_given?") @moduledef.function("iterator?") def method_block_givenp(self, space): return space.newbool( space.getexecutioncontext().gettoprubyframe().block is not None) @moduledef.function("binding") def method_binding(self, space): return space.newbinding_fromframe( space.getexecutioncontext().gettoprubyframe()) @moduledef.function("__method__") @moduledef.function("__callee__") def method_callee(self, space): frame = space.getexecutioncontext().gettoprubyframe() return space.newsymbol(frame.bytecode.name) @moduledef.function("exec") def method_exec(self, space, args_w): if len(args_w) > 1 and space.respond_to(args_w[0], "to_hash"): raise space.error(space.w_NotImplementedError, "exec with environment") if len(args_w) > 1 and space.respond_to(args_w[-1], "to_hash"): raise space.error(space.w_NotImplementedError, "exec with options") if space.respond_to(args_w[0], "to_ary"): w_cmd = space.convert_type(args_w[0], space.w_array, "to_ary") cmd_w = space.listview(w_cmd) if len(cmd_w) != 2: raise space.error(space.w_ArgumentError, "wrong first argument") cmd, argv0 = [ space.str0_w(space.convert_type(w_e, space.w_string, "to_str")) for w_e in cmd_w ] else: w_cmd = space.convert_type(args_w[0], space.w_string, "to_str") cmd = space.str0_w(w_cmd) argv0 = None if len(args_w) > 1 or argv0 is not None: if argv0 is None: sepidx = cmd.rfind(os.sep) + 1 if sepidx > 0: argv0 = cmd[sepidx:] else: argv0 = cmd args = [argv0] args += [ space.str0_w( space.convert_type(w_arg, space.w_string, "to_str")) for w_arg in args_w[1:] ] try: os.execv(cmd, args) except OSError as e: raise error_for_oserror(space, e) else: if not cmd: raise error_for_errno(space, errno.ENOENT) shell = os.environ.get("RUBYSHELL") or os.environ.get( "COMSPEC") or "/bin/sh" sepidx = shell.rfind(os.sep) + 1 if sepidx > 0: argv0 = shell[sepidx:] else: argv0 = shell try: os.execv(shell, [argv0, "-c", cmd]) except OSError as e: raise error_for_oserror(space, e) @moduledef.function("system") def method_system(self, space, args_w): raise space.error(space.w_NotImplementedError, "Kernel#system()") @moduledef.function("fork") def method_fork(self, space, block): return space.send(space.getmoduleobject(Process.moduledef), "fork", block=block) @moduledef.function("at_exit") def method_at_exit(self, space, block): space.register_exit_handler(block) return block @moduledef.function("=~") def method_match(self, space, w_other): return space.w_nil @moduledef.function("!~") def method_not_match(self, space, w_other): return space.newbool( not space.is_true(space.send(self, "=~", [w_other]))) @moduledef.function("eql?") def method_eqlp(self, space, w_other): return space.newbool(self is w_other) @moduledef.function("instance_variable_defined?", name="symbol") def method_instance_variable_definedp(self, space, name): return space.newbool(self.find_instance_var(space, name) is not None) @moduledef.method("respond_to?", include_private="bool") def method_respond_top(self, space, w_name, include_private=False): if space.respond_to(self, space.symbol_w(w_name)): return space.newbool(True) w_found = space.send(self, "respond_to_missing?", [w_name, space.newbool(include_private)]) return space.newbool(space.is_true(w_found)) @moduledef.method("respond_to_missing?") def method_respond_to_missingp(self, space, w_name, w_include_private): return space.newbool(False) @moduledef.method("dup") def method_dup(self, space): if (self is space.w_nil or self is space.w_true or self is space.w_false or space.is_kind_of(self, space.w_symbol) or space.is_kind_of(self, space.w_fixnum)): raise space.error(space.w_TypeError, "can't dup %s" % space.getclass(self).name) w_dup = space.send(space.getnonsingletonclass(self), "allocate") w_dup.copy_instance_vars(space, self) space.infect(w_dup, self, freeze=False) space.send(w_dup, "initialize_dup", [self]) return w_dup @moduledef.method("clone") def method_clone(self, space): if (self is space.w_nil or self is space.w_true or self is space.w_false or space.is_kind_of(self, space.w_symbol) or space.is_kind_of(self, space.w_fixnum)): raise space.error(space.w_TypeError, "can't dup %s" % space.getclass(self).name) w_dup = space.send(space.getnonsingletonclass(self), "allocate") w_dup.copy_instance_vars(space, self) w_dup.copy_singletonclass(space, space.getsingletonclass(self)) space.send(w_dup, "initialize_clone", [self]) space.infect(w_dup, self, freeze=True) return w_dup @moduledef.method("sleep") def method_sleep(self, space, w_duration=None): if w_duration is None: raise space.error(space.w_NotImplementedError) elif space.is_kind_of(w_duration, space.w_string): raise space.error(space.w_TypeError, "can't convert String into time interval") start = time.time() time.sleep(Coerce.float(space, w_duration)) return space.newint(int(round_double(time.time() - start, 0))) @moduledef.method("initialize_clone") @moduledef.method("initialize_dup") def method_initialize_dup(self, space, w_other): space.send(self, "initialize_copy", [w_other]) return self @moduledef.method("initialize_copy") def method_initialize_copy(self, space, w_other): return self @moduledef.function("Float") def method_Float(self, space, w_arg): if w_arg is space.w_nil: raise space.error(space.w_TypeError, "can't convert nil into Float") elif space.is_kind_of(w_arg, space.w_float): return space.newfloat(space.float_w(w_arg)) elif space.is_kind_of(w_arg, space.w_string): string = space.str_w(w_arg).strip(" ") try: return space.newfloat(float(string)) except ValueError: raise space.error(space.w_ArgumentError, "invalid value for Float(): %s" % string) else: return space.convert_type(w_arg, space.w_float, "to_f") @moduledef.method("kind_of?") @moduledef.method("is_a?") def method_is_kind_ofp(self, space, w_mod): if not isinstance(w_mod, W_ModuleObject): raise space.error(space.w_TypeError, "class or module required") return space.newbool(self.is_kind_of(space, w_mod)) @moduledef.method("instance_of?") def method_instance_of(self, space, w_mod): if not isinstance(w_mod, W_ModuleObject): raise space.error(space.w_TypeError, "class or module required") return space.newbool(space.getnonsingletonclass(self) is w_mod) @moduledef.method("eval") def method_eval(self, space, w_source, w_binding=None): if w_binding is None: frame = space.getexecutioncontext().gettoprubyframe() w_binding = space.newbinding_fromframe(frame) elif not isinstance(w_binding, W_BindingObject): raise space.error( space.w_TypeError, "wrong argument type %s (expected Binding)" % space.getclass(w_binding).name) return space.send(w_binding, "eval", [w_source]) @moduledef.method("set_trace_func") def method_set_trace_func(self, space, w_proc): if w_proc is space.w_nil: w_proc = None else: assert isinstance(w_proc, W_ProcObject) space.getexecutioncontext().settraceproc(w_proc) def new_flag(moduledef, setter, getter, remover): @moduledef.method(setter) def setter_method(self, space): self.set_flag(space, getter) return self @moduledef.method(getter) def getter_method(self, space): return self.get_flag(space, getter) if remover is None: return (setter_method, getter_method) else: @moduledef.method(remover) def remover_method(self, space): self.unset_flag(space, getter) return self return (setter_method, getter_method, remover_method) method_untrust, method_untrusted, method_trust = new_flag( moduledef, "untrust", "untrusted?", "trust") method_taint, method_tainted, method_untaint = new_flag( moduledef, "taint", "tainted?", "untaint") method_freeze, method_frozen = new_flag(moduledef, "freeze", "frozen?", None) @moduledef.method("throw", name="symbol") def method_throw(self, space, name, w_value=None): from topaz.interpreter import Throw if not space.getexecutioncontext().is_in_catch_block_for_name(name): raise space.error(space.w_ArgumentError, "uncaught throw :%s" % name) if w_value is None: w_value = space.w_nil raise Throw(name, w_value) @moduledef.method("catch", name="symbol") def method_catch(self, space, name, block): if block is None: raise space.error(space.w_LocalJumpError, "no block given") from topaz.interpreter import Throw with space.getexecutioncontext().catch_block(name): try: return space.invoke_block(block, []) except Throw as e: if e.name == name: return e.w_value raise @moduledef.method("srand") def method_srand(self, space, w_seed=None): random_class = space.getclassfor(W_RandomObject) default = space.find_const(random_class, "DEFAULT") return default.srand(space, w_seed) @moduledef.method("autoload") def method_autoload(self, space, args_w): return space.send(space.getclass(self), "autoload", args_w) @moduledef.method("autoload?") def method_autoload(self, space, args_w): return space.send(space.getclass(self), "autoload?", args_w) @moduledef.method("object_id") def method_object_id(self, space): return space.send(self, "__id__") @moduledef.method("singleton_class") def method_singleton_class(self, space): return space.getsingletonclass(self) @moduledef.method("extend") @check_frozen() 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) space.send(w_mod, "extend_object", [self]) space.send(w_mod, "extended", [self]) @moduledef.method("inspect") def method_inspect(self, space): return space.send(self, "to_s") @moduledef.method("to_s") def method_to_s(self, space): return space.newstr_fromstr(space.any_to_s(self)) @moduledef.method("===") def method_eqeqeq(self, space, w_other): if self is w_other: return space.w_true return space.send(self, "==", [w_other]) @moduledef.method("send") def method_send(self, space, args_w, block): return space.send(self, "__send__", args_w, block) @moduledef.method("nil?") def method_nilp(self, space): return space.w_false @moduledef.method("hash") def method_hash(self, space): return space.newint(compute_identity_hash(self)) @moduledef.method("instance_variable_get", name="str") def method_instance_variable_get(self, space, name): return space.find_instance_var(self, name) @moduledef.method("instance_variable_set", name="str") @check_frozen() def method_instance_variable_set(self, space, name, w_value): space.set_instance_var(self, name, w_value) return w_value @moduledef.method("method") def method_method(self, space, w_sym): return space.send( space.send(space.getclass(self), "instance_method", [w_sym]), "bind", [self]) @moduledef.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 @moduledef.method("define_singleton_method", name="symbol") @check_frozen() def method_define_singleton_method(self, space, name, w_method=None, block=None): args_w = [space.newsymbol(name)] if w_method is not None: args_w.append(w_method) return space.send(space.getsingletonclass(self), "define_method", args_w, block)
class Process(object): moduledef = ModuleDef("Process") @moduledef.function("euid") def method_euid(self, space): return space.newint(geteuid()) @moduledef.function("pid") def method_pid(self, space): return space.newint(os.getpid()) @moduledef.function("waitpid", pid="int") def method_waitpid(self, space, pid=-1): try: pid, status = os.waitpid(pid, 0) except OSError as e: raise error_for_oserror(space, e) status = WEXITSTATUS(status) w_status = space.send( space.find_const(self, "Status"), "new", [space.newint(pid), space.newint(status)]) space.globals.set(space, "$?", w_status) return space.newint(pid) @moduledef.function("exit", status="int") def method_exit(self, space, status=0): raise space.error(space.w_SystemExit, "exit", [space.newint(status)]) @moduledef.function("exit!", status="int") def method_exit_bang(self, space, status=0): os._exit(status) @moduledef.function("fork") def method_fork(self, space, block): pid = fork() if pid == 0: if block is not None: space.invoke_block(block, []) space.send(self, "exit") else: return space.w_nil else: return space.newint(pid) @moduledef.function("times") def method_times(self, space): tms = space.find_const(space.find_const(space.w_object, "Struct"), "Tms") return space.send(tms, "new", [space.newfloat(t) for t in list(os.times()[0:4])]) @moduledef.function("kill") def method_kill(self, space, w_signal, args_w): if not args_w: raise space.error( space.w_ArgumentError, "wrong number of arguments (%d for at least 2)" % (len(args_w) + 1)) if space.is_kind_of(w_signal, space.w_fixnum): sig = space.int_w(w_signal) else: s = Coerce.str(space, w_signal) if s.startswith("SIG"): s = s[len("SIG"):] try: sig = SIGNALS[s] except KeyError: raise space.error(space.w_ArgumentError, "unsupported name `SIG%s'" % s) if sig < 0: for w_arg in args_w: pid = Coerce.int(space, w_arg) try: killpg(pid, -sig) except OSError as e: raise error_for_oserror(space, e) else: for w_arg in args_w: pid = Coerce.int(space, w_arg) try: kill(pid, sig) except OSError as e: raise error_for_oserror(space, e) return space.newint(len(args_w))
class Marshal(object): moduledef = ModuleDef("Marshal") MAJOR_VERSION = 4 MINOR_VERSION = 8 NIL = 0x30 TRUE = 0x54 FALSE = 0x46 FIXNUM = 0x69 ARRAY = 0x5b SYMBOL = 0x3a IVAR = 0x49 STRING = 0x22 HASH = 0x7b FLOAT = 0x66 @moduledef.setup_module def setup_module(space, w_mod): space.set_const(w_mod, "MAJOR_VERSION", space.newint(Marshal.MAJOR_VERSION)) space.set_const(w_mod, "MINOR_VERSION", space.newint(Marshal.MINOR_VERSION)) @staticmethod def dump(space, w_obj): bytes = [] if isinstance(w_obj, W_NilObject): bytes.append(Marshal.NIL) elif isinstance(w_obj, W_TrueObject): bytes.append(Marshal.TRUE) elif isinstance(w_obj, W_FalseObject): bytes.append(Marshal.FALSE) elif isinstance(w_obj, W_FixnumObject): bytes.append(Marshal.FIXNUM) bytes += Marshal.integer2bytes(space.int_w(w_obj)) elif isinstance(w_obj, W_FloatObject): bytes.append(Marshal.FLOAT) raw_value = space.float_w(w_obj) int_value = int(raw_value) float_value = raw_value string = "" # None if raw_value == int_value: float_value = int_value # repr would be more accurate here, but it weirdly does not translate if str(raw_value) == "-0.0": # slowing things down string = "-0" else: string = str(float_value) else: # encode float string = str(float_value) length = len(string) bytes += Marshal.integer2bytes(length) for c in string: bytes.append(ord(c)) elif isinstance(w_obj, W_ArrayObject): array = space.listview(w_obj) bytes.append(Marshal.ARRAY) bytes += Marshal.integer2bytes(len(array)) for item in array: bytes += Marshal.dump(space, item) elif isinstance(w_obj, W_SymbolObject): bytes.append(Marshal.SYMBOL) symbol = space.symbol_w(w_obj) bytes += Marshal.integer2bytes(len(symbol)) for char in symbol: bytes.append(ord(char)) elif isinstance(w_obj, W_StringObject): string = space.str_w(w_obj) bytes.append(Marshal.IVAR) bytes.append(Marshal.STRING) bytes += Marshal.integer2bytes(len(string)) for char in string: bytes.append(ord(char)) bytes.append(0x06) # TODO: respect encoding bytes += Marshal.dump(space, space.newsymbol("E")) bytes += Marshal.dump(space, space.w_true) elif isinstance(w_obj, W_HashObject): bytes.append(Marshal.HASH) hash_len = w_obj.strategy.len(w_obj.dict_storage) hash_keys_w = w_obj.strategy.keys(w_obj.dict_storage) bytes += Marshal.integer2bytes(hash_len) for w_key in hash_keys_w: bytes += Marshal.dump(space, w_key) w_value = w_obj.strategy.getitem(w_obj.dict_storage, w_key) bytes += Marshal.dump(space, w_value) else: raise NotImplementedError(type(w_obj)) return bytes @staticmethod def load(space, bytes, offset=0): byte = bytes[offset] if byte == Marshal.NIL: return space.w_nil, 1 elif byte == Marshal.TRUE: return space.w_true, 1 elif byte == Marshal.FALSE: return space.w_false, 1 elif byte == Marshal.FIXNUM: value, length = Marshal.bytes2integer(bytes, offset + 1) return space.newint(value), length elif byte == Marshal.FLOAT: count, length = Marshal.bytes2integer(bytes, offset + 1) chars = [] for i in range(length, length + count): chars.append(chr(bytes[offset + i])) return space.newfloat(float("".join(chars))), length elif byte == Marshal.ARRAY: count, skip = Marshal.bytes2integer(bytes, offset + 1) array = [] for i in range(0, count): assert skip > 0 element, l = Marshal.load(space, bytes, offset + skip) skip += l array.append(element) return space.newarray(array), skip elif byte == Marshal.SYMBOL: count, length = Marshal.bytes2integer(bytes, offset + 1) chars = [] for i in range(length, length + count): chars.append(chr(bytes[offset + i])) return space.newsymbol("".join(chars)), length + count elif byte == Marshal.IVAR: # TODO: fully interpret IVARS if bytes[offset + 1] == Marshal.STRING: count, length = Marshal.bytes2integer(bytes, offset + 2) encoding = 6 chars = [] # TODO: take encoding into consideration for i in range(length + 1, length + count + 1): chars.append(chr(bytes[offset + i])) return space.newstr_fromstr( "".join(chars)), count + length + encoding else: raise NotImplementedError(bytes[offset + 1]) elif byte == Marshal.HASH: count, skip = Marshal.bytes2integer(bytes, offset + 1) w_hash = space.newhash() for i in range(0, count): assert skip > 0 k, s = Marshal.load(space, bytes, offset + skip) skip += s assert skip > 0 v, s = Marshal.load(space, bytes, offset + skip) skip += s w_hash.method_subscript_assign(space, k, v) return w_hash, skip else: raise NotImplementedError(byte) @moduledef.function("dump") def method_dump(self, space, w_obj, w_io=None): bytes = [4, 8] bytes += Marshal.dump(space, w_obj) string = "".join([chr(byte) for byte in bytes]) if w_io is not None: assert isinstance(w_io, W_IOObject) w_io.ensure_not_closed(space) os.write(w_io.fd, string) return w_io else: return space.newstr_fromstr(string) @moduledef.function("load") @moduledef.function("restore") def method_load(self, space, w_obj): string = "" if isinstance(w_obj, W_IOObject): w_obj.ensure_not_closed(space) string = os.read(w_obj.fd, int(os.fstat(w_obj.fd).st_size)) elif isinstance(w_obj, W_StringObject): string = space.str_w(w_obj) else: raise space.error(space.w_TypeError, "instance of IO needed") if len(string) < 2: raise space.error(space.w_ArgumentError, "marshal data too short") bytes = [ord(string[i]) for i in range(0, len(string))] if int(bytes[0]) != Marshal.MAJOR_VERSION or int( bytes[1]) != Marshal.MINOR_VERSION: raise space.error( space.w_TypeError, "incompatible marshal file format (can't be read)\n" "format version %s.%s required; %s.%s given" % (Marshal.MAJOR_VERSION, Marshal.MINOR_VERSION, bytes[0], bytes[1])) return Marshal.load(space, bytes, 2)[0] # extract integer from marshalled byte array # least significant byte first @staticmethod def bytes2integer(bytes, offset): if bytes[offset] >= 252: value = 256 - bytes[offset + 1] for i in range(2, 256 - bytes[offset] + 1): value += (255 - bytes[offset + i]) * int(math.pow(256, i - 1)) return -value, 256 - bytes[offset] + 2 elif bytes[offset] > 0 and bytes[offset] < 6: value = bytes[offset + 1] for i in range(2, bytes[offset] + 1): value += bytes[offset + i] * int(math.pow(256, i - 1)) return value, bytes[offset] + 2 else: value = bytes[offset] if value == 0: return 0, 2 elif value > 127: return value - 251, 2 else: return value - 5, 2 # least significant byte first @staticmethod def integer2bytes(value): bytes = [] if value > 2**30 - 1: raise NotImplementedError("Bignum") if value > 2**24 - 1: bytes.append(4) bytes.append(value % 256) bytes.append((value >> 8) % 256) bytes.append((value >> 16) % 256) bytes.append((value >> 24) % 256) elif value > 2**16 - 1: bytes.append(3) bytes.append(value % 256) bytes.append((value >> 8) % 256) bytes.append((value >> 16) % 256) elif value > 255: bytes.append(2) bytes.append(value % 256) bytes.append((value >> 8) % 256) elif value > 122: bytes.append(1) bytes.append(value) elif value > 0: bytes.append(value + 5) elif value == 0: bytes.append(0) elif value > -124: bytes.append(251 + value) elif value > -257: bytes.append(0xff) bytes.append(256 + value) elif value > -(2**16 + 1): bytes.append(0xfe) bytes.append(value % 256) bytes.append((value >> 8) % 256) elif value > -(2**24 + 1): bytes.append(0xfd) bytes.append(value % 256) bytes.append((value >> 8) % 256) bytes.append((value >> 16) % 256) elif value > -(2**30 + 1): bytes.append(0xfc) bytes.append(value % 256) bytes.append((value >> 8) % 256) bytes.append((value >> 16) % 256) bytes.append((value >> 24) % 256) else: raise NotImplementedError("number too small") return bytes
class Signal(object): moduledef = ModuleDef("Signal", filepath=__file__) @moduledef.function("trap") def method_trap(self, args_w): pass