csharp: generate helper constructors for structs.
authorLauro Moura <lauromoura@expertisesolutions.com.br>
Thu, 8 Mar 2018 23:43:14 +0000 (15:43 -0800)
committerWonki Kim <wonki_.kim@samsung.com>
Tue, 10 Apr 2018 11:10:52 +0000 (20:10 +0900)
Summary:
C# does not have a literal form for structs (like C++'s {} aggregate
initialization). Before this commit the user would need to explicitly
instantiate a struct and assign the required values to it, like:

   eina.Size2D size;
   size.W = width;
   size.H = height;
   widget.SetSize(size);

As a workaround, this commit generates helper constructor with
parameters corresponding to the struct fields in the order they are
declared. These parameters have default values if one does not want to
explicitly initialize all fields directly. With these constructs, the
above code could be translated to:

   widget.SetSize(new eina.Size2D(width, height));

It should be noted that the constructed struct will live on the managed
memory (GC) instead of the stack.

Test Plan: run "make check"

Reviewers: felipealmeida

Subscribers: cedric

Differential Revision: https://phab.enlightenment.org/D5838

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/Makefile_Efl_Mono.am
src/bin/eolian_mono/eolian/mono/helpers.hh
src/bin/eolian_mono/eolian/mono/struct_definition.hh
src/bin/eolian_mono/eolian/mono/struct_fields.hh [new file with mode: 0644]
src/tests/efl_mono/Structs.cs

index 9344fbd..e442d09 100644 (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/struct_fields.hh \
        bin/eolian_mono/eolian/mono/parameter.hh \
        bin/eolian_mono/eolian/mono/utils.hh \
        bin/eolian_mono/eolian/mono/using_decl.hh \
index 7d013bd..e02fd05 100644 (file)
@@ -76,6 +76,12 @@ inline bool need_pointer_conversion(attributes::regular_type_def const* regular)
    return false;
 }
 
+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;
+}
 
 }
 
index 324e787..a0ff033 100644 (file)
@@ -11,6 +11,7 @@
 #include "keyword.hh"
 #include "using_decl.hh"
 #include "documentation.hh"
+#include "struct_fields.hh"
 
 namespace eolian_mono {
 
@@ -24,13 +25,6 @@ inline std::string binding_struct_internal_name(attributes::struct_def const& st
    return struct_.cxx_name + "_StructInternal";
 }
 
-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;
-}
-
 struct struct_definition_generator
 {
   template <typename OutputIterator, typename Context>
@@ -70,6 +64,21 @@ struct struct_definition_generator
            if (!as_generator("///<summary>Placeholder field</summary>\npublic IntPtr field;\n").generate(sink, nullptr, context))
              return false;
        }
+     else
+       {
+          // Constructor with default parameters for easy struct initialization
+          auto struct_name = binding_struct_name(struct_);
+          if(!as_generator(
+                      scope_tab << "///<summary>Constructor for " << string << ".</summary>\n"
+                      << scope_tab << "public " << string << "(\n"
+                      << ((scope_tab << scope_tab << field_argument_default) % ",\n")
+                      << scope_tab << ")\n"
+                      << scope_tab << "{\n"
+                      << *(scope_tab << scope_tab << field_argument_assignment << ";\n")
+                      << scope_tab << "}\n")
+             .generate(sink, std::make_tuple(struct_name, struct_name, struct_.fields, struct_.fields), context))
+              return false;
+       }
 
      if(!as_generator("}\n").generate(sink, attributes::unused, context)) return false;
 
diff --git a/src/bin/eolian_mono/eolian/mono/struct_fields.hh b/src/bin/eolian_mono/eolian/mono/struct_fields.hh
new file mode 100644 (file)
index 0000000..0cd018b
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef EOLIAN_MONO_STRUCT_FIELDS_HH
+#define EOLIAN_MONO_STRUCT_FIELDS_HH
+
+#include "grammar/generator.hpp"
+#include "grammar/klass_def.hpp"
+#include "grammar/indentation.hpp"
+#include "grammar/list.hpp"
+#include "grammar/alternative.hpp"
+#include "helpers.hh"
+#include "type.hh"
+#include "keyword.hh"
+#include "using_decl.hh"
+#include "documentation.hh"
+
+namespace eolian_mono {
+
+struct field_argument_default_generator
+{
+   template<typename OutputIterator, typename Context>
+   bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
+   {
+       if (!as_generator(type << " " << string << "=default(" << type << ")")
+               .generate(sink, std::make_tuple(field.type, to_field_name(field.name), field.type), context))
+           return false;
+       return true;
+   }
+} const field_argument_default {};
+
+struct field_argument_assignment_generator
+{
+   template<typename OutputIterator, typename Context>
+   bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
+   {
+       if (!as_generator("this." << string << " = " << string)
+               .generate(sink, std::make_tuple(to_field_name(field.name), to_field_name(field.name)), context))
+           return false;
+       return true;
+   }
+} const field_argument_assignment {};
+
+}
+
+namespace efl { namespace eolian { namespace grammar {
+
+template<>
+struct is_eager_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
+template<>
+struct is_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
+
+template<>
+struct is_eager_generator< ::eolian_mono::field_argument_assignment_generator> : std::true_type {};
+template<>
+struct is_generator< ::eolian_mono::field_argument_assignment_generator> : std::true_type {};
+
+namespace type_traits {
+
+template <>
+struct attributes_needed< ::eolian_mono::field_argument_default_generator> : std::integral_constant<int, 1> {};
+
+template <>
+struct attributes_needed< ::eolian_mono::field_argument_assignment_generator> : std::integral_constant<int, 1> {};
+
+}
+
+} } }
+
+#endif
+
index dcdea0d..07917d0 100644 (file)
@@ -245,6 +245,17 @@ class TestStructs
         checkZeroedStructComplex(complex);
     }
 
+    public static void parameter_initialization()
+    {
+        var simple = new test.StructSimple(0x1, 0x2, (char)0x3, 0x4, 0x5);
+        Test.AssertEquals(0x1, simple.Fbyte);
+        Test.AssertEquals(0x2, simple.Fubyte);
+        Test.AssertEquals(0x3, simple.Fchar);
+        Test.AssertEquals(0x4, simple.Fshort);
+        Test.AssertEquals(0x5, simple.Fushort);
+        Test.AssertEquals(0, simple.Fint);
+    }
+
     // As parameters
 
     public static void simple_in()