From ccf5372b252a229ddb6693db132edc013419ccdc Mon Sep 17 00:00:00 2001 From: matz Date: Sat, 2 Sep 2006 15:05:27 +0000 Subject: * object.c (Init_Object): move symbol related code to string.c * string.c (Init_String): Symbol as subclass of String. * parse.y (rb_intern2): handle symbol as strings. * string.c (str_new): substring of symbols are mere strings, not symbols. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10834 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- string.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) (limited to 'string.c') diff --git a/string.c b/string.c index 05d0d32325..8bb3158917 100644 --- a/string.c +++ b/string.c @@ -26,6 +26,7 @@ #endif VALUE rb_cString; +VALUE rb_cSymbol; #define STR_TMPLOCK FL_USER7 #define STR_NOEMBED FL_USER1 @@ -134,6 +135,7 @@ str_new(VALUE klass, const char *ptr, long len) rb_raise(rb_eArgError, "negative string size (or size too big)"); } + if (klass == rb_cSymbol) klass = rb_cString; str = str_alloc(klass); if (len > RSTRING_EMBED_LEN_MAX) { RSTRING(str)->as.heap.aux.capa = len; @@ -4369,6 +4371,207 @@ rb_str_setter(VALUE val, ID id, VALUE *var) } +/********************************************************************** + * 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: + * Symbol.new(str) => new_sym + * Symbol.intern(str) => new_sym + * + * Returns a new symbol corresponding to str. + */ + +static VALUE +rb_sym_s_intern(VALUE s) +{ + if (rb_class_real(s) == rb_cSymbol) { + return s; + } + StringValue(s); + return rb_intern2(RSTRING_PTR(s), RSTRING_LEN(s)); +} + +/* + * 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(VALUE sym) +{ + ID id = SYM2ID(sym); + + return LONG2FIX(id); +} + + +/* + * call-seq: + * sym.inspect => string + * + * Returns the representation of sym as a symbol literal. + * + * :fred.inspect #=> ":fred" + */ + +static VALUE +sym_inspect(VALUE sym) +{ + VALUE str; + + str = rb_str_new(0, RSTRING_LEN(sym)+1); + RSTRING_PTR(str)[0] = ':'; + memcpy(RSTRING_PTR(str)+1, RSTRING_PTR(sym), RSTRING_LEN(sym)); + if (!rb_symname_p(RSTRING_PTR(sym))) { + str = rb_str_dump(str); + strncpy(RSTRING_PTR(str), ":\"", 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(VALUE sym) +{ + return rb_str_new(RSTRING_PTR(sym), RSTRING_LEN(sym)); +} + + +/* + * call-seq: + * sym.to_sym => sym + * sym.intern => 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(VALUE sym) +{ + return sym; +} + +static VALUE +sym_call(VALUE args, VALUE sym) +{ + VALUE obj; + + if (RARRAY_LEN(args) < 1) { + rb_raise(rb_eArgError, "no receiver given"); + } + obj = RARRAY_PTR(args)[0]; + return rb_funcall3(obj, (ID)sym, + RARRAY_LEN(args) - 1, + RARRAY_PTR(args) + 1); +} + +/* + * call-seq: + * sym.to_proc + * + * Returns a _Proc_ object which respond to the given method by _sym_. + * + * (1..3).collect(&:to_s) #=> ["1", "2", "3"] + */ + +static VALUE +sym_to_proc(VALUE sym) +{ + return rb_proc_new(sym_call, (VALUE)SYM2ID(sym)); +} + + +static ID +str_to_id(VALUE str) +{ + if (!RSTRING_PTR(str) || RSTRING_LEN(str) == 0) { + rb_raise(rb_eArgError, "empty symbol string"); + } + if (RBASIC(str)->klass == rb_cSymbol) + return str; + return rb_intern2(RSTRING_PTR(str), RSTRING_LEN(str)); +} + +ID +rb_to_id(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_PTR(rb_inspect(name))); + } + return id; +} + /* * A String object holds and manipulates an arbitrary sequence of * bytes, typically representing characters. String objects may be created @@ -4496,4 +4699,17 @@ Init_String(void) rb_fs = Qnil; rb_define_variable("$;", &rb_fs); rb_define_variable("$-F", &rb_fs); + + rb_cSymbol = rb_define_class("Symbol", rb_cString); + rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in parse.y */ + rb_define_singleton_method(rb_cSymbol, "intern", rb_sym_s_intern, 1); + rb_define_singleton_method(rb_cSymbol, "new", rb_sym_s_intern, 1); + + rb_define_method(rb_cSymbol, "to_i", sym_to_i, 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, "intern", sym_to_sym, 0); + rb_define_method(rb_cSymbol, "to_sym", sym_to_sym, 0); + rb_define_method(rb_cSymbol, "to_proc", sym_to_proc, 0); } -- cgit v1.2.3