csharp: Add support for efl parts as Properties

Instead of
   var bg = efl.ui.Background.static_cast(myobj.Part("background"));

Now do
   var bg = myobj.Background;

Also a couple helper functions were added.
This commit is contained in:
Lauro Moura 2018-03-19 20:35:36 -03:00 committed by Felipe Magno de Almeida
parent 9a6dd32cb1
commit f9586a831b
8 changed files with 172 additions and 6 deletions

View File

@ -78,6 +78,7 @@ bin_eolian_mono_eolian_mono_SOURCES = \
bin/eolian_mono/eolian/mono/function_registration.hh \
bin/eolian_mono/eolian/mono/enum_definition.hh \
bin/eolian_mono/eolian/mono/struct_definition.hh \
bin/eolian_mono/eolian/mono/part_definition.hh \
bin/eolian_mono/eolian/mono/struct_fields.hh \
bin/eolian_mono/eolian/mono/parameter.hh \
bin/eolian_mono/eolian/mono/utils.hh \
@ -424,6 +425,7 @@ tests_efl_mono_efl_mono_SOURCES = \
tests/efl_mono/Evas.cs \
tests/efl_mono/Events.cs \
tests/efl_mono/FunctionPointers.cs \
tests/efl_mono/Parts.cs \
tests/efl_mono/Strings.cs \
tests/efl_mono/Structs.cs \
tests/efl_mono/TestUtils.cs \

View File

@ -2,6 +2,13 @@
#define EOLIAN_MONO_HELPERS_HH
#include "grammar/klass_def.hpp"
#include "utils.hh"
/* General helper functions for the main generators.
*
* These range from blacklisting structures to 'nano-generators' (functions that receive
* a binding-specifict structure and returns a string).
*/
namespace eolian_mono {
@ -102,9 +109,19 @@ inline bool need_pointer_conversion(attributes::regular_type_def const* regular)
inline std::string to_field_name(std::string const& in)
{
std::string field_name = in;
field_name[0] = std::toupper(field_name[0]); // Hack to allow 'static' as a field name
return field_name;
return utils::capitalize(in);
}
inline std::string klass_name_to_csharp(attributes::klass_name const& clsname)
{
std::ostringstream output;
for (auto namesp : clsname.namespaces)
output << utils::to_lowercase(namesp) << ".";
output << clsname.eolian_name;
return output.str();
}
}

View File

@ -15,6 +15,7 @@
#include "function_registration.hh"
#include "function_declaration.hh"
#include "documentation.hh"
#include "part_definition.hh"
#include "grammar/string.hpp"
#include "grammar/attribute_replace.hpp"
#include "grammar/integral.hpp"
@ -239,6 +240,10 @@ struct klass
return false;
}
for (auto &&p : cls.parts)
if (!as_generator( klass_name_to_csharp(p.klass) << " " << utils::capitalize(p.name) << "{ get;}\n").generate(sink, attributes::unused, iface_cxt))
return false;
// End of interface declaration
if(!as_generator("}\n").generate(sink, attributes::unused, iface_cxt)) return false;
}
@ -331,6 +336,10 @@ struct klass
if (!generate_events_registration(sink, cls, concrete_cxt))
return false;
// Parts
if(!as_generator(*(part_definition))
.generate(sink, cls.get_all_parts(), concrete_cxt)) return false;
// Concrete function definitions
if(!as_generator(*(function_definition))
.generate(sink, methods, concrete_cxt)) return false;
@ -431,6 +440,10 @@ struct klass
if (!generate_events_registration(sink, cls, inherit_cxt))
return false;
// Parts
if(!as_generator(*(part_definition))
.generate(sink, cls.get_all_parts(), inherit_cxt)) return false;
// Inherit function definitions
if(!as_generator(*(function_definition(true)))
.generate(sink, methods, inherit_cxt)) return false;

View File

@ -0,0 +1,52 @@
#ifndef EOLIAN_MONO_PART_DEFINITION_HH
#define EOLIAN_MONO_PART_DEFINITION_HH
#include <Eina.hh>
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "utils.hh"
#include "documentation.hh"
namespace eolian_mono {
struct part_definition_generator
{
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::part_def const& part, Context const& context) const
{
std::string part_klass_name = klass_name_to_csharp(part.klass);
return as_generator(scope_tab << documentation
<< scope_tab << "public " << part_klass_name << " " << utils::capitalize(part.name) << "\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "get\n"
<< scope_tab << scope_tab << "{\n"
<< scope_tab << scope_tab << scope_tab << "efl.Object obj = efl_part(raw_handle, \"" << part.name << "\");\n"
<< scope_tab << scope_tab << scope_tab << "return " << part_klass_name << "Concrete.static_cast(obj);\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
).generate(sink, part.documentation, context);
}
} const part_definition {};
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::part_definition_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::part_definition_generator> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::part_definition_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -4,19 +4,28 @@
#include <string>
#include <algorithm>
/* Compared to the helpers.hh header, these functions are lower level, not dealing with
* binding-specific structures or knowledge */
namespace eolian_mono { namespace utils {
// Helper method to avoid multiple as_generator calls when mixing case strings
std::string to_uppercase(std::string s)
inline std::string to_uppercase(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
return s;
}
std::string to_lowercase(std::string s)
inline std::string to_lowercase(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s;
}
inline std::string capitalize(std::string const &s)
{
std::string ret = s;
ret[0] = std::toupper(ret[0]);
return ret;
}
} }
#endif

View File

@ -0,0 +1,41 @@
#define CODE_ANALYSIS
#pragma warning disable 1591
using System;
using System.Diagnostics.CodeAnalysis;
namespace TestSuite {
[SuppressMessage("Gendarme.Rules.Portability", "DoNotHardcodePathsRule")]
public static class TestParts
{
public static void basic_part_test()
{
test.Testing t = new test.TestingConcrete();
do_part_test(t);
}
private class Child : test.TestingInherit
{
public Child() : base(null) {}
}
public static void inherited_part_test() {
var t = new Child();
do_part_test(t);
}
private static void do_part_test(test.Testing t)
{
var p1 = t.Part1;
var p2 = t.Part2;
Test.Assert(p1 is test.Testing);
Test.AssertEquals("part1", p1.GetName());
Test.Assert(p2 is test.Testing);
Test.AssertEquals("part2", p2.GetName());
}
}
}

View File

@ -34,6 +34,8 @@
#include "test_numberwrapper.eo.h"
#include "test_testing.eo.h"
#include <interfaces/efl_part.eo.h>
#define EQUAL(a, b) ((a) == (b) ? 1 : (fprintf(stderr, "NOT EQUAL! %s:%i (%s)", __FILE__, __LINE__, __FUNCTION__), fflush(stderr), 0))
#define STR_EQUAL(a, b) (strcmp((a), (b)) == 0 ? 1 : (fprintf(stderr, "NOT EQUAL! %s:%i (%s) '%s' != '%s'", __FILE__, __LINE__, __FUNCTION__, (a), (b)), fflush(stderr), 0))
@ -46,6 +48,8 @@ typedef struct Test_Testing_Data
Eina_Value *stored_value;
Test_StructSimple stored_struct;
int stored_int;
Eo *part1;
Eo *part2;
} Test_Testing_Data;
typedef struct Test_Numberwrapper_Data
@ -3714,6 +3718,28 @@ void _test_testing_emit_event_with_obj(Eo *obj, EINA_UNUSED Test_Testing_Data *p
efl_event_callback_legacy_call(obj, TEST_TESTING_EVENT_EVT_WITH_OBJ, data);
}
Efl_Object *_test_testing_efl_part_part(const Eo *obj, Test_Testing_Data *pd, const char *name)
{
if (!strcmp(name, "part1"))
{
if (pd->part1 == NULL)
{
pd->part1 = efl_add(TEST_TESTING_CLASS, obj, efl_name_set(efl_added, "part1"));
}
return pd->part1;
}
else if (!strcmp(name, "part2"))
{
if (pd->part2 == NULL)
{
pd->part2 = efl_add(TEST_TESTING_CLASS, obj, efl_name_set(efl_added, "part2"));
}
return pd->part2;
}
else
return NULL;
}
#include "test_testing.eo.c"
#include "test_numberwrapper.eo.c"

View File

@ -81,7 +81,12 @@ function Test.SimpleCb {
return: int;
};
class Test.Testing (Efl.Object) {
class Test.Testing (Efl.Object, Efl.Part) {
parts {
part1: Test.Testing; [[ Part number one. ]]
part2: Test.Testing; [[ Part number two. ]]
}
methods {
return_object {
return: Test.Testing;
@ -1547,6 +1552,7 @@ class Test.Testing (Efl.Object) {
implements {
class.constructor;
class.destructor;
Efl.Part.part;
}
events {
evt,with,string @hot: string;