felipealmeida pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=0954e501fd4008c40b3848de1f2c91bcd53b2f71

commit 0954e501fd4008c40b3848de1f2c91bcd53b2f71
Author: Lauro Moura <[email protected]>
Date:   Fri Dec 20 01:35:23 2019 +0000

    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 <[email protected]>
    Differential Revision: https://phab.enlightenment.org/D10791
---
 src/bin/eolian_mono/eolian/mono/blacklist.hh       |  29 +-
 src/bin/eolian_mono/eolian/mono/documentation.hh   |  52 +-
 .../eolian_mono/eolian/mono/function_definition.hh | 574 +++++++++++++++------
 .../eolian_mono/eolian/mono/generation_contexts.hh |   7 +
 src/bin/eolian_mono/eolian/mono/helpers.hh         | 101 ++++
 src/bin/eolian_mono/eolian/mono/klass.hh           |  14 +-
 src/bin/eolian_mono/eolian/mono/name_helpers.hh    |  61 ++-
 src/bin/eolian_mono/eolian/mono/parameter.hh       |  12 +-
 src/bin/eolian_mono/eolian_mono.cc                 |   3 +-
 src/bindings/mono/efl_mono/GenericModel.cs         |  14 +-
 src/lib/eolian_cxx/grammar/klass_def.hpp           |   2 +-
 src/tests/efl_mono/Eo.cs                           |  62 ++-
 src/tests/efl_mono/dummy_event_manager.c           |   6 +
 src/tests/efl_mono/dummy_event_manager.eo          |   2 -
 src/tests/efl_mono/dummy_test_object.c             |  31 ++
 src/tests/efl_mono/dummy_test_object.eo            |  25 +
 16 files changed, 770 insertions(+), 225 deletions(-)

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<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>
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<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;
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 <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 (get_params != 0 && property.setter->parameters.size() != 
property.getter->parameters.size())
-          return true;
-      }
-
-      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 (name_helpers::klass_concrete_or_interface_name 
(*implementing_klass) == "IMapping")
+      if (false)
       {
-        // 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;
-                          });
+        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;
       }
-        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))
+
+      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)
         {
-           scope = set_scope;
-           set_scope = "";
+          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 (parameters.size() == 1)
+      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 (is_get_public)
-          if (!as_generator(scope_tab << scope_tab << set_scope <<  "get;\n"
-                            ).generate(sink, attributes::unused, context))
-            return false;
-      }
-      else if (property.getter.is_engaged() && get_params == 
0/*parameters.size() == 1 && property.getter.is_engaged()*/)
+      if (has_indexer)
       {
-        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;
+        generate_get_indexer (sink, property, context, get_scope, 
is_interface);
       }
-      else if (parameters.size() >= 1 && property.getter)
+      else
       {
-        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
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<typename Context>
+bool context_want_beta(Context const& context)
+{
+  return 
efl::eolian::grammar::context_find_tag<options_context>(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<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
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<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)
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<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
    {
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<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);
    }
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 <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;
 
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 {}

-- 


Reply via email to