pattern_utils.hh

00001 // This file is a part of Aurelia.
00002 // Copyright (C) 2010  Valentin David
00003 // Copyright (C) 2010  University of Bergen
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 #ifndef __PATTERN_UTILS_HH
00018 # define __PATTERN_UTILS_HH
00019 
00020 # include "pattern.hh"
00021 # include "../terms/term_concept.hh"
00022 
00023 namespace aurelia {
00024 
00025   template <typename T, typename Constr, size_t N,
00026             typename tuple, typename... SubPatterns>
00027   struct build_real_type;
00028 
00029   template <typename Constructor, typename ...SubPatterns>
00030   struct pattern;
00031 
00032   template <typename Pattern>
00033   struct builder;
00034 
00035   template <typename Constructor, typename ...SubPatterns>
00036   struct builder<pattern<Constructor, SubPatterns...> > {
00037     pattern<Constructor, SubPatterns...> p;
00038     builder(const pattern<Constructor, SubPatterns...>& p): p(p) {}
00039     builder(pattern<Constructor, SubPatterns...>&& p): p(std::move(p)) {}
00040 
00041     template <typename T,
00042               typename M = typename term_model<T>::model,
00043               typename = typename
00044               std::enable_if<std::is_convertible<
00045                                typename build_type<T, Constructor>::type,
00046                                T>::value>::type>
00047     operator T() {
00048       return build_real_type<T, Constructor, 0, std::tuple<SubPatterns...>,
00049                              SubPatterns...>::build(p.subpatterns);
00050     }
00051   };
00052 
00053   template <typename LHS, typename RHS, size_t N = 0,
00054             size_t Last = std::tuple_size<LHS>::value>
00055   struct assign_build {
00056     static void do_it(LHS& lhs, const RHS& rhs) {
00057       static_assert(std::tuple_size<LHS>::value == Last,
00058                     "Wrong size");
00059       static_assert(std::tuple_size<RHS>::value == Last,
00060                     "Wrong size");
00061       std::get<N>(lhs) = *std::get<N>(rhs);
00062       assign_build<LHS, RHS, N+1, Last>::do_it(lhs, rhs);
00063     }
00064   };
00065 
00066   template <typename LHS, typename RHS, size_t N>
00067   struct assign_build<LHS, RHS, N, N> {
00068     static void do_it(LHS&, const RHS&) {
00069       static_assert(std::tuple_size<LHS>::value == N,
00070                     "Wrong size");
00071       static_assert(std::tuple_size<RHS>::value == N,
00072                     "Wrong size");
00073     }
00074   };
00075 
00076   template <typename T, typename U,
00077             typename = decltype(std::declval<T>() =
00078                                 *(std::declval<const U>()))>
00079   std::true_type has_assign_build_helper(type_traits::try_first, T, U) {
00080     return 0;
00081   }
00082 
00083   template <typename T, typename U>
00084   std::false_type has_assign_build_helper(type_traits::try_second, T, U) {
00085     return 0;
00086   }
00087 
00088   template <typename T, typename U>
00089   struct can_match:
00090     type_traits::itself<
00091     decltype(has_assign_build_helper(type_traits::try_first(),
00092                                      std::declval<T>(),
00093                                      std::declval<U>()))>::type {
00094   };
00095 
00096   template <typename T, typename U, typename... TS, typename... US>
00097   struct can_match<std::tuple<T, TS...>, std::tuple<U, US...> >
00098   {
00099     enum: bool { value = can_match<T,U>::value &&
00100                  can_match<std::tuple<TS...>, std::tuple<US...> >::value };
00101   };
00102 
00103   template <>
00104   struct can_match<std::tuple<>, std::tuple<> >: public std::true_type {
00105   };
00106 
00107   template <typename Constructor, typename ...SubPatterns>
00108   struct pattern {
00109     Constructor constructor;
00110     std::tuple<SubPatterns...> subpatterns;
00111 
00112     pattern(const Constructor& constructor, SubPatterns... p):
00113       constructor(constructor), subpatterns(p...) {}
00114 
00115     template <typename Term,
00116               typename M = typename term_model<Term>::model>
00117     Term
00118     operator=(const Term& t) throw (failure) {
00119       typedef typename term_concept<M>::check require;
00120       t.match(*this);
00121       return t;
00122     }
00123 
00124     template <typename... OtherSubPatterns,
00125               typename = typename
00126               std::enable_if<can_match<std::tuple<SubPatterns...>,
00127                                        std::tuple<OtherSubPatterns...> >
00128               ::value>::type>
00129     const builder<pattern<Constructor, OtherSubPatterns...> >&
00130     operator=(const builder<pattern<Constructor, OtherSubPatterns...> >& b)
00131       throw (failure) {
00132       static_assert(sizeof...(SubPatterns)==sizeof...(OtherSubPatterns),
00133                     "Number of children in patterns not corresponding");
00134       assign_build<std::tuple<SubPatterns...>,
00135                    std::tuple<OtherSubPatterns...> >
00136         ::do_it(subpatterns, b.p.subpatterns);
00137       return b;
00138     }
00139 
00140     builder<pattern> operator*() const {
00141       return builder<pattern>(*this);
00142     }
00143 
00144   };
00145 
00146   template <typename Constructor, typename ...SubPatterns>
00147   struct pattern_model<pattern<Constructor, SubPatterns...> > {
00148     struct model {
00149       typedef pattern<Constructor, SubPatterns...> type;
00150       typedef builder<pattern<Constructor, SubPatterns...> > build_type;
00151     };
00152   };
00153 
00154   template <typename Constructor>
00155   struct pattern_generator {
00156     Constructor constructor;
00157 
00158     pattern_generator() {}
00159 
00160     pattern_generator(const Constructor& constructor):
00161       constructor(constructor) {}
00162 
00163     pattern_generator(const pattern_generator& other):
00164       constructor(other.constructor) {}
00165 
00166     template <typename ...A>
00167     pattern<Constructor, A...> operator()(A... a) const {
00168       return pattern<Constructor, A...>(constructor, std::forward<A>(a)...);
00169     }
00170   };
00171 
00172 }
00173 
00174 #endif