/* * 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_TYPE_IMPL_HH #define EOLIAN_MONO_TYPE_IMPL_HH #include "grammar/generator.hpp" #include "grammar/klass_def.hpp" #include "grammar/case.hpp" #include "name_helpers.hh" namespace eolian_mono { namespace eina = efl::eina; template T const* as_const_pointer(T* p) { return p; } inline attributes::regular_type_def replace_base_type(attributes::regular_type_def v, std::string name) { v.base_type = name; return v; } template attributes::regular_type_def replace_base_integer(attributes::regular_type_def v) { bool s = std::is_signed::value; switch (sizeof(T)) { case 1: return s ? replace_base_type(v, "sbyte") : replace_base_type(v, "byte"); case 2: return s ? replace_base_type(v, "short") : replace_base_type(v, "ushort"); case 4: return s ? replace_base_type(v, "int") : replace_base_type(v, "uint"); case 8: return s ? replace_base_type(v, "long") : replace_base_type(v, "ulong"); default: return v; } } template attributes::regular_type_def replace_base_opt_integer(attributes::regular_type_def v) { bool s = std::is_signed::value; switch (sizeof(T)) { case 1: return s ? replace_base_type(v, "sbyte?") : replace_base_type(v, "byte?"); case 2: return s ? replace_base_type(v, "short?") : replace_base_type(v, "ushort?"); case 4: return s ? replace_base_type(v, "int?") : replace_base_type(v, "uint?"); case 8: return s ? replace_base_type(v, "long?") : replace_base_type(v, "ulong?"); default: return v; } } inline attributes::complex_type_def replace_outer(attributes::complex_type_def v, attributes::regular_type_def const& regular) { v.outer = regular; return v; } template eina::optional 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 struct visitor_regular_type_def_printer { typedef visitor_regular_type_def_printer visitor_type; typedef bool result_type; mutable OutputIterator sink; Context const* context; bool operator()(grammar::attributes::regular_type_def const ®ular) const { return as_generator(string).generate(sink, name_helpers::type_full_managed_name(regular), *context); } template bool operator()(T const&) const { return true; } }; template struct visitor_generate { mutable OutputIterator sink; Context const* context; std::string c_type; bool is_out; bool is_return; bool is_ptr; mutable bool is_optional; bool is_special_subtype; typedef visitor_generate visitor_type; typedef bool result_type; bool operator()(attributes::regular_type_def const& regular) const { using attributes::regular_type_def; struct match { eina::optional name; eina::optional has_own; std::function function; } const optional_match_table[] = { // signed primitives {"byte", nullptr, [&] { return replace_base_type(regular, "sbyte?"); }} , {"float", nullptr, [&] { return replace_base_type(regular, "float?"); }} , {"double", nullptr, [&] { return replace_base_type(regular, "double?"); }} , {"bool", nullptr, [&] { return replace_base_type(regular, "bool?"); }} , {"short", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"int", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"long", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"llong", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"int8", nullptr, [&] { return replace_base_type(regular, "sbyte?"); }} , {"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_opt_integer(regular); }} // unsigned primitives , {"ubyte", nullptr, [&] { return replace_base_type(regular, "byte?"); }} , {"ushort", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"uint", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"ulong", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"ullong", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"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_opt_integer(regular); }} , {"ptrdiff", nullptr, [&] { return replace_base_opt_integer(regular); }} , {"intptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr?"); }} , {"uintptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr?"); }} , {"void_ptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr?"); }} }; struct match const match_table[] = { // signed primitives {"byte", nullptr, [&] { return replace_base_type(regular, "sbyte"); }} , {"short", nullptr, [&] { return replace_base_integer(regular); }} , {"int", nullptr, [&] { return replace_base_integer(regular); }} , {"long", nullptr, [&] { return replace_base_integer(regular); }} , {"llong", nullptr, [&] { return replace_base_integer(regular); }} , {"int8", nullptr, [&] { return replace_base_type(regular, "sbyte"); }} , {"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_integer(regular); }} // unsigned primitives , {"ubyte", nullptr, [&] { return replace_base_type(regular, "byte"); }} , {"ushort", nullptr, [&] { return replace_base_integer(regular); }} , {"uint", nullptr, [&] { return replace_base_integer(regular); }} , {"ulong", nullptr, [&] { return replace_base_integer(regular); }} , {"ullong", nullptr, [&] { return replace_base_integer(regular); }} , {"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_integer(regular); }} , {"ptrdiff", nullptr, [&] { return replace_base_integer(regular); }} , {"intptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr"); }} , {"uintptr", 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; }} , {"Eina.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; if (is_special_subtype) return replace_base_type(r, "Eina.Stringshare"); return replace_base_type(r, "System.String"); }} , {"strbuf", nullptr, [&] { return regular_type_def{"Eina.Strbuf", regular.base_qualifier, {}}; }} , {"binbuf", nullptr, [&] { return regular_type_def{"Eina.Binbuf", regular.base_qualifier, {}}; }} , {"event", nullptr, [&] { return regular_type_def{"Efl.Event", regular.base_qualifier, {}}; }} , {"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_ref", nullptr, [&] { return regular_type_def{"Eina.Value", regular.base_qualifier, {}}; }} // FIXME add proper support for any_value_ref }; std::string full_type_name = name_helpers::type_full_eolian_name(regular); if(eina::optional b = call_match (optional_match_table , [&] (match const& m) { return is_optional && (!m.name || *m.name == regular.base_type || *m.name == full_type_name) && (!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 if (is_optional && (regular.is_struct() || regular.is_enum() || regular.is_struct_opaque())) { attributes::regular_type_def r = regular; r.base_type.push_back('?'); is_optional = false; return (*this)(r); } else if(eina::optional b = call_match (match_table , [&] (match const& m) { return (!m.name || *m.name == regular.base_type || *m.name == full_type_name) && (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own)) ; } , [&] (attributes::type_def::variant_type const& v) { return v.visit(visitor_regular_type_def_printer{sink, context}); // we want to keep is_out info })) { return *b; } // in A @optional -> optional // in A& @optional -> optional // in A& @optional -> optional // in own(A&) @optional -> A* // // out A @optional -> optional // out A& @optional -> optional // out own(A&) @optional -> optional // 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_state_struct_by_name_get(c_type.c_str())) // { // return as_generator // ( // *(string << ".") // << string // ) // .generate(sink, std::make_tuple(regular.namespaces, regular.base_type), *context); // } else { return as_generator(string).generate(sink, name_helpers::type_full_managed_name(regular), *context); } } bool operator()(attributes::klass_name klass) const { // Efl.Class is manually handled in a custom marshall to be represented by a System.Type. if (name_helpers::klass_full_concrete_name(klass) == "Efl.Class") return as_generator(lit("Type")).generate(sink, attributes::unused, *context); if(klass.type == attributes::class_type::regular || klass.type == attributes::class_type::abstract_) return as_generator(string).generate(sink, name_helpers::klass_full_concrete_name(klass), *context); else return as_generator(string).generate(sink, name_helpers::klass_full_interface_name(klass), *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 name; eina::optional has_own; eina::optional is_const; std::function function; } const matches[] = { {"list", nullptr, nullptr, [&] { complex_type_def c = complex; c.outer.base_type = "Eina.List"; return c; }} , {"array", nullptr, nullptr, [&] { complex_type_def c = complex; c.outer.base_type = "Eina.Array"; return c; }} , {"hash", nullptr, nullptr , [&] { complex_type_def c = complex; c.outer.base_type = "Eina.Hash"; return c; }} , {"future", nullptr, nullptr, [&] { (*this)(regular_type_def{" Eina.Future", complex.outer.base_qualifier, {}}); return attributes::type_def::variant_type(); } } , {"iterator", nullptr, nullptr, [&] { complex_type_def c = complex; c.outer.base_type = "Eina.Iterator"; return c; } } , {"accessor", nullptr, nullptr, [&] { complex_type_def c = complex; c.outer.base_type = "Eina.Accessor"; return c; } } , {"slice", nullptr, nullptr, [&] { return regular_type_def{" Eina.Slice", complex.outer.base_qualifier, {}}; } } , {"rw_slice", nullptr, nullptr, [&] { return regular_type_def{" Eina.RwSlice", complex.outer.base_qualifier, {}}; } } }; auto default_match = [&] (attributes::complex_type_def const& complex) { regular_type_def no_pointer_regular = complex.outer; // std::vector 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, false, false, false, false}(no_pointer_regular) && as_generator("<" << (type(false, false, true) % ", ") << ">").generate(sink, complex.subtypes, *context) ; // && detail::generate_pointers(sink, pointers, *context, false); }; if(eina::optional 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(&v)) return default_match(*complex); else return v.visit(*this); })) return *b; else { return default_match(complex); } } }; } #endif