Merge pull request #6540 from mruby/add-comments-object-c

This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-05-31 22:48:02 +09:00
committed by GitHub
+227 -9
View File
@@ -12,6 +12,18 @@
#include <mruby/internal.h>
#include <mruby/presym.h>
/*
* Checks if two mruby values, `v1` and `v2`, are identical.
* For most types, this is equivalent to pointer equality.
* For immediate values (integers, symbols, true, false, nil),
* it compares their actual values.
*
* Behavior under different boxing configurations:
* - MRB_NAN_BOXING: Compares the raw `uint64_t` values.
* - MRB_WORD_BOXING: Compares the raw `mrb_word` values.
* - MRB_NO_BOXING: Checks if types are equal. If so, performs
* type-specific comparisons (value for immediates, pointer for others).
*/
MRB_API mrb_bool
mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
@@ -43,13 +55,27 @@ mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2)
#endif
}
/*
* Checks if two mruby values, `v1` and `v2`, are equal.
* This function currently calls mrb_obj_eq to perform the comparison.
*/
MRB_API mrb_bool
mrb_obj_equal(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
/* temporary definition */
return mrb_obj_eq(mrb, v1, v2);
}
/*
* Checks for equality between `obj1` and `obj2`.
*
* It first uses `mrb_obj_eq` for an identity check. If that fails,
* it handles cases like mixed integer/float comparisons.
* If `MRB_USE_BIGINT` is defined, it also considers comparisons
* involving BigInts against Integers, other BigInts, or Floats.
* Finally, if none of the above apply, it attempts to call the
* `==` operator (MRB_OPSYM(eq)) on `obj1` with `obj2` as an argument,
* unless `obj1`'s `==` method is the default `mrb_obj_equal_m`.
*/
MRB_API mrb_bool
mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
{
@@ -355,6 +381,21 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, mrb_sym method, m
return mrb_funcall_argv(mrb, val, method, 0, 0);
}
/*
* Attempts to convert the mruby value `val` to the specified `type`
* by calling the given `method` (a symbol) on `val`.
*
* It first checks if `val` is already of the target `type`. If not, it
* proceeds to call the conversion `method` on `val`.
*
* If the conversion method does not return a value of the target `type`,
* a `TypeError` is raised. However, as a special case, if the target
* `type` is `MRB_TT_STRING`, and the initial conversion fails to produce
* a string, this function will then attempt to call `mrb_any_to_s` on
* the original `val` as a fallback mechanism.
*
* Returns the converted value if successful.
*/
MRB_API mrb_value
mrb_type_convert(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method)
{
@@ -371,6 +412,25 @@ mrb_type_convert(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym met
return v;
}
/*
* Attempts to convert the mruby value `val` to the specified `type`
* by calling the given `method` (a symbol) on `val`.
*
* This function first checks if `val` is already of the target `type`.
* An exception to this initial check is if the target `type` is
* `MRB_TT_CDATA` or `MRB_TT_ISTRUCT`; in these cases, the conversion
* attempt proceeds regardless of `val`'s current type.
*
* If `val` is not already of the target `type` (or if it's `MRB_TT_CDATA`
* or `MRB_TT_ISTRUCT`), the specified `method` is called on `val` to
* perform the conversion. Unlike `mrb_type_convert`, this function
* does *not* raise an error if the conversion fails or if the returned
* value is not of the target `type`.
*
* Returns the converted value if the conversion was successful and the
* resulting value is of the target `type`. Otherwise, it returns
* `mrb_nil_value()`.
*/
MRB_API mrb_value
mrb_type_convert_check(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_sym method)
{
@@ -382,6 +442,13 @@ mrb_type_convert_check(mrb_state *mrb, mrb_value val, enum mrb_vtype type, mrb_s
return v;
}
/*
* Checks if the mruby value `x` is of the specified type `t`.
*
* If the type of `x` does not match `t`, this function raises
* a `TypeError`. The error message provides details about the
* actual type of `x` and the expected type `t`.
*/
MRB_API void
mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
{
@@ -446,9 +513,15 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
* obj.is_a?(class) => true or false
* obj.kind_of?(class) => true or false
*
* Returns <code>true</code> if <i>class</i> is the class of
* <i>obj</i>, or if <i>class</i> is one of the superclasses of
* <i>obj</i> or modules included in <i>obj</i>.
* Checks if the mruby object `obj` is an instance of class `c`,
* or an instance of a class that inherits from `c`, or an instance
* of a class that includes `c` if `c` is a module.
*
* This function traverses the class hierarchy of `obj` upwards.
* It returns `TRUE` if `c` is found in the ancestry. Otherwise,
* it returns `FALSE`.
*
* If `c` is not a class or module, a `TypeError` is raised.
*
* module M; end
* class A
@@ -457,16 +530,13 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj)
* 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.instance_of? A #=> false (mrb_obj_is_instance_of)
* b.instance_of? B #=> true (mrb_obj_is_instance_of)
* b.kind_of? A #=> true
* b.kind_of? B #=> true
* b.kind_of? C #=> false
* b.kind_of? M #=> true
*/
MRB_API mrb_bool
mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c)
{
@@ -503,6 +573,28 @@ mrb_value mrb_complex_to_f(mrb_state *mrb, mrb_value comp);
mrb_value mrb_complex_to_i(mrb_state *mrb, mrb_value comp);
#endif
/*
* Ensures that the given mruby value `val` is an Integer.
*
* If `val` is already an `MRB_TT_INTEGER`, it is returned directly.
*
* If `val` is an `MRB_TT_FLOAT` (and `MRB_NO_FLOAT` is not defined),
* it is converted to an integer using `mrb_float_to_integer`.
*
* The function also handles conversions from other numeric types if
* the respective modules are enabled:
* - `MRB_TT_BIGINT` (if `MRB_USE_BIGINT` is defined): `val` is returned as is,
* as BigInts are considered integers.
* - `MRB_TT_RATIONAL` (if `MRB_USE_RATIONAL` is defined): Converted using
* `mrb_rational_to_i`.
* - `MRB_TT_COMPLEX` (if `MRB_USE_COMPLEX` is defined): Converted using
* `mrb_complex_to_i` (typically if the imaginary part is zero).
*
* If `val` cannot be converted to an Integer (e.g., it's a String or Array,
* or a Complex with a non-zero imaginary part), a `TypeError` is raised.
*
* Returns the (potentially converted) integer value.
*/
MRB_API mrb_value
mrb_ensure_integer_type(mrb_state *mrb, mrb_value val)
{
@@ -535,6 +627,25 @@ mrb_ensure_integer_type(mrb_state *mrb, mrb_value val)
return val;
}
/*
* Ensures that the given mruby value `val` is a C `mrb_int` (fixed-size integer).
*
* This function first calls `mrb_ensure_integer_type` to convert `val`
* to a generic mruby Integer if it's not already. This step might result
* in `val` being a Fixnum or a BigInt (if `MRB_USE_BIGINT` is enabled).
*
* If `mrb_ensure_integer_type` returns a BigInt (and `MRB_USE_BIGINT`
* is defined), this function then attempts to convert the BigInt to a C
* `mrb_int` using `mrb_bint_as_int`. This conversion may involve truncation
* if the BigInt's value is outside the representable range of `mrb_int`,
* or it could raise an error (e.g., RangeError) depending on the
* `mrb_bint_as_int` implementation if the value is too large to truncate.
*
* If `val` is already a standard Integer (Fixnum) after the call to
* `mrb_ensure_integer_type`, it is returned directly as it fits `mrb_int`.
*
* Returns an `mrb_value` that represents a C `mrb_int`.
*/
MRB_API mrb_value
mrb_ensure_int_type(mrb_state *mrb, mrb_value val)
{
@@ -548,6 +659,28 @@ mrb_ensure_int_type(mrb_state *mrb, mrb_value val)
}
#ifndef MRB_NO_FLOAT
/*
* Ensures that the given mruby value `val` is a Float.
*
* If `val` is `nil`, this function raises a `TypeError`.
*
* If `val` is an `MRB_TT_INTEGER`, it is converted to an `mrb_float`.
* If `val` is already an `MRB_TT_FLOAT`, it is returned directly.
*
* The function also handles conversions from other numeric types if the
* respective mruby modules are enabled:
* - `MRB_TT_RATIONAL` (if `MRB_USE_RATIONAL` is defined): Converted to Float
* using `mrb_rational_to_f`.
* - `MRB_TT_COMPLEX` (if `MRB_USE_COMPLEX` is defined): Converted to Float
* using `mrb_complex_to_f` (typically requires the imaginary part to be zero).
* - `MRB_TT_BIGINT` (if `MRB_USE_BIGINT` is defined): Converted to Float
* using `mrb_bint_as_float`.
*
* If `val` cannot be converted to a Float (e.g., it's a String, Array, or
* an incompatible Complex number), a `TypeError` is raised.
*
* Returns an `mrb_value` representing an `mrb_float`.
*/
MRB_API mrb_value
mrb_ensure_float_type(mrb_state *mrb, mrb_value val)
{
@@ -584,6 +717,13 @@ mrb_ensure_float_type(mrb_state *mrb, mrb_value val)
}
#endif
/*
* Ensures that the given mruby value `str` is a String.
*
* If `str` is not of type `MRB_TT_STRING`, this function raises
* a `TypeError`.
* Otherwise, `str` itself is returned.
*/
MRB_API mrb_value
mrb_ensure_string_type(mrb_state *mrb, mrb_value str)
{
@@ -593,6 +733,14 @@ mrb_ensure_string_type(mrb_state *mrb, mrb_value str)
return str;
}
/*
* Checks if the given mruby value `str` is a String.
*
* If `str` is of type `MRB_TT_STRING`, this function returns `str`.
* Otherwise (if `str` is not a String), it returns `mrb_nil_value()`
* without raising an error. This allows for type checking without
* forcing error handling.
*/
MRB_API mrb_value
mrb_check_string_type(mrb_state *mrb, mrb_value str)
{
@@ -600,6 +748,13 @@ mrb_check_string_type(mrb_state *mrb, mrb_value str)
return str;
}
/*
* Ensures that the given mruby value `ary` is an Array.
*
* If `ary` is not of type `MRB_TT_ARRAY`, this function raises
* a `TypeError`.
* Otherwise, `ary` itself is returned.
*/
MRB_API mrb_value
mrb_ensure_array_type(mrb_state *mrb, mrb_value ary)
{
@@ -609,6 +764,14 @@ mrb_ensure_array_type(mrb_state *mrb, mrb_value ary)
return ary;
}
/*
* Checks if the given mruby value `ary` is an Array.
*
* If `ary` is of type `MRB_TT_ARRAY`, this function returns `ary`.
* Otherwise (if `ary` is not an Array), it returns `mrb_nil_value()`
* without raising an error. This allows for type checking without
* forcing error handling.
*/
MRB_API mrb_value
mrb_check_array_type(mrb_state *mrb, mrb_value ary)
{
@@ -616,6 +779,13 @@ mrb_check_array_type(mrb_state *mrb, mrb_value ary)
return ary;
}
/*
* Ensures that the given mruby value `hash` is a Hash.
*
* If `hash` is not of type `MRB_TT_HASH`, this function raises
* a `TypeError`.
* Otherwise, `hash` itself is returned.
*/
MRB_API mrb_value
mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash)
{
@@ -625,6 +795,14 @@ mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash)
return hash;
}
/*
* Checks if the given mruby value `hash` is a Hash.
*
* If `hash` is of type `MRB_TT_HASH`, this function returns `hash`.
* Otherwise (if `hash` is not a Hash), it returns `mrb_nil_value()`
* without raising an error. This allows for type checking without
* forcing error handling.
*/
MRB_API mrb_value
mrb_check_hash_type(mrb_state *mrb, mrb_value hash)
{
@@ -632,6 +810,22 @@ mrb_check_hash_type(mrb_state *mrb, mrb_value hash)
return hash;
}
/*
* Returns a human-readable string representation of the mruby object `obj`.
*
* This function calls the `inspect` method (identified by `MRB_SYM(inspect)`)
* on the given `obj`. The `inspect` method is expected to return a string
* that is suitable for debugging and inspection.
*
* If the object's `inspect` method does not return a String value (e.g., it
* returns `nil` or another type, or if the class doesn't define `inspect`
* appropriately), this function falls back to calling `mrb_obj_as_string`.
* `mrb_obj_as_string` typically provides a basic string representation,
* such as "#<ClassName:0xPointer>" if `inspect` is unavailable or
* misbehaves by not returning a string.
*
* The function ultimately returns the resulting string `mrb_value`.
*/
MRB_API mrb_value
mrb_inspect(mrb_state *mrb, mrb_value obj)
{
@@ -642,6 +836,22 @@ mrb_inspect(mrb_state *mrb, mrb_value obj)
return v;
}
/*
* Checks if two mruby values, `obj1` and `obj2`, are equal using
* `eql?` semantics.
*
* This function first performs an identity check on `obj1` and `obj2`
* using `mrb_obj_eq`. If they are identical (i.e., the same object),
* it returns `TRUE` immediately.
*
* Otherwise, it calls the `eql?` method on `obj1`, passing `obj2` as
* an argument. The symbol for the `eql?` method is `MRB_SYM_Q(eql)`.
*
* The function returns `TRUE` if the `eql?` method call returns a truthy
* value (any value other than `false` or `nil`). Otherwise, it returns
* `FALSE`. This is determined by `mrb_test` on the result of the
* method call.
*/
MRB_API mrb_bool
mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
{
@@ -649,6 +859,14 @@ mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
return mrb_test(mrb_funcall_argv(mrb, obj1, MRB_SYM_Q(eql), 1, &obj2));
}
/*
* Returns the receiver object itself.
*
* This function simply returns the mruby value `self` that it was passed.
* It corresponds to the `Object#itself` method in Ruby, which is useful
* in some functional programming patterns or for obtaining the object
* itself in a chain of method calls.
*/
MRB_API mrb_value
mrb_obj_itself(mrb_state *mrb, mrb_value self)
{