efl/src/bin/eolian_mono/eolian/mono/name_helpers.hh

575 lines
15 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_NAME_HELPERS_HH
#define EOLIAN_MONO_NAME_HELPERS_HH
#include <algorithm>
#include <cctype>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include "utils.hh"
#include "grammar/integral.hpp"
#include "grammar/generator.hpp"
#include "grammar/klass_def.hpp"
#include "grammar/list.hpp"
#include "grammar/string.hpp"
#include "grammar/integral.hpp"
using efl::eolian::grammar::as_generator;
using efl::eolian::grammar::string;
using efl::eolian::grammar::lit;
using efl::eolian::grammar::operator*;
namespace eolian_mono {
/* Utility functions for naming things. Compared to the utils.hh, this header has higher level
* functions, dealing with the knowledge of how to convert the items to the C# style we are using, for
* example, while being too short to be implemented as full-fledged generators.
*/
namespace name_helpers {
namespace attributes = efl::eolian::grammar::attributes;
namespace detail {
inline bool is_equal(std::string const& lhs, std::string const& rhs)
{
return lhs == rhs;
}
}
// Forward declarations
template<typename T>
inline std::string klass_concrete_or_interface_name(T const& klass);
inline std::string identity(std::string const& str)
{
return str;
}
inline std::string escape_keyword(std::string const& name)
{
using detail::is_equal;
if(is_equal(name, "delete")
|| is_equal(name, "do")
|| is_equal(name, "lock")
|| is_equal(name, "event")
|| is_equal(name, "in")
|| is_equal(name, "object")
|| is_equal(name, "interface")
|| is_equal(name, "string")
|| is_equal(name, "internal")
|| is_equal(name, "fixed")
|| is_equal(name, "var")
|| is_equal(name, "base"))
return "kw_" + name;
if (is_equal(name, "Finalize"))
return name + "Add"; // Eo's Finalize is actually the end of efl_add.
return name;
}
typedef std::function<std::string(std::string const&)> string_transform_func;
inline std::string join_namespaces(std::vector<std::string> const& namespaces, char separator,
string_transform_func func=identity)
{
std::stringstream s;
for (auto&& n : namespaces)
s << func(n) << separator;
return s.str();
}
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",
"apply",
"bind",
"cancel",
"copy",
"create",
"cut",
"delete",
"deselect",
"detach",
"do",
"gen",
"insert",
"iterate",
"join",
"leave",
"limit",
"paste",
"parse",
"prepend",
"process",
"query",
"refresh",
"remove",
"register",
"reject",
"release",
"reply",
"send",
"select",
"serialize",
"steal",
"sync",
"toggle",
"unbind",
"unregister"
};
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);
}
}
inline std::string managed_namespace(std::string const& ns)
{
return escape_keyword(utils::remove_all(ns, '_'));
}
inline std::string managed_method_name(attributes::function_def const& f)
{
std::vector<std::string> names = utils::split(f.name, '_');
name_helpers::reorder_verb(names);
std::string candidate = escape_keyword(utils::to_pascal_case(names));
// Some eolian methods have the same name as their parent class
if (candidate == klass_concrete_or_interface_name(f.klass))
candidate = "Do" + candidate;
// Avoid clashing with System.Object.GetType
if (candidate == "GetType" || candidate == "SetType")
{
candidate.insert(3, f.klass.eolian_name);
}
return candidate;
}
inline std::string managed_name(std::string const& name, char separator='_')
{
auto tokens = utils::split(name, separator);
return utils::to_pascal_case(tokens);
}
inline std::string full_managed_name(std::string const& name)
{
std::stringstream ss;
auto words = utils::split(name, '.');
std::transform(words.begin(), words.end(), words.begin(), [](std::string const& word) {
return managed_name(word);
});
auto b = std::begin(words), e = std::end(words);
if (b != e)
{
std::copy(b, std::prev(e), std::ostream_iterator<std::string>(ss, "."));
b = std::prev(e);
}
// Avoid trailing separator
if (b != e)
ss << *b;
return ss.str();
}
inline std::string alias_full_eolian_name(attributes::alias_def const& alias)
{
std::string eolian_name = utils::remove_all(alias.eolian_name, '_');
return join_namespaces(alias.namespaces, '.') + eolian_name;
}
inline std::string managed_async_method_name(attributes::function_def const& f)
{
return managed_method_name(f) + "Async";
}
inline std::string function_ptr_full_eolian_name(attributes::function_def const& func)
{
return join_namespaces(func.namespaces, '.') + func.name;
}
inline std::string type_full_eolian_name(attributes::regular_type_def const& type)
{
return join_namespaces(type.namespaces, '.') + type.base_type;
}
inline std::string type_full_managed_name(attributes::regular_type_def const& type)
{
return join_namespaces(type.namespaces, '.', managed_namespace) + utils::remove_all(type.base_type, '_');
}
inline std::string struct_full_eolian_name(attributes::struct_def const& struct_)
{
return join_namespaces(struct_.namespaces, '.') + struct_.cxx_name;
}
template<typename T>
inline std::string typedecl_managed_name(T const& item)
{
return utils::remove_all(item.cxx_name, '_');
}
inline std::string typedecl_managed_name(attributes::function_def const& func)
{
return utils::remove_all(func.name, '_');
}
inline std::string enum_field_managed_name(std::string name)
{
std::vector<std::string> names = utils::split(name, '_');
return utils::to_pascal_case(names);
}
inline std::string to_field_name(std::string const& in)
{
return utils::capitalize(in);
}
template<typename T>
inline std::string property_managed_name(T const& klass, std::string const& name)
{
auto names = utils::split(name, '_');
// No need to escape keyword here as it will be capitalized and already
// namespaced inside the owner class.
auto managed_name = utils::to_pascal_case(names);
auto managed_klass_name = klass_concrete_or_interface_name(klass);
if (managed_name == "Type")
managed_name = managed_klass_name + managed_name;
return managed_name;
}
inline std::string property_managed_name(attributes::property_def const& property)
{
return property_managed_name(property.klass, property.name);
}
inline std::string managed_part_name(attributes::part_def const& part)
{
std::vector<std::string> names = utils::split(part.name, '_');
return utils::to_pascal_case(names) + "Part";
}
// Class name translation (interface/concrete/inherit/etc)
struct klass_interface_name_generator
{
template <typename T>
std::string operator()(T const& klass) const
{
return ((klass.type == attributes::class_type::mixin
|| klass.type == attributes::class_type::interface_) ? "I" : "")
+ utils::remove_all(klass.eolian_name, '_');
}
template <typename OutputIterator, typename Attr, typename Context>
bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
{
return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
}
} const klass_interface_name;
struct klass_full_interface_name_generator
{
template <typename T>
std::string operator()(T const& klass) const
{
return join_namespaces(klass.namespaces, '.', managed_namespace) + klass_interface_name(klass);
}
template <typename OutputIterator, typename Attr, typename Context>
bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
{
return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
}
} const klass_full_interface_name;
template<typename T>
inline std::string klass_concrete_name(T const& klass)
{
return utils::remove_all(klass.eolian_name, '_') + ((klass.type == attributes::class_type::mixin
|| klass.type == attributes::class_type::interface_)
? "Concrete" : "");
}
template<typename T>
inline std::string klass_concrete_or_interface_name(T const& klass)
{
switch(klass.type)
{
case attributes::class_type::abstract_:
case attributes::class_type::regular:
return klass_concrete_name(klass);
default:
return klass_interface_name(klass);
}
}
struct klass_full_concrete_name_generator
{
template <typename T>
std::string operator()(T const& klass) const
{
return join_namespaces(klass.namespaces, '.', managed_namespace) + klass_concrete_name(klass);
}
template <typename OutputIterator, typename Attr, typename Context>
bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
{
return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
}
} const klass_full_concrete_name;
struct klass_full_concrete_or_interface_name_generator
{
template <typename T>
std::string operator()(T const& klass) const
{
switch(klass.type)
{
case attributes::class_type::abstract_:
case attributes::class_type::regular:
return klass_full_concrete_name(klass);
default:
return klass_full_interface_name(klass);
}
}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator, attributes::unused_type, Context const&) const
{
return true;
}
template <typename OutputIterator, typename Attr, typename Context>
bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
{
return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
}
} const klass_full_concrete_or_interface_name;
template<typename T>
inline std::string klass_inherit_name(T const& klass)
{
return klass_concrete_name(klass);
}
template<typename T>
inline std::string klass_native_inherit_name(EINA_UNUSED T const& klass)
{
return "NativeMethods";
}
template<typename T>
inline std::string klass_full_native_inherit_name(T const& klass)
{
return klass_full_concrete_name(klass) + "." + klass_native_inherit_name(klass);
}
template<typename T>
inline std::string klass_get_name(T const& clsname)
{
return clsname.klass_get_name;
}
template<typename T>
inline std::string klass_get_full_name(T const& clsname)
{
return klass_full_concrete_name(clsname) + "." + klass_get_name(clsname);
}
// Events
inline std::string managed_event_name(std::string const& name)
{
return utils::to_pascal_case(utils::split(name, "_,"), "") + "Event";
}
inline std::string managed_event_args_short_name(attributes::event_def const& evt)
{
return utils::remove_all(evt.klass.eolian_name, '_') + name_helpers::managed_event_name(evt.name) + "Args";
}
inline std::string managed_event_args_name(attributes::event_def evt)
{
return join_namespaces(evt.klass.namespaces, '.', managed_namespace) +
managed_event_args_short_name(evt);
}
inline std::string translate_inherited_event_name(const attributes::event_def &evt, const attributes::klass_def &klass)
{
return join_namespaces(klass.namespaces, '_') + klass_interface_name(klass) + "_" + managed_event_name(evt.name);
}
// Open/close namespaces
template<typename OutputIterator, typename Context>
bool open_namespaces(OutputIterator sink, std::vector<std::string> namespaces, Context const& context)
{
std::transform(namespaces.begin(), namespaces.end(), namespaces.begin(), managed_namespace);
std::string joined_namespace = join_namespaces(namespaces, '.');
if (joined_namespace.empty()) return true;
joined_namespace.pop_back();
return as_generator("namespace " << string << " {\n").generate(sink, joined_namespace, context);
}
template<typename OutputIterator, typename Context>
bool close_namespaces(OutputIterator sink, std::vector<std::string> const& namespaces, Context const& context)
{
if (namespaces.empty()) return true;
return as_generator("}\n\n").generate(sink, attributes::unused, context);
}
std::string constructor_managed_name(std::string full_name)
{
auto tokens = utils::split(full_name, '.');
return managed_name(tokens.at(tokens.size()-1));
}
} // namespace name_helpers
} // namespace eolian_mono
namespace efl { namespace eolian { namespace grammar {
template <>
struct is_eager_generator<eolian_mono::name_helpers::klass_interface_name_generator> : std::true_type {};
template <>
struct is_generator<eolian_mono::name_helpers::klass_interface_name_generator> : std::true_type {};
template <>
struct is_eager_generator<eolian_mono::name_helpers::klass_full_interface_name_generator> : std::true_type {};
template <>
struct is_generator<eolian_mono::name_helpers::klass_full_interface_name_generator> : std::true_type {};
template <>
struct is_eager_generator<eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::true_type {};
template <>
struct is_generator<eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::true_type {};
template <>
struct is_eager_generator<eolian_mono::name_helpers::klass_full_concrete_name_generator> : std::true_type {};
template <>
struct is_generator<eolian_mono::name_helpers::klass_full_concrete_name_generator> : std::true_type {};
namespace type_traits {
template <>
struct attributes_needed<struct ::eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::integral_constant<int, 1> {};
}
} } }
#endif