From 6175ca03be6d0d51359f9017123708987d0f5eb7 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 15 Aug 2007 23:23:39 +0000 Subject: add tag v1_8_5_91 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_5_91@13046 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_5/object.c | 2745 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2745 insertions(+) create mode 100644 ruby_1_8_5/object.c (limited to 'ruby_1_8_5/object.c') diff --git a/ruby_1_8_5/object.c b/ruby_1_8_5/object.c new file mode 100644 index 0000000000..787b860d5d --- /dev/null +++ b/ruby_1_8_5/object.c @@ -0,0 +1,2745 @@ +/********************************************************************** + + object.c - + + $Author: nobu $ + $Date: 2006/07/18 01:55:14 $ + created at: Thu Jul 15 12:01:24 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto + Copyright (C) 2000 Network Applied Communication Laboratory, Inc. + Copyright (C) 2000 Information-technology Promotion Agency, Japan + +**********************************************************************/ + +#include "ruby.h" +#include "st.h" +#include "util.h" +#include +#include +#include +#include + +VALUE rb_mKernel; +VALUE rb_cObject; +VALUE rb_cModule; +VALUE rb_cClass; +VALUE rb_cData; + +VALUE rb_cNilClass; +VALUE rb_cTrueClass; +VALUE rb_cFalseClass; +VALUE rb_cSymbol; + +static ID id_eq, id_eql, id_inspect, id_init_copy; + +/* + * call-seq: + * obj === other => true or false + * + * Case Equality---For class Object, effectively the same + * as calling #==, but typically overridden by descendents + * to provide meaningful semantics in case statements. + */ + +VALUE +rb_equal(obj1, obj2) + VALUE obj1, obj2; +{ + VALUE result; + + if (obj1 == obj2) return Qtrue; + result = rb_funcall(obj1, id_eq, 1, obj2); + if (RTEST(result)) return Qtrue; + return Qfalse; +} + +int +rb_eql(obj1, obj2) + VALUE obj1, obj2; +{ + return RTEST(rb_funcall(obj1, id_eql, 1, obj2)); +} + +/* + * call-seq: + * obj == other => true or false + * obj.equal?(other) => true or false + * obj.eql?(other) => true or false + * + * Equality---At the Object level, == returns + * true only if obj and other are the + * same object. Typically, this method is overridden in descendent + * classes to provide class-specific meaning. + * + * Unlike ==, the equal? method should never be + * overridden by subclasses: it is used to determine object identity + * (that is, a.equal?(b) iff a is the same + * object as b). + * + * The eql? method returns true if + obj and anObject have the + * same value. Used by Hash to test members for equality. + * For objects of class Object, eql? is + * synonymous with ==. Subclasses normally continue this + * tradition, but there are exceptions. Numeric types, for + * example, perform type conversion across ==, but not + * across eql?, so: + * + * 1 == 1.0 #=> true + * 1.eql? 1.0 #=> false + */ + +static VALUE +rb_obj_equal(obj1, obj2) + VALUE obj1, obj2; +{ + if (obj1 == obj2) return Qtrue; + return Qfalse; +} + +/* + * call-seq: + * obj.id => fixnum + * + * Soon-to-be deprecated version of Object#object_id. + */ + +VALUE +rb_obj_id_obsolete(obj) + VALUE obj; +{ + rb_warn("Object#id will be deprecated; use Object#object_id"); + return rb_obj_id(obj); +} + +VALUE +rb_class_real(cl) + VALUE cl; +{ + while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) { + cl = RCLASS(cl)->super; + } + return cl; +} + +/* + * call-seq: + * obj.type => class + * + * Deprecated synonym for Object#class. + */ + +VALUE +rb_obj_type(obj) + VALUE obj; +{ + rb_warn("Object#type is deprecated; use Object#class"); + return rb_class_real(CLASS_OF(obj)); +} + + +/* + * call-seq: + * obj.class => class + * + * Returns the class of obj, now preferred over + * Object#type, as an object's type in Ruby is only + * loosely tied to that object's class. This method must always be + * called with an explicit receiver, as class is also a + * reserved word in Ruby. + * + * 1.class #=> Fixnum + * self.class #=> Object + */ + +VALUE +rb_obj_class(obj) + VALUE obj; +{ + return rb_class_real(CLASS_OF(obj)); +} + +static void +init_copy(dest, obj) + VALUE dest, obj; +{ + if (OBJ_FROZEN(dest)) { + rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); + } + RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); + RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT); + if (FL_TEST(obj, FL_EXIVAR)) { + rb_copy_generic_ivar(dest, obj); + } + rb_gc_copy_finalizer(dest, obj); + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (ROBJECT(dest)->iv_tbl) { + st_free_table(ROBJECT(dest)->iv_tbl); + ROBJECT(dest)->iv_tbl = 0; + } + if (ROBJECT(obj)->iv_tbl) { + ROBJECT(dest)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl); + } + } + rb_funcall(dest, id_init_copy, 1, obj); +} + +/* + * call-seq: + * obj.clone -> an_object + * + * Produces a shallow copy of obj---the instance variables of + * obj are copied, but not the objects they reference. Copies + * the frozen and tainted state of obj. See also the discussion + * under Object#dup. + * + * class Klass + * attr_accessor :str + * end + * s1 = Klass.new #=> # + * s1.str = "Hello" #=> "Hello" + * s2 = s1.clone #=> # + * s2.str[1,4] = "i" #=> "i" + * s1.inspect #=> "#" + * s2.inspect #=> "#" + * + * This method may have class-specific behavior. If so, that + * behavior will be documented under the #+initialize_copy+ method of + * the class. + */ + +VALUE +rb_obj_clone(obj) + VALUE obj; +{ + VALUE clone; + + if (rb_special_const_p(obj)) { + rb_raise(rb_eTypeError, "can't clone %s", rb_obj_classname(obj)); + } + clone = rb_obj_alloc(rb_obj_class(obj)); + RBASIC(clone)->klass = rb_singleton_class_clone(obj); + RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT)) & ~(FL_FREEZE|FL_FINALIZE); + init_copy(clone, obj); + RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; + + return clone; +} + +/* + * call-seq: + * obj.dup -> an_object + * + * Produces a shallow copy of obj---the instance variables of + * obj are copied, but not the objects they reference. + * dup copies the tainted state of obj. See also + * the discussion under Object#clone. In general, + * clone and dup may have different semantics + * in descendent classes. While clone is used to duplicate + * an object, including its internal state, dup typically + * uses the class of the descendent object to create the new instance. + * + * This method may have class-specific behavior. If so, that + * behavior will be documented under the #+initialize_copy+ method of + * the class. + */ + +VALUE +rb_obj_dup(obj) + VALUE obj; +{ + VALUE dup; + + if (rb_special_const_p(obj)) { + rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj)); + } + dup = rb_obj_alloc(rb_obj_class(obj)); + init_copy(dup, obj); + + return dup; +} + +/* :nodoc: */ +VALUE +rb_obj_init_copy(obj, orig) + VALUE obj, orig; +{ + if (obj == orig) return obj; + rb_check_frozen(obj); + if (TYPE(obj) != TYPE(orig) || rb_obj_class(obj) != rb_obj_class(orig)) { + rb_raise(rb_eTypeError, "initialize_copy should take same class object"); + } + return obj; +} + +/* + * call-seq: + * obj.to_a -> anArray + * + * Returns an array representation of obj. For objects of class + * Object and others that don't explicitly override the + * method, the return value is an array containing self. + * However, this latter behavior will soon be obsolete. + * + * self.to_a #=> -:1: warning: default `to_a' will be obsolete + * "hello".to_a #=> ["hello"] + * Time.new.to_a #=> [39, 54, 8, 9, 4, 2003, 3, 99, true, "CDT"] + */ + + +static VALUE +rb_any_to_a(obj) + VALUE obj; +{ + rb_warn("default `to_a' will be obsolete"); + return rb_ary_new3(1, obj); +} + + +/* + * call-seq: + * obj.to_s => string + * + * Returns a string representing obj. The default + * to_s prints the object's class and an encoding of the + * object id. As a special case, the top-level object that is the + * initial execution context of Ruby programs returns ``main.'' + */ + +VALUE +rb_any_to_s(obj) + VALUE obj; +{ + char *cname = rb_obj_classname(obj); + size_t len; + VALUE str; + + len = strlen(cname)+6+16; + str = rb_str_new(0, len); /* 6:tags 16:addr */ + snprintf(RSTRING(str)->ptr, len+1, "#<%s:0x%lx>", cname, obj); + RSTRING(str)->len = strlen(RSTRING(str)->ptr); + if (OBJ_TAINTED(obj)) OBJ_TAINT(str); + + return str; +} + +VALUE +rb_inspect(obj) + VALUE obj; +{ + return rb_obj_as_string(rb_funcall(obj, id_inspect, 0, 0)); +} + +static int +inspect_i(id, value, str) + ID id; + VALUE value; + VALUE str; +{ + VALUE str2; + char *ivname; + + /* need not to show internal data */ + if (CLASS_OF(value) == 0) return ST_CONTINUE; + if (!rb_is_instance_id(id)) return ST_CONTINUE; + if (RSTRING(str)->ptr[0] == '-') { /* first element */ + RSTRING(str)->ptr[0] = '#'; + rb_str_cat2(str, " "); + } + else { + rb_str_cat2(str, ", "); + } + ivname = rb_id2name(id); + rb_str_cat2(str, ivname); + rb_str_cat2(str, "="); + str2 = rb_inspect(value); + rb_str_append(str, str2); + OBJ_INFECT(str, str2); + + return ST_CONTINUE; +} + +static VALUE +inspect_obj(obj, str) + VALUE obj, str; +{ + st_foreach_safe(ROBJECT(obj)->iv_tbl, inspect_i, str); + rb_str_cat2(str, ">"); + RSTRING(str)->ptr[0] = '#'; + OBJ_INFECT(str, obj); + + return str; +} + +/* + * call-seq: + * obj.inspect => string + * + * Returns a string containing a human-readable representation of + * obj. If not overridden, uses the to_s method to + * generate the string. + * + * [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]" + * Time.new.inspect #=> "Wed Apr 09 08:54:39 CDT 2003" + */ + + +static VALUE +rb_obj_inspect(obj) + VALUE obj; +{ + if (TYPE(obj) == T_OBJECT + && ROBJECT(obj)->iv_tbl + && ROBJECT(obj)->iv_tbl->num_entries > 0) { + VALUE str; + size_t len; + char *c; + + c = rb_obj_classname(obj); + if (rb_inspecting_p(obj)) { + len = strlen(c)+10+16+1; + str = rb_str_new(0, len); /* 10:tags 16:addr 1:nul */ + snprintf(RSTRING(str)->ptr, len, "#<%s:0x%lx ...>", c, obj); + RSTRING(str)->len = strlen(RSTRING(str)->ptr); + return str; + } + len = strlen(c)+6+16+1; + str = rb_str_new(0, len); /* 6:tags 16:addr 1:nul */ + snprintf(RSTRING(str)->ptr, len, "-<%s:0x%lx", c, obj); + RSTRING(str)->len = strlen(RSTRING(str)->ptr); + return rb_protect_inspect(inspect_obj, obj, str); + } + return rb_funcall(obj, rb_intern("to_s"), 0, 0); +} + + +/* + * call-seq: + * obj.instance_of?(class) => true or false + * + * Returns true if obj is an instance of the given + * class. See also Object#kind_of?. + */ + +VALUE +rb_obj_is_instance_of(obj, c) + VALUE obj, c; +{ + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + case T_ICLASS: + break; + default: + rb_raise(rb_eTypeError, "class or module required"); + } + + if (rb_obj_class(obj) == c) return Qtrue; + return Qfalse; +} + + +/* + * call-seq: + * obj.is_a?(class) => true or false + * obj.kind_of?(class) => true or false + * + * Returns true if class is the class of + * obj, or if class is one of the superclasses of + * obj or modules included in obj. + * + * module M; end + * class A + * include M + * end + * class B < A; end + * class C < B; end + * b = B.new + * b.instance_of? A #=> false + * b.instance_of? B #=> true + * b.instance_of? C #=> false + * b.instance_of? M #=> false + * b.kind_of? A #=> true + * b.kind_of? B #=> true + * b.kind_of? C #=> false + * b.kind_of? M #=> true + */ + +VALUE +rb_obj_is_kind_of(obj, c) + VALUE obj, c; +{ + VALUE cl = CLASS_OF(obj); + + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + case T_ICLASS: + break; + + default: + rb_raise(rb_eTypeError, "class or module required"); + } + + while (cl) { + if (cl == c || RCLASS(cl)->m_tbl == RCLASS(c)->m_tbl) + return Qtrue; + cl = RCLASS(cl)->super; + } + return Qfalse; +} + + +/* + * Document-method: singleton_method_added + * + * call-seq: + * singleton_method_added(symbol) + * + * Invoked as a callback whenever a singleton method is added to the + * receiver. + * + * module Chatty + * def Chatty.singleton_method_added(id) + * puts "Adding #{id.id2name}" + * end + * def self.one() end + * def two() end + * def Chatty.three() end + * end + * + * produces: + * + * Adding singleton_method_added + * Adding one + * Adding three + * + */ + +/* + * Document-method: singleton_method_removed + * + * call-seq: + * singleton_method_removed(symbol) + * + * Invoked as a callback whenever a singleton method is removed from + * the receiver. + * + * module Chatty + * def Chatty.singleton_method_removed(id) + * puts "Removing #{id.id2name}" + * end + * def self.one() end + * def two() end + * def Chatty.three() end + * class <produces: + * + * Removing three + * Removing one + */ + +/* + * Document-method: singleton_method_undefined + * + * call-seq: + * singleton_method_undefined(symbol) + * + * Invoked as a callback whenever a singleton method is undefined in + * the receiver. + * + * module Chatty + * def Chatty.singleton_method_undefined(id) + * puts "Undefining #{id.id2name}" + * end + * def Chatty.one() end + * class << self + * undef_method(:one) + * end + * end + * + * produces: + * + * Undefining one + */ + + +/* + * Document-method: included + * + * call-seq: + * included( othermod ) + * + * Callback invoked whenever the receiver is included in another + * module or class. This should be used in preference to + * Module.append_features if your code wants to perform some + * action when a module is included in another. + * + * module A + * def A.included(mod) + * puts "#{self} included in #{mod}" + * end + * end + * module Enumerable + * include A + * end + */ + + +/* + * Not documented + */ + +static VALUE +rb_obj_dummy() +{ + return Qnil; +} + + +/* + * call-seq: + * obj.tainted? => true or false + * + * Returns true if the object is tainted. + */ + +VALUE +rb_obj_tainted(obj) + VALUE obj; +{ + if (OBJ_TAINTED(obj)) + return Qtrue; + return Qfalse; +} + +/* + * call-seq: + * obj.taint -> obj + * + * Marks obj as tainted---if the $SAFE level is + * set appropriately, many method calls which might alter the running + * programs environment will refuse to accept tainted strings. + */ + +VALUE +rb_obj_taint(obj) + VALUE obj; +{ + rb_secure(4); + if (!OBJ_TAINTED(obj)) { + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + OBJ_TAINT(obj); + } + return obj; +} + + +/* + * call-seq: + * obj.untaint => obj + * + * Removes the taint from obj. + */ + +VALUE +rb_obj_untaint(obj) + VALUE obj; +{ + rb_secure(3); + if (OBJ_TAINTED(obj)) { + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + FL_UNSET(obj, FL_TAINT); + } + return obj; +} + +void +rb_obj_infect(obj1, obj2) + VALUE obj1, obj2; +{ + OBJ_INFECT(obj1, obj2); +} + + +/* + * call-seq: + * obj.freeze => obj + * + * Prevents further modifications to obj. A + * TypeError will be raised if modification is attempted. + * There is no way to unfreeze a frozen object. See also + * Object#frozen?. + * + * a = [ "a", "b", "c" ] + * a.freeze + * a << "z" + * + * produces: + * + * prog.rb:3:in `<<': can't modify frozen array (TypeError) + * from prog.rb:3 + */ + +VALUE +rb_obj_freeze(obj) + VALUE obj; +{ + if (!OBJ_FROZEN(obj)) { + if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) { + rb_raise(rb_eSecurityError, "Insecure: can't freeze object"); + } + OBJ_FREEZE(obj); + } + return obj; +} + +/* + * call-seq: + * obj.frozen? => true or false + * + * Returns the freeze status of obj. + * + * a = [ "a", "b", "c" ] + * a.freeze #=> ["a", "b", "c"] + * a.frozen? #=> true + */ + +static VALUE +rb_obj_frozen_p(obj) + VALUE obj; +{ + if (OBJ_FROZEN(obj)) return Qtrue; + return Qfalse; +} + + +/* + * Document-class: NilClass + * + * The class of the singleton object nil. + */ + +/* + * call-seq: + * nil.to_i => 0 + * + * Always returns zero. + * + * nil.to_i #=> 0 + */ + + +static VALUE +nil_to_i(obj) + VALUE obj; +{ + return INT2FIX(0); +} + +/* + * call-seq: + * nil.to_f => 0.0 + * + * Always returns zero. + * + * nil.to_f #=> 0.0 + */ + +static VALUE +nil_to_f(obj) + VALUE obj; +{ + return rb_float_new(0.0); +} + +/* + * call-seq: + * nil.to_s => "" + * + * Always returns the empty string. + * + * nil.to_s #=> "" + */ + +static VALUE +nil_to_s(obj) + VALUE obj; +{ + return rb_str_new2(""); +} + +/* + * call-seq: + * nil.to_a => [] + * + * Always returns an empty array. + * + * nil.to_a #=> [] + */ + +static VALUE +nil_to_a(obj) + VALUE obj; +{ + return rb_ary_new2(0); +} + +/* + * call-seq: + * nil.inspect => "nil" + * + * Always returns the string "nil". + */ + +static VALUE +nil_inspect(obj) + VALUE obj; +{ + return rb_str_new2("nil"); +} + +#ifdef NIL_PLUS +static VALUE +nil_plus(x, y) + VALUE x, y; +{ + switch (TYPE(y)) { + case T_NIL: + case T_FIXNUM: + case T_FLOAT: + case T_BIGNUM: + case T_STRING: + case T_ARRAY: + return y; + default: + rb_raise(rb_eTypeError, "tried to add %s(%s) to nil", + RSTRING(rb_inspect(y))->ptr, + rb_obj_classname(y)); + } + /* not reached */ +} +#endif + +static VALUE +main_to_s(obj) + VALUE obj; +{ + return rb_str_new2("main"); +} + + +/*********************************************************************** + * Document-class: TrueClass + * + * The global value true is the only instance of class + * TrueClass and represents a logically true value in + * boolean expressions. The class provides operators allowing + * true to be used in logical expressions. + */ + + +/* + * call-seq: + * true.to_s => "true" + * + * The string representation of true is "true". + */ + +static VALUE +true_to_s(obj) + VALUE obj; +{ + return rb_str_new2("true"); +} + + +/* + * call-seq: + * true & obj => true or false + * + * And---Returns false if obj is + * nil or false, true otherwise. + */ + +static VALUE +true_and(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qtrue:Qfalse; +} + +/* + * call-seq: + * true | obj => true + * + * Or---Returns true. As anObject is an argument to + * a method call, it is always evaluated; there is no short-circuit + * evaluation in this case. + * + * true | puts("or") + * true || puts("logical or") + * + * produces: + * + * or + */ + +static VALUE +true_or(obj, obj2) + VALUE obj, obj2; +{ + return Qtrue; +} + + +/* + * call-seq: + * true ^ obj => !obj + * + * Exclusive Or---Returns true if obj is + * nil or false, false + * otherwise. + */ + +static VALUE +true_xor(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qfalse:Qtrue; +} + + +/* + * Document-class: FalseClass + * + * The global value false is the only instance of class + * FalseClass and represents a logically false value in + * boolean expressions. The class provides operators allowing + * false to participate correctly in logical expressions. + * + */ + +/* + * call-seq: + * false.to_s => "false" + * + * 'nuf said... + */ + +static VALUE +false_to_s(obj) + VALUE obj; +{ + return rb_str_new2("false"); +} + +/* + * call-seq: + * false & obj => false + * nil & obj => false + * + * And---Returns false. obj is always + * evaluated as it is the argument to a method call---there is no + * short-circuit evaluation in this case. + */ + +static VALUE +false_and(obj, obj2) + VALUE obj, obj2; +{ + return Qfalse; +} + + +/* + * call-seq: + * false | obj => true or false + * nil | obj => true or false + * + * Or---Returns false if obj is + * nil or false; true otherwise. + */ + +static VALUE +false_or(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qtrue:Qfalse; +} + + + +/* + * call-seq: + * false ^ obj => true or false + * nil ^ obj => true or false + * + * Exclusive Or---If obj is nil or + * false, returns false; otherwise, returns + * true. + * + */ + +static VALUE +false_xor(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qtrue:Qfalse; +} + +/* + * call_seq: + * nil.nil? => true + * + * Only the object nil responds true to nil?. + */ + +static VALUE +rb_true(obj) + VALUE obj; +{ + return Qtrue; +} + +/* + * call_seq: + * nil.nil? => true + * .nil? => false + * + * Only the object nil responds true to nil?. + */ + + +static VALUE +rb_false(obj) + VALUE obj; +{ + return Qfalse; +} + + +/* + * call-seq: + * obj =~ other => false + * + * Pattern Match---Overridden by descendents (notably + * Regexp and String) to provide meaningful + * pattern-match semantics. + */ + +static VALUE +rb_obj_pattern_match(obj1, obj2) + VALUE obj1, obj2; +{ + return Qfalse; +} + +/********************************************************************** + * Document-class: Symbol + * + * Symbol objects represent names and some strings + * inside the Ruby + * interpreter. They are generated using the :name and + * :"string" literals + * syntax, and by the various to_sym methods. The same + * Symbol object will be created for a given name or string + * for the duration of a program's execution, regardless of the context + * or meaning of that name. Thus if Fred is a constant in + * one context, a method in another, and a class in a third, the + * Symbol :Fred will be the same object in + * all three contexts. + * + * module One + * class Fred + * end + * $f1 = :Fred + * end + * module Two + * Fred = 1 + * $f2 = :Fred + * end + * def Fred() + * end + * $f3 = :Fred + * $f1.id #=> 2514190 + * $f2.id #=> 2514190 + * $f3.id #=> 2514190 + * + */ + +/* + * call-seq: + * sym.to_i => fixnum + * + * Returns an integer that is unique for each symbol within a + * particular execution of a program. + * + * :fred.to_i #=> 9809 + * "fred".to_sym.to_i #=> 9809 + */ + +static VALUE +sym_to_i(sym) + VALUE sym; +{ + ID id = SYM2ID(sym); + + return LONG2FIX(id); +} + + +/* :nodoc: */ + +static VALUE +sym_to_int(sym) + VALUE sym; +{ + rb_warning("treating Symbol as an integer"); + return sym_to_i(sym); +} + + +/* + * call-seq: + * sym.inspect => string + * + * Returns the representation of sym as a symbol literal. + * + * :fred.inspect #=> ":fred" + */ + +static VALUE +sym_inspect(sym) + VALUE sym; +{ + VALUE str; + char *name; + ID id = SYM2ID(sym); + + name = rb_id2name(id); + str = rb_str_new(0, strlen(name)+1); + RSTRING(str)->ptr[0] = ':'; + strcpy(RSTRING(str)->ptr+1, name); + if (!rb_symname_p(name)) { + str = rb_str_dump(str); + strncpy(RSTRING(str)->ptr, ":\"", 2); + } + return str; +} + + +/* + * call-seq: + * sym.id2name => string + * sym.to_s => string + * + * Returns the name or string corresponding to sym. + * + * :fred.id2name #=> "fred" + */ + + +static VALUE +sym_to_s(sym) + VALUE sym; +{ + return rb_str_new2(rb_id2name(SYM2ID(sym))); +} + + +/* + * call-seq: + * sym.to_sym => sym + * + * In general, to_sym returns the Symbol corresponding + * to an object. As sym is already a symbol, self is returned + * in this case. + */ + +static VALUE +sym_to_sym(sym) + VALUE sym; +{ + return sym; +} + + +/*********************************************************************** + * + * Document-class: Module + * + * A Module is a collection of methods and constants. The + * methods in a module may be instance methods or module methods. + * Instance methods appear as methods in a class when the module is + * included, module methods do not. Conversely, module methods may be + * called without creating an encapsulating object, while instance + * methods may not. (See Module#module_function) + * + * In the descriptions that follow, the parameter syml refers + * to a symbol, which is either a quoted string or a + * Symbol (such as :name). + * + * module Mod + * include Math + * CONST = 1 + * def meth + * # ... + * end + * end + * Mod.class #=> Module + * Mod.constants #=> ["E", "PI", "CONST"] + * Mod.instance_methods #=> ["meth"] + * + */ + +/* + * call-seq: + * mod.to_s => string + * + * Return a string representing this module or class. For basic + * classes and modules, this is the name. For singletons, we + * show information on the thing we're attached to as well. + */ + +static VALUE +rb_mod_to_s(klass) + VALUE klass; + +{ + if (FL_TEST(klass, FL_SINGLETON)) { + VALUE s = rb_str_new2("#<"); + VALUE v = rb_iv_get(klass, "__attached__"); + + rb_str_cat2(s, "Class:"); + switch (TYPE(v)) { + case T_CLASS: case T_MODULE: + rb_str_append(s, rb_inspect(v)); + break; + default: + rb_str_append(s, rb_any_to_s(v)); + break; + } + rb_str_cat2(s, ">"); + + return s; + } + return rb_str_dup(rb_class_name(klass)); +} + +/* + * call-seq: + * mod.freeze + * + * Prevents further modifications to mod. + */ + +static VALUE +rb_mod_freeze(mod) + VALUE mod; +{ + rb_mod_to_s(mod); + return rb_obj_freeze(mod); +} + +/* + * call-seq: + * mod === obj => true or false + * + * Case Equality---Returns true if anObject is an + * instance of mod or one of mod's descendents. Of + * limited use for modules, but can be used in case + * statements to classify objects by class. + */ + +static VALUE +rb_mod_eqq(mod, arg) + VALUE mod, arg; +{ + return rb_obj_is_kind_of(arg, mod); +} + +/* + * call-seq: + * mod <= other => true, false, or nil + * + * Returns true if mod is a subclass of other or + * is the same as other. Returns + * nil if there's no relationship between the two. + * (Think of the relationship in terms of the class definition: + * "class Am_tbl == RCLASS(arg)->m_tbl) + return Qtrue; + mod = RBASIC(mod)->klass; + } + while (mod) { + if (RCLASS(mod)->m_tbl == RCLASS(arg)->m_tbl) + return Qtrue; + mod = RCLASS(mod)->super; + } + /* not mod < arg; check if mod > arg */ + while (arg) { + if (RCLASS(arg)->m_tbl == RCLASS(start)->m_tbl) + return Qfalse; + arg = RCLASS(arg)->super; + } + return Qnil; +} + +/* + * call-seq: + * mod < other => true, false, or nil + * + * Returns true if mod is a subclass of other. Returns + * nil if there's no relationship between the two. + * (Think of the relationship in terms of the class definition: + * "class A= other => true, false, or nil + * + * Returns true if mod is an ancestor of other, or the + * two modules are the same. Returns + * nil if there's no relationship between the two. + * (Think of the relationship in terms of the class definition: + * "class AA"). + * + */ + +static VALUE +rb_mod_ge(mod, arg) + VALUE mod, arg; +{ + switch (TYPE(arg)) { + case T_MODULE: + case T_CLASS: + break; + default: + rb_raise(rb_eTypeError, "compared with non class/module"); + } + + return rb_class_inherited_p(arg, mod); +} + +/* + * call-seq: + * mod > other => true, false, or nil + * + * Returns true if mod is an ancestor of other. Returns + * nil if there's no relationship between the two. + * (Think of the relationship in terms of the class definition: + * "class AA"). + * + */ + +static VALUE +rb_mod_gt(mod, arg) + VALUE mod, arg; +{ + if (mod == arg) return Qfalse; + return rb_mod_ge(mod, arg); +} + +/* + * call-seq: + * mod <=> other_mod => -1, 0, +1, or nil + * + * Comparison---Returns -1 if mod includes other_mod, 0 if + * mod is the same as other_mod, and +1 if mod is + * included by other_mod or if mod has no relationship with + * other_mod. Returns nil if other_mod is + * not a module. + */ + +static VALUE +rb_mod_cmp(mod, arg) + VALUE mod, arg; +{ + VALUE cmp; + + if (mod == arg) return INT2FIX(0); + switch (TYPE(arg)) { + case T_MODULE: + case T_CLASS: + break; + default: + return Qnil; + } + + cmp = rb_class_inherited_p(mod, arg); + if (NIL_P(cmp)) return Qnil; + if (cmp) { + return INT2FIX(-1); + } + return INT2FIX(1); +} + +static VALUE rb_module_s_alloc _((VALUE)); +static VALUE +rb_module_s_alloc(klass) + VALUE klass; +{ + VALUE mod = rb_module_new(); + + RBASIC(mod)->klass = klass; + return mod; +} + +static VALUE rb_class_s_alloc _((VALUE)); +static VALUE +rb_class_s_alloc(klass) + VALUE klass; +{ + return rb_class_boot(0); +} + +/* + * call-seq: + * Module.new => mod + * Module.new {|mod| block } => mod + * + * Creates a new anonymous module. If a block is given, it is passed + * the module object, and the block is evaluated in the context of this + * module using module_eval. + * + * Fred = Module.new do + * def meth1 + * "hello" + * end + * def meth2 + * "bye" + * end + * end + * a = "my string" + * a.extend(Fred) #=> "my string" + * a.meth1 #=> "hello" + * a.meth2 #=> "bye" + */ + +static VALUE +rb_mod_initialize(module) + VALUE module; +{ + if (rb_block_given_p()) { + rb_mod_module_eval(0, 0, module); + } + return Qnil; +} + +/* + * call-seq: + * Class.new(super_class=Object) => a_class + * + * Creates a new anonymous (unnamed) class with the given superclass + * (or Object if no parameter is given). You can give a + * class a name by assigning the class object to a constant. + * + */ + +static VALUE +rb_class_initialize(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + VALUE super; + + if (RCLASS(klass)->super != 0) { + rb_raise(rb_eTypeError, "already initialized class"); + } + if (rb_scan_args(argc, argv, "01", &super) == 0) { + super = rb_cObject; + } + else { + rb_check_inheritable(super); + } + RCLASS(klass)->super = super; + rb_make_metaclass(klass, RBASIC(super)->klass); + rb_mod_initialize(klass); + rb_class_inherited(super, klass); + + return klass; +} + +/* + * call-seq: + * class.allocate() => obj + * + * Allocates space for a new object of class's class. The + * returned object must be an instance of class. + * + */ + +VALUE +rb_obj_alloc(klass) + VALUE klass; +{ + VALUE obj; + + if (RCLASS(klass)->super == 0) { + rb_raise(rb_eTypeError, "can't instantiate uninitialized class"); + } + if (FL_TEST(klass, FL_SINGLETON)) { + rb_raise(rb_eTypeError, "can't create instance of virtual class"); + } + obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0); + if (rb_obj_class(obj) != rb_class_real(klass)) { + rb_raise(rb_eTypeError, "wrong instance allocation"); + } + return obj; +} + +static VALUE rb_class_allocate_instance _((VALUE)); +static VALUE +rb_class_allocate_instance(klass) + VALUE klass; +{ + NEWOBJ(obj, struct RObject); + OBJSETUP(obj, klass, T_OBJECT); + return (VALUE)obj; +} + +/* + * call-seq: + * class.new(args, ...) => obj + * + * Calls allocate to create a new object of + * class's class, then invokes that object's + * initialize method, passing it args. + * This is the method that ends up getting called whenever + * an object is constructed using .new. + * + */ + +VALUE +rb_class_new_instance(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + VALUE obj; + + obj = rb_obj_alloc(klass); + rb_obj_call_init(obj, argc, argv); + + return obj; +} + +/* + * call-seq: + * class.superclass -> a_super_class or nil + * + * Returns the superclass of class, or nil. + * + * File.superclass #=> IO + * IO.superclass #=> Object + * Object.superclass #=> nil + * + */ + +static VALUE +rb_class_superclass(klass) + VALUE klass; +{ + VALUE super = RCLASS(klass)->super; + + if (!super) { + rb_raise(rb_eTypeError, "uninitialized class"); + } + if (FL_TEST(klass, FL_SINGLETON)) { + super = RBASIC(klass)->klass; + } + while (TYPE(super) == T_ICLASS) { + super = RCLASS(super)->super; + } + if (!super) { + return Qnil; + } + return super; +} + +static ID +str_to_id(str) + VALUE str; +{ + if (!RSTRING(str)->ptr || RSTRING(str)->len == 0) { + rb_raise(rb_eArgError, "empty symbol string"); + } + if (RSTRING(str)->len != strlen(RSTRING(str)->ptr)) { + rb_warn("Symbols should not contain NUL (\\0)"); + } + return rb_intern(RSTRING(str)->ptr); +} + +ID +rb_to_id(name) + VALUE name; +{ + VALUE tmp; + ID id; + + switch (TYPE(name)) { + case T_STRING: + return str_to_id(name); + case T_FIXNUM: + rb_warn("do not use Fixnums as Symbols"); + id = FIX2LONG(name); + if (!rb_id2name(id)) { + rb_raise(rb_eArgError, "%ld is not a symbol", id); + } + break; + case T_SYMBOL: + id = SYM2ID(name); + break; + default: + tmp = rb_check_string_type(name); + if (!NIL_P(tmp)) { + return str_to_id(tmp); + } + rb_raise(rb_eTypeError, "%s is not a symbol", RSTRING(rb_inspect(name))->ptr); + } + return id; +} + +/* + * call-seq: + * attr(symbol, writable=false) => nil + * + * Defines a named attribute for this module, where the name is + * symbol.id2name, creating an instance variable + * (@name) and a corresponding access method to read it. + * If the optional writable argument is true, also + * creates a method called name= to set the attribute. + * + * module Mod + * attr :size, true + * end + * + * is equivalent to: + * + * module Mod + * def size + * @size + * end + * def size=(val) + * @size = val + * end + * end + */ + +static VALUE +rb_mod_attr(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + VALUE name, pub; + + rb_scan_args(argc, argv, "11", &name, &pub); + rb_attr(klass, rb_to_id(name), 1, RTEST(pub), Qtrue); + return Qnil; +} + +/* + * call-seq: + * attr_reader(symbol, ...) => nil + * + * Creates instance variables and corresponding methods that return the + * value of each instance variable. Equivalent to calling + * ``attr:name'' on each name in turn. + */ + +static VALUE +rb_mod_attr_reader(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + int i; + + for (i=0; i nil + * + * Creates an accessor method to allow assignment to the attribute + * aSymbol.id2name. + */ + +static VALUE +rb_mod_attr_writer(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + int i; + + for (i=0; i nil + * + * Equivalent to calling ``attrsymbol, + * true'' on each symbol in turn. + * + * module Mod + * attr_accessor(:one, :two) + * end + * Mod.instance_methods.sort #=> ["one", "one=", "two", "two="] + */ + +static VALUE +rb_mod_attr_accessor(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + int i; + + for (i=0; i obj + * + * Returns the value of the named constant in mod. + * + * Math.const_get(:PI) #=> 3.14159265358979 + */ + +static VALUE +rb_mod_const_get(mod, name) + VALUE mod, name; +{ + ID id = rb_to_id(name); + + if (!rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + } + return rb_const_get(mod, id); +} + +/* + * call-seq: + * mod.const_set(sym, obj) => obj + * + * Sets the named constant to the given object, returning that object. + * Creates a new constant if no constant with the given name previously + * existed. + * + * Math.const_set("HIGH_SCHOOL_PI", 22.0/7.0) #=> 3.14285714285714 + * Math::HIGH_SCHOOL_PI - Math::PI #=> 0.00126448926734968 + */ + +static VALUE +rb_mod_const_set(mod, name, value) + VALUE mod, name, value; +{ + ID id = rb_to_id(name); + + if (!rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + } + rb_const_set(mod, id, value); + return value; +} + +/* + * call-seq: + * mod.const_defined?(sym) => true or false + * + * Returns true if a constant with the given name is + * defined by mod. + * + * Math.const_defined? "PI" #=> true + */ + +static VALUE +rb_mod_const_defined(mod, name) + VALUE mod, name; +{ + ID id = rb_to_id(name); + + if (!rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + } + return rb_const_defined_at(mod, id); +} + +/* + * call-seq: + * obj.methods => array + * + * Returns a list of the names of methods publicly accessible in + * obj. This will include all the methods accessible in + * obj's ancestors. + * + * class Klass + * def kMethod() + * end + * end + * k = Klass.new + * k.methods[0..9] #=> ["kMethod", "freeze", "nil?", "is_a?", + * "class", "instance_variable_set", + * "methods", "extend", "__send__", "instance_eval"] + * k.methods.length #=> 42 + */ + + +static VALUE +rb_obj_methods(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + retry: + if (argc == 0) { + VALUE args[1]; + + args[0] = Qtrue; + return rb_class_instance_methods(1, args, CLASS_OF(obj)); + } + else { + VALUE recur; + + rb_scan_args(argc, argv, "1", &recur); + if (RTEST(recur)) { + argc = 0; + goto retry; + } + return rb_obj_singleton_methods(argc, argv, obj); + } +} + +/* + * call-seq: + * obj.protected_methods(all=true) => array + * + * Returns the list of protected methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ + +static VALUE +rb_obj_protected_methods(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + if (argc == 0) { /* hack to stop warning */ + VALUE args[1]; + + args[0] = Qtrue; + return rb_class_protected_instance_methods(1, args, CLASS_OF(obj)); + } + return rb_class_protected_instance_methods(argc, argv, CLASS_OF(obj)); +} + +/* + * call-seq: + * obj.private_methods(all=true) => array + * + * Returns the list of private methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ + +static VALUE +rb_obj_private_methods(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + if (argc == 0) { /* hack to stop warning */ + VALUE args[1]; + + args[0] = Qtrue; + return rb_class_private_instance_methods(1, args, CLASS_OF(obj)); + } + return rb_class_private_instance_methods(argc, argv, CLASS_OF(obj)); +} + +/* + * call-seq: + * obj.public_methods(all=true) => array + * + * Returns the list of public methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ + +static VALUE +rb_obj_public_methods(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + if (argc == 0) { /* hack to stop warning */ + VALUE args[1]; + + args[0] = Qtrue; + return rb_class_public_instance_methods(1, args, CLASS_OF(obj)); + } + return rb_class_public_instance_methods(argc, argv, CLASS_OF(obj)); +} + +/* + * call-seq: + * obj.instance_variable_get(symbol) => obj + * + * Returns the value of the given instance variable (or throws a + * NameError exception). The @ part of the + * variable name should be included for regular instance variables + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_get(:@a) #=> "cat" + * fred.instance_variable_get("@b") #=> 99 + */ + +static VALUE +rb_obj_ivar_get(obj, iv) + VALUE obj, iv; +{ + ID id = rb_to_id(iv); + + if (!rb_is_instance_id(id)) { + rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); + } + return rb_ivar_get(obj, id); +} + + +/* + * call-seq: + * obj.instance_variable_set(symbol, obj) => obj + * + * Sets the instance variable names by symbol to + * object, thereby frustrating the efforts of the class's + * author to attempt to provide proper encapsulation. The variable + * did not have to exist prior to this call. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_set(:@a, 'dog') #=> "dog" + * fred.instance_variable_set(:@c, 'cat') #=> "cat" + * fred.inspect #=> "#" + */ + +static VALUE +rb_obj_ivar_set(obj, iv, val) + VALUE obj, iv, val; +{ + ID id = rb_to_id(iv); + + if (!rb_is_instance_id(id)) { + rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); + } + return rb_ivar_set(obj, id, val); +} + +/* + * call-seq: + * mod.class_variable_get(symbol) => obj + * + * Returns the value of the given class variable (or throws a + * NameError exception). The @@ part of the + * variable name should be included for regular class variables + * + * class Fred + * @@foo = 99 + * end + * + * def Fred.foo + * class_variable_get(:@@foo) #=> 99 + * end + */ + +static VALUE +rb_mod_cvar_get(obj, iv) + VALUE obj, iv; +{ + ID id = rb_to_id(iv); + + if (!rb_is_class_id(id)) { + rb_name_error(id, "`%s' is not allowed as an class variable name", rb_id2name(id)); + } + return rb_cvar_get(obj, id); +} + + +/* + * call-seq: + * obj.class_variable_set(symbol, obj) => obj + * + * Sets the class variable names by symbol to + * object. + * + * class Fred + * @@foo = 99 + * def foo + * @@foo + * end + * end + * + * def Fred.foo + * class_variable_set(:@@foo, 101) #=> 101 + * end + * Fred.foo + * Fred.new.foo #=> 101 + */ + +static VALUE +rb_mod_cvar_set(obj, iv, val) + VALUE obj, iv, val; +{ + ID id = rb_to_id(iv); + + if (!rb_is_class_id(id)) { + rb_name_error(id, "`%s' is not allowed as an class variable name", rb_id2name(id)); + } + rb_cvar_set(obj, id, val, Qfalse); + return val; +} + +static VALUE +convert_type(val, tname, method, raise) + VALUE val; + const char *tname, *method; + int raise; +{ + ID m; + + m = rb_intern(method); + if (!rb_respond_to(val, m)) { + if (raise) { + rb_raise(rb_eTypeError, "can't convert %s into %s", + NIL_P(val) ? "nil" : + val == Qtrue ? "true" : + val == Qfalse ? "false" : + rb_obj_classname(val), + tname); + } + else { + return Qnil; + } + } + return rb_funcall(val, m, 0); +} + +VALUE +rb_convert_type(val, type, tname, method) + VALUE val; + int type; + const char *tname, *method; +{ + VALUE v; + + if (TYPE(val) == type) return val; + v = convert_type(val, tname, method, Qtrue); + if (TYPE(v) != type) { + rb_raise(rb_eTypeError, "%s#%s should return %s", + rb_obj_classname(val), method, tname); + } + return v; +} + +VALUE +rb_check_convert_type(val, type, tname, method) + VALUE val; + int type; + const char *tname, *method; +{ + VALUE v; + + /* always convert T_DATA */ + if (TYPE(val) == type && type != T_DATA) return val; + v = convert_type(val, tname, method, Qfalse); + if (NIL_P(v)) return Qnil; + if (TYPE(v) != type) { + rb_raise(rb_eTypeError, "%s#%s should return %s", + rb_obj_classname(val), method, tname); + } + return v; +} + + +static VALUE +rb_to_integer(val, method) + VALUE val; + const char *method; +{ + VALUE v = convert_type(val, "Integer", method, Qtrue); + if (!rb_obj_is_kind_of(v, rb_cInteger)) { + rb_raise(rb_eTypeError, "%s#%s should return Integer", + rb_obj_classname(val), method); + } + return v; +} + +VALUE +rb_to_int(val) + VALUE val; +{ + return rb_to_integer(val, "to_int"); +} + +VALUE +rb_Integer(val) + VALUE val; +{ + VALUE tmp; + + switch (TYPE(val)) { + case T_FLOAT: + if (RFLOAT(val)->value <= (double)FIXNUM_MAX + && RFLOAT(val)->value >= (double)FIXNUM_MIN) { + break; + } + return rb_dbl2big(RFLOAT(val)->value); + + case T_FIXNUM: + case T_BIGNUM: + return val; + + case T_STRING: + return rb_str_to_inum(val, 0, Qtrue); + + default: + break; + } + tmp = convert_type(val, "Integer", "to_int", Qfalse); + if (NIL_P(tmp)) { + return rb_to_integer(val, "to_i"); + } + return tmp; +} + +/* + * call-seq: + * Integer(arg) => integer + * + * Converts arg to a Fixnum or Bignum. + * Numeric types are converted directly (with floating point numbers + * being truncated). If arg is a String, leading + * radix indicators (0, 0b, and + * 0x) are honored. Others are converted using + * to_int and to_i. This behavior is + * different from that of String#to_i. + * + * Integer(123.999) #=> 123 + * Integer("0x1a") #=> 26 + * Integer(Time.new) #=> 1049896590 + */ + +static VALUE +rb_f_integer(obj, arg) + VALUE obj, arg; +{ + return rb_Integer(arg); +} + +double +rb_cstr_to_dbl(p, badcheck) + const char *p; + int badcheck; +{ + const char *q; + char *end; + double d; + const char *ellipsis = ""; + int w; +#define OutOfRange() (((w = end - p) > 20) ? (w = 20, ellipsis = "...") : (ellipsis = "")) + + if (!p) return 0.0; + q = p; + if (badcheck) { + while (ISSPACE(*p)) p++; + } + else { + while (ISSPACE(*p) || *p == '_') p++; + } + d = strtod(p, &end); + if (errno == ERANGE) { + OutOfRange(); + rb_warn("Float %.*s%s out of range", w, p, ellipsis); + errno = 0; + } + if (p == end) { + if (badcheck) { + bad: + rb_invalid_str(q, "Float()"); + } + return d; + } + if (*end) { + char *buf = ALLOCA_N(char, strlen(p)+1); + char *n = buf; + + while (p < end) *n++ = *p++; + while (*p) { + if (*p == '_') { + /* remove underscores between digits */ + if (badcheck) { + if (n == buf || !ISDIGIT(n[-1])) goto bad; + ++p; + if (!ISDIGIT(*p)) goto bad; + } + else { + while (*++p == '_'); + continue; + } + } + *n++ = *p++; + } + *n = '\0'; + p = buf; + d = strtod(p, &end); + if (errno == ERANGE) { + OutOfRange(); + rb_warn("Float %.*s%s out of range", w, p, ellipsis); + errno = 0; + } + if (badcheck) { + if (!end || p == end) goto bad; + while (*end && ISSPACE(*end)) end++; + if (*end) goto bad; + } + } + if (errno == ERANGE) { + errno = 0; + OutOfRange(); + rb_raise(rb_eArgError, "Float %.*s%s out of range", w, q, ellipsis); + } + return d; +} + +double +rb_str_to_dbl(str, badcheck) + VALUE str; + int badcheck; +{ + char *s; + long len; + + StringValue(str); + s = RSTRING(str)->ptr; + len = RSTRING(str)->len; + if (s) { + if (s[len]) { /* no sentinel somehow */ + char *p = ALLOCA_N(char, len+1); + + MEMCPY(p, s, char, len); + p[len] = '\0'; + s = p; + } + if (badcheck && len != strlen(s)) { + rb_raise(rb_eArgError, "string for Float contains null byte"); + } + } + return rb_cstr_to_dbl(s, badcheck); +} + +VALUE +rb_Float(val) + VALUE val; +{ + switch (TYPE(val)) { + case T_FIXNUM: + return rb_float_new((double)FIX2LONG(val)); + + case T_FLOAT: + return val; + + case T_BIGNUM: + return rb_float_new(rb_big2dbl(val)); + + case T_STRING: + return rb_float_new(rb_str_to_dbl(val, Qtrue)); + + case T_NIL: + rb_raise(rb_eTypeError, "can't convert nil into Float"); + break; + + default: + { + VALUE f = rb_convert_type(val, T_FLOAT, "Float", "to_f"); + if (isnan(RFLOAT(f)->value)) { + rb_raise(rb_eArgError, "invalid value for Float()"); + } + return f; + } + } +} + +/* + * call-seq: + * Float(arg) => float + * + * Returns arg converted to a float. Numeric types are converted + * directly, the rest are converted using arg.to_f. As of Ruby + * 1.8, converting nil generates a TypeError. + * + * Float(1) #=> 1.0 + * Float("123.456") #=> 123.456 + */ + +static VALUE +rb_f_float(obj, arg) + VALUE obj, arg; +{ + return rb_Float(arg); +} + +double +rb_num2dbl(val) + VALUE val; +{ + switch (TYPE(val)) { + case T_FLOAT: + return RFLOAT(val)->value; + + case T_STRING: + rb_raise(rb_eTypeError, "no implicit conversion to float from string"); + break; + + case T_NIL: + rb_raise(rb_eTypeError, "no implicit conversion to float from nil"); + break; + + default: + break; + } + + return RFLOAT(rb_Float(val))->value; +} + +char* +rb_str2cstr(str, len) + VALUE str; + long *len; +{ + StringValue(str); + if (len) *len = RSTRING(str)->len; + else if (RTEST(ruby_verbose) && RSTRING(str)->len != strlen(RSTRING(str)->ptr)) { + rb_warn("string contains \\0 character"); + } + return RSTRING(str)->ptr; +} + +VALUE +rb_String(val) + VALUE val; +{ + return rb_convert_type(val, T_STRING, "String", "to_s"); +} + + +/* + * call-seq: + * String(arg) => string + * + * Converts arg to a String by calling its + * to_s method. + * + * String(self) #=> "main" + * String(self.class #=> "Object" + * String(123456) #=> "123456" + */ + +static VALUE +rb_f_string(obj, arg) + VALUE obj, arg; +{ + return rb_String(arg); +} + +#if 0 +VALUE +rb_Array(val) + VALUE val; +{ + VALUE tmp = rb_check_array_type(val); + + if (NIL_P(tmp)) { + tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_a"); + if (NIL_P(tmp)) { + return rb_ary_new3(1, val); + } + } + return tmp; +} +#endif + +/* + * call-seq: + * Array(arg) => array + * + * Returns arg as an Array. First tries to call + * arg.to_ary, then arg.to_a. + * If both fail, creates a single element array containing arg + * (unless arg is nil). + * + * Array(1..5) #=> [1, 2, 3, 4, 5] + */ + +static VALUE +rb_f_array(obj, arg) + VALUE obj, arg; +{ + return rb_Array(arg); +} + +static VALUE +boot_defclass(name, super) + char *name; + VALUE super; +{ + extern st_table *rb_class_tbl; + VALUE obj = rb_class_boot(super); + ID id = rb_intern(name); + + rb_name_class(obj, id); + st_add_direct(rb_class_tbl, id, obj); + rb_const_set((rb_cObject ? rb_cObject : obj), id, obj); + return obj; +} + +VALUE ruby_top_self; + +/* + * Document-class: Class + * + * Classes in Ruby are first-class objects---each is an instance of + * class Class. + * + * When a new class is created (typically using class Name ... + * end), an object of type Class is created and + * assigned to a global constant (Name in this case). When + * Name.new is called to create a new object, the + * new method in Class is run by default. + * This can be demonstrated by overriding new in + * Class: + * + * class Class + * alias oldNew new + * def new(*args) + * print "Creating a new ", self.name, "\n" + * oldNew(*args) + * end + * end + * + * + * class Name + * end + * + * + * n = Name.new + * + * produces: + * + * Creating a new Name + * + * Classes, modules, and objects are interrelated. In the diagram + * that follows, the vertical arrows represent inheritance, and the + * parentheses meta-classes. All metaclasses are instances + * of the class `Class'. + * + * +------------------+ + * | | + * Object---->(Object) | + * ^ ^ ^ ^ | + * | | | | | + * | | +-----+ +---------+ | + * | | | | | + * | +-----------+ | | + * | | | | | + * +------+ | Module--->(Module) | + * | | ^ ^ | + * OtherClass-->(OtherClass) | | | + * | | | + * Class---->(Class) | + * ^ | + * | | + * +----------------+ + */ + + +/* + * Object is the parent class of all classes in Ruby. Its + * methods are therefore available to all objects unless explicitly + * overridden. + * + * Object mixes in the Kernel module, making + * the built-in kernel functions globally accessible. Although the + * instance methods of Object are defined by the + * Kernel module, we have chosen to document them here for + * clarity. + * + * In the descriptions of Object's methods, the parameter symbol refers + * to a symbol, which is either a quoted string or a + * Symbol (such as :name). + */ + +void +Init_Object() +{ + VALUE metaclass; + + rb_cObject = boot_defclass("Object", 0); + rb_cModule = boot_defclass("Module", rb_cObject); + rb_cClass = boot_defclass("Class", rb_cModule); + + metaclass = rb_make_metaclass(rb_cObject, rb_cClass); + metaclass = rb_make_metaclass(rb_cModule, metaclass); + metaclass = rb_make_metaclass(rb_cClass, metaclass); + + rb_mKernel = rb_define_module("Kernel"); + rb_include_module(rb_cObject, rb_mKernel); + rb_define_alloc_func(rb_cObject, rb_class_allocate_instance); + rb_define_private_method(rb_cObject, "initialize", rb_obj_dummy, 0); + rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1); + rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1); + rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1); + rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1); + rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1); + rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1); + + + rb_define_method(rb_mKernel, "nil?", rb_false, 0); + rb_define_method(rb_mKernel, "==", rb_obj_equal, 1); + rb_define_method(rb_mKernel, "equal?", rb_obj_equal, 1); + rb_define_method(rb_mKernel, "===", rb_equal, 1); + rb_define_method(rb_mKernel, "=~", rb_obj_pattern_match, 1); + + rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1); + + rb_define_method(rb_mKernel, "id", rb_obj_id_obsolete, 0); + rb_define_method(rb_mKernel, "type", rb_obj_type, 0); + rb_define_method(rb_mKernel, "class", rb_obj_class, 0); + + rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0); + rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0); + rb_define_method(rb_mKernel, "initialize_copy", rb_obj_init_copy, 1); + + rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0); + rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0); + rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0); + rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0); + rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0); + + rb_define_method(rb_mKernel, "to_a", rb_any_to_a, 0); /* to be removed */ + rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); + rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); + rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); + rb_define_method(rb_mKernel, "singleton_methods", + rb_obj_singleton_methods, -1); /* in class.c */ + rb_define_method(rb_mKernel, "protected_methods", + rb_obj_protected_methods, -1); + rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, -1); + rb_define_method(rb_mKernel, "public_methods", rb_obj_public_methods, -1); + rb_define_method(rb_mKernel, "instance_variables", + rb_obj_instance_variables, 0); /* in variable.c */ + rb_define_method(rb_mKernel, "instance_variable_get", rb_obj_ivar_get, 1); + rb_define_method(rb_mKernel, "instance_variable_set", rb_obj_ivar_set, 2); + rb_define_private_method(rb_mKernel, "remove_instance_variable", + rb_obj_remove_instance_variable, 1); /* in variable.c */ + + rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); + rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); + rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); + + rb_define_private_method(rb_mKernel, "singleton_method_added", rb_obj_dummy, 1); + rb_define_private_method(rb_mKernel, "singleton_method_removed", rb_obj_dummy, 1); + rb_define_private_method(rb_mKernel, "singleton_method_undefined", rb_obj_dummy, 1); + + rb_define_global_function("sprintf", rb_f_sprintf, -1); /* in sprintf.c */ + rb_define_global_function("format", rb_f_sprintf, -1); /* in sprintf.c */ + + rb_define_global_function("Integer", rb_f_integer, 1); + rb_define_global_function("Float", rb_f_float, 1); + + rb_define_global_function("String", rb_f_string, 1); + rb_define_global_function("Array", rb_f_array, 1); + + rb_cNilClass = rb_define_class("NilClass", rb_cObject); + rb_define_method(rb_cNilClass, "to_i", nil_to_i, 0); + rb_define_method(rb_cNilClass, "to_f", nil_to_f, 0); + rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0); + rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0); + rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0); + rb_define_method(rb_cNilClass, "&", false_and, 1); + rb_define_method(rb_cNilClass, "|", false_or, 1); + rb_define_method(rb_cNilClass, "^", false_xor, 1); + + rb_define_method(rb_cNilClass, "nil?", rb_true, 0); + rb_undef_alloc_func(rb_cNilClass); + rb_undef_method(CLASS_OF(rb_cNilClass), "new"); + rb_define_global_const("NIL", Qnil); + + rb_cSymbol = rb_define_class("Symbol", rb_cObject); + rb_define_singleton_method(rb_cSymbol, "all_symbols", + rb_sym_all_symbols, 0); /* in parse.y */ + rb_undef_alloc_func(rb_cSymbol); + rb_undef_method(CLASS_OF(rb_cSymbol), "new"); + + rb_define_method(rb_cSymbol, "to_i", sym_to_i, 0); + rb_define_method(rb_cSymbol, "to_int", sym_to_int, 0); + rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0); + rb_define_method(rb_cSymbol, "to_s", sym_to_s, 0); + rb_define_method(rb_cSymbol, "id2name", sym_to_s, 0); + rb_define_method(rb_cSymbol, "to_sym", sym_to_sym, 0); + rb_define_method(rb_cSymbol, "===", rb_obj_equal, 1); + + rb_define_method(rb_cModule, "freeze", rb_mod_freeze, 0); + rb_define_method(rb_cModule, "===", rb_mod_eqq, 1); + rb_define_method(rb_cModule, "==", rb_obj_equal, 1); + rb_define_method(rb_cModule, "<=>", rb_mod_cmp, 1); + rb_define_method(rb_cModule, "<", rb_mod_lt, 1); + rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1); + rb_define_method(rb_cModule, ">", rb_mod_gt, 1); + rb_define_method(rb_cModule, ">=", rb_mod_ge, 1); + rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */ + rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0); + rb_define_method(rb_cModule, "included_modules", + rb_mod_included_modules, 0); /* in class.c */ + rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */ + rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */ + rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */ + + rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1); + rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1); + rb_define_private_method(rb_cModule, "attr_writer", rb_mod_attr_writer, -1); + rb_define_private_method(rb_cModule, "attr_accessor", rb_mod_attr_accessor, -1); + + rb_define_alloc_func(rb_cModule, rb_module_s_alloc); + rb_define_method(rb_cModule, "initialize", rb_mod_initialize, 0); + rb_define_method(rb_cModule, "instance_methods", + rb_class_instance_methods, -1); /* in class.c */ + rb_define_method(rb_cModule, "public_instance_methods", + rb_class_public_instance_methods, -1); /* in class.c */ + rb_define_method(rb_cModule, "protected_instance_methods", + rb_class_protected_instance_methods, -1); /* in class.c */ + rb_define_method(rb_cModule, "private_instance_methods", + rb_class_private_instance_methods, -1); /* in class.c */ + + rb_define_method(rb_cModule, "constants", rb_mod_constants, 0); /* in variable.c */ + rb_define_method(rb_cModule, "const_get", rb_mod_const_get, 1); + rb_define_method(rb_cModule, "const_set", rb_mod_const_set, 2); + rb_define_method(rb_cModule, "const_defined?", rb_mod_const_defined, 1); + rb_define_private_method(rb_cModule, "remove_const", + rb_mod_remove_const, 1); /* in variable.c */ + rb_define_method(rb_cModule, "const_missing", + rb_mod_const_missing, 1); /* in variable.c */ + rb_define_method(rb_cModule, "class_variables", + rb_mod_class_variables, 0); /* in variable.c */ + rb_define_private_method(rb_cModule, "remove_class_variable", + rb_mod_remove_cvar, 1); /* in variable.c */ + rb_define_private_method(rb_cModule, "class_variable_get", rb_mod_cvar_get, 1); + rb_define_private_method(rb_cModule, "class_variable_set", rb_mod_cvar_set, 2); + + rb_define_method(rb_cClass, "allocate", rb_obj_alloc, 0); + rb_define_method(rb_cClass, "new", rb_class_new_instance, -1); + rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1); + rb_define_method(rb_cClass, "initialize_copy", rb_class_init_copy, 1); /* in class.c */ + rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0); + rb_define_alloc_func(rb_cClass, rb_class_s_alloc); + rb_undef_method(rb_cClass, "extend_object"); + rb_undef_method(rb_cClass, "append_features"); + + rb_cData = rb_define_class("Data", rb_cObject); + rb_undef_alloc_func(rb_cData); + + rb_global_variable(&ruby_top_self); + ruby_top_self = rb_obj_alloc(rb_cObject); + rb_define_singleton_method(ruby_top_self, "to_s", main_to_s, 0); + + rb_cTrueClass = rb_define_class("TrueClass", rb_cObject); + rb_define_method(rb_cTrueClass, "to_s", true_to_s, 0); + rb_define_method(rb_cTrueClass, "&", true_and, 1); + rb_define_method(rb_cTrueClass, "|", true_or, 1); + rb_define_method(rb_cTrueClass, "^", true_xor, 1); + rb_undef_alloc_func(rb_cTrueClass); + rb_undef_method(CLASS_OF(rb_cTrueClass), "new"); + rb_define_global_const("TRUE", Qtrue); + + rb_cFalseClass = rb_define_class("FalseClass", rb_cObject); + rb_define_method(rb_cFalseClass, "to_s", false_to_s, 0); + rb_define_method(rb_cFalseClass, "&", false_and, 1); + rb_define_method(rb_cFalseClass, "|", false_or, 1); + rb_define_method(rb_cFalseClass, "^", false_xor, 1); + rb_undef_alloc_func(rb_cFalseClass); + rb_undef_method(CLASS_OF(rb_cFalseClass), "new"); + rb_define_global_const("FALSE", Qfalse); + + id_eq = rb_intern("=="); + id_eql = rb_intern("eql?"); + id_inspect = rb_intern("inspect"); + id_init_copy = rb_intern("initialize_copy"); +} -- cgit v1.2.3