2018-02-16 20:42:17 +01:00
|
|
|
#ifndef FORTRAN_PARSER_IDIOMS_H_
|
|
|
|
#define FORTRAN_PARSER_IDIOMS_H_
|
2018-01-30 20:53:33 +01:00
|
|
|
|
|
|
|
// Defines anything that might ever be useful in more than one source file
|
|
|
|
// or that is too weird or too specific to the host C++ compiler to be
|
|
|
|
// exposed elsewhere.
|
|
|
|
|
|
|
|
#ifndef __cplusplus
|
2018-02-05 23:29:26 +01:00
|
|
|
#error this is a C++ program
|
2018-01-30 20:53:33 +01:00
|
|
|
#endif
|
|
|
|
#if __cplusplus < 201703L
|
2018-02-05 23:29:26 +01:00
|
|
|
#error this is a C++17 program
|
2018-01-30 20:53:33 +01:00
|
|
|
#endif
|
|
|
|
#if defined __GNUC__ && __GNUC__ < 7
|
2018-02-05 23:29:26 +01:00
|
|
|
#error G++ >= 7.0 is required
|
2018-01-30 20:53:33 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <optional>
|
|
|
|
#include <tuple>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <variant>
|
|
|
|
|
2018-02-16 19:58:17 +01:00
|
|
|
// Avoid a deduction bug in GNU 7.3.0 headers by forcing the answer.
|
2018-01-30 20:53:33 +01:00
|
|
|
// TODO: better resolution
|
|
|
|
namespace std {
|
|
|
|
template<typename A>
|
|
|
|
struct is_trivially_copy_constructible<list<A>> : false_type {};
|
|
|
|
template<typename A>
|
|
|
|
struct is_trivially_copy_constructible<optional<list<A>>> : false_type {};
|
|
|
|
} // namespace std
|
|
|
|
|
|
|
|
using namespace std::string_literals; // enable "this is a std::string"s
|
|
|
|
|
|
|
|
namespace Fortran {
|
2018-02-07 21:04:42 +01:00
|
|
|
namespace parser {
|
2018-01-30 20:53:33 +01:00
|
|
|
|
|
|
|
// Helper templates for combining a list of lambdas into an anonymous
|
|
|
|
// struct for use with std::visit() on a std::variant<> sum type.
|
|
|
|
// E.g.: std::visit(visitors{
|
|
|
|
// [&](const UnaryExpr &x) { ... },
|
|
|
|
// [&](const BinaryExpr &x) { ... },
|
|
|
|
// ...
|
|
|
|
// }, structure.unionMember);
|
|
|
|
|
2018-02-05 23:29:26 +01:00
|
|
|
template<typename... LAMBDAS> struct visitors : LAMBDAS... {
|
2018-01-30 20:53:33 +01:00
|
|
|
using LAMBDAS::operator()...;
|
|
|
|
};
|
|
|
|
|
2018-02-05 23:29:26 +01:00
|
|
|
template<typename... LAMBDAS> visitors(LAMBDAS... x)->visitors<LAMBDAS...>;
|
2018-01-30 20:53:33 +01:00
|
|
|
|
|
|
|
// Calls std::fprintf(stderr, ...), then abort().
|
2018-02-05 21:48:09 +01:00
|
|
|
[[noreturn]] void die(const char *, ...);
|
2018-01-30 20:53:33 +01:00
|
|
|
|
|
|
|
// Treat operator! as if it were a Boolean context, i.e. like if() and ? :,
|
|
|
|
// when its operand is std::optional<>.
|
|
|
|
template<typename A> bool operator!(const std::optional<A> &x) {
|
|
|
|
return !x.has_value();
|
|
|
|
}
|
|
|
|
|
|
|
|
// For switch statements without default: labels.
|
2018-02-08 00:19:54 +01:00
|
|
|
#define CRASH_NO_CASE \
|
|
|
|
Fortran::parser::die("no case at " __FILE__ "(%d)", __LINE__)
|
2018-01-30 20:53:33 +01:00
|
|
|
|
|
|
|
// For cheap assertions that should be applied in production.
|
2018-02-15 19:42:36 +01:00
|
|
|
// To disable, compile with '-DCHECK=(void)'
|
2018-02-13 21:24:54 +01:00
|
|
|
#ifndef CHECK
|
2018-01-30 20:53:33 +01:00
|
|
|
#define CHECK(x) \
|
2018-02-08 00:19:54 +01:00
|
|
|
((x) || \
|
|
|
|
(Fortran::parser::die( \
|
|
|
|
"CHECK(" #x ") failed at " __FILE__ "(%d)", __LINE__), \
|
|
|
|
false))
|
2018-02-13 21:24:54 +01:00
|
|
|
#endif
|
2018-01-30 20:53:33 +01:00
|
|
|
|
|
|
|
// To make error messages more informative, wrap some type information
|
|
|
|
// around a false compile-time value, e.g.
|
|
|
|
// static_assert(BadType<T>::value, "no case for type");
|
|
|
|
template<typename A> struct BadType : std::false_type {};
|
|
|
|
|
2018-02-28 22:24:01 +01:00
|
|
|
// User-defined type traits that default to false:
|
|
|
|
// Invoke CLASS_TRAIT(traitName) to define a trait, then put
|
|
|
|
// using traitName = std::true_type; (or false_type)
|
|
|
|
// into the appropriate class definitions. You can then use
|
|
|
|
// typename std::enable_if<traitName<...>, ...>::type
|
|
|
|
// in template specialization definitions.
|
|
|
|
#define CLASS_TRAIT(T) \
|
|
|
|
namespace class_trait_ns_##T { \
|
2018-02-28 23:53:04 +01:00
|
|
|
template<typename A> std::true_type test(typename A::T *); \
|
|
|
|
template<typename A> std::false_type test(...); \
|
|
|
|
template<typename A> \
|
2018-02-28 22:24:01 +01:00
|
|
|
constexpr bool has_trait{decltype(test<A>(nullptr))::value}; \
|
2018-02-28 23:53:04 +01:00
|
|
|
template<typename A> \
|
2018-02-28 22:24:01 +01:00
|
|
|
constexpr typename std::enable_if<has_trait<A>, bool>::type \
|
2018-02-28 23:53:04 +01:00
|
|
|
trait_value() { \
|
|
|
|
using U = typename A::T; \
|
|
|
|
return U::value; \
|
|
|
|
} \
|
|
|
|
template<typename A> \
|
2018-02-28 22:24:01 +01:00
|
|
|
constexpr typename std::enable_if<!has_trait<A>, bool>::type \
|
2018-02-28 23:53:04 +01:00
|
|
|
trait_value() { \
|
|
|
|
return false; \
|
|
|
|
} \
|
2018-02-28 22:24:01 +01:00
|
|
|
} \
|
2018-02-28 23:53:04 +01:00
|
|
|
template<typename A> constexpr bool T { class_trait_ns_##T::trait_value<A>() }
|
2018-02-07 21:04:42 +01:00
|
|
|
} // namespace parser
|
2018-01-30 20:53:33 +01:00
|
|
|
} // namespace Fortran
|
2018-02-16 20:42:17 +01:00
|
|
|
#endif // FORTRAN_PARSER_IDIOMS_H_
|