
// ============ Forward declarations ==============

template <typename T> inline const auto & GET_VALUE( const T &x) ;
template <typename T> inline auto & GET_VALUE(  T &x) ;
template <typename T> inline bool HAS_VALUE( const T &x) ;
template <typename T> inline bool HAS_VALUE(  T &x) ;

#ifndef IGNORE_Scalar
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Scalar<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Scalar<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Scalar<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Scalar<T> &x) ;
#endif

#ifndef IGNORE_Constant
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Constant<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Constant<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Constant<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Constant<T> &x) ;
#endif

#ifndef IGNORE_Integer
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Integer<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Integer<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Integer<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Integer<T> &x) ;
#endif

#ifndef IGNORE_Logical
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Logical<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Logical<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Logical<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Logical<T> &x) ;
#endif

#ifndef IGNORE_DefaultChar
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::DefaultChar<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::DefaultChar<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::DefaultChar<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::DefaultChar<T> &x) ;
#endif

#ifndef IGNORE_Indirection
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Indirection<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Indirection<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Indirection<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Indirection<T> &x) ;
#endif

#ifndef IGNORE_Statement
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Statement<T> &x) ;
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Statement<T> &x) ;
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Statement<T> &x) ;
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Statement<T> &x) ;
#endif

#ifndef IGNORE_optional
template <typename T> inline const auto & GET_VALUE( const std::optional<T> &x)  ;
template <typename T> inline auto & GET_VALUE(  std::optional<T> &x) ;
template <typename T> inline bool HAS_VALUE( const std::optional<T> &x) ;
template <typename T> inline bool HAS_VALUE(  std::optional<T> &x) ;
#endif


// =========== Actual implementation of GET_VALUE() and HAS_VALUE() ==============================


template <typename T> inline const auto & GET_VALUE( const T &x) { return x ;}
template <typename T> inline auto & GET_VALUE(  T &x) { return x ;}
template <typename T> inline bool HAS_VALUE( const T &x) { return true; }
template <typename T> inline bool HAS_VALUE(  T &x) { return true; }

#ifndef IGNORE_Scalar
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Scalar<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Scalar<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Scalar<T> &x) { return HAS_VALUE(x.thing)  ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Scalar<T> &x) { return HAS_VALUE(x.thing)  ;}
#endif

#ifndef IGNORE_Constant
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Constant<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Constant<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Constant<T> &x) { return HAS_VALUE(x.thing)  ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Constant<T> &x) { return HAS_VALUE(x.thing)  ;}
#endif

#ifndef IGNORE_Integer
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Integer<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Integer<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Integer<T> &x) { return HAS_VALUE(x.thing)  ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Integer<T> &x) { return HAS_VALUE(x.thing)  ;}
#endif

#ifndef IGNORE_Logical
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Logical<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Logical<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Logical<T> &x) { return HAS_VALUE(x.thing)  ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Logical<T> &x) { return HAS_VALUE(x.thing)  ;}
#endif

#ifndef IGNORE_DefaultChar
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::DefaultChar<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::DefaultChar<T> &x) { return GET_VALUE(x.thing) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::DefaultChar<T> &x) { return HAS_VALUE(x.thing)  ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::DefaultChar<T> &x) { return HAS_VALUE(x.thing)  ;}
#endif

#ifndef IGNORE_Indirection
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Indirection<T> &x) { return GET_VALUE(*x) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Indirection<T> &x) { return GET_VALUE(*x) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Indirection<T> &x) { return GET_VALUE(*x) ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Indirection<T> &x) { return GET_VALUE(*x) ;}
#endif

#ifndef IGNORE_Statement
template <typename T> inline const auto & GET_VALUE( const Fortran::parser::Statement<T> &x) { return GET_VALUE(x.statement) ;}
template <typename T> inline auto & GET_VALUE(  Fortran::parser::Statement<T> &x) { return GET_VALUE(x.statement) ;}
template <typename T> inline bool HAS_VALUE( const Fortran::parser::Statement<T> &x) { return HAS_VALUE(x.statement) ;}
template <typename T> inline bool HAS_VALUE(  Fortran::parser::Statement<T> &x) { return HAS_VALUE(x.statement) ;}
#endif

#ifndef IGNORE_optional
template <typename T> inline const auto & GET_VALUE( const std::optional<T> &x)  { return GET_VALUE(x.value()) ; } 
template <typename T> inline auto & GET_VALUE(  std::optional<T> &x) { return GET_VALUE(x.value()) ; } 
template <typename T> inline bool HAS_VALUE( const std::optional<T> &x) { return x.has_value() && HAS_VALUE(*x); } 
template <typename T> inline bool HAS_VALUE(  std::optional<T> &x) { return x.has_value() && HAS_VALUE(*x); } 
#endif

template <typename T> inline auto GET_OPT_VALUE(const T &x) { 
  if ( HAS_VALUE(x) ) {
    return & GET_VALUE(x) ;
  } else {
    return decltype(&GET_VALUE(x)){0} ;
  }
}

template <typename T> inline auto GET_OPT_VALUE(T &x) { 
  if ( HAS_VALUE(x) ) {
    return & GET_VALUE(x) ;
  } else {
    return decltype(&GET_VALUE(x)){0} ;
  }
}

#undef GET_VALUE
#undef HAS_VALUE
#undef GET_OPT_VALUE
