├── .gitignore ├── MetaLisp.hpp ├── README.md └── examples ├── MetaLisp.xcodeproj └── project.pbxproj ├── factorial.hpp ├── huffman.hpp ├── main.cpp ├── queen.hpp └── sqrt.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Xcode 3 | .DS_Store 4 | *.xcworkspace 5 | xcuserdata 6 | 7 | -------------------------------------------------------------------------------- /MetaLisp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __METALISP_H__ 2 | #define __METALISP_H__ 3 | 4 | #include 5 | 6 | struct number_tag { 7 | static const bool is_pair = false; 8 | static const bool is_null = false; 9 | static const bool is_number = true; 10 | static const bool is_boolean = false; 11 | static const bool is_symbol = false; 12 | }; 13 | 14 | struct null_tag { 15 | static const bool is_pair = false; 16 | static const bool is_null = true; 17 | static const bool is_number = false; 18 | static const bool is_boolean = false; 19 | static const bool is_symbol = false; 20 | }; 21 | 22 | struct pair_tag { 23 | static const bool is_pair = true; 24 | static const bool is_null = false; 25 | static const bool is_number = false; 26 | static const bool is_boolean = false; 27 | static const bool is_symbol = false; 28 | }; 29 | 30 | struct boolean_tag { 31 | static const bool is_pair = false; 32 | static const bool is_null = false; 33 | static const bool is_number = false; 34 | static const bool is_boolean = true; 35 | static const bool is_symbol = false; 36 | }; 37 | 38 | struct symbol_tag { 39 | static const bool is_pair = false; 40 | static const bool is_null = false; 41 | static const bool is_number = false; 42 | static const bool is_boolean = false; 43 | static const bool is_symbol = true; 44 | }; 45 | 46 | namespace impl { 47 | template 48 | struct gcd { 49 | static const int64_t value = gcd::value; 50 | }; 51 | 52 | template 53 | struct gcd { 54 | static const int64_t value = x; 55 | }; 56 | 57 | template 58 | struct rat_gcd; 59 | 60 | template 61 | struct rat_gcd { 62 | static const int64_t value = gcd::value; 63 | }; 64 | 65 | template 66 | struct rat_gcd { 67 | static const int64_t value = -gcd<-N, -D>::value; 68 | }; 69 | 70 | template 71 | struct rat_gcd { 72 | static const int64_t value = gcd<-N, D>::value; 73 | }; 74 | 75 | template 76 | struct rat_gcd { 77 | static const int64_t value = -gcd::value; 78 | }; 79 | 80 | template 81 | struct rat_reduce { 82 | static const int64_t numer = 0; 83 | static const int64_t denom = 1; 84 | }; 85 | 86 | template 87 | struct rat_reduce { 88 | static const int64_t numer = N / rat_gcd<(N < 0), (D < 0), N, D>::value; 89 | static const int64_t denom = D / rat_gcd<(N < 0), (D < 0), N, D>::value; 90 | }; 91 | } // namespace impl 92 | 93 | template 94 | struct number { 95 | using type = number; 96 | using tag = number_tag; 97 | static const int64_t numer = impl::rat_reduce<(N == 0 || D == 0), N, D>::numer; 98 | static const int64_t denom = impl::rat_reduce<(N == 0 || D == 0), N, D>::denom; 99 | }; 100 | 101 | // from https://github.com/irrequietus/typestring 102 | namespace impl { 103 | template 104 | struct Symbol { 105 | using type = Symbol; 106 | using tag = symbol_tag; 107 | static constexpr char const value[sizeof...(C) + 1] = {C..., '\0'}; 108 | 109 | }; 110 | 111 | template 112 | constexpr char tygrab(char const (&c)[M]) noexcept { 113 | return c[N < M ? N : M - 1]; 114 | } 115 | 116 | template 117 | auto typoke(Symbol) -> Symbol; 118 | 119 | template 120 | auto typoke(Symbol, Symbol<'\0'>, Symbol...) -> Symbol; 121 | 122 | template 123 | auto typoke(Symbol, Symbol, Symbol...) -> decltype(typoke(Symbol(), Symbol()...)); 124 | 125 | template 126 | auto typeek(Symbol) -> decltype(typoke(Symbol()...)); 127 | } 128 | 129 | #define TYPESTRING16(n, x) \ 130 | impl::tygrab<0x##n##0>(x), impl::tygrab<0x##n##1>(x), impl::tygrab<0x##n##2>(x), impl::tygrab<0x##n##3>(x), \ 131 | impl::tygrab<0x##n##4>(x), impl::tygrab<0x##n##5>(x), impl::tygrab<0x##n##6>(x), impl::tygrab<0x##n##7>(x), \ 132 | impl::tygrab<0x##n##8>(x), impl::tygrab<0x##n##9>(x), impl::tygrab<0x##n##A>(x), impl::tygrab<0x##n##B>(x), \ 133 | impl::tygrab<0x##n##C>(x), impl::tygrab<0x##n##D>(x), impl::tygrab<0x##n##E>(x), impl::tygrab<0x##n##F>(x) 134 | 135 | #define TYPESTRING32(n, x) TYPESTRING16(n##0, x), TYPESTRING16(n##1, x) 136 | 137 | #define symbol(x) decltype(impl::typeek(impl::Symbol())) 138 | 139 | template 140 | struct boolean { 141 | using tag = boolean_tag; 142 | using type = boolean; 143 | static const bool value = flag; 144 | }; 145 | 146 | struct null { 147 | using tag = null_tag; 148 | using type = null; 149 | }; 150 | 151 | template 152 | struct pair { 153 | using tag = pair_tag; 154 | using type = pair; 155 | using car_ = typename T::type; 156 | using cdr_ = typename U::type; 157 | }; 158 | 159 | template 160 | using is_null = boolean; 161 | 162 | template 163 | using is_pair = boolean; 164 | 165 | template 166 | using is_number = boolean; 167 | 168 | template 169 | using is_boolean = boolean; 170 | 171 | template 172 | using is_symbol = boolean; 173 | 174 | /////////////////////////////////////////////////////////////// 175 | template 176 | struct list; 177 | 178 | template 179 | struct list : public pair {}; 180 | 181 | template 182 | struct list : public pair> {}; 183 | 184 | template 185 | struct number_list; 186 | 187 | template 188 | struct number_list : public pair, null> {}; 189 | 190 | template 191 | struct number_list : public pair, number_list> {}; 192 | 193 | template 194 | struct car { 195 | using type = typename x::type::car_; 196 | using tag = typename type::tag; 197 | }; 198 | 199 | template 200 | struct cdr { 201 | using type = typename x::type::cdr_; 202 | using tag = typename type::tag; 203 | }; 204 | 205 | template 206 | struct cons : public pair {}; 207 | 208 | template 209 | using cadr = car>; 210 | 211 | template 212 | using cddr = cdr>; 213 | 214 | template 215 | using caddr = car>>; 216 | 217 | template 218 | using cadddr = car>>>; 219 | 220 | /////////////////////////////////////////////////////////////// 221 | template 222 | struct if_else_impl : public True {}; 223 | 224 | template 225 | struct if_else_impl, True, False> : public False {}; 226 | 227 | template 228 | struct if_else : public if_else_impl {}; 229 | 230 | template 231 | struct cond; 232 | 233 | template 234 | struct cond : public if_else> {}; 235 | 236 | template 237 | struct cond : public Else {}; 238 | 239 | ////////////////////////////////////////////////////////////// 240 | template 241 | struct or_ : public boolean<(a::type::value || b::type::value)> {}; 242 | 243 | template 244 | struct and_ : public boolean<(a::type::value && b::type::value)> {}; 245 | 246 | template 247 | struct not_ : public boolean<(!a::type::value)> {}; 248 | 249 | ///////////////////////////////////////// 250 | namespace impl { 251 | template 252 | using add = number; 253 | 254 | template 255 | using sub = number; 256 | 257 | template 258 | using is_greater = boolean<(n0 * d1 > d0 * n1)>; 259 | 260 | template 261 | using is_less = boolean<(n0 * d1 < d0 * n1)>; 262 | }; // namespace impl 263 | 264 | template 265 | struct add : public impl::add {}; 266 | 267 | template 268 | struct sub : public impl::sub {}; 269 | 270 | template 271 | struct mul : public number {}; 272 | 273 | template 274 | struct div_ : public number {}; 275 | 276 | template 277 | struct is_greater : public impl::is_greater {}; 278 | 279 | template 280 | struct is_less : public impl::is_less {}; 281 | 282 | template 283 | struct abs_ : public if_else>, a, number<-a::type::numer, a::type::denom>> {}; 284 | 285 | template 286 | struct is_equal_impl : public boolean {}; 287 | 288 | template 289 | struct is_equal_impl : public boolean<(a::type::numer == b::type::numer && a::type::denom == b::type::denom)> {}; 290 | 291 | template 292 | struct is_equal_impl : public boolean<(a::type::value == b::type::value)> {}; 293 | 294 | template 295 | struct is_equal : public is_equal_impl {}; 296 | 297 | template 298 | struct not_equal : public not_> {}; 299 | 300 | ///////////////////////////////////////////////////////////////////// 301 | template 302 | struct display_impl { 303 | static std::ostream &display(std::ostream &os, bool showBracket, number_tag) { 304 | if (T::type::denom == 1) { 305 | return os << T::type::numer; 306 | } else { 307 | return os << static_cast(T::type::numer) / static_cast(T::type::denom); 308 | } 309 | } 310 | 311 | static std::ostream &display(std::ostream &os, bool showBracket, symbol_tag) { 312 | return os << T::type::value; 313 | } 314 | 315 | static std::ostream &display(std::ostream &os, bool showBracket, boolean_tag) { 316 | if (T::type::value) { 317 | os << "#t"; 318 | } else { 319 | os << "#f"; 320 | } 321 | return os; 322 | } 323 | 324 | static std::ostream &display(std::ostream &os, bool showBracket, null_tag) { 325 | os << "()"; 326 | return os; 327 | } 328 | 329 | static std::ostream &display(std::ostream &os, bool showBracket, pair_tag) { 330 | if (showBracket) { 331 | os << "("; 332 | } 333 | display_impl>::display(os, true); 334 | using cdrT = cdr; 335 | if (is_null::value) { 336 | // nothing 337 | } else if (is_pair::value) { 338 | os << " "; 339 | display_impl>::display(os, false); 340 | } else { 341 | os << " . "; 342 | display_impl>::display(os, false); 343 | } 344 | if (showBracket) { 345 | os << ")"; 346 | } 347 | return os; 348 | } 349 | 350 | static std::ostream &display(std::ostream &os, bool showBracket) { 351 | return display(os, showBracket, typename T::tag()); 352 | } 353 | }; 354 | 355 | template 356 | void display(std::ostream &os = std::cout) { 357 | display_impl::display(os, true) << std::endl; 358 | }; 359 | 360 | ////////////////////////////////////////////// 361 | 362 | template 363 | struct length : public if_else, number<0>, add, length>>> {}; 364 | 365 | template 366 | struct list_ref : public if_else>, car, list_ref, sub>>> {}; 367 | 368 | template