Skip to content

Instantly share code, notes, and snippets.

@dekrain
Created October 27, 2020 21:25
Show Gist options
  • Save dekrain/20824f4b287ba99ac4b92ef962361c05 to your computer and use it in GitHub Desktop.
Save dekrain/20824f4b287ba99ac4b92ef962361c05 to your computer and use it in GitHub Desktop.
Gorbitsa compile-time interpreter. Based on @qookei 's version
/*
* compile with: g++ gorbitsa.cpp -o gorbitsa -ftemplate-depth=99999999 -std=c++2a
* Tested with GCC 10.1, does *not* work with Clang 10
* Editor's note: not anymore ;)
*/
#include <iostream>
#include <string_view>
#include <cctype>
#include <array>
#include <type_traits>
#include <tuple>
// From https://github.com/managarm/frigg/blob/master/include/frg/array.hpp, lines 92-124
// s/frg::/std::/
namespace details {
template<typename ...Ts>
struct concat_size;
template<typename ...Ts>
inline constexpr size_t concat_size_v = concat_size<Ts...>::value;
template<typename T, typename ...Ts>
struct concat_size<T, Ts...>
: std::integral_constant<size_t, std::tuple_size_v<T> + concat_size_v<Ts...>> { };
template<>
struct concat_size<>
: std::integral_constant<size_t, 0> { };
template<typename X, size_t N>
constexpr void concat_insert(std::array<X, N> &, size_t) { }
template<typename X, size_t N, typename T, typename... Ts>
constexpr void concat_insert(std::array<X, N> &res, size_t at, const T &other, const Ts &...tail) {
size_t n = std::tuple_size_v<T>;
for(size_t i = 0; i < n; ++i)
res[at + i] = other[i];
concat_insert(res, at + n, tail...);
}
} // namespace details
template <const char* s, size_t i, char f, char... ss>
struct _str_to_arr
: _str_to_arr<s, i+1, s[i+1], ss..., f> {};
template <const char* s, size_t i, char... ss>
struct _str_to_arr<s, i, 0, ss...> {
using type = std::integer_sequence<char, ss...>;
};
template <const char* s>
struct str_to_arr
: _str_to_arr<s, 0, s[0]> {};
template <typename arr>
struct arr_size;
template <typename T, auto... v>
struct arr_size<std::integer_sequence<T, v...>>
: std::integral_constant<size_t, sizeof...(v)> {};
template <typename T>
static constexpr inline auto arr_size_v = arr_size<T>::value;
template <typename arr, size_t idx>
struct arr_elem;
template <typename T, auto a, auto... b>
struct arr_elem<std::integer_sequence<T, a, b...>, 0>
: std::integral_constant<decltype(a), a> {};
template <typename T, size_t idx, auto a, auto... b>
struct arr_elem<std::integer_sequence<T, a, b...>, idx>
: arr_elem<std::integer_sequence<T, b...>, idx-1> {};
template <typename T, size_t idx>
static constexpr inline auto arr_elem_v = arr_elem<T, idx>::value;
template <typename T, T v, size_t count, T... vs>
struct arr_makefill {
using type = typename arr_makefill<T, v, count-1, vs..., v>::type;
};
template <typename T, T v, T... vs>
struct arr_makefill<T, v, 0, vs...> {
using type = std::integer_sequence<T, vs...>;
};
template <typename arr, auto v>
struct arr_append;
template <typename T, auto... vs, auto v>
struct arr_append<std::integer_sequence<T, vs...>, v> {
using type = std::integer_sequence<T, vs..., v>;
};
template <typename arr, auto v>
using arr_append_t = typename arr_append<arr, v>::type;
template <typename arr, typename narr, size_t idx, auto nv>
struct _arr_replace;
template <typename T, auto... nvs, auto va, auto... vs, auto nv>
struct _arr_replace<std::integer_sequence<T, va, vs...>, std::integer_sequence<T, nvs...>, 0, nv> {
using type = std::integer_sequence<T, nvs..., nv, vs...>;
};
template <typename T, size_t idx, auto... nvs, auto va, auto... vs, auto nv>
struct _arr_replace<std::integer_sequence<T, va, vs...>, std::integer_sequence<T, nvs...>, idx, nv>
: _arr_replace<std::integer_sequence<T, vs...>, std::integer_sequence<T, nvs..., va>, idx-1, nv> {};
template <typename arr, size_t idx, auto nv>
struct arr_replace;
template <typename T, T... vs, size_t idx, auto nv>
struct arr_replace<std::integer_sequence<T, vs...>, idx, nv> : _arr_replace<std::integer_sequence<T, vs...>, std::integer_sequence<T>, idx, nv> {};
template <typename arr, size_t idx, auto nv>
using arr_replace_t = typename arr_replace<arr, idx, nv>::type;
template <typename arr>
struct arr_collapse;
template <typename T, T... vs>
struct arr_collapse<std::integer_sequence<T, vs...>> {
static constexpr inline auto value = std::array<T, sizeof...(vs)>{vs...};
};
template <size_t PC, uint8_t X, typename Ram, typename Out, typename Prog>
consteval auto run_impl() {
if constexpr (PC + 1 >= arr_size_v<Prog>)
return arr_collapse<Out>::value;
else {
constexpr uint8_t op = arr_elem_v<Prog, PC>;
constexpr uint8_t arg = arr_elem_v<Prog, PC+1>;
if constexpr (op == 'G')
return run_impl<PC + 2, arr_elem_v<Ram, arg>, Ram, Out, Prog>();
if constexpr (op == 'O')
return run_impl<PC + 2, X, arr_replace_t<Ram, arg, X>, Out, Prog>();
if constexpr (op == 'R')
return run_impl<PC + 2, /*input*/ 0, Ram, Out, Prog>();
if constexpr (op == 'B')
return run_impl<X ? PC + 2 : arg * 2, X, Ram, Out, Prog>();
if constexpr (op == 'I')
return run_impl<PC + 2, (X + arg) & 0xFF, Ram, Out, Prog>();
if constexpr (op == 'T') // output
return run_impl<PC + 2, X, Ram, arr_append_t<Out, X>, Prog>();
if constexpr (op == 'S')
return run_impl<PC + 2, arg, Ram, Out, Prog>();
if constexpr (op == 'A')
return run_impl<PC + 2, (X + arr_elem_v<Ram, arg>) & 0xFF, Ram, Out, Prog>();
if constexpr (op == 'g')
return run_impl<PC + 2, arr_elem_v<Ram, arr_elem_v<Ram, arg>>, Ram, Out, Prog>();
if constexpr (op == 'o')
return run_impl<PC + 2, X, arr_replace_t<Ram, arr_elem_v<Ram, arg>, X>, Out, Prog>();
if constexpr (op == 'r')
return run_impl<PC + 2, X, arr_replace_t<Ram, arg, /*input*/ 0>, Out, Prog>();
if constexpr (op == 'b')
return run_impl<X ? PC + 2 : arr_elem_v<Ram, arg> * 2, X, Ram, Out, Prog>();
if constexpr (op == 'i')
return run_impl<PC + 2, X, arr_replace_t<Ram, arg, (arr_elem_v<Ram, arg> + X) & 0xFF>, Out, Prog>();
if constexpr (op == 't')
return run_impl<PC + 2, X, Ram, arr_append_t<Out, arr_elem_v<Ram, arg>>, Prog>();
if constexpr (op == 's')
return run_impl<PC + 2, X ^ arr_elem_v<Ram, arg>, Ram, Out, Prog>();
if constexpr (op == 'a')
return run_impl<PC + 2, (X + arr_elem_v<Ram, arr_elem_v<Ram, arg>>) & 0xFF, Ram, Out, Prog>();
//if constexpr (op == ' ')
// return run_impl<PC + 2, X, Ram, Out, Prog>();
}
}
template <typename Str, bool Parsing_command, uint8_t Tmp, size_t I, uint8_t ...c>
consteval auto run_parser() {
if constexpr (arr_size_v<Str> > I) {
if constexpr (arr_elem_v<Str, I> == 'R' || arr_elem_v<Str, I> == 'T') {
if constexpr (arr_size_v<Str> > I + 1)
static_assert(arr_elem_v<Str, I + 1> == ' ');
return run_parser<Str, true, 0, I + 2, c..., arr_elem_v<Str, I>, 0>();
} else {
if constexpr (Parsing_command)
return run_parser<Str, false, 0, I + 1, c..., arr_elem_v<Str, I>>();
else if constexpr (arr_elem_v<Str, I> >= '0' && arr_elem_v<Str, I> <= '9')
return run_parser<Str, false, (Tmp * 10 + arr_elem_v<Str, I> - '0') & 0xFF, I + 1, c...>();
else {
static_assert(arr_elem_v<Str, I> == ' ');
return run_parser<Str, true, 0, I + 1, c..., Tmp>();
}
}
} else {
return run_impl<0, 0, typename arr_makefill<uint8_t, 0, 256>::type, std::integer_sequence<uint8_t>, std::integer_sequence<uint8_t, c...>>();
}
}
template <typename Str>
consteval auto run() {
return run_parser<Str, true, 0, 0>();
}
int main() {
// Hello
//static constexpr char source[] = "S72 T S101 T S108 T T S111 T";
// A 10x10 Box (By Megarev)
//static constexpr char source[] = "S10 O0 G0 I255 O0 B19 S10 T S10 O1 G1 I255 O1 S35 T G1 B2 S0 B10 S10 T";
// Simple stairs (By Megarev)
//static constexpr char source[] = "S10 O10 S0 O1 S6 O0 G0 I255 O0 B24 t10 G1 I1 O1 O2 G2 I255 O2 S35 T G2 B6 S0 B15 t10";
// Sauron's eye (By TrolledWoods) (Broken)
//static constexpr char source[] = "S206 O132 S10 T S156 O97 S1 i97 S0 O7 G97 I237 O131 G97 i7 S1 i131 G131 B42 S0 B26 S0 O105 G132 I45 O131 G132 i105 S1 i131 G131 B68 S0 B52 G105 i7 S200 O105 G7 B94 G105 B102 S255 i7 i105 S0 B76 S46 T S0 B110 S35 T S0 B110 G97 B118 S0 B12 S1 i132 G132 B255 S0 B4";
// Snake (By Horsey) (Never completes?; Editor's note: it's actually an error)
static constexpr char source[] = "S255 O95 S27 O1 S28 O2 S29 O3 S255 O165 S3 O33 S20 O34 S27 T S91 T S50 T S74 T S10 T S34 O151 S95 T G151 I255 O151 B34 S0 B26 S10 T S16 O152 S255 O156 O157 S124 T S16 O153 G33 O158 g158 O255 B73 S16 O159 S0 O160 G160 A152 O160 G159 I255 O159 B63 S0 B54 G160 I240 A153 O160 O254 G255 s95 I1 A254 B108 G158 I255 O158 B79 S0 B47 G160 O255 G34 O254 G255 s95 I1 A254 B90 S0 B104 S27 T S91 T S57 T S49 T S109 T S219 T S0 B120 S32 T S0 B120 S27 T S91 T S57 T S50 T S109 T S219 T G157 s156 O157 i153 G153 B128 S0 B45 S27 T S91 T S48 T S109 T S124 T S10 T G152 I255 O152 B146 S0 B41 S34 O154 S196 T G154 I255 O154 B156 S0 B148 G33 O161 G1 O163 g33 O170 G161 I255 O162 g162 o161 G162 O161 B172 S0 B162 R I152 B183 I254 B191 I255 B187 I255 B195 S0 B197 S1 O165 S0 B197 S16 O165 S0 B197 S240 O165 S0 B197 S255 O165 G163 A165 O1 G34 O255 G1 O254 G255 s95 I1 A254 B211 S0 B217 S1 i33 G170 o33 s254 O34 G33 O166 G33 O167 G167 O255 G166 O254 G255 s95 I1 A254 B239 g167 O255 g166 O254 G255 s95 I1 A254 B255 G167 I255 O167 B245 S0 B221 G166 I255 O166 B251 S0 B219 S0 B14 S0";
auto output = run<
typename str_to_arr<source>::type
>();
for (auto c : output)
std::putchar(c);
std::putchar('\n');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment