Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1068 lines (887 sloc) 25.8 KB
// -*- C++ -*-
#ifndef CPPX_META
#define CPPX_META
#include <cppx/traits.hpp>
#include <cppx/tuple.hpp>
#include <cppx/compiler>
namespace cppx
{
namespace meta
{
inline namespace v1
{
template<typename T> struct is_observable_trait;
template<typename T> struct is_variable_trait;
template<typename T> struct is_function_trait;
template<typename T> struct is_member_variable_trait;
template<typename T> struct is_member_function_trait;
template<typename T> struct is_constructor_trait;
template<typename T> struct is_destructor_trait;
template<typename T> struct is_variable_or_field_trait;
template<typename T> struct is_function_or_method_trait;
// The type of a reflected AST node.
using reflection_t = std::intptr_t;
/// The many different kinds of reflections.
enum reflection_kind {
translation_unit_kind,
namespace_decl_kind,
variable_decl_kind,
function_decl_kind,
parameter_decl_kind,
member_variable_decl_kind,
member_function_decl_kind,
access_decl_kind,
enumerator_decl_kind,
internal_decl_kind,
fundamental_type_kind,
pointer_type_kind,
array_type_kind,
function_type_kind,
reference_type_kind,
member_pointer_type_kind,
class_type_kind,
union_type_kind,
enum_type_kind,
};
// The base class of all reflected entities.
template<reflection_t X, reflection_kind K>
struct entity {
static constexpr reflection_t reflection_value = X;
static constexpr void print() {
return __reflect_print(X);
}
static constexpr reflection_kind kind() {
return K;
}
static constexpr bool is_translation_unit() {
return K == translation_unit_kind;
}
static constexpr bool is_namespace() {
return K == namespace_decl_kind;
}
static constexpr bool is_variable() {
return K == variable_decl_kind;
}
static constexpr bool is_function() {
return K == function_decl_kind;
}
static constexpr bool is_parameter() {
return K == parameter_decl_kind;
}
static constexpr bool is_member_function() {
return K == member_function_decl_kind;
}
static constexpr bool is_member_variable() {
return K == member_variable_decl_kind;
}
static constexpr bool is_access_specifier() {
return K == access_decl_kind;
}
static constexpr bool is_enumerator() {
return K == enumerator_decl_kind;
}
static constexpr bool is_internal() {
return K == internal_decl_kind;
}
static constexpr bool is_fundamental_type() {
return K == fundamental_type_kind;
}
static constexpr bool is_pointer_type() {
return K == pointer_type_kind;
}
static constexpr bool is_array_type() {
return K == array_type_kind;
}
static constexpr bool is_function_type() {
return K == function_type_kind;
}
static constexpr bool is_reference_type() {
return K == reference_type_kind;
}
static constexpr bool is_member_pointer_type() {
return K == member_pointer_type_kind;
}
static constexpr bool is_class_type() {
return K == class_type_kind;
}
static constexpr bool is_union_type() {
return K == union_type_kind;
}
static constexpr bool is_enum_type() {
return K == enum_type_kind;
}
};
// The base class of all declarations.
template<reflection_t X, reflection_kind K>
struct decl : entity<X, K> {
static constexpr unsigned packed_traits = __reflect_traits(X);
static constexpr decl_traits traits() {
return decl_traits(__reflect_traits(X));
}
modification_traits mods = {};
char const* rename = {};
};
template<reflection_t X1, reflection_kind K1, reflection_t X2, reflection_kind K2>
constexpr bool operator==(decl<X1, K1>, decl<X2, K2>) {
return X1 == X2;
}
template<reflection_t X1, reflection_kind K1, reflection_t X2, reflection_kind K2>
constexpr bool operator!=(decl<X1, K1>, decl<X2, K2>) {
return X1 != X2;
}
// A reflection of an internal entity.
template<reflection_t X>
struct internal : decl<X, internal_decl_kind> {
};
// A reflection of an access specifier within a class definition.
template<reflection_t X>
struct access_spec : decl<X, access_decl_kind> {
static constexpr access_kind access() {
return decl<X, access_decl_kind>::traits().access;
}
static constexpr bool has_access() {
return access() != no_access;
}
static constexpr bool is_public() {
return access() == public_access;
}
static constexpr bool is_private() {
return access() == private_access;
}
static constexpr bool is_protected() {
return access() == protected_access;
}
};
// A helper class that provides support for named entities.
template<reflection_t X, reflection_kind K>
struct named : decl<X, K> {
static constexpr char const* name() {
return __reflect_name(X);
}
static constexpr char const* qualified_name() {
return __reflect_qualified_name(X);
}
static constexpr auto declaration_context() {
return __reflect_declaration_context(X);
}
static constexpr auto lexical_context() {
return __reflect_declaration_context(X);
}
static constexpr linkage_kind linkage() {
return decl<X, K>::traits().linkage;
}
static constexpr bool has_linkage() {
return linkage() != no_linkage;
}
static constexpr bool has_external_linkage() {
return linkage() == external_linkage;
}
static constexpr bool has_internal_linkage() {
return linkage() == internal_linkage;
}
static constexpr access_kind access() {
return decl<X, K>::traits().access;
}
static constexpr bool has_default_access() {
return __reflect_default_access(X);
}
static constexpr bool has_explicit_access() {
return !has_default_access();
}
static constexpr bool is_public() {
return access() == public_access;
}
static constexpr bool is_private() {
return access() == private_access;
}
static constexpr bool is_protected() {
return access() == protected_access;
}
constexpr void set_access(access_kind k) {
this->mods.new_access = k;
}
constexpr void make_public() {
set_access(public_access);
}
constexpr void make_private() {
set_access(private_access);
}
constexpr void make_protected() {
set_access(protected_access);
}
constexpr void set_name(char const* str) {
this->rename = str;
}
};
// A helper class that provides access to members of a scope declaration.
//
// Scoped declarations are also tuples over their members.
template<reflection_t X>
struct scope {
struct member_info {
static constexpr std::size_t size() {
return __reflect_num_members(X);
}
template<std::size_t I>
static constexpr auto get() {
return __reflect_member(X, I);
}
};
using member_tuple = filtered_tuple<member_info, is_observable_trait>;
static constexpr member_tuple members() {
return {};
}
static constexpr std::size_t size() {
return member_tuple::size();
}
static constexpr bool empty() {
return member_tuple::empty();
}
};
// Returns the Ith element in the filtered tuple.
template<std::size_t I, reflection_t X>
constexpr auto
get(scope<X> const& t) {
return get<I>(t.members());
}
// Returns the Ith element in the filtered tuple as a constant expression.
template<std::size_t I, reflection_t X>
constexpr auto
cget(scope<X> const& t) {
return get<I>(t.members());
}
// Reflects the current translation unit.
template<reflection_t X>
struct tu : decl<X, translation_unit_kind>, scope<X> {
};
// Reflects a namespace.
template<reflection_t X>
struct ns : named<X, namespace_decl_kind>, scope<X> {
static constexpr namespace_traits traits() {
return namespace_traits(__reflect_traits(X));
}
static constexpr bool is_inline() {
return traits().is_inline;
}
};
// Base class of the type hierarchy.
//
// FIXME: This is woefully incomplete. Also, types are named declarations.
template<reflection_t X, reflection_kind K>
struct type : named<X, K> {
};
template<reflection_t X1, reflection_kind K1, reflection_t X2, reflection_kind K2>
constexpr bool operator==(type<X1, K1>, type<X2, K2>) {
return X1 == X2;
}
template<reflection_t X1, reflection_kind K1, reflection_t X2, reflection_kind K2>
constexpr bool operator!=(type<X1, K1>, type<X2, K2>) {
return X1 != X2;
}
template<reflection_t X>
struct fundamental_type : type<X, fundamental_type_kind> {
};
template<reflection_t X>
struct pointer_type : type<X, pointer_type_kind> {
};
template<reflection_t X>
struct reference_type : type<X, reference_type_kind> {
};
template<reflection_t X>
struct array_type : type<X, array_type_kind> {
};
template<reflection_t X>
struct function_type : type<X, function_type_kind> {
static constexpr auto return_type() {
return __reflect_return(X);
}
};
template<reflection_t X>
struct member_pointer_type : type<X, member_pointer_type_kind> {
};
// All user-defined types define a scope.
template<reflection_t X, reflection_kind K>
struct user_defined_type : type<X, K>, scope<X> {
};
// A useful base class for class and union types.
template<reflection_t X, reflection_kind K>
struct member_type : user_defined_type<X, K> {
using member_info = typename scope<X>::member_info;
using var_tuple = filtered_tuple<member_info, is_variable_or_field_trait>;
using memvar_tuple = filtered_tuple<member_info, is_member_variable_trait>;
using svar_tuple = filtered_tuple<member_info, is_variable_trait>;
using fn_tuple = filtered_tuple<member_info, is_function_or_method_trait>;
using memfn_tuple = filtered_tuple<member_info, is_member_function_trait>;
using ctor_tuple = filtered_tuple<member_info, is_constructor_trait>;
using dtor_tuple = filtered_tuple<member_info, is_destructor_trait>;
using sfn_tuple = filtered_tuple<member_info, is_function_trait>;
static constexpr class_traits traits() {
return class_traits(__reflect_traits(X));
}
static constexpr bool is_complete() {
return traits().is_complete;
}
static constexpr var_tuple variables() {
return {};
}
static constexpr memvar_tuple member_variables() {
return {};
}
static constexpr svar_tuple static_variables() {
return {};
}
static constexpr fn_tuple functions() {
return {};
}
static constexpr memfn_tuple member_functions() {
return {};
}
static constexpr ctor_tuple constructors() {
return {};
}
static constexpr dtor_tuple destructors() {
return {};
}
static constexpr bool has_destructor() {
return !destructors().empty();
}
static constexpr auto destructor() {
return cget<0>(destructors());
}
static constexpr sfn_tuple static_functions() {
return {};
}
};
template<reflection_t X>
struct base_spec {
static constexpr auto type() {
return __reflect_type(X);
}
static constexpr base_traits traits() {
return base_traits(__reflect_traits(X));
}
static constexpr bool is_virtual() {
return traits().is_virtual;
}
static constexpr access_kind access() {
return traits().access;
}
static constexpr bool has_access() {
return access() != no_access;
}
static constexpr bool is_public() {
return access() == public_access;
}
static constexpr bool is_private() {
return access() == private_access;
}
static constexpr bool is_protected() {
return access() == protected_access;
}
// FIXME: These don't actually work.
static constexpr void set_access(access_kind k) {
__modify_access(X, k);
}
static constexpr void make_public() {
__modify_access(X, public_access);
}
static constexpr void make_private() {
__modify_access(X, private_access);
}
static constexpr void make_protected() {
__modify_access(X, protected_access);
}
static constexpr void print() {
// FIXME: This ignores specifiers.
return type().print();
}
};
template<reflection_t X>
struct class_type : member_type<X, class_type_kind> {
struct base_info {
static constexpr std::size_t size() {
return __reflect_num_bases(X);
}
template<std::size_t I>
static constexpr auto get() {
return __reflect_base(X, I);
}
};
static constexpr reflected_tuple<base_info> bases() {
// static_assert(member_type<X, class_type_kind>::is_complete());
return {};
}
static constexpr bool is_polymorphic() {
return member_type<X, class_type_kind>::traits().is_polymorphic;
}
static constexpr bool is_abstract() {
return member_type<X, class_type_kind>::traits().is_abstract;
}
static constexpr bool is_final() {
return member_type<X, class_type_kind>::traits().is_final;
}
static constexpr bool is_empty() {
return member_type<X, class_type_kind>::traits().is_empty;
}
// using entity<X, class_type_kind>::is_member_variable;
};
template<reflection_t X>
struct union_type : member_type<X, union_type_kind> {
// TODO: Are there any interesting traits here?
};
template<reflection_t X>
struct enum_type : user_defined_type<X, enum_type_kind> {
static constexpr enum_traits traits() {
return enum_traits(__reflect_traits(X));
}
static constexpr bool is_scoped() {
return traits().is_scoped;
}
static constexpr bool is_complete() {
return traits().is_complete;
}
};
// A typed entity is an entity described by a type: objects, references,
// and functions (and presumably also values?). Note that an expression
// is not an entity.
template<reflection_t X, reflection_kind K>
struct typed : named<X, K> {
static constexpr auto type() {
return __reflect_type(X);
}
static constexpr auto type_name() {
return type().name();
}
};
template<reflection_t X, reflection_kind K>
struct valued : typed<X, K> {
static constexpr variable_traits traits() {
return variable_traits(__reflect_traits(X));
}
static constexpr storage_kind storage() {
return traits().storage;
}
static constexpr bool has_static_storage() {
return storage() == static_storage;
}
static constexpr bool has_automatic_storage() {
return storage() == automatic_storage;
}
static constexpr bool has_thread_storage() {
return storage() == thread_storage;
}
constexpr void make_static() {
this->mods.new_storage = static_storage;
}
constexpr void make_thread_local() {
this->mods.new_storage = thread_storage;
}
static constexpr bool is_inline() {
return traits().is_inline;
}
static constexpr bool is_constexpr() {
return traits().is_constexpr;
}
constexpr void make_constexpr() {
this->mods.make_constexpr = true;
}
constexpr auto pointer() {
return __reflect_pointer(X);
}
};
template<reflection_t X>
struct variable : valued<X, variable_decl_kind> {
};
template<reflection_t X>
struct function : typed<X, function_decl_kind> {
struct parm_info
{
static constexpr std::size_t size() {
return __reflect_num_parameters(X);
}
template<std::size_t I>
static constexpr auto get() {
return __reflect_parameter(X, I);
}
};
static constexpr function_traits traits() {
return function_traits(__reflect_traits(X));
}
static constexpr auto return_type() {
return __reflect_return(X);
}
static constexpr bool is_constexpr() {
return traits().is_constexpr;
}
static constexpr bool is_noexcept() {
return traits().is_noexcept;
}
void make_constexpr() {
this->mods.make_constexpr(true);
}
static constexpr bool is_defined() {
return traits().is_defined;
}
static constexpr bool is_inline() {
return is_defined() && traits().is_inline;
}
static constexpr bool is_deleted() {
return traits().is_deleted;
}
static constexpr reflected_tuple<parm_info> parameters() {
return {};
}
static constexpr auto pointer() {
return __reflect_pointer(X);
}
};
// A helper class for member functions.
template<reflection_t X>
struct method : typed<X, member_function_decl_kind> {
struct parm_info
{
static constexpr std::size_t size() {
return __reflect_num_parameters(X);
}
template<std::size_t I>
static constexpr auto get() {
return __reflect_parameter(X, I);
}
};
static constexpr method_traits traits() {
return method_traits(__reflect_traits(X));
}
static constexpr reflected_tuple<parm_info> parameters() {
return {};
}
static constexpr auto return_type() {
return __reflect_return(X);
}
// Method kind
static constexpr bool is_normal() {
return traits().kind == method_normal;
}
static constexpr bool is_constructor() {
return traits().kind == method_ctor;
}
static constexpr bool is_destructor() {
return traits().kind == method_dtor;
}
static constexpr bool is_conversion() {
return traits().kind == method_conv;
}
// Specifiers
static constexpr bool is_constexpr() {
return traits().is_constexpr;
}
static constexpr bool is_explicit() {
return traits().is_explicit;
}
constexpr void make_constexpr() {
this->mods.make_constexpr(true);
}
// Virtual functions
static constexpr bool is_virtual() {
return traits().is_virtual;
}
static constexpr bool is_pure_virtual() {
return traits().is_pure;
}
static constexpr bool is_final() {
return traits().is_final;
}
static constexpr bool is_override() {
return traits().is_override;
}
constexpr void make_virtual() {
this->mods.make_virtual = true;
}
constexpr void make_pure_virtual() {
this->mods.make_virtual = true;
this->mods.make_pure = true;
}
// Traits
static constexpr bool is_default_constructor() {
return traits().is_copy_ctor;
}
static constexpr bool is_copy_constructor() {
return traits().is_copy_ctor;
}
static constexpr bool is_move_constructor() {
return traits().is_move_ctor;
}
static constexpr bool is_copy_assignment_operator() {
return traits().is_copy_assign;
}
static constexpr bool is_move_assignment_operator() {
return traits().is_move_assign;
}
static constexpr bool is_copy_assign() {
return traits().is_copy_assign;
}
static constexpr bool is_move_assign() {
return traits().is_move_assign;
}
static constexpr bool is_copy() {
return traits().is_copy_ctor || traits().is_copy_assign;
}
static constexpr bool is_move () {
return traits().is_move_ctor || traits().is_move_assign;
}
// Exceptions
static constexpr bool is_noexcept() {
return traits().is_noexcept;
}
// Definition
static constexpr bool is_defined() {
return traits().is_defined;
}
static constexpr bool is_inline() {
return is_defined() && traits().is_inline;
}
static constexpr bool is_deleted() {
return traits().is_deleted;
}
static constexpr bool is_defaulted() {
return traits().is_defaulted;
}
static constexpr bool is_trivial() {
return traits().is_trivial;
}
};
// A member variable is a non-static data member.
template<reflection_t X>
struct field : valued<X, member_variable_decl_kind> {
static constexpr field_traits traits() {
return field_traits(__reflect_traits(X));
}
static constexpr bool is_mutable() {
return traits().is_mutable;
}
static constexpr auto pointer() {
return __reflect_pointer(X);
}
// FIXME: This is dumb.
static constexpr void make_constexpr() {
compiler.error("cannot make fields constexpr");
}
};
// A function parameter is essentially a variable.
template<reflection_t X>
struct parameter : valued<X, parameter_decl_kind> {
};
// An enumeration value.
//
// NOTE: Value traits do not currently differ from decl traits.
template<reflection_t X>
struct enumerator : typed<X, enumerator_decl_kind> {
static constexpr auto value() {
return __reflect_value(X);
}
};
// -------------------------------------------------------------------------- //
// Tuple traversal/application
template<typename T, typename F>
constexpr void
for_each(T const& t, F f) {
detail::tuple_for_each_recursive<0>(t, f);
}
// -------------------------------------------------------------------------- //
// Type traits
// is internal
//
// True for any internally generated AST nodes. These are typically filtered
// from sequences by the is_observable trait.
template<typename T>
struct is_internal
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_internal<internal<X>>
: std::integral_constant<bool, true> { };
// is observable
//
// True for all non-internal nodes.
template<typename T>
struct is_observable_trait
: std::integral_constant<bool, !is_internal<T>::value> { };
template<typename T>
constexpr bool is_observable_v = is_observable_trait<T>::value;
template<typename T>
constexpr bool is_observable(T) {
return is_observable_v<T>;
}
// is variable
template<typename T>
struct is_variable_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_variable_trait<variable<X>>
: std::integral_constant<bool, true> { };
template<typename T>
constexpr bool is_variable_v = is_variable_trait<T>::value;
template<typename T>
constexpr bool is_variable(T) {
return is_variable_v<T>;
}
// is function
template<typename T>
struct is_function_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_function_trait<function<X>>
: std::integral_constant<bool, true> { };
template<typename T>
constexpr bool is_function_v = is_function_trait<T>::value;
template<typename T>
constexpr bool is_function(T) {
return is_function_v<T>;
}
// is member variable
template<typename T>
struct is_member_variable_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_member_variable_trait<field<X>>
: std::integral_constant<bool, true> { };
template<typename T>
constexpr bool is_member_variable_v = is_member_variable_trait<T>::value;
template<typename T>
constexpr bool is_member_variable(T) {
return is_member_variable_v<T>;
}
// is member function
template<typename T>
struct is_member_function_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_member_function_trait<method<X>>
: std::integral_constant<bool, true> { };
template<typename T>
constexpr bool is_member_function_v = is_member_function_trait<T>::value;
template<typename T>
constexpr bool is_member_function(T) {
return is_member_function_v<T>;
}
// is constructor
template<typename T>
struct is_constructor_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_constructor_trait<method<X>>
: std::integral_constant<bool, method<X>::is_constructor()> { };
template<typename T>
constexpr bool is_constructor_v = is_constructor_trait<T>::value;
template<typename T>
constexpr bool is_constructor(T) {
return is_constructor_v<T>;
}
// is destructor
template<typename T>
struct is_destructor_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_destructor_trait<method<X>>
: std::integral_constant<bool, method<X>::is_destructor()> { };
template<typename T>
constexpr bool is_destructor_v = is_destructor_trait<T>::value;
template<typename T>
constexpr bool is_destructor(T) {
return is_destructor_v<T>;
}
// is function or method
//
// True for any (possibly static) member variable.
template<typename T>
struct is_function_or_method_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_function_or_method_trait<function<X>>
: std::integral_constant<bool, true> { };
template<reflection_t X>
struct is_function_or_method_trait<method<X>>
: std::integral_constant<bool, true> { };
template<typename T>
constexpr bool is_function_or_method_v = is_function_or_method_trait<T>::value;
template<typename T>
constexpr bool is_function_or_method(T) {
return is_function_or_method_v<T>;
}
// is variable or field
//
// True for any (possibly static) member variable.
template<typename T>
struct is_variable_or_field_trait
: std::integral_constant<bool, false> { };
template<reflection_t X>
struct is_variable_or_field_trait<variable<X>>
: std::integral_constant<bool, true> { };
template<reflection_t X>
struct is_variable_or_field_trait<field<X>>
: std::integral_constant<bool, true> { };
template<typename T>
constexpr bool is_variable_or_field_v = is_variable_or_field_trait<T>::value;
template<typename T>
constexpr bool is_variable_or_field(T) {
return is_variable_or_field_v<T>;
}
} // inline namespace v1
} // namespace meta
} // namespace cppx
namespace std
{
// Tuple adaptors for class_type
template<cppx::meta::reflection_t X>
struct tuple_size<cppx::meta::class_type<X>>
: std::integral_constant<std::size_t, cppx::meta::class_type<X>::size()>
{ };
template<std::size_t I, cppx::meta::reflection_t X>
struct tuple_element<I, cppx::meta::class_type<X>>
{
using type = decltype(get<I>(std::declval<cppx::meta::class_type<X>>().members()));
};
// Tuple adaptors for union_type
template<cppx::meta::reflection_t X>
struct tuple_size<cppx::meta::union_type<X>>
: std::integral_constant<std::size_t, cppx::meta::union_type<X>::size()>
{ };
template<std::size_t I, cppx::meta::reflection_t X>
struct tuple_element<I, cppx::meta::union_type<X>>
{
using type = decltype(get<I>(std::declval<cppx::meta::union_type<X>>().members()));
};
// Tuple adaptors for enum_type
template<cppx::meta::reflection_t X>
struct tuple_size<cppx::meta::enum_type<X>>
: std::integral_constant<std::size_t, cppx::meta::enum_type<X>::size()>
{ };
template<std::size_t I, cppx::meta::reflection_t X>
struct tuple_element<I, cppx::meta::enum_type<X>>
{
using type = decltype(get<I>(std::declval<cppx::meta::enum_type<X>>().members()));
};
// Tuple adaptors for ns
template<cppx::meta::reflection_t X>
struct tuple_size<cppx::meta::ns<X>>
: std::integral_constant<std::size_t, cppx::meta::ns<X>::size()>
{ };
template<std::size_t I, cppx::meta::reflection_t X>
struct tuple_element<I, cppx::meta::ns<X>>
{
using type = decltype(get<I>(std::declval<cppx::meta::ns<X>>().members()));
};
// Tuple adaptors for tu
template<cppx::meta::reflection_t X>
struct tuple_size<cppx::meta::tu<X>>
: std::integral_constant<std::size_t, cppx::meta::tu<X>::size()>
{ };
template<std::size_t I, cppx::meta::reflection_t X>
struct tuple_element<I, cppx::meta::tu<X>>
{
using type = decltype(get<I>(std::declval<cppx::meta::tu<X>>().members()));
};
} // namespace std
/// Make it easier for people to use the online compiler.
///
/// TODO: Remove this.
using namespace cppx::meta;
#endif // CPPX_META
You can’t perform that action at this time.