std::pair<value_t, value_t> value_t::cast_types(const value_t &v1, const value_t &v2) { type_t t1 = v1.type(),t2 = v2.type(); if( t1.kind() == t2.kind()) return {v1,v2}; if(t1.kind() < t2.kind()) { return {v1.cast_to(t2),v2}; } else { return {v1,v2.cast_to(t1)}; } }
template<Type::Enum type> value_t raise_cast(value_t obj) { if(obj->type() != type) type_error(obj, "an object of type " + Type::names[type]); return obj; }
value_t Numeric::coerce(value_t obj, value_t other) { if(obj->type() == other->type()) return Array::allocate_pair(other, obj); auto convert = [&](value_t input) -> value_t { if(input->type() == Type::Float) return input; return raise_cast<Float>(call(input, "to_f")); }; OnStack<1> os(obj); value_t left = convert(other); value_t right = convert(obj); return Array::allocate_pair(left, right); }
value_t Bignum::coerce(Bignum *obj, value_t other) { switch(other->type()) { case Type::Fixnum: { if(obj->number.can_be_fix()) return Array::allocate_pair(other, Fixnum::from_int(obj->number.to_intptr())); else return Array::allocate_pair(Number(Fixnum::to_int(other)).to_bignum(), obj); } case Type::Bignum: return Array::allocate_pair(other, obj); default: coerce_error(other, obj); }; }