From ab02b738ae85a3fbe8c6812d74d298c353548348 Mon Sep 17 00:00:00 2001 From: Hadeweka Date: Mon, 26 Apr 2021 15:30:32 +0200 Subject: [PATCH] Added ReturnNil annotations --- Changelog.md | 10 +++++++++ README.md | 11 ---------- examples/test.rb | 5 ++++- shard.yml | 2 +- src/Main.cr | 39 +++++++++++++++++++++++----------- src/implementations/Rb3Impl.cr | 2 ++ src/macros/FunctionCalls.cr | 34 ++++++++++++++++++++++------- src/macros/WrapAll.cr | 26 ++++++++++++++++++----- src/macros/WrapMethodIndex.cr | 19 +++++++++-------- src/macros/Wrappers.cr | 30 +++++++++++++------------- test.cr | 10 +++++++++ 11 files changed, 126 insertions(+), 62 deletions(-) diff --git a/Changelog.md b/Changelog.md index 953d037..76ec025 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,16 @@ ## Releases +### Version 0.9.1 + +#### Usability + +* Allow for a wrapped function to return nil by default + +#### Bugfixes + +* Fixed broken documentation + ### Version 0.9.0 #### Features diff --git a/README.md b/README.md index ab0d413..47f9144 100644 --- a/README.md +++ b/README.md @@ -147,17 +147,6 @@ The term 'anyoli' means 'green' in the Maasai language, thus naming 'anyolite'. ## Upcoming releases -### Version 0.9.1 - -#### Usability - -* [ ] Allow for a wrapped function to return nil by default - -#### Bugfixes - -* [ ] Fixed broken documentation -* [ ] UInt does now work as argument type - ### Version 0.10.0 This version is planned to be the last feature release before 1.0.0. diff --git a/examples/test.rb b/examples/test.rb index 3ba3a00..35b25eb 100644 --- a/examples/test.rb +++ b/examples/test.rb @@ -93,4 +93,7 @@ same_as_a = TestModule::Test.new(x: a.x) puts "Are a and b equal? #{a == b}" -puts "Are a and same_as_a equal? #{a == same_as_a}" \ No newline at end of file +puts "Are a and same_as_a equal? #{a == same_as_a}" + +puts a.uint_test(arg: 123) +puts a.noreturn_test.class \ No newline at end of file diff --git a/shard.yml b/shard.yml index e49f69f..4fb9fed 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: anyolite -version: 0.9.0 +version: 0.9.1 authors: - Hadeweka diff --git a/src/Main.cr b/src/Main.cr index a41bda0..def4cdc 100644 --- a/src/Main.cr +++ b/src/Main.cr @@ -109,8 +109,9 @@ module Anyolite # # The value *operator* will append the specified `String` # to the final name and *context* can give the function a `Path` for resolving types correctly. - macro wrap_module_function(rb_interpreter, under_module, name, proc, proc_args = nil, operator = "", context = nil) - Anyolite::Macro.wrap_module_function_with_args({{rb_interpreter}}, {{under_module}}, {{name}}, {{proc}}, {{proc_args}}, operator: {{operator}}, context: {{context}}) + # The value *return_nil* will override any returned value with `nil`. + macro wrap_module_function(rb_interpreter, under_module, name, proc, proc_args = nil, operator = "", context = nil, return_nil = false) + Anyolite::Macro.wrap_module_function_with_args({{rb_interpreter}}, {{under_module}}, {{name}}, {{proc}}, {{proc_args}}, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) end # Wraps a module function into mruby, using keyword arguments. @@ -122,8 +123,9 @@ module Anyolite # # The value *operator* will append the specified `String` # to the final name and *context* can give the function a `Path` for resolving types correctly. - macro wrap_module_function_with_keywords(rb_interpreter, under_module, name, proc, keyword_args, regular_args = nil, operator = "", context = nil) - Anyolite::Macro.wrap_module_function_with_keyword_args({{rb_interpreter}}, {{under_module}}, {{name}}, {{proc}}, {{keyword_args}}, {{regular_args}}, operator: {{operator}}, context: {{context}}) + # The value *return_nil* will override any returned value with `nil`. + macro wrap_module_function_with_keywords(rb_interpreter, under_module, name, proc, keyword_args, regular_args = nil, operator = "", context = nil, return_nil = false) + Anyolite::Macro.wrap_module_function_with_keyword_args({{rb_interpreter}}, {{under_module}}, {{name}}, {{proc}}, {{keyword_args}}, {{regular_args}}, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) end # Wraps a class method into mruby. @@ -135,8 +137,9 @@ module Anyolite # # The value *operator* will append the specified `String` # to the final name and *context* can give the function a `Path` for resolving types correctly. - macro wrap_class_method(rb_interpreter, crystal_class, name, proc, proc_args = nil, operator = "", context = nil) - Anyolite::Macro.wrap_class_method_with_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{proc_args}}, operator: {{operator}}, context: {{context}}) + # The value *return_nil* will override any returned value with `nil`. + macro wrap_class_method(rb_interpreter, crystal_class, name, proc, proc_args = nil, operator = "", context = nil, return_nil = false) + Anyolite::Macro.wrap_class_method_with_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{proc_args}}, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) end # Wraps a class method into mruby, using keyword arguments. @@ -148,8 +151,9 @@ module Anyolite # # The value *operator* will append the specified `String` # to the final name and *context* can give the function a `Path` for resolving types correctly. - macro wrap_class_method_with_keywords(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil) - Anyolite::Macro.wrap_class_method_with_keyword_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{keyword_args}}, {{regular_args}}, operator: {{operator}}, context: {{context}}) + # The value *return_nil* will override any returned value with `nil`. + macro wrap_class_method_with_keywords(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil, return_nil = false) + Anyolite::Macro.wrap_class_method_with_keyword_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{keyword_args}}, {{regular_args}}, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) end # Wraps an instance method into mruby. @@ -161,8 +165,9 @@ module Anyolite # # The value *operator* will append the specified `String` # to the final name and *context* can give the function a `Path` for resolving types correctly. - macro wrap_instance_method(rb_interpreter, crystal_class, name, proc, proc_args = nil, operator = "", context = nil) - Anyolite::Macro.wrap_instance_function_with_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{proc_args}}, operator: {{operator}}, context: {{context}}) + # The value *return_nil* will override any returned value with `nil`. + macro wrap_instance_method(rb_interpreter, crystal_class, name, proc, proc_args = nil, operator = "", context = nil, return_nil = false) + Anyolite::Macro.wrap_instance_function_with_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{proc_args}}, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) end # Wraps an instance method into mruby, using keyword arguments. @@ -174,8 +179,9 @@ module Anyolite # # The value *operator* will append the specified `String` # to the final name and *context* can give the function a `Path` for resolving types correctly. - macro wrap_instance_method_with_keywords(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil) - Anyolite::Macro.wrap_instance_function_with_keyword_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{keyword_args}}, {{regular_args}}, operator: {{operator}}, context: {{context}}) + # The value *return_nil* will override any returned value with `nil`. + macro wrap_instance_method_with_keywords(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil, return_nil = false) + Anyolite::Macro.wrap_instance_function_with_keyword_args({{rb_interpreter}}, {{crystal_class}}, {{name}}, {{proc}}, {{keyword_args}}, {{regular_args}}, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) end # Wraps a setter into mruby. @@ -300,6 +306,15 @@ module Anyolite # arguments (`-1` for all arguments). annotation WrapWithoutKeywordsClassMethod; end + # Lets the function always return `nil`. + annotation ReturnNil; end + + # Lets the instance method given as the first argument always return `nil`. + annotation ReturnNilInstanceMethod; end + + # Lets the class method given as the first argument always return `nil`. + annotation ReturnNilClassMethod; end + # Specifies the generic type names for the following class as its argument, # in form of an `Array` of their names. annotation SpecifyGenericTypes; end diff --git a/src/implementations/Rb3Impl.cr b/src/implementations/Rb3Impl.cr index 86ca14f..744a130 100644 --- a/src/implementations/Rb3Impl.cr +++ b/src/implementations/Rb3Impl.cr @@ -1 +1,3 @@ # Ruby is currently not supported, so this will do nothing + +raise("Ruby is currently not supported for implementation.") \ No newline at end of file diff --git a/src/macros/FunctionCalls.cr b/src/macros/FunctionCalls.cr index 2b444af..c1017ce 100644 --- a/src/macros/FunctionCalls.cr +++ b/src/macros/FunctionCalls.cr @@ -1,16 +1,21 @@ module Anyolite module Macro - macro call_and_return(rb, proc, regular_args, converted_args, operator = "") + macro call_and_return(rb, proc, regular_args, converted_args, operator = "", return_nil = false) {% if proc.stringify == "Anyolite::Empty" %} return_value = {{operator.id}}(*{{converted_args}}) {% else %} return_value = {{proc}}{{operator.id}}(*{{converted_args}}) {% end %} - Anyolite::RbCast.return_value({{rb}}, return_value) + + {% if return_nil %} + Anyolite::RbCast.return_nil + {% else %} + Anyolite::RbCast.return_value({{rb}}, return_value) + {% end %} end macro call_and_return_keyword_method(rb, proc, converted_regular_args, keyword_args, kw_args, operator = "", - empty_regular = false, context = nil, type_vars = nil, type_var_names = nil) + empty_regular = false, context = nil, type_vars = nil, type_var_names = nil, return_nil = false) {% if proc.stringify == "Anyolite::Empty" %} return_value = {{operator.id}}( @@ -35,10 +40,14 @@ module Anyolite {% end %} ) - Anyolite::RbCast.return_value({{rb}}, return_value) + {% if return_nil %} + Anyolite::RbCast.return_nil + {% else %} + Anyolite::RbCast.return_value({{rb}}, return_value) + {% end %} end - macro call_and_return_instance_method(rb, proc, converted_obj, converted_args, operator = "") + macro call_and_return_instance_method(rb, proc, converted_obj, converted_args, operator = "", return_nil = false) if {{converted_obj}}.is_a?(Anyolite::StructWrapper) working_content = {{converted_obj}}.content @@ -56,11 +65,16 @@ module Anyolite return_value = {{converted_obj}}.{{proc}}{{operator.id}}(*{{converted_args}}) {% end %} end - Anyolite::RbCast.return_value({{rb}}, return_value) + + {% if return_nil %} + Anyolite::RbCast.return_nil + {% else %} + Anyolite::RbCast.return_value({{rb}}, return_value) + {% end %} end macro call_and_return_keyword_instance_method(rb, proc, converted_obj, converted_regular_args, keyword_args, kw_args, operator = "", - empty_regular = false, context = nil, type_vars = nil, type_var_names = nil) + empty_regular = false, context = nil, type_vars = nil, type_var_names = nil, return_nil = false) if {{converted_obj}}.is_a?(Anyolite::StructWrapper) working_content = {{converted_obj}}.content @@ -116,7 +130,11 @@ module Anyolite end - Anyolite::RbCast.return_value({{rb}}, return_value) + {% if return_nil %} + Anyolite::RbCast.return_nil + {% else %} + Anyolite::RbCast.return_value({{rb}}, return_value) + {% end %} end end end \ No newline at end of file diff --git a/src/macros/WrapAll.cr b/src/macros/WrapAll.cr index 2d02208..eb0d35c 100644 --- a/src/macros/WrapAll.cr +++ b/src/macros/WrapAll.cr @@ -31,6 +31,9 @@ module Anyolite {% all_annotations_without_keywords_im = crystal_class.resolve.annotations(Anyolite::WrapWithoutKeywordsInstanceMethod) %} {% annotation_without_keyword_im = all_annotations_without_keywords_im.find { |element| element[0].id.stringify == method.name.stringify } %} + {% all_annotations_return_nil_im = crystal_class.resolve.annotations(Anyolite::ReturnNilInstanceMethod) %} + {% annotation_return_nil_im = all_annotations_return_nil_im.find { |element| element[0].id.stringify == method.name.stringify } %} + {% if method.annotation(Anyolite::Rename) %} {% ruby_name = method.annotation(Anyolite::Rename)[0].id %} {% elsif annotation_rename_im && method.name.stringify == annotation_rename_im[0].stringify %} @@ -57,6 +60,11 @@ module Anyolite {% without_keywords = annotation_without_keyword_im[1] ? annotation_without_keyword_im[1] : -1 %} {% end %} + {% return_nil = false %} + {% if method.annotation(Anyolite::ReturnNil) || (annotation_return_nil_im) %} + {% return_nil = true %} + {% end %} + {% puts "> Processing instance method #{crystal_class}::#{method.name} to #{ruby_name}\n--> Args: #{method.args}" if verbose %} # Ignore private and protected methods (can't be called from outside, they'd need to be wrapped for this to work) @@ -79,15 +87,15 @@ module Anyolite {% elsif method.name[-1..-1] =~ /\W/ %} {% operator = ruby_name %} - Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", operator: "{{operator}}", without_keywords: -1, context: {{context}}) + Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", operator: "{{operator}}", without_keywords: -1, context: {{context}}, return_nil: {{return_nil}}) {% how_many_times_wrapped[ruby_name.stringify] = how_many_times_wrapped[ruby_name.stringify] ? how_many_times_wrapped[ruby_name.stringify] + 1 : 1 %} # Handle constructors {% elsif method.name == "initialize" && use_enum_constructor == false %} - Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", is_constructor: true, without_keywords: {{without_keywords}}, added_keyword_args: {{added_keyword_args}}, context: {{context}}) + Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", is_constructor: true, without_keywords: {{without_keywords}}, added_keyword_args: {{added_keyword_args}}, context: {{context}}, return_nil: {{return_nil}}) {% how_many_times_wrapped[ruby_name.stringify] = how_many_times_wrapped[ruby_name.stringify] ? how_many_times_wrapped[ruby_name.stringify] + 1 : 1 %} # Handle other instance methods {% else %} - Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", without_keywords: {{without_keywords}}, added_keyword_args: {{added_keyword_args}}, context: {{context}}) + Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", without_keywords: {{without_keywords}}, added_keyword_args: {{added_keyword_args}}, context: {{context}}, return_nil: {{return_nil}}) {% how_many_times_wrapped[ruby_name.stringify] = how_many_times_wrapped[ruby_name.stringify] ? how_many_times_wrapped[ruby_name.stringify] + 1 : 1 %} {% end %} @@ -138,6 +146,9 @@ module Anyolite {% all_annotations_without_keywords_im = crystal_class.resolve.annotations(Anyolite::WrapWithoutKeywordsClassMethod) %} {% annotation_without_keyword_im = all_annotations_without_keywords_im.find { |element| element[0].id.stringify == method.name.stringify } %} + {% all_annotations_return_nil_im = crystal_class.resolve.annotations(Anyolite::ReturnNilClassMethod) %} + {% annotation_return_nil_im = all_annotations_return_nil_im.find { |element| element[0].id.stringify == method.name.stringify } %} + {% if method.annotation(Anyolite::Rename) %} {% ruby_name = method.annotation(Anyolite::Rename)[0].id %} {% elsif annotation_rename_im && method.name.stringify == annotation_rename_im[0].stringify %} @@ -164,6 +175,11 @@ module Anyolite {% without_keywords = annotation_without_keyword_im[1] ? annotation_without_keyword_im[1] : -1 %} {% end %} + {% return_nil = false %} + {% if method.annotation(Anyolite::ReturnNil) || (annotation_return_nil_im) %} + {% return_nil = true %} + {% end %} + {% puts "> Processing class method #{crystal_class}::#{method.name} to #{ruby_name}\n--> Args: #{method.args}" if verbose %} # Ignore private and protected methods (can't be called from outside, they'd need to be wrapped for this to work) @@ -184,11 +200,11 @@ module Anyolite {% elsif method.name[-1..-1] =~ /\W/ %} {% operator = ruby_name %} - Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", operator: "{{operator}}", is_class_method: true, without_keywords: -1, context: {{context}}) + Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", operator: "{{operator}}", is_class_method: true, without_keywords: -1, context: {{context}}, return_nil: {{return_nil}}) {% how_many_times_wrapped[ruby_name.stringify] = how_many_times_wrapped[ruby_name.stringify] ? how_many_times_wrapped[ruby_name.stringify] + 1 : 1 %} # Handle other class methods {% else %} - Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", is_class_method: true, without_keywords: {{without_keywords}}, added_keyword_args: {{added_keyword_args}}, context: {{context}}) + Anyolite::Macro.wrap_method_index({{rb_interpreter}}, {{crystal_class}}, {{index}}, "{{ruby_name}}", is_class_method: true, without_keywords: {{without_keywords}}, added_keyword_args: {{added_keyword_args}}, context: {{context}}, return_nil: {{return_nil}}) {% how_many_times_wrapped[ruby_name.stringify] = how_many_times_wrapped[ruby_name.stringify] ? how_many_times_wrapped[ruby_name.stringify] + 1 : 1 %} {% end %} diff --git a/src/macros/WrapMethodIndex.cr b/src/macros/WrapMethodIndex.cr index 2d8dfec..d321142 100644 --- a/src/macros/WrapMethodIndex.cr +++ b/src/macros/WrapMethodIndex.cr @@ -4,7 +4,7 @@ module Anyolite is_constructor = false, is_class_method = false, operator = "", cut_name = nil, without_keywords = false, added_keyword_args = nil, - context = nil) + context = nil, return_nil = false) {% if is_class_method %} {% method = crystal_class.resolve.class.methods[method_index] %} @@ -42,11 +42,12 @@ module Anyolite {% if final_arg_array.empty? %} {% if is_class_method %} - Anyolite.wrap_class_method({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, operator: {{final_operator}}, context: {{context}}) + Anyolite.wrap_class_method({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% elsif is_constructor %} + # Do not ever let a constructor return nil (for now) Anyolite.wrap_constructor({{rb_interpreter}}, {{crystal_class}}, context: {{context}}) {% else %} - Anyolite.wrap_instance_method({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, operator: {{final_operator}}, context: {{context}}) + Anyolite.wrap_instance_method({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% end %} # A complicated check, but it is more stable than simply checking for colons @@ -66,36 +67,36 @@ module Anyolite {% if keyword_arg_partition %} {% if is_class_method %} Anyolite.wrap_class_method_with_keywords({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, - {{keyword_arg_partition}}, regular_args: {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}) + {{keyword_arg_partition}}, regular_args: {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% elsif is_constructor %} Anyolite.wrap_constructor_with_keywords({{rb_interpreter}}, {{crystal_class}}, {{keyword_arg_partition}}, regular_args: {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}) {% else %} Anyolite.wrap_instance_method_with_keywords({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, - {{keyword_arg_partition}}, regular_args: {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}) + {{keyword_arg_partition}}, regular_args: {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% end %} {% else %} {% if is_class_method %} Anyolite.wrap_class_method({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, - {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}) + {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% elsif is_constructor %} Anyolite.wrap_constructor({{rb_interpreter}}, {{crystal_class}}, {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}) {% else %} Anyolite.wrap_instance_method({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, - {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}) + {{regular_arg_partition}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% end %} {% end %} {% else %} {% if is_class_method %} Anyolite.wrap_class_method_with_keywords({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, - {{final_arg_array}}, operator: {{final_operator}}, context: {{context}}) + {{final_arg_array}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% elsif is_constructor %} Anyolite.wrap_constructor_with_keywords({{rb_interpreter}}, {{crystal_class}}, {{final_arg_array}}, operator: {{final_operator}}, context: {{context}}) {% else %} Anyolite.wrap_instance_method_with_keywords({{rb_interpreter}}, {{crystal_class}}, {{ruby_name}}, {{final_method_name}}, - {{final_arg_array}}, operator: {{final_operator}}, context: {{context}}) + {{final_arg_array}}, operator: {{final_operator}}, context: {{context}}, return_nil: {{return_nil}}) {% end %} {% end %} diff --git a/src/macros/Wrappers.cr b/src/macros/Wrappers.cr index 3e36ff3..ab0cef4 100644 --- a/src/macros/Wrappers.cr +++ b/src/macros/Wrappers.cr @@ -1,6 +1,6 @@ module Anyolite module Macro - macro wrap_module_function_with_args(rb_interpreter, under_module, name, proc, regular_args = nil, context = nil) + macro wrap_module_function_with_args(rb_interpreter, under_module, name, proc, regular_args = nil, context = nil, return_nil = nil) {% if regular_args.is_a?(ArrayLiteral) %} {% regular_arg_array = regular_args %} {% elsif regular_args == nil %} @@ -17,13 +17,13 @@ module Anyolite wrapped_method = Anyolite::RbCore::RbFunc.new do |rb, obj| converted_args = Anyolite::Macro.get_converted_args(rb, {{proc_arg_array}}, context: {{context}}) - Anyolite::Macro.call_and_return(rb, {{proc}}, {{proc_arg_array}}, converted_args) + Anyolite::Macro.call_and_return(rb, {{proc}}, {{proc_arg_array}}, converted_args, return_nil: {{return_nil}}) end {{rb_interpreter}}.define_module_function({{name}}, Anyolite::RbClassCache.get({{under_module}}), wrapped_method) end - macro wrap_module_function_with_keyword_args(rb_interpreter, under_module, name, proc, keyword_args, regular_args = nil, operator = "", context = nil) + macro wrap_module_function_with_keyword_args(rb_interpreter, under_module, name, proc, keyword_args, regular_args = nil, operator = "", context = nil, return_nil = nil) {% if regular_args.is_a?(ArrayLiteral) %} {% regular_arg_array = regular_args %} {% elsif regular_args == nil %} @@ -42,16 +42,16 @@ module Anyolite converted_regular_args = Anyolite::Macro.convert_args(rb, regular_arg_tuple, {{regular_arg_array}}, context: {{context}}) {% if !regular_arg_array || regular_arg_array.size == 0 %} - Anyolite::Macro.call_and_return_keyword_method(rb, {{proc}}, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, empty_regular: true, context: {{context}}) + Anyolite::Macro.call_and_return_keyword_method(rb, {{proc}}, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, empty_regular: true, context: {{context}}, return_nil: {{return_nil}}) {% else %} - Anyolite::Macro.call_and_return_keyword_method(rb, {{proc}}, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, context: {{context}}) + Anyolite::Macro.call_and_return_keyword_method(rb, {{proc}}, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, context: {{context}}, return_nil: {{return_nil}}) {% end %} end {{rb_interpreter}}.define_module_function({{name}}, Anyolite::RbClassCache.get({{under_module}}), wrapped_method) end - macro wrap_class_method_with_args(rb_interpreter, crystal_class, name, proc, regular_args = nil, operator = "", context = nil) + macro wrap_class_method_with_args(rb_interpreter, crystal_class, name, proc, regular_args = nil, operator = "", context = nil, return_nil = nil) {% if regular_args.is_a?(ArrayLiteral) %} {% regular_arg_array = regular_args %} {% elsif regular_args == nil %} @@ -66,13 +66,13 @@ module Anyolite wrapped_method = Anyolite::RbCore::RbFunc.new do |rb, obj| converted_args = Anyolite::Macro.get_converted_args(rb, {{regular_arg_array}}, context: {{context}}) - Anyolite::Macro.call_and_return(rb, {{proc}}, {{regular_arg_array}}, converted_args, operator: {{operator}}) + Anyolite::Macro.call_and_return(rb, {{proc}}, {{regular_arg_array}}, converted_args, operator: {{operator}}, return_nil: {{return_nil}}) end {{rb_interpreter}}.define_class_method({{name}}, Anyolite::RbClassCache.get({{crystal_class}}), wrapped_method) end - macro wrap_class_method_with_keyword_args(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil) + macro wrap_class_method_with_keyword_args(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil, return_nil = nil) {% if regular_args.is_a?(ArrayLiteral) %} {% regular_arg_array = regular_args %} {% elsif regular_args == nil %} @@ -96,17 +96,17 @@ module Anyolite {% if !regular_arg_array || regular_arg_array.size == 0 %} Anyolite::Macro.call_and_return_keyword_method(rb, {{proc}}, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, - empty_regular: true, context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}) + empty_regular: true, context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}, return_nil: {{return_nil}}) {% else %} Anyolite::Macro.call_and_return_keyword_method(rb, {{proc}}, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, - context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}) + context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}), return_nil: {{return_nil}} {% end %} end {{rb_interpreter}}.define_class_method({{name}}, Anyolite::RbClassCache.get({{crystal_class}}), wrapped_method) end - macro wrap_instance_function_with_args(rb_interpreter, crystal_class, name, proc, regular_args = nil, operator = "", context = nil) + macro wrap_instance_function_with_args(rb_interpreter, crystal_class, name, proc, regular_args = nil, operator = "", context = nil, return_nil = nil) {% if regular_args.is_a?(ArrayLiteral) %} {% regular_arg_array = regular_args %} {% elsif regular_args == nil %} @@ -128,13 +128,13 @@ module Anyolite converted_obj = Anyolite::Macro.convert_from_ruby_object(rb, obj, {{crystal_class}}).value end - Anyolite::Macro.call_and_return_instance_method(rb, {{proc}}, converted_obj, converted_args, operator: {{operator}}) + Anyolite::Macro.call_and_return_instance_method(rb, {{proc}}, converted_obj, converted_args, operator: {{operator}}, return_nil: {{return_nil}}) end {{rb_interpreter}}.define_method({{name}}, Anyolite::RbClassCache.get({{crystal_class}}), wrapped_method) end - macro wrap_instance_function_with_keyword_args(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil) + macro wrap_instance_function_with_keyword_args(rb_interpreter, crystal_class, name, proc, keyword_args, regular_args = nil, operator = "", context = nil, return_nil = nil) {% if regular_args.is_a?(ArrayLiteral) %} {% regular_arg_array = regular_args %} {% elsif regular_args == nil %} @@ -164,10 +164,10 @@ module Anyolite {% if !regular_arg_array || regular_arg_array.size == 0 %} Anyolite::Macro.call_and_return_keyword_instance_method(rb, {{proc}}, converted_obj, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, - empty_regular: true, context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}) + empty_regular: true, context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}, return_nil: {{return_nil}}) {% else %} Anyolite::Macro.call_and_return_keyword_instance_method(rb, {{proc}}, converted_obj, converted_regular_args, {{keyword_args}}, kw_args, operator: {{operator}}, - context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}) + context: {{context}}, type_vars: {{type_vars}}, type_var_names: {{type_var_names}}, return_nil: {{return_nil}}) {% end %} end diff --git a/test.cr b/test.cr index b788686..ee40abb 100644 --- a/test.cr +++ b/test.cr @@ -164,6 +164,16 @@ module SomeModule ret = self + other end + def uint_test(arg : UInt8) + arg.to_s + end + + @[Anyolite::ReturnNil] + def noreturn_test + puts "This will still be executed." + [1] + end + def overload_test(arg : Int32 | String | Bool | Nil | Float32 | Test | TestEnum | GenericTest(Int32, Int32) = "Default String") if arg.is_a?(Test) puts "Test: A test object with x = #{arg.x}"