csharp: Property Indexer implementation

Use Indexers to use brackets, eg [i], syntax.

Keys now can be used as following:

var someVal = obj.SomeProperty[key];
obj.SomeProperty[key] = someNewVal;

And for multiple keys:

var someVal = obj.SomeProperty[(key1, key2)];
obj.SomeProperty[(key1, key2)] = someNewVal;

T8384

Reviewed-by: WooHyun Jung <wh0705.jung@samsung.com>
Differential Revision: https://phab.enlightenment.org/D10791
This commit is contained in:
Lauro Moura 2019-12-20 01:35:23 +00:00 committed by Felipe Magno de Almeida
parent ed0572a33a
commit 0954e501fd
16 changed files with 772 additions and 227 deletions

View File

@ -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<std::string>{
// 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<typename Context>

View File

@ -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<typename Context>
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 <see> tag
static std::string ref_conversion(const ::Eolian_Doc_Token *token, const Eolian_State *state, std::string name_tail,
bool want_beta)
template<typename Context>
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<typename Context>
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<options_context>(context);
new_text = syntax_conversion( new_text, context_find_tag<eolian_state_context>(context).state, options.want_beta);
new_text = syntax_conversion( new_text, context_find_tag<eolian_state_context>(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<options_context>(context);
auto state = context_find_tag<eolian_state_context>(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;

View File

@ -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 <typename OutputIterator, typename Context>
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 <typename OutputIterator, typename Context>
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 <typename OutputIterator, typename Context, typename C1, typename C2>
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<attributes::parameter_def> 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<std::string> get_keys;
if(keys.size() != 1)
{
unsigned int i = 0;
for (auto&& key : keys)
{
static_cast<void>(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 <typename OutputIterator, typename Context, typename CK, typename CV>
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 <typename OutputIterator, typename Context, typename CK, typename CV>
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<typename OutputIterator, typename Context>
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<class_context>(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<class_context>(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<attributes::parameter_def> 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<std::string> 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<typename OutputIterator, typename Context>
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<class_context>(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<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::interface_property_indexer_definition_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -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<typename Context>
bool context_want_beta(Context const& context)
{
return efl::eolian::grammar::context_find_tag<options_context>(context).want_beta;
}
}
#endif

View File

@ -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<attributes::constructor_def> 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<has_property_wrapper_bit>(static_cast<int>(self) | static_cast<int>(bit));
return self;
}
bool operator&(has_property_wrapper_bit self, has_property_wrapper_bit bit)
{
return static_cast<int>(self) & static_cast<int>(bit);
}
template <typename Context>
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<class_context>(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<class_context>(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

View File

@ -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;
}

View File

@ -334,28 +334,6 @@ inline std::string to_field_name(std::string const& in)
return utils::capitalize(in);
}
template<typename T>
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<std::string> 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<typename T>
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<typename T>
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<typename T>
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<typename OutputIterator, typename Context>
bool open_namespaces(OutputIterator sink, std::vector<std::string> namespaces, Context const& context)

View File

@ -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<int, 1> {};
struct attributes_needed< ::eolian_mono::parameter_generator> : std::integral_constant<int, 1> {};
}
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<int, 1> {};
struct attributes_needed< ::eolian_mono::marshall_parameter_generator> : std::integral_constant<int, 1> {};
}
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<int, 1> {};
struct attributes_needed< ::eolian_mono::argument_generator> : std::integral_constant<int, 1> {};
}
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 <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{

View File

@ -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)
{

View File

@ -52,7 +52,7 @@ public class GenericModel<T> : Efl.Object, Efl.IModel
/// <summary>Gets the value of the given property in the wrapped model.</summary>
/// <param name="property">The property of the model.</param>
/// <returns>The value of the property.</returns>
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<T> : Efl.Object, Efl.IModel
/// <param name="value">The value of the property.</param>
/// <returns>An <see cref="Eina.Future" /> that resolves when the property has
/// been set or reports an error if it could not be set.</returns>
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<T> : Efl.Object, Efl.IModel
/// <summary>Returns an <see cref="Eina.Future" /> that will resolve when the property is ready to be read.</summary>
/// <param name="property">The property of the model.</param>
/// <returns>An <see cref="Eina.Future" /> that resolves when the property is ready.</returns>
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<T> : Efl.Object, Efl.IModel
/// <param name="count">The size of the range.</param>
/// <returns>An <see cref="Eina.Future" /> that resolves to an
/// <see cref="Eina.Array&lt;T&gt;" /> of children models.</returns>
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<T> : Efl.Object, Efl.IModel
/// <param name="token">The token for the task's cancellation.</param>
/// <returns>Task that resolves when the property has been set or could not
/// be set.</returns>
public System.Threading.Tasks.Task<Eina.Value> SetPropertyAsync( System.String property, Eina.Value value, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
public System.Threading.Tasks.Task<Eina.Value> 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<T> : Efl.Object, Efl.IModel
/// <param name="token">The token for the task's cancellation.</param>
/// <returns>Task that resolves when the given property is ready to be
/// read.</returns>
public System.Threading.Tasks.Task<Eina.Value> GetPropertyReadyAsync( System.String property, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
public System.Threading.Tasks.Task<Eina.Value> GetPropertyReadyAsync(System.String property, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
{
return model.GetPropertyReadyAsync(property, token);
}
@ -162,7 +162,7 @@ public class GenericModel<T> : Efl.Object, Efl.IModel
/// <param name="token">Token to notify the async operation of external request to cancel.</param>
/// <returns>Task that resolves when the desired <see cref="Eina.Array&lt;T&gt;" /> of
/// children models is ready.</returns>
public System.Threading.Tasks.Task<Eina.Value> GetChildrenSliceAsync( uint start, uint count, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
public System.Threading.Tasks.Task<Eina.Value> GetChildrenSliceAsync(uint start, uint count, System.Threading.CancellationToken token=default(System.Threading.CancellationToken))
{
return model.GetChildrenSliceAsync(start, count, token);
}

View File

@ -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);

View File

@ -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

View File

@ -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)
{

View File

@ -4,8 +4,6 @@ class Dummy.Event_Manager extends Efl.Object {
methods {
@property emitter {
set {
}
values {
emitter: Efl.Object @move;
}

View File

@ -16,6 +16,7 @@
#define DUMMY_TEST_IFACE_PROTECTED
#include <assert.h>
#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;

View File

@ -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 {}