forked from enlightenment/efl
868 lines
39 KiB
C++
868 lines
39 KiB
C++
/*
|
|
* Copyright 2019 by its authors. See AUTHORS.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#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/kleene.hpp"
|
|
#include "grammar/indentation.hpp"
|
|
#include "grammar/list.hpp"
|
|
#include "grammar/alternative.hpp"
|
|
#include "grammar/attribute_reorder.hpp"
|
|
#include "grammar/eps.hpp"
|
|
#include "grammar/counter.hpp"
|
|
#include "logging.hh"
|
|
#include "type.hh"
|
|
#include "name_helpers.hh"
|
|
#include "helpers.hh"
|
|
#include "function_helpers.hh"
|
|
#include "marshall_type.hh"
|
|
#include "parameter.hh"
|
|
#include "documentation.hh"
|
|
#include "using_decl.hh"
|
|
#include "generation_contexts.hh"
|
|
#include "blacklist.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
|
|
{
|
|
EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "native_function_definition_generator: " << f.c_name << std::endl;
|
|
if(blacklist::is_function_blacklisted(f, context))
|
|
return true;
|
|
|
|
auto const& indent = current_indentation(context);
|
|
|
|
// Delegate for the C# method we will export to EO as a method implementation.
|
|
if(!as_generator
|
|
(
|
|
indent << eolian_mono::marshall_annotation(true) << "\n"
|
|
<< indent << "private delegate "
|
|
<< eolian_mono::marshall_type(true)
|
|
<< " "
|
|
<< string
|
|
<< "_delegate(" << (f.is_static ? "" : "System.IntPtr obj, System.IntPtr pd")
|
|
<< ((!f.is_static && f.parameters.size() > 0) ? ", " : "")
|
|
<< (grammar::attribute_reorder<-1, -1>
|
|
(
|
|
(marshall_annotation << " " << marshall_parameter)
|
|
) % ", ")
|
|
<< ");\n\n")
|
|
.generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context))
|
|
return false;
|
|
|
|
// API delegate is the wrapper for the Eo methods exported from C that we will use from C#.
|
|
if(!as_generator
|
|
(
|
|
indent << eolian_mono::marshall_annotation(true) << "\n"
|
|
<< indent << "internal delegate "
|
|
<< eolian_mono::marshall_type(true)
|
|
<< " "
|
|
<< string << "_api_delegate(" << (f.is_static ? "" : "System.IntPtr obj")
|
|
<< ((!f.is_static && f.parameters.size() > 0) ? ", " : "")
|
|
<< (grammar::attribute_reorder<-1, -1>
|
|
(
|
|
(marshall_annotation << " " << marshall_parameter)
|
|
) % ", ")
|
|
<< ");\n\n")
|
|
.generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context))
|
|
return false;
|
|
|
|
// Delegate holder (so it can't be collected).
|
|
if(!as_generator
|
|
(indent << "internal static readonly Efl.Eo.FunctionWrapper<" << string << "_api_delegate> " << string << "_ptr = new Efl.Eo.FunctionWrapper<"
|
|
<< string << "_api_delegate>(Module, \"" << string << "\");\n\n")
|
|
.generate(sink, std::make_tuple(f.c_name, f.c_name, f.c_name, f.c_name), context))
|
|
return false;
|
|
|
|
// We do not generate the wrapper to be called from C for non public interface member directly.
|
|
if (blacklist::is_non_public_interface_member(f, *klass))
|
|
return true;
|
|
|
|
// Do not generate static method in interface
|
|
if (((klass->type == attributes::class_type::interface_) ||
|
|
(klass->type == attributes::class_type::mixin)) && f.is_static)
|
|
return true;
|
|
|
|
// Actual method implementation to be called from C.
|
|
std::string return_type;
|
|
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
|
|
return false;
|
|
|
|
std::string klass_cast_name;
|
|
if ((klass->type == attributes::class_type::interface_) ||
|
|
((klass->type == attributes::class_type::mixin) && !f.is_static))
|
|
klass_cast_name = name_helpers::klass_interface_name(*klass);
|
|
else
|
|
klass_cast_name = name_helpers::klass_inherit_name(*klass);
|
|
|
|
std::string self = "Efl.Eo.Globals.Super(obj, Efl.Eo.Globals.GetClass(obj))";
|
|
|
|
if (f.is_static)
|
|
self = "";
|
|
|
|
if(!as_generator
|
|
(indent << "[SuppressMessage(\"Microsoft.Reliability\", \"CA2000:DisposeObjectsBeforeLosingScope\", Justification = \"The instantiated objects can be stored in the called Managed API method.\")]\n"
|
|
<< indent << "private static "
|
|
<< eolian_mono::marshall_type(true) << " "
|
|
<< string
|
|
<< "(System.IntPtr obj, System.IntPtr pd"
|
|
<< *(", " << marshall_parameter)
|
|
<< ")\n"
|
|
<< indent << "{\n"
|
|
<< indent << scope_tab << "Eina.Log.Debug(\"function " << string << " was called\");\n"
|
|
<< indent << scope_tab << "var ws = Efl.Eo.Globals.GetWrapperSupervisor(obj);\n"
|
|
<< indent << scope_tab << "if (ws != null)\n"
|
|
<< indent << scope_tab << "{\n"
|
|
<< indent << scope_tab << scope_tab << eolian_mono::native_function_definition_preamble() << "\n"
|
|
<< indent << scope_tab << scope_tab << "try\n"
|
|
<< indent << scope_tab << scope_tab << "{\n"
|
|
<< indent << scope_tab << scope_tab << scope_tab << (return_type != "void" ? "_ret_var = " : "")
|
|
<< (f.is_static ? "" : "((") << klass_cast_name << (f.is_static ? "." : ")ws.Target).") << string
|
|
<< "(" << (native_argument_invocation % ", ") << ");\n"
|
|
<< indent << scope_tab << scope_tab << "}\n"
|
|
<< indent << scope_tab << scope_tab << "catch (Exception e)\n"
|
|
<< indent << scope_tab << scope_tab << "{\n"
|
|
<< indent << scope_tab << scope_tab << scope_tab << "Eina.Log.Warning($\"Callback error: {e.ToString()}\");\n"
|
|
<< indent << scope_tab << scope_tab << scope_tab << "Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);\n"
|
|
<< indent << scope_tab << scope_tab << "}\n\n"
|
|
<< indent << eolian_mono::native_function_definition_epilogue(*klass) << "\n"
|
|
<< indent << scope_tab << "}\n"
|
|
<< indent << scope_tab << "else\n"
|
|
<< indent << scope_tab << "{\n"
|
|
<< indent << scope_tab << scope_tab << (return_type != "void" ? "return " : "") << string
|
|
<< "_ptr.Value.Delegate(" << self << ((!f.is_static && f.parameters.size() > 0) ? ", " : "") << (argument % ", ") << ");\n"
|
|
<< indent << scope_tab << "}\n"
|
|
<< indent << "}\n\n"
|
|
)
|
|
.generate(sink, std::make_tuple(f.return_type, escape_keyword(f.name), f.parameters
|
|
, /***/f.c_name/***/
|
|
, f
|
|
, name_helpers::managed_method_name(f)
|
|
, f.parameters
|
|
, f
|
|
, f.c_name
|
|
, f.parameters
|
|
)
|
|
, context))
|
|
return false;
|
|
|
|
// Static functions do not need to be called from C
|
|
if (f.is_static)
|
|
return true;
|
|
|
|
// This is the delegate that will be passed to Eo to be called from C.
|
|
if(!as_generator(
|
|
indent << "private static " << f.c_name << "_delegate " << f.c_name << "_static_delegate;\n\n"
|
|
).generate(sink, attributes::unused, 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
|
|
{
|
|
EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "function_definition_generator: " << f.c_name << std::endl;
|
|
|
|
bool is_concrete = context_find_tag<class_context>(context).current_wrapper_kind == class_context::concrete;
|
|
if(blacklist::is_function_blacklisted(f, context))
|
|
return true;
|
|
|
|
// Do not generate static function for concrete class
|
|
if (is_concrete && f.is_static)
|
|
return true;
|
|
|
|
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
|
|
(documentation(2)).generate(sink, f, context))
|
|
return false;
|
|
|
|
std::string self = "this.NativeHandle";
|
|
|
|
// IsGeneratedBindingClass is set in the constructor, true if this
|
|
// instance is from a pure C# class (not generated).
|
|
if (do_super && !f.is_static)
|
|
self = "(IsGeneratedBindingClass ? " + self + " : Efl.Eo.Globals.Super(" + self + ", this.NativeClass))";
|
|
else if (f.is_static)
|
|
self = "";
|
|
|
|
if(!as_generator
|
|
(scope_tab(2) << eolian_mono::function_scope_get(f) << ((do_super && !f.is_static) ? "virtual " : "") << (f.is_static ? "static " : "") << return_type << " " << string << "(" << (parameter % ", ")
|
|
<< ") {\n"
|
|
<< scope_tab(3) << eolian_mono::function_definition_preamble()
|
|
<< klass_full_native_inherit_name(f.klass) << "." << string << "_ptr.Value.Delegate("
|
|
<< self
|
|
<< ((!f.is_static && (f.parameters.size() > 0)) ? ", " : "")
|
|
<< (argument_invocation % ", ") << ");\n"
|
|
<< scope_tab(3) << eolian_mono::function_definition_epilogue()
|
|
<< scope_tab(2) << "}\n\n")
|
|
.generate(sink, std::make_tuple(name_helpers::managed_method_name(f), 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;
|
|
|
|
struct property_extension_method_definition_generator
|
|
{
|
|
template<typename OutputIterator, typename Context>
|
|
bool generate(OutputIterator sink, attributes::property_def const& property, Context context) const
|
|
{
|
|
if (blacklist::is_property_blacklisted(property, context))
|
|
return true;
|
|
|
|
auto options = efl::eolian::grammar::context_find_tag<options_context>(context);
|
|
|
|
if (!options.want_beta)
|
|
return true; // Bindable is a beta feature for now.
|
|
|
|
auto get_params = property.getter.is_engaged() ? property.getter->parameters.size() : 0;
|
|
auto set_params = property.setter.is_engaged() ? property.setter->parameters.size() : 0;
|
|
|
|
std::string managed_name = name_helpers::property_managed_name(property);
|
|
|
|
if (get_params > 0 || set_params > 1)
|
|
return true;
|
|
|
|
std::string dir_mod;
|
|
if (property.setter.is_engaged())
|
|
dir_mod = direction_modifier(property.setter->parameters[0]);
|
|
|
|
if (property.setter.is_engaged())
|
|
{
|
|
attributes::type_def prop_type = property.setter->parameters[0].type;
|
|
if (!as_generator(scope_tab(2) << "public static Efl.BindableProperty<" << type(true) << "> " << managed_name << "<T>(this Efl.Ui.ItemFactory<T> fac) where T : "
|
|
<< name_helpers::klass_full_concrete_or_interface_name(cls) << " {\n"
|
|
<< scope_tab(2) << scope_tab << "return new Efl.BindableProperty<" << type(true) << ">(\"" << property.name << "\", fac);\n"
|
|
<< scope_tab(2) << "}\n\n"
|
|
).generate(sink, std::make_tuple(prop_type, prop_type), context))
|
|
return false;
|
|
}
|
|
|
|
// Do we need BindablePart extensions for this class?
|
|
// IContent parts are handled directly through BindableFactoryParts
|
|
if (!helpers::inherits_from(cls, "Efl.Ui.LayoutPart") || helpers::inherits_from(cls, "Efl.IContent"))
|
|
return true;
|
|
|
|
if (property.setter.is_engaged())
|
|
{
|
|
attributes::type_def prop_type = property.setter->parameters[0].type;
|
|
if (!as_generator(scope_tab(2) << "public static Efl.BindableProperty<" << type(true) << "> " << managed_name << "<T>(this Efl.BindablePart<T> part) where T : "
|
|
<< name_helpers::klass_full_concrete_or_interface_name(cls) << " {\n"
|
|
<< scope_tab(2) << scope_tab << "Contract.Requires(part != null, nameof(part));\n"
|
|
<< scope_tab(2) << scope_tab << "return new Efl.BindableProperty<" << type(true) << ">(part.PartName, \"" << property.name << "\", part.Binder);\n"
|
|
<< scope_tab(2) << "}\n\n"
|
|
).generate(sink, std::make_tuple(prop_type, prop_type), context))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
grammar::attributes::klass_def const& cls;
|
|
};
|
|
|
|
property_extension_method_definition_generator property_extension_method_definition (grammar::attributes::klass_def const& cls)
|
|
{
|
|
return {cls};
|
|
}
|
|
|
|
struct property_wrapper_definition_generator
|
|
{
|
|
template <typename OutputIterator, typename Context>
|
|
bool generate_get_indexer(OutputIterator sink, attributes::property_def const& property, Context const& context
|
|
, std::string get_scope
|
|
, bool is_interface) const
|
|
{
|
|
if (is_interface)
|
|
{
|
|
if (!as_generator(scope_tab(3) << get_scope << "get;\n"
|
|
).generate(sink, attributes::unused, context))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (!as_generator(scope_tab(2) << scope_tab << get_scope << "get\n"
|
|
<< scope_tab(2) << scope_tab << "{\n"
|
|
<< scope_tab(2) << scope_tab(2) << "var i = new "
|
|
<< name_helpers::property_concrete_indexer_name(property) << "();\n"
|
|
<< scope_tab(2) << scope_tab(2) << "i.Self = this;\n"
|
|
<< scope_tab(2) << scope_tab(2) << "return i;\n"
|
|
<< scope_tab(2) << scope_tab << "}\n"
|
|
).generate(sink, attributes::unused, context))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename OutputIterator, typename Context, typename C1, typename C2>
|
|
bool generate_indexer(OutputIterator sink
|
|
, attributes::property_def const& property
|
|
, Context const& context
|
|
, std::string scope, std::string get_scope, std::string set_scope
|
|
, std::string class_name
|
|
, C1 keys, C2 values
|
|
, bool is_interface
|
|
, bool is_concrete_for_interface
|
|
, bool has_setter) const
|
|
{
|
|
if (is_interface)
|
|
return true;
|
|
|
|
auto size_not_one = [] (std::vector<attributes::parameter_def> k) { return k.size() != 1; };
|
|
auto type_or_tuple
|
|
=
|
|
(
|
|
(
|
|
attribute_conditional(size_not_one)["("]
|
|
<< (type(false) % ", ")
|
|
<< ")"
|
|
)
|
|
| *type(false)
|
|
)
|
|
;
|
|
|
|
std::string parentship = "\n";
|
|
|
|
bool is_self_property = *implementing_klass == *klass_from_property;
|
|
|
|
if (!(is_self_property && !is_concrete_for_interface))
|
|
parentship = " : " + name_helpers::property_interface_indexer_name(property, *klass_from_property) + "\n";
|
|
|
|
if (!as_generator
|
|
(
|
|
scope_tab(2) << scope << "class " << name_helpers::property_concrete_indexer_name(property) << parentship
|
|
<< scope_tab(2) << "{\n"
|
|
<< scope_tab(3) << "public " << class_name << " Self {get; set;}\n"
|
|
<< scope_tab(3) << "public "
|
|
<< type_or_tuple << " this[" << type_or_tuple <<" i]\n"
|
|
<< scope_tab(3) << "{\n"
|
|
).generate(sink, make_tuple(values, values, keys, keys), context))
|
|
return false;
|
|
|
|
assert (!keys.empty());
|
|
std::vector<std::string> get_keys;
|
|
if(keys.size() != 1)
|
|
{
|
|
unsigned int i = 0;
|
|
for (auto&& key : keys)
|
|
{
|
|
static_cast<void>(key);
|
|
++i;
|
|
get_keys.push_back("i.Item" + std::to_string(i));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
get_keys.push_back ("i");
|
|
}
|
|
assert (!get_keys.empty());
|
|
|
|
generate_get(sink, property, context, get_scope, get_keys, values, is_interface, "Self.");
|
|
if (has_setter)
|
|
generate_set(sink, property, context, set_scope, get_keys, values, is_interface, "Self.");
|
|
|
|
if (!as_generator
|
|
(
|
|
scope_tab(3) << "}\n"
|
|
<< scope_tab(2) << "};\n"
|
|
).generate(sink, attributes::unused, context))
|
|
return false;
|
|
return true;
|
|
}
|
|
template <typename OutputIterator, typename Context, typename CK, typename CV>
|
|
bool generate_set(OutputIterator sink, attributes::property_def const& property, Context const& context
|
|
, std::string set_scope
|
|
, CK keys, CV values
|
|
, bool is_interface
|
|
, std::string name_prefix = "") const
|
|
{
|
|
using efl::eolian::grammar::counter;
|
|
if (is_interface)
|
|
{
|
|
if (!as_generator(scope_tab(2) << scope_tab << set_scope << "set;\n"
|
|
).generate(sink, attributes::unused, context))
|
|
return false;
|
|
}
|
|
else if (values.size() == 1)
|
|
{
|
|
if (!as_generator(scope_tab(2) << scope_tab << set_scope << "set " << "{ " << name_prefix << name_helpers::managed_method_name(*property.setter) + "(" << *(string << ",") << "value); }\n"
|
|
).generate(sink, keys, context))
|
|
return false;
|
|
}
|
|
else if (values.size() > 1)
|
|
{
|
|
if (!as_generator(
|
|
scope_tab(2) << scope_tab << set_scope << "set "
|
|
<< ("{ " << name_prefix << name_helpers::managed_method_name(*property.setter) + "(")
|
|
<< *(string << ",") << ((" value.Item" << counter(1)) % ", ")
|
|
<< "); }\n"
|
|
).generate(sink, std::make_tuple(keys, values), context))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
template <typename OutputIterator, typename Context, typename CK, typename CV>
|
|
bool generate_get(OutputIterator sink, attributes::property_def const& property, Context const& context
|
|
, std::string get_scope
|
|
, CK keys, CV values
|
|
, bool is_interface
|
|
, std::string name_prefix = "") const
|
|
{
|
|
using efl::eolian::grammar::attribute_reorder;
|
|
using efl::eolian::grammar::attributes::parameter_direction;
|
|
using efl::eolian::grammar::attributes::parameter_def;
|
|
|
|
if (is_interface) // only declaration
|
|
{
|
|
if (!as_generator(scope_tab(2) << scope_tab << get_scope << "get;\n"
|
|
).generate(sink, attributes::unused, context))
|
|
return false;
|
|
}
|
|
else
|
|
if (/*has_getter && */values.size() == 1)
|
|
{
|
|
if (!as_generator
|
|
(scope_tab(2) << scope_tab << get_scope
|
|
<< "get " << "{ return " << name_prefix << name_helpers::managed_method_name(*property.getter)
|
|
<< "(" << (string % ",") << "); }\n"
|
|
).generate(sink, keys, context))
|
|
return false;
|
|
}
|
|
else if (/*has_getter && */values.size() > 1)
|
|
{
|
|
if (!as_generator
|
|
(scope_tab(2) << scope_tab << get_scope << "get "
|
|
<< "{\n"
|
|
<< *attribute_reorder<1, -1, 1>
|
|
(scope_tab(4) << type(true) << " _out_"
|
|
<< argument(false) << " = default(" << type(true) << ");\n"
|
|
)
|
|
<< scope_tab(4) << name_prefix << name_helpers::managed_method_name(*property.getter)
|
|
<< "(" << *(string << ",") << (("out _out_" << argument(false)) % ", ") << ");\n"
|
|
<< scope_tab(4) << "return (" << (("_out_"<< argument(false)) % ", ") << ");\n"
|
|
<< scope_tab(3) << "}" << "\n"
|
|
).generate(sink, std::make_tuple(values, keys, values, values), context))
|
|
return false;
|
|
}
|
|
// else if (values.size() == 1)
|
|
// {
|
|
// if (!as_generator
|
|
// (scope_tab << scope_tab << get_scope << "get "
|
|
// << "{\n"
|
|
// << *attribute_reorder<1, -1, 1>(scope_tab(3) << type(true) << " _out_" << argument(false) << " = default(" << type(true) << ");\n")
|
|
// << scope_tab(3) << name_prefix << name_helpers::managed_method_name(*property.getter)
|
|
// << "(" << *(string << ",") << (("out _out_" << argument(false)) % ",") << ");\n"
|
|
// << scope_tab(3) << "return " << (("_out_"<< argument(false)) % ",") << ";\n"
|
|
// << scope_tab(2) << "}" << "\n"
|
|
// ).generate(sink, std::make_tuple(values, keys, values, values), context))
|
|
// return false;
|
|
// }
|
|
return true;
|
|
}
|
|
|
|
template<typename OutputIterator, typename Context>
|
|
bool generate(OutputIterator sink, attributes::property_def const& property, Context const& context) const
|
|
{
|
|
using efl::eolian::grammar::attribute_reorder;
|
|
using efl::eolian::grammar::counter;
|
|
using efl::eolian::grammar::attributes::parameter_direction;
|
|
using efl::eolian::grammar::attributes::parameter_def;
|
|
|
|
/// C(k) = keys count, C(v) = values count
|
|
/// /------------\ /------\.
|
|
/// |blacklisted?|---yes-----| skip |--------------\.
|
|
/// \------------/ \------/ |
|
|
/// | | |
|
|
/// no yes |
|
|
/// | | |
|
|
/// /---------\ /------------\ |
|
|
/// |is-static|----yes-----|is-interface| |
|
|
/// \---------/ \------------/ |
|
|
/// | | |
|
|
/// no no |
|
|
/// | | |
|
|
/// /--------\ /-----------\ |
|
|
/// |has-get?|---no-conc---|is-concrete|-----yes---/
|
|
/// \--------/ \-----------/
|
|
/// / \.
|
|
/// no yes
|
|
/// / \.
|
|
/// /----\ /--------------------------------------\.
|
|
/// |skip|-yes-|explicit return != Eina.Error or void |
|
|
/// \----/ \--------------------------------------/
|
|
/// |
|
|
/// no
|
|
/// |
|
|
/// /--------\.
|
|
/// |has-set?|
|
|
/// \--------/
|
|
/// / \.
|
|
/// no yes
|
|
/// / \.
|
|
/// /------\ /--------------------------------------\.
|
|
/// /------------------|no-set| |explicit return != Eina.Error or void |---- yes --\.
|
|
/// | \------/ \--------------------------------------/ |
|
|
/// | \------------|----------------------------------------------/
|
|
/// | no
|
|
/// | |
|
|
/// | /--------\.
|
|
/// | |has-both|
|
|
/// | \--------/
|
|
/// | |
|
|
/// | /-------------------\.
|
|
/// | |set-keys = get-keys|
|
|
/// | \-------------------/
|
|
/// | / |
|
|
/// | no |
|
|
/// | / |
|
|
/// | /----\ /-----------------------\.
|
|
/// | |skip|--no---|set-values = get-values|
|
|
/// | \----/ \-----------------------/
|
|
/// | /
|
|
/// | yes
|
|
/// | /
|
|
/// | /--------\.
|
|
/// \-------------------------| keys |
|
|
/// \--------/
|
|
/// / \.
|
|
/// 0 >0
|
|
/// / \.
|
|
/// /----------\ /----------\.
|
|
/// |no-indexer| | keys > 1 |
|
|
/// \----------/ \----------/
|
|
/// | / |
|
|
/// | no yes
|
|
/// | / |
|
|
/// | / |
|
|
/// | /---------\ /-------------------\.
|
|
/// | | indexer | | indexer tuple key |
|
|
/// | \---------/ \-------------------/
|
|
/// | / |
|
|
/// /--------\ |
|
|
/// | values |----------/
|
|
/// \--------/
|
|
/// / \.
|
|
/// 1 >1
|
|
/// / \.
|
|
/// /----------------\ /-------------\.
|
|
/// | no tuple value | | tuple value |
|
|
/// \----------------/ \-------------/
|
|
///
|
|
|
|
auto has_wrapper = helpers::has_property_wrapper (property, implementing_klass, context);
|
|
bool has_getter = has_wrapper & helpers::has_property_wrapper_bit::has_getter;
|
|
if (!has_getter) return true;
|
|
bool has_setter = has_wrapper & helpers::has_property_wrapper_bit::has_setter;
|
|
bool has_indexer = has_wrapper & helpers::has_property_wrapper_bit::has_indexer;
|
|
|
|
bool is_interface = context_find_tag<class_context>(context).current_wrapper_kind == class_context::interface;
|
|
bool is_static = (property.getter.is_engaged() && property.getter->is_static)
|
|
|| (property.setter.is_engaged() && property.setter->is_static);
|
|
bool is_concrete = context_find_tag<class_context>(context).current_wrapper_kind == class_context::concrete;
|
|
bool is_concrete_for_interface = is_concrete
|
|
&& (implementing_klass->type == attributes::class_type::interface_
|
|
|| implementing_klass->type == attributes::class_type::mixin);
|
|
|
|
//if (name_helpers::klass_concrete_or_interface_name (*implementing_klass) == "IMapping")
|
|
if (false)
|
|
{
|
|
if (!as_generator(grammar::lit("/// is interface ") << (int)is_interface
|
|
<< " is static " << (int)is_static
|
|
<< " is concrete " << (int)is_concrete
|
|
<< " is concrete_for_interface " << (int)is_concrete_for_interface
|
|
<< " klass_from_property->type " << (int)klass_from_property->type
|
|
<< " has_setter " << (int)has_setter
|
|
<< " property.setter->explicit_return_type != attributes::void_ " << (property.setter && property.setter->explicit_return_type != attributes::void_)
|
|
<< " property.setter->keys != property.getter->keys " << (property.setter && property.setter->keys != property.getter->keys)
|
|
<< " property.setter->values != property.getter->values " << (property.setter && property.setter->values != property.getter->values)
|
|
<< " has_setter && property.setter->scope != attributes::member_scope::scope_public " << (property.setter && property.setter->scope != attributes::member_scope::scope_public)
|
|
<< "\n")
|
|
.generate (sink, attributes::unused, context))
|
|
return false;
|
|
}
|
|
|
|
if (blacklist::is_property_blacklisted(property, context))
|
|
return true;
|
|
|
|
std::string managed_name = name_helpers::property_managed_name(property);
|
|
|
|
std::string scope = "public ";
|
|
std::string get_scope = eolian_mono::function_scope_get(*property.getter);
|
|
std::string set_scope = has_setter ? eolian_mono::function_scope_get(*property.setter) : "";
|
|
|
|
// C# interface members are declared automatically as public
|
|
if (is_interface)
|
|
{
|
|
scope = "";
|
|
get_scope = "";
|
|
set_scope = "";
|
|
}
|
|
else if ((get_scope != "") && (get_scope == set_scope))
|
|
{
|
|
scope = get_scope;
|
|
get_scope = "";
|
|
set_scope = "";
|
|
}
|
|
else if (!has_setter || (get_scope == scope))
|
|
{
|
|
scope = get_scope;
|
|
get_scope = "";
|
|
}
|
|
|
|
std::string virtual_mod = (is_static || is_interface || is_concrete) ? "" : "virtual ";
|
|
|
|
auto keys = property.getter->keys;
|
|
auto values = property.getter->values;
|
|
auto generated_values = values;
|
|
auto klass_name = name_helpers::klass_concrete_or_interface_name (*implementing_klass);
|
|
|
|
if (has_indexer)
|
|
{
|
|
assert (!!implementing_klass);
|
|
generate_indexer (sink, property, context, scope, get_scope, set_scope
|
|
, klass_name, keys, values
|
|
, is_interface, is_concrete_for_interface, has_setter);
|
|
|
|
generated_values.clear();
|
|
if (!is_interface && *implementing_klass == *klass_from_property
|
|
&& !is_concrete_for_interface)
|
|
{
|
|
generated_values.push_back
|
|
(attributes::parameter_def
|
|
{parameter_direction::in
|
|
, attributes::type_def
|
|
{
|
|
attributes::regular_type_def{name_helpers::property_concrete_indexer_name(property), {attributes::qualifier_info::is_none, ""}, {}}
|
|
, name_helpers::property_concrete_indexer_name(property)
|
|
, false, false, false, ""
|
|
}
|
|
, "indexer", {}, nullptr
|
|
});
|
|
}
|
|
else
|
|
{
|
|
generated_values.push_back
|
|
(attributes::parameter_def
|
|
{parameter_direction::in
|
|
, attributes::type_def
|
|
{
|
|
attributes::regular_type_def{name_helpers::klass_full_concrete_or_interface_name (*klass_from_property) + managed_name + "Indexer", {attributes::qualifier_info::is_none, ""}, {}}
|
|
, name_helpers::property_interface_indexer_name(property, *klass_from_property)
|
|
, false, false, false, ""
|
|
}
|
|
, "indexer", {}, nullptr
|
|
});
|
|
}
|
|
}
|
|
|
|
if (generated_values.size() == 1)
|
|
{
|
|
if (!as_generator(
|
|
documentation(2)
|
|
<< scope_tab(2) << scope << (is_static ? "static " : virtual_mod) << type(true) << " " << managed_name << " {\n"
|
|
).generate(sink, std::make_tuple(property, generated_values[0].type), context))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (!as_generator
|
|
(
|
|
documentation(2)
|
|
<< scope_tab(2) << scope << (is_static ? "static (" : "(")
|
|
<< (attribute_reorder<1, -1>(type(true) /*<< " " << argument*/) % ", ") << ") "
|
|
<< managed_name << " {\n"
|
|
).generate(sink, std::make_tuple(property, generated_values), context))
|
|
return false;
|
|
}
|
|
|
|
if (has_indexer)
|
|
{
|
|
generate_get_indexer (sink, property, context, get_scope, is_interface);
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::string> empty_keys;
|
|
generate_get(sink, property, context, get_scope, empty_keys, values, is_interface);
|
|
|
|
if (has_setter)
|
|
generate_set (sink, property, context, set_scope, empty_keys, values, is_interface);
|
|
}
|
|
|
|
if (!as_generator(scope_tab(2) << "}\n\n").generate(sink, attributes::unused, context))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
attributes::klass_def const* implementing_klass, *klass_from_property;
|
|
};
|
|
struct property_wrapper_definition_parameterized
|
|
{
|
|
property_wrapper_definition_generator operator()(attributes::klass_def const& klass
|
|
, attributes::klass_def const& prop_from_klass) const
|
|
{
|
|
return {&klass, &prop_from_klass};
|
|
}
|
|
} const property_wrapper_definition;
|
|
property_wrapper_definition_generator as_generator(property_wrapper_definition_parameterized)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
struct interface_property_indexer_definition_generator
|
|
{
|
|
template<typename OutputIterator, typename Context>
|
|
bool generate(OutputIterator sink, attributes::property_def const& property, Context const& context) const
|
|
{
|
|
using efl::eolian::grammar::attribute_reorder;
|
|
using efl::eolian::grammar::counter;
|
|
using efl::eolian::grammar::attributes::parameter_direction;
|
|
using efl::eolian::grammar::attributes::parameter_def;
|
|
|
|
bool is_interface = context_find_tag<class_context>(context).current_wrapper_kind == class_context::interface;
|
|
|
|
assert (is_interface);
|
|
auto klass_name = name_helpers::klass_concrete_or_interface_name (*implementing_klass);
|
|
std::string managed_name = name_helpers::property_managed_name(property);
|
|
|
|
if (!as_generator
|
|
(scope_tab << "public interface " << name_helpers::property_interface_indexer_short_name(property, *implementing_klass) << "\n"
|
|
<< scope_tab << "{\n"
|
|
<< scope_tab << "}\n"
|
|
).generate (sink, attributes::unused, context))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
attributes::klass_def const* implementing_klass;
|
|
};
|
|
struct interface_property_indexer_definition_parameterized
|
|
{
|
|
interface_property_indexer_definition_generator operator()(attributes::klass_def const& klass) const
|
|
{
|
|
return {&klass};
|
|
}
|
|
} const interface_property_indexer_definition;
|
|
interface_property_indexer_definition_generator as_generator(interface_property_indexer_definition_parameterized)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
}
|
|
|
|
namespace efl { namespace eolian { namespace grammar {
|
|
|
|
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_eager_generator< ::eolian_mono::property_extension_method_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_eager_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_eager_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {};
|
|
template <>
|
|
struct is_eager_generator< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::true_type {};
|
|
template <>
|
|
struct is_eager_generator< ::eolian_mono::interface_property_indexer_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::function_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::native_function_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::function_definition_parameterized> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::property_extension_method_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::true_type {};
|
|
template <>
|
|
struct is_generator< ::eolian_mono::interface_property_indexer_definition_generator> : std::true_type {};
|
|
|
|
namespace type_traits {
|
|
template <>
|
|
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> {};
|
|
|
|
template <>
|
|
struct attributes_needed< ::eolian_mono::property_extension_method_definition_generator> : std::integral_constant<int, 1> {};
|
|
|
|
template <>
|
|
struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator> : std::integral_constant<int, 1> {};
|
|
template <>
|
|
struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {};
|
|
|
|
template <>
|
|
struct attributes_needed< ::eolian_mono::interface_property_indexer_definition_parameterized> : std::integral_constant<int, 1> {};
|
|
template <>
|
|
struct attributes_needed< ::eolian_mono::interface_property_indexer_definition_generator> : std::integral_constant<int, 1> {};
|
|
}
|
|
|
|
} } }
|
|
|
|
#endif
|