summaryrefslogtreecommitdiff
path: root/src/sexpr
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2015-01-03 21:07:56 -0800
committerBen Longbons <b.r.longbons@gmail.com>2015-01-03 21:58:26 -0800
commit00da6b5977574a0564169172227d8aab45be188f (patch)
treedd52eee506a98e1eb9fcdea52e7db25079a7ad28 /src/sexpr
parent4c91abd6a020ee030114ae3f22d8f6066e7528be (diff)
downloadtmwa-00da6b5977574a0564169172227d8aab45be188f.tar.gz
tmwa-00da6b5977574a0564169172227d8aab45be188f.tar.bz2
tmwa-00da6b5977574a0564169172227d8aab45be188f.tar.xz
tmwa-00da6b5977574a0564169172227d8aab45be188f.zip
Switch MATCH to separate begin/end macros
The for loop trick turned out to be very prone to infinite loops at runtime. It's better to force compiler errors even if it's ugly.
Diffstat (limited to 'src/sexpr')
-rw-r--r--src/sexpr/fwd.hpp1
-rw-r--r--src/sexpr/variant.hpp46
-rw-r--r--src/sexpr/variant_test.cpp32
3 files changed, 54 insertions, 25 deletions
diff --git a/src/sexpr/fwd.hpp b/src/sexpr/fwd.hpp
index 41e21a1..b86d9fb 100644
--- a/src/sexpr/fwd.hpp
+++ b/src/sexpr/fwd.hpp
@@ -21,7 +21,6 @@
#include "../sanity.hpp"
#include "../strings/fwd.hpp" // rank 1
-#include "../compat/fwd.hpp" // rank 2
#include "../io/fwd.hpp" // rank 4
// sexpr/fwd.hpp is rank 5
diff --git a/src/sexpr/variant.hpp b/src/sexpr/variant.hpp
index 287a5f0..0eccc5a 100644
--- a/src/sexpr/variant.hpp
+++ b/src/sexpr/variant.hpp
@@ -23,8 +23,6 @@
#include <cstddef>
#include <utility>
-#include "../compat/attr.hpp"
-
#include "union.hpp"
#include "void.hpp"
@@ -35,14 +33,42 @@ namespace tmwa
{
namespace sexpr
{
-#define MATCH(expr) \
- WITH_VAR_NOLOOP(auto&&, _match_var, expr) \
- switch (tmwa::sexpr::VariantFriend::get_state(_match_var))
-#define TYPED_CASE(ty, var, look) \
- break; \
- case tmwa::sexpr::VariantFriend::get_state_for<look, decltype(_match_var)>(): \
- WITH_VAR_INLOOP(ty, var, tmwa::sexpr::VariantFriend::unchecked_get<look>(_match_var))
-#define CASE(ty, var) TYPED_CASE(ty, var, std::remove_const<std::remove_reference<ty>::type>::type)
+#define MATCH_BEGIN(expr) \
+ { \
+ auto&& _match_var = (expr); \
+ switch (tmwa::sexpr::VariantFriend::get_state(_match_var)) \
+ { \
+ { \
+ { \
+ /* }}}} */
+#define MATCH_END() \
+ /* {{{{ */ \
+ } \
+ } \
+ } \
+ (void) _match_var; \
+ }
+
+#define MATCH_CASE(ty, v) \
+ /* {{{{ */ \
+ } \
+ break; \
+ } \
+ { \
+ using _match_case_type = std::remove_const<std::remove_reference<ty>::type>::type; \
+ case tmwa::sexpr::VariantFriend::get_state_for<_match_case_type, decltype(_match_var)>(): \
+ { \
+ ty v = tmwa::sexpr::VariantFriend::unchecked_get<_match_case_type>(_match_var);
+ /* }}}} */
+#define MATCH_DEFAULT() \
+ /* {{{{ */ \
+ } \
+ break; \
+ } \
+ { \
+ default: \
+ { \
+ /* }}}} */
template<class... T>
class Variant
diff --git a/src/sexpr/variant_test.cpp b/src/sexpr/variant_test.cpp
index bc378aa..c671264 100644
--- a/src/sexpr/variant_test.cpp
+++ b/src/sexpr/variant_test.cpp
@@ -77,42 +77,46 @@ TEST(variant, match)
: sexpr::Variant<Foo, Bar>(Foo(1))
{}
};
+
Sub v1;
- MATCH (v1)
+ MATCH_BEGIN (v1)
{
- // This is not a public API, it's just for testing.
- default:
- FAIL();
-
- CASE(Foo, f)
+ MATCH_DEFAULT ()
+ {
+ FAIL();
+ }
+ MATCH_CASE (Foo, f)
{
(void)f;
SUCCEED();
}
- CASE(Bar, b)
+ MATCH_CASE (Bar, b)
{
(void)b;
FAIL();
}
}
+ MATCH_END ();
+
v1.emplace<Bar>(2);
- MATCH (v1)
+ MATCH_BEGIN (v1)
{
- // This is not a public API, it's just for testing.
- default:
- FAIL();
-
- CASE(Foo, f)
+ MATCH_DEFAULT ()
+ {
+ FAIL();
+ }
+ MATCH_CASE (Foo, f)
{
(void)f;
FAIL();
}
- CASE(Bar, b)
+ MATCH_CASE (Bar, b)
{
(void)b;
SUCCEED();
}
}
+ MATCH_END ();
}
TEST(variant, copymove1)