// -*- c++ -*- #include "rucy/value.h" #include #include "rucy/function.h" #include "rucy/exception.h" namespace Rucy { static void check_type (RubyValue value, RubyValueType type) { return rb_check_type(value, type); } static bool test_value (RubyValue value) { return RTEST(value); //!NIL_P(v) && v != Qfalse; } Value::Value () : val(nil()) { } Value::Value (bool b) : val(b ? Qtrue : Qfalse) { } Value::Value (int n) : val(INT2NUM(n)) { } Value::Value (unsigned int n) : val(UINT2NUM(n)) { } Value::Value (float n) : val(rb_float_new(n)) { } Value::Value (double n) : val(rb_float_new(n)) { } Value::Value (const char* s) : val(s ? rb_str_new2(s) : Qnil) { if (!s) argument_error(__FILE__, __LINE__); } Value::Value (const char* s, size_t len) : val(s ? rb_str_new(s, len) : Qnil) { if (!s) argument_error(__FILE__, __LINE__); } Value::Value (size_t size, const Value* array) { if (size == 0) { val = rb_ary_new(); } else if (array) { val = rb_ary_new4(size, (const RubyValue*) array); } else { val = rb_ary_new2(size); } } Value::Value (RubyValue v) : val(v) { } bool Value::is_i () const { return FIXNUM_P(val) || type() == RUBY_T_BIGNUM || is_kind_of(rb_cInteger); } bool Value::is_f () const { return RB_FLOAT_TYPE_P(val) || is_kind_of(rb_cFloat); } bool Value::is_s () const { return type() == RUBY_T_STRING || is_kind_of(rb_cString); } bool Value::is_sym () const { return SYMBOL_P(val) || is_kind_of(rb_cSymbol); } bool Value::is_array () const { return type() == RUBY_T_ARRAY || is_kind_of(rb_cArray); } bool Value::is_hash () const { return type() == RUBY_T_HASH || is_kind_of(rb_cHash); } bool Value::is_nil () const { return NIL_P(val); } int Value::as_i (bool convert) const { return as(convert); } double Value::as_f (bool convert) const { return as(convert); } const char* Value::as_s (bool convert) const { return as(convert); } Symbol Value::as_sym (bool convert) const { return as(convert); } Value* Value::as_array (bool convert) { return as(convert); } const Value* Value::as_array (bool convert) const { return as(convert); } Value Value::to_i () const { if (is_i()) return *this; RUCY_SYM(to_i); return call(to_i); } Value Value::to_f () const { if (is_f()) return *this; RUCY_SYM(to_f); return call(to_f); } Value Value::to_s () const { if (is_s()) return *this; RUCY_SYM(to_s); return call(to_s); } Value Value::to_sym () const { if (is_sym()) return *this; RUCY_SYM(to_sym); return call(to_sym); } Value Value::to_array () const { if (is_array()) return *this; RUCY_SYM(to_a); return call(to_a); } % ["call", "operator ()"].each do |op| Value Value::<%= op %> (Symbol name, int argc, const Value* argv) const { return protect(rb_funcall2, val, name.symbol(), argc, (const RubyValue*) argv); } % NTIMES.each do |n| Value Value::<%= op %> (Symbol name<%= params(n) {|i| ", Value v#{i}"} %>) const { const RubyValue args[] = {<%= params(n, ', ') {|i| "v#{i}"} %>}; return protect(rb_funcall2, val, name.symbol(), <%= n %>, args); } % end % end void Value::mark () const { rb_gc_mark(val); } RubyValue Value::value () const { return val; } RubyValueType Value::type () const { return TYPE(val); } Value::operator RubyValue () const { return val; } Value::operator bool () const { return test_value(val); } bool Value::operator ! () const { return !operator bool(); } bool Value::operator == (const Value& rhs) const { return operator==(rhs.val); } bool Value::operator == (RubyValue rhs) const { return val == rhs;// test_value(rb_obj_equal(val, rhs); } bool Value::operator != (const Value& rhs) const { return !operator==(rhs); } bool Value::operator != (RubyValue rhs) const { return !operator==(rhs); } Value Value::klass () const { return RBASIC(val)->klass; } bool Value::is_kind_of (Value klass) const { return rb_obj_is_kind_of(val, klass); } Value Value::inspect () const { RUCY_SYM(inspect); return call(inspect); } Value Value::push (Value obj) { return rb_ary_push(value(), obj.value()); } Value Value::pop () { return rb_ary_pop(value()); } Value Value::shift () { return rb_ary_shift(value()); } Value Value::unshift (Value obj) { return rb_ary_unshift(value(), obj.value()); } Value& Value::operator [] (int i) { return as_array()[i]; } const Value& Value::operator [] (int i) const { return const_cast(this)->operator[](i); } const char* Value::c_str () const { return as(true); } static int get_length (const Value& value, RubySymbol symbol) { if (value.type() == RUBY_T_ARRAY) return (int) RARRAY_LEN(value.value()); else if (value.type() == RUBY_T_STRING) return (int) RSTRING_LEN(value.value()); else return value.call(symbol); } int Value::length () const { RUCY_SYM(length); return get_length(*this, length); } int Value::size () const { RUCY_SYM(size); return get_length(*this, size); } GlobalValue::GlobalValue () { init(false); } GlobalValue::GlobalValue (bool b, bool gc_) : Super(b) { init(gc_); } GlobalValue::GlobalValue (int n, bool gc_) : Super(n) { init(gc_); } GlobalValue::GlobalValue (unsigned int n, bool gc_) : Super(n) { init(gc_); } GlobalValue::GlobalValue (float n, bool gc_) : Super(n) { init(gc_); } GlobalValue::GlobalValue (double n, bool gc_) : Super(n) { init(gc_); } GlobalValue::GlobalValue (const char* s, bool gc_) : Super(s) { init(gc_); } GlobalValue::GlobalValue (const char* s, size_t len, bool gc_) : Super(s, len) { init(gc_); } GlobalValue::GlobalValue (size_t size, const Value* array, bool gc_) : Super(size, array) { init(gc_); } GlobalValue::GlobalValue (RubyValue v, bool gc_) : Super(v) { init(gc_); } GlobalValue::GlobalValue (const Value& v, bool gc_) : Super(v) { init(gc_); } GlobalValue::GlobalValue (const GlobalValue& obj, bool gc_) : Super(obj) { init(gc_); } GlobalValue& GlobalValue::operator = (const Value& v) { Super::operator=(v); update_guard(); return *this; } GlobalValue::~GlobalValue () { while (gc_guarded) gc(true); } void GlobalValue::gc (bool enable) const { gc_disable_count += enable ? -1 : +1; update_guard(); } void GlobalValue::init (bool gc_) { gc_disable_count = 0; gc_guarded = false; if (!gc_) gc(false); } void GlobalValue::update_guard () const { assert(gc_disable_count >= 0); if (IMMEDIATE_P(val)) { if (gc_guarded) rb_gc_unregister_address((RubyValue*) &val); gc_guarded = false; } else if (gc_disable_count > 0) { if (!gc_guarded) rb_gc_register_address((RubyValue*) &val); gc_guarded = true; } else { if (gc_guarded) rb_gc_unregister_address((RubyValue*) &val); gc_guarded = false; } } Value nil () { return Qnil; } Value value (bool b) { return b; } Value value (char n) { return (int) n; } Value value (unsigned char n) { return (unsigned int) n; } Value value (short n) { return (int) n; } Value value (unsigned short n) { return (unsigned int) n; } Value value (int n) { return n; } Value value (unsigned int n) { return n; } Value value (long n) { return LONG2NUM(n); } Value value (unsigned long n) { return ULONG2NUM(n); } Value value (long long n) { return LL2NUM(n); } Value value (unsigned long long n) { return ULL2NUM(n); } Value value (float n) { return n; } Value value (double n) { return n; } Value value (const char* s) { return Value(s); } Value value (const char* s, size_t len) { return Value(s, len); } Value value (size_t size, const Value* array) { return Value(size, array); } Value value (void* ptr) { if (ptr) argument_error(__FILE__, __LINE__, "Rucy::value(void*) can take only (void*) NULL."); return nil(); } % (1..10).each do |n| Value array (<%= params(n, ', ') {|i| "Value v#{i}"} %>) { Value tmp[] = {<%= params(n, ', ') {|i| "v#{i}"} %>}; return value(<%= n %>, tmp); } % end template <> bool value_to (Value obj, bool convert) { return (bool) obj; } template <> int value_to (Value obj, bool convert) { if (convert) obj = obj.to_i(); return NUM2INT(obj.value()); } template <> unsigned int value_to (Value obj, bool convert) { if (convert) obj = obj.to_i(); return NUM2UINT(obj.value()); } template <> char value_to (Value obj, bool convert) { return (char) value_to(obj, convert); } template <> unsigned char value_to (Value obj, bool convert) { return (unsigned char) value_to(obj, convert); } template <> short value_to (Value obj, bool convert) { return (short) value_to(obj, convert); } template <> unsigned short value_to (Value obj, bool convert) { return (unsigned short) value_to(obj, convert); } template <> long value_to (Value obj, bool convert) { if (convert) obj = obj.to_i(); return NUM2LONG(obj.value()); } template <> unsigned long value_to (Value obj, bool convert) { if (convert) obj = obj.to_i(); return NUM2ULONG(obj.value()); } template <> long long value_to (Value obj, bool convert) { if (convert) obj = obj.to_i(); return NUM2LL(obj.value()); } template <> unsigned long long value_to (Value obj, bool convert) { if (convert) obj = obj.to_i(); return NUM2ULL(obj.value()); } template <> double value_to (Value obj, bool convert) { if (convert) obj = obj.to_f(); check_type(obj, RUBY_T_FLOAT); return RFLOAT_VALUE(obj.value()); } template <> float value_to (Value obj, bool convert) { return (float) value_to(obj, convert); } template <> char* value_to (Value obj, bool convert) { if (convert) obj = obj.to_s(); RubyValue s = obj.value(); return StringValueCStr(s); } template <> const char* value_to (Value obj, bool convert) { return value_to(obj, convert); } template <> Symbol value_to (Value obj, bool convert) { if (convert) obj = obj.to_sym(); check_type(obj, RUBY_T_SYMBOL); return SYM2ID(obj.value()); } template <> Value* value_to (Value obj, bool convert) { if (convert) obj = obj.to_array(); check_type(obj, RUBY_T_ARRAY); return (Value*) RARRAY_PTR(obj.value()); } template <> const Value* value_to (Value obj, bool convert) { if (convert) obj = obj.to_array(); check_type(obj, RUBY_T_ARRAY); return (const Value*) RARRAY_PTR(obj.value()); } }// Rucy