Commit 55d35dcf authored by Thierry Geraud's avatar Thierry Geraud
Browse files

Add meta switch-case; disambiguate typedef_.

	"typedef exists but its value is not_found" and "typedef is
	not found because it does not exist".

- tests/case.cc: New file.
- tests/switch.cc (where_): Precise name.
- tests/ret.cc: New file.
- mlc/bool.hh (assert): Remove is_true to avoid cryptic error
message such as "is_true" inaccessible.
- mlc/flags.hh (found): New class.
- mlc/typedef.hh (result2): New inner class to disambiguate between
"typedef is found but its value is not_found" and "typedef is not
found".
(mlc_ret, mlc_decl_typedef(ret)): Move to...
- mlc/ret.hh: ...this new file.
- mlc/switch.hh: Change that makes this file soon obsolete.
- mlc/case.hh: New file.


git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@415 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 119255ef
2006-03-02 Thierry Geraud <theo@lrde.epita.fr>
Add meta switch-case; disambiguate typedef_.
"typedef exists but its value is not_found" and "typedef is
not found because it does not exist".
* tests/case.cc: New file.
* tests/switch.cc (where_): Precise name.
* tests/ret.cc: New file.
* mlc/bool.hh (assert): Remove is_true to avoid cryptic error
message such as "is_true" inaccessible.
* mlc/flags.hh (found): New class.
* mlc/typedef.hh (result2): New inner class to disambiguate between
"typedef is found but its value is not_found" and "typedef is not
found".
(mlc_ret, mlc_decl_typedef(ret)): Move to...
* mlc/ret.hh: ...this new file.
* mlc/switch.hh: Change that makes this file soon obsolete.
* mlc/case.hh: New file.
2006-02-17 Thierry Geraud <theo@lrde.epita.fr>
Enhance error handling in mlc::switch_.
......
......@@ -276,9 +276,8 @@ namespace mlc
template <typename bexpr, typename err = no_error_message>
struct assert_ :
private virtual internal::check_<bexpr, typename bexpr::is_true>
public virtual internal::check_<bexpr, typename bexpr::is_true>
{
typedef dummy is_true;
protected:
assert_() {}
};
......@@ -339,6 +338,9 @@ namespace mlc
** each expression is true. 3) using "virtual" allow to encompass
** the multiple base class problem.
**
** Limitation: no error message can be provided with this present
** version of multiple_assert_ so prefer using several assert_.
**
** \see assert_<bexpr, err>
*/
......
// Copyright (C) 2005, 2006 EPITA Research and Development Laboratory
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
#ifndef METALIC_CASE_HH
# define METALIC_CASE_HH
# include <mlc/bool.hh>
# include <mlc/ret.hh>
# include <mlc/is_a.hh>
# include <mlc/implies.hh>
# include <mlc/comma.hh>
# include <mlc/cmp.hh>
# include <mlc/if.hh>
// FIXME: doc this file!
namespace mlc
{
struct case_selected {};
struct case_not_selected {};
namespace internal
{
struct a_simple_case;
struct a_switch_case;
const unsigned unknown_case_id = 10000U;
}
namespace ERROR
{
struct A_case_STATEMENT_SHOULD_NOT_START_AT_INDEX_0_BUT_1;
struct A_case_STATEMENT_SHOULD_DERIVE_FROM_mlc_where_;
struct A_default_case_STATEMENT_SHOULD_NOT_DERIVE_FROM_mlc_where_;
struct NO_case_STATEMENT_CAN_BE_SELECTED;
struct A_default_case_STATEMENT_IN_A_switch_SHOULD_HAVE_A_ret;
struct A_case_STATEMENT_IN_A_switch_SHOULD_HAVE_A_ret;
}
template <typename bexpr>
struct where_ : public mlc_if_( typename bexpr::eval,
case_selected,
case_not_selected )
{
};
} // end of namespace mlc
/// \def mlc_case_equipment_for_namespace(NAMESPACE)
# define mlc_case_equipment_for_namespace(NAMESPACE) \
\
namespace NAMESPACE \
{ \
\
template <typename context, \
typename data, \
unsigned i = mlc::internal::unknown_case_id> \
struct case_ : public mlc::undefined \
{ \
}; \
\
\
template <typename context, typename data> \
struct case_ <context, data, 0> : public mlc::undefined \
{ \
typedef mlc::locked ret; \
}; \
\
\
template <typename context, \
typename data> \
struct default_case_ : public mlc::undefined \
{ \
}; \
\
\
namespace internal \
{ \
\
template <typename use, \
typename context, typename data, unsigned i, \
bool the_ith_case_derives_from_true, \
bool the_ith_case_derives_from_false> \
struct handle_case_; \
\
\
template <typename use, \
typename context, typename data, unsigned i> \
struct handle_case_ <use, context, data, i, 1, 1>; \
\
\
template <typename use, typename context, typename data> \
struct handle_default_case_ \
\
: private mlc::assert_< mlc::implies_< mlc_is_not_a(mlc_comma_1(NAMESPACE::default_case_<context, data>), \
mlc::undefined), \
mlc_is_not_a(mlc_comma_1(NAMESPACE::default_case_<context, data>), \
mlc::where_) >, \
mlc::ERROR::A_default_case_STATEMENT_SHOULD_NOT_DERIVE_FROM_mlc_where_ >, \
\
private mlc::assert_< mlc::implies_< mlc::and_< mlc::eq_<use, mlc::internal::a_switch_case>, \
mlc_is_not_a(mlc_comma_1(NAMESPACE::default_case_<context, data>), \
mlc::undefined) >, \
mlc::ret_found_in_< NAMESPACE::default_case_<context, data> > >, \
mlc::ERROR::A_default_case_STATEMENT_IN_A_switch_SHOULD_HAVE_A_ret > \
{ \
typedef NAMESPACE::default_case_<context, data> case_t; \
typedef typename mlc::if_<mlc_is_a(case_t, mlc::undefined), \
mlc::none, \
case_t>::ret ret; \
}; \
\
\
template <typename use, typename context, typename data, unsigned i> \
struct handle_case_ <use, context, data, i, 0, 0> \
\
: private mlc::assert_< mlc::implies_< mlc_is_not_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::undefined), \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::where_) >, \
mlc::ERROR::A_case_STATEMENT_SHOULD_DERIVE_FROM_mlc_where_ > \
{ \
typedef handle_default_case_<use, context, data> handle_t; \
typedef typename handle_t::ret ret; \
}; \
\
\
\
template <typename use, \
typename context, typename data, unsigned i> \
struct handle_case_ <use, context, data, i, 1, 0> \
\
: private mlc::assert_< mlc::or_< mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::where_), \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::undefined) >, \
mlc::ERROR::A_case_STATEMENT_SHOULD_DERIVE_FROM_mlc_where_ >, \
\
private mlc::assert_< mlc::implies_< mlc::and_< mlc::eq_<use, mlc::internal::a_switch_case>, \
mlc_is_not_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::undefined) >, \
mlc::ret_found_in_< NAMESPACE::case_<context, data, i> > >, \
mlc::ERROR::A_case_STATEMENT_IN_A_switch_SHOULD_HAVE_A_ret > \
{ \
typedef NAMESPACE::case_<context, data, i> ret; \
}; \
\
\
\
template <typename use, \
typename context, typename data, unsigned i> \
struct handle_case_ <use, context, data, i, 0, 1> \
\
: private mlc::assert_< mlc::or_< mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::where_), \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::undefined) >, \
mlc::ERROR::A_case_STATEMENT_SHOULD_DERIVE_FROM_mlc_where_ >, \
\
private mlc::assert_< mlc::implies_< mlc::and_< mlc::eq_<use, mlc::internal::a_switch_case>, \
mlc_is_not_a(mlc_comma_2(NAMESPACE::case_<context, data, i>), \
mlc::undefined) >, \
mlc::ret_found_in_< NAMESPACE::case_<context, data, i> > >, \
mlc::ERROR::A_case_STATEMENT_IN_A_switch_SHOULD_HAVE_A_ret > \
{ \
typedef handle_case_ < \
use, \
context, data, i+1, \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i+1>), \
mlc::case_selected)::value, \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, i+1>), \
mlc::case_not_selected)::value > next_t; \
typedef typename next_t::ret ret; \
}; \
\
\
\
template <typename use, typename context, typename data> \
struct select_case_ \
\
: private mlc::assert_< mlc::eq_< mlc_ret(mlc_comma_2(NAMESPACE::case_<context, data, 0>)), \
mlc::locked >, \
mlc::ERROR::A_case_STATEMENT_SHOULD_NOT_START_AT_INDEX_0_BUT_1 > \
{ \
typedef handle_case_ < \
use, \
context, data, 1, \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, 1>), \
mlc::case_selected)::value, \
mlc_is_a(mlc_comma_2(NAMESPACE::case_<context, data, 1>), \
mlc::case_not_selected)::value > handle_t; \
typedef typename handle_t::ret ret; \
}; \
\
\
} \
\
\
template <typename context, typename data> \
struct case_ <context, data, mlc::internal::unknown_case_id> \
\
: private mlc::assert_< mlc::neq_< mlc_comma_2(typename NAMESPACE::internal::select_case_<mlc::internal::a_simple_case, \
context, data>::ret), \
mlc::none >, \
mlc::ERROR::NO_case_STATEMENT_CAN_BE_SELECTED > \
\
{ \
typedef typename NAMESPACE::internal::select_case_<mlc::internal::a_simple_case, context, data>::ret ret; \
}; \
\
\
template <typename context, typename data> \
struct switch_ \
\
: private mlc::assert_< mlc::neq_< mlc_comma_2(typename NAMESPACE::internal::select_case_<mlc::internal::a_switch_case, \
context, data>::ret), \
mlc::none >, \
mlc::ERROR::NO_case_STATEMENT_CAN_BE_SELECTED > \
\
{ \
typedef typename NAMESPACE::internal::select_case_<mlc::internal::a_switch_case, context, data>::ret case_t; \
typedef typename case_t::ret ret; \
}; \
\
\
} \
\
struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n \
#endif // ! METALIC_CASE_HH
......@@ -151,6 +151,15 @@ namespace mlc {
struct not_found : public abstract::flag {};
/*! \class mlc::found
**
** The class corresponding to "not mlc::not_found".
**
** \see mlc::not_found
*/
struct found : public abstract::flag {};
/*! \class mlc::undefined
**
** Flag class to state that a type is undefined, that is, declared
......
// Copyright (C) 2005, 2006 EPITA Research and Development Laboratory
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
#ifndef METALIC_RET_HH
# define METALIC_RET_HH
# include <mlc/typedef.hh>
/*! \FIXME: what's the correct comment flag here?
**
** Since we often rely on having a typedef named "ret" in types, we offer
** a default equipment for this particular typedef. FIXME: doc
*/
mlc_decl_typedef(ret);
# define mlc_ret(Type) typename typedef_::ret::from_<Type>::ret
// test code
# define mlc_ret2(Type) typename typedef_::ret::from_<Type>::ret2
namespace mlc
{
template <typename T>
struct ret_found_in_
: public mlc::eq_< typename typedef_::ret::from_<T>::ret2::first_elt,
mlc::found >
{};
} // end of namespace mlc
#endif // ! METALIC_RET_HH
......@@ -57,21 +57,6 @@ namespace mlc
{
};
// template <typename bexpr>
// struct where_ : public where_<typename bexpr::eval>
// {
// };
// template <>
// struct where_<true_>
// {
// };
// template <>
// struct where_<false_>
// {
// };
// FIXME: doc
......@@ -98,8 +83,8 @@ namespace mlc
namespace ERROR
{
struct A_case_STATEMENT_IN_mlc_switch_SHOULD_DERIVE_FROM_mlc_where_;
struct A_default_case_STATEMENT_IN_mlc_switch_SHOULD_NOT_DERIVE_FROM_mlc_where_;
struct A_case_STATEMENT_SHOULD_DERIVE_FROM_mlc_where_;
struct A_default_case_STATEMENT_SHOULD_NOT_DERIVE_FROM_mlc_where_;
struct SWITCH_DOES_NOT_HAVE_A_CASE_FOR_YOUR_DATA;
struct RESULT_IS_NOT_FOUND_IN_default_case_;
template <unsigned i> struct RESULT_IS_NOT_FOUND_IN_case_;
......@@ -134,7 +119,7 @@ namespace mlc
undefined),
mlc_is_not_a(mlc_comma_1(default_case_<context, data>),
where_) >,
ERROR::A_default_case_STATEMENT_IN_mlc_switch_SHOULD_NOT_DERIVE_FROM_mlc_where_ >,
ERROR::A_default_case_STATEMENT_SHOULD_NOT_DERIVE_FROM_mlc_where_ >,
private assert_< implies_< mlc_is_not_a(mlc_comma_1(default_case_<context, data>),
undefined),
......@@ -146,8 +131,7 @@ namespace mlc
typedef default_case_<context, data> current_t;
typedef typename mlc::if_<mlc_is_a(current_t, undefined),
none,
current_t>::ret case_type;
typedef mlc_ret(current_t) ret;
current_t>::ret ret;
};
......@@ -163,12 +147,11 @@ namespace mlc
undefined),
mlc_is_a(mlc_comma_2(case_<context, data, i>),
where_) >,
ERROR::A_case_STATEMENT_IN_mlc_switch_SHOULD_DERIVE_FROM_mlc_where_ >
ERROR::A_case_STATEMENT_SHOULD_DERIVE_FROM_mlc_where_ >
{
typedef handle_default_case_<context, data> last_t;
typedef typename last_t::case_type case_type;
typedef typename last_t::ret ret;
typedef mlc_ret(last_t) ret;
};
......@@ -191,8 +174,7 @@ namespace mlc
ERROR::RESULT_IS_NOT_FOUND_IN_case_<i> >
{
typedef case_<context, data, i> case_type;
typedef mlc_ret(case_type) ret;
typedef case_<context, data, i> ret;
};
......@@ -216,24 +198,22 @@ namespace mlc
internal::case_true)::value,
mlc_is_a(mlc_comma_2(case_<context, data, i+1>),
internal::case_false)::value > next_t;
typedef typename next_t::case_type case_type;
typedef typename next_t::ret ret;
typedef mlc_ret(next_t) ret;
};
// switch_
// case_
template <typename context, typename data>
struct switch_
struct case_
{
typedef internal::handle_case_ < context, data, 1,
mlc_is_a(mlc_comma_2(case_<context, data, 1>),
internal::case_true)::value,
mlc_is_a(mlc_comma_2(case_<context, data, 1>),
internal::case_false)::value > handle_t;
typedef typename handle_t::case_type case_type;
typedef typename handle_t::ret ret;
typedef mlc_ret(handle_t) ret;
};
......@@ -244,13 +224,29 @@ namespace mlc
// FIXME: doc
template <typename context, typename data>
struct switch_
: private assert_< neq_< mlc_comma_1(typename internal::switch_<context, data>::case_type),
struct case_
: private assert_< neq_< mlc_comma_1(typename internal::case_<context, data>::ret),
none >,
ERROR::SWITCH_DOES_NOT_HAVE_A_CASE_FOR_YOUR_DATA >
{
typedef typename internal::switch_<context, data>::case_type case_type;
typedef typename internal::switch_<context, data>::ret ret;
typedef typename internal::case_<context, data>::ret ret;
};
// FIXME: doc
template <typename context, typename data>
struct switch_
: private assert_< neq_< mlc_comma_1(typename internal::case_<context, data>::ret),
none >,
ERROR::SWITCH_DOES_NOT_HAVE_A_CASE_FOR_YOUR_DATA >,
private assert_< neq_< mlc_ret(),
not_found >,
ERROR::SWITCH_
{
typedef typename internal::case_<context, data>::ret case_t;
typedef mlc_ret(case_t) ret;
};
......
// Copyright (C) 2005 EPITA Research and Development Laboratory
// Copyright (C) 2005, 2006 EPITA Research and Development Laboratory
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
......@@ -30,6 +30,8 @@
# include <mlc/flags.hh>
# include <mlc/bool.hh>
# include <mlc/pair.hh>
# include <mlc/cmp.hh>
/*! \macro mlc_decl_typedef(TypedefName)
......@@ -149,7 +151,7 @@ namespace typedef_ { \
template <class T> \
static no selector(...); \
\
template <class T, bool found> \
template <class T, bool found_> \
struct result; \
\
template <class T> \
......@@ -162,6 +164,21 @@ namespace typedef_ { \
typedef mlc::not_found ret; \
}; \
\
template <class T, bool found_> \
struct result2; \
\
template <class T> \
struct result2 <T, true> { \
typedef mlc::pair_<mlc::found, \
typename T::TypedefName> ret; \
}; \
\
template <class T> \
struct result2 <T, false> { \
typedef mlc::pair_<mlc::not_found, \
mlc::dummy> ret; \
}; \
\
}; \
\
} \
......@@ -181,6 +198,10 @@ namespace typedef_ { \
typedef \
typename helper_::result<T, found_>::ret \
ret; \
\
typedef \
typename helper_::result2<T, found_>::ret \
ret2; \
}; \
\
template <class T, bool b> \
......@@ -205,7 +226,7 @@ namespace typedef_ { \
\
} \
\
struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n
struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n \
/*! \macro mlc_typedef(Type, TypedefName)
......@@ -246,17 +267,4 @@ struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n
typedef_::TypedefName::from_onlyif_<Type, mlc_bool(Bexpr)>::ret
/*! \FIXME: what's the correct comment flag here?
**
** Since we often rely on having a typedef named "ret" in types, we offer
** a default equipment for this particular typedef. FIXME: doc
*/
mlc_decl_typedef(ret);
# define mlc_ret(Type) typename typedef_::ret::from_<Type>::ret
#endif // ! METALIC_TYPEDEF_HH
#include <mlc/is_a.hh>
#include <mlc/case.hh>
struct test;
mlc_case_equipment_for_namespace(client);
namespace client
{
template <class T>
struct case_ <test, T, 1> : public mlc::where_< mlc_is_a(T, short) >
{
};
template <class T>
struct case_ <test, T, 2> : public mlc::where_< mlc_is_a(T, int) >
{
};
// ok
template <class T>
struct case_ <test, T, 3> : public mlc::where_< mlc_is_a(T, char) >
{
};