Summary: Syntatic sugar around the Get/Set functions for now.
Test Plan: Run efl-mono-suite
Reviewers: vitor.sousa, segfaultxavi, felipealmeida, Jaehyun_Cho
Reviewed By: vitor.sousa
Subscribers: cedric
Tags: #efl_language_bindings
Differential Revision: https://phab.enlightenment.org/D7394
return
c_name == "efl_event_callback_array_priority_add"
|| c_name == "efl_player_position_get"
- || c_name == "efl_text_font_source_get"
- || c_name == "efl_text_font_source_set"
- || c_name == "efl_ui_focus_manager_focus_get"
|| c_name == "efl_ui_widget_focus_set"
|| c_name == "efl_ui_widget_focus_get"
|| c_name == "efl_ui_text_password_get"
|| c_name == "elm_interface_scrollable_repeat_events_get"
|| c_name == "elm_interface_scrollable_repeat_events_set"
|| c_name == "elm_wdg_item_del"
- || c_name == "elm_wdg_item_focus_get"
- || c_name == "elm_wdg_item_focus_set"
|| c_name == "elm_interface_scrollable_mirrored_set"
|| c_name == "evas_obj_table_mirrored_get"
|| c_name == "evas_obj_table_mirrored_set"
return name_helpers::alias_full_eolian_name(alias) == "Eina.Error";
}
+inline bool is_property_blacklisted(attributes::property_def const& property)
+{
+ auto name = name_helpers::klass_full_concrete_or_interface_name(property.klass) + "." + name_helpers::property_managed_name(property);
+ return name == "Efl.Input.Key.Key"
+ || name == "Efl.Input.Hold.Hold"
+ || name == "Efl.Text.Text";
+}
+
}
}
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "function_definition_generator: " << f.c_name << std::endl;
- if(!do_super && f.is_static) // Static methods goes only on Concrete classes.
- return true;
if(blacklist::is_function_blacklisted(f.c_name))
return true;
}
} const native_function_definition;
+struct property_wrapper_definition_generator
+{
+ template<typename OutputIterator, typename Context>
+ bool generate(OutputIterator sink, attributes::property_def const& property, Context context) const
+ {
+ if (blacklist::is_property_blacklisted(property))
+ return true;
+
+ bool 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);
+
+
+ if (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;
+
+ attributes::type_def prop_type;
+
+ if (property.getter.is_engaged())
+ prop_type = property.getter->return_type;
+ else if (property.setter.is_engaged())
+ prop_type = property.setter->parameters[0].type;
+ 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]);
+
+ std::string managed_name = name_helpers::property_managed_name(property);
+
+ if (!as_generator(
+ scope_tab << documentation
+ << scope_tab << (interface ? "" : "public ") << (is_static ? "static " : "") << type(true) << " " << managed_name << " {\n"
+ ).generate(sink, std::make_tuple(property, prop_type), context))
+ return false;
+
+ if (property.getter.is_engaged())
+ if (!as_generator(scope_tab << scope_tab << "get " << (interface ? ";" : "{ return Get" + managed_name + "(); }") << "\n"
+ ).generate(sink, attributes::unused, context))
+ return false;
+
+ if (property.setter.is_engaged())
+ if (!as_generator(scope_tab << scope_tab << "set " << (interface ? ";" : "{ Set" + managed_name + "(" + dir_mod + "value); }") << "\n"
+ ).generate(sink, attributes::unused, context))
+ return false;
+
+ if (!as_generator(scope_tab << "}\n").generate(sink, attributes::unused, context))
+ return false;
+
+ return true;
+ }
+} const property_wrapper_definition;
+
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::native_function_definition_generator> : std::true_type {};
template <>
+struct is_eager_generator< ::eolian_mono::property_wrapper_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 {};
template <>
struct is_generator< ::eolian_mono::function_definition_parameterized> : std::true_type {};
+template <>
+struct is_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
namespace type_traits {
template <>
template <>
struct attributes_needed< ::eolian_mono::native_function_definition_generator> : std::integral_constant<int, 1> {};
+
+template <>
+struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator> : std::integral_constant<int, 1> {};
}
} } }
).generate(sink, p, iface_cxt))
return false;
+ if (!as_generator(*(property_wrapper_definition)).generate(sink, cls.properties, iface_cxt))
+ return false;
+
// End of interface declaration
if(!as_generator("}\n").generate(sink, attributes::unused, iface_cxt)) return false;
if(!as_generator(*(async_function_definition)).generate(sink, implemented_methods, concrete_cxt))
return false;
+ // Property wrappers
+ if (!as_generator(*(property_wrapper_definition)).generate(sink, cls.properties, concrete_cxt))
+ return false;
+
+ for (auto&& klass : helpers::non_implemented_interfaces(cls))
+ {
+ attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
+ if (!as_generator(*(property_wrapper_definition)).generate(sink, c.properties, concrete_cxt))
+ return false;
+ }
+
+
if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false;
}
if(!as_generator(*(async_function_definition(true))).generate(sink, implemented_methods, inherit_cxt))
return false;
+ // Property wrappers
+ if (!as_generator(*(property_wrapper_definition)).generate(sink, cls.properties, inherit_cxt))
+ return false;
+
+ for (auto&& klass : helpers::non_implemented_interfaces(cls))
+ {
+ attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
+ if (!as_generator(*(property_wrapper_definition)).generate(sink, c.properties, inherit_cxt))
+ return false;
+ }
+
if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false;
}
return utils::capitalize(in);
}
+inline std::string property_managed_name(attributes::property_def const& property)
+{
+ auto names = utils::split(property.name, '_');
+ // No need to escape keyword here as it will be capitalized and already
+ // namespaced inside the owner class.
+ return utils::to_pascal_case(names);
+}
+
inline std::string managed_part_name(attributes::part_def const& part)
{
std::vector<std::string> names = utils::split(part.name, '_');
}
}
+class TestCsharpProperties
+{
+ public static void test_csharp_properties()
+ {
+ var obj = new Dummy.TestObject();
+ var name = "My Name";
+ obj.Name = name;
+
+ Test.AssertEquals(name, obj.Name);
+ }
+
+ public static void test_getter_only()
+ {
+ var obj = new Dummy.TestObject();
+ Test.Assert(!obj.Invalidating);
+ }
+
+ public static void test_setter_only()
+ {
+ var obj = new Dummy.TestObject();
+ int val = -1984;
+
+ obj.SetterOnly = val;
+ Test.AssertEquals(val, obj.GetSetterOnly());
+ }
+
+ public static void test_class_property()
+ {
+ int val = -42;
+ Dummy.TestObject.KlassProp = val;
+ Test.AssertEquals(val, Dummy.TestObject.KlassProp);
+ }
+
+ public static void test_iface_property()
+ {
+ int val = -33;
+ Dummy.TestIface iface = new Dummy.TestObject();
+ iface.IfaceProp = val;
+ Test.AssertEquals(val, iface.IfaceProp);
+ }
+}
+
}
}
emit_nonconflicted {
}
+ @property iface_prop {
+ get {}
+ set {}
+ values {
+ data: int;
+ }
+ }
}
events {
conflicted: void;
}
return: accessor<ptr(int)> @owned;
}
+
+ @property setter_only {
+ set {}
+ values {
+ prop: int;
+ }
+ }
+
+ get_setter_only {
+ return: int;
+ }
}
implements {
class.constructor;
Efl.Part.part_get;
Dummy.Test_Iface.emit_test_conflicted;
Dummy.Test_Iface.emit_nonconflicted;
+ Dummy.Test_Iface.iface_prop { get; set; }
Dummy.Another_Iface.emit_another_conflicted;
}
events {
Eo *part_two;
Eina_Promise *promise;
Eina_List *list_for_accessor;
+ int setter_only;
+ int iface_prop;
} Dummy_Test_Object_Data;
typedef struct Dummy_Numberwrapper_Data
efl_event_callback_legacy_call(obj, DUMMY_ANOTHER_IFACE_EVENT_CONFLICTED, NULL);
}
+void _dummy_test_object_setter_only_set(EINA_UNUSED Eo *obj, Dummy_Test_Object_Data *pd, int value)
+{
+ pd->setter_only = value;
+}
+
+int _dummy_test_object_get_setter_only(EINA_UNUSED Eo *obj, Dummy_Test_Object_Data *pd)
+{
+ return pd->setter_only;
+}
+void _dummy_test_object_dummy_test_iface_iface_prop_set(EINA_UNUSED Eo *obj, Dummy_Test_Object_Data *pd, int value)
+{
+ pd->iface_prop = value;
+}
+
+int _dummy_test_object_dummy_test_iface_iface_prop_get(EINA_UNUSED const Eo *obj, Dummy_Test_Object_Data *pd)
+{
+ return pd->iface_prop;
+}
#include "dummy_test_object.eo.c"
#include "dummy_numberwrapper.eo.c"