/* * Copyright 2019 by its authors. See AUTHORS. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef EOLIAN_MONO_PARAMETER_HH #define EOLIAN_MONO_PARAMETER_HH #include "grammar/generator.hpp" #include "grammar/klass_def.hpp" #include "grammar/attribute_reorder.hpp" #include "grammar/case.hpp" #include "helpers.hh" #include "marshall_type.hh" #include "type.hh" #include "using_decl.hh" #include "name_helpers.hh" using namespace eolian_mono::name_helpers; namespace eolian_mono { struct parameter_generator; struct marshall_parameter_generator; struct argument_generator; struct argument_invocation_generator; struct native_argument_invocation_generator; struct native_convert_in_variable_generator; struct convert_in_variable_generator; struct native_convert_out_variable_generator; struct convert_out_variable_generator; struct convert_out_assign_generator; struct native_convert_in_ptr_assign_generator; struct convert_in_ptr_assign_generator; struct native_convert_out_assign_parameterized; struct native_convert_out_assign_generator; struct convert_return_generator; struct convert_return_variable_generator; struct native_convert_return_generator; struct native_convert_return_parameterized; struct native_convert_return_variable_generator; struct convert_function_pointer_generator; struct native_convert_function_pointer_generator; struct constructor_param_generator; struct constructor_invocation_generator; struct constructor_parameter_name_generator; struct constructor_parameter_name_paremeterized; } namespace efl { namespace eolian { namespace grammar { template <> struct is_eager_generator< ::eolian_mono::parameter_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::parameter_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::parameter_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::marshall_parameter_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::marshall_parameter_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::marshall_parameter_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::argument_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::argument_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::argument_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::argument_invocation_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::argument_invocation_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::argument_invocation_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_argument_invocation_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_argument_invocation_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_argument_invocation_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_in_variable_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_in_variable_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_in_variable_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_in_variable_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_in_variable_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_in_variable_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_out_variable_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_out_variable_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_out_variable_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_out_variable_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_out_variable_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_out_variable_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_out_assign_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_out_assign_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_out_assign_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_in_ptr_assign_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_in_ptr_assign_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_in_ptr_assign_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_in_ptr_assign_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_in_ptr_assign_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_in_ptr_assign_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_return_variable_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_return_variable_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_return_variable_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_return_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_return_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_return_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_out_assign_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_out_assign_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_out_assign_parameterized> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_out_assign_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_return_variable_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_return_variable_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_return_variable_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_return_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_return_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_return_parameterized> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_return_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::convert_function_pointer_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::convert_function_pointer_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::convert_function_pointer_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::native_convert_function_pointer_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_convert_function_pointer_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::native_convert_function_pointer_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::constructor_param_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::constructor_param_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::constructor_param_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::constructor_invocation_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::constructor_invocation_generator> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::constructor_invocation_generator> : std::integral_constant {}; } template <> struct is_eager_generator< ::eolian_mono::constructor_parameter_name_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::constructor_parameter_name_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::constructor_parameter_name_paremeterized> : std::true_type {}; namespace type_traits { template <> struct attributes_needed< ::eolian_mono::constructor_parameter_name_generator> : std::integral_constant {}; } } } } namespace eolian_mono { namespace attributes = efl::eolian::grammar::attributes; // Helper function to query parameter attributes const static bool WANT_OWN = true; const static bool WANT_OUT = true; inline bool param_is_acceptable(attributes::parameter_def const ¶m, std::string c_type, bool want_own, bool want_out) { return (param.type.c_type == c_type) && ((param.direction != attributes::parameter_direction::in) == want_out) && (param.type.has_own == want_own); } inline bool param_should_use_out_var(attributes::parameter_def const& param, bool native) { if (param.direction == attributes::parameter_direction::in) return false; if ((native && param_is_acceptable(param, "const char *", !WANT_OWN, WANT_OUT)) || (native && param_is_acceptable(param, "Eina_Stringshare *", !WANT_OWN, WANT_OUT)) || param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Value", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Value", !WANT_OWN, WANT_OUT) ) return true; auto regular = efl::eina::get(¶m.type.original_type); if (helpers::need_struct_conversion(regular)) return true; if (param.type.is_ptr && helpers::need_pointer_conversion(regular)) return true; return false; } inline bool param_should_use_in_var(attributes::parameter_def const& param, bool /*native*/) { if (param.direction != attributes::parameter_direction::in) return false; if (param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Array *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Array *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_List *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_List *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_List *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_List *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", !WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Value", WANT_OWN, !WANT_OUT) || param_is_acceptable(param, "Eina_Value", !WANT_OWN, !WANT_OUT) ) return true; auto regular = efl::eina::get(¶m.type.original_type); if (helpers::need_struct_conversion(regular)) return true; if (param.type.is_ptr && helpers::need_pointer_conversion(regular)) return true; return false; } inline std::string out_variable_name(std::string const& param_name) { return "_out_" + escape_keyword(param_name); } inline std::string in_variable_name(std::string const& param_name) { return "_in_" + escape_keyword(param_name); } inline std::string direction_modifier(attributes::parameter_def const& param) { if (param.direction == attributes::parameter_direction::inout) { return "ref "; } else if (param.direction != attributes::parameter_direction::in) { if (param.type.c_type == "Eina_Slice" || param.type.c_type == "Eina_Rw_Slice") return "ref "; else return "out "; } else if (param.direction == attributes::parameter_direction::in && param.type.is_ptr) { auto regular = efl::eina::get(¶m.type.original_type); if (helpers::need_struct_conversion(regular)) return "ref "; // Don't add ref on Marshal if it is ptr } return ""; } std::string marshall_direction_modifier(attributes::parameter_def const& param) { if (param.direction == attributes::parameter_direction::in && param.type.is_ptr) { auto regular = efl::eina::get(¶m.type.original_type); if (helpers::need_struct_conversion(regular) && param.type.has_own) return " "; // Don't add ref on Marshal if it is ptr } return direction_modifier(param); } struct is_fp_visitor { typedef is_fp_visitor visitor_type; typedef bool result_type; bool operator()(grammar::attributes::regular_type_def const &type) const { return type.is_function_ptr(); } template bool operator()(T const &) const { return false; } }; struct type_name_visitor { typedef type_name_visitor visitor_type; typedef std::string result_type; std::string operator()(grammar::attributes::regular_type_def const &type) const { return name_helpers::type_full_eolian_name(type); } template std::string operator()(T const &) const { return ""; } }; struct parameter_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { std::string param_name = escape_keyword(param.param_name); return as_generator( direction_modifier(param) << type << " " << string ).generate(sink, std::make_tuple(param, param_name), context); } } const parameter {}; struct marshall_parameter_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { std::string param_name = escape_keyword(param.param_name); if (!param.type.original_type.visit(is_fp_visitor{})) return as_generator( marshall_direction_modifier(param) << marshall_type << " " << string ).generate(sink, std::make_tuple(param, param_name), context); return as_generator( "IntPtr " << param_name << "_data, " << type << "Internal " << param_name << ", Eina.Callbacks.EinaFreeCb " << param_name << "_free_cb" ).generate(sink, param, context); } } const marshall_parameter {}; // FIXME This seems to be used only in the else branch of the native function definition. Is it really needed? struct argument_generator { bool generate_direction; argument_generator () : generate_direction(true) {} argument_generator (bool r) : generate_direction(r) {} template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { std::string param_name = escape_keyword(param.param_name); std::string direction = marshall_direction_modifier(param); if (generate_direction && !param.type.original_type.visit(is_fp_visitor{})) return as_generator(direction << param_name).generate(sink, attributes::unused, context); if (!generate_direction && !param.type.original_type.visit(is_fp_visitor{})) return as_generator(param_name).generate(sink, attributes::unused, context); else return as_generator (param_name << "_data, " << param_name << ", " << param_name << "_free_cb" ).generate(sink, attributes::unused, context); } argument_generator operator ()(bool r) const { return {r}; } } const argument {}; struct native_argument_invocation_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { std::string arg = direction_modifier(param); if (param_should_use_out_var(param, true)) arg += out_variable_name(param.param_name); else if (param_should_use_in_var(param, true)) arg += in_variable_name(param.param_name); else if (param.type.original_type.visit(is_fp_visitor{})) { arg += escape_keyword(param.param_name) + "_wrapper.ManagedCb"; } else // FIXME Wrap data and C function pointers into some kind of structure. arg += escape_keyword(param.param_name); return as_generator(arg).generate(sink, attributes::unused, context); } } const native_argument_invocation {}; // Generates the correct parameter name when invoking a function struct argument_invocation_generator { constexpr argument_invocation_generator(bool conversion_vars) : use_conversion_vars(conversion_vars) {} template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { std::string arg = marshall_direction_modifier(param); if (use_conversion_vars && param_should_use_out_var(param, false)) arg += out_variable_name(param.param_name); else if (use_conversion_vars && param_should_use_in_var(param, false)) arg += in_variable_name(param.param_name); else if (param.type.original_type.visit(is_fp_visitor{})) { std::string param_name = escape_keyword(param.param_name); return as_generator("GCHandle.ToIntPtr(" << param_name << "_handle), " << type << "Wrapper.Cb, Efl.Eo.Globals.free_gchandle") .generate(sink, param.type, context); } else arg += escape_keyword(param.param_name); return as_generator(arg).generate(sink, attributes::unused, context); } bool const use_conversion_vars; } const argument_invocation {true}; argument_invocation_generator const argument_invocation_no_conversion {false}; struct native_convert_in_variable_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction != attributes::parameter_direction::in) return true; auto regular = efl::eina::get(¶m.type.original_type); if (param.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(param, regular)) { return as_generator( "var " << string << " = Eina.PrimitiveConversion.PointerToManaged<" << type << ">(" << escape_keyword(param.param_name) << ");\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.type), context); } else if (helpers::need_struct_conversion(regular)) { return as_generator( type << " " << string << " = " << escape_keyword(param.param_name) << ";\n" ).generate(sink, std::make_tuple(param.type, in_variable_name(param.param_name)), context); } else if (param.type.c_type == "Eina_Binbuf *" || param.type.c_type == "const Eina_Binbuf *") { return as_generator( "var " << string << " = new Eina.Binbuf(" << escape_keyword(param.param_name) << ", " << (param.type.has_own ? "true" : "false") << ");\n" ).generate(sink, in_variable_name(param.param_name), context); } else if (param.type.c_type == "Eina_Hash *" || param.type.c_type == "const Eina_Hash *") { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex || complex->subtypes.size() != 2) return false; return as_generator( "var " << string << " = new " << type << "(" << escape_keyword(param.param_name) << ", " << (param.type.has_own ? "true" : "false") << ", " << (complex->subtypes.front().has_own ? "true" : "false") << ", " << (complex->subtypes.back().has_own ? "true" : "false") << ");\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.type), context); } else if (param.type.c_type == "Eina_Array *" || param.type.c_type == "const Eina_Array *" || param.type.c_type == "Eina_List *" || param.type.c_type == "const Eina_List *" ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( "var " << string << " = new " << type << "(" << escape_keyword(param.param_name) << ", " << (param.type.has_own ? "true" : "false") << ", " << (complex->subtypes.front().is_value_type || complex->subtypes.front().has_own ? "true" : "false") << ");\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.type), context); } else if (param.type.c_type == "Eina_Iterator *" || param.type.c_type == "const Eina_Iterator *") { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( "var " << string << " = Efl.Eo.Globals.IteratorTo" << type << "(" << escape_keyword(param.param_name) << ");\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.type), context); } else if (param.type.c_type == "Eina_Accessor *" || param.type.c_type == "const Eina_Accessor *") { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( "var " << string << " = Efl.Eo.Globals.AccessorTo" << type << "(" << escape_keyword(param.param_name) << ");\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.type), context); } else if (param.type.c_type == "Eina_Value") { return as_generator( "var " << string << " = new " << type << "(" << string << ");\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.type, param.param_name), context); } return true; } } const native_convert_in_variable {}; struct convert_in_variable_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction != attributes::parameter_direction::in) return true; auto regular = efl::eina::get(¶m.type.original_type); if (param.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(param, regular)) { return as_generator( "var " << string << " = Eina.PrimitiveConversion.ManagedToPointerAlloc(" << escape_keyword(param.param_name) << ");\n" ).generate(sink, in_variable_name(param.param_name), context); } else if (helpers::need_struct_conversion(regular)) { return as_generator( marshall_type << " " << string << " = " << escape_keyword(param.param_name) << ";\n" ).generate(sink, std::make_tuple(param.type, in_variable_name(param.param_name)), context); } else if (param.type.c_type == "Eina_Binbuf *" || param.type.c_type == "const Eina_Binbuf *") { auto var_name = in_variable_name(param.param_name); if (!as_generator( "var " << string << " = " << escape_keyword(param.param_name) << ".Handle;\n" ).generate(sink, var_name, context)) return false; if (param.type.has_own) { return as_generator( escape_keyword(param.param_name) << ".Own = false;\n" ).generate(sink, attributes::unused, context); } } else if (param.type.c_type == "Eina_Hash *" || param.type.c_type == "const Eina_Hash *") { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex || complex->subtypes.size() != 2) return false; auto var_name = in_variable_name(param.param_name); if (!as_generator( "var " << string << " = " << escape_keyword(param.param_name) << ".Handle;\n" ).generate(sink, var_name, context)) return false; if (param.type.has_own && !as_generator( escape_keyword(param.param_name) << ".SetOwn(false);\n" ).generate(sink, attributes::unused, context)) return false; if (complex->subtypes.front().has_own && !as_generator( escape_keyword(param.param_name) << ".SetOwnKey(false);\n" ).generate(sink, attributes::unused, context)) return false; if (complex->subtypes.back().has_own && !as_generator( escape_keyword(param.param_name) << ".SetOwnValue(false);\n" << escape_keyword(param.param_name) << ".UnSetFreeCb();\n" ).generate(sink, attributes::unused, context)) return false; } else if (param.type.c_type == "Eina_Array *" || param.type.c_type == "const Eina_Array *" || param.type.c_type == "Eina_List *" || param.type.c_type == "const Eina_List *" ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; auto var_name = in_variable_name(param.param_name); if (!as_generator( "var " << string << " = " << escape_keyword(param.param_name) << ".Handle;\n" ).generate(sink, var_name, context)) return false; if (param.type.has_own && !as_generator( escape_keyword(param.param_name) << ".Own = false;\n" ).generate(sink, attributes::unused, context)) return false; if (!complex->subtypes.front().is_value_type && complex->subtypes.front().has_own && !as_generator( escape_keyword(param.param_name) << ".OwnContent = false;\n" ).generate(sink, attributes::unused, context)) return false; } else if (param.type.c_type == "Eina_Iterator *" || param.type.c_type == "const Eina_Iterator *") { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; auto var_name = in_variable_name(param.param_name); if (!as_generator( "var " << string << " = " << "Efl.Eo.Globals.IEnumerableToIterator(" << escape_keyword(param.param_name) << ");\n" ).generate(sink, var_name, context)) return false; } else if (param.type.c_type == "Eina_Accessor *" || param.type.c_type == "const Eina_Accessor *") { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; auto var_name = in_variable_name(param.param_name); if (!as_generator( "var " << string << " = Efl.Eo.Globals.IEnumerableToAccessor(" << escape_keyword(param.param_name) << ", " << (param.type.has_own ? "true" : "false")<< ");\n" ).generate(sink, var_name, context)) return false; } else if (param.type.c_type == "Eina_Value") { return as_generator( "var " << string << " = " << string << ".GetNative();\n" ).generate(sink, std::make_tuple(in_variable_name(param.param_name), param.param_name), context); } return true; } } const convert_in_variable {}; /* Some types require an intermediate variable to be filled as out parameter in the marshalled function */ struct convert_out_variable_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction == attributes::parameter_direction::in) return true; auto regular = efl::eina::get(¶m.type.original_type); if (param.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(regular)) { return as_generator( "System.IntPtr " << string << " = System.IntPtr.Zero;\n" ).generate(sink, out_variable_name(param.param_name), context); } else if (helpers::need_struct_conversion(regular)) { return as_generator( "var " << string << " = new " << marshall_type << "();\n" ).generate(sink, std::make_tuple(out_variable_name(param.param_name), param), context); } else if (param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", !WANT_OWN, WANT_OUT) ) { return as_generator( "System.IntPtr " << string << " = System.IntPtr.Zero;\n" ).generate(sink, out_variable_name(param.param_name), context); } else if (param_is_acceptable(param, "Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", !WANT_OWN, WANT_OUT) ) { return as_generator( "System.IntPtr " << string << " = System.IntPtr.Zero;\n" ).generate(sink, out_variable_name(param.param_name), context); } else if (param_is_acceptable(param, "Eina_Value", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Value", !WANT_OWN, WANT_OUT)) { return as_generator( marshall_type << " " << string << ";\n" ).generate(sink, std::make_tuple(param.type, out_variable_name(param.param_name)), context); } return true; } } const convert_out_variable {}; struct native_convert_out_variable_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction == attributes::parameter_direction::in) return true; auto regular = efl::eina::get(¶m.type.original_type); if (param.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(regular)) { return as_generator( type << " " << string << " = default(" << type << ");\n" ).generate(sink, std::make_tuple(param, out_variable_name(param.param_name), param), context); } else if (helpers::need_struct_conversion(regular) || param_is_acceptable(param, "const char *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Stringshare *", !WANT_OWN, WANT_OUT)) { return as_generator( type << " " << string << " = default(" << type << ");\n" ).generate(sink, std::make_tuple(param, out_variable_name(param.param_name), param), context); } else if (param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", !WANT_OWN, WANT_OUT) ) { return as_generator( "Eina.Binbuf " << string << " = default(Eina.Binbuf);\n" ).generate(sink, out_variable_name(param.param_name), context); } else if (param_is_acceptable(param, "Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( type << " " << string << " = default(" << type << ");\n" ).generate(sink, std::make_tuple(param.type, out_variable_name(param.param_name), param.type), context); } else if (param_is_acceptable(param, "Eina_Value", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Value", !WANT_OWN, WANT_OUT)) { return as_generator( string << " = default(" << marshall_type << ");\n" << type << " " << string << " = null;\n" ).generate(sink, std::make_tuple(param.param_name, param, param, out_variable_name(param.param_name)), context); } else if (param.direction == attributes::parameter_direction::out) { // Assign a default value to the out variable in case we end up in the catch clause. return as_generator( string << " = default(" << type << ");" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param), context); } return true; } } const native_convert_out_variable {}; /* Assign the Managed out variables from the marshalled intermediate ones if needed. */ struct convert_out_assign_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction == attributes::parameter_direction::in) return true; auto regular = efl::eina::get(¶m.type.original_type); if (param.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion_in_return(param.type, param.direction)) { bool ret = as_generator( string << " = Eina.PrimitiveConversion.PointerToManaged<" << type << ">(" << out_variable_name(param.param_name) << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type), context); if (param.type.has_own) ret = ret && as_generator(scope_tab << scope_tab << "Marshal.FreeHGlobal(" << out_variable_name(param.param_name) << ");\n" ).generate(sink, attributes::unused, context); return ret; } else if (helpers::need_struct_conversion(regular)) { return as_generator( string << " = " << out_variable_name(param.param_name) << ";\n" ).generate(sink, escape_keyword(param.param_name), context); } else if (param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", !WANT_OWN, WANT_OUT) ) { return as_generator( string << " = new Eina.Binbuf(" << string << ", " << (param.type.has_own ? "true" : "false") << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex || complex->subtypes.size() != 2) return false; return as_generator( string << " = new " << type << "(" << string << ", " << (param.type.has_own ? "true" : "false") << ", " << (complex->subtypes.front().has_own ? "true" : "false") << ", " << (complex->subtypes.back().has_own ? "true" : "false") << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type, out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( string << " = new " << type << "(" << string << ", " << (param.type.has_own ? "true" : "false") << ", " << (complex->subtypes.front().is_value_type || complex->subtypes.front().has_own ? "true" : "false") << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type, out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( string << " = Efl.Eo.Globals.AccessorTo" << type << "(" << string << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type, out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; return as_generator( string << " = Efl.Eo.Globals.IteratorTo" << type << "(" << string << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type, out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Value", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Value", !WANT_OWN, WANT_OUT)) { return as_generator( string << " = new " << type << "(" << string << ");\n" ).generate(sink, std::make_tuple(param.param_name, param.type, out_variable_name(param.param_name)), context); } return true; } } const convert_out_assign {}; struct native_convert_in_ptr_assign_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { auto regular = efl::eina::get(¶m.type.original_type); if (param_should_use_in_var(param, true) && param.type.is_ptr && !param.type.has_own && helpers::need_struct_conversion(regular)) { return as_generator( string << " = " << in_variable_name(param.param_name) << ";\n" ).generate(sink, escape_keyword(param.param_name), context); } return true; } } const native_convert_in_ptr_assign {}; struct convert_in_ptr_assign_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { auto regular = efl::eina::get(¶m.type.original_type); if (param_should_use_in_var(param, true) && param.type.is_ptr && !param.type.has_own && helpers::need_struct_conversion(regular)) { return as_generator( string << " = " << in_variable_name(param.param_name) << ";\n" ).generate(sink, escape_keyword(param.param_name), context); } return true; } } const convert_in_ptr_assign {}; struct convert_return_variable_generator { template bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const { if (ret_type.c_type != "void") return as_generator("var _ret_var = ").generate(sink, attributes::unused, context); return true; } } const convert_return_variable {}; /* Converts the intermediate return variable to the proper API type */ struct convert_return_generator { template bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const { auto regular = efl::eina::get(&ret_type.original_type); if (ret_type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion_in_return(ret_type, attributes::parameter_direction::unknown)) { return as_generator( "var __ret_tmp = Eina.PrimitiveConversion.PointerToManaged<" << type << ">(_ret_var);\n" << scope_tab << scope_tab << (ret_type.has_own ? ("Marshal.FreeHGlobal(_ret_var);\n"): "\n") << scope_tab << scope_tab << "return __ret_tmp;\n" ).generate(sink, ret_type, context); } else if (helpers::need_struct_conversion(regular)) { return as_generator( "return _ret_var;" ).generate(sink, nullptr, context); } else if (ret_type.c_type == "Eina_Binbuf *" || ret_type.c_type == "const Eina_Binbuf *") { if (!as_generator("var _binbuf_ret = new Eina.Binbuf(_ret_var, " << std::string{ret_type.has_own ? "true" : "false"} << ");\n" << scope_tab << scope_tab << "return _binbuf_ret;\n") .generate(sink, attributes::unused, context)) return false; } else if (ret_type.c_type == "Eina_Hash *" || ret_type.c_type == "const Eina_Hash *") { attributes::complex_type_def const* complex = efl::eina::get(&ret_type.original_type); if (!complex || complex->subtypes.size() != 2) return false; if (!as_generator("return new " << type << "(_ret_var, " << std::string{ret_type.has_own ? "true" : "false"} << ", " << (complex->subtypes.front().has_own ? "true" : "false") << ", " << (complex->subtypes.back().has_own ? "true" : "false") << ");\n") .generate(sink, ret_type, context)) return false; } else if (ret_type.c_type == "Eina_Array *" || ret_type.c_type == "const Eina_Array *" || ret_type.c_type == "Eina_List *" || ret_type.c_type == "const Eina_List *" ) { attributes::complex_type_def const* complex = efl::eina::get(&ret_type.original_type); if (!complex) return false; if (!as_generator("return new " << type << "(_ret_var, " << std::string{ret_type.has_own ? "true" : "false"} << ", " << (complex->subtypes.front().is_value_type || complex->subtypes.front().has_own ? "true" : "false") << ");\n") .generate(sink, ret_type, context)) return false; } else if (ret_type.c_type == "Eina_Accessor *" || ret_type.c_type == "const Eina_Accessor *") { attributes::complex_type_def const* complex = efl::eina::get(&ret_type.original_type); if (!complex) return false; if (!as_generator("return Efl.Eo.Globals.AccessorTo" << type << "(_ret_var);") .generate(sink, ret_type, context)) return false; } else if (ret_type.c_type == "Eina_Iterator *" || ret_type.c_type == "const Eina_Iterator *") { attributes::complex_type_def const* complex = efl::eina::get(&ret_type.original_type); if (!complex) return false; if (!as_generator("return Efl.Eo.Globals.IteratorTo" << type << "(_ret_var);") .generate(sink, ret_type, context)) return false; } else if (ret_type.c_type != "void") { return as_generator("return _ret_var;").generate(sink, ret_type, context); } return true; } } const convert_return {}; // Native (virtual wrappers) generators struct native_convert_out_assign_generator { attributes::klass_def const* klass; template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "native_convert_out_assign_generator: " << param.param_name << std::endl; if (param.direction == attributes::parameter_direction::in) return true; auto regular = efl::eina::get(¶m.type.original_type); if (param.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion_in_return(param.type, param.direction)) { return as_generator( string << " = Eina.PrimitiveConversion.ManagedToPointerAlloc(" << string << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), out_variable_name(param.param_name)), context); } else if (helpers::need_struct_conversion(regular)) { return as_generator( string << " = " << string << ";\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Stringshare *", !WANT_OWN, WANT_OUT)) { if (klass == nullptr) { EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) << "Null class found when trying to assign out stringshare from native wrapper." << std::endl; return false; } return as_generator( string << "= " << string << ";\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "const char *", !WANT_OWN, WANT_OUT)) { if (klass == nullptr) { EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) << "Null class found when trying to assign out string from native wrapper." << std::endl; return false; } return as_generator( string << " = " << string << ";\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), out_variable_name(param.param_name)), context); } else if (param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Binbuf *", !WANT_OWN, WANT_OUT) ) { if (!as_generator( string << " = " << string << ".Handle;\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), out_variable_name(param.param_name)), context)) return false; if (param.type.has_own) return as_generator( string << ".Own = false;\n" ).generate(sink, out_variable_name(param.param_name), context); } else if (param_is_acceptable(param, "Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Hash *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Hash *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex || complex->subtypes.size() != 2) return false; auto outvar = out_variable_name(param.param_name); if (!as_generator( string << " = " << string << ".Handle;\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), outvar), context)) return false; if (param.type.has_own && !as_generator( string << ".SetOwn(false);\n" ).generate(sink, outvar, context)) return false; if (complex->subtypes.front().has_own && !as_generator( string << ".SetOwnKey(false);\n" ).generate(sink, outvar, context)) return false; if (complex->subtypes.back().has_own && !as_generator( string << ".SetOwnValue(false);\n" << string << ".UnSetFreeCb();\n" ).generate(sink, std::make_tuple(outvar, outvar), context)) return false; } else if (param_is_acceptable(param, "Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Array *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_List *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_List *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; auto outvar = out_variable_name(param.param_name); if (!as_generator( string << " = " << string << ".Handle;\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), outvar), context)) return false; if (param.type.has_own && !as_generator( string << ".Own = false;\n" ).generate(sink, outvar, context)) return false; // Iterators and Accessors can't own their content. if (param.type.c_type == "Eina_Iterator *" || param.type.c_type == "const Eina_Iterator *" || param.type.c_type == "Eina_Accessor *" || param.type.c_type == "const Eina_Accessor *" ) return true; if (!complex->subtypes.front().is_value_type && complex->subtypes.front().has_own && !as_generator( string << ".OwnContent = false;\n" ).generate(sink, outvar, context)) return false; } else if (param_is_acceptable(param, "Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Accessor *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Accessor *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; auto outvar = out_variable_name(param.param_name); if (!as_generator( string << " = Efl.Eo.Globals.IEnumerableToAccessor(" << string << ", " << (param.type.has_own ? "true" : "false")<< ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), outvar), context)) return false; } else if (param_is_acceptable(param, "Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Iterator *", !WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "const Eina_Iterator *", !WANT_OWN, WANT_OUT) ) { attributes::complex_type_def const* complex = efl::eina::get(¶m.type.original_type); if (!complex) return false; auto outvar = out_variable_name(param.param_name); if (!as_generator( string << " = Efl.Eo.Globals.IEnumerableToIterator(" << string << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), outvar), context)) return false; } return true; } }; struct native_convert_return_variable_generator { template bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const { if (ret_type.c_type == "Eina_Accessor *" || ret_type.c_type == "const Eina_Accessor *" || ret_type.c_type == "Eina_Iterator *" || ret_type.c_type == "const Eina_Iterator *") return as_generator( type << " _ret_var = null;" ).generate(sink, ret_type, context); else if (ret_type.c_type != "void") return as_generator( type << " _ret_var = default(" << type << ");" ).generate(sink, std::make_tuple(ret_type, ret_type), context); return true; } } const native_convert_return_variable {}; struct native_convert_return_generator { attributes::klass_def const* klass; template bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const { auto regular = efl::eina::get(&ret_type.original_type); if (ret_type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion_in_return(ret_type, attributes::parameter_direction::unknown) ) { return as_generator( "return Eina.PrimitiveConversion.ManagedToPointerAlloc(_ret_var);" ).generate(sink, attributes::unused, context); } else if (helpers::need_struct_conversion(regular)) { return as_generator( "return _ret_var;" ).generate(sink, nullptr, context); } else if (ret_type.c_type == "const char *") { if(!ret_type.has_own) { if (klass == nullptr) { EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) << "Null class found when trying to return string from native wrapper." << std::endl; return false; } return as_generator( "return _ret_var;" ).generate(sink, attributes::unused, context); } else { return as_generator("return _ret_var;" ).generate(sink, attributes::unused, context); } } else if (ret_type.c_type == "Eina_Stringshare *") { // Correct check for string? if (!ret_type.has_own) { if (klass == nullptr) { EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) << "Null class found when trying to return stringshare from native wrapper." << std::endl; return false; } return as_generator( "return _ret_var;" ).generate(sink, attributes::unused, context); } else { return as_generator("return _ret_var;") .generate(sink, attributes::unused, context); } } else if (ret_type.c_type == "Eina_Binbuf *" || ret_type.c_type == "const Eina_Binbuf *") { if (ret_type.has_own && !as_generator("_ret_var.Own = false; ") .generate(sink, attributes::unused, context)) return false; return as_generator("return _ret_var.Handle;") .generate(sink, attributes::unused, context); } else if (ret_type.c_type == "Eina_Hash *" || ret_type.c_type == "const Eina_Hash *") { attributes::complex_type_def const* complex = efl::eina::get(&ret_type.original_type); if (!complex || complex->subtypes.size() != 2) return false; if (ret_type.has_own && !as_generator("_ret_var.SetOwn(false); ") .generate(sink, attributes::unused, context)) return false; if (complex->subtypes.front().has_own && !as_generator("_ret_var.SetOwnKey(false); ") .generate(sink, attributes::unused, context)) return false; if (complex->subtypes.back().has_own && !as_generator("_ret_var.SetOwnValue(false); _ret_var.UnSetFreeCb(); ") .generate(sink, attributes::unused, context)) return false; return as_generator("return _ret_var.Handle;") .generate(sink, attributes::unused, context); } else if (ret_type.c_type == "Eina_Array *" || ret_type.c_type == "const Eina_Array *" || ret_type.c_type == "Eina_List *" || ret_type.c_type == "const Eina_List *" ) { attributes::complex_type_def const* complex = efl::eina::get(&ret_type.original_type); if (!complex) return false; if (ret_type.has_own && !as_generator("_ret_var.Own = false; ") .generate(sink, attributes::unused, context)) return false; // Iterators and Accessors can't own their content. if (ret_type.c_type != "Eina_Iterator *" && ret_type.c_type != "const Eina_Iterator *" && ret_type.c_type != "Eina_Accessor *" && ret_type.c_type != "const Eina_Accessor *" ) { if (!complex->subtypes.front().is_value_type && complex->subtypes.front().has_own && !as_generator("_ret_var.OwnContent = false; ") .generate(sink, attributes::unused, context)) return false; } return as_generator("return _ret_var.Handle;") .generate(sink, attributes::unused, context); } else if (ret_type.c_type == "Eina_Accessor *" || ret_type.c_type == "const Eina_Accessor *") { return as_generator(lit("return Efl.Eo.Globals.IEnumerableToAccessor(_ret_var, ") << (ret_type.has_own ? "true" : "false") << ");") .generate(sink, attributes::unused, context); } else if (ret_type.c_type == "Eina_Iterator *" || ret_type.c_type == "const Eina_Iterator *") { return as_generator("return Efl.Eo.Globals.IEnumerableToIterator(_ret_var);") .generate(sink, attributes::unused, context); } else if (ret_type.c_type != "void") return as_generator("return _ret_var;").generate(sink, ret_type, context); return true; } }; struct native_convert_out_assign_parameterized { native_convert_out_assign_generator const operator()(attributes::klass_def const &klass) const { return {&klass}; } } const native_convert_out_assign; struct native_convert_return_parameterized { native_convert_return_generator const operator()(attributes::klass_def const &klass) const { return {&klass}; } } const native_convert_return; struct convert_function_pointer_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction != attributes::parameter_direction::in) return true; if (!param.type.original_type.visit(is_fp_visitor{})) return true; std::string param_name = escape_keyword(param.param_name); // Allocate GCHandle in "param_name"_handle for param; if (!as_generator( "GCHandle " << param_name << "_handle = GCHandle.Alloc(" << param_name << ");\n" ).generate(sink, attributes::unused, context)) return false; return true; } } const convert_function_pointer {}; struct native_convert_function_pointer_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { if (param.direction != attributes::parameter_direction::in) return true; if (!param.type.original_type.visit(is_fp_visitor{})) return true; // Getting the type through C api std::string type_name = param.type.original_type.visit(type_name_visitor{}); const Eolian_Typedecl *tpd = ::eolian_unit_alias_by_name_get(param.unit, type_name.c_str()); if (!tpd) { EINA_LOG_ERR("Failed to get typedecl for c type [%s]", param.type.c_type.c_str()); return false; } if (eolian_typedecl_type_get(tpd) != EOLIAN_TYPEDECL_FUNCTION_POINTER) return true; const Eolian_Function *fd = eolian_typedecl_function_pointer_get(tpd); if (!fd) { EINA_LOG_ERR("Failed to get function pointer info for c type [%s]", param.type.c_type.c_str()); return false; } attributes::function_def f(fd, EOLIAN_FUNCTION_POINTER, tpd, param.unit); std::string param_name = escape_keyword(param.param_name); // Allocate GCHandle in "param_name"_handle for param; if (!as_generator( scope_tab << type << "Wrapper " << param_name << "_wrapper = new " << type << "Wrapper(" << param_name << ", " << param_name << "_data, " << param_name << "_free_cb);\n" ).generate(sink, std::make_tuple(param.type, param.type), context)) return false; // FIXME What about calling the free function? return true; } } const native_convert_function_pointer {}; struct constructor_parameter_name_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { auto target_name = name_helpers::constructor_managed_name(ctor.name); // Only multi-valued constructing methods get their actual parameter names if (ctor.function.parameters.size() > 1) target_name += '_' + param.param_name; auto name = name_helpers::managed_name(target_name); name[0] = std::tolower(name[0]); return as_generator(string).generate(sink, name, context); } attributes::constructor_def const& ctor; }; struct constructor_parameter_name_parameterized { constructor_parameter_name_generator const operator()(attributes::constructor_def const& ctor) const { return {ctor}; } } const constructor_parameter_name; // Generates the parameters for the given constructor // If the constructor receives multiple parameters, they get the name // of the constructor plus the name of the parameter (e.g. DefineParentData, DefineIndex) struct constructor_param_generator { template bool generate(OutputIterator sink, attributes::constructor_def const& ctor, Context const& context) const { auto params = ctor.function.parameters; if (!as_generator( efl::eolian::grammar::attribute_reorder<1, -1> (type(false, ctor.is_optional) << " " << constructor_parameter_name(ctor) << (ctor.is_optional ? " = null" : "")) % ", " ).generate(sink, params, context)) return false; // } return true; } } const constructor_param; // Generates the invocation of the given parameter struct constructor_invocation_generator { template bool generate(OutputIterator sink, attributes::constructor_def const& ctor, Context const& context) const { auto params = ctor.function.parameters; if (!as_generator( "if (" << (efl::eolian::grammar::attribute_reorder<-1> ("Efl.Eo.Globals.ParamHelperCheck(" << constructor_parameter_name(ctor) << ")") % " || ") << ")\n" << scope_tab << scope_tab << "{\n" << scope_tab << scope_tab << scope_tab << name_helpers::managed_method_name(ctor.function) << "(" ).generate(sink, params, context)) return false; size_t idx = 0; for (auto&& param : params) { idx++; if (!as_generator( "Efl.Eo.Globals.GetParamHelper(" << constructor_parameter_name(ctor) << ")" << ((idx < params.size()) ? ", " : "") ).generate(sink, param, context)) return false; } if (!as_generator( ");\n" << scope_tab << scope_tab << "}\n").generate(sink, attributes::unused, context)) return false; return true; } } const constructor_invocation; } #endif