diff --git a/ext/tm/include/tm/optional.hpp b/ext/tm/include/tm/optional.hpp index 3e16df8ce..eaa50438a 100644 --- a/ext/tm/include/tm/optional.hpp +++ b/ext/tm/include/tm/optional.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -212,6 +213,31 @@ class Optional { return fallback; } + /** + * Returns a copy of the underlying value or + * the result of calling the fallback lambda. + * + * ``` + * auto obj = Thing(1); + * auto opt = Optional(obj); + * assert_eq(Thing(1), opt.value_or([]() { return Thing(2); })); + * ``` + * + * If we don't have a value present, then the fallback + * is called and the result returned. + * + * ``` + * auto opt = Optional(); + * assert_eq(Thing(2), opt.value_or([]() { return Thing(2); })); + * ``` + */ + T value_or(std::function fallback) const { + if (present()) + return value(); + else + return fallback(); + } + /** * Returns a reference to the underlying value. * diff --git a/include/natalie/array_object.hpp b/include/natalie/array_object.hpp index a36757397..a11a598a8 100644 --- a/include/natalie/array_object.hpp +++ b/include/natalie/array_object.hpp @@ -122,7 +122,7 @@ class ArrayObject : public Object { bool is_empty() { return m_vector.is_empty(); } - Value initialize(Env *, Value, Value, Block *); + Value initialize(Env *, Optional, Optional, Block *); Value add(Env *, Value); Value any(Env *, Args &&, Block *); @@ -135,7 +135,7 @@ class ArrayObject : public Object { Value compact(Env *); Value compact_in_place(Env *); Value concat(Env *, Args &&); - Value cycle(Env *, Value, Block *); + Value cycle(Env *, Optional, Block *); Value delete_at(Env *, Value); Value delete_if(Env *, Block *); Value delete_item(Env *, Value, Block *); @@ -147,14 +147,14 @@ class ArrayObject : public Object { Value each_index(Env *, Block *); bool eq(Env *, Value); bool eql(Env *, Value); - Value fetch(Env *, Value, Value, Block *); - Value fill(Env *, Value, Value, Value, Block *); - Value first(Env *, Value); - Value flatten(Env *, Value); - Value flatten_in_place(Env *, Value); + Value fetch(Env *, Value, Optional, Block *); + Value fill(Env *, Optional, Optional, Optional, Block *); + Value first(Env *, Optional); + Value flatten(Env *, Optional); + Value flatten_in_place(Env *, Optional); Value hash(Env *); bool include(Env *, Value); - Value index(Env *, Value, Block *); + Value index(Env *, Optional, Block *); Value initialize_copy(Env *, Value); Value inspect(Env *); Value insert(Env *, Args &&); @@ -162,38 +162,38 @@ class ArrayObject : public Object { Value intersection(Env *, Args &&); bool intersects(Env *, Value); Value _subjoin(Env *, Value, Value); - Value join(Env *, Value); + Value join(Env *, Optional); Value keep_if(Env *, Block *); - Value last(Env *, Value); + Value last(Env *, Optional); Value ltlt(Env *, Value); Value map(Env *, Block *); Value map_in_place(Env *, Block *); - Value max(Env *, Value, Block *); - Value min(Env *, Value, Block *); + Value max(Env *, Optional, Block *); + Value min(Env *, Optional, Block *); Value minmax(Env *, Block *); Value multiply(Env *, Value); Value none(Env *, Args &&, Block *); Value one(Env *, Args &&, Block *); Value pack(Env *, Value, Value); - Value pop(Env *, Value); + Value pop(Env *, Optional); Value product(Env *, Args &&, Block *); Value push(Env *, Args &&); Value rassoc(Env *, Value); - Value ref(Env *, Value, Value = nullptr); - Value refeq(Env *, Value, Value, Value); + Value ref(Env *, Value, Optional = {}); + Value refeq(Env *, Value, Value, Optional = {}); Value reject(Env *, Block *); Value reject_in_place(Env *, Block *); Value reverse(Env *); Value reverse_each(Env *, Block *); Value reverse_in_place(Env *); - Value rindex(Env *, Value, Block *); - Value rotate(Env *, Value); - Value rotate_in_place(Env *, Value); + Value rindex(Env *, Optional, Block *); + Value rotate(Env *, Optional); + Value rotate_in_place(Env *, Optional); Value select(Env *, Block *); Value select_in_place(Env *, Block *); bool select_in_place(std::function); - Value shift(Env *, Value); - Value slice_in_place(Env *, Value, Value); + Value shift(Env *, Optional); + Value slice_in_place(Env *, Value, Optional); Value sort(Env *, Block *); Value sub(Env *, Value); static Value try_convert(Env *, Value); @@ -227,7 +227,7 @@ class ArrayObject : public Object { nat_int_t _resolve_index(nat_int_t) const; bool _flatten_in_place(Env *, nat_int_t depth, Hashmap visited_arrays = Hashmap {}); Value _slice_in_place(nat_int_t start, nat_int_t end, bool exclude_end); - Value find_index(Env *, Value, Block *, bool = false); + Value find_index(Env *, Optional, Block *, bool = false); bool include_eql(Env *, Value); }; diff --git a/include/natalie/class_object.hpp b/include/natalie/class_object.hpp index cbfbad3d3..8a4a16388 100644 --- a/include/natalie/class_object.hpp +++ b/include/natalie/class_object.hpp @@ -54,7 +54,7 @@ class ClassObject : public ModuleObject { Type object_type() { return m_object_type; } - Value initialize(Env *, Value, Block *); + Value initialize(Env *, Optional, Block *); bool is_singleton() const { return m_is_singleton; } void set_is_singleton(bool is_singleton) { m_is_singleton = is_singleton; } diff --git a/include/natalie/float_object.hpp b/include/natalie/float_object.hpp index cfc891e7d..d5c7bc8a8 100644 --- a/include/natalie/float_object.hpp +++ b/include/natalie/float_object.hpp @@ -114,26 +114,26 @@ class FloatObject : public Object { Value abs(Env *) const; Value add(Env *, Value); Value arg(Env *); - Value ceil(Env *, Value); + Value ceil(Env *, Optional); Value cmp(Env *, Value); Value coerce(Env *, Value); Value denominator(Env *) const; Value div(Env *, Value); Value divmod(Env *, Value); - Value floor(Env *, Value); + Value floor(Env *, Optional); Value mod(Env *, Value); Value mul(Env *, Value); Value numerator(Env *) const; Value next_float(Env *) const; Value pow(Env *, Value); Value prev_float(Env *) const; - Value round(Env *, Value); + Value round(Env *, Optional); Value sub(Env *, Value); Value to_f() const { return new FloatObject { *this }; } Value to_i(Env *) const; Value to_r(Env *) const; Value to_s() const; - Value truncate(Env *, Value); + Value truncate(Env *, Optional); bool lt(Env *, Value); bool lte(Env *, Value); diff --git a/include/natalie/hash_object.hpp b/include/natalie/hash_object.hpp index d14bb0458..443340c50 100644 --- a/include/natalie/hash_object.hpp +++ b/include/natalie/hash_object.hpp @@ -110,7 +110,7 @@ class HashObject : public Object { bool is_empty() { return m_hashmap.size() == 0; } Value get(Env *, Value); - Value get_default(Env *, Value = nullptr); + Value get_default(Env *, Optional = {}); Value set_default(Env *, Value); void put(Env *, Value, Value); @@ -194,12 +194,12 @@ class HashObject : public Object { bool lte(Env *, Value); bool lt(Env *, Value); Value except(Env *, Args &&); - Value fetch(Env *, Value, Value, Block *); + Value fetch(Env *, Value, Optional = {}, Block * = nullptr); Value fetch_values(Env *, Args &&, Block *); Value hash(Env *); bool has_key(Env *, Value); bool has_value(Env *, Value); - Value initialize(Env *, Value, Value = nullptr, Block * = nullptr); + Value initialize(Env *, Optional, Optional = {}, Block * = nullptr); Value inspect(Env *); Value keep_if(Env *, Block *); Value keys(Env *); diff --git a/include/natalie/integer_methods.hpp b/include/natalie/integer_methods.hpp index f5c7dee75..3405369ab 100644 --- a/include/natalie/integer_methods.hpp +++ b/include/natalie/integer_methods.hpp @@ -62,7 +62,7 @@ class IntegerMethods { static String to_s(const Integer self) { return self.to_string(); } - static Value to_s(Env *, Integer self, Value = nullptr); + static Value to_s(Env *, Integer self, Optional = {}); static Value to_i(Integer self) { return self; } static Value to_f(Integer self); static Value add(Env *, Integer, Value); @@ -73,7 +73,7 @@ class IntegerMethods { static Value pow(Env *, Integer, Integer); static Value pow(Env *, Integer, Value); static Value powmod(Env *, Integer, Integer, Integer); - static Value powmod(Env *, Integer, Value, Value); + static Value powmod(Env *, Integer, Value, Optional); static Value cmp(Env *, Integer, Value); static Value times(Env *, Integer, Block *); static Value bitwise_and(Env *, Integer, Value); @@ -85,20 +85,20 @@ class IntegerMethods { static Value pred(Env *env, Integer self) { return self - 1; } static Value size(Env *, Integer); static Value succ(Env *, Integer self) { return self + 1; } - static Value ceil(Env *, Integer, Value); + static Value ceil(Env *, Integer, Optional); static Value coerce(Env *, Value, Value); - static Value floor(Env *, Integer, Value); + static Value floor(Env *, Integer, Optional); static Value gcd(Env *, Integer, Value); static Value abs(Env *, Integer self) { return self.is_negative() ? -self : self; } - static Value chr(Env *, Integer, Value); + static Value chr(Env *, Integer, Optional = {}); static Value negate(Env *, Integer self) { return -self; } static Value numerator(Integer self) { return self; } static Value complement(Env *, Integer self) { return ~self; } static Value ord(Integer self) { return self; } static Value denominator() { return Value::integer(1); } - static Value round(Env *, Integer, Value, Value); - static Value truncate(Env *, Integer, Value); - static Value ref(Env *, Integer, Value, Value); + static Value round(Env *, Integer, Optional, Optional); + static Value truncate(Env *, Integer, Optional); + static Value ref(Env *, Integer, Value, Optional); static bool neq(Env *env, Value self, Value other) { return self.send(env, "=="_s, { other }).is_falsey(); } static bool eq(Env *, Integer, Value); diff --git a/include/natalie/kernel_module.hpp b/include/natalie/kernel_module.hpp index 37a98e06a..684edead0 100644 --- a/include/natalie/kernel_module.hpp +++ b/include/natalie/kernel_module.hpp @@ -87,11 +87,11 @@ class KernelModule { static bool is_frozen(Value self) { return self.is_frozen(); } static Value loop(Env *env, Value self, Block *block); static Value method(Env *env, Value self, Value name); - static Value methods(Env *env, Value self, Value regular_val); + static Value methods(Env *env, Value self, Optional regular_val); static bool neqtilde(Env *env, Value self, Value other); - static Value private_methods(Env *env, Value self, Value recur = nullptr); - static Value protected_methods(Env *env, Value self, Value recur = nullptr); - static Value public_methods(Env *env, Value self, Value recur = nullptr); + static Value private_methods(Env *env, Value self, Optional recur = {}); + static Value protected_methods(Env *env, Value self, Optional recur = {}); + static Value public_methods(Env *env, Value self, Optional recur = {}); static Value remove_instance_variable(Env *env, Value self, Value name_val); static bool respond_to_missing(Env *, Value, Value, Value) { return false; } static bool respond_to_method(Env *, Value, Value, Value); diff --git a/include/natalie/module_object.hpp b/include/natalie/module_object.hpp index b601be73b..eab035d37 100644 --- a/include/natalie/module_object.hpp +++ b/include/natalie/module_object.hpp @@ -57,7 +57,7 @@ class ModuleObject : public Object { Value const_find(Env *, SymbolObject *, ConstLookupSearchMode = ConstLookupSearchMode::Strict, ConstLookupFailureMode = ConstLookupFailureMode::ConstMissing); Value const_get(SymbolObject *) const; - Value const_get(Env *, Value, Value = nullptr); + Value const_get(Env *, Value, Optional = {}); Value const_fetch(SymbolObject *) const; Value const_set(SymbolObject *, Value); Value const_set(SymbolObject *, MethodFnPtr, StringObject *); @@ -65,7 +65,7 @@ class ModuleObject : public Object { void remove_const(SymbolObject *); Value remove_const(Env *, Value); - Value constants(Env *, Value) const; + Value constants(Env *, Optional) const; Value const_missing(Env *, Value); void make_method_alias(Env *, SymbolObject *, SymbolObject *); @@ -101,10 +101,10 @@ class ModuleObject : public Object { bool class_variable_defined(Env *, Value); Value class_variable_get(Env *, Value); Value class_variable_set(Env *, Value, Value); - ArrayObject *class_variables(Value = nullptr) const; + ArrayObject *class_variables(Optional = {}) const; Value remove_class_variable(Env *, Value); - Value define_method(Env *, Value, Value, Block *); + Value define_method(Env *, Value, Optional, Block *); SymbolObject *define_method(Env *, SymbolObject *, MethodFnPtr, int); SymbolObject *define_method(Env *, SymbolObject *, Block *); SymbolObject *undefine_method(Env *, SymbolObject *); @@ -118,11 +118,11 @@ class ModuleObject : public Object { Value instance_method(Env *, Value); Value public_instance_method(Env *, Value); - Value instance_methods(Env *, Value, std::function); - Value instance_methods(Env *, Value); - Value private_instance_methods(Env *, Value); - Value protected_instance_methods(Env *, Value); - Value public_instance_methods(Env *, Value); + Value instance_methods(Env *, Optional, std::function); + Value instance_methods(Env *, Optional); + Value private_instance_methods(Env *, Optional); + Value protected_instance_methods(Env *, Optional); + Value public_instance_methods(Env *, Optional); ArrayObject *ancestors(Env *); bool ancestors_includes(Env *, ModuleObject *); @@ -163,7 +163,7 @@ class ModuleObject : public Object { Value private_constant(Env *, Args &&); Value public_constant(Env *, Args &&); - bool const_defined(Env *, Value, Value = nullptr); + bool const_defined(Env *, Value, Optional = {}); Value alias_method(Env *, Value, Value); Value remove_method(Env *, Args &&); Value undef_method(Env *, Args &&); diff --git a/include/natalie/object.hpp b/include/natalie/object.hpp index 6ab9dd362..521d45f4a 100644 --- a/include/natalie/object.hpp +++ b/include/natalie/object.hpp @@ -11,6 +11,7 @@ #include "natalie/object_type.hpp" #include "natalie/value.hpp" #include "tm/hashmap.hpp" +#include "tm/optional.hpp" namespace Natalie { @@ -122,7 +123,7 @@ class Object : public Cell { static SymbolObject *define_singleton_method(Env *, Value, SymbolObject *, Block *); static SymbolObject *undefine_singleton_method(Env *, Value, SymbolObject *); - Value main_obj_define_method(Env *, Value, Value, Block *); + Value main_obj_define_method(Env *, Value, Optional, Block *); Value main_obj_inspect(Env *); virtual Value private_method(Env *, Args &&); diff --git a/include/natalie/random_object.hpp b/include/natalie/random_object.hpp index a979b9aa4..d8dd85e98 100644 --- a/include/natalie/random_object.hpp +++ b/include/natalie/random_object.hpp @@ -28,10 +28,10 @@ class RandomObject : public Object { ~RandomObject() { delete m_generator; } - Value initialize(Env *, Value); + Value initialize(Env *, Optional = {}); Value bytes(Env *, Value); - Value rand(Env *, Value); + Value rand(Env *, Optional); Value seed() const { return Value::integer(m_seed); } virtual void gc_inspect(char *buf, size_t len) const override { @@ -42,9 +42,8 @@ class RandomObject : public Object { return Value::integer(std::random_device()()); } - static Value srand(Env *env, Value seed) { - if (!seed) - seed = new_seed(env); + static Value srand(Env *env, Optional seed_arg) { + auto seed = seed_arg.value_or([&env]() { return new_seed(env); }); auto default_random = GlobalEnv::the()->Random()->const_fetch("DEFAULT"_s).as_random(); auto old_seed = default_random->seed(); auto new_seed = IntegerMethods::convert_to_native_type(env, seed); diff --git a/include/natalie/range_object.hpp b/include/natalie/range_object.hpp index 74811d910..0db3149f4 100644 --- a/include/natalie/range_object.hpp +++ b/include/natalie/range_object.hpp @@ -25,19 +25,19 @@ class RangeObject : public Object { Value end() { return m_end; } bool exclude_end() const { return m_exclude_end; } - Value initialize(Env *, Value, Value, Value); + Value initialize(Env *, Value, Value, Optional); Value to_a(Env *); Value each(Env *, Block *); - Value first(Env *, Value); + Value first(Env *, Optional); Value inspect(Env *); - Value last(Env *, Value); + Value last(Env *, Optional); String to_s() const; Value to_s(Env *); bool eq(Env *, Value); bool eql(Env *, Value); bool include(Env *, Value); Value bsearch(Env *, Block *); - Value step(Env *, Value, Block *); + Value step(Env *, Optional, Block *); static Value size_fn(Env *env, Value self, Args &&, Block *) { return Value::integer(self.as_range()->to_a(env).as_array()->size()); diff --git a/include/natalie/rational_object.hpp b/include/natalie/rational_object.hpp index ef854d195..deb09c6a8 100644 --- a/include/natalie/rational_object.hpp +++ b/include/natalie/rational_object.hpp @@ -34,7 +34,7 @@ class RationalObject : public Object { Value denominator(Env *); Value div(Env *, Value); bool eq(Env *, Value); - Value floor(Env *, Value); + Value floor(Env *, Optional = {}); Value inspect(Env *); Value marshal_dump(Env *); Value mul(Env *, Value); @@ -46,7 +46,7 @@ class RationalObject : public Object { Value to_i(Env *); Value to_r() { return this; } Value to_s(Env *); - Value truncate(Env *, Value); + Value truncate(Env *, Optional); virtual void visit_children(Visitor &visitor) const override { Object::visit_children(visitor); diff --git a/include/natalie/regexp_object.hpp b/include/natalie/regexp_object.hpp index f165bcb0e..6c204c769 100644 --- a/include/natalie/regexp_object.hpp +++ b/include/natalie/regexp_object.hpp @@ -59,17 +59,24 @@ class RegexpObject : public Object { onig_free(m_regex); } - static Value compile(Env *env, Value pattern, Value flags = nullptr, ClassObject *klass = nullptr) { + static Value compile(Env *env, Value pattern, Optional flags = {}, Optional klass = {}) { if (!klass) klass = GlobalEnv::the()->Regexp(); - RegexpObject *regexp = new RegexpObject { klass }; - regexp->send(env, "initialize"_s, { pattern, flags }); + RegexpObject *regexp; + if (klass) + regexp = new RegexpObject { klass.value() }; + else + regexp = new RegexpObject; + if (flags) + regexp->send(env, "initialize"_s, { pattern, flags.value() }); + else + regexp->send(env, "initialize"_s, { pattern }); return regexp; } static EncodingObject *onig_encoding_to_ruby_encoding(OnigEncoding encoding); static OnigEncoding ruby_encoding_to_onig_encoding(NonNullPtr encoding); - static Value last_match(Env *, Value); + static Value last_match(Env *, Optional); static Value quote(Env *, Value); static Value try_convert(Env *, Value); static Value regexp_union(Env *, Args &&); @@ -172,11 +179,11 @@ class RegexpObject : public Object { return m_options & RegexOpts::FixedEncoding; } - bool has_match(Env *env, Value, Value); - Value initialize(Env *, Value, Value); + bool has_match(Env *env, Value, Optional); + Value initialize(Env *, Value, Optional); Value inspect(Env *env); Value eqtilde(Env *env, Value); - Value match(Env *env, Value, Value = nullptr, Block * = nullptr); + Value match(Env *env, Value, Optional = {}, Block * = nullptr); Value match_at_byte_offset(Env *env, StringObject *, size_t); Value named_captures(Env *) const; Value names() const; diff --git a/include/natalie/rounding_mode.hpp b/include/natalie/rounding_mode.hpp index f779c6b7e..ecf5c9500 100644 --- a/include/natalie/rounding_mode.hpp +++ b/include/natalie/rounding_mode.hpp @@ -10,6 +10,6 @@ enum class RoundingMode { Even, }; -RoundingMode rounding_mode_from_value(Env *env, Value value, RoundingMode default_rounding_mode = RoundingMode::Up); +RoundingMode rounding_mode_from_value(Env *env, Optional value, RoundingMode default_rounding_mode = RoundingMode::Up); } diff --git a/include/natalie/string_object.hpp b/include/natalie/string_object.hpp index 4f544806b..b077a37ac 100644 --- a/include/natalie/string_object.hpp +++ b/include/natalie/string_object.hpp @@ -229,9 +229,9 @@ class StringObject : public Object { Value each_grapheme_cluster(Env *, Block *); Value grapheme_clusters(Env *, Block *); - void each_line(Env *, Value, Value, std::function) const; - Value each_line(Env *, Value = nullptr, Value = nullptr, Block * = nullptr); - Value lines(Env *, Value = nullptr, Value = nullptr, Block * = nullptr); + void each_line(Env *, Optional, Optional, std::function) const; + Value each_line(Env *, Optional = {}, Optional = {}, Block * = nullptr); + Value lines(Env *, Optional = {}, Optional = {}, Block * = nullptr); SymbolObject *to_symbol(Env *) const; Value to_sym(Env *) const; @@ -285,14 +285,14 @@ class StringObject : public Object { StringObject *successive(Env *); StringObject *successive_in_place(Env *); - Value byteindex(Env *, Value, Value = nullptr) const; - Value byterindex(Env *, Value, Value = nullptr) const; + Value byteindex(Env *, Value, Optional = {}) const; + Value byterindex(Env *, Value, Optional = {}) const; - Value index(Env *, Value, Value); + Value index(Env *, Value, Optional); Value index(Env *, Value, size_t start); nat_int_t index_int(Env *, Value, size_t byte_start); - Value rindex(Env *, Value, Value = nullptr) const; + Value rindex(Env *, Value, Optional = {}) const; Value rindex(Env *, Value, size_t) const; nat_int_t rindex_int(Env *, Value, size_t) const; @@ -300,7 +300,7 @@ class StringObject : public Object { m_string.truncate(length); } - Value initialize(Env *, Value, Value, Value); + Value initialize(Env *, Optional, Optional, Optional); Value initialize_copy(Env *, Value); Value ltlt(Env *, Value); @@ -316,26 +316,26 @@ class StringObject : public Object { bool end_with(Env *, Args &&) const; bool is_empty() const { return m_string.is_empty(); } - Value gsub(Env *, Value, Value = nullptr, Block *block = nullptr); - Value gsub_in_place(Env *, Value, Value = nullptr, Block *block = nullptr); + Value gsub(Env *, Value, Optional = {}, Block *block = nullptr); + Value gsub_in_place(Env *, Value, Optional = {}, Block *block = nullptr); Value getbyte(Env *, Value) const; - Value sub(Env *, Value, Value = nullptr, Block *block = nullptr); - Value sub_in_place(Env *, Value, Value = nullptr, Block *block = nullptr); + Value sub(Env *, Value, Optional = {}, Block *block = nullptr); + Value sub_in_place(Env *, Value, Optional = {}, Block *block = nullptr); Value add(Env *, Value) const; Value append_as_bytes(Env *, Args &&); Value b(Env *) const; Value bytes(Env *, Block *); - Value byteslice(Env *, Value, Value = nullptr); + Value byteslice(Env *, Value, Optional = {}); Value bytesplice(Env *, Args &&); - StringObject *capitalize(Env *, Value, Value); - Value capitalize_in_place(Env *, Value, Value); + StringObject *capitalize(Env *, Optional, Optional); + Value capitalize_in_place(Env *, Optional, Optional); Value casecmp(Env *, Value); Value is_casecmp(Env *, Value); - Value center(Env *, Value, Value); + Value center(Env *, Value, Optional); Value chr(Env *); - Value chomp(Env *, Value) const; - Value chomp_in_place(Env *, Value); + Value chomp(Env *, Optional) const; + Value chomp_in_place(Env *, Optional = {}); Value chop(Env *) const; Value chop_in_place(Env *); Value clear(Env *); @@ -349,56 +349,56 @@ class StringObject : public Object { Value delete_prefix_in_place(Env *, Value); Value delete_suffix(Env *, Value); Value delete_suffix_in_place(Env *, Value); - StringObject *downcase(Env *, Value, Value); - Value downcase_in_place(Env *, Value = nullptr, Value = nullptr); + StringObject *downcase(Env *, Optional = {}, Optional = {}); + Value downcase_in_place(Env *, Optional = {}, Optional = {}); Value dump(Env *); Value each_byte(Env *, Block *); - Value encode(Env *, Value = nullptr, Value = nullptr, HashObject * = nullptr); - Value encode_in_place(Env *, Value = nullptr, Value = nullptr, HashObject * = nullptr); + Value encode(Env *, Optional = {}, Optional = {}, HashObject * = nullptr); + Value encode_in_place(Env *, Optional = {}, Optional = {}, HashObject * = nullptr); bool eq(Env *, Value arg); Value eqtilde(Env *, Value); Value force_encoding(Env *, Value); - bool has_match(Env *, Value, Value = nullptr); + bool has_match(Env *, Value, Optional = {}); Value hex(Env *) const; bool include(Env *, Value); bool include(const char *) const; bool include(Env *, nat_int_t) const; Value insert(Env *, Value, Value); - Value ljust(Env *, Value, Value) const; + Value ljust(Env *, Value, Optional) const; Value lstrip(Env *) const; Value lstrip_in_place(Env *); - Value match(Env *, Value, Value = nullptr, Block * = nullptr); + Value match(Env *, Value, Optional = {}, Block * = nullptr); Value mul(Env *, Value) const; Value ord(Env *) const; Value partition(Env *, Value); Value prepend(Env *, Args &&); - Value ref(Env *, Value, Value = nullptr); + Value ref(Env *, Value, Optional = {}); Value ref_slice_range_in_place(size_t, size_t); Value ref_fast_index(Env *, size_t) const; Value ref_fast_range(Env *, size_t, size_t) const; Value ref_fast_range_endless(Env *, size_t) const; - Value refeq(Env *, Value, Value, Value); + Value refeq(Env *, Value, Optional, Optional); Value reverse(Env *); Value reverse_in_place(Env *); - Value rjust(Env *, Value, Value) const; + Value rjust(Env *, Value, Optional) const; Value rstrip(Env *) const; Value rstrip_in_place(Env *); size_t char_count(Env *) const; Value scan(Env *, Value, Block * = nullptr); Value setbyte(Env *, Value, Value); Value size(Env *) const; - Value slice_in_place(Env *, Value, Value); - Value split(Env *, Value, Value); + Value slice_in_place(Env *, Value, Optional); + Value split(Env *, Optional, Optional = {}); Value split(Env *, RegexpObject *, int); Value split(Env *, StringObject *, int); Value strip(Env *) const; Value strip_in_place(Env *); - Value sum(Env *, Value = nullptr); - StringObject *swapcase(Env *, Value, Value); - Value swapcase_in_place(Env *, Value, Value); + Value sum(Env *, Optional = {}); + StringObject *swapcase(Env *, Optional, Optional); + Value swapcase_in_place(Env *, Optional, Optional); Value to_c(Env *); Value to_f(Env *) const; - Value to_i(Env *, Value = nullptr) const; + Value to_i(Env *, Optional = {}) const; Value to_r(Env *) const; Value tr(Env *, Value, Value) const; Value tr_in_place(Env *, Value, Value); @@ -406,10 +406,10 @@ class StringObject : public Object { Value uminus(Env *); Value unpack(Env *, Value, Value = nullptr) const; Value unpack1(Env *, Value, Value = nullptr) const; - StringObject *upcase(Env *, Value, Value); - Value upcase_in_place(Env *, Value, Value); + StringObject *upcase(Env *, Optional = {}, Optional = {}); + Value upcase_in_place(Env *, Optional = {}, Optional = {}); Value uplus(Env *); - Value upto(Env *, Value, Value = nullptr, Block * = nullptr); + Value upto(Env *, Value, Optional = {}, Block * = nullptr); Value convert_float(); Value convert_integer(Env *, nat_int_t base); @@ -420,6 +420,9 @@ class StringObject : public Object { ssize_t byte_index_to_char_index(size_t) const; static CaseMapType check_case_options(Env *env, Value arg1, Value arg2, bool downcase = false); + static CaseMapType check_case_options(Env *env, Optional arg1, Optional arg2, bool downcase = false) { + return check_case_options(env, arg1.value_or(Value::nil()), arg2.value_or(Value::nil()), downcase); + } unsigned char at(size_t index) const { return m_string.at(index); @@ -519,7 +522,7 @@ class StringObject : public Object { private: StringObject *expand_backrefs(Env *, StringObject *, MatchDataObject *); - void regexp_sub(Env *, TM::String &, StringObject *, RegexpObject *, Value, MatchDataObject **, StringObject **, size_t = 0, Block *block = nullptr); + void regexp_sub(Env *, TM::String &, StringObject *, RegexpObject *, Optional, MatchDataObject **, StringObject **, size_t = 0, Block *block = nullptr); nat_int_t unpack_offset(Env *, Value) const; using Object::Object; diff --git a/include/natalie/symbol_object.hpp b/include/natalie/symbol_object.hpp index e426d744f..7d77cd016 100644 --- a/include/natalie/symbol_object.hpp +++ b/include/natalie/symbol_object.hpp @@ -60,11 +60,11 @@ class SymbolObject : public Object { bool start_with(Env *, Args &&); Value eqtilde(Env *, Value); - bool has_match(Env *, Value, Value = nullptr) const; + bool has_match(Env *, Value, Optional = {}) const; Value length(Env *); Value match(Env *, Value, Block *) const; Value name(Env *) const; - Value ref(Env *, Value, Value); + Value ref(Env *, Value, Optional = {}); const String &string() const { return m_name; } EncodingObject *encoding(Env *env) const { return m_encoding; } diff --git a/include/natalie/thread/mutex_object.hpp b/include/natalie/thread/mutex_object.hpp index 48f6b259f..16e8bcc94 100644 --- a/include/natalie/thread/mutex_object.hpp +++ b/include/natalie/thread/mutex_object.hpp @@ -19,7 +19,7 @@ class Thread::MutexObject : public Object { : Object { Object::Type::ThreadMutex, klass } { } Value lock(Env *); - Value sleep(Env *, Value = nullptr); + Value sleep(Env *, Optional = {}); Value synchronize(Env *, Block *); bool try_lock(); Value unlock(Env *); diff --git a/include/natalie/thread_object.hpp b/include/natalie/thread_object.hpp index abf17983c..cfb3ac321 100644 --- a/include/natalie/thread_object.hpp +++ b/include/natalie/thread_object.hpp @@ -131,7 +131,7 @@ class ThreadObject : public Object { Value priority(Env *) const; Value set_priority(Env *, Value); - Value fetch(Env *, Value, Value = nullptr, Block * = nullptr); + Value fetch(Env *, Value, Optional = {}, Block * = nullptr); bool has_key(Env *, Value); Value keys(Env *); Value ref(Env *env, Value key); diff --git a/include/natalie/time_object.hpp b/include/natalie/time_object.hpp index ab4a7c36b..ad4a01bdb 100644 --- a/include/natalie/time_object.hpp +++ b/include/natalie/time_object.hpp @@ -3,7 +3,9 @@ #include #include "natalie/forward.hpp" +#include "natalie/integer.hpp" #include "natalie/object.hpp" +#include "tm/optional.hpp" namespace Natalie { @@ -24,13 +26,13 @@ class TimeObject : public Object { free(m_zone); } - static TimeObject *at(Env *, Value, Value, Value); - static TimeObject *at(Env *, Value, Value, Value, Value in); + static TimeObject *at(Env *, Value, Optional = {}, Optional = {}); + static TimeObject *at(Env *, Value, Optional, Optional, Optional in); static TimeObject *create(Env *); - static TimeObject *initialize(Env *, Value, Value, Value, Value, Value, Value, Value, Value in); - static TimeObject *local(Env *, Value, Value, Value, Value, Value, Value, Value); + static TimeObject *initialize(Env *, Optional, Optional, Optional, Optional, Optional, Optional, Optional, Optional in); + static TimeObject *local(Env *, Value, Optional, Optional, Optional, Optional, Optional, Optional); static TimeObject *now(Env *, Value in); - static TimeObject *utc(Env *, Value, Value, Value, Value, Value, Value, Value); + static TimeObject *utc(Env *, Value, Optional, Optional, Optional, Optional, Optional, Optional); Value add(Env *, Value); Value asctime(Env *); @@ -83,7 +85,7 @@ class TimeObject : public Object { static nat_int_t normalize_timezone(Env *, Value val); Value build_string(Env *, const char *); - void build_time(Env *, Value, Value, Value, Value, Value, Value); + void build_time(Env *, Value, Optional, Optional, Optional, Optional, Optional); void set_subsec(Env *, long); void set_subsec(Env *, Integer); void set_subsec(Env *, RationalObject *); diff --git a/lib/ffi.cpp b/lib/ffi.cpp index 28bbcf50c..fc1cc9d1b 100644 --- a/lib/ffi.cpp +++ b/lib/ffi.cpp @@ -29,7 +29,7 @@ static void *dlopen_wrapper(Env *env, const String &name) { static const auto so_ext = [&] { auto RbConfig = GlobalEnv::the()->Object()->const_fetch("RbConfig"_s).as_module(); auto CONFIG = RbConfig->const_fetch("CONFIG"_s).as_hash_or_raise(env); - auto SO_EXT = CONFIG->fetch(env, new StringObject { "SOEXT" }, nullptr, nullptr).as_string_or_raise(env); + auto SO_EXT = CONFIG->fetch(env, new StringObject { "SOEXT" }).as_string_or_raise(env); return String::format(".{}", SO_EXT->string()); }(); if (!name.begins_with('/') && !name.ends_with(so_ext)) { @@ -95,7 +95,7 @@ Value FFI_Library_ffi_lib(Env *env, Value self, Args &&args, Block *) { auto error = new StringObject; for (auto name2 : *name.as_array()) error->append_sprintf("Could not open library '%s': %s.\n", name2.as_string()->string().c_str(), dlerror()); - error->chomp_in_place(env, nullptr); + error->chomp_in_place(env); env->raise("LoadError", error->string()); } } else { diff --git a/lib/natalie/compiler/binding_gen.rb b/lib/natalie/compiler/binding_gen.rb index 75f5e3e9a..146bac826 100644 --- a/lib/natalie/compiler/binding_gen.rb +++ b/lib/natalie/compiler/binding_gen.rb @@ -99,6 +99,7 @@ def initialize( cast_self: false, # only relevant when cpp_function_type: :static module_function: false, pass_klass: false, + pass_null: true, # transitional setting, as we eliminate passing nullptr for missing arguments kwargs: nil, visibility: :public, aliases: [] @@ -117,6 +118,7 @@ def initialize( @cast_self = cast_self @module_function = module_function @pass_klass = pass_klass + @pass_null = pass_null @kwargs = kwargs @visibility = visibility @aliases = aliases @@ -139,6 +141,7 @@ def pass_env? = !!@pass_env def pass_self? = !!@pass_self def cast_self? = !!@cast_self def pass_klass? = !!@pass_klass + def pass_null? = !!@pass_null def pass_block? = !!@pass_block def module_function? = !!@module_function @@ -277,8 +280,22 @@ def set_visibility_method_name def pop_kwargs case @kwargs when Array - "auto kwargs = args.pop_keyword_hash();\n" + - @kwargs.map { |kw| "auto kwarg_#{kw} = kwargs ? kwargs->remove(env, #{kw.to_s.inspect}_s) : nullptr;" }.join("\n") + if pass_null? + "auto kwargs = args.pop_keyword_hash();\n" + + @kwargs.map { |kw| "auto kwarg_#{kw} = kwargs ? kwargs->remove(env, #{kw.to_s.inspect}_s) : nullptr;" }.join("\n") + else + [ + "auto kwargs = args.pop_keyword_hash();", + ].tap do |lines| + @kwargs.each do |kw| + lines << "Optional kwarg_#{kw};" + lines << 'if (kwargs) {' + lines << "auto value_or_null = kwargs->remove(env, #{kw.to_s.inspect}_s);" + lines << "if (value_or_null != nullptr) kwarg_#{kw} = value_or_null;" + lines << '}' + end + end.join("\n") + end when true "auto kwargs = args.pop_keyword_hash();\n" end @@ -307,7 +324,17 @@ def kwargs_assertion def args if max_argc - (0...max_argc).map { |i| "args.at(#{i}, nullptr)" } + if pass_null? + (0...max_argc).map { |i| "args.at(#{i}, nullptr)" } + else + (0...max_argc).map do |i| + if i < min_argc + "args.at(#{i})" + else + "args.size() > #{i} && !args.at(#{i}).is_null() ? Optional(args.at(#{i})) : Optional()" + end + end + end else ['std::move(args)'] end @@ -328,6 +355,17 @@ def return_code end end + def min_argc + case argc + when :any + nil + when Range + argc.begin + when Integer + argc + end + end + def max_argc case argc when :any @@ -373,8 +411,8 @@ def generate_name gen.binding('Array', 'eql?', 'ArrayObject', 'eql', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Array', '==', 'ArrayObject', 'eq', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Array', '===', 'ArrayObject', 'eq', argc: 1, pass_env: true, pass_block: false, return_type: :bool) -gen.binding('Array', '[]', 'ArrayObject', 'ref', argc: 1..2, pass_env: true, pass_block: false, aliases: ['slice'], return_type: :Object) -gen.binding('Array', '[]=', 'ArrayObject', 'refeq', argc: 2..3, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', '[]', 'ArrayObject', 'ref', argc: 1..2, pass_env: true, pass_block: false, aliases: ['slice'], return_type: :Object, pass_null: false) +gen.binding('Array', '[]=', 'ArrayObject', 'refeq', argc: 2..3, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'any?', 'ArrayObject', 'any', argc: :any, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'at', 'ArrayObject', 'at', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'assoc', 'ArrayObject', 'assoc', argc: 1, pass_env: true, pass_block: false, return_type: :Object) @@ -386,7 +424,7 @@ def generate_name gen.binding('Array', 'concat', 'ArrayObject', 'concat', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'compact', 'ArrayObject', 'compact', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'compact!', 'ArrayObject', 'compact_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Array', 'cycle', 'ArrayObject', 'cycle', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Array', 'cycle', 'ArrayObject', 'cycle', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Array', 'deconstruct', 'Object', 'itself', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('Array', 'delete', 'ArrayObject', 'delete_item', argc: 1, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'delete_at', 'ArrayObject', 'delete_at', argc: 1, pass_env: true, pass_block: false, return_type: :Object) @@ -398,31 +436,31 @@ def generate_name gen.binding('Array', 'each', 'ArrayObject', 'each', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'each_index', 'ArrayObject', 'each_index', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'empty?', 'ArrayObject', 'is_empty', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('Array', 'fetch', 'ArrayObject', 'fetch', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Array', 'fill', 'ArrayObject', 'fill', argc: 0..3, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Array', 'find_index', 'ArrayObject', 'index', argc: 0..1, pass_env: true, pass_block: true, aliases: ['index'], return_type: :Object) -gen.binding('Array', 'first', 'ArrayObject', 'first', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Array', 'flatten', 'ArrayObject', 'flatten', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Array', 'flatten!', 'ArrayObject', 'flatten_in_place', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', 'fetch', 'ArrayObject', 'fetch', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('Array', 'fill', 'ArrayObject', 'fill', argc: 0..3, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('Array', 'find_index', 'ArrayObject', 'index', argc: 0..1, pass_env: true, pass_block: true, aliases: ['index'], return_type: :Object, pass_null: false) +gen.binding('Array', 'first', 'ArrayObject', 'first', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Array', 'flatten', 'ArrayObject', 'flatten', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Array', 'flatten!', 'ArrayObject', 'flatten_in_place', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'hash', 'ArrayObject', 'hash', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'include?', 'ArrayObject', 'include', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Array', 'intersection', 'ArrayObject', 'intersection', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'intersect?', 'ArrayObject', 'intersects', argc: 1, pass_env: true, pass_block: false, return_type: :bool) -gen.binding('Array', 'initialize', 'ArrayObject', 'initialize', argc: 0..2, pass_env: true, pass_block: true, return_type: :Object, visibility: :private) +gen.binding('Array', 'initialize', 'ArrayObject', 'initialize', argc: 0..2, pass_env: true, pass_block: true, return_type: :Object, visibility: :private, pass_null: false) gen.binding('Array', 'initialize_copy', 'ArrayObject', 'initialize_copy', argc: 1, pass_env: true, pass_block: false, aliases: ['replace'], return_type: :Object) gen.binding('Array', 'insert', 'ArrayObject', 'insert', argc: 1.., pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'inspect', 'ArrayObject', 'inspect', argc: 0, pass_env: true, pass_block: false, aliases: ['to_s'], return_type: :Object) -gen.binding('Array', 'join', 'ArrayObject', 'join', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', 'join', 'ArrayObject', 'join', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'keep_if', 'ArrayObject', 'keep_if', argc: 0, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Array', 'last', 'ArrayObject', 'last', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', 'last', 'ArrayObject', 'last', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'length', 'ArrayObject', 'size', argc: 0, pass_env: false, pass_block: false, aliases: ['size'], return_type: :size_t) -gen.binding('Array', 'max', 'ArrayObject', 'max', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Array', 'min', 'ArrayObject', 'min', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Array', 'max', 'ArrayObject', 'max', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('Array', 'min', 'ArrayObject', 'min', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('Array', 'minmax', 'ArrayObject', 'minmax', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'none?', 'ArrayObject', 'none', argc: :any, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'one?', 'ArrayObject', 'one', argc: :any, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'pack', 'ArrayObject', 'pack', argc: 1, kwargs: [:buffer], pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Array', 'pop', 'ArrayObject', 'pop', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', 'pop', 'ArrayObject', 'pop', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'product', 'ArrayObject', 'product', argc: :any, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'push', 'ArrayObject', 'push', argc: :any, pass_env: true, pass_block: false, aliases: ['append'], return_type: :Object) gen.binding('Array', 'rassoc', 'ArrayObject', 'rassoc', argc: 1, pass_env: true, pass_block: false, return_type: :Object) @@ -431,13 +469,13 @@ def generate_name gen.binding('Array', 'reverse', 'ArrayObject', 'reverse', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'reverse!', 'ArrayObject', 'reverse_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Array', 'reverse_each', 'ArrayObject', 'reverse_each', argc: 0, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Array', 'rindex', 'ArrayObject', 'rindex', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Array', 'rotate', 'ArrayObject', 'rotate', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Array', 'rotate!', 'ArrayObject', 'rotate_in_place', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', 'rindex', 'ArrayObject', 'rindex', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('Array', 'rotate', 'ArrayObject', 'rotate', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Array', 'rotate!', 'ArrayObject', 'rotate_in_place', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'select', 'ArrayObject', 'select', argc: 0, pass_env: true, pass_block: true, aliases: ['filter'], return_type: :Object) gen.binding('Array', 'select!', 'ArrayObject', 'select_in_place', argc: 0, pass_env: true, pass_block: true, aliases: ['filter!'], return_type: :Object) -gen.binding('Array', 'shift', 'ArrayObject', 'shift', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Array', 'slice!', 'ArrayObject', 'slice_in_place', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Array', 'shift', 'ArrayObject', 'shift', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Array', 'slice!', 'ArrayObject', 'slice_in_place', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Array', 'sort', 'ArrayObject', 'sort', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'sort!', 'ArrayObject', 'sort_in_place', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Array', 'sort_by!', 'ArrayObject', 'sort_by_in_place', argc: 0, pass_env: true, pass_block: true, return_type: :Object) @@ -467,7 +505,7 @@ def generate_name gen.binding('Binding', 'source_location', 'BindingObject', 'source_location', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.undefine_instance_method('Class', 'module_function') -gen.binding('Class', 'initialize', 'ClassObject', 'initialize', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, visibility: :private) +gen.binding('Class', 'initialize', 'ClassObject', 'initialize', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, visibility: :private, pass_null: false) gen.binding('Class', 'superclass', 'ClassObject', 'superclass', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Class', 'singleton_class?', 'ClassObject', 'is_singleton', argc: 0, pass_env: false, pass_block: false, return_type: :bool) @@ -756,13 +794,13 @@ def generate_name gen.binding('Float', '>=', 'FloatObject', 'gte', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Float', 'abs', 'FloatObject', 'abs', argc: 0, pass_env: true, pass_block: false, aliases: ['magnitude'], return_type: :Object) gen.binding('Float', 'arg', 'FloatObject', 'arg', argc: 0, pass_env: true, pass_block: false, aliases: %w[phase angle], return_type: :Object) -gen.binding('Float', 'ceil', 'FloatObject', 'ceil', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Float', 'ceil', 'FloatObject', 'ceil', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Float', 'coerce', 'FloatObject', 'coerce', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Float', 'denominator', 'FloatObject', 'denominator', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Float', 'divmod', 'FloatObject', 'divmod', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Float', 'eql?', 'FloatObject', 'eql', argc: 1, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Float', 'finite?', 'FloatObject', 'is_finite', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('Float', 'floor', 'FloatObject', 'floor', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Float', 'floor', 'FloatObject', 'floor', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Float', 'infinite?', 'FloatObject', 'is_infinite', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Float', 'nan?', 'FloatObject', 'is_nan', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Float', 'negative?', 'FloatObject', 'is_negative', argc: 0, pass_env: false, pass_block: false, return_type: :bool) @@ -771,12 +809,12 @@ def generate_name gen.binding('Float', 'positive?', 'FloatObject', 'is_positive', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Float', 'prev_float', 'FloatObject', 'prev_float', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Float', 'quo', 'FloatObject', 'div', argc: 1, pass_env: true, pass_block: false, aliases: ['fdiv'], return_type: :Object) -gen.binding('Float', 'round', 'FloatObject', 'round', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Float', 'round', 'FloatObject', 'round', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Float', 'to_f', 'FloatObject', 'to_f', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('Float', 'to_i', 'FloatObject', 'to_i', argc: 0, pass_env: true, pass_block: false, aliases: ['to_int'], return_type: :Object) gen.binding('Float', 'to_r', 'FloatObject', 'to_r', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Float', 'to_s', 'FloatObject', 'to_s', argc: 0, pass_env: false, pass_block: false, aliases: ['inspect'], return_type: :Object) -gen.binding('Float', 'truncate', 'FloatObject', 'truncate', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Float', 'truncate', 'FloatObject', 'truncate', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Float', 'zero?', 'FloatObject', 'is_zero', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.static_binding_as_class_method('GC', 'enable', 'GCModule', 'enable', argc: 0, pass_env: false, pass_block: false, return_type: :bool) @@ -799,7 +837,7 @@ def generate_name gen.binding('Hash', 'compact!', 'HashObject', 'compact_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Hash', 'compare_by_identity', 'HashObject', 'compare_by_identity', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Hash', 'compare_by_identity?', 'HashObject', 'is_comparing_by_identity', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('Hash', 'default', 'HashObject', 'get_default', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Hash', 'default', 'HashObject', 'get_default', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Hash', 'default=', 'HashObject', 'set_default', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Hash', 'default_proc', 'HashObject', 'default_proc', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Hash', 'default_proc=', 'HashObject', 'set_default_proc', argc: 1, pass_env: true, pass_block: false, return_type: :Object) @@ -810,11 +848,11 @@ def generate_name gen.binding('Hash', 'empty?', 'HashObject', 'is_empty', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Hash', 'eql?', 'HashObject', 'eql', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Hash', 'except', 'HashObject', 'except', argc: :any, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Hash', 'fetch', 'HashObject', 'fetch', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Hash', 'fetch', 'HashObject', 'fetch', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('Hash', 'fetch_values', 'HashObject', 'fetch_values', argc: :any, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Hash', 'hash', 'HashObject', 'hash', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Hash', 'has_value?', 'HashObject', 'has_value', argc: 1, pass_env: true, pass_block: false, aliases: ['value?'], return_type: :bool) -gen.binding('Hash', 'initialize', 'HashObject', 'initialize', argc: 0..1, kwargs: [:capacity], pass_env: true, pass_block: true, return_type: :Object, visibility: :private) +gen.binding('Hash', 'initialize', 'HashObject', 'initialize', argc: 0..1, kwargs: [:capacity], pass_env: true, pass_block: true, return_type: :Object, visibility: :private, pass_null: false) gen.binding('Hash', 'initialize_copy', 'HashObject', 'replace', argc: 1, pass_env: true, pass_block: false, aliases: ['replace'], return_type: :Object) gen.binding('Hash', 'inspect', 'HashObject', 'inspect', argc: 0, pass_env: true, pass_block: false, aliases: ['to_s'], return_type: :Object) gen.binding('Hash', 'include?', 'HashObject', 'has_key', argc: 1, pass_env: true, pass_block: false, aliases: ['member?', 'has_key?', 'key?'], return_type: :bool) @@ -847,33 +885,33 @@ def generate_name gen.static_binding_as_instance_method('Integer', '<=', 'IntegerMethods', 'lte', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :bool) gen.static_binding_as_instance_method('Integer', '>', 'IntegerMethods', 'gt', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :bool) gen.static_binding_as_instance_method('Integer', '>>', 'IntegerMethods', 'right_shift', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Integer', '[]', 'IntegerMethods', 'ref', argc: 1..2, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Integer', '[]', 'IntegerMethods', 'ref', argc: 1..2, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Integer', '>=', 'IntegerMethods', 'gte', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :bool) gen.static_binding_as_instance_method('Integer', '===', 'IntegerMethods', 'eq', argc: 1, pass_env: true, cast_self: true, pass_block: false, aliases: ['=='], return_type: :bool) gen.static_binding_as_instance_method('Integer', '^', 'IntegerMethods', 'bitwise_xor', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'abs', 'IntegerMethods', 'abs', argc: 0, pass_env: true, cast_self: true, pass_block: false, aliases: ['magnitude'], return_type: :Object) gen.static_binding_as_instance_method('Integer', 'bit_length', 'IntegerMethods', 'bit_length', argc: 0, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Integer', 'chr', 'IntegerMethods', 'chr', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Integer', 'ceil', 'IntegerMethods', 'ceil', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Integer', 'chr', 'IntegerMethods', 'chr', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) +gen.static_binding_as_instance_method('Integer', 'ceil', 'IntegerMethods', 'ceil', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Integer', 'coerce', 'IntegerMethods', 'coerce', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'denominator', 'IntegerMethods', 'denominator', argc: 0, pass_env: false, pass_self: false, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'even?', 'IntegerMethods', 'is_even', argc: 0, pass_env: false, cast_self: true, pass_block: false, return_type: :bool) -gen.static_binding_as_instance_method('Integer', 'floor', 'IntegerMethods', 'floor', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Integer', 'floor', 'IntegerMethods', 'floor', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Integer', 'gcd', 'IntegerMethods', 'gcd', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'inspect', 'IntegerMethods', 'inspect', argc: 0, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'numerator', 'IntegerMethods', 'numerator', argc: 0, pass_env: false, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'odd?', 'IntegerMethods', 'is_odd', argc: 0, pass_env: false, cast_self: true, pass_block: false, return_type: :bool) gen.static_binding_as_instance_method('Integer', 'ord', 'IntegerMethods', 'ord', argc: 0, pass_env: false, cast_self: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Integer', 'round', 'IntegerMethods', 'round', argc: 0..1, pass_env: true, cast_self: true, kwargs: [:half], pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Integer', 'round', 'IntegerMethods', 'round', argc: 0..1, pass_env: true, cast_self: true, kwargs: [:half], pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Integer', 'size', 'IntegerMethods', 'size', argc: 0, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'succ', 'IntegerMethods', 'succ', argc: 0, pass_env: true, cast_self: true, pass_block: false, aliases: ['next'], return_type: :Object) -gen.static_binding_as_instance_method('Integer', 'pow', 'IntegerMethods', 'powmod', argc: 1..2, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Integer', 'pow', 'IntegerMethods', 'powmod', argc: 1..2, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Integer', 'pred', 'IntegerMethods', 'pred', argc: 0, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'times', 'IntegerMethods', 'times', argc: 0, pass_env: true, cast_self: true, pass_block: true, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'to_f', 'IntegerMethods', 'to_f', argc: 0, pass_env: false, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'to_i', 'IntegerMethods', 'to_i', argc: 0, pass_env: false, cast_self: true, pass_block: false, aliases: ['to_int'], return_type: :Object) -gen.static_binding_as_instance_method('Integer', 'to_s', 'IntegerMethods', 'to_s', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Integer', 'truncate', 'IntegerMethods', 'truncate', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Integer', 'to_s', 'IntegerMethods', 'to_s', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) +gen.static_binding_as_instance_method('Integer', 'truncate', 'IntegerMethods', 'truncate', argc: 0..1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Integer', '|', 'IntegerMethods', 'bitwise_or', argc: 1, pass_env: true, cast_self: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Integer', 'zero?', 'IntegerMethods', 'is_zero', argc: 0, pass_env: false, cast_self: true, pass_block: false, return_type: :bool) @@ -975,7 +1013,7 @@ def generate_name gen.module_function_binding('Kernel', 'Rational', 'KernelModule', 'Rational', argc: 1..2, kwargs: [:exception], pass_env: true, pass_block: false, return_type: :Object) gen.module_function_binding('Kernel', 'sleep', 'KernelModule', 'sleep', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) gen.module_function_binding('Kernel', 'spawn', 'KernelModule', 'spawn', argc: 1.., pass_env: true, pass_block: false, return_type: :Object) -gen.module_function_binding('Kernel', 'srand', 'RandomObject', 'srand', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.module_function_binding('Kernel', 'srand', 'RandomObject', 'srand', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.module_function_binding('Kernel', 'String', 'KernelModule', 'String', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.module_function_binding('Kernel', 'test', 'KernelModule', 'test', argc: 2, pass_env: true, pass_block: false, return_type: :Object) gen.module_function_binding('Kernel', 'throw', 'KernelModule', 'throw_method', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) @@ -997,12 +1035,12 @@ def generate_name gen.static_binding_as_instance_method('Kernel', 'kind_of?', 'KernelModule', 'is_a', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.static_binding_as_instance_method('Kernel', 'loop', 'KernelModule', 'loop', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.static_binding_as_instance_method('Kernel', 'method', 'KernelModule', 'method', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Kernel', 'methods', 'KernelModule', 'methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Kernel', 'methods', 'KernelModule', 'methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Kernel', 'nil?', 'KernelModule', 'is_nil', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.static_binding_as_instance_method('Kernel', 'object_id', 'Object', 'object_id', argc: 0, pass_env: false, pass_block: false, return_type: :int) -gen.static_binding_as_instance_method('Kernel', 'private_methods', 'KernelModule', 'private_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Kernel', 'protected_methods', 'KernelModule', 'protected_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_instance_method('Kernel', 'public_methods', 'KernelModule', 'public_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.static_binding_as_instance_method('Kernel', 'private_methods', 'KernelModule', 'private_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.static_binding_as_instance_method('Kernel', 'protected_methods', 'KernelModule', 'protected_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.static_binding_as_instance_method('Kernel', 'public_methods', 'KernelModule', 'public_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_instance_method('Kernel', 'remove_instance_variable', 'KernelModule', 'remove_instance_variable', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Kernel', 'singleton_class', 'Object', 'singleton_class', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.static_binding_as_instance_method('Kernel', 'tap', 'KernelModule', 'tap', argc: 0, pass_env: true, pass_block: true, return_type: :Object) @@ -1064,20 +1102,20 @@ def generate_name gen.binding('Module', 'class_variable_defined?', 'ModuleObject', 'class_variable_defined', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Module', 'class_variable_get', 'ModuleObject', 'class_variable_get', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'class_variable_set', 'ModuleObject', 'class_variable_set', argc: 2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'class_variables', 'ModuleObject', 'class_variables', argc: 0..1, pass_env: false, pass_block: false, return_type: :Object) -gen.binding('Module', 'const_defined?', 'ModuleObject', 'const_defined', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool) -gen.binding('Module', 'const_get', 'ModuleObject', 'const_get', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Module', 'class_variables', 'ModuleObject', 'class_variables', argc: 0..1, pass_env: false, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Module', 'const_defined?', 'ModuleObject', 'const_defined', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool, pass_null: false) +gen.binding('Module', 'const_get', 'ModuleObject', 'const_get', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Module', 'const_missing', 'ModuleObject', 'const_missing', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'const_set', 'ModuleObject', 'const_set', argc: 2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'constants', 'ModuleObject', 'constants', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'define_method', 'ModuleObject', 'define_method', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Module', 'constants', 'ModuleObject', 'constants', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Module', 'define_method', 'ModuleObject', 'define_method', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('Module', 'deprecate_constant', 'ModuleObject', 'deprecate_constant', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'extend_object', 'ModuleObject', 'extend_object', argc: 1, pass_env: true, pass_block: false, return_type: :Object, visibility: :private) gen.binding('Module', 'include', 'ModuleObject', 'include', argc: 1.., pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'include?', 'ModuleObject', 'does_include_module', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Module', 'included_modules', 'ModuleObject', 'included_modules', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'instance_method', 'ModuleObject', 'instance_method', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'instance_methods', 'ModuleObject', 'instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Module', 'instance_methods', 'ModuleObject', 'instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Module', 'method_defined?', 'ModuleObject', 'is_method_defined', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Module', 'module_eval', 'ModuleObject', 'module_eval', argc: 0, pass_env: true, pass_block: true, aliases: ['class_eval'], return_type: :Object) gen.binding('Module', 'module_exec', 'ModuleObject', 'module_exec', argc: :any, pass_env: true, pass_block: true, aliases: ['class_exec'], return_type: :Object) @@ -1087,13 +1125,13 @@ def generate_name gen.binding('Module', 'private', 'ModuleObject', 'private_method', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'private_class_method', 'ModuleObject', 'private_class_method', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'private_constant', 'ModuleObject', 'private_constant', argc: :any, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'private_instance_methods', 'ModuleObject', 'private_instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Module', 'private_instance_methods', 'ModuleObject', 'private_instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Module', 'protected', 'ModuleObject', 'protected_method', argc: :any, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'protected_instance_methods', 'ModuleObject', 'protected_instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Module', 'protected_instance_methods', 'ModuleObject', 'protected_instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Module', 'public', 'ModuleObject', 'public_method', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'public_class_method', 'ModuleObject', 'public_class_method', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'public_constant', 'ModuleObject', 'public_constant', argc: :any, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Module', 'public_instance_methods', 'ModuleObject', 'public_instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Module', 'public_instance_methods', 'ModuleObject', 'public_instance_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Module', 'public_instance_method', 'ModuleObject', 'public_instance_method', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'remove_class_variable', 'ModuleObject', 'remove_class_variable', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Module', 'remove_const', 'ModuleObject', 'remove_const', argc: 1, pass_env: true, pass_block: false, return_type: :Object, visibility: :private) @@ -1171,14 +1209,14 @@ def generate_name gen.module_function_binding('Process::UID', 'rid', 'ProcessModule', 'uid', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.static_binding_as_class_method('Random', 'new_seed', 'RandomObject', 'new_seed', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_class_method('Random', 'srand', 'RandomObject', 'srand', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.static_binding_as_class_method('Random', 'srand', 'RandomObject', 'srand', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_class_method('Random', 'urandom', 'RandomObject', 'urandom', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Random', 'initialize', 'RandomObject', 'initialize', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, visibility: :private) +gen.binding('Random', 'initialize', 'RandomObject', 'initialize', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, visibility: :private, pass_null: false) gen.binding('Random', 'bytes', 'RandomObject', 'bytes', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Random', 'rand', 'RandomObject', 'rand', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Random', 'rand', 'RandomObject', 'rand', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Random', 'seed', 'RandomObject', 'seed', argc: 0, pass_env: false, pass_block: false, return_type: :Object) -gen.binding('Range', '%', 'RangeObject', 'step', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Range', '%', 'RangeObject', 'step', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('Range', '==', 'RangeObject', 'eq', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Range', 'begin', 'RangeObject', 'begin', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('Range', 'bsearch', 'RangeObject', 'bsearch', argc: 0, pass_env: true, pass_block: true, return_type: :Object) @@ -1186,12 +1224,12 @@ def generate_name gen.binding('Range', 'each', 'RangeObject', 'each', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Range', 'eql?', 'RangeObject', 'eql', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Range', 'exclude_end?', 'RangeObject', 'exclude_end', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('Range', 'first', 'RangeObject', 'first', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Range', 'initialize', 'RangeObject', 'initialize', argc: 2..3, pass_env: true, pass_block: false, return_type: :Object, visibility: :private) +gen.binding('Range', 'first', 'RangeObject', 'first', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('Range', 'initialize', 'RangeObject', 'initialize', argc: 2..3, pass_env: true, pass_block: false, return_type: :Object, visibility: :private, pass_null: false) gen.binding('Range', 'inspect', 'RangeObject', 'inspect', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Range', 'last', 'RangeObject', 'last', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Range', 'last', 'RangeObject', 'last', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Range', 'member?', 'RangeObject', 'include', argc: 1, pass_env: true, pass_block: false, aliases: ['include?'], return_type: :bool) -gen.binding('Range', 'step', 'RangeObject', 'step', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Range', 'step', 'RangeObject', 'step', argc: 0..1, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('Range', 'to_a', 'RangeObject', 'to_a', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Range', 'to_s', 'RangeObject', 'to_s', argc: 0, pass_env: true, pass_block: false, return_type: :Object) @@ -1205,7 +1243,7 @@ def generate_name gen.binding('Rational', '==', 'RationalObject', 'eq', argc: 1, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Rational', 'coerce', 'RationalObject', 'coerce', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Rational', 'denominator', 'RationalObject', 'denominator', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Rational', 'floor', 'RationalObject', 'floor', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Rational', 'floor', 'RationalObject', 'floor', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Rational', 'inspect', 'RationalObject', 'inspect', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Rational', 'marshal_dump', 'RationalObject', 'marshal_dump', argc: 0, pass_env: true, pass_block: false, return_type: :Object, visibility: :private) gen.binding('Rational', 'numerator', 'RationalObject', 'numerator', argc: 0, pass_env: true, pass_block: false, return_type: :Object) @@ -1214,12 +1252,12 @@ def generate_name gen.binding('Rational', 'to_i', 'RationalObject', 'to_i', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Rational', 'to_r', 'RationalObject', 'to_r', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('Rational', 'to_s', 'RationalObject', 'to_s', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Rational', 'truncate', 'RationalObject', 'truncate', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Rational', 'truncate', 'RationalObject', 'truncate', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Rational', 'zero?', 'RationalObject', 'is_zero', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.static_binding_as_class_method('Regexp', 'compile', 'RegexpObject', 'compile', argc: 1..2, pass_env: true, pass_block: false, pass_klass: true, return_type: :Object) +gen.static_binding_as_class_method('Regexp', 'compile', 'RegexpObject', 'compile', argc: 1..2, pass_env: true, pass_block: false, pass_klass: true, return_type: :Object, pass_null: false) gen.static_binding_as_class_method('Regexp', 'escape', 'RegexpObject', 'quote', argc: 1, pass_env: true, pass_block: false, pass_klass: false, aliases: ['quote'], return_type: :Object) -gen.static_binding_as_class_method('Regexp', 'last_match', 'RegexpObject', 'last_match', argc: 0..1, pass_env: true, pass_block: false, pass_klass: false, return_type: :Object) +gen.static_binding_as_class_method('Regexp', 'last_match', 'RegexpObject', 'last_match', argc: 0..1, pass_env: true, pass_block: false, pass_klass: false, return_type: :Object, pass_null: false) gen.static_binding_as_class_method('Regexp', 'try_convert', 'RegexpObject', 'try_convert', argc: 1, pass_env: true, pass_block: false, pass_klass: false, return_type: :Object) gen.static_binding_as_class_method('Regexp', 'union', 'RegexpObject', 'regexp_union', argc: :any, pass_env: true, pass_block: false, pass_klass: false, return_type: :Object) gen.binding('Regexp', '===', 'RegexpObject', 'eqeqeq', argc: 1, pass_env: true, pass_block: false, return_type: :bool) @@ -1230,10 +1268,10 @@ def generate_name gen.binding('Regexp', 'eql?', 'RegexpObject', 'eq', argc: 1, pass_env: true, pass_block: false, aliases: ['=='], return_type: :bool) gen.binding('Regexp', 'fixed_encoding?', 'RegexpObject', 'is_fixed_encoding', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Regexp', 'hash', 'RegexpObject', 'hash', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Regexp', 'initialize', 'RegexpObject', 'initialize', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, visibility: :private) +gen.binding('Regexp', 'initialize', 'RegexpObject', 'initialize', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, visibility: :private, pass_null: false) gen.binding('Regexp', 'inspect', 'RegexpObject', 'inspect', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Regexp', 'match', 'RegexpObject', 'match', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Regexp', 'match?', 'RegexpObject', 'has_match', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool) +gen.binding('Regexp', 'match', 'RegexpObject', 'match', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('Regexp', 'match?', 'RegexpObject', 'has_match', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool, pass_null: false) gen.binding('Regexp', 'named_captures', 'RegexpObject', 'named_captures', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Regexp', 'names', 'RegexpObject', 'names', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('Regexp', 'options', 'RegexpObject', 'options', argc: 0, pass_env: true, pass_block: false, return_type: :int) @@ -1251,25 +1289,25 @@ def generate_name gen.binding('String', '<=>', 'StringObject', 'cmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', '==', 'StringObject', 'eq', argc: 1, pass_env: true, pass_block: false, aliases: ['==='], return_type: :bool) gen.binding('String', '=~', 'StringObject', 'eqtilde', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', '[]', 'StringObject', 'ref', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', '[]=', 'StringObject', 'refeq', argc: 1..3, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', '[]', 'StringObject', 'ref', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', '[]=', 'StringObject', 'refeq', argc: 1..3, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'ascii_only?', 'StringObject', 'is_ascii_only', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('String', 'append_as_bytes', 'StringObject', 'append_as_bytes', argc: 1.., pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'b', 'StringObject', 'b', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'bytes', 'StringObject', 'bytes', argc: 0, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'byteindex', 'StringObject', 'byteindex', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'byterindex', 'StringObject', 'byterindex', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'byteslice', 'StringObject', 'byteslice', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'byteindex', 'StringObject', 'byteindex', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'byterindex', 'StringObject', 'byterindex', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'byteslice', 'StringObject', 'byteslice', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'bytesplice', 'StringObject', 'bytesplice', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'bytesize', 'StringObject', 'bytesize', argc: 0, pass_env: false, pass_block: false, return_type: :size_t) -gen.binding('String', 'capitalize', 'StringObject', 'capitalize', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'capitalize!', 'StringObject', 'capitalize_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'capitalize', 'StringObject', 'capitalize', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'capitalize!', 'StringObject', 'capitalize_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'casecmp', 'StringObject', 'casecmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'casecmp?', 'StringObject', 'is_casecmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'center', 'StringObject', 'center', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'center', 'StringObject', 'center', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'chars', 'StringObject', 'chars', argc: 0, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'chomp', 'StringObject', 'chomp', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'chomp!', 'StringObject', 'chomp_in_place', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'chomp', 'StringObject', 'chomp', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'chomp!', 'StringObject', 'chomp_in_place', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'chop', 'StringObject', 'chop', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'chop!', 'StringObject', 'chop_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'chr', 'StringObject', 'chr', argc: 0, pass_env: true, pass_block: false, return_type: :Object) @@ -1285,65 +1323,65 @@ def generate_name gen.binding('String', 'delete_prefix!', 'StringObject', 'delete_prefix_in_place', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'delete_suffix', 'StringObject', 'delete_suffix', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'delete_suffix!', 'StringObject', 'delete_suffix_in_place', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'downcase', 'StringObject', 'downcase', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'downcase!', 'StringObject', 'downcase_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'downcase', 'StringObject', 'downcase', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'downcase!', 'StringObject', 'downcase_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'each_byte', 'StringObject', 'each_byte', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('String', 'each_char', 'StringObject', 'each_char', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('String', 'each_codepoint', 'StringObject', 'each_codepoint', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('String', 'each_grapheme_cluster', 'StringObject', 'each_grapheme_cluster', argc: 0, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'each_line', 'StringObject', 'each_line', argc: 0..1, kwargs: [:chomp], pass_env: true, pass_block: true, return_type: :Object) +gen.binding('String', 'each_line', 'StringObject', 'each_line', argc: 0..1, kwargs: [:chomp], pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('String', 'empty?', 'StringObject', 'is_empty', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('String', 'encode', 'StringObject', 'encode', argc: 0..2, kwargs: true, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'encode!', 'StringObject', 'encode_in_place', argc: 0..2, kwargs: true, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'encode', 'StringObject', 'encode', argc: 0..2, kwargs: true, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'encode!', 'StringObject', 'encode_in_place', argc: 0..2, kwargs: true, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'encoding', 'StringObject', 'encoding', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('String', 'end_with?', 'StringObject', 'end_with', argc: :any, pass_env: true, pass_block: false, return_type: :bool) gen.binding('String', 'eql?', 'StringObject', 'eql', argc: 1, pass_env: false, pass_block: false, return_type: :bool) gen.binding('String', 'force_encoding', 'StringObject', 'force_encoding', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'getbyte', 'StringObject', 'getbyte', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'grapheme_clusters', 'StringObject', 'grapheme_clusters', argc: 0, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'gsub', 'StringObject', 'gsub', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'gsub!', 'StringObject', 'gsub_in_place', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('String', 'gsub', 'StringObject', 'gsub', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('String', 'gsub!', 'StringObject', 'gsub_in_place', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('String', 'hex', 'StringObject', 'hex', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'include?', 'StringObject', 'include', argc: 1, pass_env: true, pass_block: false, return_type: :bool) -gen.binding('String', 'index', 'StringObject', 'index', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'initialize', 'StringObject', 'initialize', argc: 0..1, kwargs: %i[encoding capacity], pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'index', 'StringObject', 'index', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'initialize', 'StringObject', 'initialize', argc: 0..1, kwargs: %i[encoding capacity], pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'initialize_copy', 'StringObject', 'initialize_copy', argc: 1, pass_env: true, pass_block: false, aliases: ['replace'], return_type: :Object) gen.binding('String', 'insert', 'StringObject', 'insert', argc: 2, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'inspect', 'StringObject', 'inspect', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'intern', 'StringObject', 'to_sym', argc: 0, pass_env: true, pass_block: false, aliases: ['to_sym'], return_type: :Object) gen.binding('String', 'length', 'StringObject', 'size', argc: 0, pass_env: true, pass_block: false, aliases: ['size'], return_type: :Object) -gen.binding('String', 'lines', 'StringObject', 'lines', argc: 0..1, kwargs: [:chomp], pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'ljust', 'StringObject', 'ljust', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'lines', 'StringObject', 'lines', argc: 0..1, kwargs: [:chomp], pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('String', 'ljust', 'StringObject', 'ljust', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'lstrip', 'StringObject', 'lstrip', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'lstrip!', 'StringObject', 'lstrip_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'match', 'StringObject', 'match', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'match?', 'StringObject', 'has_match', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool) +gen.binding('String', 'match', 'StringObject', 'match', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('String', 'match?', 'StringObject', 'has_match', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool, pass_null: false) gen.binding('String', 'prepend', 'StringObject', 'prepend', argc: :any, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'ord', 'StringObject', 'ord', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'partition', 'StringObject', 'partition', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'reverse', 'StringObject', 'reverse', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'reverse!', 'StringObject', 'reverse_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'rindex', 'StringObject', 'rindex', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'rjust', 'StringObject', 'rjust', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'rindex', 'StringObject', 'rindex', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'rjust', 'StringObject', 'rjust', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'rstrip', 'StringObject', 'rstrip', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'rstrip!', 'StringObject', 'rstrip_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'scan', 'StringObject', 'scan', argc: 1, pass_env: true, pass_block: true, return_type: :Object) gen.binding('String', 'setbyte', 'StringObject', 'setbyte', argc: 2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'slice!', 'StringObject', 'slice_in_place', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'split', 'StringObject', 'split', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'slice!', 'StringObject', 'slice_in_place', argc: 1..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'split', 'StringObject', 'split', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'start_with?', 'StringObject', 'start_with', argc: :any, pass_env: true, pass_block: false, return_type: :bool) gen.binding('String', 'strip', 'StringObject', 'strip', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'strip!', 'StringObject', 'strip_in_place', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'sub', 'StringObject', 'sub', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('String', 'sub!', 'StringObject', 'sub_in_place', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('String', 'sub', 'StringObject', 'sub', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) +gen.binding('String', 'sub!', 'StringObject', 'sub_in_place', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('String', 'succ', 'StringObject', 'successive', argc: 0, pass_env: true, pass_block: false, aliases: ['next'], return_type: :Object) gen.binding('String', 'succ!', 'StringObject', 'successive_in_place', argc: 0, pass_env: true, pass_block: false, aliases: ['next!'], return_type: :Object) -gen.binding('String', 'swapcase', 'StringObject', 'swapcase', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'swapcase!', 'StringObject', 'swapcase_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'sum', 'StringObject', 'sum', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'sum', 'StringObject', 'sum', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'swapcase', 'StringObject', 'swapcase', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'swapcase!', 'StringObject', 'swapcase_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'to_c', 'StringObject', 'to_c', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'to_f', 'StringObject', 'to_f', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'to_i', 'StringObject', 'to_i', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('String', 'to_i', 'StringObject', 'to_i', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('String', 'to_r', 'StringObject', 'to_r', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'to_s', 'StringObject', 'to_s', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('String', 'to_str', 'StringObject', 'to_s', argc: 0, pass_env: false, pass_block: false, return_type: :Object) @@ -1352,16 +1390,16 @@ def generate_name gen.static_binding_as_class_method('String', 'try_convert', 'StringObject', 'try_convert', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'unpack', 'StringObject', 'unpack', argc: 1, kwargs: [:offset], pass_env: true, pass_block: false, return_type: :Object) gen.binding('String', 'unpack1', 'StringObject', 'unpack1', argc: 1, kwargs: [:offset], pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'upcase', 'StringObject', 'upcase', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'upcase!', 'StringObject', 'upcase_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('String', 'upto', 'StringObject', 'upto', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('String', 'upcase', 'StringObject', 'upcase', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'upcase!', 'StringObject', 'upcase_in_place', argc: 0..2, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.binding('String', 'upto', 'StringObject', 'upto', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('String', 'valid_encoding?', 'StringObject', 'valid_encoding', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.undefine_singleton_method('Symbol', 'new') gen.static_binding_as_class_method('Symbol', 'all_symbols', 'SymbolObject', 'all_symbols', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Symbol', '<=>', 'SymbolObject', 'cmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Symbol', '=~', 'SymbolObject', 'eqtilde', argc: 1, pass_env: true, pass_block: false, return_type: :Object) -gen.binding('Symbol', '[]', 'SymbolObject', 'ref', argc: 1..2, pass_env: true, pass_block: false, aliases: ['slice'], return_type: :Object) +gen.binding('Symbol', '[]', 'SymbolObject', 'ref', argc: 1..2, pass_env: true, pass_block: false, aliases: ['slice'], return_type: :Object, pass_null: false) gen.binding('Symbol', 'capitalize', 'SymbolObject', 'capitalize', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Symbol', 'casecmp', 'SymbolObject', 'casecmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Symbol', 'casecmp?', 'SymbolObject', 'is_casecmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) @@ -1372,7 +1410,7 @@ def generate_name gen.binding('Symbol', 'inspect', 'SymbolObject', 'inspect', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Symbol', 'length', 'SymbolObject', 'length', argc: 0, pass_env: true, pass_block: false, aliases: ['size'], return_type: :Object) gen.binding('Symbol', 'match', 'SymbolObject', 'match', argc: 1, pass_env: true, pass_block: true, return_type: :Object) -gen.binding('Symbol', 'match?', 'SymbolObject', 'has_match', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool) +gen.binding('Symbol', 'match?', 'SymbolObject', 'has_match', argc: 1..2, pass_env: true, pass_block: false, return_type: :bool, pass_null: false) gen.binding('Symbol', 'name', 'SymbolObject', 'name', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Symbol', 'start_with?', 'SymbolObject', 'start_with', argc: :any, pass_env: true, pass_block: false, return_type: :bool) gen.binding('Symbol', 'succ', 'SymbolObject', 'succ', argc: 0, pass_env: true, pass_block: false, aliases: ['next'], return_type: :Object) @@ -1398,7 +1436,7 @@ def generate_name gen.binding('Thread', 'abort_on_exception', 'ThreadObject', 'abort_on_exception', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Thread', 'abort_on_exception=', 'ThreadObject', 'set_abort_on_exception', argc: 1, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Thread', 'alive?', 'ThreadObject', 'is_alive', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('Thread', 'fetch', 'ThreadObject', 'fetch', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.binding('Thread', 'fetch', 'ThreadObject', 'fetch', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.binding('Thread', 'group', 'ThreadObject', 'group', argc: 0, pass_env: false, pass_block: false, return_type: :Object) gen.binding('Thread', 'initialize', 'ThreadObject', 'initialize', argc: :any, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Thread', 'join', 'ThreadObject', 'join', argc: 0, pass_env: true, pass_block: false, return_type: :Object) @@ -1438,16 +1476,16 @@ def generate_name gen.binding('Thread::Mutex', 'lock', 'Thread::MutexObject', 'lock', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Thread::Mutex', 'locked?', 'Thread::MutexObject', 'is_locked', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Thread::Mutex', 'owned?', 'Thread::MutexObject', 'is_owned', argc: 0, pass_env: false, pass_block: false, return_type: :bool) -gen.binding('Thread::Mutex', 'sleep', 'Thread::MutexObject', 'sleep', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object) +gen.binding('Thread::Mutex', 'sleep', 'Thread::MutexObject', 'sleep', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.binding('Thread::Mutex', 'synchronize', 'Thread::MutexObject', 'synchronize', argc: 0, pass_env: true, pass_block: true, return_type: :Object) gen.binding('Thread::Mutex', 'try_lock', 'Thread::MutexObject', 'try_lock', argc: 0, pass_env: false, pass_block: false, return_type: :bool) gen.binding('Thread::Mutex', 'unlock', 'Thread::MutexObject', 'unlock', argc: 0, pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_class_method('Time', 'at', 'TimeObject', 'at', argc: 1..3, kwargs: [:in], pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_class_method('Time', 'local', 'TimeObject', 'local', argc: 1..7, pass_env: true, pass_block: false, aliases: ['mktime'], return_type: :Object) -gen.static_binding_as_class_method('Time', 'new', 'TimeObject', 'initialize', argc: 0..7, kwargs: [:in], pass_env: true, pass_block: false, return_type: :Object) +gen.static_binding_as_class_method('Time', 'at', 'TimeObject', 'at', argc: 1..3, kwargs: [:in], pass_env: true, pass_block: false, return_type: :Object, pass_null: false) +gen.static_binding_as_class_method('Time', 'local', 'TimeObject', 'local', argc: 1..7, pass_env: true, pass_block: false, aliases: ['mktime'], return_type: :Object, pass_null: false) +gen.static_binding_as_class_method('Time', 'new', 'TimeObject', 'initialize', argc: 0..7, kwargs: [:in], pass_env: true, pass_block: false, return_type: :Object, pass_null: false) gen.static_binding_as_class_method('Time', 'now', 'TimeObject', 'now', argc: 0, kwargs: [:in], pass_env: true, pass_block: false, return_type: :Object) -gen.static_binding_as_class_method('Time', 'utc', 'TimeObject', 'utc', argc: 1..7, pass_env: true, pass_block: false, aliases: ['gm'], return_type: :Object) +gen.static_binding_as_class_method('Time', 'utc', 'TimeObject', 'utc', argc: 1..7, pass_env: true, pass_block: false, aliases: ['gm'], return_type: :Object, pass_null: false) gen.binding('Time', '+', 'TimeObject', 'add', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Time', '-', 'TimeObject', 'minus', argc: 1, pass_env: true, pass_block: false, return_type: :Object) gen.binding('Time', '<=>', 'TimeObject', 'cmp', argc: 1, pass_env: true, pass_block: false, return_type: :Object) @@ -1492,7 +1530,7 @@ def generate_name gen.binding('UnboundMethod', 'name', 'UnboundMethodObject', 'name', argc: 0, pass_env: true, pass_block: false, return_type: :Object) gen.binding('UnboundMethod', 'owner', 'UnboundMethodObject', 'owner', argc: 0, pass_env: false, pass_block: false, return_type: :Object) -gen.member_binding_as_class_method('main_obj', 'define_method', 'Object', 'main_obj_define_method', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object) +gen.member_binding_as_class_method('main_obj', 'define_method', 'Object', 'main_obj_define_method', argc: 1..2, pass_env: true, pass_block: true, return_type: :Object, pass_null: false) gen.member_binding_as_class_method('main_obj', 'to_s', 'Object', 'main_obj_inspect', argc: 0, pass_env: true, pass_block: false, aliases: ['inspect'], return_type: :Object) gen.init diff --git a/lib/openssl.cpp b/lib/openssl.cpp index 104d20cbe..69ab3665b 100644 --- a/lib/openssl.cpp +++ b/lib/openssl.cpp @@ -289,7 +289,7 @@ Value OpenSSL_Digest_initialize(Env *env, Value self, Args &&args, Block *) { if (!EVP_DigestInit_ex(mdctx, md, nullptr)) OpenSSL_raise_error(env, "EVP_DigestInit_ex"); - self->ivar_set(env, "@name"_s, name.as_string()->upcase(env, nullptr, nullptr)); + self->ivar_set(env, "@name"_s, name.as_string()->upcase(env)); self->ivar_set(env, "@mdctx"_s, new VoidPObject { mdctx, OpenSSL_MD_CTX_cleanup }); if (args.size() == 2) diff --git a/src/array_object.cpp b/src/array_object.cpp index b08b59e64..743a7ad64 100644 --- a/src/array_object.cpp +++ b/src/array_object.cpp @@ -22,24 +22,24 @@ ArrayObject::ArrayObject(std::initializer_list list) } } -Value ArrayObject::initialize(Env *env, Value size, Value value, Block *block) { +Value ArrayObject::initialize(Env *env, Optional size_arg, Optional value_arg, Block *block) { this->assert_not_frozen(env); - if (!size && !value && block) + if (!size_arg && !value_arg && block) env->verbose_warn("given block not used"); - if (!size) { + if (!size_arg) return initialize_copy(env, new ArrayObject); - } - if (!value) { + auto size = size_arg.value(); + + if (!value_arg) { auto to_ary = "to_ary"_s; if (!size.is_array() && size.respond_to(env, to_ary)) size = size.send(env, to_ary); - if (size.is_array()) { + if (size.is_array()) return initialize_copy(env, size); - } } auto size_integer = size.to_int(env); @@ -52,7 +52,7 @@ Value ArrayObject::initialize(Env *env, Value size, Value value, Block *block) { env->raise("ArgumentError", "negative argument"); if (block) { - if (value) + if (value_arg) env->warn("block supersedes default value argument"); ArrayObject new_array; @@ -64,7 +64,7 @@ Value ArrayObject::initialize(Env *env, Value size, Value value, Block *block) { } } else { - if (!value) value = Value::nil(); + auto value = value_arg.value_or(Value::nil()); for (nat_int_t i = 0; i < s; i++) { push(value); } @@ -240,7 +240,7 @@ Value ArrayObject::sum(Env *env, Args &&args, Block *block) { return method_info.method()->call(env, this, std::move(args), block); } -Value ArrayObject::ref(Env *env, Value index_obj, Value size) { +Value ArrayObject::ref(Env *env, Value index_obj, Optional size) { if (!size) { if (!index_obj.is_integer() && index_obj.respond_to(env, "to_int"_s)) index_obj = index_obj.send(env, "to_int"_s); @@ -257,7 +257,7 @@ Value ArrayObject::ref(Env *env, Value index_obj, Value size) { return copy->slice_in_place(env, index_obj, size); } -Value ArrayObject::refeq(Env *env, Value index_obj, Value size, Value val) { +Value ArrayObject::refeq(Env *env, Value index_obj, Value size, Optional val_arg) { this->assert_not_frozen(env); nat_int_t start, width; if (index_obj.is_range()) { @@ -266,7 +266,7 @@ Value ArrayObject::refeq(Env *env, Value index_obj, Value size, Value val) { Value end_obj = range->end(); // Ignore "size" - val = size; + val_arg = size; if (begin_obj.is_nil()) { start = 0; @@ -308,7 +308,10 @@ Value ArrayObject::refeq(Env *env, Value index_obj, Value size, Value val) { start = this->size() + start; } - if (!val) { + Value val; + if (val_arg) { + val = val_arg.value(); + } else { val = size; if (start < (nat_int_t)this->size()) { (*this)[start] = val; @@ -337,10 +340,16 @@ Value ArrayObject::refeq(Env *env, Value index_obj, Value size, Value val) { new_ary.set_size(start, Value::nil()); // the new entry/entries - if (val.is_array() || val.respond_to(env, "to_ary"_s)) { - new_ary.concat(val.to_ary(env)->m_vector); + Value val; + if (val_arg) { + val = val_arg.value(); + if (val.is_array() || val.respond_to(env, "to_ary"_s)) { + new_ary.concat(val.to_ary(env)->m_vector); + } else { + new_ary.push(val); + } } else { - new_ary.push(val); + NAT_UNREACHABLE(); } // stuff after the new entry/entries @@ -499,27 +508,27 @@ Value ArrayObject::map_in_place(Env *env, Block *block) { return this; } -Value ArrayObject::fill(Env *env, Value obj, Value start_obj, Value length_obj, Block *block) { +Value ArrayObject::fill(Env *env, Optional obj_arg, Optional start_arg, Optional length_arg, Block *block) { assert_not_frozen(env); - if (block && length_obj) { + if (block && length_arg) env->raise("ArgumentError", "wrong number of arguments (given 3, expected 0..2)"); - } - if (!obj && !block) { + if (!obj_arg && !block) env->raise("ArgumentError", "wrong number of arguments (given 0, expected 1..3)"); - } - if (!length_obj && block) { - length_obj = start_obj; - start_obj = obj; + if (!length_arg && block) { + length_arg = start_arg; + start_arg = obj_arg; } nat_int_t start = 0; nat_int_t max = size(); - if (start_obj && !start_obj.is_nil()) { - if (!length_obj && start_obj.is_range()) { + if (start_arg && !start_arg.value().is_nil()) { + auto start_obj = start_arg.value(); + if (!length_arg && start_arg.value().is_range()) { + Value begin = start_obj.as_range()->begin(); if (!begin.is_nil()) { start = IntegerMethods::convert_to_nat_int_t(env, begin); @@ -548,8 +557,8 @@ Value ArrayObject::fill(Env *env, Value obj, Value start_obj, Value length_obj, if (start < 0) start = 0; - if (length_obj && !length_obj.is_nil()) { - auto length = IntegerMethods::convert_to_nat_int_t(env, length_obj); + if (length_arg && !length_arg.value().is_nil()) { + auto length = IntegerMethods::convert_to_nat_int_t(env, length_arg.value()); if (length >= 2LL << 60) env->raise("ArgumentError", "argument too big"); @@ -573,22 +582,20 @@ Value ArrayObject::fill(Env *env, Value obj, Value start_obj, Value length_obj, Value args[1] = { Value::integer(i) }; m_vector[i] = block->run(env, Args(1, args), nullptr); } else - m_vector[i] = obj; + m_vector[i] = obj_arg.value(); } return this; } -Value ArrayObject::first(Env *env, Value n) { - auto has_count = n != nullptr; - - if (!has_count) { +Value ArrayObject::first(Env *env, Optional n) { + if (!n) { if (is_empty()) return Value::nil(); return (*this)[0]; } - nat_int_t n_value = IntegerMethods::convert_to_nat_int_t(env, n); + nat_int_t n_value = IntegerMethods::convert_to_nat_int_t(env, n.value()); if (n_value < 0) { env->raise("ArgumentError", "negative array size"); @@ -602,20 +609,19 @@ Value ArrayObject::first(Env *env, Value n) { return new ArrayObject { std::move(array) }; } -Value ArrayObject::flatten(Env *env, Value depth) { +Value ArrayObject::flatten(Env *env, Optional depth) { ArrayObject *copy = new ArrayObject { m_vector }; copy->flatten_in_place(env, depth); return copy; } -Value ArrayObject::flatten_in_place(Env *env, Value depth) { +Value ArrayObject::flatten_in_place(Env *env, Optional depth) { this->assert_not_frozen(env); bool changed { false }; - auto has_depth = depth != nullptr; - if (has_depth) { - auto depth_value = IntegerMethods::convert_to_nat_int_t(env, depth); + if (depth) { + auto depth_value = IntegerMethods::convert_to_nat_int_t(env, depth.value()); changed = _flatten_in_place(env, depth_value); } else { changed = _flatten_in_place(env, -1); @@ -798,17 +804,15 @@ Value ArrayObject::drop_while(Env *env, Block *block) { return new ArrayObject { std::move(array) }; } -Value ArrayObject::last(Env *env, Value n) { - auto has_count = n != nullptr; - - if (!has_count) { +Value ArrayObject::last(Env *env, Optional n) { + if (!n) { if (is_empty()) return Value::nil(); return (*this)[size() - 1]; } - auto n_value = IntegerMethods::convert_to_nat_int_t(env, n); + auto n_value = IntegerMethods::convert_to_nat_int_t(env, n.value()); if (n_value < 0) { env->raise("ArgumentError", "negative array size"); @@ -836,22 +840,21 @@ bool ArrayObject::include(Env *env, Value item) { } } -Value ArrayObject::index(Env *env, Value object, Block *block) { +Value ArrayObject::index(Env *env, Optional object, Block *block) { if (!block && !object) return send(env, "enum_for"_s, { "index"_s }); return find_index(env, object, block); } -Value ArrayObject::shift(Env *env, Value count) { +Value ArrayObject::shift(Env *env, Optional count) { assert_not_frozen(env); - auto has_count = count != nullptr; - if (!has_count && is_empty()) + if (!count && is_empty()) return Value::nil(); size_t shift_count = 1; Value result = nullptr; - if (has_count) { - auto count_signed = IntegerMethods::convert_to_nat_int_t(env, count); + if (count) { + auto count_signed = IntegerMethods::convert_to_nat_int_t(env, count.value()); if (count_signed < 0) env->raise("ArgumentError", "negative array size"); @@ -916,7 +919,7 @@ Value ArrayObject::_subjoin(Env *env, Value item, Value joiner) { env->raise("NoMethodError", "needed to_str, to_ary, or to_s"); } -Value ArrayObject::join(Env *env, Value joiner) { +Value ArrayObject::join(Env *env, Optional joiner_arg) { TM::RecursionGuard guard { this }; return guard.run([&](bool is_recursive) { if (is_recursive) @@ -924,9 +927,13 @@ Value ArrayObject::join(Env *env, Value joiner) { if (size() == 0) { return (Value) new StringObject { "", Encoding::US_ASCII }; } else { - if (!joiner || joiner.is_nil()) + Value joiner; + if (joiner_arg && !joiner_arg.value().is_nil()) + joiner = joiner_arg.value(); + else joiner = env->global_get("$,"_s); - if (!joiner || joiner.is_nil()) joiner = new StringObject { "" }; + if (joiner.is_nil()) + joiner = new StringObject { "" }; if (!joiner.is_string()) joiner = joiner.to_str(env); @@ -1016,11 +1023,11 @@ void ArrayObject::push_splat(Env *env, Value val) { } } -Value ArrayObject::pop(Env *env, Value count) { +Value ArrayObject::pop(Env *env, Optional count) { this->assert_not_frozen(env); if (count) { - auto c = IntegerMethods::convert_to_nat_int_t(env, count); + auto c = IntegerMethods::convert_to_nat_int_t(env, count.value()); if (c < 0) env->raise("ArgumentError", "negative array size"); @@ -1205,7 +1212,7 @@ Value ArrayObject::reject_in_place(Env *env, Block *block) { return Value::nil(); } -Value ArrayObject::max(Env *env, Value count, Block *block) { +Value ArrayObject::max(Env *env, Optional count, Block *block) { if (m_vector.size() == 0) return Value::nil(); @@ -1224,13 +1231,13 @@ Value ArrayObject::max(Env *env, Value count, Block *block) { return nat_int > 0; }; - auto has_implicit_count = !count || count.is_nil(); + auto has_implicit_count = !count || count.value().is_nil(); size_t c; if (has_implicit_count) { c = 1; } else { - auto c_nat_int = IntegerMethods::convert_to_nat_int_t(env, count); + auto c_nat_int = IntegerMethods::convert_to_nat_int_t(env, count.value()); if (c_nat_int < 0) env->raise("ArgumentError", "negative size ({})", c_nat_int); @@ -1255,7 +1262,7 @@ Value ArrayObject::max(Env *env, Value count, Block *block) { return new ArrayObject { maxes.slice(0, c) }; } -Value ArrayObject::min(Env *env, Value count, Block *block) { +Value ArrayObject::min(Env *env, Optional count, Block *block) { if (m_vector.size() == 0) return Value::nil(); @@ -1274,13 +1281,13 @@ Value ArrayObject::min(Env *env, Value count, Block *block) { return nat_int < 0; }; - auto has_implicit_count = !count || count.is_nil(); + auto has_implicit_count = !count || count.value().is_nil(); size_t c; if (has_implicit_count) { c = 1; } else { - auto c_nat_int = IntegerMethods::convert_to_nat_int_t(env, count); + auto c_nat_int = IntegerMethods::convert_to_nat_int_t(env, count.value()); if (c_nat_int < 0) env->raise("ArgumentError", "negative size ({})", c_nat_int); @@ -1383,12 +1390,12 @@ Value ArrayObject::compact_in_place(Env *env) { return Value::nil(); } -Value ArrayObject::cycle(Env *env, Value count, Block *block) { +Value ArrayObject::cycle(Env *env, Optional count, Block *block) { // FIXME: delegating to Enumerable#cycle like this does not have the same semantics as MRI, // i.e. one can override Enumerable#cycle in MRI and it won't affect Array#cycle. auto Enumerable = GlobalEnv::the()->Object()->const_fetch("Enumerable"_s).as_module(); auto method_info = Enumerable->find_method(env, "cycle"_s); - auto args = count ? Vector { count } : Vector {}; + auto args = count ? Vector { count.value() } : Vector {}; return method_info.method()->call(env, this, { std::move(args) }, block); } @@ -1430,7 +1437,7 @@ Value ArrayObject::clear(Env *env) { } Value ArrayObject::at(Env *env, Value n) { - return ref(env, n, nullptr); + return ref(env, n); } Value ArrayObject::assoc(Env *env, Value needle) { @@ -1725,12 +1732,12 @@ nat_int_t ArrayObject::_resolve_index(nat_int_t nat_index) const { return index; } -Value ArrayObject::rindex(Env *env, Value object, Block *block) { +Value ArrayObject::rindex(Env *env, Optional object, Block *block) { if (!block && !object) return send(env, "enum_for"_s, { "rindex"_s }); return find_index(env, object, block, true); } -Value ArrayObject::fetch(Env *env, Value arg_index, Value default_value, Block *block) { +Value ArrayObject::fetch(Env *env, Value arg_index, Optional default_value, Block *block) { Value value; auto index_val = IntegerMethods::convert_to_nat_int_t(env, arg_index); auto index = _resolve_index(index_val); @@ -1742,7 +1749,7 @@ Value ArrayObject::fetch(Env *env, Value arg_index, Value default_value, Block * Value args[] = { arg_index }; value = block->run(env, Args(1, args), nullptr); } else if (default_value) { - value = default_value; + value = default_value.value(); } else { env->raise("IndexError", "index {} outside of array bounds: {}...{}", index_val, -(nat_int_t)size(), size()); } @@ -1753,7 +1760,7 @@ Value ArrayObject::fetch(Env *env, Value arg_index, Value default_value, Block * return value; } -Value ArrayObject::find_index(Env *env, Value object, Block *block, bool search_reverse) { +Value ArrayObject::find_index(Env *env, Optional object, Block *block, bool search_reverse) { if (object && block) env->warn("given block not used"); assert(size() <= NAT_INT_MAX); @@ -1762,7 +1769,7 @@ Value ArrayObject::find_index(Env *env, Value object, Block *block, bool search_ nat_int_t index = search_reverse ? length - i - 1 : i; auto item = m_vector[index]; if (object) { - if (item.send(env, "=="_s, { object }).is_truthy()) + if (item.send(env, "=="_s, { object.value() }).is_truthy()) return Value::integer(index); } else { Value args[] = { item }; @@ -1839,18 +1846,17 @@ Value ArrayObject::product(Env *env, Args &&args, Block *block) { return products; } -Value ArrayObject::rotate(Env *env, Value val) { +Value ArrayObject::rotate(Env *env, Optional val) { ArrayObject *copy = new ArrayObject { m_vector }; copy->rotate_in_place(env, val); return copy; } -Value ArrayObject::rotate_in_place(Env *env, Value val) { +Value ArrayObject::rotate_in_place(Env *env, Optional val) { assert_not_frozen(env); nat_int_t count = 1; - if (val) { - count = IntegerMethods::convert_to_nat_int_t(env, val); - } + if (val) + count = IntegerMethods::convert_to_nat_int_t(env, val.value()); if (size() == 0) { // prevent @@ -1886,14 +1892,14 @@ Value ArrayObject::rotate_in_place(Env *env, Value val) { return this; } -Value ArrayObject::slice_in_place(Env *env, Value index_obj, Value size) { +Value ArrayObject::slice_in_place(Env *env, Value index_obj, Optional size) { this->assert_not_frozen(env); + Integer size_int; if (size) { index_obj = index_obj.to_int(env); - size = size.to_int(env); - - IntegerMethods::assert_fixnum(env, size.integer()); + size_int = size.value().to_int(env); + IntegerMethods::assert_fixnum(env, size_int); } if (index_obj.is_integer()) { @@ -1914,9 +1920,7 @@ Value ArrayObject::slice_in_place(Env *env, Value index_obj, Value size) { return item; } - size.assert_integer(env); - - auto length = size.integer().to_nat_int_t(); + auto length = size_int.to_nat_int_t(); if (length < 0) return Value::nil(); diff --git a/src/class_object.cpp b/src/class_object.cpp index ac1704ecf..e8fa89d14 100644 --- a/src/class_object.cpp +++ b/src/class_object.cpp @@ -2,11 +2,10 @@ namespace Natalie { -Value ClassObject::initialize(Env *env, Value superclass, Block *block) { +Value ClassObject::initialize(Env *env, Optional superclass_arg, Block *block) { if (m_is_initialized) env->raise("TypeError", "already initialized class"); - if (!superclass) - superclass = GlobalEnv::the()->Object(); + auto superclass = superclass_arg.value_or(GlobalEnv::the()->Object()); if (!superclass.is_class()) env->raise("TypeError", "superclass must be an instance of Class (given an instance of {})", superclass.klass()->inspect_str()); superclass.as_class()->initialize_subclass(this, env, "", superclass.as_class()->object_type()); diff --git a/src/encoding_object.cpp b/src/encoding_object.cpp index 2582d9126..da8bec356 100644 --- a/src/encoding_object.cpp +++ b/src/encoding_object.cpp @@ -109,7 +109,8 @@ Value EncodingObject::encode(Env *env, EncodingObject *orig_encoding, StringObje auto result_str = result.to_str(env); if (result_str->encoding()->num() != num()) { try { - result_str = result_str->encode(env, EncodingObject::get(num())).to_str(env); + Value encoding = EncodingObject::get(num()); + result_str = result_str->encode(env, encoding).to_str(env); } catch (ExceptionObject *e) { // FIXME: I'm not sure how Ruby knows the character is "too big" for the target encoding. // We don't have that kind of information yet. diff --git a/src/file_object.cpp b/src/file_object.cpp index 2c9ac6fc6..a88cf8238 100644 --- a/src/file_object.cpp +++ b/src/file_object.cpp @@ -734,14 +734,14 @@ Value FileObject::utime(Env *env, Args &&args) { } else if (args[0].is_time()) { atime = args[0].as_time(); } else { - atime = TimeObject::at(env, args[0], nullptr, nullptr); + atime = TimeObject::at(env, args[0]); } if (args[1].is_nil()) { mtime = TimeObject::create(env); } else if (args[1].is_time()) { mtime = args[1].as_time(); } else { - mtime = TimeObject::at(env, args[1], nullptr, nullptr); + mtime = TimeObject::at(env, args[1]); } struct timeval ubuf[2], *ubufp = nullptr; diff --git a/src/file_stat_object.cpp b/src/file_stat_object.cpp index 85ae72a64..e08cd7d55 100644 --- a/src/file_stat_object.cpp +++ b/src/file_stat_object.cpp @@ -152,14 +152,14 @@ Value FileStatObject::comparison(Env *env, Value other) const { Value FileStatObject::atime(Env *env) const { Value sec = Value::integer(fstatus.st_atim.tv_sec); Value ns = Value::integer(fstatus.st_atim.tv_nsec); - return TimeObject::at(env, sec, ns, "nanosecond"_s); + return TimeObject::at(env, sec, ns, Value("nanosecond"_s)); } Value FileStatObject::birthtime(Env *env) const { #if defined(__FreeBSD__) or defined(__NetBSD__) or defined(__APPLE__) Value sec = Value::integer(fstatus.st_birthtimespec.tv_sec); Value ns = Value::integer(fstatus.st_birthtimespec.tv_nsec); - return TimeObject::at(env, sec, ns, "nanosecond"_s); + return TimeObject::at(env, sec, ns, Value("nanosecond"_s)); #else env->raise("NotImplementedError", "birthtime not supported on this platform"); #endif @@ -168,13 +168,13 @@ Value FileStatObject::birthtime(Env *env) const { Value FileStatObject::ctime(Env *env) const { Value sec = Value::integer(fstatus.st_ctim.tv_sec); Value ns = Value::integer(fstatus.st_ctim.tv_nsec); - return TimeObject::at(env, sec, ns, "nanosecond"_s); + return TimeObject::at(env, sec, ns, Value("nanosecond"_s)); } Value FileStatObject::mtime(Env *env) const { Value sec = Value::integer(fstatus.st_mtim.tv_sec); Value ns = Value::integer(fstatus.st_mtim.tv_nsec); - return TimeObject::at(env, sec, ns, "nanosecond"_s); + return TimeObject::at(env, sec, ns, Value("nanosecond"_s)); } } diff --git a/src/float_object.cpp b/src/float_object.cpp index 49eb4138b..b5cfa0774 100644 --- a/src/float_object.cpp +++ b/src/float_object.cpp @@ -40,9 +40,10 @@ bool FloatObject::eql(Value other) const { } #define ROUNDING_OPERATION(name, libm_name) \ - Value FloatObject::name(Env *env, Value precision_value) { \ + Value FloatObject::name(Env *env, Optional precision_arg) { \ nat_int_t precision = 0; \ - if (precision_value) { \ + if (precision_arg) { \ + auto precision_value = precision_arg.value(); \ if (precision_value.is_float()) { \ precision_value = precision_value.as_float()->to_i(env); \ } \ diff --git a/src/hash_object.cpp b/src/hash_object.cpp index 5cdef2760..00242e66e 100644 --- a/src/hash_object.cpp +++ b/src/hash_object.cpp @@ -66,11 +66,11 @@ nat_int_t HashObject::generate_key_hash(Env *env, Value key) const { } } -Value HashObject::get_default(Env *env, Value key) { +Value HashObject::get_default(Env *env, Optional key) { if (m_default_proc) { if (!key) return Value::nil(); - return m_default_proc->call(env, { this, key }, nullptr); + return m_default_proc->call(env, { this, key.value() }, nullptr); } else { return m_default_value; } @@ -212,26 +212,22 @@ void HashObject::key_list_remove_node(HashKey *node) { next->prev = prev; } -Value HashObject::initialize(Env *env, Value default_value, Value capacity, Block *block) { +Value HashObject::initialize(Env *env, Optional default_arg, Optional capacity, Block *block) { assert_not_frozen(env); if (capacity) { - const auto capacity_int = IntegerMethods::convert_to_native_type(env, capacity); + const auto capacity_int = IntegerMethods::convert_to_native_type(env, capacity.value()); if (capacity_int > 0) m_hashmap = TM::Hashmap { static_cast(capacity_int) }; } if (block) { - if (default_value) { + if (default_arg) { env->raise("ArgumentError", "wrong number of arguments (given 1, expected 0)"); } set_default_proc(new ProcObject { block }); } else { - if (!default_value) { - default_value = Value::nil(); - } - - set_default(env, default_value); + set_default(env, default_arg.value_or(Value::nil())); } return this; } @@ -541,7 +537,7 @@ Value HashObject::except(Env *env, Args &&args) { return new_hash; } -Value HashObject::fetch(Env *env, Value key, Value default_value, Block *block) { +Value HashObject::fetch(Env *env, Value key, Optional default_value, Block *block) { Value value = get(env, key); if (!value) { if (block) { @@ -551,7 +547,7 @@ Value HashObject::fetch(Env *env, Value key, Value default_value, Block *block) Value args[] = { key }; value = block->run(env, Args(1, args), nullptr); } else if (default_value) { - value = default_value; + value = default_value.value(); } else { env->raise_key_error(this, key); } @@ -564,7 +560,7 @@ Value HashObject::fetch_values(Env *env, Args &&args, Block *block) { auto array = new ArrayObject { args.size() }; for (size_t i = 0; i < args.size(); ++i) { - array->push(fetch(env, args[i], nullptr, block)); + array->push(fetch(env, args[i], {}, block)); } return array; } diff --git a/src/integer_methods.cpp b/src/integer_methods.cpp index 498fca3e9..9b7018bc9 100644 --- a/src/integer_methods.cpp +++ b/src/integer_methods.cpp @@ -4,13 +4,13 @@ namespace Natalie { -Value IntegerMethods::to_s(Env *env, Integer self, Value base_value) { +Value IntegerMethods::to_s(Env *env, Integer self, Optional base_value) { if (self == 0) return new StringObject { "0" }; nat_int_t base = 10; if (base_value) { - base = convert_to_nat_int_t(env, base_value); + base = convert_to_nat_int_t(env, base_value.value()); if (base < 2 || base > 36) { env->raise("ArgumentError", "invalid radix {}", base); @@ -198,7 +198,7 @@ Value IntegerMethods::pow(Env *env, Integer self, Value arg) { return pow(env, self, arg.integer()); } -Value IntegerMethods::powmod(Env *env, Integer self, Value exponent, Value mod) { +Value IntegerMethods::powmod(Env *env, Integer self, Value exponent, Optional mod) { if (exponent.is_integer() && exponent.integer().is_negative() && mod) env->raise("RangeError", "2nd argument not allowed when first argument is negative"); @@ -207,10 +207,10 @@ Value IntegerMethods::powmod(Env *env, Integer self, Value exponent, Value mod) if (!mod) return powd; - if (!mod.is_integer()) + if (!mod.value().is_integer()) env->raise("TypeError", "2nd argument not allowed unless all arguments are integers"); - auto modi = mod.integer(); + auto modi = mod.value().integer(); if (modi.is_zero()) env->raise("ZeroDivisionError", "cannot divide by zero"); @@ -496,13 +496,13 @@ Value IntegerMethods::coerce(Env *env, Value self, Value arg) { return ary; } -Value IntegerMethods::ceil(Env *env, Integer self, Value arg) { - if (arg == nullptr) +Value IntegerMethods::ceil(Env *env, Integer self, Optional arg) { + if (!arg) return self; - arg.assert_integer(env); + arg.value().assert_integer(env); - auto precision = arg.integer().to_nat_int_t(); + auto precision = arg.value().integer().to_nat_int_t(); if (precision >= 0) return self; @@ -512,13 +512,13 @@ Value IntegerMethods::ceil(Env *env, Integer self, Value arg) { return Value::integer(result); } -Value IntegerMethods::floor(Env *env, Integer self, Value arg) { - if (arg == nullptr) +Value IntegerMethods::floor(Env *env, Integer self, Optional arg) { + if (!arg) return self; - arg.assert_integer(env); + arg.value().assert_integer(env); - auto precision = arg.integer().to_nat_int_t(); + auto precision = arg.value().integer().to_nat_int_t(); if (precision >= 0) return self; @@ -533,13 +533,15 @@ Value IntegerMethods::gcd(Env *env, Integer self, Value divisor) { return Natalie::gcd(self, divisor.integer()); } -Value IntegerMethods::chr(Env *env, Integer self, Value encoding) { +Value IntegerMethods::chr(Env *env, Integer self, Optional encoding_arg) { if (self < 0 || self > (nat_int_t)UINT_MAX) env->raise("RangeError", "{} out of char range", self.to_string()); else if (self.is_bignum()) env->raise("RangeError", "bignum out of char range"); - if (encoding) { + Value encoding; + if (encoding_arg) { + encoding = encoding_arg.value(); if (!encoding.is_encoding()) { encoding.assert_type(env, Object::Type::String, "String"); encoding = EncodingObject::find(env, encoding); @@ -583,11 +585,11 @@ Value IntegerMethods::sqrt(Env *env, Value arg) { return Natalie::sqrt(argument); } -Value IntegerMethods::round(Env *env, Integer self, Value ndigits, Value half) { +Value IntegerMethods::round(Env *env, Integer self, Optional ndigits, Optional half) { if (!ndigits) return self; - int digits = convert_to_int(env, ndigits); + int digits = convert_to_int(env, ndigits.value()); RoundingMode rounding_mode = rounding_mode_from_value(env, half); if (digits >= 0) @@ -626,11 +628,11 @@ Value IntegerMethods::round(Env *env, Integer self, Value ndigits, Value half) { return result; } -Value IntegerMethods::truncate(Env *env, Integer self, Value ndigits) { +Value IntegerMethods::truncate(Env *env, Integer self, Optional ndigits) { if (!ndigits) return self; - int digits = convert_to_int(env, ndigits); + int digits = convert_to_int(env, ndigits.value()); if (digits >= 0) return self; @@ -642,7 +644,7 @@ Value IntegerMethods::truncate(Env *env, Integer self, Value ndigits) { return result - remainder; } -Value IntegerMethods::ref(Env *env, Integer self, Value offset_obj, Value size_obj) { +Value IntegerMethods::ref(Env *env, Integer self, Value offset_obj, Optional size_obj) { auto from_offset_and_size = [self, env](Optional offset_or_empty, Optional size_or_empty = {}) -> Value { auto offset = offset_or_empty.value_or(0); @@ -697,7 +699,7 @@ Value IntegerMethods::ref(Env *env, Integer self, Value offset_obj, Value size_o Optional size; if (size_obj) { - auto size_integer = size_obj.to_int(env); + auto size_integer = size_obj.value().to_int(env); if (size_integer.is_bignum()) env->raise("RangeError", "shift width too big"); diff --git a/src/io_object.cpp b/src/io_object.cpp index b3b007f72..194b249d0 100644 --- a/src/io_object.cpp +++ b/src/io_object.cpp @@ -323,7 +323,7 @@ Value IoObject::write_file(Env *env, Args &&args) { if (kwargs && kwargs->has_key(env, "open_args"_s)) { auto next_args = new ArrayObject { filename }; - next_args->concat(*kwargs->fetch(env, "open_args"_s, nullptr, nullptr).to_ary(env)); + next_args->concat(*kwargs->fetch(env, "open_args"_s).to_ary(env)); auto open_args_has_kw = next_args->last().is_hash(); file = _new(env, File, Args(next_args, open_args_has_kw), nullptr).as_file(); } else { @@ -639,7 +639,7 @@ Value IoObject::putc(Env *env, Value val) { } else { ord = IntegerMethods::convert_to_nat_int_t(env, val) & 0xff; } - send(env, "write"_s, { IntegerMethods::chr(env, ord, nullptr) }); + send(env, "write"_s, { IntegerMethods::chr(env, ord) }); return val; } @@ -792,10 +792,10 @@ Value IoObject::set_encoding(Env *env, Value ext_enc, Value int_enc) { if ((int_enc == nullptr || int_enc.is_nil()) && ext_enc != nullptr && (ext_enc.is_string() || ext_enc.respond_to(env, "to_str"_s))) { ext_enc = ext_enc.to_str(env); if (ext_enc.as_string()->include(":")) { - auto colon = new StringObject { ":" }; - auto encsplit = ext_enc.to_str(env)->split(env, colon, nullptr).as_array(); - ext_enc = encsplit->ref(env, Value::integer(static_cast(0)), nullptr); - int_enc = encsplit->ref(env, Value::integer(static_cast(1)), nullptr); + Value colon = new StringObject { ":" }; + auto encsplit = ext_enc.to_str(env)->split(env, colon).as_array(); + ext_enc = encsplit->ref(env, Value::integer(static_cast(0))); + int_enc = encsplit->ref(env, Value::integer(static_cast(1))); } } diff --git a/src/ioutil.cpp b/src/ioutil.cpp index 81ef06318..0cd3eb2c1 100644 --- a/src/ioutil.cpp +++ b/src/ioutil.cpp @@ -51,11 +51,11 @@ namespace ioutil { switch (flags_obj.type()) { case Object::Type::String: { - auto colon = new StringObject { ":" }; - auto flagsplit = flags_obj.as_string()->split(env, colon, nullptr).as_array(); - auto flags_str = flagsplit->fetch(env, Value::integer(static_cast(0)), new StringObject { "" }, nullptr).as_string()->string(); - auto extenc = flagsplit->ref(env, Value::integer(static_cast(1)), nullptr); - auto intenc = flagsplit->ref(env, Value::integer(static_cast(2)), nullptr); + Value colon = new StringObject { ":" }; + auto flagsplit = flags_obj.as_string()->split(env, colon).as_array(); + auto flags_str = flagsplit->fetch(env, Value::integer(static_cast(0)), Value(new StringObject { "" }), nullptr).as_string()->string(); + auto extenc = flagsplit->ref(env, Value::integer(static_cast(1))); + auto intenc = flagsplit->ref(env, Value::integer(static_cast(2))); if (!extenc.is_nil()) m_external_encoding = EncodingObject::find_encoding(env, extenc); if (!intenc.is_nil()) m_internal_encoding = EncodingObject::find_encoding(env, intenc); @@ -132,10 +132,10 @@ namespace ioutil { } else { encoding = encoding.to_str(env); if (encoding.as_string()->include(":")) { - auto colon = new StringObject { ":" }; - auto encsplit = encoding.to_str(env)->split(env, colon, nullptr).as_array(); - encoding = encsplit->ref(env, Value::integer(static_cast(0)), nullptr); - auto internal_encoding = encsplit->ref(env, Value::integer(static_cast(1)), nullptr); + Value colon = new StringObject { ":" }; + auto encsplit = encoding.to_str(env)->split(env, colon).as_array(); + encoding = encsplit->ref(env, Value::integer(static_cast(0))); + auto internal_encoding = encsplit->ref(env, Value::integer(static_cast(1))); m_internal_encoding = EncodingObject::find_encoding(env, internal_encoding); } m_external_encoding = EncodingObject::find_encoding(env, encoding); diff --git a/src/kernel_module.cpp b/src/kernel_module.cpp index 5b452b402..3258db6be 100644 --- a/src/kernel_module.cpp +++ b/src/kernel_module.cpp @@ -1059,17 +1059,17 @@ Value KernelModule::method(Env *env, Value self, Value name) { return new MethodObject { self, method_info.method() }; } -Value KernelModule::methods(Env *env, Value self, Value regular_val) { - bool regular = regular_val ? regular_val.is_truthy() : true; +Value KernelModule::methods(Env *env, Value self, Optional regular_val) { + bool regular = regular_val ? regular_val.value().is_truthy() : true; if (regular) { if (self->singleton_class()) { - return self->singleton_class()->instance_methods(env, TrueObject::the()); + return self->singleton_class()->instance_methods(env, Value(TrueObject::the())); } else { - return self.klass()->instance_methods(env, TrueObject::the()); + return self.klass()->instance_methods(env, Value(TrueObject::the())); } } if (self->singleton_class()) - return self->singleton_class()->instance_methods(env, FalseObject::the()); + return self->singleton_class()->instance_methods(env, Value(FalseObject::the())); else return new ArrayObject {}; } @@ -1078,23 +1078,23 @@ bool KernelModule::neqtilde(Env *env, Value self, Value other) { return self.send(env, "=~"_s, { other }).is_falsey(); } -Value KernelModule::private_methods(Env *env, Value self, Value recur) { +Value KernelModule::private_methods(Env *env, Value self, Optional recur) { if (self->singleton_class()) - return self->singleton_class()->private_instance_methods(env, TrueObject::the()); + return self->singleton_class()->private_instance_methods(env, Value(TrueObject::the())); else return self.klass()->private_instance_methods(env, recur); } -Value KernelModule::protected_methods(Env *env, Value self, Value recur) { +Value KernelModule::protected_methods(Env *env, Value self, Optional recur) { if (self->singleton_class()) - return self->singleton_class()->protected_instance_methods(env, TrueObject::the()); + return self->singleton_class()->protected_instance_methods(env, Value(TrueObject::the())); else return self.klass()->protected_instance_methods(env, recur); } -Value KernelModule::public_methods(Env *env, Value self, Value recur) { +Value KernelModule::public_methods(Env *env, Value self, Optional recur) { if (self.singleton_class()) - return self.singleton_class()->public_instance_methods(env, TrueObject::the()); + return self.singleton_class()->public_instance_methods(env, Value(TrueObject::the())); else return self.klass()->public_instance_methods(env, recur); } diff --git a/src/module_object.cpp b/src/module_object.cpp index 31fc965cd..902919b17 100644 --- a/src/module_object.cpp +++ b/src/module_object.cpp @@ -88,11 +88,11 @@ Value ModuleObject::const_get(SymbolObject *name) const { return nullptr; } -Value ModuleObject::const_get(Env *env, Value name, Value inherited) { +Value ModuleObject::const_get(Env *env, Value name, Optional inherited) { auto symbol = name.to_symbol(env, Value::Conversion::Strict); auto constant = const_get(symbol); if (!constant) { - if (inherited && inherited.is_falsey()) + if (inherited && inherited.value().is_falsey()) env->raise("NameError", "uninitialized constant {}", symbol->string()); return send(env, "const_missing"_s, { name }); } @@ -326,11 +326,11 @@ Value ModuleObject::remove_const(Env *env, Value name) { return constant->value(); } -Value ModuleObject::constants(Env *env, Value inherit) const { +Value ModuleObject::constants(Env *env, Optional inherit) const { auto ary = new ArrayObject; for (auto pair : m_constants) ary->push(pair.first); - if (inherit == nullptr || inherit.is_truthy()) { + if (!inherit || inherit.value().is_truthy()) { for (ModuleObject *module : m_included_modules) { if (module != this) { ary->concat(*module->constants(env, inherit).as_array()); @@ -460,7 +460,7 @@ Value ModuleObject::class_variable_set(Env *env, Value name, Value value) { return cvar_set(env, name.to_symbol(env, Value::Conversion::Strict), value); } -ArrayObject *ModuleObject::class_variables(Value inherit) const { +ArrayObject *ModuleObject::class_variables(Optional inherit) const { std::lock_guard lock(g_gc_recursive_mutex); auto result = new ArrayObject {}; @@ -470,7 +470,7 @@ ArrayObject *ModuleObject::class_variables(Value inherit) const { for (auto [cvar, _] : singleton_class()->m_class_vars) result->push(cvar); } - if (inherit && inherit.is_truthy() && m_superclass) + if (inherit && inherit.value().is_truthy() && m_superclass) result->concat(*m_superclass->class_variables(inherit)); return result; } @@ -636,8 +636,8 @@ Value ModuleObject::public_instance_method(Env *env, Value name_value) { } } -Value ModuleObject::instance_methods(Env *env, Value include_super_value, std::function predicate) { - bool include_super = !include_super_value || include_super_value.is_truthy(); +Value ModuleObject::instance_methods(Env *env, Optional include_super_value, std::function predicate) { + bool include_super = !include_super_value || include_super_value.value().is_truthy(); ArrayObject *array = new ArrayObject {}; methods(env, array, include_super); array->select_in_place([this, env, predicate](Value &name_value) -> bool { @@ -648,25 +648,25 @@ Value ModuleObject::instance_methods(Env *env, Value include_super_value, std::f return array; } -Value ModuleObject::instance_methods(Env *env, Value include_super_value) { +Value ModuleObject::instance_methods(Env *env, Optional include_super_value) { return instance_methods(env, include_super_value, [](MethodVisibility visibility) { return visibility == MethodVisibility::Public || visibility == MethodVisibility::Protected; }); } -Value ModuleObject::private_instance_methods(Env *env, Value include_super_value) { +Value ModuleObject::private_instance_methods(Env *env, Optional include_super_value) { return instance_methods(env, include_super_value, [](MethodVisibility visibility) { return visibility == MethodVisibility::Private; }); } -Value ModuleObject::protected_instance_methods(Env *env, Value include_super_value) { +Value ModuleObject::protected_instance_methods(Env *env, Optional include_super_value) { return instance_methods(env, include_super_value, [](MethodVisibility visibility) { return visibility == MethodVisibility::Protected; }); } -Value ModuleObject::public_instance_methods(Env *env, Value include_super_value) { +Value ModuleObject::public_instance_methods(Env *env, Optional include_super_value) { return instance_methods(env, include_super_value, [](MethodVisibility visibility) { return visibility == MethodVisibility::Public; }); @@ -902,9 +902,10 @@ bool ModuleObject::does_include_module(Env *env, Value module) { return false; } -Value ModuleObject::define_method(Env *env, Value name_value, Value method_value, Block *block) { +Value ModuleObject::define_method(Env *env, Value name_value, Optional method_arg, Block *block) { auto name = name_value.to_symbol(env, Value::Conversion::Strict); - if (method_value) { + if (method_arg) { + auto method_value = method_arg.value(); if (method_value.is_proc()) { define_method(env, name, method_value.as_proc()->block()); } else { @@ -1065,12 +1066,12 @@ Value ModuleObject::public_constant(Env *env, Args &&args) { return this; } -bool ModuleObject::const_defined(Env *env, Value name_value, Value inherited) { +bool ModuleObject::const_defined(Env *env, Value name_value, Optional inherited) { auto name = name_value.to_symbol(env, Value::Conversion::NullAllowed); if (!name) { env->raise("TypeError", "no implicit conversion of {} to String", name_value.inspect_str(env)); } - if (inherited && inherited.is_falsey()) { + if (inherited && inherited.value().is_falsey()) { return !!m_constants.get(name); } return !!const_find(env, name, ConstLookupSearchMode::NotStrict, ConstLookupFailureMode::Null); diff --git a/src/natalie.cpp b/src/natalie.cpp index 6900a2e72..9cfc256c2 100644 --- a/src/natalie.cpp +++ b/src/natalie.cpp @@ -126,7 +126,7 @@ Env *build_top_env() { ClassObject *Random = Object->subclass(env, "Random", Object::Type::Random); global_env->set_Random(Random); Object->const_set("Random"_s, Random); - Random->const_set("DEFAULT"_s, (new RandomObject)->initialize(env, nullptr)); + Random->const_set("DEFAULT"_s, (new RandomObject)->initialize(env)); ModuleObject *RandomFormatter = new ModuleObject { "Formatter" }; Random->const_set("Formatter"_s, RandomFormatter); diff --git a/src/object.cpp b/src/object.cpp index 32919b615..71b8cf33f 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -495,7 +495,7 @@ SymbolObject *Object::undefine_method(Env *env, Value self, SymbolObject *name) return name; } -Value Object::main_obj_define_method(Env *env, Value name, Value proc_or_unbound_method, Block *block) { +Value Object::main_obj_define_method(Env *env, Value name, Optional proc_or_unbound_method, Block *block) { return m_klass->define_method(env, name, proc_or_unbound_method, block); } diff --git a/src/random_object.cpp b/src/random_object.cpp index c10092c48..b2f9a59a1 100644 --- a/src/random_object.cpp +++ b/src/random_object.cpp @@ -3,14 +3,14 @@ #include namespace Natalie { -Value RandomObject::initialize(Env *env, Value seed) { - if (!seed) { +Value RandomObject::initialize(Env *env, Optional seed_arg) { + if (!seed_arg) { m_seed = (nat_int_t)std::random_device()(); } else { + auto seed = seed_arg.value(); if (seed.is_float()) { seed = seed.as_float()->to_i(env); } - m_seed = IntegerMethods::convert_to_nat_int_t(env, seed); } @@ -35,8 +35,9 @@ Value RandomObject::bytes(Env *env, Value size) { return new StringObject { reinterpret_cast(output), static_cast(isize), Encoding::ASCII_8BIT }; } -Value RandomObject::rand(Env *env, Value arg) { - if (arg) { +Value RandomObject::rand(Env *env, Optional max_arg) { + if (max_arg) { + auto arg = max_arg.value(); if (arg.is_float()) { double max = arg.as_float()->to_double(); if (max <= 0) { diff --git a/src/range_object.cpp b/src/range_object.cpp index 897f89f66..4234bff71 100644 --- a/src/range_object.cpp +++ b/src/range_object.cpp @@ -16,14 +16,14 @@ void RangeObject::assert_no_bad_value(Env *env, Value begin, Value end) { env->raise("ArgumentError", "bad value for range"); } -Value RangeObject::initialize(Env *env, Value begin, Value end, Value exclude_end_value) { +Value RangeObject::initialize(Env *env, Value begin, Value end, Optional exclude_end_value) { assert_not_frozen(env); assert_no_bad_value(env, begin, end); m_begin = begin; m_end = end; - m_exclude_end = exclude_end_value && exclude_end_value.is_truthy(); + m_exclude_end = exclude_end_value && exclude_end_value.value().is_truthy(); freeze(); return this; @@ -181,12 +181,12 @@ Value RangeObject::each(Env *env, Block *block) { return this; } -Value RangeObject::first(Env *env, Value n) { +Value RangeObject::first(Env *env, Optional n) { if (m_begin.is_nil()) { env->raise("RangeError", "cannot get the first element of beginless range"); } if (n) { - nat_int_t count = IntegerMethods::convert_to_nat_int_t(env, n); + nat_int_t count = IntegerMethods::convert_to_nat_int_t(env, n.value()); if (count < 0) { env->raise("ArgumentError", "negative array size (or size too big)"); return nullptr; @@ -194,7 +194,7 @@ Value RangeObject::first(Env *env, Value n) { ArrayObject *ary = new ArrayObject { (size_t)count }; iterate_over_range(env, [&](Value item) -> Value { - if (count == 0) return n; + if (count == 0) return n.value(); ary->push(item); count--; @@ -239,7 +239,7 @@ Value RangeObject::inspect(Env *env) { } } -Value RangeObject::last(Env *env, Value n) { +Value RangeObject::last(Env *env, Optional n) { if (m_end.is_nil()) env->raise("RangeError", "cannot get the last element of endless range"); @@ -382,9 +382,8 @@ Value RangeObject::bsearch(Env *env, Block *block) { NAT_UNREACHABLE(); } -Value RangeObject::step(Env *env, Value n, Block *block) { - if (!n) - n = Value::nil(); +Value RangeObject::step(Env *env, Optional n_arg, Block *block) { + auto n = n_arg.value_or(Value::nil()); if (!n.is_numeric() && !n.is_nil()) { static const auto coerce_sym = "coerce"_s; diff --git a/src/rational_object.cpp b/src/rational_object.cpp index 0e84b953a..cd125a203 100644 --- a/src/rational_object.cpp +++ b/src/rational_object.cpp @@ -133,24 +133,24 @@ bool RationalObject::eq(Env *env, Value other) { return true; } -Value RationalObject::floor(Env *env, Value precision_value) { - nat_int_t precision = 0; - if (precision_value) - precision = IntegerMethods::convert_to_nat_int_t(env, precision_value); - +Value RationalObject::floor(Env *env, Optional precision_arg) { if (m_denominator == 1) - return IntegerMethods::floor(env, m_numerator, precision_value); + return IntegerMethods::floor(env, m_numerator, precision_arg); + + nat_int_t precision = 0; + if (precision_arg) + precision = IntegerMethods::convert_to_nat_int_t(env, precision_arg.value()); if (precision < 0) { auto i = to_i(env).integer(); - return IntegerMethods::floor(env, i, precision_value); + return IntegerMethods::floor(env, i, precision_arg.value()); } if (precision == 0) - return to_f(env).as_float()->floor(env, precision_value); + return to_f(env).as_float()->floor(env, precision_arg); auto powered = Natalie::pow(10, precision); - auto numerator = mul(env, powered).as_rational()->floor(env, nullptr).integer(); + auto numerator = mul(env, powered).as_rational()->floor(env).integer(); return create(env, numerator, powered); } @@ -276,15 +276,15 @@ Value RationalObject::rationalize(Env *env) { return this; } -Value RationalObject::truncate(Env *env, Value ndigits) { +Value RationalObject::truncate(Env *env, Optional ndigits_arg) { auto numerator = m_numerator.to_nat_int_t(); auto denominator = m_denominator.to_nat_int_t(); nat_int_t digits = 0; - if (ndigits) { - if (!ndigits.is_integer()) + if (ndigits_arg) { + if (!ndigits_arg.value().is_integer()) env->raise("TypeError", "not an integer"); - digits = ndigits.integer().to_nat_int_t(); + digits = ndigits_arg.value().integer().to_nat_int_t(); } if (digits == 0) @@ -292,7 +292,7 @@ Value RationalObject::truncate(Env *env, Value ndigits) { if (digits < 0) { auto quotient = Value::integer(numerator / denominator); - return IntegerMethods::truncate(env, quotient.integer(), ndigits); + return IntegerMethods::truncate(env, quotient.integer(), ndigits_arg); } const auto power = static_cast(std::pow(10, digits)); diff --git a/src/regexp_object.cpp b/src/regexp_object.cpp index 8ffb70c23..7e1030eae 100644 --- a/src/regexp_object.cpp +++ b/src/regexp_object.cpp @@ -106,10 +106,10 @@ OnigEncoding RegexpObject::ruby_encoding_to_onig_encoding(NonNullPtr ref) { auto match = env->caller()->last_match(); if (ref && match.is_match_data()) - return match.as_match_data()->ref(env, ref); + return match.as_match_data()->ref(env, ref.value_or(static_cast(nullptr))); return match; } @@ -204,7 +204,7 @@ Value RegexpObject::regexp_union(Env *env, Args &&args) { return new RegexpObject { env, out }; } -Value RegexpObject::initialize(Env *env, Value pattern, Value opts) { +Value RegexpObject::initialize(Env *env, Value pattern, Optional opts_arg) { assert_not_frozen(env); if (is_initialized()) @@ -212,14 +212,15 @@ Value RegexpObject::initialize(Env *env, Value pattern, Value opts) { if (pattern.is_regexp()) { auto other = pattern.as_regexp(); - if (opts && !opts.is_nil()) + if (opts_arg && !opts_arg.value().is_nil()) env->warn("flags ignored"); initialize_internal(env, other->m_pattern, other->options()); return this; } nat_int_t options = 0; - if (opts != nullptr) { + if (opts_arg) { + auto opts = opts_arg.value(); if (opts.is_integer()) { options = opts.integer().to_nat_int_t(); } else if (opts.is_string()) { @@ -447,7 +448,7 @@ Value RegexpObject::eqtilde(Env *env, Value other) { } } -Value RegexpObject::match(Env *env, Value other, Value start, Block *block) { +Value RegexpObject::match(Env *env, Value other, Optional start, Block *block) { assert_initialized(env); Env *caller_env = env->caller(); @@ -465,8 +466,8 @@ Value RegexpObject::match(Env *env, Value other, Value start, Block *block) { env->raise_invalid_byte_sequence_error(str_obj->encoding()); nat_int_t start_byte_index = 0; - if (start != nullptr) { - auto char_index = IntegerMethods::convert_to_native_type(env, start); + if (start) { + auto char_index = IntegerMethods::convert_to_native_type(env, start.value()); start_byte_index = str_obj->char_index_to_byte_index(char_index); } @@ -506,7 +507,7 @@ Value RegexpObject::match_at_byte_offset(Env *env, StringObject *str, size_t byt } } -bool RegexpObject::has_match(Env *env, Value other, Value start) { +bool RegexpObject::has_match(Env *env, Value other, Optional start) { assert_initialized(env); if (other.is_nil()) return false; @@ -517,8 +518,8 @@ bool RegexpObject::has_match(Env *env, Value other, Value start) { StringObject *str_obj = other.as_string(); nat_int_t start_index = 0; - if (start && start.is_integer()) - start_index = start.integer().to_nat_int_t(); + if (start && start.value().is_integer()) + start_index = start.value().integer().to_nat_int_t(); if (start_index < 0) start_index += str_obj->length(); diff --git a/src/rounding_mode.cpp b/src/rounding_mode.cpp index d8832ef51..e9b088ccd 100644 --- a/src/rounding_mode.cpp +++ b/src/rounding_mode.cpp @@ -2,12 +2,14 @@ namespace Natalie { -RoundingMode rounding_mode_from_value(Env *env, Value value, RoundingMode default_rounding_mode) { - if (!value) return default_rounding_mode; - if (value.is_nil()) return default_rounding_mode; - if (!value.is_symbol()) { +RoundingMode rounding_mode_from_value(Env *env, Optional value_arg, RoundingMode default_rounding_mode) { + if (!value_arg) + return default_rounding_mode; + auto value = value_arg.value(); + if (value.is_nil()) + return default_rounding_mode; + if (!value.is_symbol()) env->raise("ArgumentError", "invalid rounding mode: {}", value.inspect_str(env)); - } auto symbol = value.as_symbol(); diff --git a/src/string_object.cpp b/src/string_object.cpp index 832a0cc3e..4b566ef29 100644 --- a/src/string_object.cpp +++ b/src/string_object.cpp @@ -3,6 +3,7 @@ #include "natalie.hpp" #include "natalie/crypt.h" #include "natalie/integer_methods.hpp" +#include "natalie/object_type.hpp" #include "natalie/string_unpacker.hpp" #include "string.h" @@ -261,17 +262,20 @@ String create_padding(String &padding, size_t length) { return buffer; } -Value StringObject::center(Env *env, Value length, Value padstr) { +Value StringObject::center(Env *env, Value length, Optional pad_arg) { nat_int_t length_i = length.to_int(env).to_nat_int_t(); String pad; - if (!padstr) { + if (!pad_arg) { pad = String { " " }; - } else if (padstr.is_string()) { - pad = padstr.as_string()->string(); } else { - pad = padstr.to_str(env)->string(); + auto padstr = pad_arg.value(); + if (padstr.is_string()) { + pad = padstr.as_string()->string(); + } else { + pad = padstr.to_str(env)->string(); + } } if (pad.is_empty()) @@ -291,24 +295,22 @@ Value StringObject::center(Env *env, Value length, Value padstr) { return new StringObject { result, m_encoding }; } -Value StringObject::chomp(Env *env, Value record_separator) const { +Value StringObject::chomp(Env *env, Optional record_separator) const { auto new_str = new StringObject { m_string, m_encoding }; new_str->chomp_in_place(env, record_separator); return new_str; } -Value StringObject::chomp_in_place(Env *env, Value record_separator) { +Value StringObject::chomp_in_place(Env *env, Optional record_separator) { assert_not_frozen(env); // When passed nil, return nil - if (!record_separator.is_null() && record_separator.is_nil()) { + if (record_separator && record_separator.value().is_nil()) return Value::nil(); - } // When passed a non nil object, call to_str(); - if (!record_separator.is_null() && !record_separator.is_string()) { - record_separator = record_separator.to_str(env); - } + if (record_separator && !record_separator.value().is_string()) + record_separator = record_separator.value().to_str(env); if (is_empty()) { // if this is an empty string, return nil return Value::nil(); @@ -317,7 +319,7 @@ Value StringObject::chomp_in_place(Env *env, Value record_separator) { size_t end_idx = m_string.length(); String global_record_separator = env->global_get("$/"_s).as_string()->string(); // When using default record separator, also remove trailing \r - if (record_separator.is_null() && global_record_separator == "\n") { + if (!record_separator && global_record_separator == "\n") { size_t char_pos = end_idx; auto removed_char = prev_char(&char_pos); auto last_codept = m_encoding->decode_codepoint(removed_char); @@ -342,7 +344,7 @@ Value StringObject::chomp_in_place(Env *env, Value record_separator) { // When called with custom global record separator and no args // don't remove \r unless specified by record separator - } else if (record_separator.is_null()) { + } else if (!record_separator) { // FIXME: this seems unused????????????????????????????????????????????????????????????????????? size_t end_idx = length(); size_t last_idx = end_idx - 1; size_t sep_idx = global_record_separator.length() - 1; @@ -369,9 +371,9 @@ Value StringObject::chomp_in_place(Env *env, Value record_separator) { } } - record_separator.assert_type(env, Object::Type::String, "String"); + record_separator.value().assert_type(env, Object::Type::String, "String"); - const String rs = record_separator.as_string()->m_string; + const String rs = record_separator.value().as_string()->m_string; size_t rs_len = rs.length(); // when passed empty string remove trailing \n and \r\n but not \r @@ -636,7 +638,7 @@ bool StringObject::internal_start_with(Env *env, Value needle) { needle = needle.as_regexp()->to_s(env); needle.as_string()->prepend(env, { new StringObject { "\\A" } }); needle = new RegexpObject { env, needle.as_string()->string() }; - return needle.as_regexp()->match(env, this, nullptr).is_truthy(); + return needle.as_regexp()->match(env, this).is_truthy(); } nat_int_t i = index_int(env, needle, 0); @@ -742,10 +744,10 @@ static Value byteindex_string_needle(Env *env, const StringObject *haystack, Str return Value::integer(result); } -Value StringObject::byteindex(Env *env, Value needle_obj, Value offset_obj) const { +Value StringObject::byteindex(Env *env, Value needle_obj, Optional offset_arg) const { ssize_t offset = 0; - if (offset_obj) - offset = IntegerMethods::convert_to_native_type(env, offset_obj); + if (offset_arg) + offset = IntegerMethods::convert_to_native_type(env, offset_arg.value()); if (offset < 0) offset += bytesize(); if (offset < 0 || (size_t)offset > bytesize()) @@ -758,10 +760,10 @@ Value StringObject::byteindex(Env *env, Value needle_obj, Value offset_obj) cons return byteindex_string_needle(env, this, needle, offset); } -Value StringObject::byterindex(Env *env, Value needle_obj, Value offset_obj) const { +Value StringObject::byterindex(Env *env, Value needle_obj, Optional offset_arg) const { ssize_t offset = bytesize(); - if (offset_obj) - offset = IntegerMethods::convert_to_native_type(env, offset_obj); + if (offset_arg) + offset = IntegerMethods::convert_to_native_type(env, offset_arg.value()); if (offset < 0) offset += bytesize(); if (offset < 0) @@ -775,8 +777,8 @@ Value StringObject::byterindex(Env *env, Value needle_obj, Value offset_obj) con return byteindex_string_needle(env, this, needle, offset, true); } -Value StringObject::index(Env *env, Value needle, Value offset) { - int offset_i = (offset) ? IntegerMethods::convert_to_int(env, offset) : 0; +Value StringObject::index(Env *env, Value needle, Optional offset) { + int offset_i = offset ? IntegerMethods::convert_to_int(env, offset.value()) : 0; int len = char_count(env); if (offset_i < -1 * len) { // extremely negative offset larger than string length returns nil @@ -846,9 +848,9 @@ nat_int_t StringObject::index_int(Env *env, Value needle, size_t byte_start) { return (char *)ptr - c_str(); } -Value StringObject::rindex(Env *env, Value needle, Value offset) const { +Value StringObject::rindex(Env *env, Value needle, Optional offset) const { int len = char_count(env); - int offset_i = (offset) ? IntegerMethods::convert_to_int(env, offset) : len; + int offset_i = offset ? IntegerMethods::convert_to_int(env, offset.value()) : len; if (offset_i < -1 * len) { // extremely negative offset larger than string length returns nil return Value::nil(); @@ -932,14 +934,13 @@ nat_int_t StringObject::rindex_int(Env *env, Value needle, size_t byte_start) co return -1; } -Value StringObject::initialize(Env *env, Value arg, Value encoding, Value capacity) { +Value StringObject::initialize(Env *env, Optional arg, Optional encoding, Optional capacity) { if (arg) - initialize_copy(env, arg.to_str(env)); - if (encoding) { - force_encoding(env, encoding); - } + initialize_copy(env, arg.value().to_str(env)); + if (encoding) + force_encoding(env, encoding.value()); if (capacity) { - const auto cap = IntegerMethods::convert_to_native_type(env, capacity); + const auto cap = IntegerMethods::convert_to_native_type(env, capacity.value()); m_string.set_capacity(cap); } return this; @@ -1166,7 +1167,7 @@ Value StringObject::eqtilde(Env *env, Value other) { return other.as_regexp()->eqtilde(env, this); } -Value StringObject::match(Env *env, Value other, Value index, Block *block) { +Value StringObject::match(Env *env, Value other, Optional index_arg, Block *block) { if (!other.is_regexp()) { if (other.is_string()) { other = new RegexpObject { env, other.as_string()->string() }; @@ -1177,7 +1178,11 @@ Value StringObject::match(Env *env, Value other, Value index, Block *block) { } } other.assert_type(env, Object::Type::Regexp, "Regexp"); - auto result = other.send(env, "match"_s, { this, index }, block); + Value result; + if (index_arg) + result = other.send(env, "match"_s, { this, index_arg.value() }, block); + else + result = other.send(env, "match"_s, { this }, block); env->caller()->set_match(env->match()); return result; } @@ -1358,21 +1363,21 @@ Value StringObject::size(Env *env) const { return IntegerMethods::from_size_t(env, char_count(env)); } -Value StringObject::encode(Env *env, Value dst_encoding, Value src_encoding, HashObject *kwargs) { +Value StringObject::encode(Env *env, Optional dst_encoding, Optional src_encoding, HashObject *kwargs) { StringObject *copy = duplicate(env).as_string(); return copy->encode_in_place(env, dst_encoding, src_encoding, kwargs); } -Value StringObject::encode_in_place(Env *env, Value dst_encoding, Value src_encoding, HashObject *kwargs) { +Value StringObject::encode_in_place(Env *env, Optional dst_encoding_arg, Optional src_encoding_arg, HashObject *kwargs) { assert_not_frozen(env); - if (!dst_encoding) - dst_encoding = EncodingObject::default_internal(); - if (!dst_encoding) + Value dst_encoding = EncodingObject::default_internal(); + if (dst_encoding_arg) + dst_encoding = dst_encoding_arg.value(); + if (dst_encoding == nullptr) // default_internal can return null dst_encoding = EncodingObject::get(Encoding::UTF_8); - if (!src_encoding) - src_encoding = m_encoding.ptr(); + auto src_encoding = src_encoding_arg.value_or(m_encoding.ptr()); EncodeOptions options; if (kwargs) { @@ -1445,9 +1450,9 @@ Value StringObject::force_encoding(Env *env, Value encoding) { return this; } -bool StringObject::has_match(Env *env, Value other, Value start) { +bool StringObject::has_match(Env *env, Value other, Optional start) { other.assert_type(env, Object::Type::Regexp, "Regexp"); - return other.as_regexp()->has_match(env, this, start); + return other.as_regexp()->has_match(env, this, start.value_or(Value::nil())); } /** @@ -1569,14 +1574,16 @@ Value StringObject::hex(Env *env) const { * slice(regexp, capture) → new_str or nil * slice(match_str) → new_str or nil */ -Value StringObject::ref(Env *env, Value index_obj, Value length_obj) { +Value StringObject::ref(Env *env, Value index_obj, Optional length_arg) { // not sure how we'd handle a string that big anyway assert(length() < NAT_INT_MAX); // First, check if there's a second argument. This is important for the // order in which things are attempted to be implicitly converted into // integers. - if (length_obj != nullptr) { + if (length_arg) { + auto length_obj = length_arg.value(); + // First, we'll check if the index is a regexp. If it's not and there // _is_ a second argument, the index is assumed to be an integer or an // object that can be implicitly converted into an integer. @@ -1725,10 +1732,10 @@ Value StringObject::ref(Env *env, Value index_obj, Value length_obj) { if (index < 0) index += count; - if (length_obj != nullptr) { + if (length_arg) { // If we have a length, then attempt to convert the length object // into an integer, and make sure it fits into a fixnum. - nat_int_t length = IntegerMethods::convert_to_nat_int_t(env, length_obj); + nat_int_t length = IntegerMethods::convert_to_nat_int_t(env, length_arg.value()); // Now, check that the index is within the bounds of the string. If // not, then return nil. @@ -1755,13 +1762,15 @@ Value StringObject::ref(Env *env, Value index_obj, Value length_obj) { * byteslice(index, length = 1) → string or nil * byteslice(range) → string or nil */ -Value StringObject::byteslice(Env *env, Value index_obj, Value length_obj) { +Value StringObject::byteslice(Env *env, Value index_obj, Optional length_arg) { nat_int_t m_length = static_cast(length()); // not sure how we'd handle a string that big anyway assert(m_length < NAT_INT_MAX); - if (length_obj != nullptr) { + if (length_arg) { + auto length_obj = length_arg.value(); + // First, we're going to get the start index of the slice and make sure // that it's not right at the end of the string. If it is, we'll just // return an empty string. @@ -2030,7 +2039,7 @@ Value StringObject::bytesplice(Env *env, Args &&args) { return this; } -Value StringObject::slice_in_place(Env *env, Value index_obj, Value length_obj) { +Value StringObject::slice_in_place(Env *env, Value index_obj, Optional length_obj) { assert_not_frozen(env); // not sure how we'd handle a string that big anyway @@ -2104,8 +2113,8 @@ Value StringObject::slice_in_place(Env *env, Value index_obj, Value length_obj) // captures or the name of a group. If it's not a string, make sure // we attempt to convert it into an integer _before_ we return nil // if there we no match result. - if (length_obj != nullptr && !length_obj.is_string()) - capture = IntegerMethods::convert_to_nat_int_t(env, length_obj); + if (length_obj && !length_obj.value().is_string()) + capture = IntegerMethods::convert_to_nat_int_t(env, length_obj.value()); // If the match failed, return nil. Note that this must happen after // the implicit conversion of the index argument to an integer. @@ -2168,9 +2177,9 @@ Value StringObject::slice_in_place(Env *env, Value index_obj, Value length_obj) nat_int_t index = IntegerMethods::convert_to_nat_int_t(env, index_obj); nat_int_t count = static_cast(char_count(env)); - if (length_obj != nullptr) { + if (length_obj) { // First, convert the length to an integer. - nat_int_t length = IntegerMethods::convert_to_nat_int_t(env, length_obj); + nat_int_t length = IntegerMethods::convert_to_nat_int_t(env, length_obj.value()); // Now, check that the index is within the bounds of the string. If // not, then return nil. @@ -2388,12 +2397,12 @@ ssize_t StringObject::byte_index_to_char_index(size_t byte_index) const { return current_char_index; } -Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { +Value StringObject::refeq(Env *env, Value arg1, Optional arg2, Optional value) { assert_not_frozen(env); - if (value == nullptr) { + if (!value) { value = arg2; - arg2 = nullptr; + arg2 = Optional {}; } auto chars = this->chars(env).as_array(); @@ -2408,9 +2417,9 @@ Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { return start; }; - auto get_end_by_length = [env](nat_int_t begin, Value length_argument) -> nat_int_t { + auto get_end_by_length = [env](nat_int_t begin, Optional length_argument) -> nat_int_t { if (length_argument) { - auto length = IntegerMethods::convert_to_nat_int_t(env, length_argument); + auto length = IntegerMethods::convert_to_nat_int_t(env, length_argument.value()); if (length < 0) env->raise("IndexError", "negative length {}", length); return begin + length; @@ -2426,7 +2435,7 @@ Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { begin = process_begin(arg1.integer().to_nat_int_t()); end = get_end_by_length(begin, arg2); } else if (arg1.is_range()) { - assert(arg2 == nullptr); + assert(!arg2); auto range = arg1.as_range(); begin = IntegerMethods::convert_to_nat_int_t(env, range->begin()); @@ -2458,7 +2467,7 @@ Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { nat_int_t match_index_argument = 0; if (arg2) - match_index_argument = IntegerMethods::convert_to_nat_int_t(env, arg2); + match_index_argument = IntegerMethods::convert_to_nat_int_t(env, arg2.value()); if (::abs(match_index_argument) >= (nat_int_t)match_result->size()) env->raise("IndexError", "index {} out of regexp", match_index_argument); @@ -2474,7 +2483,7 @@ Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { begin = IntegerMethods::convert_to_nat_int_t(env, offset->at(0)); end = IntegerMethods::convert_to_nat_int_t(env, offset->at(1)); } else if (arg1.is_string()) { - assert(arg2 == nullptr); + assert(!arg2); auto query = arg1.as_string()->string(); begin = m_string.find(query); if (begin == -1) @@ -2490,7 +2499,7 @@ Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { if (end > (nat_int_t)chars->size()) chars_to_be_removed = chars->size() - begin; - auto string = value.to_str(env); + auto string = value.value().to_str(env); auto arg_chars = string->chars(env).as_array(); size_t new_length = arg_chars->size() + (chars->size() - chars_to_be_removed); @@ -2505,10 +2514,10 @@ Value StringObject::refeq(Env *env, Value arg1, Value arg2, Value value) { } m_string = result.string(); - return value; + return value.value(); } -Value StringObject::sub(Env *env, Value find, Value replacement_value, Block *block) { +Value StringObject::sub(Env *env, Value find, Optional replacement_value, Block *block) { if (!block && !replacement_value) env->raise("ArgumentError", "wrong number of arguments (given 1, expected 2)"); @@ -2535,7 +2544,7 @@ Value StringObject::sub(Env *env, Value find, Value replacement_value, Block *bl return new StringObject { out, m_encoding }; } -Value StringObject::sub_in_place(Env *env, Value find, Value replacement_value, Block *block) { +Value StringObject::sub_in_place(Env *env, Value find, Optional replacement_value, Block *block) { assert_not_frozen(env); auto replacement = sub(env, find, replacement_value, block).as_string()->string(); @@ -2546,7 +2555,7 @@ Value StringObject::sub_in_place(Env *env, Value find, Value replacement_value, return this; } -Value StringObject::gsub(Env *env, Value find, Value replacement_value, Block *block) { +Value StringObject::gsub(Env *env, Value find, Optional replacement_value, Block *block) { if (!replacement_value && !block) env->raise("NotImplementedError", "Enumerator reply in String#gsub"); @@ -2581,7 +2590,7 @@ Value StringObject::gsub(Env *env, Value find, Value replacement_value, Block *b return new StringObject { out, m_encoding }; } -Value StringObject::gsub_in_place(Env *env, Value find, Value replacement_value, Block *block) { +Value StringObject::gsub_in_place(Env *env, Value find, Optional replacement_value, Block *block) { assert_not_frozen(env); auto replacement = gsub(env, find, replacement_value, block).as_string()->string(); @@ -2612,14 +2621,14 @@ Value StringObject::getbyte(Env *env, Value index_obj) const { return Integer(byte); } -void StringObject::regexp_sub(Env *env, TM::String &out, StringObject *orig_string, RegexpObject *find, Value replacement_value, MatchDataObject **match, StringObject **expanded_replacement, size_t byte_index, Block *block) { +void StringObject::regexp_sub(Env *env, TM::String &out, StringObject *orig_string, RegexpObject *find, Optional replacement_arg, MatchDataObject **match, StringObject **expanded_replacement, size_t byte_index, Block *block) { HashObject *replacement_hash = nullptr; StringObject *replacement_str = nullptr; - if (replacement_value) { - if (replacement_value.is_hash()) { - replacement_hash = replacement_value.as_hash(); + if (replacement_arg) { + if (replacement_arg.value().is_hash()) { + replacement_hash = replacement_arg.value().as_hash(); } else { - replacement_str = replacement_value.to_str(env); + replacement_str = replacement_arg.value().to_str(env); } block = nullptr; } @@ -2735,7 +2744,7 @@ Value StringObject::to_f(Env *env) const { return new FloatObject { result }; } -Value StringObject::to_i(Env *env, Value base_obj) const { +Value StringObject::to_i(Env *env, Optional base_obj) const { size_t start = 0; // strip leading whitespace @@ -2759,7 +2768,7 @@ Value StringObject::to_i(Env *env, Value base_obj) const { int base = 10; if (base_obj) { - base = base_obj.to_int(env).to_nat_int_t(); + base = base_obj.value().to_int(env).to_nat_int_t(); if (base < 0 || base == 1 || base > 36) { env->raise("ArgumentError", "invalid radix {}", base); @@ -2972,24 +2981,23 @@ Value StringObject::split(Env *env, StringObject *splitstr, int max_count) { // + special case single-space splitter // + proper handling of negative max-count-values -Value StringObject::split(Env *env, Value splitter, Value max_count_value) { +Value StringObject::split(Env *env, Optional splitter_arg, Optional max_count_arg) { assert_valid_encoding(env); ArrayObject *ary = new ArrayObject {}; - if (!splitter || splitter.is_nil()) { + if (!splitter_arg || splitter_arg.value().is_nil()) { auto field_sep = env->global_get("$;"_s); if (!field_sep.is_nil()) { env->warn("$; is set to non-nil value, but the output was {}", field_sep.klass()->inspect_str()); - splitter = field_sep; + splitter_arg = field_sep; } } - if (!splitter) { - splitter = new RegexpObject { env, "\\s+" }; - } + Value splitter = splitter_arg.value_or([&env]() { return new RegexpObject { env, "\\s+" }; }); + int max_count = 0; - if (max_count_value) { - max_count = IntegerMethods::convert_to_int(env, max_count_value); - } + if (max_count_arg) + max_count = IntegerMethods::convert_to_int(env, max_count_arg.value()); + if (length() == 0) { return ary; } else if (max_count == 1 || splitter.is_nil()) { @@ -3093,15 +3101,15 @@ Value StringObject::insert(Env *env, Value index_obj, Value other_str) { return this; } -void StringObject::each_line(Env *env, Value separator, Value chomp_value, std::function callback) const { - if (separator) { +void StringObject::each_line(Env *env, Optional separator_arg, Optional chomp_arg, std::function callback) const { + auto separator = Value::nil(); + if (separator_arg) { + separator = separator_arg.value(); if (!separator.is_nil()) separator = separator.to_str(env); } else { auto dollar_slash = env->global_get("$/"_s); - if (dollar_slash.is_nil()) - separator = Value::nil(); - else + if (!dollar_slash.is_nil()) separator = dollar_slash.to_str(env); } @@ -3122,7 +3130,7 @@ void StringObject::each_line(Env *env, Value separator, Value chomp_value, std:: separator = new StringObject { "\n\n" }; } - const auto chomp = chomp_value ? chomp_value.is_truthy() : false; + const auto chomp = chomp_arg ? chomp_arg.value().is_truthy() : false; auto separator_length = separator.as_string()->length(); size_t last_index = 0; @@ -3162,19 +3170,21 @@ void StringObject::each_line(Env *env, Value separator, Value chomp_value, std:: } } -Value StringObject::each_line(Env *env, Value separator, Value chomp, Block *block) { +Value StringObject::each_line(Env *env, Optional separator_arg, Optional chomp, Block *block) { if (!block) { - Vector args { separator }; - auto do_chomp = chomp ? chomp.is_truthy() : false; + Vector args(1); + if (separator_arg) + args.push(separator_arg.value()); + auto do_chomp = chomp ? chomp.value().is_truthy() : false; if (do_chomp) { auto hash = new HashObject {}; - hash->put(env, "chomp"_s, chomp); + hash->put(env, "chomp"_s, chomp.value_or(FalseObject::the())); args.push(hash); } return enum_for(env, "each_line", Args(args, do_chomp)); } - each_line(env, separator, chomp, [&](StringObject *part) -> Value { + each_line(env, separator_arg, chomp, [&](StringObject *part) -> Value { Value args[] = { part }; block->run(env, Args(1, args), nullptr); return this; @@ -3182,7 +3192,7 @@ Value StringObject::each_line(Env *env, Value separator, Value chomp, Block *blo return this; } -Value StringObject::lines(Env *env, Value separator, Value chomp, Block *block) { +Value StringObject::lines(Env *env, Optional separator, Optional chomp, Block *block) { if (block) return each_line(env, separator, chomp, block); @@ -3194,16 +3204,15 @@ Value StringObject::lines(Env *env, Value separator, Value chomp, Block *block) return ary; } -Value StringObject::ljust(Env *env, Value length_obj, Value pad_obj) const { +Value StringObject::ljust(Env *env, Value length_obj, Optional pad_arg) const { nat_int_t length_i = length_obj.to_int(env).to_nat_int_t(); size_t length = length_i < 0 ? 0 : length_i; StringObject *padstr; - if (!pad_obj) { + if (pad_arg) + padstr = pad_arg.value().to_str(env); + else padstr = new StringObject { " " }; - } else { - padstr = pad_obj.to_str(env); - } if (padstr->string().is_empty()) env->raise("ArgumentError", "zero width padding"); @@ -3292,16 +3301,15 @@ Value StringObject::lstrip_in_place(Env *env) { return this; } -Value StringObject::rjust(Env *env, Value length_obj, Value pad_obj) const { +Value StringObject::rjust(Env *env, Value length_obj, Optional pad_arg) const { nat_int_t length_i = length_obj.to_int(env).to_nat_int_t(); size_t length = length_i < 0 ? 0 : length_i; StringObject *padstr; - if (!pad_obj) { + if (pad_arg) + padstr = pad_arg.value().to_str(env); + else padstr = new StringObject { " " }; - } else { - padstr = pad_obj.to_str(env); - } if (padstr->string().is_empty()) env->raise("ArgumentError", "zero width padding"); @@ -3379,10 +3387,10 @@ CaseMapType StringObject::check_case_options(Env *env, Value arg1, Value arg2, b SymbolObject *turk = "turkic"_s; SymbolObject *lith = "lithuanian"_s; // return for zero arg case - if (arg1.is_null() && arg2.is_null()) + if (arg1.is_nil() && arg2.is_nil()) return CaseMapFull; // two arg case only accepts turkic and lithuanian (in either order) - if (!arg1.is_null() && !arg2.is_null()) { + if (!arg1.is_nil() && !arg2.is_nil()) { if ((arg1 == turk && arg2 == lith) || (arg1 == lith && arg2 == turk)) { return CaseMapTurkicAzeri | CaseMapLithuanian; } else { @@ -3424,8 +3432,8 @@ Value StringObject::casecmp(Env *env, Value other) { if (!negotiate_compatible_encoding(other_str)) return Value::nil(); - auto str1 = this->downcase(env, "ascii"_s, nullptr); - auto str2 = other_str->downcase(env, "ascii"_s, nullptr); + auto str1 = this->downcase(env, Value("ascii"_s)); + auto str2 = other_str->downcase(env, Value("ascii"_s)); return str1->cmp(env, Value(str2)); } @@ -3442,15 +3450,15 @@ Value StringObject::is_casecmp(Env *env, Value other) { if (!negotiate_compatible_encoding(other_str)) return Value::nil(); - auto str1 = this->downcase(env, "fold"_s, nullptr); - auto str2 = other_str->downcase(env, "fold"_s, nullptr); + auto str1 = this->downcase(env, Value("fold"_s)); + auto str2 = other_str->downcase(env, Value("fold"_s)); if (str1->string() == str2->string()) return TrueObject::the(); return FalseObject::the(); } -StringObject *StringObject::capitalize(Env *env, Value arg1, Value arg2) { +StringObject *StringObject::capitalize(Env *env, Optional arg1, Optional arg2) { auto flags = check_case_options(env, arg1, arg2); auto str = new StringObject { "", m_encoding }; bool first_char = true; @@ -3469,7 +3477,7 @@ StringObject *StringObject::capitalize(Env *env, Value arg1, Value arg2) { return str; } -Value StringObject::capitalize_in_place(Env *env, Value arg1, Value arg2) { +Value StringObject::capitalize_in_place(Env *env, Optional arg1, Optional arg2) { auto copy = capitalize(env, arg1, arg2); assert_not_frozen(env); if (*this == *copy) { @@ -3479,7 +3487,7 @@ Value StringObject::capitalize_in_place(Env *env, Value arg1, Value arg2) { return this; } -StringObject *StringObject::downcase(Env *env, Value arg1, Value arg2) { +StringObject *StringObject::downcase(Env *env, Optional arg1, Optional arg2) { auto flags = check_case_options(env, arg1, arg2, true); auto str = new StringObject { "", m_encoding }; nat_int_t result[3] = {}; @@ -3508,7 +3516,7 @@ StringObject *StringObject::downcase(Env *env, Value arg1, Value arg2) { return str; } -Value StringObject::downcase_in_place(Env *env, Value arg1, Value arg2) { +Value StringObject::downcase_in_place(Env *env, Optional arg1, Optional arg2) { assert_not_frozen(env); StringObject *copy = duplicate(env).as_string(); *this = *downcase(env, arg1, arg2); @@ -3582,7 +3590,7 @@ Value StringObject::dump(Env *env) { return new StringObject { std::move(out), m_encoding }; } -StringObject *StringObject::upcase(Env *env, Value arg1, Value arg2) { +StringObject *StringObject::upcase(Env *env, Optional arg1, Optional arg2) { auto flags = check_case_options(env, arg1, arg2); auto str = new StringObject { "", m_encoding }; nat_int_t result[3] = {}; @@ -3595,7 +3603,7 @@ StringObject *StringObject::upcase(Env *env, Value arg1, Value arg2) { return str; } -Value StringObject::upcase_in_place(Env *env, Value arg1, Value arg2) { +Value StringObject::upcase_in_place(Env *env, Optional arg1, Optional arg2) { assert_not_frozen(env); StringObject *copy = duplicate(env).as_string(); *this = *upcase(env, arg1, arg2); @@ -3606,7 +3614,7 @@ Value StringObject::upcase_in_place(Env *env, Value arg1, Value arg2) { return this; } -StringObject *StringObject::swapcase(Env *env, Value arg1, Value arg2) { +StringObject *StringObject::swapcase(Env *env, Optional arg1, Optional arg2) { // currently not doing anything with the returned flags check_case_options(env, arg1, arg2); auto str = new StringObject { "", m_encoding }; @@ -3629,7 +3637,7 @@ StringObject *StringObject::swapcase(Env *env, Value arg1, Value arg2) { return str; } -Value StringObject::swapcase_in_place(Env *env, Value arg1, Value arg2) { +Value StringObject::swapcase_in_place(Env *env, Optional arg1, Optional arg2) { assert_not_frozen(env); StringObject *copy = duplicate(env).as_string(); *this = *swapcase(env, arg1, arg2); @@ -3658,9 +3666,10 @@ Value StringObject::uminus(Env *env) { return duplicate; } -Value StringObject::upto(Env *env, Value other, Value exclusive, Block *block) { - if (!exclusive) - exclusive = FalseObject::the(); +Value StringObject::upto(Env *env, Value other, Optional exclusive_arg, Block *block) { + Value exclusive = FalseObject::the(); + if (exclusive_arg) + exclusive = exclusive_arg.value(); if (!block) return enum_for(env, "upto", { other, exclusive }); @@ -4172,12 +4181,12 @@ Value StringObject::partition(Env *env, Value val) { return ary; } -Value StringObject::sum(Env *env, Value val) { +Value StringObject::sum(Env *env, Optional val) { int base = 16; int sum = 0; if (val) - base = val.to_int(env).to_nat_int_t(); + base = val.value().to_int(env).to_nat_int_t(); for (size_t i = 0; i < length(); ++i) { sum += m_string[i]; diff --git a/src/symbol_object.cpp b/src/symbol_object.cpp index e09d75507..989b7f574 100644 --- a/src/symbol_object.cpp +++ b/src/symbol_object.cpp @@ -160,12 +160,12 @@ Value SymbolObject::length(Env *env) { Value SymbolObject::match(Env *env, Value other, Block *block) const { other.assert_type(env, Object::Type::Regexp, "Regexp"); - return other.as_regexp()->match(env, name(env), nullptr, block); + return other.as_regexp()->match(env, name(env), {}, block); } -bool SymbolObject::has_match(Env *env, Value other, Value start) const { +bool SymbolObject::has_match(Env *env, Value other, Optional start) const { other.assert_type(env, Object::Type::Regexp, "Regexp"); - return other.as_regexp()->has_match(env, name(env), start); + return other.as_regexp()->has_match(env, name(env), start.value_or(Value::nil())); } Value SymbolObject::name(Env *env) const { @@ -176,7 +176,7 @@ Value SymbolObject::name(Env *env) const { } return symbol->m_string; } -Value SymbolObject::ref(Env *env, Value index_obj, Value length_obj) { +Value SymbolObject::ref(Env *env, Value index_obj, Optional length_obj) { // The next line worked in nearly every case, except it did not set `$~` // return to_s(env).send(env, intern("[]"), { index_obj, length_obj }); return to_s(env)->ref(env, index_obj, length_obj); diff --git a/src/thread/mutex_object.cpp b/src/thread/mutex_object.cpp index 4fa07cc87..aaf3ecfe6 100644 --- a/src/thread/mutex_object.cpp +++ b/src/thread/mutex_object.cpp @@ -27,13 +27,15 @@ Value MutexObject::lock(Env *env) { return this; } -Value MutexObject::sleep(Env *env, Value timeout) { - if (!timeout || timeout.is_nil()) { +Value MutexObject::sleep(Env *env, Optional timeout_arg) { + if (!timeout_arg || timeout_arg.value().is_nil()) { ThreadObject::current()->sleep(env, -1.0, this); lock(env); return this; } + auto timeout = timeout_arg.value(); + if ((timeout.is_float() && timeout.as_float()->is_negative()) || (timeout.is_integer() && timeout.integer().is_negative())) env->raise("ArgumentError", "time interval must not be negative"); diff --git a/src/thread_object.cpp b/src/thread_object.cpp index a277de6d3..370776c6c 100644 --- a/src/thread_object.cpp +++ b/src/thread_object.cpp @@ -515,7 +515,7 @@ Value ThreadObject::set_priority(Env *env, Value priority) { return priority; } -Value ThreadObject::fetch(Env *env, Value key, Value default_value, Block *block) { +Value ThreadObject::fetch(Env *env, Value key, Optional default_value, Block *block) { key = validate_key(env, key); HashObject *hash = nullptr; if (m_current_fiber) diff --git a/src/time_object.cpp b/src/time_object.cpp index e38763da0..3c17637d9 100644 --- a/src/time_object.cpp +++ b/src/time_object.cpp @@ -4,33 +4,33 @@ namespace Natalie { -TimeObject *TimeObject::at(Env *env, Value time, Value subsec, Value unit) { +TimeObject *TimeObject::at(Env *env, Value time, Optional subsec, Optional unit) { RationalObject *rational = convert_rational(env, time); if (subsec) { - auto scale = convert_unit(env, unit ? unit : "microsecond"_s); - rational = rational->add(env, convert_rational(env, subsec)->div(env, scale)).as_rational(); + auto scale = convert_unit(env, unit.value_or("microsecond"_s)); + rational = rational->add(env, convert_rational(env, subsec.value())->div(env, scale)).as_rational(); } return create(env, rational, Mode::Localtime); } -TimeObject *TimeObject::at(Env *env, Value time, Value subsec, Value unit, Value in) { +TimeObject *TimeObject::at(Env *env, Value time, Optional subsec, Optional unit, Optional in) { auto result = at(env, time, subsec, unit); if (in) { - result->m_time.tm_gmtoff = normalize_timezone(env, in); + result->m_time.tm_gmtoff = normalize_timezone(env, in.value()); result->m_zone = strdup("UTC"); result->m_time.tm_zone = result->m_zone; } return result; } -TimeObject *TimeObject::local(Env *env, Value year, Value month, Value mday, Value hour, Value min, Value sec, Value usec) { +TimeObject *TimeObject::local(Env *env, Value year, Optional month, Optional mday, Optional hour, Optional min, Optional sec, Optional usec) { TimeObject *result = new TimeObject {}; result->build_time(env, year, month, mday, hour, min, sec); int seconds = mktime(&result->m_time); result->m_mode = Mode::Localtime; result->m_integer = seconds; - if (usec && usec.is_integer()) { - result->set_subsec(env, usec.integer()); + if (usec && usec.value().is_integer()) { + result->set_subsec(env, usec.value().integer()); } return result; } @@ -40,24 +40,25 @@ TimeObject *TimeObject::create(Env *env) { } // Time.new -TimeObject *TimeObject::initialize(Env *env, Value year, Value month, Value mday, Value hour, Value min, Value sec, Value tmzone, Value in) { - if (!year) { +TimeObject *TimeObject::initialize(Env *env, Optional year, Optional month, Optional mday, Optional hour, Optional min, Optional sec, Optional tmzone, Optional in) { + if (!year) return now(env, nullptr); - } else if (year.is_nil()) { + + if (year.value().is_nil()) { env->raise("TypeError", "Year cannot be nil"); } else { auto result = now(env, nullptr); - result->build_time(env, year, month, mday, hour, min, sec); + result->build_time(env, year.value(), month, mday, hour, min, sec); int seconds = mktime(&result->m_time); result->m_integer = seconds; result->m_subsec = nullptr; if (tmzone && in) { env->raise("ArgumentError", "cannot specify zone and in:"); } else if (tmzone) { - result->m_time.tm_gmtoff = normalize_timezone(env, tmzone); + result->m_time.tm_gmtoff = normalize_timezone(env, tmzone.value()); result->m_mode = Mode::UTC; } else if (in) { - result->m_time.tm_gmtoff = normalize_timezone(env, in); + result->m_time.tm_gmtoff = normalize_timezone(env, in.value()); result->m_mode = Mode::UTC; } else { result->m_mode = Mode::Localtime; @@ -82,14 +83,15 @@ TimeObject *TimeObject::now(Env *env, Value in) { return result; } -TimeObject *TimeObject::utc(Env *env, Value year, Value month, Value mday, Value hour, Value min, Value sec, Value subsec) { +TimeObject *TimeObject::utc(Env *env, Value year, Optional month, Optional mday, Optional hour, Optional min, Optional sec, Optional subsec_arg) { TimeObject *result = new TimeObject {}; result->build_time(env, year, month, mday, hour, min, sec); result->m_time.tm_gmtoff = 0; int seconds = timegm(&result->m_time); result->m_mode = Mode::UTC; result->m_integer = seconds; - if (subsec) { + if (subsec_arg) { + auto subsec = subsec_arg.value(); if (subsec.is_integer()) { auto integer = subsec.integer(); if (integer < 0 || integer >= 1000000) @@ -377,7 +379,7 @@ nat_int_t TimeObject::normalize_month(Env *env, Value val) { if (!val.is_integer()) { if (val.is_string() || val.respond_to(env, "to_str"_s)) { val = val.to_str(env); - auto monstr = val.as_string()->downcase(env, nullptr, nullptr)->string(); + auto monstr = val.as_string()->downcase(env)->string(); if (monstr == "jan") { return 0; } else if (monstr == "feb") { @@ -452,7 +454,7 @@ TimeObject *TimeObject::create(Env *env, RationalObject *rational, Mode mode) { RationalObject *subseconds; TimeObject *result = new TimeObject {}; if (rational->send(env, "<"_s, { Value::integer(0) }).is_true()) { - auto floor = rational->floor(env, nullptr); + auto floor = rational->floor(env); integer = floor.send(env, "to_i"_s).integer(); subseconds = rational->sub(env, floor).as_rational(); } else { @@ -471,7 +473,7 @@ TimeObject *TimeObject::create(Env *env, RationalObject *rational, Mode mode) { return result; } -void TimeObject::build_time(Env *env, Value year, Value month, Value mday, Value hour, Value min, Value sec) { +void TimeObject::build_time(Env *env, Value year, Optional month, Optional mday, Optional hour, Optional min, Optional sec_arg) { m_time = { 0 }; m_time.tm_year = TimeObject::normalize_field(env, year) - 1900; m_time.tm_mon = 0; @@ -482,18 +484,19 @@ void TimeObject::build_time(Env *env, Value year, Value month, Value mday, Value m_time.tm_isdst = -1; // dst-unknown == -1 ; mktime() will set to 0 or 1. if (month) { - m_time.tm_mon = TimeObject::normalize_month(env, month); + m_time.tm_mon = TimeObject::normalize_month(env, month.value()); } if (mday) { - m_time.tm_mday = TimeObject::normalize_field(env, mday, 1, 31); + m_time.tm_mday = TimeObject::normalize_field(env, mday.value(), 1, 31); } if (hour) { - m_time.tm_hour = TimeObject::normalize_field(env, hour, 0, 24); + m_time.tm_hour = TimeObject::normalize_field(env, hour.value(), 0, 24); } if (min) { - m_time.tm_min = TimeObject::normalize_field(env, min, 0, 59); + m_time.tm_min = TimeObject::normalize_field(env, min.value(), 0, 59); } - if (sec && !sec.is_nil()) { + if (sec_arg && !sec_arg.value().is_nil()) { + auto sec = sec_arg.value(); if (sec.is_string()) { // ensure base10 conversion for case of "01" input sec = KernelModule::Integer(env, sec, 10, true);