diff --git a/src/bin/eolian_mono/eolian/mono/blacklist.hh b/src/bin/eolian_mono/eolian/mono/blacklist.hh index 8d8de9d1bf..70bc34a038 100644 --- a/src/bin/eolian_mono/eolian/mono/blacklist.hh +++ b/src/bin/eolian_mono/eolian/mono/blacklist.hh @@ -150,9 +150,34 @@ inline bool is_alias_blacklisted(attributes::alias_def const& alias, Context con return name_helpers::alias_full_eolian_name(alias) == "Eina.Error"; } -inline bool is_property_blacklisted(std::string const&) +inline bool is_property_blacklisted(std::string const& name) { - return false; + auto properties = std::vector{ + // These properties encode (void* arr, int len) arrays + "Efl.Gfx.IGradient.Stop" + , "Efl.Gfx.GradientConcrete.Stop" + , "Efl.Gfx.IShape.StrokeDash" + , "Efl.Gfx.ShapeConcrete.StrokeDash" + , "Efl.Gfx.Vg.ValueProvider.Transform" + , "Efl.Canvas.Vg.Node.Transformation" + // Will be bound manually + , "Efl.Core.Env.Env" + // Setter returns a future + , "Efl.IModel.Property" + // Protected + , "Efl.Access.IAction.ActionName" + , "Efl.Access.IAction.ActionLocalizedName" + , "Efl.Access.IComponent.Extents" + , "Efl.Access.IText.AccessSelection" + , "Efl.Access.IText.AccessText" + , "Efl.Access.IText.BoundedRanges" + , "Efl.Access.IText.Character" + , "Efl.Access.IText.OffsetAtPoint" + , "Efl.Access.IText.String" + , "Efl.Access.IText.TextAttributes" + }; + + return std::find(std::begin(properties), std::end(properties), name) != std::end(properties); } template diff --git a/src/bin/eolian_mono/eolian/mono/documentation.hh b/src/bin/eolian_mono/eolian/mono/documentation.hh index d009e4571d..db00ba8a0f 100644 --- a/src/bin/eolian_mono/eolian/mono/documentation.hh +++ b/src/bin/eolian_mono/eolian/mono/documentation.hh @@ -21,6 +21,7 @@ #include "grammar/html_escaped_string.hpp" #include "using_decl.hh" #include "name_helpers.hh" +#include "helpers.hh" #include "generation_contexts.hh" #include "blacklist.hh" @@ -76,7 +77,11 @@ struct documentation_generator // The name_tail parameter is the last 4 chars of the original string, which // could be ".set" or ".get" and in this case they are ignored by Eolian. // We want them to know what the documentation intended to reference. - static std::string function_conversion(const ::Eolian_Object *klass, const ::Eolian_Function *function, std::string name_tail) + template + static std::string function_conversion(const ::Eolian_Object *klass + , const ::Eolian_Function *function + , std::string name_tail + , Context const& context) { ::Eolian_Function_Type ftype = ::eolian_function_type_get(function); const char* eo_name = ::eolian_function_name_get(function); @@ -122,13 +127,27 @@ struct documentation_generator break; case ::EOLIAN_PROPERTY: { - int getter_nkeys = property_num_keys(function, ::EOLIAN_PROP_GET); - int setter_nkeys = property_num_keys(function, ::EOLIAN_PROP_SET); std::string short_name = name_helpers::property_managed_name(klass_d, eo_name); - bool blacklisted = blacklist::is_property_blacklisted(name + "." + short_name); - // EO properties with keys or blacklisted are not converted into C# properties. - // In these cases we refer to the getter method instead of the property. - if ((getter_nkeys > 0) || (setter_nkeys > 0) || (blacklisted)) name += ".Get" + short_name; + + // We need to replace the current class context with the context + // from the class that originated this property. + class_context::wrapper_kind klass_kind; + if (helpers::is_managed_interface(klass_d)) + klass_kind = class_context::interface; + else + klass_kind = class_context::inherit; + + auto my_context = grammar::context_replace_tag(class_context{klass_kind}, context); + + auto unit = eolian_object_unit_get((const Eolian_Object*)function); + attributes::function_def getter_func{function, ::EOLIAN_PROP_GET, nullptr, unit}; + attributes::function_def setter_func{function, ::EOLIAN_PROP_SET, nullptr, unit}; + attributes::property_def prop{function, getter_func, setter_func, unit}; + + auto has_wrapper = helpers::has_property_wrapper(prop, &klass_d, my_context); + + if (has_wrapper == helpers::has_property_wrapper_bit::has_none) + name += ".Get" + short_name; else if (name_tail == ".get") name += ".Get" + short_name; else if (name_tail == ".set") name += ".Set" + short_name; else name += "." + short_name; @@ -165,9 +184,13 @@ struct documentation_generator } // Turns an Eolian reference like @Efl.Input.Pointer.tool into a tag - static std::string ref_conversion(const ::Eolian_Doc_Token *token, const Eolian_State *state, std::string name_tail, - bool want_beta) + template + static std::string ref_conversion(const ::Eolian_Doc_Token *token + , const Eolian_State *state + , std::string name_tail + , Context const& context) { + bool want_beta = context_want_beta(context); const Eolian_Object *data, *data2; ::Eolian_Object_Type type = ::eolian_doc_token_ref_resolve(token, state, &data, &data2); @@ -195,7 +218,7 @@ struct documentation_generator is_beta = eolian_object_is_beta(data) || eolian_object_is_beta(data2); break; case ::EOLIAN_OBJECT_FUNCTION: - ref += function_conversion(data, (const ::Eolian_Function *)data2, name_tail); + ref += function_conversion(data, (const ::Eolian_Function *)data2, name_tail, context); is_beta = eolian_object_is_beta(data) || eolian_object_is_beta(data2); break; case ::EOLIAN_OBJECT_CONSTANT: @@ -227,7 +250,8 @@ struct documentation_generator } // Turns EO documentation syntax into C# triple-slash XML comment syntax - static std::string syntax_conversion(std::string text, const Eolian_State *state, bool want_beta) + template + static std::string syntax_conversion(std::string text, const Eolian_State *state, Context const& context) { std::string new_text, ref; ::Eolian_Doc_Token_Type previous_token_type = ::EOLIAN_DOC_TOKEN_UNKNOWN; @@ -266,7 +290,7 @@ struct documentation_generator new_text += token_text; break; case ::EOLIAN_DOC_TOKEN_REF: - ref = ref_conversion(&token, state, name_tail, want_beta); + ref = ref_conversion(&token, state, name_tail, context); if (ref != "") { if (utils::ends_with(ref, BETA_REF_SUFFIX)) @@ -331,7 +355,7 @@ struct documentation_generator if (!as_generator(html_escaped_string).generate(std::back_inserter(new_text), text, context)) return false; auto options = context_find_tag(context); - new_text = syntax_conversion( new_text, context_find_tag(context).state, options.want_beta); + new_text = syntax_conversion( new_text, context_find_tag(context).state, context); std::string tabs; as_generator(scope_tab(scope_size) << "/// ").generate (std::back_inserter(tabs), attributes::unused, context); @@ -653,7 +677,7 @@ struct documentation_string_generator auto options = context_find_tag(context); auto state = context_find_tag(context).state; - if (!as_generator(string).generate(sink, documentation_generator::syntax_conversion(escaped, state, options.want_beta), context)) + if (!as_generator(string).generate(sink, documentation_generator::syntax_conversion(escaped, state, context), context)) return false; return true; diff --git a/src/bin/eolian_mono/eolian/mono/function_definition.hh b/src/bin/eolian_mono/eolian/mono/function_definition.hh index cded973d23..86eb2db192 100644 --- a/src/bin/eolian_mono/eolian/mono/function_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/function_definition.hh @@ -26,6 +26,7 @@ #include "grammar/list.hpp" #include "grammar/alternative.hpp" #include "grammar/attribute_reorder.hpp" +#include "grammar/eps.hpp" #include "grammar/counter.hpp" #include "logging.hh" #include "type.hh" @@ -44,7 +45,7 @@ namespace eolian_mono { struct native_function_definition_generator { attributes::klass_def const* klass; - + template bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const { @@ -181,7 +182,7 @@ struct native_function_definition_generator return true; } }; - + struct function_definition_generator { function_definition_generator(bool do_super = false) @@ -323,6 +324,199 @@ property_extension_method_definition_generator property_extension_method_definit struct property_wrapper_definition_generator { + template + bool generate_get_indexer(OutputIterator sink, attributes::property_def const& property, Context const& context + , std::string get_scope + , bool is_interface) const + { + if (is_interface) + { + if (!as_generator(scope_tab << scope_tab << get_scope << "get;\n" + ).generate(sink, attributes::unused, context)) + return false; + } + else + { + if (!as_generator(scope_tab << scope_tab << get_scope << "get\n" + << scope_tab << scope_tab << "{\n" + << scope_tab << scope_tab(2) << "var i = new " + << name_helpers::property_concrete_indexer_name(property) << "();\n" + << scope_tab << scope_tab(2) << "i.Self = this;\n" + << scope_tab << scope_tab(2) << "return i;\n" + << scope_tab << scope_tab << "}\n" + ).generate(sink, attributes::unused, context)) + return false; + } + + return true; + } + + template + bool generate_indexer(OutputIterator sink + , attributes::property_def const& property + , Context const& context + , std::string scope, std::string get_scope, std::string set_scope + , std::string class_name + , C1 keys, C2 values + , bool is_interface + , bool is_concrete_for_interface + , bool has_setter) const + { + if (is_interface) + return true; + + auto size_not_one = [] (std::vector k) { return k.size() != 1; }; + auto type_or_tuple + = + ( + ( + attribute_conditional(size_not_one)["("] + << (type(false) % ", ") + << ")" + ) + | *type(false) + ) + ; + + std::string parentship = "\n"; + + bool is_self_property = *implementing_klass == *klass_from_property; + + if (!(is_self_property && !is_concrete_for_interface)) + parentship = " : " + name_helpers::property_interface_indexer_name(property, *klass_from_property) + "\n"; + + if (!as_generator + ( + scope_tab << scope << "class " << name_helpers::property_concrete_indexer_name(property) << parentship + << scope_tab << "{\n" + << scope_tab(2) << "public " << class_name << " Self {get; set;}\n" + << scope_tab(2) << "public " + << type_or_tuple << " this[" << type_or_tuple <<" i]\n" + << scope_tab(2) << "{\n" + ).generate(sink, make_tuple(values, values, keys, keys), context)) + return false; + + assert (!keys.empty()); + std::vector get_keys; + if(keys.size() != 1) + { + unsigned int i = 0; + for (auto&& key : keys) + { + static_cast(key); + ++i; + get_keys.push_back("i.Item" + std::to_string(i)); + } + } + else + { + get_keys.push_back ("i"); + } + assert (!get_keys.empty()); + + generate_get(sink, property, context, get_scope, get_keys, values, is_interface, "Self."); + if (has_setter) + generate_set(sink, property, context, set_scope, get_keys, values, is_interface, "Self."); + + if (!as_generator + ( + scope_tab(2) << "}\n" + << scope_tab << "};\n" + ).generate(sink, attributes::unused, context)) + return false; + return true; + } + template + bool generate_set(OutputIterator sink, attributes::property_def const& property, Context const& context + , std::string set_scope + , CK keys, CV values + , bool is_interface + , std::string name_prefix = "") const + { + using efl::eolian::grammar::counter; + if (is_interface) + { + if (!as_generator(scope_tab << scope_tab << set_scope << "set;\n" + ).generate(sink, attributes::unused, context)) + return false; + } + else if (values.size() == 1) + { + if (!as_generator(scope_tab << scope_tab << set_scope << "set " << "{ " << name_prefix << name_helpers::managed_method_name(*property.setter) + "(" << *(string << ",") << "value); }\n" + ).generate(sink, keys, context)) + return false; + } + else if (values.size() > 1) + { + if (!as_generator( + scope_tab << scope_tab << set_scope << "set " + << ("{ " << name_prefix << name_helpers::managed_method_name(*property.setter) + "(") + << *(string << ",") << ((" value.Item" << counter(1)) % ", ") + << "); }\n" + ).generate(sink, std::make_tuple(keys, values), context)) + return false; + } + return true; + } + template + bool generate_get(OutputIterator sink, attributes::property_def const& property, Context const& context + , std::string get_scope + , CK keys, CV values + , bool is_interface + , std::string name_prefix = "") const + { + using efl::eolian::grammar::attribute_reorder; + using efl::eolian::grammar::attributes::parameter_direction; + using efl::eolian::grammar::attributes::parameter_def; + + if (is_interface) // only declaration + { + if (!as_generator(scope_tab << scope_tab << get_scope << "get;\n" + ).generate(sink, attributes::unused, context)) + return false; + } + else + if (/*has_getter && */values.size() == 1) + { + if (!as_generator + (scope_tab << scope_tab << get_scope + << "get " << "{ return " << name_prefix << name_helpers::managed_method_name(*property.getter) + << "(" << (string % ",") << "); }\n" + ).generate(sink, keys, context)) + return false; + } + else if (/*has_getter && */values.size() > 1) + { + if (!as_generator + (scope_tab << scope_tab << get_scope << "get " + << "{\n" + << *attribute_reorder<1, -1, 1> + (scope_tab(3) << type(true) << " _out_" + << argument(false) << " = default(" << type(true) << ");\n" + ) + << scope_tab(3) << name_prefix << name_helpers::managed_method_name(*property.getter) + << "(" << *(string << ",") << (("out _out_" << argument(false)) % ", ") << ");\n" + << scope_tab(3) << "return (" << (("_out_"<< argument(false)) % ", ") << ");\n" + << scope_tab(2) << "}" << "\n" + ).generate(sink, std::make_tuple(values, keys, values, values), context)) + return false; + } + // else if (values.size() == 1) + // { + // if (!as_generator + // (scope_tab << scope_tab << get_scope << "get " + // << "{\n" + // << *attribute_reorder<1, -1, 1>(scope_tab(3) << type(true) << " _out_" << argument(false) << " = default(" << type(true) << ");\n") + // << scope_tab(3) << name_prefix << name_helpers::managed_method_name(*property.getter) + // << "(" << *(string << ",") << (("out _out_" << argument(false)) % ",") << ");\n" + // << scope_tab(3) << "return " << (("_out_"<< argument(false)) % ",") << ";\n" + // << scope_tab(2) << "}" << "\n" + // ).generate(sink, std::make_tuple(values, keys, values, values), context)) + // return false; + // } + return true; + } + template bool generate(OutputIterator sink, attributes::property_def const& property, Context const& context) const { @@ -331,103 +525,127 @@ struct property_wrapper_definition_generator using efl::eolian::grammar::attributes::parameter_direction; using efl::eolian::grammar::attributes::parameter_def; - if (blacklist::is_property_blacklisted(property, *implementing_klass, context)) - return true; + /// C(k) = keys count, C(v) = values count + /// /------------\ /------\. + /// |blacklisted?|---yes-----| skip |--------------\. + /// \------------/ \------/ | + /// | | | + /// no yes | + /// | | | + /// /---------\ /------------\ | + /// |is-static|----yes-----|is-interface| | + /// \---------/ \------------/ | + /// | | | + /// no no | + /// | | | + /// /--------\ /-----------\ | + /// |has-get?|---no-conc---|is-concrete|-----yes---/ + /// \--------/ \-----------/ + /// / \. + /// no yes + /// / \. + /// /----\ /--------------------------------------\. + /// |skip|-yes-|explicit return != Eina.Error or void | + /// \----/ \--------------------------------------/ + /// | + /// no + /// | + /// /--------\. + /// |has-set?| + /// \--------/ + /// / \. + /// no yes + /// / \. + /// /------\ /--------------------------------------\. + /// /------------------|no-set| |explicit return != Eina.Error or void |---- yes --\. + /// | \------/ \--------------------------------------/ | + /// | \------------|----------------------------------------------/ + /// | no + /// | | + /// | /--------\. + /// | |has-both| + /// | \--------/ + /// | | + /// | /-------------------\. + /// | |set-keys = get-keys| + /// | \-------------------/ + /// | / | + /// | no | + /// | / | + /// | /----\ /-----------------------\. + /// | |skip|--no---|set-values = get-values| + /// | \----/ \-----------------------/ + /// | / + /// | yes + /// | / + /// | /--------\. + /// \-------------------------| keys | + /// \--------/ + /// / \. + /// 0 >0 + /// / \. + /// /----------\ /----------\. + /// |no-indexer| | keys > 1 | + /// \----------/ \----------/ + /// | / | + /// | no yes + /// | / | + /// | / | + /// | /---------\ /-------------------\. + /// | | indexer | | indexer tuple key | + /// | \---------/ \-------------------/ + /// | / | + /// /--------\ | + /// | values |----------/ + /// \--------/ + /// / \. + /// 1 >1 + /// / \. + /// /----------------\ /-------------\. + /// | no tuple value | | tuple value | + /// \----------------/ \-------------/ + /// + + auto has_wrapper = helpers::has_property_wrapper (property, implementing_klass, context); + bool has_getter = has_wrapper & helpers::has_property_wrapper_bit::has_getter; + if (!has_getter) return true; + bool has_setter = has_wrapper & helpers::has_property_wrapper_bit::has_setter; + bool has_indexer = has_wrapper & helpers::has_property_wrapper_bit::has_indexer; bool is_interface = context_find_tag(context).current_wrapper_kind == class_context::interface; bool is_static = (property.getter.is_engaged() && property.getter->is_static) || (property.setter.is_engaged() && property.setter->is_static); bool is_concrete = context_find_tag(context).current_wrapper_kind == class_context::concrete; + bool is_concrete_for_interface = is_concrete + && (implementing_klass->type == attributes::class_type::interface_ + || implementing_klass->type == attributes::class_type::mixin); - - if ((is_concrete || is_interface) && is_static) - return true; - - auto get_params = property.getter.is_engaged() ? property.getter->parameters.size() : 0; - //auto set_params = property.setter.is_engaged() ? property.setter->parameters.size() : 0; - - // C# properties must have a single value. - // - // Single values in getters are automatically converted to return_type, - // meaning they should have 0 parameters. - // - // For setters, we ignore the return type - usually boolean. - // if (get_params > 0 || set_params > 1) - // return true; - - if (property.getter - && std::find_if (property.getter->parameters.begin() - , property.getter->parameters.end() - , [] (parameter_def const& p) - { - return p.direction != parameter_direction::out; - }) != property.getter->parameters.end()) - return true; - if (property.setter - && std::find_if (property.setter->parameters.begin() - , property.setter->parameters.end() - , [] (parameter_def const& p) - { - return p.direction != parameter_direction::in; - }) != property.setter->parameters.end()) - return true; - - if (property.getter && property.setter) + //if (name_helpers::klass_concrete_or_interface_name (*implementing_klass) == "IMapping") + if (false) { - if (get_params != 0 && property.setter->parameters.size() != property.getter->parameters.size()) - return true; + if (!as_generator(grammar::lit("/// is interface ") << (int)is_interface + << " is static " << (int)is_static + << " is concrete " << (int)is_concrete + << " is concrete_for_interface " << (int)is_concrete_for_interface + << " klass_from_property->type " << (int)klass_from_property->type + << " has_setter " << (int)has_setter + << " property.setter->explicit_return_type != attributes::void_ " << (property.setter && property.setter->explicit_return_type != attributes::void_) + << " property.setter->keys != property.getter->keys " << (property.setter && property.setter->keys != property.getter->keys) + << " property.setter->values != property.getter->values " << (property.setter && property.setter->values != property.getter->values) + << " has_setter && property.setter->scope != attributes::member_scope::scope_public " << (property.setter && property.setter->scope != attributes::member_scope::scope_public) + << "\n") + .generate (sink, attributes::unused, context)) + return false; } - std::vector parameters; - - if (property.setter.is_engaged()) - { - std::transform (property.setter->parameters.begin(), property.setter->parameters.end() - , std::back_inserter(parameters) - , [] (parameter_def p) -> parameter_def - { - //p.direction = efl::eolian::attributes::parameter_direction::in; - return p; - }); - } - else if (property.getter.is_engaged()) - { - // if getter has parameters, then we ignore return type, otherwise - // we use the return type. - if (get_params == 0) - parameters.push_back({parameter_direction::in - , property.getter->return_type, "propertyResult", {} - , property.getter->unit}); - else - std::transform (property.getter->parameters.begin(), property.getter->parameters.end() - , std::back_inserter(parameters) - , [] (parameter_def p) -> parameter_def - { - p.direction = parameter_direction::in; - return p; - }); - } - else - { - EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) << "Property must have either a getter or a setter." << std::endl; - return false; - } - - std::string dir_mod; - if (property.setter.is_engaged()) - dir_mod = direction_modifier(property.setter->parameters[0]); + if (blacklist::is_property_blacklisted(property, context)) + return true; std::string managed_name = name_helpers::property_managed_name(property); std::string scope = "public "; - std::string get_scope = property.getter.is_engaged() ? eolian_mono::function_scope_get(*property.getter) : ""; - bool is_get_public = get_scope == "public "; - std::string set_scope = property.setter.is_engaged() ? eolian_mono::function_scope_get(*property.setter) : ""; - bool is_set_public = set_scope == "public "; - - // No need to generate this wrapper as no accessor is public. - if (is_interface && (!is_get_public && !is_set_public)) - return true; + std::string get_scope = eolian_mono::function_scope_get(*property.getter); + std::string set_scope = has_setter ? eolian_mono::function_scope_get(*property.setter) : ""; // C# interface members are declared automatically as public if (is_interface) @@ -442,23 +660,64 @@ struct property_wrapper_definition_generator get_scope = ""; set_scope = ""; } - else if (!property.setter.is_engaged() || (get_scope == scope)) + else if (!has_setter || (get_scope == scope)) { scope = get_scope; get_scope = ""; } - else if (!property.getter.is_engaged() || (set_scope == scope)) - { - scope = set_scope; - set_scope = ""; - } - if (parameters.size() == 1) + std::string virtual_mod = (is_static || is_interface || is_concrete) ? "" : "virtual "; + + auto keys = property.getter->keys; + auto values = property.getter->values; + auto generated_values = values; + auto klass_name = name_helpers::klass_concrete_or_interface_name (*implementing_klass); + + if (has_indexer) + { + assert (!!implementing_klass); + generate_indexer (sink, property, context, scope, get_scope, set_scope + , klass_name, keys, values + , is_interface, is_concrete_for_interface, has_setter); + + generated_values.clear(); + if (!is_interface && *implementing_klass == *klass_from_property + && !is_concrete_for_interface) + { + generated_values.push_back + (attributes::parameter_def + {parameter_direction::in + , attributes::type_def + { + attributes::regular_type_def{name_helpers::property_concrete_indexer_name(property), {attributes::qualifier_info::is_none, ""}, {}} + , name_helpers::property_concrete_indexer_name(property) + , false, false, false, "" + } + , "indexer", {}, nullptr + }); + } + else + { + generated_values.push_back + (attributes::parameter_def + {parameter_direction::in + , attributes::type_def + { + attributes::regular_type_def{name_helpers::klass_full_concrete_or_interface_name (*klass_from_property) + managed_name + "Indexer", {attributes::qualifier_info::is_none, ""}, {}} + , name_helpers::property_interface_indexer_name(property, *klass_from_property) + , false, false, false, "" + } + , "indexer", {}, nullptr + }); + } + } + + if (generated_values.size() == 1) { if (!as_generator( documentation(1) - << scope_tab << scope << (is_static ? "static " : "") << type(true) << " " << managed_name << " {\n" - ).generate(sink, std::make_tuple(property, parameters[0].type), context)) + << scope_tab << scope << (is_static ? "static " : virtual_mod) << type(true) << " " << managed_name << " {\n" + ).generate(sink, std::make_tuple(property, generated_values[0].type), context)) return false; } else @@ -469,73 +728,21 @@ struct property_wrapper_definition_generator << scope_tab << scope << (is_static ? "static (" : "(") << (attribute_reorder<1, -1>(type(true) /*<< " " << argument*/) % ", ") << ") " << managed_name << " {\n" - ).generate(sink, std::make_tuple(property, parameters), context)) + ).generate(sink, std::make_tuple(property, generated_values), context)) return false; } - if (property.getter.is_engaged() && is_interface) + if (has_indexer) { - if (is_get_public) - if (!as_generator(scope_tab << scope_tab << set_scope << "get;\n" - ).generate(sink, attributes::unused, context)) - return false; + generate_get_indexer (sink, property, context, get_scope, is_interface); } - else if (property.getter.is_engaged() && get_params == 0/*parameters.size() == 1 && property.getter.is_engaged()*/) + else { - if (!as_generator - (scope_tab << scope_tab << get_scope - << "get " << "{ return " + name_helpers::managed_method_name(*property.getter) + "(); }\n" - ).generate(sink, attributes::unused, context)) - return false; - } - else if (parameters.size() >= 1 && property.getter) - { - if (!as_generator - (scope_tab << scope_tab << get_scope << "get " - << "{\n" - << *attribute_reorder<1, -1, 1> - (scope_tab(3) << type(true) << " _out_" - << argument(false) << " = default(" << type(true) << ");\n" - ) - << scope_tab(3) << name_helpers::managed_method_name(*property.getter) - << "(" << (("out _out_" << argument(false)) % ", ") << ");\n" - << scope_tab(3) << "return (" << (("_out_"<< argument(false)) % ", ") << ");\n" - << scope_tab(2) << "}" << "\n" - ).generate(sink, std::make_tuple(parameters, parameters, parameters), context)) - return false; - } - // else if (parameters.size() == 1) - // { - // if (!as_generator - // (scope_tab << scope_tab << get_scope << "get " - // << "{\n" - // << *attribute_reorder<1, -1, 1>(scope_tab(3) << type(true) << " _out_" << argument(false) << " = default(" << type(true) << ");\n") - // << scope_tab(3) << name_helpers::managed_method_name(*property.getter) - // << "(" << (("out _out_" << argument(false)) % ",") << ");\n" - // << scope_tab(3) << "return " << (("_out_"<< argument(false)) % ",") << ";\n" - // << scope_tab(2) << "}" << "\n" - // ).generate(sink, std::make_tuple(parameters, parameters, parameters), context)) - // return false; - // } + std::vector empty_keys; + generate_get(sink, property, context, get_scope, empty_keys, values, is_interface); - if (property.setter.is_engaged() && is_interface) - { - if (is_set_public) - if (!as_generator(scope_tab << scope_tab << set_scope << "set;\n" - ).generate(sink, attributes::unused, context)) - return false; - } - else if (parameters.size() == 1 && property.setter.is_engaged()) - { - if (!as_generator(scope_tab << scope_tab << set_scope << "set " << "{ " + name_helpers::managed_method_name(*property.setter) + "(" + dir_mod + "value); }\n" - ).generate(sink, attributes::unused, context)) - return false; - } - else if (parameters.size() > 1 && property.setter.is_engaged()) - { - if (!as_generator(scope_tab << scope_tab << set_scope << "set " << ("{ " + name_helpers::managed_method_name(*property.setter) + "(" + dir_mod) << ((" value.Item" << counter(1)) % ", ") << "); }" << "\n" - ).generate(sink, parameters, context)) - return false; + if (has_setter) + generate_set (sink, property, context, set_scope, empty_keys, values, is_interface); } if (!as_generator(scope_tab << "}\n\n").generate(sink, attributes::unused, context)) @@ -543,13 +750,14 @@ struct property_wrapper_definition_generator return true; } - attributes::klass_def const* implementing_klass; + attributes::klass_def const* implementing_klass, *klass_from_property; }; struct property_wrapper_definition_parameterized { - property_wrapper_definition_generator operator()(attributes::klass_def const& klass) const + property_wrapper_definition_generator operator()(attributes::klass_def const& klass + , attributes::klass_def const& prop_from_klass) const { - return {&klass}; + return {&klass, &prop_from_klass}; } } const property_wrapper_definition; property_wrapper_definition_generator as_generator(property_wrapper_definition_parameterized) @@ -557,6 +765,45 @@ property_wrapper_definition_generator as_generator(property_wrapper_definition_p return {}; } +struct interface_property_indexer_definition_generator +{ + template + bool generate(OutputIterator sink, attributes::property_def const& property, Context const& context) const + { + using efl::eolian::grammar::attribute_reorder; + using efl::eolian::grammar::counter; + using efl::eolian::grammar::attributes::parameter_direction; + using efl::eolian::grammar::attributes::parameter_def; + + bool is_interface = context_find_tag(context).current_wrapper_kind == class_context::interface; + + assert (is_interface); + auto klass_name = name_helpers::klass_concrete_or_interface_name (*implementing_klass); + std::string managed_name = name_helpers::property_managed_name(property); + + if (!as_generator + ("public interface " << name_helpers::property_interface_indexer_short_name(property, *implementing_klass) << "\n" + << "{\n" + << "}\n" + ).generate (sink, attributes::unused, context)) + return false; + + return true; + } + attributes::klass_def const* implementing_klass; +}; +struct interface_property_indexer_definition_parameterized +{ + interface_property_indexer_definition_generator operator()(attributes::klass_def const& klass) const + { + return {&klass}; + } +} const interface_property_indexer_definition; +interface_property_indexer_definition_generator as_generator(interface_property_indexer_definition_parameterized) +{ + return {}; +} + } namespace efl { namespace eolian { namespace grammar { @@ -572,6 +819,10 @@ struct is_eager_generator< ::eolian_mono::property_wrapper_definition_generator> template <> struct is_eager_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {}; template <> +struct is_eager_generator< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::true_type {}; +template <> +struct is_eager_generator< ::eolian_mono::interface_property_indexer_definition_generator> : std::true_type {}; +template <> struct is_generator< ::eolian_mono::function_definition_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::native_function_definition_generator> : std::true_type {}; @@ -583,6 +834,10 @@ template <> struct is_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {}; template <> struct is_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {}; +template <> +struct is_generator< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::true_type {}; +template <> +struct is_generator< ::eolian_mono::interface_property_indexer_definition_generator> : std::true_type {}; namespace type_traits { template <> @@ -601,8 +856,13 @@ template <> struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator> : std::integral_constant {}; template <> struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant {}; + +template <> +struct attributes_needed< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::integral_constant {}; +template <> +struct attributes_needed< ::eolian_mono::interface_property_indexer_definition_generator> : std::integral_constant {}; } - + } } } #endif diff --git a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh index f7376f056a..2ac16b0f61 100644 --- a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh +++ b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh @@ -26,6 +26,7 @@ namespace eolian_mono { struct class_context { enum wrapper_kind { + none, interface, concrete, inherit, @@ -109,6 +110,12 @@ struct options_context { std::string examples_dir; }; +template +bool context_want_beta(Context const& context) +{ + return efl::eolian::grammar::context_find_tag(context).want_beta; +} + } #endif diff --git a/src/bin/eolian_mono/eolian/mono/helpers.hh b/src/bin/eolian_mono/eolian/mono/helpers.hh index b34a985749..049f263d80 100644 --- a/src/bin/eolian_mono/eolian/mono/helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/helpers.hh @@ -17,6 +17,7 @@ #define EOLIAN_MONO_HELPERS_HH #include "grammar/klass_def.hpp" +#include "grammar/context.hpp" #include "blacklist.hh" #include "generation_contexts.hh" #include "name_helpers.hh" @@ -305,6 +306,106 @@ inline std::vector reorder_constructors(std::vector return constructors; } +enum class has_property_wrapper_bit +{ + has_none = 0 + , has_getter = 1 << 0 + , has_setter = 1 << 1 + , has_indexer = 1 << 2 + , has_key_tuple = 1 << 3 + , has_value_tuple = 1 << 4 + , has_set_error_check = 1 << 5 + , has_get_error_check = 1 << 6 +}; + +has_property_wrapper_bit& operator|=(has_property_wrapper_bit& self, has_property_wrapper_bit bit) +{ + self = static_cast(static_cast(self) | static_cast(bit)); + return self; +} + +bool operator&(has_property_wrapper_bit self, has_property_wrapper_bit bit) +{ + return static_cast(self) & static_cast(bit); +} + +template +has_property_wrapper_bit has_property_wrapper(attributes::property_def const& property, attributes::klass_def const* implementing_klass + , Context const& context) +{ + using efl::eolian::grammar::context_find_tag; + has_property_wrapper_bit r = has_property_wrapper_bit::has_none; + + if (blacklist::is_property_blacklisted(property, *implementing_klass, context)) + return r; + + bool has_getter = property.getter.is_engaged(); + bool has_setter = property.setter.is_engaged(); + + bool is_interface = context_find_tag(context).current_wrapper_kind == class_context::interface; + bool is_static = (property.getter.is_engaged() && property.getter->is_static) + || (has_setter && property.setter->is_static); + bool is_concrete = context_find_tag(context).current_wrapper_kind == class_context::concrete; + + if (is_static) + { + if (is_interface) return r; + else if (is_concrete) return r; + } + + // EINA_LOG_ERR("Generating property %s", name_helpers::property_managed_name(property).c_str()); + // C# interface can have only + if (is_interface) + { + has_getter = has_getter && property.getter->scope == attributes::member_scope:: scope_public; + } + + if (!has_getter) + { + return r; + } + + if (property.getter->explicit_return_type != attributes::void_) + { + return r; + } + else if (has_setter) + { + if (property.setter->explicit_return_type != attributes::void_) + has_setter = false; // do not generate setter + else if (property.setter->keys != property.getter->keys) + has_setter = false; + else if (property.setter->values != property.getter->values) + has_setter = false; + } + + if (is_interface) + { + if (property.getter->scope != attributes::member_scope::scope_public) + return r; + else if (has_setter && property.setter->scope != attributes::member_scope::scope_public) + has_setter = false; + } + + if (has_getter) + r |= has_property_wrapper_bit::has_getter; + if (has_setter) + r |= has_property_wrapper_bit::has_setter; + + if (property.getter->keys.size() == 1) + r |= has_property_wrapper_bit::has_indexer; + else if (property.getter->keys.size() > 1) + { + r |= has_property_wrapper_bit::has_indexer; + r |= has_property_wrapper_bit::has_key_tuple; + } + + if (property.getter->values.size() > 1) + r |= has_property_wrapper_bit::has_value_tuple; + + return r; +} + } // namespace helpers } // namespace eolian_mono diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh index 11a7cd6627..e26121c05d 100644 --- a/src/bin/eolian_mono/eolian/mono/klass.hh +++ b/src/bin/eolian_mono/eolian/mono/klass.hh @@ -106,6 +106,10 @@ struct klass name_helpers::klass_full_concrete_or_interface_name(cls)}, context); + // Property wrappers + if (!as_generator(*(interface_property_indexer_definition(cls))).generate(sink, cls.properties, iface_cxt)) + return false; + if(!as_generator(documentation).generate(sink, cls, iface_cxt)) return false; @@ -158,7 +162,7 @@ struct klass ).generate(sink, p, iface_cxt)) return false; - if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, cls.properties, iface_cxt)) + if (!as_generator(*(property_wrapper_definition(cls, cls))).generate(sink, cls.properties, iface_cxt)) return false; // End of interface declaration @@ -259,13 +263,13 @@ struct klass return false; // Property wrappers - if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, cls.properties, concrete_cxt)) + if (!as_generator(*(property_wrapper_definition(cls, cls))).generate(sink, cls.properties, concrete_cxt)) return false; for (auto&& klass : helpers::non_implemented_interfaces(cls, concrete_cxt)) { attributes::klass_def c(get_klass(klass, cls.unit), cls.unit); - if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, c.properties, concrete_cxt)) + if (!as_generator(*(property_wrapper_definition(cls, c))).generate(sink, c.properties, concrete_cxt)) return false; } @@ -343,13 +347,13 @@ struct klass return false; // Property wrappers - if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, cls.properties, inherit_cxt)) + if (!as_generator(*(property_wrapper_definition(cls, cls))).generate(sink, cls.properties, inherit_cxt)) return false; for (auto&& klass : helpers::non_implemented_interfaces(cls, inherit_cxt)) { attributes::klass_def c(get_klass(klass, cls.unit), cls.unit); - if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, c.properties, inherit_cxt)) + if (!as_generator(*(property_wrapper_definition(cls, c))).generate(sink, c.properties, inherit_cxt)) return false; } diff --git a/src/bin/eolian_mono/eolian/mono/name_helpers.hh b/src/bin/eolian_mono/eolian/mono/name_helpers.hh index 7f71d9279b..bf0abb7863 100644 --- a/src/bin/eolian_mono/eolian/mono/name_helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/name_helpers.hh @@ -334,28 +334,6 @@ inline std::string to_field_name(std::string const& in) return utils::capitalize(in); } - - -template -inline std::string property_managed_name(T const& klass, std::string const& name) -{ - auto names = utils::split(name, '_'); - // No need to escape keyword here as it will be capitalized and already - // namespaced inside the owner class. - auto managed_name = utils::to_pascal_case(names); - auto managed_klass_name = klass_concrete_or_interface_name(klass); - - if (managed_name == "Type") - managed_name = managed_klass_name + managed_name; - - return managed_name; -} - -inline std::string property_managed_name(attributes::property_def const& property) -{ - return property_managed_name(property.klass, property.name); -} - inline std::string managed_part_name(attributes::part_def const& part) { std::vector names = utils::split(part.name, '_'); @@ -512,6 +490,45 @@ inline std::string translate_inherited_event_name(const attributes::event_def &e return join_namespaces(klass.namespaces, '_') + klass_interface_name(klass) + "_" + managed_event_name(evt.name); } +// Properties + +template +inline std::string property_managed_name(T const& klass, std::string const& name) +{ + auto names = utils::split(name, '_'); + // No need to escape keyword here as it will be capitalized and already + // namespaced inside the owner class. + auto managed_name = utils::to_pascal_case(names); + auto managed_klass_name = klass_concrete_or_interface_name(klass); + + if (managed_name == "Type") + managed_name = managed_klass_name + managed_name; + + return managed_name; +} + +inline std::string property_managed_name(attributes::property_def const& property) +{ + return property_managed_name(property.klass, property.name); +} + +inline std::string property_concrete_indexer_name(attributes::property_def const& property) +{ + return property_managed_name(property) + "Indexer"; +} + +template +inline std::string property_interface_indexer_name(attributes::property_def const& property, T const& current_klass) +{ + return name_helpers::klass_full_interface_name(current_klass) + property_concrete_indexer_name(property); +} + +template +inline std::string property_interface_indexer_short_name(attributes::property_def const& property, T const& current_klass) +{ + return name_helpers::klass_interface_name(current_klass) + property_concrete_indexer_name(property); +} + // Open/close namespaces template bool open_namespaces(OutputIterator sink, std::vector namespaces, Context const& context) diff --git a/src/bin/eolian_mono/eolian/mono/parameter.hh b/src/bin/eolian_mono/eolian/mono/parameter.hh index 210e5f22d5..4af5fe2aef 100644 --- a/src/bin/eolian_mono/eolian/mono/parameter.hh +++ b/src/bin/eolian_mono/eolian/mono/parameter.hh @@ -65,7 +65,7 @@ struct is_generator< ::eolian_mono::parameter_generator> : std::true_type {}; namespace type_traits { template <> -struct attributes_needed< ::eolian_mono::parameter_generator> : std::integral_constant {}; +struct attributes_needed< ::eolian_mono::parameter_generator> : std::integral_constant {}; } template <> @@ -75,9 +75,9 @@ struct is_generator< ::eolian_mono::marshall_parameter_generator> : std::true_ty namespace type_traits { template <> -struct attributes_needed< ::eolian_mono::marshall_parameter_generator> : std::integral_constant {}; +struct attributes_needed< ::eolian_mono::marshall_parameter_generator> : std::integral_constant {}; } - + template <> struct is_eager_generator< ::eolian_mono::argument_generator> : std::true_type {}; template <> @@ -85,9 +85,9 @@ struct is_generator< ::eolian_mono::argument_generator> : std::true_type {}; namespace type_traits { template <> -struct attributes_needed< ::eolian_mono::argument_generator> : std::integral_constant {}; +struct attributes_needed< ::eolian_mono::argument_generator> : std::integral_constant {}; } - + template <> struct is_eager_generator< ::eolian_mono::argument_invocation_generator> : std::true_type {}; template <> @@ -1553,7 +1553,7 @@ struct native_convert_function_pointer_generator struct constructor_parameter_name_generator { - + template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { diff --git a/src/bin/eolian_mono/eolian_mono.cc b/src/bin/eolian_mono/eolian_mono.cc index 62eed11b2a..b6d2b6f1a0 100644 --- a/src/bin/eolian_mono/eolian_mono.cc +++ b/src/bin/eolian_mono/eolian_mono.cc @@ -182,13 +182,14 @@ run(options_type const& opts) auto context = context_add_tag(eolian_mono::indentation_context{0}, context_add_tag(eolian_mono::eolian_state_context{opts.state}, + context_add_tag(eolian_mono::class_context{eolian_mono::class_context::none}, context_add_tag(eolian_mono::options_context{opts.want_beta, opts.examples_dir}, context_add_tag(eolian_mono::library_context{opts.dllimport, opts.v_major, opts.v_minor, opts.references_map}, - efl::eolian::grammar::context_null())))); + efl::eolian::grammar::context_null()))))); EINA_ITERATOR_FOREACH(aliases, tp) { diff --git a/src/bindings/mono/efl_mono/GenericModel.cs b/src/bindings/mono/efl_mono/GenericModel.cs index 8d7cc813a2..faa2a2f099 100644 --- a/src/bindings/mono/efl_mono/GenericModel.cs +++ b/src/bindings/mono/efl_mono/GenericModel.cs @@ -52,7 +52,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// Gets the value of the given property in the wrapped model. /// The property of the model. /// The value of the property. - public Eina.Value GetProperty( System.String property) + public Eina.Value GetProperty(System.String property) { return model.GetProperty(property); } @@ -62,7 +62,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// The value of the property. /// An that resolves when the property has /// been set or reports an error if it could not be set. - public Eina.Future SetProperty( System.String property, Eina.Value value) + public Eina.Future SetProperty(System.String property, Eina.Value value) { return model.SetProperty(property, value); } @@ -77,7 +77,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// Returns an that will resolve when the property is ready to be read. /// The property of the model. /// An that resolves when the property is ready. - public Eina.Future GetPropertyReady( System.String property) + public Eina.Future GetPropertyReady(System.String property) { return model.GetPropertyReady(property); } @@ -87,7 +87,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// The size of the range. /// An that resolves to an /// of children models. - public Eina.Future GetChildrenSlice( uint start, uint count) + public Eina.Future GetChildrenSlice(uint start, uint count) { return model.GetChildrenSlice(start, count); } @@ -141,7 +141,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// The token for the task's cancellation. /// Task that resolves when the property has been set or could not /// be set. - public System.Threading.Tasks.Task SetPropertyAsync( System.String property, Eina.Value value, System.Threading.CancellationToken token=default(System.Threading.CancellationToken)) + public System.Threading.Tasks.Task SetPropertyAsync(System.String property, Eina.Value value, System.Threading.CancellationToken token=default(System.Threading.CancellationToken)) { return model.SetPropertyAsync(property, value, token); } @@ -151,7 +151,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// The token for the task's cancellation. /// Task that resolves when the given property is ready to be /// read. - public System.Threading.Tasks.Task GetPropertyReadyAsync( System.String property, System.Threading.CancellationToken token=default(System.Threading.CancellationToken)) + public System.Threading.Tasks.Task GetPropertyReadyAsync(System.String property, System.Threading.CancellationToken token=default(System.Threading.CancellationToken)) { return model.GetPropertyReadyAsync(property, token); } @@ -162,7 +162,7 @@ public class GenericModel : Efl.Object, Efl.IModel /// Token to notify the async operation of external request to cancel. /// Task that resolves when the desired of /// children models is ready. - public System.Threading.Tasks.Task GetChildrenSliceAsync( uint start, uint count, System.Threading.CancellationToken token=default(System.Threading.CancellationToken)) + public System.Threading.Tasks.Task GetChildrenSliceAsync(uint start, uint count, System.Threading.CancellationToken token=default(System.Threading.CancellationToken)) { return model.GetChildrenSliceAsync(start, count, token); } diff --git a/src/lib/eolian_cxx/grammar/klass_def.hpp b/src/lib/eolian_cxx/grammar/klass_def.hpp index 86fb61e8a3..48b8b52c80 100644 --- a/src/lib/eolian_cxx/grammar/klass_def.hpp +++ b/src/lib/eolian_cxx/grammar/klass_def.hpp @@ -897,7 +897,7 @@ struct function_def } else if(type == EOLIAN_PROP_GET) { - for(auto&& v : values) + for(auto v : values) { v.direction = parameter_direction::out; parameters.push_back(v); diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs index 7c580480ad..af40bf12d8 100644 --- a/src/tests/efl_mono/Eo.cs +++ b/src/tests/efl_mono/Eo.cs @@ -402,15 +402,15 @@ class TestCsharpProperties obj.Dispose(); } - public static void test_setter_only() - { - var obj = new Dummy.TestObject(); - int val = -1984; + // public static void test_setter_only() + // { + // var obj = new Dummy.TestObject(); + // int val = -1984; - obj.SetterOnly = val; - Test.AssertEquals(val, obj.GetSetterOnly()); - obj.Dispose(); - } + // obj.SetterOnly = val; + // Test.AssertEquals(val, obj.GetSetterOnly()); + // obj.Dispose(); + // } public static void test_class_property() { @@ -436,6 +436,52 @@ class TestCsharpProperties Test.AssertEquals(ret, (1, 2)); obj.Dispose(); } + + public static void test_csharp_keyed_multi_valued_prop() + { + var obj = new Dummy.TestObject(); + obj.KeyedMultiValuedProp[100] = (1, 2); + Test.AssertEquals(obj.KeyedMultiValuedProp[100], (1, 2)); + obj.Dispose(); + } + + public static void test_csharp_multi_keyed_multi_valued_prop() + { + var obj = new Dummy.TestObject(); + obj.MultiKeyedMultiValuedProp[(100, 101)] = (1, 2); + Test.AssertEquals(obj.MultiKeyedMultiValuedProp[(100, 101)], (1, 2)); + obj.Dispose(); + } + + public static void test_csharp_multi_prop() + { + var obj = new Dummy.TestObject(); + obj.MultiKeyedMultiValuedProp[(100, 101)] = (1, 2); + obj.KeyedMultiValuedProp[100] = (1, 2); + Test.AssertEquals(obj.KeyedMultiValuedProp[100], + obj.MultiKeyedMultiValuedProp[(100, 101)]); + int a1, b1, a2, b2; +#if __MonoCS__ + (int a, int b) t1 = obj.MultiKeyedMultiValuedProp[(100, 101)]; + (a1, b1) = (t1.Item1, t1.Item2); + (int a, int b) t2 = obj.KeyedMultiValuedProp[100]; + (a2, b2) = (t2.Item1, t2.Item2); +#else + (a1, b1) = obj.MultiKeyedMultiValuedProp[(100, 101)]; + (a2, b2) = obj.KeyedMultiValuedProp[100]; +#endif + Test.AssertEquals(a1, a2); + Test.AssertEquals(b1, b2); + var i = (100, 101); + var j = 100; + Test.AssertEquals(obj.KeyedMultiValuedProp[j], + obj.MultiKeyedMultiValuedProp[i]); + obj.MultiKeyedMultiValuedProp[i] = (1, 3); + obj.KeyedMultiValuedProp[j] = obj.MultiKeyedMultiValuedProp[i]; + Test.AssertEquals(obj.KeyedMultiValuedProp[j], + obj.MultiKeyedMultiValuedProp[i]); + + } } class TestEoGrandChildrenFinalize diff --git a/src/tests/efl_mono/dummy_event_manager.c b/src/tests/efl_mono/dummy_event_manager.c index 62bdd05c7f..813622929a 100644 --- a/src/tests/efl_mono/dummy_event_manager.c +++ b/src/tests/efl_mono/dummy_event_manager.c @@ -43,6 +43,12 @@ _dummy_event_manager_emitter_set(EINA_UNUSED Eo *obj, Dummy_Event_Manager_Data * pd->emitter = emitter; } +static Efl_Object* +_dummy_event_manager_emitter_get(EINA_UNUSED Eo const *obj, Dummy_Event_Manager_Data *pd) +{ + return pd->emitter; +} + static Eina_Bool _dummy_event_manager_emit_with_int(EINA_UNUSED Eo *obj, Dummy_Event_Manager_Data *pd, int data) { diff --git a/src/tests/efl_mono/dummy_event_manager.eo b/src/tests/efl_mono/dummy_event_manager.eo index b16f7b92cb..5c8b1d0791 100644 --- a/src/tests/efl_mono/dummy_event_manager.eo +++ b/src/tests/efl_mono/dummy_event_manager.eo @@ -4,8 +4,6 @@ class Dummy.Event_Manager extends Efl.Object { methods { @property emitter { - set { - } values { emitter: Efl.Object @move; } diff --git a/src/tests/efl_mono/dummy_test_object.c b/src/tests/efl_mono/dummy_test_object.c index b87aff1cd4..19539906f4 100644 --- a/src/tests/efl_mono/dummy_test_object.c +++ b/src/tests/efl_mono/dummy_test_object.c @@ -16,6 +16,7 @@ #define DUMMY_TEST_IFACE_PROTECTED +#include #include "libefl_mono_native_test.h" typedef struct Dummy_Test_Object_Data @@ -4612,6 +4613,36 @@ void _dummy_test_object_multi_valued_prop_set(Eo* obj EINA_UNUSED, Dummy_Test_Ob pd->prop2 = prop2; } +void _dummy_test_object_keyed_multi_valued_prop_get(Eo const* obj EINA_UNUSED, Dummy_Test_Object_Data* pd, int prop_key1, int* prop1, int* prop2) +{ + assert (prop_key1 == 100); + *prop1 = pd->prop1; + *prop2 = pd->prop2; +} + +void _dummy_test_object_keyed_multi_valued_prop_set(Eo* obj EINA_UNUSED, Dummy_Test_Object_Data* pd, int prop_key1, int prop1, int prop2) +{ + assert (prop_key1 == 100); + pd->prop1 = prop1; + pd->prop2 = prop2; +} + +void _dummy_test_object_multi_keyed_multi_valued_prop_get(Eo const* obj EINA_UNUSED, Dummy_Test_Object_Data* pd, int prop_key1, int prop_key2, int* prop1, int* prop2) +{ + assert (prop_key1 == 100); + assert (prop_key2 == 101); + *prop1 = pd->prop1; + *prop2 = pd->prop2; +} + +void _dummy_test_object_multi_keyed_multi_valued_prop_set(Eo* obj EINA_UNUSED, Dummy_Test_Object_Data* pd, int prop_key1, int prop_key2, int prop1, int prop2) +{ + assert (prop_key1 == 100); + assert (prop_key2 == 101); + pd->prop1 = prop1; + pd->prop2 = prop2; +} + /* Class Properties */ static int _dummy_test_object_klass_prop = 0; diff --git a/src/tests/efl_mono/dummy_test_object.eo b/src/tests/efl_mono/dummy_test_object.eo index cf2ae7ce03..37c08cb495 100644 --- a/src/tests/efl_mono/dummy_test_object.eo +++ b/src/tests/efl_mono/dummy_test_object.eo @@ -1581,6 +1581,31 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface { } } + @property keyed_multi_valued_prop { + get {} + set {} + keys { + key1: int; + } + values { + prop1: int; + prop2: int; + } + } + + @property multi_keyed_multi_valued_prop { + get {} + set {} + keys { + key1: int; + key2: int; + } + values { + prop1: int; + prop2: int; + } + } + @property klass_prop @static { get {} set {}