eolian_mono: Added code for eolian_mono generator

Based on the eolian_cxx library generators. Buildsystem files will come
in a future commmit.
This commit is contained in:
Lauro Moura 2017-11-23 21:50:16 -03:00
parent 9391407319
commit d93e9ff286
23 changed files with 4607 additions and 0 deletions

1
src/bin/eolian_mono/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/eolian_mono

View File

@ -0,0 +1,74 @@
#ifndef EOLIAN_MONO_ENUM_DEFINITION_HH
#define EOLIAN_MONO_ENUM_DEFINITION_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "type.hh"
#include "keyword.hh"
#include "using_decl.hh"
namespace eolian_mono {
struct enum_definition_generator
{
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::enum_def const& enum_, Context const& context) const
{
std::vector<std::string> cpp_namespaces = escape_namespace(attributes::cpp_namespaces(enum_.namespaces));
auto open_namespace = *("namespace " << string << " { ") << "\n";
if(!as_generator(open_namespace).generate(sink, cpp_namespaces, add_lower_case_context(context))) return false;
if(!as_generator
(
"public enum " << string << "\n{\n"
)
.generate(sink, enum_.cxx_name, context))
return false;
// iterate enum fiels
for(auto first = std::begin(enum_.fields)
, last = std::end(enum_.fields); first != last; ++first)
{
auto name = (*first).name;
auto literal = (*first).value.literal;
name[0] = std::toupper(name[0]); // Hack to allow 'static' as a field name
if (!as_generator
(
string << " = " << string << ",\n"
)
.generate(sink, std::make_tuple(name, literal), context))
return false;
}
if(!as_generator("}\n").generate(sink, attributes::unused, context)) return false;
auto close_namespace = *(lit("} ")) << "\n";
if(!as_generator(close_namespace).generate(sink, cpp_namespaces, context)) return false;
return true;
}
};
enum_definition_generator const enum_definition = {};
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::enum_definition_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::enum_definition_generator> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::enum_definition_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,48 @@
#ifndef EOLIAN_MONO_FUNCTION_BLACKLIST_HH
#define EOLIAN_MONO_FUNCTION_BLACKLIST_HH
namespace eolian_mono {
inline bool is_function_blacklisted(std::string const& c_name)
{
return
c_name == "efl_event_callback_array_priority_add"
|| c_name == "efl_player_position_get"
|| c_name == "efl_image_load_error_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 == "efl_ui_text_password_set"
|| 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 == "edje_obj_load_error_get"
|| c_name == "efl_ui_focus_user_parent_get"
|| c_name == "efl_canvas_object_scale_get" // duplicated signature
|| c_name == "efl_canvas_object_scale_set" // duplicated signature
|| c_name == "efl_ui_format_cb_set"
|| c_name == "efl_access_parent_get"
|| c_name == "efl_access_name_get"
|| c_name == "efl_access_name_set"
|| c_name == "efl_access_root_get"
|| c_name == "efl_access_type_get"
|| c_name == "efl_access_role_get"
|| c_name == "efl_access_action_description_get"
|| c_name == "efl_access_action_description_set"
|| c_name == "efl_access_image_description_get"
|| c_name == "efl_access_image_description_set"
|| c_name == "efl_access_component_layer_get" // duplicated signature
|| c_name == "efl_access_component_alpha_get"
|| c_name == "efl_ui_spin_button_loop_get"
;
}
}
#endif

View File

@ -0,0 +1,49 @@
#ifndef EOLIAN_MONO_FUNCTION_DECLARATION_HH
#define EOLIAN_MONO_FUNCTION_DECLARATION_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "type.hh"
#include "parameter.hh"
#include "keyword.hh"
#include "using_decl.hh"
namespace eolian_mono {
struct function_declaration_generator
{
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
if(is_function_blacklisted(f.c_name))
return true;
else
return as_generator
(eolian_mono::type(true) << " " << string << "(" << (parameter % ", ") << ");\n")
.generate(sink, std::make_tuple(f.return_type, managed_method_name(f.name), f.parameters), context);
}
};
function_declaration_generator const function_declaration = {};
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::function_declaration_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::function_declaration_generator> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::function_declaration_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,223 @@
#ifndef EOLIAN_MONO_FUNCTION_DEFINITION_HH
#define EOLIAN_MONO_FUNCTION_DEFINITION_HH
#include <Eina.hh>
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "grammar/attribute_reorder.hpp"
#include "type.hh"
#include "function_helpers.hh"
#include "marshall_type.hh"
#include "parameter.hh"
#include "keyword.hh"
#include "using_decl.hh"
#include "generation_contexts.hh"
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
{
if(is_function_blacklisted(f.c_name))
return true;
else
{
if(!as_generator
("\n\n" << scope_tab
<< eolian_mono::marshall_native_annotation(true)
<< " public delegate "
<< eolian_mono::marshall_type(true)
<< " "
<< string
<< "_delegate(System.IntPtr obj, System.IntPtr pd"
<< *grammar::attribute_reorder<-1, -1>
(
(", " << marshall_native_annotation << " " << marshall_parameter)
)
<< ");\n")
.generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context))
return false;
if(!as_generator
(scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(context).actual_library_name(f.filename) << ")] "
<< eolian_mono::marshall_native_annotation(true)
<< " public static extern "
<< eolian_mono::marshall_type(true)
<< " " << string
<< "(System.IntPtr obj"
<< *grammar::attribute_reorder<-1, -1>
(
(", " << marshall_native_annotation << " " << marshall_parameter)
)
<< ");\n")
.generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context))
return false;
std::string return_type;
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
return false;
if(!as_generator
(scope_tab
<< " public static "
<< eolian_mono::marshall_type(true) << " "
<< string
<< "(System.IntPtr obj, System.IntPtr pd"
<< *(", " << marshall_parameter)
<< ")\n"
<< scope_tab << "{\n"
/****/
<< scope_tab << scope_tab << "eina.Log.Debug(\"function " << string << " was called\");\n"
/****/
<< scope_tab << scope_tab << "efl.eo.IWrapper wrapper = efl.eo.Globals.data_get(pd);\n"
<< scope_tab << scope_tab << "if(wrapper != null) {\n"
<< scope_tab << scope_tab << scope_tab << eolian_mono::native_function_definition_preamble()
<< scope_tab << scope_tab << scope_tab << "try {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << (return_type != " void" ? "_ret_var = " : "") << "((" << string << "Inherit)wrapper)." << string
<< "(" << (native_argument_invocation % ", ") << ");\n"
<< scope_tab << scope_tab << scope_tab << "} catch (Exception e) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Warning($\"Callback error: {e.ToString()}\");\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "eina.Error.Set(eina.Error.EFL_ERROR);\n"
<< scope_tab << scope_tab << scope_tab << "}\n"
<< eolian_mono::native_function_definition_epilogue(*klass)
<< scope_tab << scope_tab << "} else {\n"
<< scope_tab << scope_tab << scope_tab << (return_type != " void" ? "return " : "") << string
<< "(efl.eo.Globals.efl_super(obj, " << string << "Inherit.klass)" << *(", " << argument) << ");\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
)
.generate(sink, std::make_tuple(f.return_type, escape_keyword(f.name), f.parameters
, /***/f.c_name/***/
, f
, klass->cxx_name, managed_method_name(f.name)
, f.parameters
, f
, f.c_name
, klass->cxx_name, f.parameters
)
, context))
return false;
if(!as_generator
(scope_tab << "public static "
<< string
<< "_delegate "
<< string << "_static_delegate = new " << string << "_delegate(" << string << "NativeInherit." << string << ");\n"
)
.generate(sink, std::make_tuple(f.c_name, f.c_name, f.c_name, klass->cxx_name
, escape_keyword(f.name)), context))
return false;
return true;
}
}
};
struct function_definition_generator
{
function_definition_generator(bool do_super = false)
: do_super(do_super)
{}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
if(is_function_blacklisted(f.c_name))
return true;
else
{
if(!as_generator
("\n\n" << scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(context).actual_library_name(f.filename) << ")]\n"
<< scope_tab << eolian_mono::marshall_annotation(true)
<< " public static extern "
<< eolian_mono::marshall_type(true)
<< " " << string
<< "(System.IntPtr obj"
<< *grammar::attribute_reorder<-1, -1>
(
(", " << marshall_annotation << " " << marshall_parameter)
)
<< ");\n")
.generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context))
return false;
std::string return_type;
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
return false;
if(!as_generator
(scope_tab << (do_super ? "virtual " : "") << "public " << return_type << " " << string << "(" << (parameter % ", ")
<< ") {\n "
<< eolian_mono::function_definition_preamble() << string << "("
<< (do_super ? "efl.eo.Globals.efl_super(" : "")
<< "this.raw_handle"
<< (do_super ? ", this.raw_klass)" : "")
<< *(", " << argument_invocation ) << ");\n"
<< eolian_mono::function_definition_epilogue()
<< " }\n")
.generate(sink, std::make_tuple(managed_method_name(f.name), f.parameters, f, f.c_name, f.parameters, f), context))
return false;
return true;
}
}
bool do_super;
};
struct function_definition_parameterized
{
function_definition_generator operator()(bool do_super) const
{
return {do_super};
}
} const function_definition;
function_definition_generator as_generator(function_definition_parameterized)
{
return {};
}
struct native_function_definition_parameterized
{
native_function_definition_generator operator()(attributes::klass_def const& klass) const
{
return {&klass};
}
} const native_function_definition;
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::function_definition_generator> : std::true_type {};
template <>
struct is_eager_generator< ::eolian_mono::native_function_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 {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::function_definition_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::function_definition_parameterized> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::native_function_definition_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,243 @@
#ifndef EOLIAN_MONO_FUNCTION_DEFINITION_HELPERS_HH
#define EOLIAN_MONO_FUNCTION_DEFINITION_HELPERS_HH
#include <Eina.hh>
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "grammar/attribute_reorder.hpp"
/* #include "type.hh" */
/* #include "marshall_type.hh" */
#include "parameter.hh"
#include "function_pointer.hh"
/* #include "keyword.hh" */
/* #include "using_decl.hh" */
/* #include "generation_contexts.hh" */
namespace eolian_mono {
/*
* Generators for things that must happen inside the function definition *before* and
* *after* the actual invocation of the underlying C function.
*
* For example, declaration and assignment of intermediate variables for out/ return types
* that require some kind of manual work (e.g. string and Stringshare).
*/
struct native_function_definition_preamble_generator
{
// FIXME Suport scoping tabs
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
std::string return_type;
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
return false;
if (!as_generator(
scope_tab << scope_tab << "//Placeholder in variables\n"
<< *(scope_tab << scope_tab << native_convert_in_variable << "\n")
<< scope_tab << scope_tab << "//Placeholder out variables\n"
<< *(scope_tab << scope_tab << native_convert_out_variable << "\n")
<< scope_tab << scope_tab << "//Function pointer wrappers\n"
<< *(scope_tab << scope_tab << native_convert_function_pointer << "\n")
<< scope_tab << scope_tab << "//Return variable and function call\n"
<< scope_tab << scope_tab << scope_tab << native_convert_return_variable << "\n"
).generate(sink, std::make_tuple(f.parameters, f.parameters, f.parameters, f.return_type), context))
return false;
return true;
}
};
struct function_definition_preamble_generator
{
// FIXME Suport scoping tabs
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
std::string return_type;
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
return false;
if (!as_generator(
scope_tab << scope_tab << "//Placeholder in variables\n"
<< *(scope_tab << scope_tab << convert_in_variable << "\n")
<< scope_tab << scope_tab << "//Placeholder out variables\n"
<< *(scope_tab << scope_tab << convert_out_variable << "\n")
<< scope_tab << scope_tab << "//Function pointers handling\n"
<< *(scope_tab << scope_tab << convert_function_pointer << "\n")
<< scope_tab << scope_tab << "//Return variable and function call\n"
<< scope_tab << scope_tab << convert_return_variable
).generate(sink, std::make_tuple(f.parameters, f.parameters, f.parameters, f.return_type), context))
return false;
return true;
}
};
struct native_function_definition_epilogue_generator
{
attributes::klass_def const* klass;
// FIXME Suport scoping tabs
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
std::string return_type;
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
return false;
if (!as_generator(
scope_tab << scope_tab << "//Assigning out variables\n"
<< *(scope_tab << scope_tab << native_convert_out_assign(*klass) << "\n")
<< scope_tab << scope_tab << "//Converting return variable\n"
<< scope_tab << scope_tab << native_convert_return(*klass)
).generate(sink, std::make_tuple(f.parameters, f.return_type), context))
return false;
return true;
}
};
struct function_definition_epilogue_generator
{
// FIXME Suport scoping tabs
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
if (!as_generator(
scope_tab << scope_tab << "eina.Error.RaiseIfOccurred();\n"
<< scope_tab << scope_tab << "//Assigning out variables\n"
<< *(scope_tab << scope_tab << convert_out_assign << "\n")
<< scope_tab << scope_tab << "//Converting return variable\n"
<< scope_tab << scope_tab << convert_return
).generate(sink, std::make_tuple(f.parameters, f.return_type), context))
return false;
return true;
}
};
// Preamble tokens
struct native_function_definition_preamble_terminal
{
native_function_definition_preamble_generator const operator()() const
{
return native_function_definition_preamble_generator();
}
} const native_function_definition_preamble = {};
native_function_definition_preamble_generator const as_generator(native_function_definition_preamble_terminal)
{
return native_function_definition_preamble_generator{};
}
struct function_definition_preamble_terminal
{
function_definition_preamble_generator const operator()() const
{
return function_definition_preamble_generator();
}
} const function_definition_preamble = {};
function_definition_preamble_generator const as_generator(function_definition_preamble_terminal)
{
return function_definition_preamble_generator{};
}
// Epilogue tokens
struct native_function_definition_epilogue_parameterized
{
native_function_definition_epilogue_generator const operator()(attributes::klass_def const& klass) const
{
return {&klass};
}
} const native_function_definition_epilogue;
struct function_definition_epilogue_terminal
{
function_definition_epilogue_generator const operator()() const
{
return function_definition_epilogue_generator();
}
} const function_definition_epilogue = {};
function_definition_epilogue_generator const as_generator(function_definition_epilogue_terminal)
{
return function_definition_epilogue_generator{};
}
} // namespace eolian_mono
namespace efl { namespace eolian { namespace grammar {
// Preamble
template <>
struct is_eager_generator< ::eolian_mono::native_function_definition_preamble_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::native_function_definition_preamble_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::native_function_definition_preamble_terminal> : std::true_type {};
template <>
struct is_eager_generator< ::eolian_mono::function_definition_preamble_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::function_definition_preamble_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::function_definition_preamble_terminal> : std::true_type {};
// Epilogue
template <>
struct is_eager_generator< ::eolian_mono::native_function_definition_epilogue_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::native_function_definition_epilogue_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::native_function_definition_epilogue_parameterized> : std::true_type {};
template <>
struct is_eager_generator< ::eolian_mono::function_definition_epilogue_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::function_definition_epilogue_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::function_definition_epilogue_terminal> : std::true_type {};
namespace type_traits {
// Preamble
template <>
struct attributes_needed< ::eolian_mono::native_function_definition_preamble_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::native_function_definition_preamble_terminal> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::function_definition_preamble_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::function_definition_preamble_terminal> : std::integral_constant<int, 1> {};
// Epilogue
template <>
struct attributes_needed< ::eolian_mono::native_function_definition_epilogue_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::native_function_definition_epilogue_parameterized> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::function_definition_epilogue_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::function_definition_epilogue_terminal> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,95 @@
#ifndef EOLIAN_MONO_FUNCTION_POINTER_HPP
#define EOLIAN_MONO_FUNCTION_POINTER_HPP
#include <Eolian.h>
#include <vector>
#include <string>
namespace eolian_mono {
// Blacklist structs that require some kind of manual binding.
static bool is_function_ptr_blacklisted(attributes::function_def const& func, std::vector<std::string> const &namesp)
{
std::stringstream full_name;
for (auto&& i : namesp)
full_name << i << ".";
full_name << func.name;
std::string name = full_name.str();
return name == "Efl.Ui.Format_Func_Cb";
}
struct function_pointer {
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, std::vector<std::string> const &namesp, Context const& context) const
{
// FIXME export Typedecl in eolian_cxx API
std::vector<std::string> namespaces = escape_namespace(namesp);
if (is_function_ptr_blacklisted(f, namesp))
return true;
auto open_namespace = *("namespace " << string << " {") << "\n";
if(!as_generator(open_namespace).generate(sink, namespaces, add_lower_case_context(context))) return false;
// C# visible delegate
if (!as_generator("public delegate " << type << " " << string
<< "(" << (parameter % ", ") << ");\n")
.generate(sink, std::make_tuple(f.return_type, escape_keyword(f.name), f.parameters), context))
return false;
// "Internal" delegate, 1-to-1 with the Unamaged function type
if (!as_generator("public delegate " << type << " " << string // public?
<< "Internal(IntPtr data, " << (parameter % ", ") << ");\n")
.generate(sink, std::make_tuple(f.return_type, escape_keyword(f.name), f.parameters), context))
return false;
std::string f_name = escape_keyword(f.name);
// Wrapper type, with callback matching the Unamanaged one
if (!as_generator("public class " << f_name << "Wrapper\n"
<< "{\n\n"
<< scope_tab << "private " << f_name << "Internal _cb;\n"
<< scope_tab << "private IntPtr _cb_data;\n"
<< scope_tab << "private Eina_Free_Cb _cb_free_cb;\n\n"
<< scope_tab << "public " << f_name << "Wrapper (" << f_name << "Internal _cb, IntPtr _cb_data, Eina_Free_Cb _cb_free_cb)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "this._cb = _cb;\n"
<< scope_tab << scope_tab << "this._cb_data = _cb_data;\n"
<< scope_tab << scope_tab << "this._cb_free_cb = _cb_free_cb;\n"
<< scope_tab << "}\n\n"
<< scope_tab << "~" << f_name << "Wrapper()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "if (this._cb_free_cb != null)\n"
<< scope_tab << scope_tab << scope_tab << "this._cb_free_cb(this._cb_data);\n"
<< scope_tab << "}\n\n"
<< scope_tab << "public " << type << " ManagedCb(" << (parameter % ",") << ")\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << (f.return_type.c_type != "void" ? "return ": "") << "_cb(_cb_data, " << (argument_invocation % ", ") << ");\n"
<< scope_tab << "}\n\n"
<< scope_tab << "public static " << type << " Cb(IntPtr cb_data, " << (parameter % ", ") << ")\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "GCHandle handle = GCHandle.FromIntPtr(cb_data);\n"
<< scope_tab << scope_tab << string << " cb = (" << string << ")handle.Target;\n"
<< scope_tab << scope_tab << (f.return_type.c_type != "void" ? "return " : "") << "cb(" << (argument_invocation % ", ") << ");\n"
<< scope_tab << "}\n"
<< "}\n"
).generate(sink, std::make_tuple(f.return_type, f.parameters, f.parameters, f.return_type, f.parameters, f_name, f_name, f.parameters), context))
return false;
auto close_namespace = *(lit("} ")) << "\n";
if(!as_generator(close_namespace).generate(sink, namespaces, context)) return false;
return true;
}
};
struct function_pointer const function_pointer = {};
}
#endif

View File

@ -0,0 +1,78 @@
#ifndef EOLIAN_MONO_FUNCTION_REGISTRATION_HH
#define EOLIAN_MONO_FUNCTION_REGISTRATION_HH
#include <Eina.hh>
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "grammar/attribute_reorder.hpp"
#include "type.hh"
#include "marshall_type.hh"
#include "parameter.hh"
#include "keyword.hh"
#include "using_decl.hh"
#include "generation_contexts.hh"
namespace eolian_mono {
template <typename I>
struct function_registration_generator
{
I index_generator;
attributes::klass_def const* klass;
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
{
if(is_function_blacklisted(f.c_name))
return true;
else
{
auto index = index_generator();
if(!as_generator
#ifdef _WIN32
(scope_tab << scope_tab << "descs[" << index << "].api_func = Marshal.StringToHGlobalAnsi(\"" << string << "\");\n"
#else
(scope_tab << scope_tab << "descs[" << index << "].api_func = efl.eo.Globals.dlsym(efl.eo.Globals.RTLD_DEFAULT, \"" << string << "\");\n"
#endif
<< scope_tab << scope_tab << "descs[" << index << "].func = Marshal.GetFunctionPointerForDelegate(" << string << "NativeInherit." << string << "_static_delegate);\n"
)
.generate(sink, std::make_tuple(f.c_name, klass->cxx_name, f.c_name), context))
return false;
return true;
}
}
};
struct function_registration_parameterized
{
template <typename I>
function_registration_generator<I> operator()(I i, attributes::klass_def const& klass) const
{
return {i, &klass};
}
} const function_registration;
}
namespace efl { namespace eolian { namespace grammar {
template <typename I>
struct is_eager_generator< ::eolian_mono::function_registration_generator<I>> : std::true_type {};
template <typename I>
struct is_generator< ::eolian_mono::function_registration_generator<I>> : std::true_type {};
namespace type_traits {
template <typename I>
struct attributes_needed< ::eolian_mono::function_registration_generator<I>> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,42 @@
#ifndef EOLIAN_MONO_GENERATION_CONTEXTS_HH
#define EOLIAN_MONO_GENERATION_CONTEXTS_HH
namespace eolian_mono {
struct class_context
{
enum wrapper_kind {
interface,
concrete,
inherit,
inherit_native,
};
wrapper_kind current_wrapper_kind;
};
struct library_context
{
std::string library_name;
int v_major;
int v_minor;
std::map<const std::string, std::string> references;
const std::string actual_library_name(const std::string& filename) const;
};
const std::string
library_context::actual_library_name(const std::string& filename) const
{
// Libraries mapped follow the efl.Libs.NAME scheme.
// TODO What about references from outside efl (not present in the efl.Libs class?)
auto ref = references.find(filename);
if (ref != references.end())
return "efl.Libs." + ref->second;
// Fallback to original behaviour with explicit library name
return '"' + library_name + '"';
}
}
#endif

View File

@ -0,0 +1,52 @@
#ifndef EOLIAN_CXX_KEYWORD_HH
#define EOLIAN_CXX_KEYWORD_HH
#include <string>
#include <strings.h>
#include <vector>
#include "name_helpers.hh"
namespace eolian_mono {
namespace detail {
inline bool is_iequal(std::string const& lhs, std::string const& rhs)
{
return strcasecmp(lhs.c_str(), rhs.c_str()) == 0;
}
}
inline std::string escape_keyword(std::string const& name)
{
using detail::is_iequal;
if(is_iequal(name, "delete")
|| is_iequal(name, "register")
|| is_iequal(name, "do")
|| is_iequal(name, "lock")
|| is_iequal(name, "event")
|| is_iequal(name, "in")
|| is_iequal(name, "object")
|| is_iequal(name, "interface")
|| is_iequal(name, "string")
|| is_iequal(name, "internal")
|| is_iequal(name, "fixed")
|| is_iequal(name, "base"))
return "kw_" + name;
if (is_iequal(name, "Finalize"))
return name + "Add"; // Eo's Finalize is actually the end of efl_add.
return name;
}
std::string managed_method_name(std::string const& underscore_name)
{
std::vector<std::string> names = name_helpers::split(underscore_name, '_');
name_helpers::reorder_verb(names);
return escape_keyword(name_helpers::pascal_case(names));
}
}
#endif

View File

@ -0,0 +1,745 @@
#ifndef EOLIAN_MONO_CLASS_DEFINITION_HPP
#define EOLIAN_MONO_CLASS_DEFINITION_HPP
#include "grammar/integral.hpp"
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "function_blacklist.hh"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "type.hh"
#include "namespace.hh"
#include "function_definition.hh"
#include "function_registration.hh"
#include "function_declaration.hh"
#include "grammar/string.hpp"
#include "grammar/attribute_replace.hpp"
#include "grammar/integral.hpp"
#include "grammar/case.hpp"
#include "using_decl.hh"
#include "utils.hh"
#include <string>
#include <algorithm>
namespace eolian_mono {
template <typename OutputIterator, typename Context>
static bool generate_static_cast_method(OutputIterator sink, const std::string &class_name, Context const &context)
{
return as_generator(
scope_tab << "public static " << class_name << " static_cast(efl.Object obj)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "if (obj == null)\n"
<< scope_tab << scope_tab << scope_tab << "throw new System.ArgumentNullException(\"obj\");\n"
<< scope_tab << scope_tab << "return new " << class_name << "Concrete(obj.raw_handle);\n"
<< scope_tab << "}\n"
).generate(sink, nullptr, context);
}
template <typename OutputIterator, typename Context>
static bool generate_equals_method(OutputIterator sink, Context const &context)
{
return as_generator(
scope_tab << "public override bool Equals(object obj)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "var other = obj as efl.Object;\n"
<< scope_tab << scope_tab << "if (other == null)\n"
<< scope_tab << scope_tab << scope_tab << "return false;\n"
<< scope_tab << scope_tab << "return this.raw_handle == other.raw_handle;\n"
<< scope_tab << "}\n"
<< scope_tab << "public override int GetHashCode()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "return this.raw_handle.ToInt32();\n"
<< scope_tab << "}\n"
).generate(sink, nullptr, context);
}
/* Get the actual number of functions of a class, checking for blacklisted ones */
static std::size_t
get_function_count(grammar::attributes::klass_def const& cls)
{
auto methods = cls.get_all_methods();
return std::count_if(methods.cbegin(), methods.cend(), [](grammar::attributes::function_def const& func)
{
return !is_function_blacklisted(func.c_name);
});
}
struct get_csharp_type_visitor
{
typedef get_csharp_type_visitor visitor_type;
typedef std::string result_type;
std::string operator()(grammar::attributes::regular_type_def const& type) const
{
std::stringstream csharp_name;
for (auto&& i : escape_namespace(type.namespaces))
csharp_name << utils::to_lowercase(i) << ".";
csharp_name << type.base_type;
return csharp_name.str();
}
std::string operator()(grammar::attributes::klass_name const& name) const
{
std::stringstream csharp_name;
for (auto&& i : escape_namespace(name.namespaces))
csharp_name << utils::to_lowercase(i) << ".";
csharp_name << name.eolian_name;
return csharp_name.str();
}
std::string operator()(attributes::complex_type_def const&) const
{
return "UNSUPPORTED";
}
};
struct get_event_args_visitor
{
std::string arg_type;
typedef get_event_args_visitor visitor_type;
typedef std::string result_type;
std::string operator()(grammar::attributes::regular_type_def const&) const
{
return "(" + arg_type + ")Marshal.PtrToStructure(evt.Info, typeof(" + arg_type + "))";
}
std::string operator()(grammar::attributes::klass_name const&) const
{
return "new " + arg_type + "Concrete(evt.Info)";
}
std::string operator()(attributes::complex_type_def const&) const
{
return "UNSUPPORTED";
}
};
struct klass
{
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
{
std::string suffix, class_type;
switch(cls.type)
{
case attributes::class_type::regular:
case attributes::class_type::abstract_:
class_type = "class";
suffix = "CLASS";
break;
case attributes::class_type::mixin:
class_type = "interface";
suffix = "MIXIN";
break;
case attributes::class_type::interface_:
class_type = "interface";
suffix = "INTERFACE";
break;
}
std::vector<std::string> namespaces = escape_namespace(cls.namespaces);
auto open_namespace = *("namespace " << string << " { ") << "\n";
if(!as_generator(open_namespace).generate(sink, namespaces, add_lower_case_context(context))) return false;
auto methods = cls.get_all_methods();
// FIXME Generate local event argument wrappers
for (auto&& e : cls.events)
{
efl::eina::optional<grammar::attributes::type_def> etype = e.type;
if (!etype.is_engaged())
continue;
std::string evt_name = utils::to_uppercase(e.name);
std::replace(evt_name.begin(), evt_name.end(), ',', '_');
std::string arg_type = (*etype).original_type.visit(get_csharp_type_visitor{});
if (!as_generator("public class " << evt_name << "_Args : EventArgs {\n"
<< scope_tab << "public " << arg_type << " arg { get; set; }\n"
<< "}\n").generate(sink, NULL, context))
return false;
}
// Interface class
{
auto iface_cxt = context_add_tag(class_context{class_context::interface}, context);
if(!as_generator
(
"public " /*<< class_type*/ "interface" /*<<*/ " " << string << " : "
)
.generate(sink, cls.cxx_name, iface_cxt))
return false;
for(auto first = std::begin(cls.immediate_inherits)
, last = std::end(cls.immediate_inherits); first != last; ++first)
{
if(!as_generator("\n" << scope_tab << *(lower_case[string] << ".") << string << " ,")
.generate(sink, std::make_tuple(escape_namespace(first->namespaces), first->eolian_name), iface_cxt))
return false;
// if(std::next(first) != last)
// *sink++ = ',';
}
// if(cls.immediate_inherits.empty())
if(!as_generator("\n" << scope_tab << "efl.eo.IWrapper, IDisposable").generate(sink, attributes::unused, iface_cxt)) return false;
if(!as_generator("\n{\n").generate(sink, attributes::unused, iface_cxt)) return false;
if(!as_generator(*(scope_tab << function_declaration))
.generate(sink, cls.functions, iface_cxt)) return false;
// FIXME Move the event generator into another generator like function?
for (auto &&e : cls.events)
{
std::string wrapper_args_type;
std::string evt_name = utils::to_uppercase(e.name);
std::replace(evt_name.begin(), evt_name.end(), ',', '_');
efl::eina::optional<grammar::attributes::type_def> etype = e.type;
if (etype.is_engaged())
wrapper_args_type = "<" + evt_name + "_Args>";
//FIXME Add a way to generate camelcase names
if (!as_generator(
scope_tab << "event EventHandler" << wrapper_args_type << " "
<< evt_name << ";\n"
).generate(sink, NULL, iface_cxt))
return false;
}
// End of interface declaration
if(!as_generator("}\n").generate(sink, attributes::unused, iface_cxt)) return false;
}
auto class_get_name = *(lower_case[string] << "_") << lower_case[string] << "_class_get";
// Concrete class
// if(class_type == "class")
{
auto concrete_cxt = context_add_tag(class_context{class_context::concrete}, context);
if(!as_generator
(
"public class " << string << "Concrete : " << string << "\n{\n"
<< scope_tab << "System.IntPtr handle;\n"
<< scope_tab << "public System.IntPtr raw_handle {\n"
<< scope_tab << scope_tab << "get { return handle; }\n"
<< scope_tab << "}\n"
<< scope_tab << "public System.IntPtr raw_klass {\n"
<< scope_tab << scope_tab << "get { return efl.eo.Globals.efl_class_get(handle); }\n"
<< scope_tab << "}\n"
<< scope_tab << "public delegate void ConstructingMethod(" << string << " obj);\n"
<< scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename)
<< ")] static extern System.IntPtr\n"
<< scope_tab << scope_tab << class_get_name << "();\n"
<< (class_type == "class" ? "" : "/*")
<< scope_tab << "public " << string << "Concrete(efl.Object parent = null, ConstructingMethod init_cb=null)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "System.IntPtr klass = " << class_get_name << "();\n"
<< scope_tab << scope_tab << "System.IntPtr parent_ptr = System.IntPtr.Zero;\n"
<< scope_tab << scope_tab << "if(parent != null)\n"
<< scope_tab << scope_tab << scope_tab << "parent_ptr = parent.raw_handle;\n"
<< scope_tab << scope_tab << "handle = efl.eo.Globals._efl_add_internal_start(\"file\", 0, klass, parent_ptr, 0, 0);\n"
<< scope_tab << scope_tab << "if (init_cb != null) {\n"
<< scope_tab << scope_tab << scope_tab << "init_cb(this);\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "handle = efl.eo.Globals._efl_add_end(handle, 0, 0);\n" // replace handle with the actual final handle
<< scope_tab << scope_tab << "register_event_proxies();\n"
<< scope_tab << scope_tab << "eina.Error.RaiseIfOccurred();\n"
<< scope_tab << "}\n"
<< (class_type == "class" ? "" : "*/")
<< scope_tab << "public " << string << "Concrete(System.IntPtr raw)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "handle = raw;\n"
<< scope_tab << scope_tab << "register_event_proxies();\n"
<< scope_tab << "}\n"
<< scope_tab << "~" << string << "Concrete()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "Dispose(false);\n"
<< scope_tab << "}\n"
<< scope_tab << "protected virtual void Dispose(bool disposing)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "if (handle != System.IntPtr.Zero) {\n"
<< scope_tab << scope_tab << scope_tab << "efl.eo.Globals.efl_unref(handle);\n"
<< scope_tab << scope_tab << scope_tab << "handle = System.IntPtr.Zero;\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
<< scope_tab << "public void Dispose()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "Dispose(true);\n"
<< scope_tab << scope_tab << "GC.SuppressFinalize(this);\n"
<< scope_tab << "}\n"
)
.generate(sink
, std::make_tuple(
cls.cxx_name, cls.cxx_name, cls.cxx_name, cls.namespaces, cls.eolian_name
, cls.cxx_name, cls.namespaces, cls.eolian_name, cls.cxx_name
, cls.cxx_name)
, concrete_cxt))
return false;
if (!generate_static_cast_method(sink, cls.cxx_name, concrete_cxt))
return false;
if (!generate_equals_method(sink, concrete_cxt))
return false;
if (!generate_events(sink, cls, concrete_cxt))
return false;
if (!generate_events_registration(sink, cls, concrete_cxt))
return false;
// Concrete function definitions
if(!as_generator(*(function_definition))
.generate(sink, methods, concrete_cxt)) return false;
if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false;
}
// Inherit class
if(class_type == "class")
{
auto inherit_cxt = context_add_tag(class_context{class_context::inherit}, context);
bool cls_has_string_return = has_string_return(cls);
bool cls_has_stringshare_return = has_stringshare_return(cls);
if(!as_generator
(
"public " << class_type << " " << string << "Inherit : " << string << "\n{\n"
<< scope_tab << "System.IntPtr handle;\n"
<< scope_tab << "public static System.IntPtr klass = System.IntPtr.Zero;\n"
<< scope_tab << "private static readonly object klassAllocLock = new object();\n"
<< scope_tab << (cls_has_string_return ? ("public Dictionary<String, IntPtr> cached_strings = new Dictionary<String, IntPtr>();") : "") << "\n"
<< scope_tab << (cls_has_stringshare_return ? ("public Dictionary<String, IntPtr> cached_stringshares = new Dictionary<String, IntPtr>();") : "") << "\n"
<< scope_tab << "public System.IntPtr raw_handle {\n"
<< scope_tab << scope_tab << "get { return handle; }\n"
<< scope_tab << "}\n"
<< scope_tab << "public System.IntPtr raw_klass {\n"
<< scope_tab << scope_tab << "get { return klass; }\n"
<< scope_tab << "}\n"
<< scope_tab << "public delegate void ConstructingMethod(" << string << " obj);\n"
<< scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(inherit_cxt).actual_library_name(cls.filename)
<< ")] static extern System.IntPtr\n"
<< scope_tab << scope_tab << class_get_name << "();\n"
<< scope_tab << "public " << string << "Inherit(efl.Object parent = null, ConstructingMethod init_cb=null)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "if (klass == System.IntPtr.Zero) {\n"
<< scope_tab << scope_tab << scope_tab << "lock (klassAllocLock) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (klass == System.IntPtr.Zero) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "klass = efl.eo.Globals.register_class(new efl.eo.Globals.class_initializer(" << string << "NativeInherit.class_initializer), " << class_get_name << "());\n"
//<< scope_tab << scope_tab << "klass = efl.eo.Globals.register_class(null/*new efl.eo.Globals.class_initializer(" << string << "NativeInherit.class_initializer)*/, " << class_get_name << "());\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "handle = efl.eo.Globals.instantiate_start(klass, parent);\n"
<< scope_tab << scope_tab << "if (init_cb != null) {\n"
<< scope_tab << scope_tab << scope_tab << "init_cb(this);\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "handle = efl.eo.Globals.instantiate_end(handle);\n"
<< scope_tab << scope_tab << "efl.eo.Globals.data_set(this);\n"
<< scope_tab << scope_tab << "register_event_proxies();\n"
<< scope_tab << scope_tab << "eina.Error.RaiseIfOccurred();\n"
<< scope_tab << "}\n"
<< scope_tab << "~" << string << "Inherit()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "Dispose(false);\n"
<< scope_tab << "}\n"
<< scope_tab << "protected virtual void Dispose(bool disposing)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "if (handle != System.IntPtr.Zero) {\n"
<< scope_tab << scope_tab << scope_tab << "efl.eo.Globals.efl_unref(handle);\n"
<< scope_tab << scope_tab << scope_tab << "handle = System.IntPtr.Zero;\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
<< scope_tab << "public void Dispose()\n"
<< scope_tab << "{\n"
<< scope_tab << (cls_has_string_return ? "efl.eo.Globals.free_dict_values(cached_strings);" : "") << "\n"
<< scope_tab << (cls_has_stringshare_return ? "efl.eo.Globals.free_stringshare_values(cached_stringshares);" : "") << "\n"
<< scope_tab << scope_tab << "Dispose(true);\n"
<< scope_tab << scope_tab << "GC.SuppressFinalize(this);\n"
<< scope_tab << "}\n"
)
.generate(sink
, std::make_tuple(
cls.cxx_name, cls.cxx_name, cls.cxx_name, cls.namespaces, cls.eolian_name
, cls.cxx_name, cls.cxx_name, cls.namespaces, cls.eolian_name, cls.cxx_name
, cls.cxx_name)
, inherit_cxt))
return false;
if (!generate_static_cast_method(sink, cls.cxx_name, inherit_cxt))
return false;
if (!generate_equals_method(sink, inherit_cxt))
return false;
if (!generate_events(sink, cls, inherit_cxt))
return false;
if (!generate_events_registration(sink, cls, inherit_cxt))
return false;
// Inherit function definitions
if(!as_generator(*(function_definition(true)))
.generate(sink, methods, inherit_cxt)) return false;
if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false;
}
std::size_t function_count = get_function_count(cls);
int function_registration_index = 0;
auto index_generator = [&function_registration_index]
{
return function_registration_index++;
};
// Native Inherit class
if(class_type == "class")
{
auto inative_cxt = context_add_tag(class_context{class_context::inherit_native}, context);
if(!as_generator
(
"public " << class_type << " " << string << "NativeInherit {\n"
<< scope_tab << "public static byte class_initializer(IntPtr klass)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "Efl_Op_Description[] descs = new Efl_Op_Description[" << grammar::int_ << "];\n"
)
.generate(sink, std::make_tuple(cls.cxx_name, function_count), inative_cxt))
return false;
// Native wrapper registration
if(!as_generator(*(function_registration(index_generator, cls)))
.generate(sink, methods, inative_cxt)) return false;
if(!as_generator
( scope_tab << scope_tab << "IntPtr descs_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(descs[0])*" << function_count << ");\n"
<< scope_tab << scope_tab << "IntPtr ptr = descs_ptr;\n"
<< scope_tab << scope_tab << "for(int i = 0; i != " << function_count << "; ++i)\n"
<< scope_tab << scope_tab << "{\n"
<< scope_tab << scope_tab << scope_tab << "Marshal.StructureToPtr(descs[i], ptr, false);\n"
<< scope_tab << scope_tab << scope_tab << "ptr = IntPtr.Add(ptr, Marshal.SizeOf(descs[0]));\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "Efl_Object_Ops ops;\n"
<< scope_tab << scope_tab << "ops.descs = descs_ptr;\n"
<< scope_tab << scope_tab << "ops.count = (UIntPtr)" << function_count << ";\n"
<< scope_tab << scope_tab << "IntPtr ops_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ops));\n"
<< scope_tab << scope_tab << "Marshal.StructureToPtr(ops, ops_ptr, false);\n"
<< scope_tab << scope_tab << "efl.eo.Globals.efl_class_functions_set(klass, ops_ptr, IntPtr.Zero);\n"
).generate(sink, attributes::unused, inative_cxt)) return false;
if(!as_generator(scope_tab << scope_tab << "return 1;\n"
<< scope_tab << "}\n")
.generate(sink, attributes::unused, inative_cxt)) return false;
// Native method definitions
if(!as_generator(*(native_function_definition(cls)))
.generate(sink, methods, inative_cxt)) return false;
if(!as_generator("}\n").generate(sink, attributes::unused, inative_cxt)) return false;
}
auto close_namespace = *(lit("} ")) << "\n";
if(!as_generator(close_namespace).generate(sink, namespaces, context)) return false;
return true;
}
template <typename OutputIterator, typename Context>
bool generate_events_registration(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
{
// Event proxy registration
if (!as_generator(
scope_tab << "private void register_event_proxies()\n"
<< scope_tab << "{\n"
)
.generate(sink, NULL, context))
return false;
// Generate event registrations here
// Assigning the delegates
for (auto&& e : cls.events)
{
if (!as_generator(scope_tab << scope_tab << "evt_" << grammar::string_replace(',', '_') << "_delegate = "
<< "new efl.Event_Cb(on_" << grammar::string_replace(',', '_') << "_NativeCallback);\n")
.generate(sink, std::make_tuple(e.name, e.name), context))
return false;
}
for (auto&& c : cls.inherits)
{
attributes::klass_def klass(get_klass(c, NULL), NULL);
for (auto&& e : klass.events)
{
std::string wrapper_event_name = translate_inherited_event_name(e, klass);
if (!as_generator(scope_tab << scope_tab << "evt_" << wrapper_event_name << "_delegate = "
<< "new efl.Event_Cb(on_" << wrapper_event_name << "_NativeCallback);\n")
.generate(sink, NULL, context))
return false;
}
}
if (!as_generator(
scope_tab << "}\n"
).generate(sink, NULL, context))
return false;
return true;
}
static std::string translate_inherited_event_name(const attributes::event_def &evt, const attributes::klass_def &klass)
{
std::stringstream s;
for (auto&& n : klass.namespaces)
{
s << n;
s << '_';
}
std::string evt_name = utils::to_uppercase(evt.name);
std::replace(evt_name.begin(), evt_name.end(), ',', '_');
s << klass.cxx_name << '_' << evt_name;
return s.str();
}
template <typename OutputIterator, typename Context>
bool generate_events(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
{
if (!has_events(cls))
return true;
if (!as_generator(scope_tab << "private readonly object eventLock = new object();\n"
<< scope_tab << "private Dictionary<string, int> event_cb_count = new Dictionary<string, int>();\n")
.generate(sink, NULL, context))
return false;
// Callback registration functions
if (!as_generator(
scope_tab << "private bool add_cpp_event_handler(string key, efl.Event_Cb evt_delegate) {\n"
<< scope_tab << scope_tab << "int event_count = 0;\n"
<< scope_tab << scope_tab << "if (!event_cb_count.TryGetValue(key, out event_count))\n"
<< scope_tab << scope_tab << scope_tab << "event_cb_count[key] = event_count;\n"
<< scope_tab << scope_tab << "if (event_count == 0) {\n"
<< scope_tab << scope_tab << scope_tab << "efl.kw_event.Description desc = new efl.kw_event.Description(key);\n"
<< scope_tab << scope_tab << scope_tab << "bool result = efl.eo.Globals.efl_event_callback_priority_add(handle, desc, 0, evt_delegate, System.IntPtr.Zero);\n"
<< scope_tab << scope_tab << scope_tab << "if (!result) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Failed to add event proxy for event ${key}\");\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n"
<< scope_tab << scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << scope_tab << "eina.Error.RaiseIfOccurred();\n"
<< scope_tab << scope_tab << "} \n"
<< scope_tab << scope_tab << "event_cb_count[key]++;\n"
<< scope_tab << scope_tab << "return true;\n"
<< scope_tab << "}\n"
<< scope_tab << "private bool remove_cpp_event_handler(string key, efl.Event_Cb evt_delegate) {\n"
<< scope_tab << scope_tab << "int event_count = 0;\n"
<< scope_tab << scope_tab << "if (!event_cb_count.TryGetValue(key, out event_count))\n"
<< scope_tab << scope_tab << scope_tab << "event_cb_count[key] = event_count;\n"
<< scope_tab << scope_tab << "if (event_count == 1) {\n"
<< scope_tab << scope_tab << scope_tab << "efl.kw_event.Description desc = new efl.kw_event.Description(key);\n"
<< scope_tab << scope_tab << scope_tab << "bool result = efl.eo.Globals.efl_event_callback_del(handle, desc, evt_delegate, System.IntPtr.Zero);\n"
<< scope_tab << scope_tab << scope_tab << "if (!result) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Failed to remove event proxy for event ${key}\");\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n"
<< scope_tab << scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << scope_tab << "eina.Error.RaiseIfOccurred();\n"
<< scope_tab << scope_tab << "} else if (event_count == 0) {\n"
<< scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Trying to remove proxy for event ${key} when there is nothing registered.\");\n"
<< scope_tab << scope_tab << scope_tab << "return false;\n"
<< scope_tab << scope_tab << "} \n"
<< scope_tab << scope_tab << "event_cb_count[key]--;\n"
<< scope_tab << scope_tab << "return true;\n"
<< scope_tab << "}\n"
)
.generate(sink, NULL, context))
return false;
// Self events
for (auto&& e : cls.events)
{
std::string upper_name = utils::to_uppercase(e.name);
std::replace(upper_name.begin(), upper_name.end(), ',', '_');
std::string upper_c_name = utils::to_uppercase(e.c_name);
std::string event_name = e.name;
std::replace(event_name.begin(), event_name.end(), ',', '_');
std::string wrapper_args_type = "EventArgs";
std::string wrapper_args_template = "";
std::string event_args = "EventArgs args = EventArgs.Empty;\n";
efl::eina::optional<grammar::attributes::type_def> etype = e.type;
if (etype.is_engaged())
{
wrapper_args_type = upper_name + "_Args";
wrapper_args_template = "<" + wrapper_args_type + ">";
std::string arg_type = wrapper_args_type + " args = new " + wrapper_args_type + "();\n"; // = (*etype).original_type.visit(get_csharp_type_visitor{});
std::string actual_arg_type = (*etype).original_type.visit(get_csharp_type_visitor{});
arg_type += "args.arg = " + (*etype).original_type.visit(get_event_args_visitor{actual_arg_type}) + ";\n";
event_args = arg_type;
}
// Marshal.PtrToStructure for value types
// Wrapper event declaration
if(!as_generator(
scope_tab << "protected event EventHandler" << wrapper_args_template << " " << upper_name << ";\n"
<< scope_tab << "protected void On_" << event_name << "(" << wrapper_args_type << " e)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "EventHandler" << wrapper_args_template << " evt;\n"
<< scope_tab << scope_tab << "lock (eventLock) {\n"
<< scope_tab << scope_tab << scope_tab << "evt = " << upper_name << ";\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "if (evt != null) { evt(this, e); }\n"
<< scope_tab << "}\n"
<< scope_tab << "public void on_" << event_name << "_NativeCallback(System.IntPtr data, ref efl.Event evt)\n"
<< scope_tab << "{\n"
<< scope_tab << event_args
<< scope_tab << scope_tab << "try {\n"
<< scope_tab << scope_tab << scope_tab << "On_" << event_name << "(args);\n"
<< scope_tab << scope_tab << "} catch (Exception e) {\n"
<< scope_tab << scope_tab << scope_tab << "eina.Log.Warning(e.ToString());\n"
<< scope_tab << scope_tab << scope_tab << "eina.Error.Set(eina.Error.EFL_ERROR);\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
<< scope_tab << "efl.Event_Cb evt_" << event_name << "_delegate;\n"
<< scope_tab << "event EventHandler" << wrapper_args_template << " " << cls.cxx_name << "." << upper_name << "{\n")
.generate(sink, NULL, context))
return false;
if (!as_generator(
scope_tab << scope_tab << "add {\n"
<< scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (add_cpp_event_handler(key, this.evt_" << event_name << "_delegate))\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << upper_name << " += value;\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "else\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Error adding proxy for event ${key}\");\n"
<< scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "remove {\n"
<< scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (remove_cpp_event_handler(key, this.evt_" << event_name << "_delegate))\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << upper_name << " -= value;\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "else\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Error removing proxy for event ${key}\");\n"
<< scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n")
.generate(sink, NULL, context))
return false;
}
// Inherited events
for (auto&& c : cls.inherits)
{
attributes::klass_def klass(get_klass(c, NULL), NULL);
// FIXME Enable inherited events registration. Beware of conflicting events
for (auto&& e : klass.events)
{
std::string wrapper_evt_name = translate_inherited_event_name(e, klass);
std::string upper_name = utils::to_uppercase(e.name);
std::replace(upper_name.begin(), upper_name.end(), ',', '_');
std::string upper_c_name = utils::to_uppercase(e.c_name);
std::stringstream wrapper_args_type;
std::string wrapper_args_template;
std::string event_args = "EventArgs args = EventArgs.Empty;\n";
efl::eina::optional<grammar::attributes::type_def> etype = e.type;
if (etype.is_engaged())
{
for (auto&& i : klass.namespaces)
{
wrapper_args_type << escape_keyword(utils::to_lowercase(i)) << ".";
}
wrapper_args_type << upper_name << "_Args";
wrapper_args_template = "<" + wrapper_args_type.str() + ">";
std::string arg_type = wrapper_args_type.str() + " args = new " + wrapper_args_type.str() + "();\n"; // = (*etype).original_type.visit(get_csharp_type_visitor{});
std::string actual_arg_type = (*etype).original_type.visit(get_csharp_type_visitor{});
arg_type += "args.arg = " + (*etype).original_type.visit(get_event_args_visitor{actual_arg_type}) + ";\n";
event_args = arg_type;
}
else
{
wrapper_args_type << "EventArgs";
}
if (!as_generator(
scope_tab << "protected event EventHandler" << wrapper_args_template << " " << wrapper_evt_name << ";\n"
<< scope_tab << "protected void On_" << wrapper_evt_name << "(" << wrapper_args_type.str() << " e)\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "EventHandler" << wrapper_args_template << " evt;\n"
<< scope_tab << scope_tab << "lock (eventLock) {\n"
<< scope_tab << scope_tab << scope_tab << "evt = " << wrapper_evt_name << ";\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "if (evt != null) { evt(this, e); }\n"
<< scope_tab << "}\n"
<< scope_tab << "efl.Event_Cb evt_" << wrapper_evt_name << "_delegate;\n"
<< scope_tab << "protected void on_" << wrapper_evt_name << "_NativeCallback(System.IntPtr data, ref efl.Event evt)"
<< scope_tab << "{\n"
<< scope_tab << event_args
<< scope_tab << scope_tab << "try {\n"
<< scope_tab << scope_tab << scope_tab << "On_" << wrapper_evt_name << "(args);\n"
<< scope_tab << scope_tab << "} catch (Exception e) {\n"
<< scope_tab << scope_tab << scope_tab << "eina.Log.Warning(e.ToString());\n"
<< scope_tab << scope_tab << scope_tab << "eina.Error.Set(eina.Error.EFL_ERROR);\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
<< scope_tab << "event EventHandler" << wrapper_args_template << " " << *(lower_case[string] << ".") << klass.cxx_name << ".")
.generate(sink, escape_namespace(klass.namespaces), context))
return false;
if (!as_generator(upper_name << " {\n"
<< scope_tab << scope_tab << "add {\n"
<< scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (add_cpp_event_handler(key, this.evt_" << wrapper_evt_name << "_delegate))\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << wrapper_evt_name << " += value;\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "else\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Error adding proxy for event ${key}\");\n"
<< scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "remove {\n"
<< scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (remove_cpp_event_handler(key, this.evt_" << wrapper_evt_name << "_delegate))\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << wrapper_evt_name << " -= value;\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "else\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eina.Log.Error(\"Error removing proxy for event ${key}\");\n"
<< scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n")
.generate(sink, NULL, context))
return false;
}
}
return true;
}
};
struct klass const klass = {};
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator<struct ::eolian_mono::klass> : std::true_type {};
template <>
struct is_generator<struct ::eolian_mono::klass> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed<struct ::eolian_mono::klass> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,246 @@
#ifndef EOLIAN_MONO_MARSHALL_ANNOTATION_IMPL_HH
#define EOLIAN_MONO_MARSHALL_ANNOTATION_IMPL_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/case.hpp"
#include "namespace.hh"
#include "type_impl.hh"
namespace eolian_mono {
namespace eina = efl::eina;
namespace detail {
template <typename Array, typename F, int N, typename A>
eina::optional<bool> call_annotation_match(Array const (&array)[N], F f, A a)
{
typedef Array const* iterator_type;
iterator_type match_iterator = &array[0], match_last = match_iterator + N;
match_iterator = std::find_if(match_iterator, match_last, f);
if(match_iterator != match_last)
{
return a(match_iterator->function());
}
return {nullptr};
}
template <typename OutputIterator, typename Context>
struct marshall_annotation_visitor_generate
{
mutable OutputIterator sink;
Context const* context;
std::string c_type;
bool is_out;
bool is_return;
bool is_ptr;
typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type;
typedef bool result_type;
bool operator()(attributes::regular_type_def const& regular) const
{
using attributes::regular_type_def;
struct match
{
eina::optional<std::string> name;
eina::optional<bool> has_own;
std::function<std::string()> function;
};
match const parameter_match_table[] =
{
// signed primitives
{"bool", nullptr, [&] { return " [MarshalAs(UnmanagedType.I1)]"; }},
{"string", true, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringPassOwnershipMarshaler))]";
}},
{"string", false, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringKeepOwnershipMarshaler))]";
}},
{"mstring", true, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringPassOwnershipMarshaler))]";
}},
{"mstring", false, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringKeepOwnershipMarshaler))]";
}},
{"stringshare", true, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringsharePassOwnershipMarshaler))]";
}},
{"stringshare", false, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringshareKeepOwnershipMarshaler))]";
}},
{"any_value_ptr", true, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(eina.ValueMarshalerOwn))]";
}},
{"any_value_ptr", false, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(eina.ValueMarshaler))]";
}},
};
match const return_match_table[] =
{
// signed primitives
{"bool", nullptr, [&] { return " [return: MarshalAs(UnmanagedType.I1)]"; }},
{"string", true, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringPassOwnershipMarshaler))]";
}},
{"string", false, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringKeepOwnershipMarshaler))]";
}},
{"mstring", true, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringPassOwnershipMarshaler))]";
}},
{"mstring", false, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringKeepOwnershipMarshaler))]";
}},
{"stringshare", true, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringsharePassOwnershipMarshaler))]";
}},
{"stringshare", false, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringshareKeepOwnershipMarshaler))]";
}},
{"any_value_ptr", true, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(eina.ValueMarshalerOwn))]";
}},
{"any_value_ptr", false, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(eina.ValueMarshaler))]";
}},
};
if(eina::optional<bool> b = call_annotation_match
((is_return ? return_match_table : parameter_match_table)
, [&] (match const& m)
{
return (!m.name || *m.name == regular.base_type)
&& (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
;
}
, [&] (std::string const& string)
{
std::copy(string.begin(), string.end(), sink);
return true;
}))
{
return *b;
}
else
{
return true;
}
}
bool operator()(attributes::klass_name const& klass_name) const
{
const char no_return_prefix[] = "[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(efl.eo.MarshalTest<";
const char return_prefix[] = "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(efl.eo.MarshalTest<";
std::vector<std::string> namespaces = escape_namespace(klass_name.namespaces);
return as_generator
((is_return ? return_prefix : no_return_prefix)
<< *(lower_case[string] << ".") << string
<< "Concrete, efl.eo." << (klass_name.base_qualifier & qualifier_info::is_own ? "OwnTag" : "NonOwnTag") << ">))]"
).generate(sink, std::make_tuple(namespaces, klass_name.eolian_name), *context);
}
bool operator()(attributes::complex_type_def const&) const
{
return true;
}
};
template <typename OutputIterator, typename Context>
struct marshall_native_annotation_visitor_generate
{
mutable OutputIterator sink;
Context const* context;
std::string c_type;
bool is_out;
bool is_return;
bool is_ptr;
typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type;
typedef bool result_type;
bool operator()(attributes::regular_type_def const& regular) const
{
using attributes::regular_type_def;
struct match
{
eina::optional<std::string> name;
eina::optional<bool> has_own;
std::function<std::string()> function;
};
match const parameter_match_table[] =
{
// signed primitives
{"bool", nullptr, [&] { return " [MarshalAs(UnmanagedType.I1)]"; }},
{"string", true, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringPassOwnershipMarshaler))]";
}},
{"string", false, [&] {
if (is_out)
return "";
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringKeepOwnershipMarshaler))]";
}},
{"stringshare", true, [&] {
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringsharePassOwnershipMarshaler))]";
}},
{"stringshare", false, [&] {
if (is_out)
return "";
return " [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringshareKeepOwnershipMarshaler))]";
}},
};
match const return_match_table[] =
{
// signed primitives
{"bool", nullptr, [&] { return " [return: MarshalAs(UnmanagedType.I1)]"; }},
{"string", true, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringPassOwnershipMarshaler))]";
}},
{"string", false, [&] { return ""; }},
{"stringshare", true, [&] {
return " [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(efl.eo.StringsharePassOwnershipMarshaler))]";
}},
{"stringshare", false, [&] { return ""; }},
};
if(eina::optional<bool> b = call_annotation_match
((is_return ? return_match_table : parameter_match_table)
, [&] (match const& m)
{
return (!m.name || *m.name == regular.base_type)
&& (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
;
}
, [&] (std::string const& string)
{
std::copy(string.begin(), string.end(), sink);
return true;
}))
{
return *b;
}
else
{
return true;
}
}
bool operator()(attributes::klass_name const& klass_name) const
{
const char no_return_prefix[] = "[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(efl.eo.MarshalTest<";
const char return_prefix[] = "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(efl.eo.MarshalTest<";
std::vector<std::string> namespaces = escape_namespace(klass_name.namespaces);
return as_generator
((is_return ? return_prefix : no_return_prefix)
<< *(lower_case[string] << ".") << string
<< "Concrete, efl.eo." << (klass_name.base_qualifier & qualifier_info::is_own ? "OwnTag" : "NonOwnTag") << ">))]"
).generate(sink, std::make_tuple(namespaces, klass_name.eolian_name), *context);
}
bool operator()(attributes::complex_type_def const&) const
{
return true;
}
};
} }
#endif

View File

@ -0,0 +1,165 @@
#ifndef EOLIAN_MONO_MARSHALL_TYPE_HH
#define EOLIAN_MONO_MARSHALL_TYPE_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/case.hpp"
namespace eolian_mono {
namespace attributes = efl::eolian::grammar::attributes;
namespace detail {
template <typename OutputIterator, typename Context>
struct marshall_type_visitor_generate;
template <typename OutputIterator, typename Context>
struct marshall_annotation_visitor_generate;
template <typename OutputIterator, typename Context>
struct marshall_native_annotation_visitor_generate;
}
struct marshall_type_generator
{
marshall_type_generator(bool is_return = false)
: is_return(is_return) {}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& type, Context const& context) const
{
return type.original_type.visit(detail::marshall_type_visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr });
}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
return param.type.original_type.visit(detail::marshall_type_visitor_generate<OutputIterator, Context>{sink, &context, param.type.c_type
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr});
}
bool is_return;
};
struct marshall_annotation_generator
{
marshall_annotation_generator(bool is_return = false)
: is_return(is_return) {}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& type, Context const& context) const
{
return type.original_type.visit(detail::marshall_annotation_visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr});
}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
return param.type.original_type.visit(detail::marshall_annotation_visitor_generate<OutputIterator, Context>{sink, &context, param.type.c_type
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr});
}
bool is_return;
};
struct marshall_native_annotation_generator
{
marshall_native_annotation_generator(bool is_return = false)
: is_return(is_return) {}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& type, Context const& context) const
{
return type.original_type.visit(detail::marshall_native_annotation_visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr});
}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
return param.type.original_type.visit(detail::marshall_native_annotation_visitor_generate<OutputIterator, Context>{sink, &context, param.type.c_type
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr});
}
bool is_return;
};
struct marshall_type_terminal
{
marshall_type_generator const operator()(bool is_return) const
{
return marshall_type_generator(is_return);
}
} const marshall_type = {};
marshall_type_generator const as_generator(marshall_type_terminal)
{
return marshall_type_generator{};
}
struct marshall_annotation_terminal
{
marshall_annotation_generator const operator()(bool is_return) const
{
return marshall_annotation_generator(is_return);
}
} const marshall_annotation = {};
marshall_annotation_generator const as_generator(marshall_annotation_terminal)
{
return marshall_annotation_generator{};
}
struct marshall_native_annotation_terminal
{
marshall_native_annotation_generator const operator()(bool is_return) const
{
return marshall_native_annotation_generator(is_return);
}
} const marshall_native_annotation = {};
marshall_native_annotation_generator const as_generator(marshall_native_annotation_terminal)
{
return marshall_native_annotation_generator{};
}
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::marshall_type_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::marshall_type_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::marshall_type_terminal> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::marshall_type_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::marshall_type_terminal> : std::integral_constant<int, 1> {};
}
template <>
struct is_eager_generator< ::eolian_mono::marshall_annotation_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::marshall_annotation_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::marshall_annotation_terminal> : std::true_type {};
template <>
struct is_eager_generator< ::eolian_mono::marshall_native_annotation_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::marshall_native_annotation_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::marshall_native_annotation_terminal> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::marshall_annotation_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::marshall_annotation_terminal> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::marshall_native_annotation_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::marshall_native_annotation_terminal> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,263 @@
#ifndef EOLIAN_MONO_MARSHALL_TYPE_IMPL_HH
#define EOLIAN_MONO_MARSHALL_TYPE_IMPL_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/case.hpp"
#include "namespace.hh"
#include "type_impl.hh"
#include "generation_contexts.hh"
namespace eolian_mono {
namespace eina = efl::eina;
namespace detail {
template <typename OutputIterator, typename Context>
struct marshall_type_visitor_generate
{
mutable OutputIterator sink;
Context const* context;
std::string c_type;
bool is_out;
bool is_return;
bool is_ptr;
typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type;
typedef bool result_type;
bool operator()(attributes::regular_type_def const& regular) const
{
using attributes::regular_type_def;
bool is_inherit_native = context_find_tag<class_context>(*context).current_wrapper_kind == class_context::inherit_native;
struct match
{
eina::optional<std::string> name;
eina::optional<bool> has_own;
std::function<attributes::type_def::variant_type()> function;
}
const match_table[] =
{
// signed primitives
{"string", true, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
// if(is_out || is_return)
return replace_base_type(r, " System.String");
// else return replace_base_type(r, " ::efl::eina::string_view");
}}
, {"string", false, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
if (is_inherit_native && (is_return || is_out))
return replace_base_type(r, " System.IntPtr");
return replace_base_type(r, " System.String");
}}
, {"mstring", true, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
// if(is_out || is_return)
return replace_base_type(r, " System.String");
// else return replace_base_type(r, " ::efl::eina::string_view");
}}
, {"mstring", false, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
if (is_inherit_native && (is_return || is_out))
return replace_base_type(r, " System.IntPtr");
return replace_base_type(r, " System.String");
}}
, {"stringshare", true, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
return replace_base_type(r, " System.String");
}}
, {"stringshare", false, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
if (is_inherit_native && (is_return || is_out))
return replace_base_type(r, " System.IntPtr");
else
return replace_base_type(r, " System.String");
}}
, {"Binbuf", true, [&]
{
regular_type_def r = regular;
r.base_type = " System.IntPtr";
r.namespaces.clear();
return r;
}}
, {"Binbuf", false, [&]
{
regular_type_def r = regular;
r.base_type = " System.IntPtr";
r.namespaces.clear();
return r;
}}
, {"any_value", true, [&]
{
regular_type_def r = regular;
r.namespaces.clear();
if (is_ptr)
r.base_type = " eina.Value";
else
r.base_type = " eina.Value_Native";
return r;
}}
, {"any_value", false, [&]
{
regular_type_def r = regular;
r.namespaces.clear();
if (is_ptr)
r.base_type = " eina.Value";
else
r.base_type = " eina.Value_Native";
return r;
}}
, {"any_value_ptr", true, [&]
{
regular_type_def r = regular;
r.namespaces.clear();
r.base_type = " eina.Value";
return r;
}}
, {"any_value_ptr", false, [&]
{
regular_type_def r = regular;
r.namespaces.clear();
r.base_type = " eina.Value";
return r;
}}
, {"void", nullptr, [&]
{
regular_type_def r = regular;
r.namespaces.clear();
if (is_out) // @inout too
r.base_type = " System.IntPtr";
else
r.base_type = " void";
return r;
}}
};
if(eina::optional<bool> b = call_match
(match_table
, [&] (match const& m)
{
return (!m.name || *m.name == regular.base_type)
&& (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
;
}
, [&] (attributes::type_def::variant_type const& v)
{
return v.visit(*this); // we want to keep is_out info
}))
{
return *b;
}
else
{
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return}(regular);
}
}
bool operator()(attributes::klass_name klass_name) const
{
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return}(klass_name);
// return as_generator(" System.IntPtr").generate(sink, attributes::unused, *context);
}
bool operator()(attributes::complex_type_def const& complex) const
{
using attributes::regular_type_def;
using attributes::qualifier_info;
struct match
{
eina::optional<std::string> name;
eina::optional<bool> has_own;
eina::optional<bool> is_const;
std::function<attributes::type_def::variant_type()> function;
} const matches[] =
{
{"array", nullptr, nullptr, [&]
{
return regular_type_def{" System.IntPtr", complex.outer.base_qualifier, {}};
}
}
,{"inarray", nullptr, nullptr, [&]
{
return regular_type_def{" System.IntPtr", complex.outer.base_qualifier, {}};
}
}
,{"list", nullptr, nullptr, [&]
{
return regular_type_def{" System.IntPtr", complex.outer.base_qualifier, {}};
}
}
,{"inlist", nullptr, nullptr, [&]
{
return regular_type_def{" System.IntPtr", complex.outer.base_qualifier, {}};
}
}
,{"hash", nullptr, nullptr, [&]
{
return regular_type_def{" System.IntPtr", complex.outer.base_qualifier, {}};
}
}
,{"iterator", nullptr, nullptr, [&]
{
return regular_type_def{" System.IntPtr", complex.outer.base_qualifier, {}};
}
}
};
auto default_match = [&] (attributes::complex_type_def const& complex)
{
regular_type_def no_pointer_regular = complex.outer;
// std::vector<attributes::pointer_indirection> pointers;
// pointers.swap(no_pointer_regular.pointers);
// if(is_out)
// pointers.push_back({{attributes::qualifier_info::is_none, {}}, true});
return visitor_type{sink, context, c_type, false}(no_pointer_regular)
&& as_generator("<" << (type % ", ") << ">").generate(sink, complex.subtypes, *context)
;
// && detail::generate_pointers(sink, pointers, *context, false);
};
if(eina::optional<bool> b = call_match
(matches
, [&] (match const& m)
{
return (!m.name || *m.name == complex.outer.base_type)
&& (!m.has_own || *m.has_own == bool(complex.outer.base_qualifier & qualifier_info::is_own))
&& (!m.is_const || *m.is_const == bool(complex.outer.base_qualifier & qualifier_info::is_const));
}
, [&] (attributes::type_def::variant_type const& v)
{
if(v.empty())
return true;
else if(attributes::complex_type_def const* complex
= eina::get<attributes::complex_type_def>(&v))
return default_match(*complex);
else
return v.visit(*this);
}))
{
return *b;
}
//return default_match(complex);
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return}(complex);
// return as_generator(" System.IntPtr").generate(sink, attributes::unused, *context);
}
};
} }
#endif

View File

@ -0,0 +1,139 @@
#ifndef EOLIAN_MONO_NAME_HELPERS_HH
#define EOLIAN_MONO_NAME_HELPERS_HH
#include <algorithm>
#include <cctype>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
namespace eolian_mono {
namespace name_helpers {
static const std::vector<std::string> verbs =
{
"add",
"get",
"is",
"del",
"thaw",
"freeze",
"save",
"wait",
"eject",
"raise",
"lower",
"load",
"dup",
"reset",
"unload",
"close",
"set",
"interpolate",
"has",
"grab",
"check",
"find",
"ungrab",
"unset",
"clear",
"pop",
"new",
"peek",
"push",
"update",
"show",
"move",
"hide",
"calculate",
"resize",
"attach",
"pack",
"unpack",
"emit",
"call",
"append"
};
const std::vector<std::string> not_verbs =
{
"below",
"above",
"name",
"unfreezable",
"value",
"r",
"g",
"b",
"a",
"finalize",
"destructor",
"to",
"circle",
"rect",
"path",
"commands",
"type",
"colorspace"
"op",
"type",
"properties",
"status",
"status",
"relative",
"ptr",
"pair",
"pos",
"end"
};
void reorder_verb(std::vector<std::string> &names)
{
if (names.size() <= 1)
return;
std::string verb = names.back();
if (std::find(verbs.begin(), verbs.end(), verb) != verbs.end())
{
names.pop_back();
names.insert(names.begin(), verb);
}
}
std::vector<std::string> split(std::string const &input, char delim)
{
std::stringstream ss(input);
std::string name;
std::vector<std::string> names;
while (std::getline(ss, name, delim)) {
if (!name.empty())
names.push_back(name);
}
return names;
}
std::string pascal_case(const std::vector<std::string> &names)
{
std::vector<std::string> outv(names.size());
std::stringstream osstream;
std::transform(names.begin(), names.end(), outv.begin(),
[](std::string name) {
name[0] = std::toupper(name[0]);
return name;
});
std::copy(outv.begin(), outv.end(), std::ostream_iterator<std::string>(osstream, ""));
return osstream.str();
}
} // namespace name_helpers
} // namespace eolian_mono
#endif

View File

@ -0,0 +1,27 @@
#ifndef EOLIAN_MONO_NAMESPACE_HH
#define EOLIAN_MONO_NAMESPACE_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/case.hpp"
#include "grammar/type.hpp"
#include "using_decl.hh"
#include "keyword.hh"
namespace eolian_mono {
std::vector<std::string> escape_namespace(std::vector<std::string> namespaces)
{
// if(namespaces.empty())
// namespaces.push_back("nonamespace");
// else
{
for(auto&& i : namespaces)
i = escape_keyword(i);
}
return namespaces;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
#ifndef EOLIAN_MONO_STRUCT_DEFINITION_HH
#define EOLIAN_MONO_STRUCT_DEFINITION_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/indentation.hpp"
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "type.hh"
#include "keyword.hh"
#include "using_decl.hh"
namespace eolian_mono {
// Blacklist structs that require some kind of manual binding.
static bool is_struct_blacklisted(attributes::struct_def const& struct_)
{
std::string full_name;
for (auto it=struct_.namespaces.begin(); it != struct_.namespaces.end(); it++)
{
full_name += *it + ".";
}
full_name += struct_.cxx_name;
return full_name == "Efl.Event.Description"
|| full_name == "Eina.File"
|| full_name == "Eina.Binbuf"
|| full_name == "Eina.Slice"
|| full_name == "Eina.Rw_Slice";
}
struct struct_definition_generator
{
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
{
if (is_struct_blacklisted(struct_))
return true;
std::vector<std::string> cpp_namespaces = escape_namespace(attributes::cpp_namespaces(struct_.namespaces));
auto open_namespace = *("namespace " << string << " { ") << "\n";
if(!as_generator(open_namespace).generate(sink, cpp_namespaces, add_lower_case_context(context))) return false;
if(!as_generator
(
"public struct " << string << "\n{\n"
)
.generate(sink, struct_.cxx_name, context))
return false;
// iterate enum fiels
for(auto first = std::begin(struct_.fields)
, last = std::end(struct_.fields); first != last; ++first)
{
auto field_name = (*first).name;
auto field_type = (*first).type;
field_name[0] = std::toupper(field_name[0]); // Hack to allow 'static' as a field name
if (!as_generator
(
"public " << type << " " << string << ";\n"
)
.generate(sink, std::make_tuple(field_type, field_name), context))
return false;
}
if(!as_generator("}\n").generate(sink, attributes::unused, context)) return false;
auto close_namespace = *(lit("} ")) << "\n";
if(!as_generator(close_namespace).generate(sink, cpp_namespaces, context)) return false;
return true;
}
};
struct_definition_generator const struct_definition = {};
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::struct_definition_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::struct_definition_generator> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::struct_definition_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,68 @@
#ifndef EOLIAN_MONO_TYPE_HH
#define EOLIAN_MONO_TYPE_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/case.hpp"
namespace eolian_mono {
namespace attributes = efl::eolian::grammar::attributes;
template <typename OutputIterator, typename Context>
struct visitor_generate;
struct type_generator
{
type_generator(bool is_return = false)
: is_return(is_return) {}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& type, Context const& context) const
{
return type.original_type.visit(visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return});
}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
return param.type.original_type.visit(visitor_generate<OutputIterator, Context>{sink, &context, param.type.c_type
, param.direction != attributes::parameter_direction::in, false});
}
bool is_return;
};
struct type_terminal
{
type_generator const operator()(bool is_return) const
{
return type_generator(is_return);
}
} const type = {};
type_generator const as_generator(type_terminal)
{
return type_generator{};
}
}
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator< ::eolian_mono::type_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::type_generator> : std::true_type {};
template <>
struct is_generator< ::eolian_mono::type_terminal> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed< ::eolian_mono::type_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::type_terminal> : std::integral_constant<int, 1> {};
}
} } }
#endif

View File

@ -0,0 +1,373 @@
#ifndef EOLIAN_MONO_TYPE_IMPL_HH
#define EOLIAN_MONO_TYPE_IMPL_HH
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/case.hpp"
#include "namespace.hh"
namespace eolian_mono {
namespace eina = efl::eina;
template <typename T>
T const* as_const_pointer(T* p) { return p; }
attributes::regular_type_def replace_base_type(attributes::regular_type_def v, std::string name)
{
v.base_type = name;
return v;
}
attributes::complex_type_def replace_outer(attributes::complex_type_def v, attributes::regular_type_def const& regular)
{
v.outer = regular;
return v;
}
template <typename Array, typename F, int N, typename A>
eina::optional<bool> call_match(Array const (&array)[N], F f, A a)
{
typedef Array const* iterator_type;
iterator_type match_iterator = &array[0], match_last = match_iterator + N;
match_iterator = std::find_if(match_iterator, match_last, f);
if(match_iterator != match_last)
{
return a(match_iterator->function());
}
return {nullptr};
}
template <typename OutputIterator, typename Context>
struct visitor_generate
{
mutable OutputIterator sink;
Context const* context;
std::string c_type;
bool is_out;
bool is_return;
typedef visitor_generate<OutputIterator, Context> visitor_type;
typedef bool result_type;
bool operator()(attributes::regular_type_def const& regular) const
{
using attributes::regular_type_def;
struct match
{
eina::optional<std::string> name;
eina::optional<bool> has_own;
std::function<attributes::type_def::variant_type()> function;
}
const match_table[] =
{
// signed primitives
{"byte", nullptr, [&] { return replace_base_type(regular, " byte"); }}
, {"llong", nullptr, [&] { return replace_base_type(regular, " long"); }}
, {"int8", nullptr, [&] { return replace_base_type(regular, " byte"); }}
, {"int16", nullptr, [&] { return replace_base_type(regular, " short"); }}
, {"int32", nullptr, [&] { return replace_base_type(regular, " int"); }}
, {"int64", nullptr, [&] { return replace_base_type(regular, " long"); }}
, {"ssize", nullptr, [&] { return replace_base_type(regular, " long"); }}
// unsigned primitives
, {"ubyte", nullptr, [&] { return replace_base_type(regular, " byte"); }}
, {"ushort", nullptr, [&] { return replace_base_type(regular, " ushort"); }}
, {"uint", nullptr, [&] { return replace_base_type(regular, " uint"); }}
, {"ulong", nullptr, [&] { return replace_base_type(regular, " ulong"); }}
, {"ullong", nullptr, [&] { return replace_base_type(regular, " ulong"); }}
, {"uint8", nullptr, [&] { return replace_base_type(regular, " byte"); }}
, {"uint16", nullptr, [&] { return replace_base_type(regular, " ushort"); }}
, {"uint32", nullptr, [&] { return replace_base_type(regular, " uint"); }}
, {"uint64", nullptr, [&] { return replace_base_type(regular, " ulong"); }}
, {"size", nullptr, [&] { return replace_base_type(regular, " ulong"); }}
, {"ptrdiff", nullptr, [&] { return replace_base_type(regular, " long"); }}
, {"intptr", nullptr, [&] { return replace_base_type(regular, " System.IntPtr"); }}
, {"void_ptr", nullptr, [&] { return replace_base_type(regular, " System.IntPtr"); }}
, {"void", nullptr, [&]
{
regular_type_def r = regular;
r.namespaces.clear();
if (is_out) // @inout too
r.base_type = " System.IntPtr";
else
r.base_type = " void";
return r;
}}
, {"Error", nullptr, [&] // Eina.Error
{
return regular_type_def{" eina.Error", regular.base_qualifier, {}};
}} // TODO
, {"string", nullptr, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
return replace_base_type(r, " System.String");
}}
, {"mstring", nullptr, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
return replace_base_type(r, " System.String");
}}
, {"stringshare", nullptr, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
return replace_base_type(r, " System.String");
}}
, {"any_value", true, [&]
{ return regular_type_def{" eina.Value", regular.base_qualifier, {}};
}}
, {"any_value", false, [&]
{ return regular_type_def{" eina.Value", regular.base_qualifier, {}};
}}
, {"any_value_ptr", nullptr, [&]
{ return regular_type_def{" eina.Value", regular.base_qualifier, {}};
}} // FIXME add proper support for any_value_ptr
};
// if(regular.base_type == "void_ptr")
// {
// if(regular.base_qualifier & qualifier_info::is_ref)
// throw std::runtime_error("ref of void_ptr is invalid");
// return as_generator
// (
// lit("void") << (regular.base_qualifier & qualifier_info::is_const ? " const" : "")
// << "*"
// << (is_out ? "&" : "")
// )
// .generate(sink, attributes::unused, *context);
// }
// else
if(eina::optional<bool> b = call_match
(match_table
, [&] (match const& m)
{
return (!m.name || *m.name == regular.base_type)
&& (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
;
}
, [&] (attributes::type_def::variant_type const& v)
{
return v.visit(*this); // we want to keep is_out info
}))
{
return *b;
}
// in A @optional -> optional<A>
// in A& @optional -> optional<A&>
// in A& @optional -> optional<A&>
// in own(A&) @optional -> A*
//
// out A @optional -> optional<A&>
// out A& @optional -> optional<A&>
// out own(A&) @optional -> optional<A*&>
// else if(regular.base_qualifier & qualifier_info::is_optional)
// {
// attributes::regular_type_def no_optional_regular = regular;
// no_optional_regular.base_qualifier.qualifier ^= qualifier_info::is_optional;
// if(is_out)
// {
// if(no_optional_regular.base_qualifier & qualifier_info::is_own)
// {
// return as_generator(" ::efl::eina::optional<").generate(sink, attributes::unused, *context)
// && (*this)(no_optional_regular)
// && as_generator("&>").generate(sink, attributes::unused, *context);
// }
// else if(no_optional_regular.base_qualifier & qualifier_info::is_ref)
// {
// no_optional_regular.base_qualifier.qualifier ^= qualifier_info::is_ref;
// return (*this)(no_optional_regular)
// && as_generator("**").generate(sink, attributes::unused, *context);
// }
// else
// return (*this)(no_optional_regular)
// && as_generator("*").generate(sink, attributes::unused, *context);
// }
// else
// {
// // regular.base_qualifier & qualifier_info::is_ref
// return as_generator(" ::efl::eina::optional<").generate(sink, attributes::unused, *context)
// && (*this)(no_optional_regular)
// && as_generator(">").generate(sink, attributes::unused, *context);
// }
// }
// else if((is_return || is_out) && regular.base_qualifier & qualifier_info::is_ref
// && regular.base_qualifier & qualifier_info::is_own)
// {
// if(as_generator
// (
// " ::std::unique_ptr<"
// << *(string << "_")
// << string
// << (regular.base_qualifier & qualifier_info::is_const ? " const" : "")
// << ", ::efl::eina::malloc_deleter>"
// )
// .generate(sink, std::make_tuple(regular.namespaces, regular.base_type), *context))
// return true;
// else
// return false;
// }
// else if(Eolian_Typedecl const* typedecl = eolian_typedecl_struct_get_by_name(c_type.c_str()))
// {
// return as_generator
// (
// *(string << ".")
// << string
// )
// .generate(sink, std::make_tuple(regular.namespaces, regular.base_type), *context);
// }
else
{
// as_generator(" Generating: " << *(lower_case[string] << ".") << string << "\n")
// .generate(std::ostream_iterator<char>(std::cerr), std::make_tuple(eolian_mono::escape_namespace(regular.namespaces), regular.base_type), *context);
if(as_generator
(
*(lower_case[string] << ".")
<< string
// << (regular.base_qualifier & qualifier_info::is_const
// || (regular.base_qualifier & qualifier_info::is_ref
// && !is_return && !is_out)
// ? /*" const"*/ "" : "")
/*<< (regular.base_qualifier & qualifier_info::is_ref? "&" : "")*/
)
.generate(sink, std::make_tuple(eolian_mono::escape_namespace(regular.namespaces), regular.base_type), *context))
return true;
else
return false;
}
}
bool operator()(attributes::klass_name klass) const
{
// as_generator(" Generating: " << *(lower_case[string] << ".") << string << "\n")
// .generate(std::ostream_iterator<char>(std::cerr), std::make_tuple(attributes::cpp_namespaces(klass.namespaces), klass.eolian_name), *context);
// if(klass.namespaces.size() == 1
// && klass.namespaces[0] == "Eina"
// && klass.eolian_name == "Error")
// return
// as_generator(" System.IntPtr")
// .generate(sink, attributes::unused, *context);
return
as_generator(*(lower_case[string] << ".") << string)
.generate(sink, std::make_tuple(eolian_mono::escape_namespace(klass.namespaces), klass.eolian_name), *context)
// && (!(klass.base_qualifier & qualifier_info::is_ref)
// || as_generator("&").generate(sink, attributes::unused, *context))
;
}
bool operator()(attributes::complex_type_def const& complex) const
{
using attributes::regular_type_def;
using attributes::complex_type_def;
using attributes::qualifier_info;
struct match
{
eina::optional<std::string> name;
eina::optional<bool> has_own;
eina::optional<bool> is_const;
std::function<attributes::type_def::variant_type()> function;
} const matches[] =
{
{"list", nullptr, nullptr, [&]
{
complex_type_def c = complex;
c.outer.base_type = "eina.List";
return c;
}}
, {"inlist", nullptr, nullptr, [&]
{
complex_type_def c = complex;
c.outer.base_type = "eina.Inlist";
return c;
}}
, {"array", nullptr, nullptr, [&]
{
complex_type_def c = complex;
c.outer.base_type = "eina.Array";
return c;
}}
, {"inarray", nullptr, nullptr, [&]
{
complex_type_def c = complex;
c.outer.base_type = "eina.Inarray";
return c;
}}
, {"hash", nullptr, nullptr
, [&]
{
complex_type_def c = complex;
c.outer.base_type = "eina.Hash";
return c;
}}
, {"promise", nullptr, nullptr, [&]
{
return replace_outer
(complex, regular_type_def{" ::efl::promise", complex.outer.base_qualifier, {}});
}
}
, {"future", nullptr, nullptr, [&]
{
(*this)(regular_type_def{" int", complex.outer.base_qualifier, {}});
return attributes::type_def::variant_type();
// return replace_outer
// (complex, regular_type_def{" ::efl::shared_future", complex.outer.base_qualifier, {}});
}
}
, {"iterator", nullptr, nullptr, [&]
{
complex_type_def c = complex;
c.outer.base_type = "eina.Iterator";
return c;
}
}
, {"accessor", nullptr, nullptr, [&]
{
(*this)(regular_type_def{" int", complex.outer.base_qualifier, {}});
return attributes::type_def::variant_type();
// return replace_outer
// (complex, regular_type_def{" ::efl::eina::accessor", complex.outer.base_qualifier, {}});
}
}
};
auto default_match = [&] (attributes::complex_type_def const& complex)
{
regular_type_def no_pointer_regular = complex.outer;
// std::vector<attributes::pointer_indirection> pointers;
// pointers.swap(no_pointer_regular.pointers);
// if(is_out)
// pointers.push_back({{attributes::qualifier_info::is_none, {}}, true});
return visitor_type{sink, context, c_type, false}(no_pointer_regular)
&& as_generator("<" << (type % ", ") << ">").generate(sink, complex.subtypes, *context)
;
// && detail::generate_pointers(sink, pointers, *context, false);
};
if(eina::optional<bool> b = call_match
(matches
, [&] (match const& m)
{
return (!m.name || *m.name == complex.outer.base_type)
&& (!m.has_own || *m.has_own == bool(complex.outer.base_qualifier & qualifier_info::is_own))
&& (!m.is_const || *m.is_const == bool(complex.outer.base_qualifier & qualifier_info::is_const));
}
, [&] (attributes::type_def::variant_type const& v)
{
if(v.empty())
return true;
else if(attributes::complex_type_def const* complex
= eina::get<attributes::complex_type_def>(&v))
return default_match(*complex);
else
return v.visit(*this);
}))
return *b;
else
{
return default_match(complex);
}
}
};
}
#endif

View File

@ -0,0 +1,21 @@
#ifndef EOLIAN_MONO_USING_DECL_HH
#define EOLIAN_MONO_USING_DECL_HH
namespace eolian_mono {
namespace grammar = efl::eolian::grammar;
using efl::eolian::grammar::as_generator;
using efl::eolian::grammar::string;
using efl::eolian::grammar::operator<<;
using efl::eolian::grammar::operator%;
using efl::eolian::grammar::operator*;
using efl::eolian::grammar::scope_tab;
using efl::eolian::grammar::lower_case;
using efl::eolian::grammar::upper_case;
using efl::eolian::grammar::lit;
using efl::eolian::grammar::qualifier_info;
using efl::eolian::grammar::context_find_tag;
}
#endif

View File

@ -0,0 +1,22 @@
#ifndef EOLIAN_MONO_UTILS_HPP
#define EOLIAN_MONO_UTILS_HPP
#include <string>
#include <algorithm>
namespace eolian_mono { namespace utils {
// Helper method to avoid multiple as_generator calls when mixing case strings
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)
{
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s;
}
} }
#endif

View File

@ -0,0 +1,367 @@
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <libgen.h>
#include <string>
#include <map>
#include <algorithm>
#include <stdexcept>
#include <iosfwd>
#include <type_traits>
#include <cassert>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Eolian.h>
#include <Eina.hh>
#include <Eolian_Cxx.hh>
#include <eolian/mono/klass.hh>
#include <eolian/mono/enum_definition.hh>
#include <eolian/mono/struct_definition.hh>
#include <eolian/mono/type_impl.hh>
#include <eolian/mono/marshall_type_impl.hh>
#include <eolian/mono/marshall_annotation.hh>
#include <eolian/mono/function_pointer.hh>
namespace eolian_mono {
/// Program options.
struct options_type
{
std::vector<std::string> include_dirs;
std::string in_file;
std::string out_file;
std::string dllimport;
int v_major;
int v_minor;
std::map<const std::string, std::string> references_map;
};
efl::eina::log_domain domain("eolian_mono");
// Parses a CSV file in the format 'filename,library' (without trimming spaces around ',')
static std::vector<std::pair<std::string, std::string> >
parse_reference(std::string filename)
{
std::vector<std::pair<std::string, std::string> > ret;
std::string delimiter = ",";
std::ifstream infile(filename);
std::string line;
while (std::getline(infile, line))
{
size_t pos = line.find(delimiter);
if (pos == std::string::npos)
throw std::invalid_argument("Malformed mapping. Must be 'filename,library'");
std::string eo_filename = line.substr(0, pos);
std::string library = line.substr(pos + 1);
library[0] = std::toupper(library[0]);
ret.push_back(std::pair<std::string, std::string>(eo_filename, library));
}
return ret;
}
static bool
opts_check(eolian_mono::options_type const& opts)
{
if (opts.in_file.empty())
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
<< "Nothing to generate?" << std::endl;
}
else if (opts.out_file.empty())
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
<< "Nowhere to generate?" << std::endl;
}
else
return true; // valid.
return false;
}
static void
run(options_type const& opts)
{
const Eolian_Class *klass = NULL;
Eina_Iterator *aliases = NULL;
const Eolian_Typedecl *tp = NULL;
char* dup = strdup(opts.in_file.c_str());
std::string basename_input = basename(dup);
klass = ::eolian_class_get_by_file(NULL, basename_input.c_str());
aliases= ::eolian_typedecl_aliases_get_by_file(NULL, basename_input.c_str());
free(dup);
std::string class_file_name = opts.out_file;
std::ofstream output_file;
std::ostream_iterator<char> iterator
{[&]
{
if(opts.out_file == "-")
return std::ostream_iterator<char>(std::cout);
else
{
output_file.open(class_file_name);
if (!output_file.good())
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
<< "Can't open output file: " << class_file_name << std::endl;
throw std::runtime_error("");
}
return std::ostream_iterator<char>(output_file);
}
}()};
if (!as_generator("using System;\nusing System.Runtime.InteropServices;\nusing System.Collections.Generic;\n")
.generate(iterator, efl::eolian::grammar::attributes::unused, efl::eolian::grammar::context_null()))
{
throw std::runtime_error("Failed to generate file preamble");
}
auto context = efl::eolian::grammar::context_add_tag(eolian_mono::library_context{opts.dllimport,
opts.v_major,
opts.v_minor,
opts.references_map},
efl::eolian::grammar::context_null());
EINA_ITERATOR_FOREACH(aliases, tp)
{
if (eolian_typedecl_type_get(tp) != EOLIAN_TYPEDECL_FUNCTION_POINTER)
continue;
const Eolian_Function *fp = eolian_typedecl_function_pointer_get(tp);
efl::eolian::grammar::attributes::function_def function_def(fp, EOLIAN_FUNCTION_POINTER, NULL);
std::vector<std::string> namespaces;
for (efl::eina::iterator<const char> namespace_iterator(::eolian_typedecl_namespaces_get(tp)), namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
{
namespaces.push_back(&*namespace_iterator);
}
if (!eolian_mono::function_pointer
.generate(iterator, function_def, escape_namespace(namespaces), context))
{
throw std::runtime_error("Failed to generate function pointer wrapper");
}
}
if (klass)
{
efl::eolian::grammar::attributes::klass_def klass_def(klass, NULL);
std::vector<efl::eolian::grammar::attributes::klass_def> klasses{klass_def};
if (!eolian_mono::klass
.generate(iterator, klass_def, context))
{
throw std::runtime_error("Failed to generate class");
}
}
//else
{
for (efl::eina::iterator<const Eolian_Typedecl> enum_iterator( ::eolian_typedecl_enums_get_by_file(NULL, basename_input.c_str()))
, enum_last; enum_iterator != enum_last; ++enum_iterator)
{
efl::eolian::grammar::attributes::enum_def enum_(&*enum_iterator);
if (!eolian_mono::enum_definition.generate(iterator, enum_, efl::eolian::grammar::context_null()))
{
throw std::runtime_error("Failed to generate enum");
}
}
for (efl::eina::iterator<const Eolian_Typedecl> struct_iterator( ::eolian_typedecl_structs_get_by_file(NULL, basename_input.c_str()))
, struct_last; struct_iterator != struct_last; ++struct_iterator)
{
efl::eolian::grammar::attributes::struct_def struct_(&*struct_iterator);
if (!eolian_mono::struct_definition.generate(iterator, struct_, efl::eolian::grammar::context_null()))
{
throw std::runtime_error("Failed to generate struct");
}
}
}
}
static void
database_load(options_type const& opts)
{
for (auto src : opts.include_dirs)
{
if (!::eolian_directory_scan(src.c_str()))
{
EINA_CXX_DOM_LOG_WARN(eolian_mono::domain)
<< "Couldn't load eolian from '" << src << "'.";
}
}
if (!::eolian_all_eot_files_parse())
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
<< "Eolian failed parsing eot files";
assert(false && "Error parsing eot files");
}
if (opts.in_file.empty())
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
<< "No input file.";
assert(false && "Error parsing input file");
}
if (!::eolian_file_parse(opts.in_file.c_str()))
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
<< "Failed parsing: " << opts.in_file << ".";
assert(false && "Error parsing input file");
}
}
} // namespace eolian_mono {
static void
_print_version()
{
std::cerr
<< "Eolian C++ Binding Generator (EFL "
<< PACKAGE_VERSION << ")" << std::endl;
}
static void
_usage(const char *progname)
{
std::cerr
<< progname
<< " [options] [file.eo]" << std::endl
<< " A single input file must be provided (unless -a is specified)." << std::endl
<< "Options:" << std::endl
<< " -a, --all Generate bindings for all Eo classes." << std::endl
<< " -c, --class <name> The Eo class name to generate code for." << std::endl
<< " -D, --out-dir <dir> Output directory where generated code will be written." << std::endl
<< " -I, --in <file/dir> The source containing the .eo descriptions." << std::endl
<< " -o, --out-file <file> The output file name. [default: <classname>.eo.hh]" << std::endl
<< " -n, --namespace <ns> Wrap generated code in a namespace. [Eg: efl::ecore::file]" << std::endl
<< " -r, --recurse Recurse input directories loading .eo files." << std::endl
<< " -v, --version Print the version." << std::endl
<< " -h, --help Print this help." << std::endl;
exit(EXIT_FAILURE);
}
static void
_assert_not_dup(std::string option, std::string value)
{
if (value != "")
{
EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) <<
"Option -" + option + " already set (" + value + ")";
}
}
static eolian_mono::options_type
opts_get(int argc, char **argv)
{
eolian_mono::options_type opts;
const struct option long_options[] =
{
{ "in", required_argument, 0, 'I' },
{ "out-file", required_argument, 0, 'o' },
{ "version", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' },
{ "dllimport", required_argument, 0, 'l' },
{ "vmaj", required_argument, 0, 'M' },
{ "vmin", required_argument, 0, 'm' },
{ "references", required_argument, 0, 'r'},
{ 0, 0, 0, 0 }
};
const char* options = "I:D:o:c:M:m:ar:vh";
int c, idx;
while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1)
{
if (c == 'I')
{
opts.include_dirs.push_back(optarg);
}
else if (c == 'o')
{
_assert_not_dup("o", opts.out_file);
opts.out_file = optarg;
}
else if (c == 'h')
{
_usage(argv[0]);
}
else if (c == 'l')
{
opts.dllimport = optarg;
}
else if (c == 'M')
{
opts.v_major = std::stoi(optarg);
}
else if (c == 'm')
{
opts.v_minor = std::stoi(optarg);
}
else if (c == 'r')
{
try
{
std::vector<std::pair<std::string, std::string> > names = eolian_mono::parse_reference(optarg);
for (auto&& p : names)
{
opts.references_map[p.first] = p.second;
}
}
catch (const std::invalid_argument &e)
{
std::cerr << "Invalid argument processing argument " << optarg << std::endl;
_usage(argv[0]);
assert(false && e.what());
}
}
else if (c == 'v')
{
_print_version();
if (argc == 2) exit(EXIT_SUCCESS);
}
}
if (optind == argc-1)
{
opts.in_file = argv[optind];
}
if (!eolian_mono::opts_check(opts))
{
_usage(argv[0]);
assert(false && "Wrong options passed in command-line");
}
return opts;
}
int main(int argc, char **argv)
{
try
{
efl::eina::eina_init eina_init;
efl::eolian::eolian_init eolian_init;
eolian_mono::options_type opts = opts_get(argc, argv);
eolian_mono::database_load(opts);
eolian_mono::run(opts);
}
catch(std::exception const& e)
{
std::cerr << "EOLCXX: Eolian C++ failed generation for the following reason: " << e.what() << std::endl;
std::cout << "EOLCXX: Eolian C++ failed generation for the following reason: " << e.what() << std::endl;
return -1;
}
return 0;
}