<NME> luaclingo.cc <BEF> // {{{ MIT License // Copyright 2017 Roland Kaminski // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // }}} #include "luaclingo.h" #include <lua.hpp> #include <cstring> #include <forward_list> #include <stdexcept> #include <sstream> #include <vector> #include <iostream> #include <algorithm> #include <cassert> #include <limits> namespace { // {{{1 error handling template <typename T> auto protect(lua_State *L, T f) -> decltype(f()) { try { return f(); } catch (std::exception const &e) { luaL_error(L, e.what()); } catch (...) { luaL_error(L, "unknown error"); } throw std::logic_error("cannot happen"); } #define PROTECT(E) (protect(L, [&]{ return (E); })) // translates a clingo api error into a lua error void handle_c_error(lua_State *L, bool ret) { if (!ret) { char const *msg = clingo_error_message(); if (!msg) { msg = "no message"; } luaL_error(L, msg); } } // translates a lua error into a a clingo api error bool handle_lua_error(lua_State *L, char const *loc, char const *desc, int code) { try { switch (code) { case LUA_ERRRUN: case LUA_ERRERR: case LUA_ERRSYNTAX: { char const *s = lua_tostring(L, -1); std::ostringstream msg; msg << loc << ": " << "error: " << desc << ":\n" << (code == LUA_ERRSYNTAX ? " SyntaxError: " : " RuntimeError: ") << s << "\n" ; clingo_set_error(clingo_error_runtime, msg.str().c_str()); lua_pop(L, 1); return false; } case LUA_ERRMEM: { std::stringstream msg; msg << loc << ": error: lua interpreter ran out of memory" << "\n"; clingo_set_error(clingo_error_bad_alloc, msg.str().c_str()); lua_pop(L, 1); return false; } } } catch(...) { lua_pop(L, 1); clingo_set_error(clingo_error_logic, "error during error handling"); return false; } return true; } template <typename... T> struct Types { }; template<int, typename... T> struct LastTypes; template<> struct LastTypes<0> { using Type = Types<>; }; template<typename A, typename... T> struct LastTypes<0, A, T...> { using Type = Types<A, T...>; }; template<int n, typename A, typename... T> struct LastTypes<n, A, T...> : LastTypes<n-1, T...> { }; template<int n, typename T> struct LastArgs; template<int n, typename... Args> struct LastArgs<n, bool (*)(Args...)> : LastTypes<n, Args...> { }; template <typename F, typename... Args> void call_c_(Types<>*, lua_State *L, F f, Args ...args) { handle_c_error(L, f(args...)); } template <typename T, typename F, typename... Args> T call_c_(Types<T*>*, lua_State *L, F f, Args ...args) { T ret; handle_c_error(L, f(args..., &ret)); return ret; } template <typename T, typename U, typename F, typename... Args> std::pair<T, U> call_c_(Types<T*, U*>*, lua_State *L, F f, Args ...args) { T ret1; U ret2; handle_c_error(L, f(args..., &ret1, &ret2)); return {ret1, ret2}; } template <typename F, typename... Args, typename T=typename LastArgs<sizeof...(Args), F>::Type> static auto call_c(lua_State *L, F f, Args... args) -> decltype(call_c_(static_cast<T*>(nullptr), L, f, args...)) { return call_c_(static_cast<T*>(nullptr), L, f, args...); } static int luaTraceback (lua_State *L) { if (!lua_isstring(L, 1)) { return 1; } lua_getglobal(L, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); lua_pushinteger(L, 2); lua_call(L, 2, 1); lua_getglobal(L, "string"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "gsub"); if (!lua_isfunction(L, -1)) { lua_pop(L, 1); return 1; } lua_pushvalue(L, -3); lua_pushliteral(L, "\t"); lua_pushliteral(L, " "); lua_call(L, 3, 1); return 1; } // {{{1 Object void lua_regMeta(lua_State *L, char const *name, luaL_Reg const * funs, lua_CFunction indexfun = nullptr, lua_CFunction newindexfun = nullptr) { #if LUA_VERSION_NUM < 502 luaL_newmetatable(L, name); luaL_register(L, 0, funs); #else luaL_newmetatable(L, name); luaL_setfuncs(L, funs, 0); #endif lua_pushliteral(L, "__metatable"); lua_pushvalue(L, -2); lua_rawset(L, -3); lua_pushliteral(L, "__index"); if (indexfun) { lua_pushcfunction(L, indexfun); } else { lua_pushvalue(L, -2); } lua_rawset(L, -3); if (newindexfun) { lua_pushliteral(L, "__newindex"); lua_pushcfunction(L, newindexfun); lua_rawset(L, -3); } } template <typename T> struct Object { template <typename... Args> static int new_(lua_State *L, Args&&... args) { new (lua_newuserdata(L, sizeof(T))) T(std::forward<Args>(args)...); luaL_getmetatable(L, T::typeName); lua_setmetatable(L, -2); return 1; } static void reg(lua_State *L) { lua_regMeta(L, T::typeName, T::meta, T::index, T::newindex); } static T &get_self(lua_State* L) { return *(T*)luaL_checkudata(L, 1, T::typeName); } T &cmpKey() { return *static_cast<T*>(this); } static int eq(lua_State *L) { T *a = static_cast<T*>(luaL_checkudata(L, 1, T::typeName)); T *b = static_cast<T*>(luaL_checkudata(L, 2, T::typeName)); lua_pushboolean(L, a->cmpKey() == b->cmpKey()); return 1; } static int lt(lua_State *L) { T *a = static_cast<T*>(luaL_checkudata(L, 1, T::typeName)); T *b = static_cast<T*>(luaL_checkudata(L, 2, T::typeName)); lua_pushboolean(L, a->cmpKey() < b->cmpKey()); return 1; } static int le(lua_State *L) { T *a = static_cast<T*>(luaL_checkudata(L, 1, T::typeName)); T *b = static_cast<T*>(luaL_checkudata(L, 2, T::typeName)); lua_pushboolean(L, a->cmpKey() <= b->cmpKey()); return 1; } static constexpr luaL_Reg const meta[] = {{nullptr, nullptr}}; static constexpr lua_CFunction const index = nullptr; static constexpr lua_CFunction const newindex = nullptr; }; template <typename T> constexpr luaL_Reg const Object<T>::meta[]; template <typename T> constexpr lua_CFunction const Object<T>::index; template <typename T> constexpr lua_CFunction const Object<T>::newindex; // {{{1 wrap Any struct Any { struct PlaceHolder { virtual ~PlaceHolder() { }; }; template <class T> struct Holder : public PlaceHolder { template <typename... Args> Holder(Args&&... args) : value(std::forward<Args>(args)...) { } T value; }; Any() : content(nullptr) { } Any(Any &&other) : content(nullptr) { std::swap(content, other.content); } template<typename T, typename... Args> Any(T*, Args&&... args) : content(new Holder<T>(std::forward<T>(args)...)) { } ~Any() { delete content; } Any &operator=(Any &&other) { std::swap(content, other.content); return *this; } template<typename T> T *get() { auto x = dynamic_cast<Holder<T>*>(content); return x ? &x->value : nullptr; } template<typename T> T const *get() const { auto x = dynamic_cast<Holder<T>*>(content); return x ? &x->value : nullptr; } bool empty() const { return !content; } PlaceHolder *content = nullptr; }; template <typename T, typename... Args> Any make_any(Args&&... args) { return Any(static_cast<T*>(nullptr), std::forward<Args>(args)...); } struct AnyWrap : Object<AnyWrap> { Any any; AnyWrap() { } template <typename T, typename... Args> static T *new_(lua_State *L, Args&&... args) { Object::new_(L); auto self = static_cast<AnyWrap*>(lua_touserdata(L, -1)); PROTECT((self->any = make_any<T>(std::forward<Args>(args)...), 0)); return self->any.get<T>(); } static int gc(lua_State *L) { auto &self = get_self(L); self.~AnyWrap(); return 0; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo._Any"; }; constexpr char const *AnyWrap::typeName; luaL_Reg const AnyWrap::meta[] = { {"__gc", gc}, {nullptr, nullptr} }; // {{{1 auxliary functions namespace Detail { template <int X> using int_type = std::integral_constant<int, X>; template <class T, class S> inline void nc_check(S s, int_type<0>) { // same sign (void)s; assert((std::is_same<T, S>::value) || (s >= std::numeric_limits<T>::min() && s <= std::numeric_limits<T>::max())); } template <class T, class S> inline void nc_check(S s, int_type<-1>) { // Signed -> Unsigned (void)s; assert(s >= 0 && static_cast<S>(static_cast<T>(s)) == s); } template <class T, class S> inline void nc_check(S s, int_type<1>) { // Unsigned -> Signed (void)s; assert(!(s > static_cast<typename std::make_unsigned<T>::type>(std::numeric_limits<T>::max()))); } } // namespace Detail template <class T, class S> inline T numeric_cast(S s) { constexpr int sv = int(std::numeric_limits<T>::is_signed) - int(std::numeric_limits<S>::is_signed); Detail::nc_check<T>(s, Detail::int_type<sv>()); return static_cast<T>(s); } clingo_symbol_t luaToVal(lua_State *L, int idx); #if LUA_VERSION_NUM < 502 int lua_absindex(lua_State *L, int idx) { return (idx < 0) ? lua_gettop(L) + idx + 1 : idx; } // size_t lua_len(lua_State *L, int index) { // return lua_objlen(L, index); // } // size_t lua_rawlen(lua_State *L, int index) { // return lua_objlen(L, index); // } #endif static int luaPushKwArg(lua_State *L, int index, int pos, char const *name, bool optional) { index = lua_absindex(L, index); lua_pushinteger(L, pos); lua_gettable(L, index); if (!lua_isnil(L, -1)) { if (name) { lua_getfield(L, index, name); if (!lua_isnil(L, -1)) { lua_pop(L, 2); return luaL_error(L, "argument #%d also given by keyword %s", pos, name); } lua_pop(L, 1); } } else if (name) { lua_pop(L, 1); lua_getfield(L, index, name); } if (!optional && lua_isnil(L, -1)) { return name ? luaL_error(L, "argument %s (#%d) missing", name, pos) : luaL_error(L, "argument #%d missing", pos); } return 1; } template <class T, class U> void luaToCpp(lua_State *L, int index, std::pair<T, U> &x); void luaToCpp(lua_State *L, int index, clingo_weighted_literal_t &x); template <class T> void luaToCpp(lua_State *L, int index, std::vector<T> &x); void luaToCpp(lua_State *L, int index, bool &x) { x = lua_toboolean(L, index) != 0; } void luaToCpp(lua_State *L, int index, std::string &x) { char const *str = lua_tostring(L, index); PROTECT(x = str); } template <class T> void luaToCpp(lua_State *L, int index, T &x, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) { if (lua_type(L, index) != LUA_TNUMBER) { luaL_error(L, "number expected"); } x = numeric_cast<T>(lua_tointeger(L, index)); } struct symbol_wrapper { clingo_symbol_t symbol; }; void luaToCpp(lua_State *L, int index, symbol_wrapper &x) { x.symbol = luaToVal(L, index); } struct symbolic_literal_t { clingo_symbol_t symbol; bool positive; }; void luaToCpp(lua_State *L, int index, symbolic_literal_t &x); template <class T> void luaToCpp(lua_State *L, int index, std::vector<T> &x) { index = lua_absindex(L, index); if (lua_type(L, index) != LUA_TTABLE) { luaL_error(L, "table expected"); } lua_pushnil(L); while (lua_next(L, index) != 0) { auto &y = protect(L, [&x]() -> T& { x.emplace_back(); return x.back(); }); luaToCpp(L, -1, y); lua_pop(L, 1); } } template <class T, class U> void luaToCpp(lua_State *L, int index, std::pair<T, U> &x) { index = lua_absindex(L, index); if (lua_type(L, index) != LUA_TTABLE) { luaL_error(L, "table expected"); } lua_pushnil(L); if (lua_next(L, index) != 0) { luaToCpp(L, -1, x.first); lua_pop(L, 1); } else { luaL_error(L, "tuple expected"); } if (lua_next(L, index) != 0) { luaToCpp(L, -1, x.second); lua_pop(L, 1); } else { luaL_error(L, "tuple expected"); } if (lua_next(L, index) != 0) { luaL_error(L, "tuple expected"); } } void luaToCpp(lua_State *L, int index, symbolic_literal_t &x) { std::pair<symbol_wrapper&, bool&> p{reinterpret_cast<symbol_wrapper&>(x.symbol), x.positive}; luaToCpp(L, index, p); } void luaToCpp(lua_State *L, int index, clingo_weighted_literal_t &x) { std::pair<clingo_literal_t&, clingo_weight_t&> y{x.literal, x.weight}; luaToCpp(L, index, y); } template <class T> typename std::enable_if<std::is_integral<T>::value, void>::type cppToLua(lua_State *L, T value) { lua_pushnumber(L, value); } template <class T> void cppToLua(lua_State *L, T *values, size_t size) { lua_createtable(L, size, 0); int i = 1; for (auto it = values, ie = it + size; it != ie; ++it) { cppToLua(L, *it); lua_rawseti(L, -2, i++); } } // replaces the table at index idx with a pointer holding a vector std::vector<clingo_symbol_t> *luaToVals(lua_State *L, int idx) { idx = lua_absindex(L, idx); luaL_checktype(L, idx, LUA_TTABLE); std::vector<clingo_symbol_t> *vals = AnyWrap::new_<std::vector<clingo_symbol_t>>(L); lua_pushnil(L); while (lua_next(L, idx) != 0) { clingo_symbol_t sym = luaToVal(L, -1); protect(L, [sym, &vals](){ vals->push_back(sym); }); lua_pop(L, 1); } lua_replace(L, idx); return vals; } struct LuaClear { LuaClear(lua_State *L) : L(L), n(lua_gettop(L)) { } ~LuaClear() { lua_settop(L, n); } lua_State *L; int n; }; std::ostream &operator<<(std::ostream &out, clingo_location_t loc) { out << loc.begin_file << ":" << loc.begin_line << ":" << loc.begin_column; if (strcmp(loc.begin_file, loc.end_file) != 0) { out << "-" << loc.end_file << ":" << loc.end_line << ":" << loc.end_column; } else if (loc.begin_line != loc.end_line) { out << "-" << loc.end_line << ":" << loc.end_column; } else if (loc.begin_column != loc.end_column) { out << "-" << loc.end_column; } return out; } // {{{1 wrap SolveResult struct SolveResult : Object<SolveResult> { clingo_solve_result_bitset_t res; SolveResult(clingo_solve_result_bitset_t res) : res(res) { } static int satisfiable(lua_State *L) { auto &&res = get_self(L).res; if (res & clingo_solve_result_satisfiable) { lua_pushboolean(L, true); } else if (res & clingo_solve_result_unsatisfiable) { lua_pushboolean(L, false); } else { lua_pushnil(L); } return 1; } static int unsatisfiable(lua_State *L) { auto &&res = get_self(L).res; if (res & clingo_solve_result_unsatisfiable) { lua_pushboolean(L, true); } else if (res & clingo_solve_result_satisfiable) { lua_pushboolean(L, false); } else { lua_pushnil(L); } return 1; } static int unknown(lua_State *L) { auto &&res = get_self(L).res; if ((res & clingo_solve_result_unsatisfiable) || (res & clingo_solve_result_satisfiable)) { lua_pushboolean(L, false); } else { lua_pushboolean(L, true); } return 1; } static int exhausted(lua_State *L) { auto &&res = get_self(L).res; lua_pushboolean(L, res & clingo_solve_result_exhausted); return 1; } static int interrupted(lua_State *L) { auto &&res = get_self(L).res; lua_pushboolean(L, res & clingo_solve_result_interrupted); return 1; } static int index(lua_State *L) { char const *name = luaL_checkstring(L, 2); if (strcmp(name, "satisfiable") == 0) { return satisfiable(L); } else if (strcmp(name, "unsatisfiable") == 0) { return unsatisfiable(L); } else if (strcmp(name, "unknown") == 0) { return unknown(L); } else if (strcmp(name, "exhausted") == 0) { return exhausted(L); } else if (strcmp(name, "interrupted") == 0) { return interrupted(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, name); return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", name); } } static int toString(lua_State *L) { auto &&res = get_self(L).res; if (res & clingo_solve_result_satisfiable) { lua_pushstring(L, "SAT"); } else if (res & clingo_solve_result_unsatisfiable) { lua_pushstring(L, "UNSAT"); } else { lua_pushstring(L, "UNKNOWN"); } return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.SolveResult"; }; constexpr char const *SolveResult::typeName; luaL_Reg const SolveResult::meta[] = { {"__tostring", toString}, {nullptr, nullptr} }; // {{{1 wrap TheoryTerm struct TheoryTermType : Object<TheoryTermType> { clingo_theory_term_type_e type; TheoryTermType(clingo_theory_term_type_e type) : type(type) { } clingo_theory_term_type_e cmpKey() { return type; } static int addToRegistry(lua_State *L) { lua_createtable(L, 0, 6); for (auto t : { clingo_theory_term_type_function, clingo_theory_term_type_number, clingo_theory_term_type_symbol, clingo_theory_term_type_tuple, clingo_theory_term_type_list, clingo_theory_term_type_set}) { Object::new_(L, t); lua_setfield(L, -2, field_(t)); } lua_setfield(L, -2, "TheoryTermType"); return 0; } static char const *field_(clingo_theory_term_type_t t) { switch (static_cast<clingo_theory_term_type_e>(t)) { case clingo_theory_term_type_function: { return "Function"; } case clingo_theory_term_type_number: { return "Number"; } case clingo_theory_term_type_symbol: { return "Symbol"; } case clingo_theory_term_type_tuple: { return "Tuple"; } case clingo_theory_term_type_list: { return "List"; } case clingo_theory_term_type_set: { return "Set"; } } return ""; } static int new_(lua_State *L, clingo_theory_term_type_t t) { lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); lua_getfield(L, -1, "TheoryTermType"); lua_replace(L, -2); lua_getfield(L, -1, field_(t)); lua_replace(L, -2); return 1; } static int toString(lua_State *L) { lua_pushstring(L, field_(get_self(L).type)); return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.TheoryTermType"; }; constexpr char const *TheoryTermType::typeName; luaL_Reg const TheoryTermType::meta[] = { {"__eq", eq}, {"__lt", lt}, {"__le", le}, {"__tostring", toString}, { nullptr, nullptr } }; struct TheoryTerm : Object<TheoryTerm> { clingo_theory_atoms_t const *atoms; clingo_id_t id; TheoryTerm(clingo_theory_atoms_t const *atoms, clingo_id_t id) : atoms(atoms), id(id) { } clingo_id_t cmpKey() { return id; } static int name(lua_State *L) { auto &self = get_self(L); lua_pushstring(L, call_c(L, clingo_theory_atoms_term_name, self.atoms, self.id)); return 1; } static int number(lua_State *L) { auto &self = get_self(L); lua_pushinteger(L, call_c(L, clingo_theory_atoms_term_number, self.atoms, self.id)); return 1; } static int args(lua_State *L) { auto &self = get_self(L); auto ret = call_c(L, clingo_theory_atoms_term_arguments, self.atoms, self.id); lua_createtable(L, numeric_cast<int>(ret.second), 0); int i = 1; for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) { new_(L, self.atoms, *it); lua_rawseti(L, -2, i++); } return 1; } static int toString(lua_State *L) { auto &self = get_self(L); size_t size = call_c(L, clingo_theory_atoms_term_to_string_size, self.atoms, self.id); char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1 handle_c_error(L, clingo_theory_atoms_term_to_string(self.atoms, self.id, buf, size)); lua_pushstring(L, buf); // +1 lua_replace(L, -2); // -1 return 1; } static int type(lua_State *L) { auto &self = get_self(L); return TheoryTermType::new_(L, call_c(L, clingo_theory_atoms_term_type, self.atoms, self.id)); } static int index(lua_State *L) { char const *field = luaL_checkstring(L, 2); if (strcmp(field, "type") == 0) { return type(L); } else if (strcmp(field, "name") == 0) { return name(L); } else if (strcmp(field, "arguments") == 0) { return args(L); } else if (strcmp(field, "number") == 0) { return number(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, field); return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", field); } } static constexpr char const *typeName = "clingo.TheoryTerm"; static luaL_Reg const meta[]; }; constexpr char const *TheoryTerm::typeName; luaL_Reg const TheoryTerm::meta[] = { {"__tostring", toString}, {"__eq", eq}, {"__lt", lt}, {"__le", le}, {nullptr, nullptr} }; // {{{1 wrap TheoryElement struct TheoryElement : Object<TheoryElement> { TheoryElement(clingo_theory_atoms_t const *atoms, clingo_id_t id) : atoms(atoms) , id(id) { } clingo_theory_atoms_t const *atoms; clingo_id_t cmpKey() { return id; } clingo_id_t id; static int terms(lua_State *L) { auto &self = get_self(L); auto ret = call_c(L, clingo_theory_atoms_element_tuple, self.atoms, self.id); lua_createtable(L, numeric_cast<int>(ret.second), 0); int i = 1; for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) { TheoryTerm::new_(L, self.atoms, *it); lua_rawseti(L, -2, i++); } return 1; } static int condition(lua_State *L) { auto &self = get_self(L); auto ret = call_c(L, clingo_theory_atoms_element_condition, self.atoms, self.id); lua_createtable(L, numeric_cast<int>(ret.second), 0); int i = 1; for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) { lua_pushinteger(L, *it); lua_rawseti(L, -2, i++); } return 1; } static int conditionId(lua_State *L) { auto &self = get_self(L); lua_pushinteger(L, call_c(L, clingo_theory_atoms_element_condition_id, self.atoms, self.id)); return 1; } static int toString(lua_State *L) { auto &self = get_self(L); auto size = call_c(L, clingo_theory_atoms_element_to_string_size, self.atoms, self.id); char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1 handle_c_error(L, clingo_theory_atoms_element_to_string(self.atoms, self.id, buf, size)); lua_pushstring(L, buf); // +1 lua_replace(L, -2); // -1 return 1; } static int index(lua_State *L) { char const *field = luaL_checkstring(L, 2); if (strcmp(field, "terms") == 0) { return terms(L); } else if (strcmp(field, "condition") == 0) { return condition(L); } else if (strcmp(field, "condition_id") == 0) { return conditionId(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, field); return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", field); } } static constexpr char const *typeName = "clingo.TheoryElement"; static luaL_Reg const meta[]; }; constexpr char const *TheoryElement::typeName; luaL_Reg const TheoryElement::meta[] = { {"__tostring", toString}, {"__eq", eq}, {"__lt", lt}, {"__le", le}, {nullptr, nullptr} }; // {{{1 wrap TheoryAtom struct TheoryAtom : Object<TheoryAtom> { clingo_theory_atoms_t const *atoms; clingo_id_t id; TheoryAtom(clingo_theory_atoms_t const *atoms, clingo_id_t id) : atoms(atoms) , id(id) { } clingo_id_t cmpKey() { return id; } static int elements(lua_State *L) { auto &self = get_self(L); auto ret = call_c(L, clingo_theory_atoms_atom_elements, self.atoms, self.id); lua_createtable(L, numeric_cast<int>(ret.second), 0); int i = 1; for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) { TheoryElement::new_(L, self.atoms, *it); lua_rawseti(L, -2, i++); } return 1; } static int term(lua_State *L) { auto &self = get_self(L); return TheoryTerm::new_(L, self.atoms, call_c(L, clingo_theory_atoms_atom_term, self.atoms, self.id)); } static int literal(lua_State *L) { auto &self = get_self(L); lua_pushinteger(L, call_c(L, clingo_theory_atoms_atom_literal, self.atoms, self.id)); return 1; } static int guard(lua_State *L) { auto &self = get_self(L); if (!call_c(L, clingo_theory_atoms_atom_has_guard, self.atoms, self.id)) { lua_pushnil(L); return 1; } lua_createtable(L, 2, 0); auto ret = call_c(L, clingo_theory_atoms_atom_guard, self.atoms, self.id); lua_pushstring(L, ret.first); lua_rawseti(L, -2, 1); TheoryTerm::new_(L, self.atoms, ret.second); lua_rawseti(L, -2, 2); return 1; } static int toString(lua_State *L) { auto &self = get_self(L); auto size = call_c(L, clingo_theory_atoms_atom_to_string_size, self.atoms, self.id); char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1 handle_c_error(L, clingo_theory_atoms_atom_to_string(self.atoms, self.id, buf, size)); lua_pushstring(L, buf); // +1 lua_replace(L, -2); // -1 return 1; } static int index(lua_State *L) { char const *field = luaL_checkstring(L, 2); if (strcmp(field, "elements") == 0) { return elements(L); } else if (strcmp(field, "term") == 0) { return term(L); } else if (strcmp(field, "guard") == 0) { return guard(L); } else if (strcmp(field, "literal") == 0) { return literal(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, field); return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", field); } } static constexpr char const *typeName = "clingo.TheoryAtom"; static luaL_Reg const meta[]; }; constexpr char const *TheoryAtom::typeName; luaL_Reg const TheoryAtom::meta[] = { {"__tostring", toString}, {"__eq", eq}, {"__lt", lt}, {"__le", le}, {nullptr, nullptr} }; // {{{1 wrap TheoryIter struct TheoryIter { static int iter(lua_State *L, clingo_theory_atoms_t const *atoms) { lua_pushlightuserdata(L, const_cast<clingo_theory_atoms_t*>(atoms)); lua_pushinteger(L, 0); lua_pushcclosure(L, iter_, 2); return 1; } static int iter_(lua_State *L) { auto atoms = (clingo_theory_atoms_t const *)lua_topointer(L, lua_upvalueindex(1)); clingo_id_t idx = numeric_cast<clingo_id_t>(lua_tonumber(L, lua_upvalueindex(2))); if (idx < call_c(L, clingo_theory_atoms_size, atoms)) { lua_pushinteger(L, idx + 1); lua_replace(L, lua_upvalueindex(2)); TheoryAtom::new_(L, atoms, idx); } else { lua_pushnil(L); } return 1; } }; // {{{1 wrap Term struct SymbolType : Object<SymbolType> { clingo_symbol_type_t type; SymbolType(clingo_symbol_type_t type) : type(type) { } clingo_symbol_type_t cmpKey() { return type; } static int addToRegistry(lua_State *L) { lua_createtable(L, 0, 5); for (auto t : {clingo_symbol_type_number, clingo_symbol_type_string, clingo_symbol_type_function, clingo_symbol_type_infimum, clingo_symbol_type_supremum}) { new_(L, t); lua_setfield(L, -2, field_(t)); } lua_setfield(L, -2, "SymbolType"); return 0; } static char const *field_(clingo_symbol_type_t type) { switch (static_cast<clingo_symbol_type_e>(type)) { case clingo_symbol_type_number: { return "Number"; } case clingo_symbol_type_string: { return "String"; } case clingo_symbol_type_function: { return "Function"; } case clingo_symbol_type_infimum: { return "Infimum"; } case clingo_symbol_type_supremum: { break; } } return "Supremum"; } static int toString(lua_State *L) { lua_pushstring(L, field_(get_self(L).type)); return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.SymbolType"; }; constexpr char const *SymbolType::typeName; luaL_Reg const SymbolType::meta[] = { {"__eq", eq}, {"__lt", lt}, {"__le", le}, {"__tostring", toString}, { nullptr, nullptr } }; struct Term : Object<Term> { clingo_symbol_t symbol; Term(clingo_symbol_t symbol) : symbol(symbol) { } static int new_(lua_State *L, clingo_symbol_t sym) { auto type = clingo_symbol_type(sym); if (type == clingo_symbol_type_supremum) { lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); lua_getfield(L, -1, "Supremum"); lua_replace(L, -2); } else if (type == clingo_symbol_type_infimum) { lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); lua_getfield(L, -1, "Infimum"); lua_replace(L, -2); } else { Object::new_(L, sym); } return 1; } static int addToRegistry(lua_State *L) { clingo_symbol_t sym; clingo_symbol_create_supremum(&sym); Object::new_(L, sym); lua_setfield(L, -2, "Supremum"); clingo_symbol_create_infimum(&sym); Object::new_(L, sym); lua_setfield(L, -2, "Infimum"); return 0; } static int newFun(lua_State *L) { char const *name = luaL_checklstring(L, 1, nullptr); bool positive = true; if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) { luaToCpp(L, 3, positive); } if (name[0] == '\0' && !positive) { luaL_argerror(L, 2, "tuples must not have signs"); } if (lua_isnoneornil(L, 2)) { return new_(L, call_c(L, clingo_symbol_create_id, name, positive)); } else { lua_pushvalue(L, 2); std::vector<clingo_symbol_t> *args = luaToVals(L, -1); new_(L, call_c(L, clingo_symbol_create_function, name, args->data(), args->size(), positive)); lua_replace(L, -2); return 1; } } static int newTuple(lua_State *L) { lua_pushstring(L, ""); lua_insert(L, 1); return newFun(L); } static int newNumber(lua_State *L) { clingo_symbol_t sym; clingo_symbol_create_number(numeric_cast<int>(luaL_checkinteger(L, 1)), &sym); return Term::new_(L, sym); } static int newString(lua_State *L) { return Term::new_(L, call_c(L, clingo_symbol_create_string, luaL_checkstring(L, 1))); } bool operator==(Term const &other) { return clingo_symbol_is_equal_to(symbol, other.symbol); } bool operator <(Term const &other) { return clingo_symbol_is_less_than(symbol, other.symbol); } bool operator<=(Term const &other) { return !clingo_symbol_is_less_than(other.symbol, symbol); } static int name(lua_State *L) { auto &self = get_self(L); if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) { lua_pushstring(L, call_c(L, clingo_symbol_name, self.symbol)); } else { lua_pushnil(L); } return 1; } static int string(lua_State *L) { auto &self = get_self(L); if (clingo_symbol_type(self.symbol) == clingo_symbol_type_string) { lua_pushstring(L, call_c(L, clingo_symbol_string, self.symbol)); } else { lua_pushnil(L); } return 1; } static int number(lua_State *L) { auto &self = get_self(L); if (clingo_symbol_type(self.symbol) == clingo_symbol_type_number) { lua_pushinteger(L, call_c(L, clingo_symbol_number, self.symbol)); } else { lua_pushnil(L); } return 1; } static int negative(lua_State *L) { auto &self = get_self(L); if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) { lua_pushboolean(L, call_c(L, clingo_symbol_is_negative, self.symbol)); } else { lua_pushnil(L); } return 1; } static int positive(lua_State *L) { auto &self = get_self(L); if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) { lua_pushboolean(L, call_c(L, clingo_symbol_is_positive, self.symbol)); } else { lua_pushnil(L); } return 1; } static int args(lua_State *L) { auto &self = get_self(L); if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) { auto ret = call_c(L, clingo_symbol_arguments, self.symbol); lua_createtable(L, numeric_cast<int>(ret.second), 0); int i = 1; for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) { Term::new_(L, *it); lua_rawseti(L, -2, i++); } } else { lua_pushnil(L); } return 1; } static int toString(lua_State *L) { auto &self = get_self(L); auto size = call_c(L, clingo_symbol_to_string_size, self.symbol); char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1 handle_c_error(L, clingo_symbol_to_string(self.symbol, buf, size)); lua_pushstring(L, buf); // +1 lua_replace(L, -2); // -1 return 1; } static int type(lua_State *L) { auto &self = get_self(L); lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); lua_getfield(L, -1, "SymbolType"); lua_getfield(L, -1, SymbolType::field_(clingo_symbol_type(self.symbol))); return 1; } static int index(lua_State *L) { char const *field = luaL_checkstring(L, 2); if (strcmp(field, "positive") == 0) { return positive(L); } else if (strcmp(field, "negative") == 0) { return negative(L); } else if (strcmp(field, "arguments") == 0) { return args(L); } else if (strcmp(field, "name") == 0) { return name(L); } else if (strcmp(field, "string") == 0) { return string(L); } else if (strcmp(field, "number") == 0) { return number(L); } else if (strcmp(field, "type") == 0) { return type(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, field); return 1; } } static constexpr char const *typeName = "clingo.Symbol"; static luaL_Reg const meta[]; }; constexpr char const *Term::typeName; luaL_Reg const Term::meta[] = { {"__tostring", toString}, {"__eq", eq}, {"__lt", lt}, {"__le", le}, {nullptr, nullptr} }; clingo_symbol_t luaToVal(lua_State *L, int idx) { int type = lua_type(L, idx); switch (type) { case LUA_TSTRING: { return call_c(L, clingo_symbol_create_string, lua_tostring(L, idx)); } case LUA_TNUMBER: { clingo_symbol_t ret; clingo_symbol_create_number(numeric_cast<int>(lua_tointeger(L, idx)), &ret); return ret; } case LUA_TUSERDATA: { bool check = false; if (lua_getmetatable(L, idx)) { // +1 lua_getfield(L, LUA_REGISTRYINDEX, "clingo.Symbol"); // +1 check = lua_rawequal(L, -1, -2) != 0; lua_pop(L, 2); // -2 } if (check) { return static_cast<Term*>(lua_touserdata(L, idx))->symbol; } } default: { luaL_error(L, "cannot convert to value"); } } return {}; } struct LuaCallArgs_ { char const *name; clingo_symbol_t const *arguments; size_t size; clingo_symbol_callback_t symbol_callback; void *data; }; int luacall_(lua_State *L) { auto &args = *static_cast<LuaCallArgs_*>(lua_touserdata(L, 1)); int context = 0; if (!lua_isnil(L, 2)) { context = 1; lua_getfield(L, 2, args.name); lua_pushvalue(L, 2); } else { lua_getglobal(L, args.name); } for (auto it = args.arguments, ie = it + args.size; it != ie; ++it) { Term::new_(L, *it); } lua_call(L, numeric_cast<int>(args.size + context), 1); if (lua_type(L, -1) == LUA_TTABLE) { lua_pushnil(L); while (lua_next(L, -2)) { clingo_symbol_t val = luaToVal(L, -1); handle_c_error(L, args.symbol_callback(&val, 1, args.data)); lua_pop(L, 1); } } else { clingo_symbol_t val = luaToVal(L, -1); handle_c_error(L, args.symbol_callback(&val, 1, args.data)); } return 0; } // TODO: also needs a version with a string location bool luacall(lua_State *L, clingo_location_t const *location, int context, char const *name, clingo_symbol_t const *arguments, size_t arguments_size, clingo_symbol_callback_t symbol_callback, void *symbol_callback_data) { if (!lua_checkstack(L, 4)) { clingo_set_error(clingo_error_bad_alloc, "lua stack size exceeded"); return false; } LuaCallArgs_ args{ name, arguments, arguments_size, symbol_callback, symbol_callback_data }; lua_pushcfunction(L, luaTraceback); // +1 int err = lua_gettop(L); lua_pushcfunction(L, luacall_); // +1 lua_pushlightuserdata(L, &args); // +1 if (context) { lua_pushvalue(L, context); } else { lua_pushnil(L); } // +1 auto ret = lua_pcall(L, 2, 0, -4); // -3|-2 lua_remove(L, err); if (ret != 0) { std::string loc, desc; try { std::ostringstream oss; oss << *location; loc = oss.str(); desc = "error calling "; desc += name; } catch (...) { lua_pop(L, 1); // |-1 clingo_set_error(clingo_error_runtime, "error during error handling"); return false; } return handle_lua_error(L, loc.c_str(), desc.c_str(), ret); } return true; } // {{{1 wrap SymbolicAtom struct SymbolicAtom : Object<SymbolicAtom> { clingo_symbolic_atoms_t const *atoms; clingo_symbolic_atom_iterator_t iter; static luaL_Reg const meta[]; static constexpr const char *typeName = "clingo.SymbolicAtom"; SymbolicAtom(clingo_symbolic_atoms_t const *atoms, clingo_symbolic_atom_iterator_t iter) : atoms(atoms) , iter(iter) { } static int symbol(lua_State *L) { auto &self = get_self(L); return Term::new_(L, call_c(L, clingo_symbolic_atoms_symbol, self.atoms, self.iter)); } static int literal(lua_State *L) { auto &self = get_self(L); lua_pushinteger(L, call_c(L, clingo_symbolic_atoms_literal, self.atoms, self.iter)); return 1; } static int is_fact(lua_State *L) { auto &self = get_self(L); lua_pushboolean(L, call_c(L, clingo_symbolic_atoms_is_fact, self.atoms, self.iter)); return 1; } static int is_external(lua_State *L) { auto &self = get_self(L); lua_pushboolean(L, call_c(L, clingo_symbolic_atoms_is_external, self.atoms, self.iter)); return 1; } static int index(lua_State *L) { char const *name = luaL_checkstring(L, 2); if (strcmp(name, "is_fact") == 0) { return is_fact(L); } else if (strcmp(name, "is_external") == 0) { return is_external(L); } else if (strcmp(name, "symbol") == 0) { return symbol(L); } else if (strcmp(name, "literal") == 0) { return literal(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, name); return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", name); } } }; constexpr const char *SymbolicAtom::typeName; luaL_Reg const SymbolicAtom::meta[] = { {nullptr, nullptr} }; // {{{1 wrap SymbolicAtoms struct SymbolicAtoms : Object<SymbolicAtoms> { clingo_symbolic_atoms_t const *atoms; static luaL_Reg const meta[]; static constexpr const char *typeName = "clingo.SymbolicAtoms"; SymbolicAtoms(clingo_symbolic_atoms_t const *atoms) : atoms(atoms) { } static int symbolicAtomIter(lua_State *L) { auto current = static_cast<SymbolicAtom *>(luaL_checkudata(L, lua_upvalueindex(1), SymbolicAtom::typeName)); if (call_c(L, clingo_symbolic_atoms_is_valid, current->atoms, current->iter)) { lua_pushvalue(L, lua_upvalueindex(1)); // +1 auto next = call_c(L, clingo_symbolic_atoms_next, current->atoms, current->iter); SymbolicAtom::new_(L, current->atoms, next); // +1 lua_replace(L, lua_upvalueindex(1)); // -1 } else { lua_pushnil(L); } // +1 return 1; } static int len(lua_State *L) { auto &self = get_self(L); lua_pushinteger(L, call_c(L, clingo_symbolic_atoms_size, self.atoms)); return 1; } static int iter(lua_State *L) { auto &self = get_self(L); auto range = call_c(L, clingo_symbolic_atoms_begin, self.atoms, nullptr); SymbolicAtom::new_(L, self.atoms, range); // +1 lua_pushcclosure(L, symbolicAtomIter, 1); // +0 return 1; } static int lookup(lua_State *L) { auto &self = get_self(L); auto atom = luaToVal(L, 2); auto range = call_c(L, clingo_symbolic_atoms_find, self.atoms, atom); if (call_c(L, clingo_symbolic_atoms_is_valid, self.atoms, range)) { SymbolicAtom::new_(L, self.atoms, range); // +1 } else { lua_pushnil(L); } // +1 return 1; } static int by_signature(lua_State *L) { auto &self = get_self(L); char const *name = luaL_checkstring(L, 2); int arity = numeric_cast<int>(luaL_checkinteger(L, 3)); bool positive = lua_isnone(L, 4) || lua_toboolean(L, 4); clingo_signature_t sig = call_c(L, clingo_signature_create, name, arity, positive); auto range = call_c(L, clingo_symbolic_atoms_begin, self.atoms, &sig); SymbolicAtom::new_(L, self.atoms, range); // +1 lua_pushcclosure(L, symbolicAtomIter, 1); // +0 return 1; } static int signatures(lua_State *L) { auto &self = get_self(L); auto size = call_c(L, clingo_symbolic_atoms_signatures_size, self.atoms); clingo_signature_t *ret = static_cast<clingo_signature_t*>(lua_newuserdata(L, sizeof(*ret) * size)); // +1 handle_c_error(L, clingo_symbolic_atoms_signatures(self.atoms, ret, size)); lua_createtable(L, numeric_cast<int>(size), 0); // +1 int i = 1; for (auto it = ret, ie = it + size; it != ie; ++it) { lua_createtable(L, 3, 0); // +1 lua_pushstring(L, clingo_signature_name(*it)); // +1 lua_rawseti(L, -2, 1); // -1 lua_pushinteger(L, clingo_signature_arity(*it)); // +1 lua_rawseti(L, -2, 2); // -1 lua_pushboolean(L, clingo_signature_is_positive(*it)); // +1 lua_rawseti(L, -2, 3); // -1 lua_rawseti(L, -2, i); // -1 ++i; } lua_replace(L, -2); // -1 return 1; } static int index(lua_State *L) { char const *name = luaL_checkstring(L, 2); if (strcmp(name, "signatures") == 0) { return signatures(L); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, name); return 1; } } }; constexpr const char *SymbolicAtoms::typeName; luaL_Reg const SymbolicAtoms::meta[] = { {"__len", len}, {"iter", iter}, {"lookup", lookup}, {"by_signature", by_signature}, {nullptr, nullptr} }; // {{{1 wrap SolveControl static clingo_literal_t luaToAtom(lua_State *L, int idx, clingo_symbolic_atoms_t const *atoms) { if (lua_isnumber(L, idx)) { clingo_literal_t lit; luaToCpp(L, idx, lit); return lit; } else { symbol_wrapper sym; luaToCpp(L, idx, sym); auto it = call_c(L, clingo_symbolic_atoms_find, atoms, sym.symbol); if (call_c(L, clingo_symbolic_atoms_is_valid, atoms, it)) { auto ret = call_c(L, clingo_symbolic_atoms_literal, atoms, it); return ret; } } return 0; } /* static clingo_literal_t luaToLit(lua_State *L, int idx, clingo_symbolic_atoms_t const *atoms, bool *positive = nullptr) { if (lua_isnumber(L, idx)) { clingo_literal_t lit; luaToCpp(L, idx, lit); if (positive) { *positive = lit > 0; } return lit; } else { symbolic_literal_t sym; luaToCpp(L, idx, sym); if (positive) { *positive = sym.positive; } auto it = call_c(L, clingo_symbolic_atoms_find, atoms, sym.symbol); if (call_c(L, clingo_symbolic_atoms_is_valid, atoms, it)) { auto ret = call_c(L, clingo_symbolic_atoms_literal, atoms, it); return sym.positive ? ret : -ret; } } return 0; } */ // invert is just to turn clauses into nogoods, which was added to match the formal background in our papers // disjunctive determines if the literals are going to be used as a disjunction or conjunction // this function returns null if the literals are unnecessary, i.e., if // there is a true literal in a disjunction, or // there is a false literal in a conjunction static std::vector<clingo_literal_t> *luaToLits(lua_State *L, int tableIdx, clingo_symbolic_atoms_t const *atoms, bool invert, bool disjunctive) { if (lua_type(L, tableIdx) != LUA_TTABLE) { luaL_error(L, "table expected"); } tableIdx = lua_absindex(L, tableIdx); std::vector<clingo_literal_t> *lits = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1 lua_pushnil(L); // +1 while (lua_next(L, tableIdx) != 0) { // +1/-1 if (lua_isnumber(L, -1)) { clingo_literal_t lit; luaToCpp(L, -1, lit); if (invert) { lit = -lit; } protect(L, [lits, lit]() { lits->emplace_back(lit); }); } else { symbolic_literal_t sym; luaToCpp(L, -1, sym); if (invert) { sym.positive = !sym.positive; } auto it = call_c(L, clingo_symbolic_atoms_find, atoms, sym.symbol); if (call_c(L, clingo_symbolic_atoms_is_valid, atoms, it)) { clingo_literal_t lit = call_c(L, clingo_symbolic_atoms_literal, atoms, it); if (!sym.positive) { lit = -lit; } protect(L, [lits, lit]() { lits->emplace_back(lit); }); } else if (sym.positive != disjunctive) { lua_pop(L, 3); return nullptr; } } lua_pop(L, 1); // -1 } return lits; } struct SolveControl : Object<SolveControl> { clingo_solve_control_t *ctl; SolveControl(clingo_solve_control_t *ctl) : ctl(ctl) { } static int getClause(lua_State *L, bool invert) { auto &self = get_self(L); auto atoms = call_c(L, clingo_solve_control_symbolic_atoms, self.ctl); if (auto *lits = luaToLits(L, 2, atoms, invert, true)) { // +1/+0 handle_c_error(L, clingo_solve_control_add_clause(self.ctl, lits->data(), lits->size())); lua_pop(L, 1); // -1 } return 0; } static int add_clause(lua_State *L) { return getClause(L, false); } static int add_nogood(lua_State *L) { return getClause(L, true); } static int index(lua_State *L) { auto &self = get_self(L); char const *name = luaL_checkstring(L, 2); if (strcmp(name, "symbolic_atoms") == 0) { return SymbolicAtoms::new_(L, call_c(L, clingo_solve_control_symbolic_atoms, self.ctl)); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, name); return 1; } } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.SolveControl"; }; constexpr char const *SolveControl::typeName; luaL_Reg const SolveControl::meta[] = { {"add_clause", add_clause}, {"add_nogood", add_nogood}, {nullptr, nullptr} }; // {{{1 wrap Model struct ModelType : Object<ModelType> { using Type = clingo_model_type_t; static SolveHandle *new_(lua_State *L) { lua_newtable(L); // +1 auto *self = (SolveHandle*)lua_newuserdata(L, sizeof(SolveHandle)); // +1 lua_rawseti(L, -2, 1); // -1 luaL_getmetatable(L, typeName); // +1 lua_setmetatable(L, -2); // -1 lua_setfield(L, -2, field_(t)); } lua_setfield(L, -2, "ModelType"); return 0; } self->ass = nullptr; return self; } static int close(lua_State *L) { auto &self = get_self(L); if (self.handle) { auto h = self.handle; self.handle = nullptr; lua_pushstring(L, field_(get_self(L).type)); return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.ModelType"; }; constexpr char const *ModelType::typeName; luaL_Reg const ModelType::meta[] = { {"__eq", eq}, {"__lt", lt}, {"__le", le}, {"__tostring", toString}, { nullptr, nullptr } }; struct Model : Object<Model> { clingo_model_t const *model; clingo_model_t *mut_model; Model(clingo_model_t *model) : model(model), mut_model{model} { } Model(clingo_model_t const *model) : model(model), mut_model{nullptr} { } static int contains(lua_State *L) { auto &self = get_self(L); clingo_symbol_t sym = luaToVal(L, 2); lua_pushboolean(L, call_c(L, clingo_model_contains, self.model, sym)); return 1; } static int is_true(lua_State *L) { auto &self = get_self(L); clingo_literal_t lit; luaToCpp(L, 2, lit); lua_pushboolean(L, call_c(L, clingo_model_is_true, self.model, lit)); return 1; } static int atoms(lua_State *L) { auto &self = get_self(L); clingo_show_type_bitset_t atomset = 0; luaL_checktype(L, 2, LUA_TTABLE); lua_getfield(L, 2, "atoms"); if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_atoms; } lua_pop(L, 1); lua_getfield(L, 2, "shown"); if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_shown; } lua_pop(L, 1); lua_getfield(L, 2, "terms"); if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_terms; } lua_pop(L, 1); lua_getfield(L, 2, "theory"); if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_theory; } lua_pop(L, 1); lua_getfield(L, 2, "complement"); if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_complement; } lua_pop(L, 1); auto size = call_c(L, clingo_model_symbols_size, self.model, atomset); clingo_symbol_t *symbols = static_cast<clingo_symbol_t *>(lua_newuserdata(L, size * sizeof(*symbols))); // +1 handle_c_error(L, clingo_model_symbols(self.model, atomset, symbols, size)); lua_createtable(L, numeric_cast<int>(size), 0); // +1 int i = 1; for (auto it = symbols, ie = it + size; it != ie; ++it) { Term::new_(L, *it); // +1 lua_rawseti(L, -2, i++); // -1 } lua_replace(L, -2); // -1 return 1; } static int cost(lua_State *L) { auto &self = get_self(L); auto size = call_c(L, clingo_model_cost_size, self.model); int64_t *costs = static_cast<int64_t *>(lua_newuserdata(L, size * sizeof(*costs))); // +1 handle_c_error(L, clingo_model_cost(self.model, costs, size)); lua_createtable(L, numeric_cast<int>(size), 0); // +1 int i = 1; for (auto it = costs, ie = it + size; it != ie; ++it) { lua_pushinteger(L, numeric_cast<lua_Integer>(*it)); // +1 lua_rawseti(L, -2, i++); // -1 } lua_replace(L, -2); // -1 return 1; } static int thread_id(lua_State *L) { auto &self = get_self(L); lua_pushinteger(L, call_c(L, clingo_model_thread_id, self.model) + 1); // +1 return 1; } static int toString(lua_State *L) { auto &self = get_self(L); std::vector<char> *buf = AnyWrap::new_<std::vector<char>>(L); // +1 auto printSymbol = [buf, L](std::ostream &out, clingo_symbol_t val) { auto size = call_c(L, clingo_symbol_to_string_size, val); PROTECT(buf->resize(size)); handle_c_error(L, clingo_symbol_to_string(val, buf->data(), size)); PROTECT((out << buf->data(), 0)); }; auto printAtom = [L, printSymbol](std::ostream &out, clingo_symbol_t val) { if (clingo_symbol_type_function == clingo_symbol_type(val)) { auto name = call_c(L, clingo_symbol_name, val); auto args = call_c(L, clingo_symbol_arguments, val); if (args.second == 2 && strcmp(name, "$") == 0) { printSymbol(out, args.first[0]); out << "="; printSymbol(out, args.first[1]); } else { printSymbol(out, val); } return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.SolveHandle"; }; constexpr char const *SolveHandle::typeName; luaL_Reg const SolveHandle::meta[] = { {"iter", iter}, {"close", close}, {"__gc", close}, {"get", get}, {"resume", resume}, {"cancel", cancel}, {nullptr, nullptr} }; // {{{1 wrap Configuration if (!self.mut_model) { luaL_error(L, "models can only be extended from on_model callback"); } handle_c_error(L, clingo_model_extend(self.mut_model, symbols->data(), symbols->size())); lua_pop(L, 1); // -1 return 0; } static int index(lua_State *L) { auto &self = get_self(L); char const *name = luaL_checkstring(L, 2); if (strcmp(name, "cost") == 0) { return cost(L); } else if (strcmp(name, "context") == 0) { return context(L); } else if (strcmp(name, "thread_id") == 0) { return thread_id(L); } else if (strcmp(name, "number") == 0) { lua_pushinteger(L, numeric_cast<lua_Integer>(call_c(L, clingo_model_number, self.model))); return 1; } else if (strcmp(name, "optimality_proven") == 0) { lua_pushboolean(L, call_c(L, clingo_model_optimality_proven, self.model)); return 1; } else if (strcmp(name, "type") == 0) { return ModelType::new_(L, call_c(L, clingo_model_type, self.model)); } else { lua_getmetatable(L, 1); lua_getfield(L, -1, name); return 1; } } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.Model"; }; constexpr char const *Model::typeName; luaL_Reg const Model::meta[] = { {"__tostring", toString}, {"symbols", atoms}, {"contains", contains}, {"extend", extend}, {"is_true", is_true}, {nullptr, nullptr} }; // {{{1 wrap Statistics int newStatistics(lua_State *L, clingo_statistics_t const *stats, uint64_t key) { switch (call_c(L, clingo_statistics_type, stats, key)) { case clingo_statistics_type_value: { lua_pushnumber(L, numeric_cast<lua_Number>(call_c(L, clingo_statistics_value_get, stats, key))); // +1 return 1; } case clingo_statistics_type_array: { lua_newtable(L); // +1 for (size_t i = 0, e = call_c(L, clingo_statistics_array_size, stats, key); i != e; ++i) { newStatistics(L, stats, call_c(L, clingo_statistics_array_at, stats, key, i)); // +1 lua_rawseti(L, -2, numeric_cast<int>(i+1)); // -1 } return 1; } case clingo_statistics_type_map: { lua_newtable(L); // +1 for (size_t i = 0, e = call_c(L, clingo_statistics_map_size, stats, key); i != e; ++i) { auto name = call_c(L, clingo_statistics_map_subkey_name, stats, key, i); lua_pushstring(L, name); // +1 newStatistics(L, stats, call_c(L, clingo_statistics_map_at, stats, key, name)); // +1 lua_rawset(L, -3); // -2 } return 1; } default: { return luaL_error(L, "cannot happen"); } } } // {{{1 wrap SolveHandle struct SolveHandle : Object<SolveHandle> { clingo_solve_handle_t *handle; clingo_solve_mode_bitset_t mode; bool hasMH, hasFH; clingo_control_t *ctl; std::vector<clingo_literal_t> *ass; SolveHandle(clingo_solve_handle_t *handle) : handle(handle) { } static SolveHandle &get_self(lua_State *L, int offset=1) { void *p = nullptr; if (lua_istable(L, offset)) { lua_rawgeti(L, offset, 1); // +1 p = lua_touserdata(L, -1); if (p) { if (lua_getmetatable(L, offset)) { // +1 luaL_getmetatable(L, typeName); // +1 if (!lua_rawequal(L, -1, -2)) { p = nullptr; } lua_pop(L, 2); // -2 } else { p = nullptr; } } lua_pop(L, 1); // -1 } if (!p) { const char *msg = lua_pushfstring(L, "%s expected, got %s", typeName, luaL_typename(L, 1)); // +1 luaL_argerror(L, 1, msg); } return *static_cast<SolveHandle*>(p); } static SolveHandle *new_(lua_State *L) { lua_newtable(L); // +1 auto *self = (SolveHandle*)lua_newuserdata(L, sizeof(SolveHandle)); // +1 luaL_getmetatable(L, typeNameI); // +1 lua_setmetatable(L, -2); // +1 lua_rawseti(L, -2, 1); // -1 luaL_getmetatable(L, typeName); // +1 lua_setmetatable(L, -2); // -1 self->handle = nullptr; self->mode = 0; self->hasFH = false; self->hasMH = false; self->ctl = nullptr; self->ass = nullptr; return self; } static void reg(lua_State *L) { lua_regMeta(L, typeName, meta, index, newindex); lua_regMeta(L, typeNameI, metaI, nullptr, nullptr); } static int gc(lua_State *L) { return close_(L, *(SolveHandle*)lua_touserdata(L, 1)); } static int close(lua_State *L) { return close_(L, get_self(L)); } static int close_(lua_State *L, SolveHandle &self) { if (self.handle) { auto h = self.handle; self.handle = nullptr; handle_c_error(L, clingo_solve_handle_close(h)); } return 0; } static int next(lua_State *L) { auto &handle = get_self(L, lua_upvalueindex(1)); call_c(L, clingo_solve_handle_resume, handle.handle); clingo_model_t const *model = call_c(L, clingo_solve_handle_model, handle.handle); if (model) { Model::new_(L, model); } else { lua_pushnil(L); } return 1; } static int iter(lua_State *L) { get_self(L); lua_pushvalue(L,1); lua_pushcclosure(L, next, 1); return 1; } static int get(lua_State *L) { auto &self = get_self(L); SolveResult::new_(L, call_c(L, clingo_solve_handle_get, self.handle)); return 1; } static int resume(lua_State *L) { auto &self = get_self(L); call_c(L, clingo_solve_handle_resume, self.handle); return 0; } static int cancel(lua_State *L) { auto &self = get_self(L); handle_c_error(L, clingo_solve_handle_cancel(self.handle)); return 0; } static int on_model_(lua_State *L) { auto m = static_cast<clingo_model_t*>(lua_touserdata(L, 2)); auto goon = static_cast<bool*>(lua_touserdata(L, 3)); lua_pushstring(L, "on_model"); lua_rawget(L, 1); Model::new_(L, m); lua_call(L, 1, 1); *goon = lua_isnil(L, -1) || lua_toboolean(L, -1); return 0; } static int core(lua_State *L) { auto core = call_c(L, clingo_solve_handle_core, get_self(L).handle); if (core.first == nullptr) { lua_pushnil(L); // +1 } else { cppToLua(L, core.first, core.second); // +1 } return 1; } static int on_finish_(lua_State *L) { lua_pushstring(L, "on_model"); lua_rawget(L, 1); auto x = static_cast<clingo_solve_mode_bitset_t*>(lua_touserdata(L, 2)); SolveResult::new_(L, *x); lua_call(L, 1, 0); return 0; } static bool on_event_(clingo_solve_event_type_t type, void *event, void *data, bool *goon) { auto *L = static_cast<lua_State*>(data); int top = lua_gettop(L); auto &handle = get_self(L, top); if (!lua_checkstack(L, 5)) { clingo_set_error(clingo_error_bad_alloc, "lua stack size exceeded"); return false; } switch (type) { case clingo_solve_event_type_model: { if (!handle.hasMH) { return true; } lua_pushcfunction(L, luaTraceback); // +1 lua_pushcfunction(L, on_model_); // +1 lua_pushvalue(L, top); // +1 lua_pushlightuserdata(L, event); // +1 lua_pushlightuserdata(L, goon); // +1 int code = lua_pcall(L, 3, 0, -5); // -4|-3 lua_remove(L, top + 1); // -1 return handle_lua_error(L, "on_model", "error in model callback", code); // |-1 } case clingo_solve_event_type_finish: { if (!handle.hasFH) { return true; } lua_pushcfunction(L, luaTraceback); // +1 lua_pushcfunction(L, on_finish_); // +1 lua_pushvalue(L, top); // +1 lua_pushlightuserdata(L, event); // +1 int code = lua_pcall(L, 2, 0, -4); // -3|-2 lua_remove(L, top + 1); // -1 bool ret = handle_lua_error(L, "on_finish", "error in finish callback", code); // |-1 return ret; } } return true; } static int solve_(lua_State *L) { auto &handle = get_self(L); handle.handle = call_c(L, clingo_control_solve, handle.ctl, handle.mode, handle.ass->data(), handle.ass->size(), (handle.hasFH || handle.hasMH) ? on_event_ : nullptr, L); if (handle.mode == 0) { lua_pushcfunction(L, get); // +1 lua_pushvalue(L, 1); // +1 lua_call(L, 1, 1); // -1 auto h = handle.handle; handle.handle = nullptr; call_c(L, clingo_solve_handle_close, h); } else { lua_pushvalue(L, 1); // +1 } return 1; } static luaL_Reg const meta[]; static luaL_Reg const metaI[]; static constexpr char const *typeName = "clingo.SolveHandle"; static constexpr char const *typeNameI = "clingo._SolveHandle"; }; constexpr char const *SolveHandle::typeName; constexpr char const *SolveHandle::typeNameI; luaL_Reg const SolveHandle::meta[] = { {"iter", iter}, {"close", close}, {"get", get}, {"core", core}, {"resume", resume}, {"cancel", cancel}, {nullptr, nullptr} }; luaL_Reg const SolveHandle::metaI[] = { {"__gc", gc}, {nullptr, nullptr} }; // {{{1 wrap Configuration struct Configuration : Object<Configuration> { clingo_configuration_t *conf; clingo_id_t key; Configuration(clingo_configuration_t *conf, clingo_id_t key) : conf(conf), key(key) { } static int keys(lua_State *L) { auto &self = get_self(L); auto type = call_c(L, clingo_configuration_type, self.conf, self.key); if (type & clingo_configuration_type_map) { size_t size = call_c(L, clingo_configuration_map_size, self.conf, self.key); lua_createtable(L, numeric_cast<int>(size), 0); for (size_t i = 0; i < size; ++i) { lua_pushstring(L, call_c(L, clingo_configuration_map_subkey_name, self.conf, self.key, i)); lua_rawseti(L, -2, numeric_cast<int>(i+1)); } } return 1; } bool get_subkey(lua_State *L, char const *name, clingo_id_t &subkey) { if ((call_c(L, clingo_configuration_type, conf, key) & clingo_configuration_type_map) && call_c(L, clingo_configuration_map_has_subkey, conf, key, name)) { subkey = call_c(L, clingo_configuration_map_at, conf, key, name); return true; } return false; } static int description(lua_State *L) { auto &self = get_self(L); char const *name = luaL_checkstring(L, 2); clingo_id_t subkey; if (self.get_subkey(L, name, subkey)) { lua_pushstring(L, call_c(L, clingo_configuration_description, self.conf, subkey)); // +1 return 1; } return luaL_error(L, "unknown option: %s", name); } static int index(lua_State *L) { auto &self = get_self(L); char const *name = luaL_checkstring(L, 2); lua_getmetatable(L, 1); lua_getfield(L, -1, name); // +1 if (!lua_isnil(L, -1)) { return 1; } lua_pop(L, 1); // -1 if (strcmp(name, "keys") == 0) { return keys(L); } bool desc = strncmp("__desc_", name, 7) == 0; if (desc) { name += 7; } clingo_id_t subkey; if (self.get_subkey(L, name, subkey)) { // NOTE: for backward compatibility should be removed in the future if (desc) { lua_pushstring(L, call_c(L, clingo_configuration_description, self.conf, subkey)); // +1 return 1; } else if (call_c(L, clingo_configuration_type, self.conf, subkey) & clingo_configuration_type_value) { if (!call_c(L, clingo_configuration_value_is_assigned, self.conf, subkey)) { lua_pushnil(L); return 1; } size_t size = call_c(L, clingo_configuration_value_get_size, self.conf, subkey); char *ret = static_cast<char*>(lua_newuserdata(L, sizeof(*ret) * size)); // +1 handle_c_error(L, clingo_configuration_value_get(self.conf, subkey, ret, size)); lua_pushstring(L, ret); // +1 lua_replace(L, -2); // -1 return 1; } else { return Configuration::new_(L, self.conf, subkey); } // +1 } lua_pushnil(L); // +1 return 1; } static int newindex(lua_State *L) { auto &self = get_self(L); auto *name = luaL_checkstring(L, 2); auto subkey = call_c(L, clingo_configuration_map_at, self.conf, self.key, name); auto value = lua_tostring(L, 3); handle_c_error(L, clingo_configuration_value_set(self.conf, subkey, value)); return 0; } static int next(lua_State *L) { auto &self = *(Configuration *)luaL_checkudata(L, lua_upvalueindex(1), typeName); size_t index = luaL_checkinteger(L, lua_upvalueindex(2)); lua_pushinteger(L, numeric_cast<lua_Integer>(index + 1)); lua_replace(L, lua_upvalueindex(2)); size_t size = call_c(L, clingo_configuration_array_size, self.conf, self.key); if (index < size) { auto key = call_c(L, clingo_configuration_array_at, self.conf, self.key, index); return new_(L, self.conf, key); } else { lua_pushnil(L); return 1; } } static int iter(lua_State *L) { luaL_checkudata(L, 1, typeName); lua_pushvalue(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, next, 2); return 1; } static int len(lua_State *L) { auto &self = get_self(L); size_t n = 0; if (call_c(L, clingo_configuration_type, self.conf, self.key) & clingo_configuration_type_array) { n = call_c(L, clingo_configuration_array_size, self.conf, self.key); } lua_pushinteger(L, numeric_cast<lua_Integer>(n)); return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.Configuration"; }; constexpr char const *Configuration::typeName; luaL_Reg const Configuration::meta[] = { {"__len", len}, {"iter", iter}, {"description", description}, {nullptr, nullptr} }; // {{{1 wrap wrap Backend struct ExternalType : Object<ExternalType> { using Type = clingo_external_type_t; Type type; ExternalType(Type type) : type(type) { } Type cmpKey() { return type; } static int addToRegistry(lua_State *L) { lua_createtable(L, 0, 4); for (auto t : { clingo_external_type_true, clingo_external_type_false, clingo_external_type_free, clingo_external_type_release }) { Object::new_(L, t); lua_setfield(L, -2, field_(t)); } lua_setfield(L, -2, "ExternalType"); return 0; } static char const *field_(Type t) { switch (static_cast<clingo_external_type_e>(t)) { case clingo_external_type_true: { return "True"; } case clingo_external_type_false: { return "False"; } case clingo_external_type_free: { return "Free"; } case clingo_external_type_release: { break; } } return "Release"; } static int new_(lua_State *L, Type t) { lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); lua_getfield(L, -1, "ExternalType"); lua_replace(L, -2); lua_getfield(L, -1, field_(t)); lua_replace(L, -2); return 1; } static int toString(lua_State *L) { lua_pushstring(L, field_(get_self(L).type)); return 1; } static luaL_Reg const meta[]; static constexpr char const *typeName = "clingo.ExternalType"; }; constexpr char const *ExternalType::typeName; luaL_Reg const ExternalType::meta[] = { {"__eq", eq}, {"__lt", lt}, {"__le", le}, {"__tostring", toString}, { nullptr, nullptr } }; struct Backend : Object<Backend> { clingo_backend_t *backend; Backend(clingo_backend_t *backend) : backend(backend) { } static constexpr const char *typeName = "clingo.Backend"; static luaL_Reg const meta[]; static int addAtom(lua_State *L) { symbol_wrapper sym; clingo_symbol_t *symp = nullptr; if (!lua_isnone(L, 2) && !lua_isnil(L, 2)) { luaToCpp(L, 2, sym); symp = &sym.symbol; } lua_pushinteger(L, call_c(L, clingo_backend_add_atom, get_self(L).backend, symp)); return 1; } static int addRule(lua_State *L) { auto &self = get_self(L); auto *head = AnyWrap::new_<std::vector<clingo_atom_t>>(L); // +1 auto *body = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1 bool choice = false; luaL_checktype(L, 2, LUA_TTABLE); luaPushKwArg(L, 2, 1, "head", false); // +1 luaToCpp(L, -1, *head); lua_pop(L, 1); // -1 luaPushKwArg(L, 2, 2, "body", true); // +1 if (!lua_isnil(L, -1)) { luaToCpp(L, -1, *body); } lua_pop(L, 1); // -1 luaPushKwArg(L, 2, 3, "choice", true); // +1 luaToCpp(L, -1, choice); // -1 lua_pop(L, 1); handle_c_error(L, clingo_backend_rule(self.backend, choice, head->data(), head->size(), body->data(), body->size())); lua_pop(L, 2); // -2 return 0; } static int addExternal(lua_State *L) { auto &self = get_self(L); clingo_atom_t atom; clingo_external_type_t value = clingo_external_type_false; luaToCpp(L, 2, atom); if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) { value = static_cast<ExternalType*>(luaL_checkudata(L, 3, ExternalType::typeName))->type; } handle_c_error(L, clingo_backend_external(self.backend, atom, value)); return 0; } static int addWeightRule(lua_State *L) { auto &self = get_self(L); auto *head = AnyWrap::new_<std::vector<clingo_atom_t>>(L); // +1 clingo_weight_t lower; auto *body = AnyWrap::new_<std::vector<clingo_weighted_literal_t>>(L); // +1 bool choice = false; luaL_checktype(L, 2, LUA_TTABLE); luaPushKwArg(L, 2, 1, "head", false); // +1 luaToCpp(L, -1, *head); lua_pop(L, 1); // -1 luaPushKwArg(L, 2, 2, "lower", false); // +1 luaToCpp(L, -1, lower); lua_pop(L, 1); // -1 luaPushKwArg(L, 2, 3, "body", false); // +1 luaToCpp(L, -1, *body); lua_pop(L, 1); // -1 luaPushKwArg(L, 2, 4, "choice", true); // +1 luaToCpp(L, -1, choice); lua_pop(L, 1); // -1 handle_c_error(L, clingo_backend_weight_rule(self.backend, choice, head->data(), head->size(), lower, body->data(), body->size())); lua_pop(L, 2); // -2 return 0; } static int addMinimize(lua_State *L) { auto &self = get_self(L); clingo_weight_t priority; auto *body = AnyWrap::new_<std::vector<clingo_weighted_literal_t>>(L); // +1 luaL_checktype(L, 2, LUA_TTABLE); luaPushKwArg(L, 2, 1, "priority", false); // +1 luaToCpp(L, -1, priority); lua_pop(L, 1); // -1 luaPushKwArg(L, 2, 2, "body", false); // +1 luaToCpp(L, -1, *body); lua_pop(L, 1); // -1 handle_c_error(L, clingo_backend_minimize(self.backend, priority, body->data(), body->size())); lua_pop(L, 1); // -1 return 0; } static int close(lua_State *L) { auto &self = get_self(L); handle_c_error(L, clingo_backend_end(self.backend)); return 0; } }; luaL_Reg const Backend::meta[] = { {"add_atom", addAtom}, {"add_rule", addRule}, {"add_external", addExternal}, {"add_weight_rule", addWeightRule}, {"add_minimize", addMinimize}, {"close", close}, {nullptr, nullptr} }; // {{{1 wrap Trail struct Trail : Object<Trail> { clingo_assignment_t const *ass; Trail(clingo_assignment_t const *ass) : ass(ass) { } int32_t size_(lua_State *L) { return call_c(L, clingo_assignment_trail_size, ass); } clingo_literal_t at_(lua_State *L, uint32_t idx) { return call_c(L, clingo_assignment_trail_at, ass, idx); } static int size(lua_State *L) { lua_pushnumber(L, get_self(L).size_(L)); return 1; } static int begin(lua_State *L) { auto &self = get_self(L); auto level = numeric_cast<uint32_t>(luaL_checkinteger(L, 2)); lua_pushnumber(L, call_c(L, clingo_assignment_trail_begin, self.ass, level) + 1); return 1; } static int end(lua_State *L) { auto &self = get_self(L); auto level = numeric_cast<uint32_t>(luaL_checkinteger(L, 2)); lua_pushnumber(L, call_c(L, clingo_assignment_trail_end, self.ass, level)); return 1; } static int pairs_iter_(lua_State *L) { auto &self = get_self(L); auto idx = numeric_cast<int32_t>(luaL_checkinteger(L, 2)); if (idx < self.size_(L)) { lua_pushinteger(L, idx + 1); lua_pushnumber(L, self.at_(L, idx)); return 2; } return 0; } static int iter_(lua_State *L) { auto &self = *static_cast<Trail *>(luaL_checkudata(L, lua_upvalueindex(1), typeName)); auto idx = numeric_cast<int32_t>(lua_tointeger(L, lua_upvalueindex(2))); if (idx < self.size_(L)) { lua_pushinteger(L, idx + 1); lua_replace(L, lua_upvalueindex(2)); lua_pushnumber(L, self.at_(L, idx)); return 1; } return 0; } static int iter(lua_State *L) { lua_pushvalue(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, iter_, 2); return 1; } static int pairs(lua_State *L) { lua_pushcfunction(L, pairs_iter_); lua_pushvalue(L, 1); lua_pushinteger(L, 0); return 3; } static int at(lua_State *L) { auto &self = get_self(L); auto index = numeric_cast<int32_t>(luaL_checkinteger(L, 2)) - 1; if (index < self.size_(L)) { lua_pushnumber(L, self.at_(L, index)); return 1; } return 0; } static int index(lua_State *L) { if (lua_isnumber(L, 2)) { return at(L); } char const *name = luaL_checkstring(L, 2); lua_getmetatable(L, 1); lua_getfield(L, -1, name); return 1; } static constexpr char const *typeName = "clingo.Trail"; static luaL_Reg const meta[]; }; constexpr char const *Trail::typeName; luaL_Reg const Trail::meta[] = { {"iter", iter}, {"first", begin}, {"last", end}, {"__len", size}, {"__pairs", pairs}, {"__ipairs", pairs}, {nullptr, nullptr} }; // {{{1 wrap Assignment struct Assignment : Object<Assignment> { clingo_assignment_t const *ass; Assignment(clingo_assignment_t const *ass) : ass(ass) { } static int hasConflict(lua_State *L) { lua_pushboolean(L, clingo_assignment_has_conflict(get_self(L).ass)); return 1; } static int decisionLevel(lua_State *L) {
{'commit': 'diff --git a/app/clingo/tests/run.py b/app/clingo/tests/run.py\nindex 5cb461b6..926b0a73 100755\n--- a/app/clingo/tests/run.py\n+++ b/app/clingo/tests/run.py\n@@ -76,7 +76,7 @@ def normalize(out):\n     step=0\n     result="ERROR"\n     norm=[]\n-    for line in out.split(\'\\n\'):\n+    for line in out.split("\\n"):\n         if state == 1:\n             if step > 0:\n                 norm.append("Step: {}".format(step))\n@@ -115,7 +115,7 @@ if parse_ret.action == "normalize":\n     args = [clingo, "0", parse_ret.file, "-Wnone"]\n     b = os.path.splitext(parse_ret.file)[0]\n     if os.path.exists(b + ".cmd"):\n-        for x in open(b + ".cmd"):\n+        for x in open(b + ".cmd", \'rU\'):\n             args.extend(x.strip().split())\n     args.extend(extra_argv)\n     out, err = sp.Popen(args, stderr=sp.PIPE, stdout=sp.PIPE, universal_newlines=True).communicate()\n@@ -133,7 +133,7 @@ if parse_ret.action == "run":\n         for f in sorted(files):\n             if f.endswith(".lp"):\n                 b = os.path.join(root, f[:-3])\n-                inst = open(b + ".lp").read()\n+                inst = open(b + ".lp", \'rU\').read()\n                 if (not with_python and re.search(r"#script[ ]*\\(python\\)", inst)) or \\\n                    (not with_lua and re.search(r"#script[ ]*\\(lua\\)", inst)) or \\\n                    (not with_threads and re.search("async=", inst)) or \\\n@@ -145,12 +145,12 @@ if parse_ret.action == "run":\n \n                 args = [clingo, "0", b + ".lp", "-Wnone"]\n                 if os.path.exists(b + ".cmd"):\n-                    for x in open(b + ".cmd"):\n+                    for x in open(b + ".cmd", \'rU\'):\n                         args.extend(x.strip().split())\n                 args.extend(extra_argv)\n                 out, err = sp.Popen(args, stderr=sp.PIPE, stdout=sp.PIPE, universal_newlines=True).communicate()\n                 norm = normalize(out)\n-                sol  = reorder(open(b + ".sol").read())\n+                sol  = reorder(open(b + ".sol", \'rU\').read())\n                 if norm != sol:\n                     failed+= 1\n                     print\ndiff --git a/libluaclingo/luaclingo.cc b/libluaclingo/luaclingo.cc\nindex 3949b506..d9f39611 100644\n--- a/libluaclingo/luaclingo.cc\n+++ b/libluaclingo/luaclingo.cc\n@@ -1481,6 +1481,8 @@ struct SolveHandle : Object<SolveHandle> {\n     static SolveHandle *new_(lua_State *L) {\n         lua_newtable(L);                         // +1\n         auto *self = (SolveHandle*)lua_newuserdata(L, sizeof(SolveHandle)); // +1\n+        luaL_getmetatable(L, typeNameI);         // +1\n+        lua_setmetatable(L, -2);                 // +1\n         lua_rawseti(L, -2, 1);                   // -1\n         luaL_getmetatable(L, typeName);          // +1\n         lua_setmetatable(L, -2);                 // -1\n@@ -1492,8 +1494,17 @@ struct SolveHandle : Object<SolveHandle> {\n         self->ass = nullptr;\n         return self;\n     }\n+    static void reg(lua_State *L) {\n+        lua_regMeta(L, typeName, meta, index, newindex);\n+        lua_regMeta(L, typeNameI, metaI, nullptr, nullptr);\n+    }\n+    static int gc(lua_State *L) {\n+        return close_(L, *(SolveHandle*)lua_touserdata(L, 1));\n+    }\n     static int close(lua_State *L) {\n-        auto &self = get_self(L);\n+        return close_(L, get_self(L));\n+    }\n+    static int close_(lua_State *L, SolveHandle &self) {\n         if (self.handle) {\n             auto h = self.handle;\n             self.handle = nullptr;\n@@ -1604,19 +1615,26 @@ struct SolveHandle : Object<SolveHandle> {\n         return 1;\n     }\n     static luaL_Reg const meta[];\n+    static luaL_Reg const metaI[];\n     static constexpr char const *typeName = "clingo.SolveHandle";\n+    static constexpr char const *typeNameI = "clingo._SolveHandle";\n };\n \n constexpr char const *SolveHandle::typeName;\n+constexpr char const *SolveHandle::typeNameI;\n+\n luaL_Reg const SolveHandle::meta[] = {\n     {"iter",  iter},\n     {"close", close},\n-    {"__gc", close},\n     {"get", get},\n     {"resume", resume},\n     {"cancel", cancel},\n     {nullptr, nullptr}\n };\n+luaL_Reg const SolveHandle::metaI[] = {\n+    {"__gc", gc},\n+    {nullptr, nullptr}\n+};\n \n // {{{1 wrap Configuration\n \n@@ -2806,21 +2824,21 @@ struct ControlWrap : Object<ControlWrap> {\n \n         if (handle->mode & clingo_solve_mode_async) { return luaL_error(L, "asynchronous solving not supported"); }\n \n-        lua_settop(L, handleIdx);\n+        lua_settop(L, handleIdx + 1);\n \n         if (!lua_checkstack(L, 3)) { luaL_error(L, "lua stack size exceeded"); }\n         lua_pushcfunction(L, luaTraceback);        // +1\n         lua_pushcfunction(L, SolveHandle::solve_); // +1\n         lua_pushvalue(L, handleIdx);               // +1\n         int code = lua_pcall(L, 1, 1, -3);         // -1\n-        lua_replace(L, -2);                        // -1\n         if (code) {\n             auto h = handle->handle;\n             handle->handle = NULL;\n             call_c(L, clingo_solve_handle_close, h);\n         }\n-        lua_replace(L, -2);                        // -1\n         if (code) { lua_error(L); }\n+        lua_replace(L, handleIdx);\n+        lua_settop(L, handleIdx);\n         return 1;\n     }\n     static int assign_external(lua_State *L) {\n@@ -2910,16 +2928,24 @@ struct ControlWrap : Object<ControlWrap> {\n     }\n     template <class F>\n     static int new_(lua_State *L, F f) {\n-        lua_newtable(L);                                                           // +1\n+        lua_newtable(L);                                                   // +1\n         auto self = (ControlWrap*)lua_newuserdata(L, sizeof(ControlWrap)); // +1\n-        lua_rawseti(L, -2, 1);                                                     // -1\n+        // see: https://stackoverflow.com/questions/27426704/lua-5-1-workaround-for-gc-metamethod-for-tables\n+        luaL_getmetatable(L, typeNameI);                                   // +1\n+        lua_setmetatable(L, -2);                                           // -1\n+        lua_rawseti(L, -2, 1);                                             // -1\n         protect(L, [self, f]() { f(self); });\n-        luaL_getmetatable(L, typeName);                                            // +1\n-        lua_setmetatable(L, -2);                                                   // -1\n+        luaL_getmetatable(L, typeName);                                    // +1\n+        lua_setmetatable(L, -2);                                           // -1\n         return 1;\n     }\n+    static void reg(lua_State *L) {\n+        lua_regMeta(L, typeName, meta, index, newindex);\n+        lua_regMeta(L, typeNameI, metaI, nullptr, nullptr);\n+    }\n+\n     static int gc(lua_State *L) {\n-        auto &self = get_self(L);\n+        auto &self = *(ControlWrap*)lua_touserdata(L, 1);\n         if (self.free) { clingo_control_free(self.ctl); }\n         self.~ControlWrap();\n         return 0;\n@@ -3000,7 +3026,9 @@ struct ControlWrap : Object<ControlWrap> {\n     }\n \n     static luaL_Reg meta[];\n+    static luaL_Reg metaI[];\n     static constexpr char const *typeName = "clingo.Control";\n+    static constexpr char const *typeNameI = "clingo._Control";\n };\n \n constexpr char const *ControlWrap::typeName;\n@@ -3016,6 +3044,9 @@ luaL_Reg ControlWrap::meta[] = {\n     {"interrupt", interrupt},\n     {"register_propagator", registerPropagator},\n     {"register_observer", registerObserver},\n+    {nullptr, nullptr}\n+};\n+luaL_Reg ControlWrap::metaI[] = {\n     {"__gc", gc},\n     {nullptr, nullptr}\n };\n', 'commit_subject': 'fix lua 5.1 memory leak and invalid memory access in solve function', 'repo_name': 'potassco/clingo', 'committer': {'name': 'Roland Kaminski', 'email': 'b49c5fc565684f3d90f5d504b200a4b59080dff6@cs.uni-potsdam.de', 'time_sec': '1491930165', 'tz_offset': '120', 'date': {'seconds': '1491930165'}}, 'commit_tree': '932df3818cdec62d6d6a195cff000d1e99ef1960', 'commit_message': 'fix lua 5.1 memory leak and invalid memory access in solve function\n', 'language_name': 'Shell', 'license': 'mit', 'hunks': '@@ -1481,6 +1481,8 @@ struct SolveHandle : Object<SolveHandle> {\n     static SolveHandle *new_(lua_State *L) {\n         lua_newtable(L);                         // +1\n         auto *self = (SolveHandle*)lua_newuserdata(L, sizeof(SolveHandle)); // +1\n+        luaL_getmetatable(L, typeNameI);         // +1\n+        lua_setmetatable(L, -2);                 // +1\n         lua_rawseti(L, -2, 1);                   // -1\n         luaL_getmetatable(L, typeName);          // +1\n         lua_setmetatable(L, -2);                 // -1\n@@ -1492,8 +1494,17 @@ struct SolveHandle : Object<SolveHandle> {\n         self->ass = nullptr;\n         return self;\n     }\n+    static void reg(lua_State *L) {\n+        lua_regMeta(L, typeName, meta, index, newindex);\n+        lua_regMeta(L, typeNameI, metaI, nullptr, nullptr);\n+    }\n+    static int gc(lua_State *L) {\n+        return close_(L, *(SolveHandle*)lua_touserdata(L, 1));\n+    }\n     static int close(lua_State *L) {\n-        auto &self = get_self(L);\n+        return close_(L, get_self(L));\n+    }\n+    static int close_(lua_State *L, SolveHandle &self) {\n         if (self.handle) {\n             auto h = self.handle;\n             self.handle = nullptr;\n@@ -1604,19 +1615,26 @@ struct SolveHandle : Object<SolveHandle> {\n         return 1;\n     }\n     static luaL_Reg const meta[];\n+    static luaL_Reg const metaI[];\n     static constexpr char const *typeName = "clingo.SolveHandle";\n+    static constexpr char const *typeNameI = "clingo._SolveHandle";\n };\n \n constexpr char const *SolveHandle::typeName;\n+constexpr char const *SolveHandle::typeNameI;\n+\n luaL_Reg const SolveHandle::meta[] = {\n     {"iter",  iter},\n     {"close", close},\n-    {"__gc", close},\n     {"get", get},\n     {"resume", resume},\n     {"cancel", cancel},\n     {nullptr, nullptr}\n };\n+luaL_Reg const SolveHandle::metaI[] = {\n+    {"__gc", gc},\n+    {nullptr, nullptr}\n+};\n \n // {{{1 wrap Configuration\n \n@@ -2806,21 +2824,21 @@ struct ControlWrap : Object<ControlWrap> {\n \n         if (handle->mode & clingo_solve_mode_async) { return luaL_error(L, "asynchronous solving not supported"); }\n \n-        lua_settop(L, handleIdx);\n+        lua_settop(L, handleIdx + 1);\n \n         if (!lua_checkstack(L, 3)) { luaL_error(L, "lua stack size exceeded"); }\n         lua_pushcfunction(L, luaTraceback);        // +1\n         lua_pushcfunction(L, SolveHandle::solve_); // +1\n         lua_pushvalue(L, handleIdx);               // +1\n         int code = lua_pcall(L, 1, 1, -3);         // -1\n-        lua_replace(L, -2);                        // -1\n         if (code) {\n             auto h = handle->handle;\n             handle->handle = NULL;\n             call_c(L, clingo_solve_handle_close, h);\n         }\n-        lua_replace(L, -2);                        // -1\n         if (code) { lua_error(L); }\n+        lua_replace(L, handleIdx);\n+        lua_settop(L, handleIdx);\n         return 1;\n     }\n     static int assign_external(lua_State *L) {\n@@ -2910,16 +2928,24 @@ struct ControlWrap : Object<ControlWrap> {\n     }\n     template <class F>\n     static int new_(lua_State *L, F f) {\n-        lua_newtable(L);                                                           // +1\n+        lua_newtable(L);                                                   // +1\n         auto self = (ControlWrap*)lua_newuserdata(L, sizeof(ControlWrap)); // +1\n-        lua_rawseti(L, -2, 1);                                                     // -1\n+        // see: https://stackoverflow.com/questions/27426704/lua-5-1-workaround-for-gc-metamethod-for-tables\n+        luaL_getmetatable(L, typeNameI);                                   // +1\n+        lua_setmetatable(L, -2);                                           // -1\n+        lua_rawseti(L, -2, 1);                                             // -1\n         protect(L, [self, f]() { f(self); });\n-        luaL_getmetatable(L, typeName);                                            // +1\n-        lua_setmetatable(L, -2);                                                   // -1\n+        luaL_getmetatable(L, typeName);                                    // +1\n+        lua_setmetatable(L, -2);                                           // -1\n         return 1;\n     }\n+    static void reg(lua_State *L) {\n+        lua_regMeta(L, typeName, meta, index, newindex);\n+        lua_regMeta(L, typeNameI, metaI, nullptr, nullptr);\n+    }\n+\n     static int gc(lua_State *L) {\n-        auto &self = get_self(L);\n+        auto &self = *(ControlWrap*)lua_touserdata(L, 1);\n         if (self.free) { clingo_control_free(self.ctl); }\n         self.~ControlWrap();\n         return 0;\n@@ -3000,7 +3026,9 @@ struct ControlWrap : Object<ControlWrap> {\n     }\n \n     static luaL_Reg meta[];\n+    static luaL_Reg metaI[];\n     static constexpr char const *typeName = "clingo.Control";\n+    static constexpr char const *typeNameI = "clingo._Control";\n };\n \n constexpr char const *ControlWrap::typeName;\n@@ -3016,6 +3044,9 @@ luaL_Reg ControlWrap::meta[] = {\n     {"interrupt", interrupt},\n     {"register_propagator", registerPropagator},\n     {"register_observer", registerObserver},\n+    {nullptr, nullptr}\n+};\n+luaL_Reg ControlWrap::metaI[] = {\n     {"__gc", gc},\n     {nullptr, nullptr}\n };\n', 'addition_count': 41, 'deletion_count': 10, 'src_file': 'a/libluaclingo/luaclingo.cc', 'tgt_file': 'b/libluaclingo/luaclingo.cc', 'file_extension': '.cc', 'before_file': '// {{{ MIT License\n\n// Copyright 2017 Roland Kaminski\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the "Software"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n// IN THE SOFTWARE.\n\n// }}}\n\n#include "luaclingo.h"\n\n#include <lua.hpp>\n#include <cstring>\n#include <forward_list>\n#include <stdexcept>\n#include <sstream>\n#include <vector>\n#include <iostream>\n#include <algorithm>\n#include <cassert>\n#include <limits>\n\nnamespace {\n\n// {{{1 error handling\n\ntemplate <typename T>\nauto protect(lua_State *L, T f) -> decltype(f()) {\n    try                             { return f(); }\n    catch (std::exception const &e) { luaL_error(L, e.what()); }\n    catch (...)                     { luaL_error(L, "unknown error"); }\n    throw std::logic_error("cannot happen");\n}\n#define PROTECT(E) (protect(L, [&]{ return (E); }))\n\n// translates a clingo api error into a lua error\nvoid handle_c_error(lua_State *L, bool ret) {\n    if (!ret) {\n        char const *msg = clingo_error_message();\n        if (!msg) { msg = "no message"; }\n        luaL_error(L, msg);\n    }\n}\n\n// translates a lua error into a a clingo api error\nbool handle_lua_error(lua_State *L, char const *loc, char const *desc, int code) {\n    try {\n        switch (code) {\n            case LUA_ERRRUN:\n            case LUA_ERRERR:\n            case LUA_ERRSYNTAX: {\n                char const *s = lua_tostring(L, -1);\n                std::ostringstream msg;\n                msg << loc << ": " << "error: " << desc << ":\\n"\n                    << (code == LUA_ERRSYNTAX ? "  SyntaxError: " : "  RuntimeError: ")\n                    << s << "\\n"\n                    ;\n                clingo_set_error(clingo_error_runtime, msg.str().c_str());\n                lua_pop(L, 1);\n                return false;\n            }\n            case LUA_ERRMEM: {\n                std::stringstream msg;\n                msg << loc << ": error: lua interpreter ran out of memory" << "\\n";\n                clingo_set_error(clingo_error_bad_alloc, msg.str().c_str());\n                lua_pop(L, 1);\n                return false;\n            }\n        }\n    }\n    catch(...) {\n        lua_pop(L, 1);\n        clingo_set_error(clingo_error_logic, "error during error handling");\n        return false;\n    }\n    return true;\n}\n\n\ntemplate <typename... T>\nstruct Types { };\n\ntemplate<int, typename... T>\nstruct LastTypes;\ntemplate<>\nstruct LastTypes<0> { using Type = Types<>; };\ntemplate<typename A, typename... T>\nstruct LastTypes<0, A, T...> { using Type = Types<A, T...>; };\ntemplate<int n, typename A, typename... T>\nstruct LastTypes<n, A, T...> : LastTypes<n-1, T...> { };\n\ntemplate<int n, typename T>\nstruct LastArgs;\ntemplate<int n, typename... Args>\nstruct LastArgs<n, bool (*)(Args...)> : LastTypes<n, Args...> { };\n\ntemplate <typename F, typename... Args>\nvoid call_c_(Types<>*, lua_State *L, F f, Args ...args) {\n    handle_c_error(L, f(args...));\n}\n\ntemplate <typename T, typename F, typename... Args>\nT call_c_(Types<T*>*, lua_State *L, F f, Args ...args) {\n    T ret;\n    handle_c_error(L, f(args..., &ret));\n    return ret;\n}\n\ntemplate <typename T, typename U, typename F, typename... Args>\nstd::pair<T, U> call_c_(Types<T*, U*>*, lua_State *L, F f, Args ...args) {\n    T ret1;\n    U ret2;\n    handle_c_error(L, f(args..., &ret1, &ret2));\n    return {ret1, ret2};\n}\n\ntemplate <typename F, typename... Args, typename T=typename LastArgs<sizeof...(Args), F>::Type>\nstatic auto call_c(lua_State *L, F f, Args... args) -> decltype(call_c_(static_cast<T*>(nullptr), L, f, args...)) {\n    return call_c_(static_cast<T*>(nullptr), L, f, args...);\n}\n\nstatic int luaTraceback (lua_State *L) {\n    if (!lua_isstring(L, 1)) { return 1; }\n    lua_getglobal(L, "debug");\n    if (!lua_istable(L, -1)) {\n        lua_pop(L, 1);\n        return 1;\n    }\n    lua_getfield(L, -1, "traceback");\n    if (!lua_isfunction(L, -1)) {\n        lua_pop(L, 2);\n        return 1;\n    }\n    lua_pushvalue(L, 1);\n    lua_pushinteger(L, 2);\n    lua_call(L, 2, 1);\n    lua_getglobal(L, "string");\n    if (!lua_istable(L, -1)) {\n        lua_pop(L, 1);\n        return 1;\n    }\n    lua_getfield(L, -1, "gsub");\n    if (!lua_isfunction(L, -1)) {\n        lua_pop(L, 1);\n        return 1;\n    }\n    lua_pushvalue(L, -3);\n    lua_pushliteral(L, "\\t");\n    lua_pushliteral(L, "  ");\n    lua_call(L, 3, 1);\n    return 1;\n}\n\n// {{{1 Object\n\nvoid lua_regMeta(lua_State *L, char const *name, luaL_Reg const * funs, lua_CFunction indexfun = nullptr, lua_CFunction newindexfun = nullptr) {\n#if LUA_VERSION_NUM < 502\n    luaL_newmetatable(L, name);\n    luaL_register(L, 0, funs);\n#else\n    luaL_newmetatable(L, name);\n    luaL_setfuncs(L, funs, 0);\n#endif\n    lua_pushliteral(L, "__metatable");\n    lua_pushvalue(L, -2);\n    lua_rawset(L, -3);\n    lua_pushliteral(L, "__index");\n    if (indexfun) {\n        lua_pushcfunction(L, indexfun);\n    }\n    else {\n        lua_pushvalue(L, -2);\n    }\n    lua_rawset(L, -3);\n    if (newindexfun) {\n        lua_pushliteral(L, "__newindex");\n        lua_pushcfunction(L, newindexfun);\n        lua_rawset(L, -3);\n    }\n}\n\ntemplate <typename T>\nstruct Object {\n    template <typename... Args>\n    static int new_(lua_State *L, Args&&... args) {\n        new (lua_newuserdata(L, sizeof(T))) T(std::forward<Args>(args)...);\n        luaL_getmetatable(L, T::typeName);\n        lua_setmetatable(L, -2);\n        return 1;\n    }\n\n    static void reg(lua_State *L) {\n        lua_regMeta(L, T::typeName, T::meta, T::index, T::newindex);\n    }\n\n    static T &get_self(lua_State* L) {\n        return *(T*)luaL_checkudata(L, 1, T::typeName);\n    }\n\n    T &cmpKey() { return *static_cast<T*>(this); }\n\n    static int eq(lua_State *L) {\n        T *a = static_cast<T*>(luaL_checkudata(L, 1, T::typeName));\n        T *b = static_cast<T*>(luaL_checkudata(L, 2, T::typeName));\n        lua_pushboolean(L, a->cmpKey() == b->cmpKey());\n        return 1;\n    }\n    static int lt(lua_State *L) {\n        T *a = static_cast<T*>(luaL_checkudata(L, 1, T::typeName));\n        T *b = static_cast<T*>(luaL_checkudata(L, 2, T::typeName));\n        lua_pushboolean(L, a->cmpKey() < b->cmpKey());\n        return 1;\n    }\n    static int le(lua_State *L) {\n        T *a = static_cast<T*>(luaL_checkudata(L, 1, T::typeName));\n        T *b = static_cast<T*>(luaL_checkudata(L, 2, T::typeName));\n        lua_pushboolean(L, a->cmpKey() <= b->cmpKey());\n        return 1;\n    }\n    static constexpr luaL_Reg const meta[] = {{nullptr, nullptr}};\n    static constexpr lua_CFunction const index = nullptr;\n    static constexpr lua_CFunction const newindex = nullptr;\n};\n\ntemplate <typename T>\nconstexpr luaL_Reg const Object<T>::meta[];\ntemplate <typename T>\nconstexpr lua_CFunction const Object<T>::index;\ntemplate <typename T>\nconstexpr lua_CFunction const Object<T>::newindex;\n\n// {{{1 wrap Any\n\nstruct Any {\n    struct PlaceHolder {\n        virtual ~PlaceHolder() { };\n    };\n    template <class T>\n    struct Holder : public PlaceHolder {\n        template <typename... Args>\n        Holder(Args&&... args) : value(std::forward<Args>(args)...) { }\n        T value;\n    };\n    Any() : content(nullptr) { }\n    Any(Any &&other) : content(nullptr) { std::swap(content, other.content); }\n    template<typename T, typename... Args>\n    Any(T*, Args&&... args) : content(new Holder<T>(std::forward<T>(args)...)) { }\n    ~Any() { delete content; }\n\n    Any &operator=(Any &&other) {\n        std::swap(content, other.content);\n        return *this;\n    }\n\n    template<typename T>\n    T *get() {\n        auto x = dynamic_cast<Holder<T>*>(content);\n        return x ? &x->value : nullptr;\n    }\n    template<typename T>\n    T const *get() const {\n        auto x = dynamic_cast<Holder<T>*>(content);\n        return x ? &x->value : nullptr;\n    }\n    bool empty() const { return !content; }\n\n    PlaceHolder *content = nullptr;\n};\n\ntemplate <typename T, typename... Args>\nAny make_any(Args&&... args) {\n    return Any(static_cast<T*>(nullptr), std::forward<Args>(args)...);\n}\n\nstruct AnyWrap : Object<AnyWrap> {\n    Any any;\n    AnyWrap() { }\n    template <typename T, typename... Args>\n    static T *new_(lua_State *L, Args&&... args) {\n        Object::new_(L);\n        auto self = static_cast<AnyWrap*>(lua_touserdata(L, -1));\n        PROTECT((self->any = make_any<T>(std::forward<Args>(args)...), 0));\n        return self->any.get<T>();\n    }\n    static int gc(lua_State *L) {\n        auto &self = get_self(L);\n        self.~AnyWrap();\n        return 0;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo._Any";\n};\n\nconstexpr char const *AnyWrap::typeName;\n\nluaL_Reg const AnyWrap::meta[] = {\n    {"__gc", gc},\n    {nullptr, nullptr}\n};\n\n// {{{1 auxliary functions\n\nnamespace Detail {\n\ntemplate <int X> using int_type = std::integral_constant<int, X>;\ntemplate <class T, class S>\ninline void nc_check(S s, int_type<0>) { // same sign\n    (void)s;\n    assert((std::is_same<T, S>::value) || (s >= std::numeric_limits<T>::min() && s <= std::numeric_limits<T>::max()));\n}\ntemplate <class T, class S>\ninline void nc_check(S s, int_type<-1>) { // Signed -> Unsigned\n    (void)s;\n    assert(s >= 0 && static_cast<S>(static_cast<T>(s)) == s);\n}\ntemplate <class T, class S>\ninline void nc_check(S s, int_type<1>) { // Unsigned -> Signed\n    (void)s;\n    assert(!(s > static_cast<typename std::make_unsigned<T>::type>(std::numeric_limits<T>::max())));\n}\n\n} // namespace Detail\n\ntemplate <class T, class S>\ninline T numeric_cast(S s) {\n    constexpr int sv = int(std::numeric_limits<T>::is_signed) - int(std::numeric_limits<S>::is_signed);\n    Detail::nc_check<T>(s, Detail::int_type<sv>());\n    return static_cast<T>(s);\n}\n\n\nclingo_symbol_t luaToVal(lua_State *L, int idx);\n\n#if LUA_VERSION_NUM < 502\n\nint lua_absindex(lua_State *L, int idx) {\n    return (idx < 0) ? lua_gettop(L) + idx + 1 : idx;\n}\n\n// size_t lua_len(lua_State *L, int index) {\n//     return lua_objlen(L, index);\n// }\n\n// size_t lua_rawlen(lua_State *L, int index) {\n//     return lua_objlen(L, index);\n// }\n\n#endif\n\nstatic int luaPushKwArg(lua_State *L, int index, int pos, char const *name, bool optional) {\n    index = lua_absindex(L, index);\n    lua_pushinteger(L, pos);\n    lua_gettable(L, index);\n    if (!lua_isnil(L, -1)) {\n        if (name) {\n            lua_getfield(L, index, name);\n            if (!lua_isnil(L, -1)) {\n                lua_pop(L, 2);\n                return luaL_error(L, "argument #%d also given by keyword %s", pos, name);\n            }\n            lua_pop(L, 1);\n        }\n    }\n    else if (name) {\n        lua_pop(L, 1);\n        lua_getfield(L, index, name);\n    }\n    if (!optional && lua_isnil(L, -1)) {\n        return name ? luaL_error(L, "argument %s (#%d) missing", name, pos) : luaL_error(L, "argument #%d missing", pos);\n    }\n    return 1;\n}\n\ntemplate <class T, class U>\nvoid luaToCpp(lua_State *L, int index, std::pair<T, U> &x);\n\nvoid luaToCpp(lua_State *L, int index, clingo_weighted_literal_t &x);\n\ntemplate <class T>\nvoid luaToCpp(lua_State *L, int index, std::vector<T> &x);\n\nvoid luaToCpp(lua_State *L, int index, bool &x) {\n    x = lua_toboolean(L, index) != 0;\n}\n\nvoid luaToCpp(lua_State *L, int index, std::string &x) {\n    char const *str = lua_tostring(L, index);\n    PROTECT(x = str);\n}\n\ntemplate <class T>\nvoid luaToCpp(lua_State *L, int index, T &x, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) {\n    if (lua_type(L, index) != LUA_TNUMBER) {\n        luaL_error(L, "number expected");\n    }\n    x = numeric_cast<T>(lua_tointeger(L, index));\n}\n\nstruct symbol_wrapper {\n    clingo_symbol_t symbol;\n};\n\nvoid luaToCpp(lua_State *L, int index, symbol_wrapper &x) {\n    x.symbol = luaToVal(L, index);\n}\n\nstruct symbolic_literal_t {\n    clingo_symbol_t symbol;\n    bool positive;\n};\n\nvoid luaToCpp(lua_State *L, int index, symbolic_literal_t &x);\n\ntemplate <class T>\nvoid luaToCpp(lua_State *L, int index, std::vector<T> &x) {\n    index = lua_absindex(L, index);\n    if (lua_type(L, index) != LUA_TTABLE) {\n        luaL_error(L, "table expected");\n    }\n    lua_pushnil(L);\n    while (lua_next(L, index) != 0) {\n        auto &y = protect(L, [&x]() -> T& { x.emplace_back(); return x.back(); });\n        luaToCpp(L, -1, y);\n        lua_pop(L, 1);\n    }\n}\n\ntemplate <class T, class U>\nvoid luaToCpp(lua_State *L, int index, std::pair<T, U> &x) {\n    index = lua_absindex(L, index);\n    if (lua_type(L, index) != LUA_TTABLE) {\n        luaL_error(L, "table expected");\n    }\n    lua_pushnil(L);\n    if (lua_next(L, index) != 0) {\n        luaToCpp(L, -1, x.first);\n        lua_pop(L, 1);\n    }\n    else {\n        luaL_error(L, "tuple expected");\n    }\n    if (lua_next(L, index) != 0) {\n        luaToCpp(L, -1, x.second);\n        lua_pop(L, 1);\n    }\n    else {\n        luaL_error(L, "tuple expected");\n    }\n    if (lua_next(L, index) != 0) {\n        luaL_error(L, "tuple expected");\n    }\n}\n\nvoid luaToCpp(lua_State *L, int index, symbolic_literal_t &x) {\n    std::pair<symbol_wrapper&, bool&> p{reinterpret_cast<symbol_wrapper&>(x.symbol), x.positive};\n    luaToCpp(L, index, p);\n}\n\nvoid luaToCpp(lua_State *L, int index, clingo_weighted_literal_t &x) {\n    std::pair<clingo_literal_t&, clingo_weight_t&> y{x.literal, x.weight};\n    luaToCpp(L, index, y);\n}\n\ntemplate <class T>\ntypename std::enable_if<std::is_integral<T>::value, void>::type cppToLua(lua_State *L, T value) {\n    lua_pushnumber(L, value);\n}\n\ntemplate <class T>\nvoid cppToLua(lua_State *L, T *values, size_t size) {\n    lua_createtable(L, size, 0);\n    int i = 1;\n    for (auto it = values, ie = it + size; it != ie; ++it) {\n        cppToLua(L, *it);\n        lua_rawseti(L, -2, i++);\n    }\n}\n\n// replaces the table at index idx with a pointer holding a vector\nstd::vector<clingo_symbol_t> *luaToVals(lua_State *L, int idx) {\n    idx = lua_absindex(L, idx);\n    luaL_checktype(L, idx, LUA_TTABLE);\n    std::vector<clingo_symbol_t> *vals = AnyWrap::new_<std::vector<clingo_symbol_t>>(L);\n    lua_pushnil(L);\n    while (lua_next(L, idx) != 0) {\n        clingo_symbol_t sym = luaToVal(L, -1);\n        protect(L, [sym, &vals](){ vals->push_back(sym); });\n        lua_pop(L, 1);\n    }\n    lua_replace(L, idx);\n    return vals;\n}\n\nstruct LuaClear {\n    LuaClear(lua_State *L) : L(L), n(lua_gettop(L)) { }\n    ~LuaClear() { lua_settop(L, n); }\n    lua_State *L;\n    int n;\n};\n\nstd::ostream &operator<<(std::ostream &out, clingo_location_t loc) {\n    out << loc.begin_file << ":" << loc.begin_line << ":" << loc.begin_column;\n    if (strcmp(loc.begin_file, loc.end_file) != 0) {\n        out << "-" << loc.end_file << ":" << loc.end_line << ":" << loc.end_column;\n    }\n    else if (loc.begin_line != loc.end_line) {\n        out << "-" << loc.end_line << ":" << loc.end_column;\n    }\n    else if (loc.begin_column != loc.end_column) {\n        out << "-" << loc.end_column;\n    }\n    return out;\n}\n\n// {{{1 wrap SolveResult\n\nstruct SolveResult : Object<SolveResult> {\n    clingo_solve_result_bitset_t res;\n    SolveResult(clingo_solve_result_bitset_t res) : res(res) { }\n    static int satisfiable(lua_State *L) {\n        auto &&res = get_self(L).res;\n        if      (res & clingo_solve_result_satisfiable)   { lua_pushboolean(L, true); }\n        else if (res & clingo_solve_result_unsatisfiable) { lua_pushboolean(L, false); }\n        else                                              { lua_pushnil(L); }\n        return 1;\n    }\n    static int unsatisfiable(lua_State *L) {\n        auto &&res = get_self(L).res;\n        if      (res & clingo_solve_result_unsatisfiable) { lua_pushboolean(L, true); }\n        else if (res & clingo_solve_result_satisfiable)   { lua_pushboolean(L, false); }\n        else                                              { lua_pushnil(L); }\n        return 1;\n    }\n    static int unknown(lua_State *L) {\n        auto &&res = get_self(L).res;\n        if ((res & clingo_solve_result_unsatisfiable) ||\n            (res & clingo_solve_result_satisfiable)) { lua_pushboolean(L, false); }\n        else                                         { lua_pushboolean(L, true); }\n        return 1;\n    }\n    static int exhausted(lua_State *L) {\n        auto &&res = get_self(L).res;\n        lua_pushboolean(L, res & clingo_solve_result_exhausted);\n        return 1;\n    }\n    static int interrupted(lua_State *L) {\n        auto &&res = get_self(L).res;\n        lua_pushboolean(L, res & clingo_solve_result_interrupted);\n        return 1;\n    }\n    static int index(lua_State *L) {\n        char const *name = luaL_checkstring(L, 2);\n        if      (strcmp(name, "satisfiable")   == 0) { return satisfiable(L); }\n        else if (strcmp(name, "unsatisfiable") == 0) { return unsatisfiable(L); }\n        else if (strcmp(name, "unknown")       == 0) { return unknown(L); }\n        else if (strcmp(name, "exhausted")     == 0) { return exhausted(L); }\n        else if (strcmp(name, "interrupted")   == 0) { return interrupted(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", name);\n        }\n    }\n    static int toString(lua_State *L) {\n        auto &&res = get_self(L).res;\n        if      (res & clingo_solve_result_satisfiable)   { lua_pushstring(L, "SAT"); }\n        else if (res & clingo_solve_result_unsatisfiable) { lua_pushstring(L, "UNSAT"); }\n        else                                              { lua_pushstring(L, "UNKNOWN"); }\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.SolveResult";\n};\n\nconstexpr char const *SolveResult::typeName;\n\nluaL_Reg const SolveResult::meta[] = {\n    {"__tostring", toString},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap TheoryTerm\n\nstruct TheoryTermType : Object<TheoryTermType> {\n    clingo_theory_term_type_e type;\n    TheoryTermType(clingo_theory_term_type_e type) : type(type) { }\n    clingo_theory_term_type_e cmpKey() { return type; }\n    static int addToRegistry(lua_State *L) {\n        lua_createtable(L, 0, 6);\n        for (auto t : { clingo_theory_term_type_function, clingo_theory_term_type_number, clingo_theory_term_type_symbol, clingo_theory_term_type_tuple, clingo_theory_term_type_list, clingo_theory_term_type_set}) {\n            Object::new_(L, t);\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "TheoryTermType");\n        return 0;\n    }\n    static char const *field_(clingo_theory_term_type_t t) {\n        switch (static_cast<clingo_theory_term_type_e>(t)) {\n            case clingo_theory_term_type_function: { return "Function"; }\n            case clingo_theory_term_type_number:   { return "Number"; }\n            case clingo_theory_term_type_symbol:   { return "Symbol"; }\n            case clingo_theory_term_type_tuple:    { return "Tuple"; }\n            case clingo_theory_term_type_list:     { return "List"; }\n            case clingo_theory_term_type_set:      { return "Set"; }\n        }\n        return "";\n    }\n    static int new_(lua_State *L, clingo_theory_term_type_t t) {\n        lua_getfield(L, LUA_REGISTRYINDEX, "clingo");\n        lua_getfield(L, -1, "TheoryTermType");\n        lua_replace(L, -2);\n        lua_getfield(L, -1, field_(t));\n        lua_replace(L, -2);\n        return 1;\n    }\n    static int toString(lua_State *L) {\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.TheoryTermType";\n};\n\nconstexpr char const *TheoryTermType::typeName;\n\nluaL_Reg const TheoryTermType::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\n\nstruct TheoryTerm : Object<TheoryTerm> {\n    clingo_theory_atoms_t const *atoms;\n    clingo_id_t id;\n    TheoryTerm(clingo_theory_atoms_t const *atoms, clingo_id_t id) : atoms(atoms), id(id) { }\n    clingo_id_t cmpKey() { return id; }\n    static int name(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushstring(L, call_c(L, clingo_theory_atoms_term_name, self.atoms, self.id));\n        return 1;\n    }\n    static int number(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_theory_atoms_term_number, self.atoms, self.id));\n        return 1;\n    }\n    static int args(lua_State *L) {\n        auto &self = get_self(L);\n        auto ret = call_c(L, clingo_theory_atoms_term_arguments, self.atoms, self.id);\n        lua_createtable(L, numeric_cast<int>(ret.second), 0);\n        int i = 1;\n        for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) {\n            new_(L, self.atoms, *it);\n            lua_rawseti(L, -2, i++);\n        }\n        return 1;\n    }\n    static int toString(lua_State *L) {\n        auto &self = get_self(L);\n        size_t size = call_c(L, clingo_theory_atoms_term_to_string_size, self.atoms, self.id);\n        char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1\n        handle_c_error(L, clingo_theory_atoms_term_to_string(self.atoms, self.id, buf, size));\n        lua_pushstring(L, buf);                                                   // +1\n        lua_replace(L, -2);                                                       // -1\n        return 1;\n    }\n    static int type(lua_State *L) {\n        auto &self = get_self(L);\n        return TheoryTermType::new_(L, call_c(L, clingo_theory_atoms_term_type, self.atoms, self.id));\n    }\n    static int index(lua_State *L) {\n        char const *field = luaL_checkstring(L, 2);\n        if (strcmp(field, "type") == 0) { return type(L); }\n        else if (strcmp(field, "name") == 0) { return name(L); }\n        else if (strcmp(field, "arguments") == 0) { return args(L); }\n        else if (strcmp(field, "number") == 0) { return number(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, field);\n            return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", field);\n        }\n    }\n    static constexpr char const *typeName = "clingo.TheoryTerm";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *TheoryTerm::typeName;\nluaL_Reg const TheoryTerm::meta[] = {\n    {"__tostring", toString},\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap TheoryElement\n\nstruct TheoryElement : Object<TheoryElement> {\n    TheoryElement(clingo_theory_atoms_t const *atoms, clingo_id_t id) : atoms(atoms) , id(id) { }\n    clingo_theory_atoms_t const *atoms;\n    clingo_id_t cmpKey() { return id; }\n    clingo_id_t id;\n\n    static int terms(lua_State *L) {\n        auto &self = get_self(L);\n        auto ret = call_c(L, clingo_theory_atoms_element_tuple, self.atoms, self.id);\n        lua_createtable(L, numeric_cast<int>(ret.second), 0);\n        int i = 1;\n        for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) {\n            TheoryTerm::new_(L, self.atoms, *it);\n            lua_rawseti(L, -2, i++);\n        }\n        return 1;\n    }\n\n    static int condition(lua_State *L) {\n        auto &self = get_self(L);\n        auto ret = call_c(L, clingo_theory_atoms_element_condition, self.atoms, self.id);\n        lua_createtable(L, numeric_cast<int>(ret.second), 0);\n        int i = 1;\n        for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) {\n            lua_pushinteger(L, *it);\n            lua_rawseti(L, -2, i++);\n        }\n        return 1;\n    }\n\n    static int conditionId(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_theory_atoms_element_condition_id, self.atoms, self.id));\n        return 1;\n    }\n\n    static int toString(lua_State *L) {\n        auto &self = get_self(L);\n        auto size = call_c(L, clingo_theory_atoms_element_to_string_size, self.atoms, self.id);\n        char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1\n        handle_c_error(L, clingo_theory_atoms_element_to_string(self.atoms, self.id, buf, size));\n        lua_pushstring(L, buf);                                                   // +1\n        lua_replace(L, -2);                                                       // -1\n        return 1;\n    }\n\n    static int index(lua_State *L) {\n        char const *field = luaL_checkstring(L, 2);\n        if (strcmp(field, "terms") == 0) { return terms(L); }\n        else if (strcmp(field, "condition") == 0) { return condition(L); }\n        else if (strcmp(field, "condition_id") == 0) { return conditionId(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, field);\n            return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", field);\n        }\n    }\n\n    static constexpr char const *typeName = "clingo.TheoryElement";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *TheoryElement::typeName;\nluaL_Reg const TheoryElement::meta[] = {\n    {"__tostring", toString},\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap TheoryAtom\n\nstruct TheoryAtom : Object<TheoryAtom> {\n    clingo_theory_atoms_t const *atoms;\n    clingo_id_t id;\n    TheoryAtom(clingo_theory_atoms_t const *atoms, clingo_id_t id) : atoms(atoms) , id(id) { }\n    clingo_id_t cmpKey() { return id; }\n\n    static int elements(lua_State *L) {\n        auto &self = get_self(L);\n        auto ret = call_c(L, clingo_theory_atoms_atom_elements, self.atoms, self.id);\n        lua_createtable(L, numeric_cast<int>(ret.second), 0);\n        int i = 1;\n        for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) {\n            TheoryElement::new_(L, self.atoms, *it);\n            lua_rawseti(L, -2, i++);\n        }\n        return 1;\n    }\n\n    static int term(lua_State *L) {\n        auto &self = get_self(L);\n        return TheoryTerm::new_(L, self.atoms, call_c(L, clingo_theory_atoms_atom_term, self.atoms, self.id));\n    }\n\n    static int literal(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_theory_atoms_atom_literal, self.atoms, self.id));\n        return 1;\n    }\n\n    static int guard(lua_State *L) {\n        auto &self = get_self(L);\n        if (!call_c(L, clingo_theory_atoms_atom_has_guard, self.atoms, self.id)) {\n            lua_pushnil(L);\n            return 1;\n        }\n        lua_createtable(L, 2, 0);\n        auto ret = call_c(L, clingo_theory_atoms_atom_guard, self.atoms, self.id);\n        lua_pushstring(L, ret.first);\n        lua_rawseti(L, -2, 1);\n        TheoryTerm::new_(L, self.atoms, ret.second);\n        lua_rawseti(L, -2, 2);\n        return 1;\n    }\n\n    static int toString(lua_State *L) {\n        auto &self = get_self(L);\n        auto size = call_c(L, clingo_theory_atoms_atom_to_string_size, self.atoms, self.id);\n        char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1\n        handle_c_error(L, clingo_theory_atoms_atom_to_string(self.atoms, self.id, buf, size));\n        lua_pushstring(L, buf);                                                   // +1\n        lua_replace(L, -2);                                                       // -1\n        return 1;\n    }\n\n    static int index(lua_State *L) {\n        char const *field = luaL_checkstring(L, 2);\n        if (strcmp(field, "elements") == 0) { return elements(L); }\n        else if (strcmp(field, "term") == 0) { return term(L); }\n        else if (strcmp(field, "guard") == 0) { return guard(L); }\n        else if (strcmp(field, "literal") == 0) { return literal(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, field);\n            return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", field);\n        }\n    }\n\n    static constexpr char const *typeName = "clingo.TheoryAtom";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *TheoryAtom::typeName;\nluaL_Reg const TheoryAtom::meta[] = {\n    {"__tostring", toString},\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap TheoryIter\n\nstruct TheoryIter {\n    static int iter(lua_State *L, clingo_theory_atoms_t const *atoms) {\n        lua_pushlightuserdata(L, const_cast<clingo_theory_atoms_t*>(atoms));\n        lua_pushinteger(L, 0);\n        lua_pushcclosure(L, iter_, 2);\n        return 1;\n    }\n\n    static int iter_(lua_State *L) {\n        auto atoms = (clingo_theory_atoms_t const *)lua_topointer(L, lua_upvalueindex(1));\n        clingo_id_t idx = numeric_cast<clingo_id_t>(lua_tonumber(L, lua_upvalueindex(2)));\n        if (idx < call_c(L, clingo_theory_atoms_size, atoms)) {\n            lua_pushinteger(L, idx + 1);\n            lua_replace(L, lua_upvalueindex(2));\n            TheoryAtom::new_(L, atoms, idx);\n        }\n        else { lua_pushnil(L); }\n        return 1;\n    }\n};\n\n// {{{1 wrap Term\n\nstruct SymbolType : Object<SymbolType> {\n    clingo_symbol_type_t type;\n    SymbolType(clingo_symbol_type_t type) : type(type) { }\n    clingo_symbol_type_t cmpKey() { return type; }\n    static int addToRegistry(lua_State *L) {\n        lua_createtable(L, 0, 5);\n        for (auto t : {clingo_symbol_type_number, clingo_symbol_type_string, clingo_symbol_type_function, clingo_symbol_type_infimum, clingo_symbol_type_supremum}) {\n            new_(L, t);\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "SymbolType");\n        return 0;\n    }\n    static char const *field_(clingo_symbol_type_t type) {\n        switch (static_cast<clingo_symbol_type_e>(type)) {\n            case clingo_symbol_type_number:   { return "Number"; }\n            case clingo_symbol_type_string:   { return "String"; }\n            case clingo_symbol_type_function: { return "Function"; }\n            case clingo_symbol_type_infimum:  { return "Infimum"; }\n            case clingo_symbol_type_supremum: { break; }\n        }\n        return "Supremum";\n    }\n\n    static int toString(lua_State *L) {\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.SymbolType";\n};\n\nconstexpr char const *SymbolType::typeName;\n\nluaL_Reg const SymbolType::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\n\nstruct Term : Object<Term> {\n    clingo_symbol_t symbol;\n    Term(clingo_symbol_t symbol) : symbol(symbol) { }\n    static int new_(lua_State *L, clingo_symbol_t sym) {\n        auto type = clingo_symbol_type(sym);\n        if (type == clingo_symbol_type_supremum) {\n            lua_getfield(L, LUA_REGISTRYINDEX, "clingo");\n            lua_getfield(L, -1, "Supremum");\n            lua_replace(L, -2);\n        }\n        else if (type == clingo_symbol_type_infimum) {\n            lua_getfield(L, LUA_REGISTRYINDEX, "clingo");\n            lua_getfield(L, -1, "Infimum");\n            lua_replace(L, -2);\n        }\n        else { Object::new_(L, sym); }\n        return 1;\n    }\n    static int addToRegistry(lua_State *L) {\n        clingo_symbol_t sym;\n        clingo_symbol_create_supremum(&sym);\n        Object::new_(L, sym);\n        lua_setfield(L, -2, "Supremum");\n        clingo_symbol_create_infimum(&sym);\n        Object::new_(L, sym);\n        lua_setfield(L, -2, "Infimum");\n        return 0;\n    }\n    static int newFun(lua_State *L) {\n        char const *name = luaL_checklstring(L, 1, nullptr);\n        bool positive = true;\n        if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) {\n            luaToCpp(L, 3, positive);\n        }\n        if (name[0] == \'\\0\' && !positive) { luaL_argerror(L, 2, "tuples must not have signs"); }\n        if (lua_isnoneornil(L, 2)) {\n            return new_(L, call_c(L, clingo_symbol_create_id, name, positive));\n        }\n        else {\n            lua_pushvalue(L, 2);\n            std::vector<clingo_symbol_t> *args = luaToVals(L, -1);\n            new_(L, call_c(L, clingo_symbol_create_function, name, args->data(), args->size(), positive));\n            lua_replace(L, -2);\n            return 1;\n        }\n    }\n    static int newTuple(lua_State *L) {\n        lua_pushstring(L, "");\n        lua_insert(L, 1);\n        return newFun(L);\n    }\n    static int newNumber(lua_State *L) {\n        clingo_symbol_t sym;\n        clingo_symbol_create_number(numeric_cast<int>(luaL_checkinteger(L, 1)), &sym);\n        return Term::new_(L, sym);\n    }\n    static int newString(lua_State *L) {\n        return Term::new_(L, call_c(L, clingo_symbol_create_string, luaL_checkstring(L, 1)));\n    }\n    bool operator==(Term const &other) {\n        return clingo_symbol_is_equal_to(symbol, other.symbol);\n    }\n    bool operator <(Term const &other) {\n        return clingo_symbol_is_less_than(symbol, other.symbol);\n    }\n    bool operator<=(Term const &other) {\n        return !clingo_symbol_is_less_than(other.symbol, symbol);\n    }\n    static int name(lua_State *L) {\n        auto &self = get_self(L);\n        if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) {\n            lua_pushstring(L, call_c(L, clingo_symbol_name, self.symbol));\n        }\n        else {\n            lua_pushnil(L);\n        }\n        return 1;\n    }\n    static int string(lua_State *L) {\n        auto &self = get_self(L);\n        if (clingo_symbol_type(self.symbol) == clingo_symbol_type_string) {\n            lua_pushstring(L, call_c(L, clingo_symbol_string, self.symbol));\n        }\n        else {\n            lua_pushnil(L);\n        }\n        return 1;\n    }\n    static int number(lua_State *L) {\n        auto &self = get_self(L);\n        if (clingo_symbol_type(self.symbol) == clingo_symbol_type_number) {\n            lua_pushinteger(L, call_c(L, clingo_symbol_number, self.symbol));\n        }\n        else {\n            lua_pushnil(L);\n        }\n        return 1;\n    }\n    static int negative(lua_State *L) {\n        auto &self = get_self(L);\n        if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) {\n            lua_pushboolean(L, call_c(L, clingo_symbol_is_negative, self.symbol));\n        }\n        else {\n            lua_pushnil(L);\n        }\n        return 1;\n    }\n    static int positive(lua_State *L) {\n        auto &self = get_self(L);\n        if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) {\n            lua_pushboolean(L, call_c(L, clingo_symbol_is_positive, self.symbol));\n        }\n        else {\n            lua_pushnil(L);\n        }\n        return 1;\n    }\n    static int args(lua_State *L) {\n        auto &self = get_self(L);\n        if (clingo_symbol_type(self.symbol) == clingo_symbol_type_function) {\n            auto ret = call_c(L, clingo_symbol_arguments, self.symbol);\n            lua_createtable(L, numeric_cast<int>(ret.second), 0);\n            int i = 1;\n            for (auto it = ret.first, ie = it + ret.second; it != ie; ++it) {\n                Term::new_(L, *it);\n                lua_rawseti(L, -2, i++);\n            }\n        }\n        else {\n            lua_pushnil(L);\n        }\n        return 1;\n    }\n    static int toString(lua_State *L) {\n        auto &self = get_self(L);\n        auto size = call_c(L, clingo_symbol_to_string_size, self.symbol);\n        char *buf = static_cast<char *>(lua_newuserdata(L, size * sizeof(*buf))); // +1\n        handle_c_error(L, clingo_symbol_to_string(self.symbol, buf, size));\n        lua_pushstring(L, buf);                                                   // +1\n        lua_replace(L, -2);                                                       // -1\n        return 1;\n    }\n    static int type(lua_State *L) {\n        auto &self = get_self(L);\n        lua_getfield(L, LUA_REGISTRYINDEX, "clingo");\n        lua_getfield(L, -1, "SymbolType");\n        lua_getfield(L, -1, SymbolType::field_(clingo_symbol_type(self.symbol)));\n        return 1;\n    }\n    static int index(lua_State *L) {\n        char const *field = luaL_checkstring(L, 2);\n        if      (strcmp(field, "positive") == 0)  { return positive(L); }\n        else if (strcmp(field, "negative") == 0)  { return negative(L); }\n        else if (strcmp(field, "arguments") == 0) { return args(L); }\n        else if (strcmp(field, "name") == 0)      { return name(L); }\n        else if (strcmp(field, "string") == 0)    { return string(L); }\n        else if (strcmp(field, "number") == 0)    { return number(L); }\n        else if (strcmp(field, "type") == 0)      { return type(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, field);\n            return 1;\n        }\n    }\n    static constexpr char const *typeName = "clingo.Symbol";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *Term::typeName;\nluaL_Reg const Term::meta[] = {\n    {"__tostring", toString},\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {nullptr, nullptr}\n};\n\nclingo_symbol_t luaToVal(lua_State *L, int idx) {\n    int type = lua_type(L, idx);\n    switch (type) {\n        case LUA_TSTRING: {\n            return call_c(L, clingo_symbol_create_string, lua_tostring(L, idx));\n        }\n        case LUA_TNUMBER: {\n            clingo_symbol_t ret;\n            clingo_symbol_create_number(numeric_cast<int>(lua_tointeger(L, idx)), &ret);\n            return ret;\n        }\n        case LUA_TUSERDATA: {\n            bool check = false;\n            if (lua_getmetatable(L, idx)) {                          // +1\n                lua_getfield(L, LUA_REGISTRYINDEX, "clingo.Symbol"); // +1\n                check = lua_rawequal(L, -1, -2) != 0;\n                lua_pop(L, 2);                                       // -2\n            }\n            if (check) { return static_cast<Term*>(lua_touserdata(L, idx))->symbol; }\n        }\n        default: { luaL_error(L, "cannot convert to value"); }\n    }\n    return {};\n}\n\nstruct LuaCallArgs_ {\n    char const *name;\n    clingo_symbol_t const *arguments;\n    size_t size;\n    clingo_symbol_callback_t symbol_callback;\n    void *data;\n};\n\nint luacall_(lua_State *L) {\n    auto &args = *static_cast<LuaCallArgs_*>(lua_touserdata(L, 1));\n    int context = 0;\n    if (!lua_isnil(L, 2)) {\n        context = 1;\n        lua_getfield(L, 2, args.name);\n        lua_pushvalue(L, 2);\n    }\n    else { lua_getglobal(L, args.name); }\n    for (auto it = args.arguments, ie = it + args.size; it != ie; ++it) {\n        Term::new_(L, *it);\n    }\n    lua_call(L, numeric_cast<int>(args.size + context), 1);\n    if (lua_type(L, -1) == LUA_TTABLE) {\n        lua_pushnil(L);\n        while (lua_next(L, -2)) {\n            clingo_symbol_t val = luaToVal(L, -1);\n            handle_c_error(L, args.symbol_callback(&val, 1, args.data));\n            lua_pop(L, 1);\n        }\n    }\n    else {\n        clingo_symbol_t val = luaToVal(L, -1);\n        handle_c_error(L, args.symbol_callback(&val, 1, args.data));\n    }\n    return 0;\n}\n\n// TODO: also needs a version with a string location\nbool luacall(lua_State *L, clingo_location_t const *location, int context, char const *name, clingo_symbol_t const *arguments, size_t arguments_size, clingo_symbol_callback_t symbol_callback, void *symbol_callback_data) {\n    if (!lua_checkstack(L, 4)) {\n        clingo_set_error(clingo_error_bad_alloc, "lua stack size exceeded");\n        return false;\n    }\n    LuaCallArgs_ args{ name, arguments, arguments_size, symbol_callback, symbol_callback_data };\n    lua_pushcfunction(L, luaTraceback); // +1\n    int err = lua_gettop(L);\n    lua_pushcfunction(L, luacall_);     // +1\n    lua_pushlightuserdata(L, &args);    // +1\n    if (context) { lua_pushvalue(L, context); }\n    else         { lua_pushnil(L); }    // +1\n    auto ret = lua_pcall(L, 2, 0, -4);  // -3|-2\n    lua_remove(L, err);\n    if (ret != 0) {\n        std::string loc, desc;\n        try {\n            std::ostringstream oss;\n            oss << *location;\n            loc = oss.str();\n            desc = "error calling ";\n            desc += name;\n        }\n        catch (...) {\n            lua_pop(L, 1); // |-1\n            clingo_set_error(clingo_error_runtime, "error during error handling");\n            return false;\n        }\n        return handle_lua_error(L, loc.c_str(), desc.c_str(), ret);\n    }\n    return true;\n}\n\n// {{{1 wrap SymbolicAtom\n\nstruct SymbolicAtom : Object<SymbolicAtom> {\n    clingo_symbolic_atoms_t const *atoms;\n    clingo_symbolic_atom_iterator_t iter;\n    static luaL_Reg const meta[];\n    static constexpr const char *typeName = "clingo.SymbolicAtom";\n    SymbolicAtom(clingo_symbolic_atoms_t const *atoms, clingo_symbolic_atom_iterator_t iter)\n    : atoms(atoms)\n    , iter(iter) { }\n    static int symbol(lua_State *L) {\n        auto &self = get_self(L);\n        return Term::new_(L, call_c(L, clingo_symbolic_atoms_symbol, self.atoms, self.iter));\n    }\n    static int literal(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_symbolic_atoms_literal, self.atoms, self.iter));\n        return 1;\n    }\n    static int is_fact(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushboolean(L, call_c(L, clingo_symbolic_atoms_is_fact, self.atoms, self.iter));\n        return 1;\n    }\n    static int is_external(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushboolean(L, call_c(L, clingo_symbolic_atoms_is_external, self.atoms, self.iter));\n        return 1;\n    }\n    static int index(lua_State *L) {\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "is_fact") == 0) { return is_fact(L); }\n        else if (strcmp(name, "is_external") == 0) { return is_external(L); }\n        else if (strcmp(name, "symbol") == 0) { return symbol(L); }\n        else if (strcmp(name, "literal") == 0) { return literal(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return !lua_isnil(L, -1) ? 1 : luaL_error(L, "unknown field: %s", name);\n        }\n    }\n};\n\nconstexpr const char *SymbolicAtom::typeName;\n\nluaL_Reg const SymbolicAtom::meta[] = {\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap SymbolicAtoms\n\nstruct SymbolicAtoms : Object<SymbolicAtoms> {\n    clingo_symbolic_atoms_t const *atoms;\n    static luaL_Reg const meta[];\n    static constexpr const char *typeName = "clingo.SymbolicAtoms";\n    SymbolicAtoms(clingo_symbolic_atoms_t const *atoms) : atoms(atoms) { }\n\n    static int symbolicAtomIter(lua_State *L) {\n        auto current = static_cast<SymbolicAtom *>(luaL_checkudata(L, lua_upvalueindex(1), SymbolicAtom::typeName));\n        if (call_c(L, clingo_symbolic_atoms_is_valid, current->atoms, current->iter)) {\n            lua_pushvalue(L, lua_upvalueindex(1));                                               // +1\n            auto next = call_c(L, clingo_symbolic_atoms_next, current->atoms, current->iter);\n            SymbolicAtom::new_(L, current->atoms, next);                                         // +1\n            lua_replace(L, lua_upvalueindex(1));                                                 // -1\n        }\n        else { lua_pushnil(L); }                                                                 // +1\n        return 1;\n    }\n\n    static int len(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_symbolic_atoms_size, self.atoms));\n        return 1;\n    }\n\n    static int iter(lua_State *L) {\n        auto &self = get_self(L);\n        auto range = call_c(L, clingo_symbolic_atoms_begin, self.atoms, nullptr);\n        SymbolicAtom::new_(L, self.atoms, range); // +1\n        lua_pushcclosure(L, symbolicAtomIter, 1); // +0\n        return 1;\n    }\n\n    static int lookup(lua_State *L) {\n        auto &self = get_self(L);\n        auto atom = luaToVal(L, 2);\n        auto range = call_c(L, clingo_symbolic_atoms_find, self.atoms, atom);\n        if (call_c(L, clingo_symbolic_atoms_is_valid, self.atoms, range)) {\n            SymbolicAtom::new_(L, self.atoms, range); // +1\n        }\n        else { lua_pushnil(L); } // +1\n        return 1;\n    }\n\n    static int by_signature(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        int arity = numeric_cast<int>(luaL_checkinteger(L, 3));\n        bool positive = lua_isnone(L, 4) || lua_toboolean(L, 4);\n        clingo_signature_t sig = call_c(L, clingo_signature_create, name, arity, positive);\n        auto range = call_c(L, clingo_symbolic_atoms_begin, self.atoms, &sig);\n        SymbolicAtom::new_(L, self.atoms, range); // +1\n        lua_pushcclosure(L, symbolicAtomIter, 1); // +0\n        return 1;\n    }\n\n    static int signatures(lua_State *L) {\n        auto &self = get_self(L);\n        auto size = call_c(L, clingo_symbolic_atoms_signatures_size, self.atoms);\n        clingo_signature_t *ret = static_cast<clingo_signature_t*>(lua_newuserdata(L, sizeof(*ret) * size)); // +1\n        handle_c_error(L, clingo_symbolic_atoms_signatures(self.atoms, ret, size));\n        lua_createtable(L, numeric_cast<int>(size), 0);            // +1\n        int i = 1;\n        for (auto it = ret, ie = it + size; it != ie; ++it) {\n            lua_createtable(L, 3, 0);                              // +1\n            lua_pushstring(L, clingo_signature_name(*it));         // +1\n            lua_rawseti(L, -2, 1);                                 // -1\n            lua_pushinteger(L, clingo_signature_arity(*it));       // +1\n            lua_rawseti(L, -2, 2);                                 // -1\n            lua_pushboolean(L, clingo_signature_is_positive(*it)); // +1\n            lua_rawseti(L, -2, 3);                                 // -1\n            lua_rawseti(L, -2, i);                                 // -1\n            ++i;\n        }\n        lua_replace(L, -2);                                        // -1\n        return 1;\n    }\n    static int index(lua_State *L) {\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "signatures") == 0) { return signatures(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n};\n\nconstexpr const char *SymbolicAtoms::typeName;\n\nluaL_Reg const SymbolicAtoms::meta[] = {\n    {"__len", len},\n    {"iter", iter},\n    {"lookup", lookup},\n    {"by_signature", by_signature},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap SolveControl\n\nstatic clingo_literal_t luaToAtom(lua_State *L, int idx, clingo_symbolic_atoms_t const *atoms) {\n    if (lua_isnumber(L, idx)) {\n        clingo_literal_t lit;\n        luaToCpp(L, idx, lit);\n        return lit;\n    }\n    else {\n        symbol_wrapper sym;\n        luaToCpp(L, idx, sym);\n        auto it = call_c(L, clingo_symbolic_atoms_find, atoms, sym.symbol);\n        if (call_c(L, clingo_symbolic_atoms_is_valid, atoms, it)) {\n            auto ret = call_c(L, clingo_symbolic_atoms_literal, atoms, it);\n            return ret;\n        }\n    }\n    return 0;\n}\n\n/*\nstatic clingo_literal_t luaToLit(lua_State *L, int idx, clingo_symbolic_atoms_t const *atoms, bool *positive = nullptr) {\n    if (lua_isnumber(L, idx)) {\n        clingo_literal_t lit;\n        luaToCpp(L, idx, lit);\n        if (positive) { *positive = lit > 0; }\n        return lit;\n    }\n    else {\n        symbolic_literal_t sym;\n        luaToCpp(L, idx, sym);\n        if (positive) { *positive = sym.positive; }\n        auto it = call_c(L, clingo_symbolic_atoms_find, atoms, sym.symbol);\n        if (call_c(L, clingo_symbolic_atoms_is_valid, atoms, it)) {\n            auto ret = call_c(L, clingo_symbolic_atoms_literal, atoms, it);\n            return sym.positive ? ret : -ret;\n        }\n    }\n    return 0;\n}\n*/\n\n// invert is just to turn clauses into nogoods, which was added to match the formal background in our papers\n// disjunctive determines if the literals are going to be used as a disjunction or conjunction\n// this function returns null if the literals are unnecessary, i.e., if\n//   there is a true literal in a disjunction, or\n//   there is a false literal in a conjunction\nstatic std::vector<clingo_literal_t> *luaToLits(lua_State *L, int tableIdx, clingo_symbolic_atoms_t const *atoms, bool invert, bool disjunctive) {\n    if (lua_type(L, tableIdx) != LUA_TTABLE) {\n        luaL_error(L, "table expected");\n    }\n    tableIdx = lua_absindex(L, tableIdx);\n    std::vector<clingo_literal_t> *lits = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1\n    lua_pushnil(L);                                                                        // +1\n    while (lua_next(L, tableIdx) != 0) {                                                   // +1/-1\n        if (lua_isnumber(L, -1)) {\n            clingo_literal_t lit;\n            luaToCpp(L, -1, lit);\n            if (invert) { lit = -lit; }\n            protect(L, [lits, lit]() { lits->emplace_back(lit); });\n        }\n        else {\n            symbolic_literal_t sym;\n            luaToCpp(L, -1, sym);\n            if (invert) { sym.positive = !sym.positive; }\n            auto it = call_c(L, clingo_symbolic_atoms_find, atoms, sym.symbol);\n            if (call_c(L, clingo_symbolic_atoms_is_valid, atoms, it)) {\n                clingo_literal_t lit = call_c(L, clingo_symbolic_atoms_literal, atoms, it);\n                if (!sym.positive) { lit = -lit; }\n                protect(L, [lits, lit]() { lits->emplace_back(lit); });\n            }\n            else if (sym.positive != disjunctive) {\n                lua_pop(L, 3);\n                return nullptr;\n            }\n        }\n        lua_pop(L, 1); // -1\n    }\n    return lits;\n}\n\nstruct SolveControl : Object<SolveControl> {\n    clingo_solve_control_t *ctl;\n    SolveControl(clingo_solve_control_t *ctl) : ctl(ctl) { }\n    static int getClause(lua_State *L, bool invert) {\n        auto &self = get_self(L);\n        auto atoms = call_c(L, clingo_solve_control_symbolic_atoms, self.ctl);\n        if (auto *lits = luaToLits(L, 2, atoms, invert, true)) { // +1/+0\n            handle_c_error(L, clingo_solve_control_add_clause(self.ctl, lits->data(), lits->size()));\n            lua_pop(L, 1); // -1\n        }\n        return 0;\n    }\n    static int add_clause(lua_State *L) {\n        return getClause(L, false);\n    }\n    static int add_nogood(lua_State *L) {\n        return getClause(L, true);\n    }\n    static int index(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "symbolic_atoms") == 0) { return SymbolicAtoms::new_(L, call_c(L, clingo_solve_control_symbolic_atoms, self.ctl)); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.SolveControl";\n};\n\nconstexpr char const *SolveControl::typeName;\n\nluaL_Reg const SolveControl::meta[] = {\n    {"add_clause", add_clause},\n    {"add_nogood", add_nogood},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap Model\n\nstruct ModelType : Object<ModelType> {\n    using Type = clingo_model_type_t;\n    static SolveHandle *new_(lua_State *L) {\n        lua_newtable(L);                         // +1\n        auto *self = (SolveHandle*)lua_newuserdata(L, sizeof(SolveHandle)); // +1\n        lua_rawseti(L, -2, 1);                   // -1\n        luaL_getmetatable(L, typeName);          // +1\n        lua_setmetatable(L, -2);                 // -1\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "ModelType");\n        return 0;\n    }\n        self->ass = nullptr;\n        return self;\n    }\n    static int close(lua_State *L) {\n        auto &self = get_self(L);\n        if (self.handle) {\n            auto h = self.handle;\n            self.handle = nullptr;\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.ModelType";\n};\n\nconstexpr char const *ModelType::typeName;\n\nluaL_Reg const ModelType::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\n\nstruct Model : Object<Model> {\n    clingo_model_t const *model;\n    clingo_model_t *mut_model;\n    Model(clingo_model_t *model) : model(model), mut_model{model} { }\n    Model(clingo_model_t const *model) : model(model), mut_model{nullptr} { }\n    static int contains(lua_State *L) {\n        auto &self = get_self(L);\n        clingo_symbol_t sym = luaToVal(L, 2);\n        lua_pushboolean(L, call_c(L, clingo_model_contains, self.model, sym));\n        return 1;\n    }\n    static int is_true(lua_State *L) {\n        auto &self = get_self(L);\n        clingo_literal_t lit;\n        luaToCpp(L, 2, lit);\n        lua_pushboolean(L, call_c(L, clingo_model_is_true, self.model, lit));\n        return 1;\n    }\n    static int atoms(lua_State *L) {\n        auto &self = get_self(L);\n        clingo_show_type_bitset_t atomset = 0;\n        luaL_checktype(L, 2, LUA_TTABLE);\n        lua_getfield(L, 2, "atoms");\n        if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_atoms; }\n        lua_pop(L, 1);\n        lua_getfield(L, 2, "shown");\n        if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_shown; }\n        lua_pop(L, 1);\n        lua_getfield(L, 2, "terms");\n        if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_terms; }\n        lua_pop(L, 1);\n        lua_getfield(L, 2, "theory");\n        if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_theory; }\n        lua_pop(L, 1);\n        lua_getfield(L, 2, "complement");\n        if (lua_toboolean(L, -1)) { atomset |= clingo_show_type_complement; }\n        lua_pop(L, 1);\n        auto size = call_c(L, clingo_model_symbols_size, self.model, atomset);\n        clingo_symbol_t *symbols = static_cast<clingo_symbol_t *>(lua_newuserdata(L, size * sizeof(*symbols))); // +1\n        handle_c_error(L, clingo_model_symbols(self.model, atomset, symbols, size));\n        lua_createtable(L, numeric_cast<int>(size), 0); // +1\n        int i = 1;\n        for (auto it = symbols, ie = it + size; it != ie; ++it) {\n            Term::new_(L, *it);      // +1\n            lua_rawseti(L, -2, i++); // -1\n        }\n        lua_replace(L, -2); // -1\n        return 1;\n    }\n    static int cost(lua_State *L) {\n        auto &self = get_self(L);\n        auto size = call_c(L, clingo_model_cost_size, self.model);\n        int64_t *costs = static_cast<int64_t *>(lua_newuserdata(L, size * sizeof(*costs))); // +1\n        handle_c_error(L, clingo_model_cost(self.model, costs, size));\n        lua_createtable(L, numeric_cast<int>(size), 0); // +1\n        int i = 1;\n        for (auto it = costs, ie = it + size; it != ie; ++it) {\n            lua_pushinteger(L, numeric_cast<lua_Integer>(*it)); // +1\n            lua_rawseti(L, -2, i++); // -1\n        }\n        lua_replace(L, -2); // -1\n        return 1;\n    }\n    static int thread_id(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_model_thread_id, self.model) + 1); // +1\n        return 1;\n    }\n    static int toString(lua_State *L) {\n        auto &self = get_self(L);\n        std::vector<char> *buf = AnyWrap::new_<std::vector<char>>(L); // +1\n        auto printSymbol = [buf, L](std::ostream &out, clingo_symbol_t val) {\n            auto size = call_c(L, clingo_symbol_to_string_size, val);\n            PROTECT(buf->resize(size));\n            handle_c_error(L, clingo_symbol_to_string(val, buf->data(), size));\n            PROTECT((out << buf->data(), 0));\n        };\n        auto printAtom = [L, printSymbol](std::ostream &out, clingo_symbol_t val) {\n            if (clingo_symbol_type_function == clingo_symbol_type(val)) {\n                auto name = call_c(L, clingo_symbol_name, val);\n                auto args = call_c(L, clingo_symbol_arguments, val);\n                if (args.second == 2 && strcmp(name, "$") == 0) {\n                    printSymbol(out, args.first[0]);\n                    out << "=";\n                    printSymbol(out, args.first[1]);\n                }\n                else { printSymbol(out, val); }\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.SolveHandle";\n};\n\nconstexpr char const *SolveHandle::typeName;\nluaL_Reg const SolveHandle::meta[] = {\n    {"iter",  iter},\n    {"close", close},\n    {"__gc", close},\n    {"get", get},\n    {"resume", resume},\n    {"cancel", cancel},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap Configuration\n\n        if (!self.mut_model) {\n            luaL_error(L, "models can only be extended from on_model callback");\n        }\n        handle_c_error(L, clingo_model_extend(self.mut_model, symbols->data(), symbols->size()));\n        lua_pop(L, 1);                   // -1\n        return 0;\n    }\n    static int index(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "cost") == 0) {\n            return cost(L);\n        }\n        else if (strcmp(name, "context") == 0) {\n            return context(L);\n        }\n        else if (strcmp(name, "thread_id") == 0) {\n            return thread_id(L);\n        }\n        else if (strcmp(name, "number") == 0) {\n            lua_pushinteger(L, numeric_cast<lua_Integer>(call_c(L, clingo_model_number, self.model)));\n            return 1;\n        }\n        else if (strcmp(name, "optimality_proven") == 0) {\n            lua_pushboolean(L, call_c(L, clingo_model_optimality_proven, self.model));\n            return 1;\n        }\n        else if (strcmp(name, "type") == 0) {\n            return ModelType::new_(L, call_c(L, clingo_model_type, self.model));\n        }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.Model";\n};\n\nconstexpr char const *Model::typeName;\nluaL_Reg const Model::meta[] = {\n    {"__tostring", toString},\n    {"symbols", atoms},\n    {"contains", contains},\n    {"extend", extend},\n    {"is_true", is_true},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap Statistics\n\nint newStatistics(lua_State *L, clingo_statistics_t const *stats, uint64_t key) {\n    switch (call_c(L, clingo_statistics_type, stats, key)) {\n        case clingo_statistics_type_value: {\n            lua_pushnumber(L, numeric_cast<lua_Number>(call_c(L, clingo_statistics_value_get, stats, key))); // +1\n            return 1;\n        }\n        case clingo_statistics_type_array: {\n            lua_newtable(L); // +1\n            for (size_t i = 0, e = call_c(L, clingo_statistics_array_size, stats, key); i != e; ++i) {\n                newStatistics(L, stats, call_c(L, clingo_statistics_array_at, stats, key, i)); // +1\n                lua_rawseti(L, -2, numeric_cast<int>(i+1)); // -1\n            }\n            return 1;\n        }\n        case clingo_statistics_type_map: {\n            lua_newtable(L); // +1\n            for (size_t i = 0, e = call_c(L, clingo_statistics_map_size, stats, key); i != e; ++i) {\n                auto name = call_c(L, clingo_statistics_map_subkey_name, stats, key, i);\n                lua_pushstring(L, name); // +1\n                newStatistics(L, stats, call_c(L, clingo_statistics_map_at, stats, key, name)); // +1\n                lua_rawset(L, -3); // -2\n            }\n            return 1;\n        }\n        default: {\n            return luaL_error(L, "cannot happen");\n        }\n    }\n}\n\n// {{{1 wrap SolveHandle\n\nstruct SolveHandle : Object<SolveHandle> {\n    clingo_solve_handle_t *handle;\n    clingo_solve_mode_bitset_t mode;\n    bool hasMH, hasFH;\n    clingo_control_t *ctl;\n    std::vector<clingo_literal_t> *ass;\n    SolveHandle(clingo_solve_handle_t *handle) : handle(handle) { }\n    static SolveHandle &get_self(lua_State *L, int offset=1) {\n        void *p = nullptr;\n        if (lua_istable(L, offset)) {\n            lua_rawgeti(L, offset, 1);              // +1\n            p = lua_touserdata(L, -1);\n            if (p) {\n                if (lua_getmetatable(L, offset)) {  // +1\n                    luaL_getmetatable(L, typeName); // +1\n                    if (!lua_rawequal(L, -1, -2)) { p = nullptr; }\n                    lua_pop(L, 2);                  // -2\n                }\n                else { p = nullptr; }\n            }\n            lua_pop(L, 1);                          // -1\n        }\n        if (!p) {\n            const char *msg = lua_pushfstring(L, "%s expected, got %s", typeName, luaL_typename(L, 1)); // +1\n            luaL_argerror(L, 1, msg);\n        }\n        return *static_cast<SolveHandle*>(p);\n    }\n    static SolveHandle *new_(lua_State *L) {\n        lua_newtable(L);                         // +1\n        auto *self = (SolveHandle*)lua_newuserdata(L, sizeof(SolveHandle)); // +1\n        luaL_getmetatable(L, typeNameI);         // +1\n        lua_setmetatable(L, -2);                 // +1\n        lua_rawseti(L, -2, 1);                   // -1\n        luaL_getmetatable(L, typeName);          // +1\n        lua_setmetatable(L, -2);                 // -1\n        self->handle = nullptr;\n        self->mode = 0;\n        self->hasFH = false;\n        self->hasMH = false;\n        self->ctl = nullptr;\n        self->ass = nullptr;\n        return self;\n    }\n    static void reg(lua_State *L) {\n        lua_regMeta(L, typeName, meta, index, newindex);\n        lua_regMeta(L, typeNameI, metaI, nullptr, nullptr);\n    }\n    static int gc(lua_State *L) {\n        return close_(L, *(SolveHandle*)lua_touserdata(L, 1));\n    }\n    static int close(lua_State *L) {\n        return close_(L, get_self(L));\n    }\n    static int close_(lua_State *L, SolveHandle &self) {\n        if (self.handle) {\n            auto h = self.handle;\n            self.handle = nullptr;\n            handle_c_error(L, clingo_solve_handle_close(h));\n        }\n        return 0;\n    }\n    static int next(lua_State *L) {\n        auto &handle = get_self(L, lua_upvalueindex(1));\n        call_c(L, clingo_solve_handle_resume, handle.handle);\n        clingo_model_t const *model = call_c(L, clingo_solve_handle_model, handle.handle);\n        if (model) { Model::new_(L, model); }\n        else       { lua_pushnil(L); }\n        return 1;\n    }\n    static int iter(lua_State *L) {\n        get_self(L);\n        lua_pushvalue(L,1);\n        lua_pushcclosure(L, next, 1);\n        return 1;\n    }\n    static int get(lua_State *L) {\n        auto &self = get_self(L);\n        SolveResult::new_(L, call_c(L, clingo_solve_handle_get, self.handle));\n        return 1;\n    }\n    static int resume(lua_State *L) {\n        auto &self = get_self(L);\n        call_c(L, clingo_solve_handle_resume, self.handle);\n        return 0;\n    }\n    static int cancel(lua_State *L) {\n        auto &self = get_self(L);\n        handle_c_error(L, clingo_solve_handle_cancel(self.handle));\n        return 0;\n    }\n    static int on_model_(lua_State *L) {\n        auto m = static_cast<clingo_model_t*>(lua_touserdata(L, 2));\n        auto goon = static_cast<bool*>(lua_touserdata(L, 3));\n        lua_pushstring(L, "on_model");\n        lua_rawget(L, 1);\n        Model::new_(L, m);\n        lua_call(L, 1, 1);\n        *goon = lua_isnil(L, -1) || lua_toboolean(L, -1);\n        return 0;\n    }\n    static int core(lua_State *L) {\n        auto core = call_c(L, clingo_solve_handle_core, get_self(L).handle);\n        if (core.first == nullptr) {\n            lua_pushnil(L);                       // +1\n        }\n        else {\n            cppToLua(L, core.first, core.second); // +1\n        }\n        return 1;\n    }\n    static int on_finish_(lua_State *L) {\n        lua_pushstring(L, "on_model");\n        lua_rawget(L, 1);\n        auto x = static_cast<clingo_solve_mode_bitset_t*>(lua_touserdata(L, 2));\n        SolveResult::new_(L, *x);\n        lua_call(L, 1, 0);\n        return 0;\n    }\n    static bool on_event_(clingo_solve_event_type_t type, void *event, void *data, bool *goon) {\n        auto *L = static_cast<lua_State*>(data);\n        int top = lua_gettop(L);\n        auto &handle = get_self(L, top);\n        if (!lua_checkstack(L, 5)) {\n            clingo_set_error(clingo_error_bad_alloc, "lua stack size exceeded");\n            return false;\n        }\n        switch (type) {\n            case clingo_solve_event_type_model: {\n                if (!handle.hasMH) { return true; }\n                lua_pushcfunction(L, luaTraceback); // +1\n                lua_pushcfunction(L, on_model_);    // +1\n                lua_pushvalue(L, top);              // +1\n                lua_pushlightuserdata(L, event);    // +1\n                lua_pushlightuserdata(L, goon);     // +1\n                int code = lua_pcall(L, 3, 0, -5);  // -4|-3\n                lua_remove(L, top + 1);             // -1\n                return handle_lua_error(L, "on_model", "error in model callback", code); // |-1\n            }\n            case clingo_solve_event_type_finish: {\n                if (!handle.hasFH) { return true; }\n                lua_pushcfunction(L, luaTraceback); // +1\n                lua_pushcfunction(L, on_finish_);   // +1\n                lua_pushvalue(L, top);              // +1\n                lua_pushlightuserdata(L, event);    // +1\n                int code = lua_pcall(L, 2, 0, -4);  // -3|-2\n                lua_remove(L, top + 1);             // -1\n                bool ret = handle_lua_error(L, "on_finish", "error in finish callback", code); // |-1\n                return ret;\n            }\n        }\n        return true;\n    }\n\n    static int solve_(lua_State *L) {\n        auto &handle = get_self(L);\n\n        handle.handle = call_c(L, clingo_control_solve, handle.ctl, handle.mode, handle.ass->data(), handle.ass->size(), (handle.hasFH || handle.hasMH) ? on_event_ : nullptr, L);\n        if (handle.mode == 0) {\n            lua_pushcfunction(L, get); // +1\n            lua_pushvalue(L, 1);       // +1\n            lua_call(L, 1, 1);         // -1\n            auto h = handle.handle;\n            handle.handle = nullptr;\n            call_c(L, clingo_solve_handle_close, h);\n        }\n        else {\n            lua_pushvalue(L, 1);       // +1\n        }\n\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static luaL_Reg const metaI[];\n    static constexpr char const *typeName = "clingo.SolveHandle";\n    static constexpr char const *typeNameI = "clingo._SolveHandle";\n};\n\nconstexpr char const *SolveHandle::typeName;\nconstexpr char const *SolveHandle::typeNameI;\n\nluaL_Reg const SolveHandle::meta[] = {\n    {"iter",  iter},\n    {"close", close},\n    {"get", get},\n    {"core", core},\n    {"resume", resume},\n    {"cancel", cancel},\n    {nullptr, nullptr}\n};\nluaL_Reg const SolveHandle::metaI[] = {\n    {"__gc", gc},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap Configuration\n\nstruct Configuration : Object<Configuration> {\n    clingo_configuration_t *conf;\n    clingo_id_t key;\n    Configuration(clingo_configuration_t *conf, clingo_id_t key) : conf(conf), key(key) { }\n\n    static int keys(lua_State *L) {\n        auto &self = get_self(L);\n        auto type = call_c(L, clingo_configuration_type, self.conf, self.key);\n        if (type & clingo_configuration_type_map) {\n            size_t size = call_c(L, clingo_configuration_map_size, self.conf, self.key);\n            lua_createtable(L, numeric_cast<int>(size), 0);\n            for (size_t i = 0; i < size; ++i) {\n                lua_pushstring(L, call_c(L, clingo_configuration_map_subkey_name, self.conf, self.key, i));\n                lua_rawseti(L, -2, numeric_cast<int>(i+1));\n            }\n        }\n        return 1;\n    }\n\n    bool get_subkey(lua_State *L, char const *name, clingo_id_t &subkey) {\n        if ((call_c(L, clingo_configuration_type, conf, key) & clingo_configuration_type_map) &&\n             call_c(L, clingo_configuration_map_has_subkey, conf, key, name)) {\n            subkey = call_c(L, clingo_configuration_map_at, conf, key, name);\n            return true;\n        }\n        return false;\n    }\n\n    static int description(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        clingo_id_t subkey;\n        if (self.get_subkey(L, name, subkey)) {\n            lua_pushstring(L, call_c(L, clingo_configuration_description, self.conf, subkey)); // +1\n            return 1;\n        }\n        return luaL_error(L, "unknown option: %s", name);\n    }\n    static int index(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        lua_getmetatable(L, 1);\n        lua_getfield(L, -1, name); // +1\n        if (!lua_isnil(L, -1)) { return 1; }\n        lua_pop(L, 1); // -1\n\n        if (strcmp(name, "keys") == 0) {\n            return keys(L);\n        }\n\n        bool desc = strncmp("__desc_", name, 7) == 0;\n        if (desc) { name += 7; }\n\n        clingo_id_t subkey;\n        if (self.get_subkey(L, name, subkey)) {\n            // NOTE: for backward compatibility should be removed in the future\n            if (desc) {\n                lua_pushstring(L, call_c(L, clingo_configuration_description, self.conf, subkey)); // +1\n                return 1;\n            }\n            else if (call_c(L, clingo_configuration_type, self.conf, subkey) & clingo_configuration_type_value) {\n                if (!call_c(L, clingo_configuration_value_is_assigned, self.conf, subkey)) { lua_pushnil(L); return 1; }\n                size_t size = call_c(L, clingo_configuration_value_get_size, self.conf, subkey);\n                char *ret = static_cast<char*>(lua_newuserdata(L, sizeof(*ret) * size)); // +1\n                handle_c_error(L, clingo_configuration_value_get(self.conf, subkey, ret, size));\n                lua_pushstring(L, ret); // +1\n                lua_replace(L, -2); // -1\n                return 1;\n            }\n            else { return Configuration::new_(L, self.conf, subkey); } // +1\n        }\n\n        lua_pushnil(L); // +1\n        return 1;\n    }\n\n    static int newindex(lua_State *L) {\n        auto &self = get_self(L);\n        auto *name = luaL_checkstring(L, 2);\n        auto subkey = call_c(L, clingo_configuration_map_at, self.conf, self.key, name);\n        auto value = lua_tostring(L, 3);\n        handle_c_error(L, clingo_configuration_value_set(self.conf, subkey, value));\n        return 0;\n    }\n\n    static int next(lua_State *L) {\n        auto &self = *(Configuration *)luaL_checkudata(L, lua_upvalueindex(1), typeName);\n        size_t index = luaL_checkinteger(L, lua_upvalueindex(2));\n        lua_pushinteger(L, numeric_cast<lua_Integer>(index + 1));\n        lua_replace(L, lua_upvalueindex(2));\n        size_t size = call_c(L, clingo_configuration_array_size, self.conf, self.key);\n        if (index < size) {\n            auto key = call_c(L, clingo_configuration_array_at, self.conf, self.key, index);\n            return new_(L, self.conf, key);\n        }\n        else {\n            lua_pushnil(L);\n            return 1;\n        }\n    }\n\n    static int iter(lua_State *L) {\n        luaL_checkudata(L, 1, typeName);\n        lua_pushvalue(L, 1);\n        lua_pushinteger(L, 0);\n        lua_pushcclosure(L, next, 2);\n        return 1;\n    }\n\n    static int len(lua_State *L) {\n        auto &self = get_self(L);\n        size_t n = 0;\n        if (call_c(L, clingo_configuration_type, self.conf, self.key) & clingo_configuration_type_array) {\n            n = call_c(L, clingo_configuration_array_size, self.conf, self.key);\n        }\n        lua_pushinteger(L, numeric_cast<lua_Integer>(n));\n        return 1;\n    }\n\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.Configuration";\n};\n\nconstexpr char const *Configuration::typeName;\nluaL_Reg const Configuration::meta[] = {\n    {"__len", len},\n    {"iter", iter},\n    {"description", description},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap wrap Backend\n\nstruct ExternalType : Object<ExternalType> {\n    using Type = clingo_external_type_t;\n    Type type;\n    ExternalType(Type type) : type(type) { }\n    Type cmpKey() { return type; }\n    static int addToRegistry(lua_State *L) {\n        lua_createtable(L, 0, 4);\n        for (auto t : { clingo_external_type_true, clingo_external_type_false, clingo_external_type_free, clingo_external_type_release }) {\n            Object::new_(L, t);\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "ExternalType");\n        return 0;\n    }\n    static char const *field_(Type t) {\n        switch (static_cast<clingo_external_type_e>(t)) {\n            case clingo_external_type_true:    { return "True"; }\n            case clingo_external_type_false:   { return "False"; }\n            case clingo_external_type_free:    { return "Free"; }\n            case clingo_external_type_release: { break; }\n        }\n        return "Release";\n    }\n    static int new_(lua_State *L, Type t) {\n        lua_getfield(L, LUA_REGISTRYINDEX, "clingo");\n        lua_getfield(L, -1, "ExternalType");\n        lua_replace(L, -2);\n        lua_getfield(L, -1, field_(t));\n        lua_replace(L, -2);\n        return 1;\n    }\n    static int toString(lua_State *L) {\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.ExternalType";\n};\n\nconstexpr char const *ExternalType::typeName;\n\nluaL_Reg const ExternalType::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\n\nstruct Backend : Object<Backend> {\n    clingo_backend_t *backend;\n\n    Backend(clingo_backend_t *backend) : backend(backend) { }\n\n    static constexpr const char *typeName = "clingo.Backend";\n    static luaL_Reg const meta[];\n\n    static int addAtom(lua_State *L) {\n        symbol_wrapper sym;\n        clingo_symbol_t *symp = nullptr;\n        if (!lua_isnone(L, 2) && !lua_isnil(L, 2)) {\n            luaToCpp(L, 2, sym);\n            symp = &sym.symbol;\n        }\n        lua_pushinteger(L, call_c(L, clingo_backend_add_atom, get_self(L).backend, symp));\n        return 1;\n    }\n\n    static int addRule(lua_State *L) {\n        auto &self = get_self(L);\n        auto *head = AnyWrap::new_<std::vector<clingo_atom_t>>(L);    // +1\n        auto *body = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1\n        bool choice = false;\n        luaL_checktype(L, 2, LUA_TTABLE);\n        luaPushKwArg(L, 2, 1, "head", false);                         // +1\n        luaToCpp(L, -1, *head);\n        lua_pop(L, 1);                                                // -1\n        luaPushKwArg(L, 2, 2, "body", true);                          // +1\n        if (!lua_isnil(L, -1)) { luaToCpp(L, -1, *body); }\n        lua_pop(L, 1);                                                // -1\n        luaPushKwArg(L, 2, 3, "choice", true);                        // +1\n        luaToCpp(L, -1, choice);                                      // -1\n        lua_pop(L, 1);\n        handle_c_error(L, clingo_backend_rule(self.backend, choice, head->data(), head->size(), body->data(), body->size()));\n        lua_pop(L, 2);                                                // -2\n        return 0;\n    }\n\n    static int addExternal(lua_State *L) {\n        auto &self = get_self(L);\n        clingo_atom_t atom;\n        clingo_external_type_t value = clingo_external_type_false;\n        luaToCpp(L, 2, atom);\n        if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) {\n            value = static_cast<ExternalType*>(luaL_checkudata(L, 3, ExternalType::typeName))->type;\n        }\n        handle_c_error(L, clingo_backend_external(self.backend, atom, value));\n        return 0;\n    }\n\n    static int addWeightRule(lua_State *L) {\n        auto &self = get_self(L);\n        auto *head = AnyWrap::new_<std::vector<clingo_atom_t>>(L);             // +1\n        clingo_weight_t lower;\n        auto *body = AnyWrap::new_<std::vector<clingo_weighted_literal_t>>(L); // +1\n        bool choice = false;\n        luaL_checktype(L, 2, LUA_TTABLE);\n        luaPushKwArg(L, 2, 1, "head", false);                                  // +1\n        luaToCpp(L, -1, *head);\n        lua_pop(L, 1);                                                         // -1\n        luaPushKwArg(L, 2, 2, "lower", false);                                 // +1\n        luaToCpp(L, -1, lower);\n        lua_pop(L, 1);                                                         // -1\n        luaPushKwArg(L, 2, 3, "body", false);                                  // +1\n        luaToCpp(L, -1, *body);\n        lua_pop(L, 1);                                                         // -1\n        luaPushKwArg(L, 2, 4, "choice", true);                                 // +1\n        luaToCpp(L, -1, choice);\n        lua_pop(L, 1);                                                         // -1\n        handle_c_error(L, clingo_backend_weight_rule(self.backend, choice, head->data(), head->size(), lower, body->data(), body->size()));\n        lua_pop(L, 2);                                                         // -2\n        return 0;\n    }\n\n    static int addMinimize(lua_State *L) {\n        auto &self = get_self(L);\n        clingo_weight_t priority;\n        auto *body = AnyWrap::new_<std::vector<clingo_weighted_literal_t>>(L); // +1\n        luaL_checktype(L, 2, LUA_TTABLE);\n        luaPushKwArg(L, 2, 1, "priority", false);                              // +1\n        luaToCpp(L, -1, priority);\n        lua_pop(L, 1);                                                         // -1\n        luaPushKwArg(L, 2, 2, "body", false);                                  // +1\n        luaToCpp(L, -1, *body);\n        lua_pop(L, 1);                                                         // -1\n        handle_c_error(L, clingo_backend_minimize(self.backend, priority, body->data(), body->size()));\n        lua_pop(L, 1);                                                         // -1\n        return 0;\n    }\n\n    static int close(lua_State *L) {\n        auto &self = get_self(L);\n        handle_c_error(L, clingo_backend_end(self.backend));\n        return 0;\n    }\n};\n\nluaL_Reg const Backend::meta[] = {\n    {"add_atom", addAtom},\n    {"add_rule", addRule},\n    {"add_external", addExternal},\n    {"add_weight_rule", addWeightRule},\n    {"add_minimize", addMinimize},\n    {"close", close},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap Trail\n\nstruct Trail : Object<Trail> {\n    clingo_assignment_t const *ass;\n    Trail(clingo_assignment_t const *ass) : ass(ass) { }\n\n    int32_t size_(lua_State *L) {\n        return call_c(L, clingo_assignment_trail_size, ass);\n    }\n\n    clingo_literal_t at_(lua_State *L, uint32_t idx) {\n        return call_c(L, clingo_assignment_trail_at, ass, idx);\n    }\n\n    static int size(lua_State *L) {\n        lua_pushnumber(L, get_self(L).size_(L));\n        return 1;\n    }\n\n    static int begin(lua_State *L) {\n        auto &self = get_self(L);\n        auto level = numeric_cast<uint32_t>(luaL_checkinteger(L, 2));\n        lua_pushnumber(L, call_c(L, clingo_assignment_trail_begin, self.ass, level) + 1);\n        return 1;\n    }\n\n    static int end(lua_State *L) {\n        auto &self = get_self(L);\n        auto level = numeric_cast<uint32_t>(luaL_checkinteger(L, 2));\n        lua_pushnumber(L, call_c(L, clingo_assignment_trail_end, self.ass, level));\n        return 1;\n    }\n\n    static int pairs_iter_(lua_State *L) {\n        auto &self = get_self(L);\n        auto idx = numeric_cast<int32_t>(luaL_checkinteger(L, 2));\n        if (idx < self.size_(L)) {\n            lua_pushinteger(L, idx + 1);\n            lua_pushnumber(L, self.at_(L, idx));\n            return 2;\n        }\n        return 0;\n    }\n\n    static int iter_(lua_State *L) {\n        auto &self = *static_cast<Trail *>(luaL_checkudata(L, lua_upvalueindex(1), typeName));\n        auto idx = numeric_cast<int32_t>(lua_tointeger(L, lua_upvalueindex(2)));\n        if (idx < self.size_(L)) {\n            lua_pushinteger(L, idx + 1);\n            lua_replace(L, lua_upvalueindex(2));\n            lua_pushnumber(L, self.at_(L, idx));\n            return 1;\n        }\n        return 0;\n    }\n\n    static int iter(lua_State *L) {\n        lua_pushvalue(L, 1);\n        lua_pushinteger(L, 0);\n        lua_pushcclosure(L, iter_, 2);\n        return 1;\n    }\n\n    static int pairs(lua_State *L) {\n        lua_pushcfunction(L, pairs_iter_);\n        lua_pushvalue(L, 1);\n        lua_pushinteger(L, 0);\n        return 3;\n    }\n\n    static int at(lua_State *L) {\n        auto &self = get_self(L);\n        auto index = numeric_cast<int32_t>(luaL_checkinteger(L, 2)) - 1;\n        if (index < self.size_(L)) {\n            lua_pushnumber(L, self.at_(L, index));\n            return 1;\n        }\n        return 0;\n    }\n\n    static int index(lua_State *L) {\n        if (lua_isnumber(L, 2)) { return at(L); }\n        char const *name = luaL_checkstring(L, 2);\n        lua_getmetatable(L, 1);\n        lua_getfield(L, -1, name);\n        return 1;\n    }\n\n    static constexpr char const *typeName = "clingo.Trail";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *Trail::typeName;\nluaL_Reg const Trail::meta[] = {\n    {"iter", iter},\n    {"first", begin},\n    {"last", end},\n    {"__len", size},\n    {"__pairs", pairs},\n    {"__ipairs", pairs},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap Assignment\n\nstruct Assignment : Object<Assignment> {\n    clingo_assignment_t const *ass;\n    Assignment(clingo_assignment_t const *ass) : ass(ass) { }\n\n    static int hasConflict(lua_State *L) {\n        lua_pushboolean(L, clingo_assignment_has_conflict(get_self(L).ass));\n        return 1;\n    }\n\n    static int decisionLevel(lua_State *L) {\n        lua_pushinteger(L, clingo_assignment_decision_level(get_self(L).ass));\n        return 1;\n    }\n\n    static int rootLevel(lua_State *L) {\n        lua_pushinteger(L, clingo_assignment_root_level(get_self(L).ass));\n        return 1;\n    }\n\n    static int hasLit(lua_State *L) {\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushboolean(L, clingo_assignment_has_literal(get_self(L).ass, lit));\n        return 1;\n    }\n\n    static int level(lua_State *L) {\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushinteger(L, call_c(L, clingo_assignment_level, get_self(L).ass, lit));\n        return 1;\n    }\n\n    static int decision(lua_State *L) {\n        auto level = numeric_cast<uint32_t>(luaL_checkinteger(L, 2));\n        lua_pushinteger(L, call_c(L, clingo_assignment_decision, get_self(L).ass, level));\n        return 1;\n    }\n\n    static int isFixed(lua_State *L) {\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushboolean(L, call_c(L, clingo_assignment_is_fixed, get_self(L).ass, lit));\n        return 1;\n    }\n\n    static int isTrue(lua_State *L) {\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushboolean(L, call_c(L, clingo_assignment_is_true, get_self(L).ass, lit));\n        return 1;\n    }\n\n    static int value(lua_State *L) {\n        auto &self = get_self(L);\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        auto val = call_c(L, clingo_assignment_truth_value, self.ass, lit);\n        if (val == clingo_truth_value_free) { lua_pushnil(L); }\n        else { lua_pushboolean(L, val == clingo_truth_value_true); }\n        return 1;\n    }\n\n    static int isFalse(lua_State *L) {\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushboolean(L, call_c(L, clingo_assignment_is_false, get_self(L).ass, lit));\n        return 1;\n    }\n\n    static int size(lua_State *L) {\n        lua_pushnumber(L, clingo_assignment_size(get_self(L).ass));\n        return 1;\n    }\n\n    static int isTotal(lua_State *L) {\n        lua_pushboolean(L, clingo_assignment_is_total(get_self(L).ass));\n        return 1;\n    }\n\n    int32_t size_() {\n        return clingo_assignment_size(ass);\n    }\n\n    clingo_literal_t at_(lua_State *L, size_t idx) {\n        return call_c(L, clingo_assignment_at, ass, idx);\n    }\n\n    static int pairs_iter_(lua_State *L) {\n        auto &self = get_self(L);\n        auto idx = numeric_cast<std::make_signed<size_t>::type>(luaL_checkinteger(L, 2));\n        if (0 <= idx && idx < self.size_()) {\n            lua_pushinteger(L, idx + 1);\n            lua_pushnumber(L, self.at_(L, idx));\n            return 2;\n        }\n        return 0;\n    }\n\n    static int iter_(lua_State *L) {\n        auto &self = *static_cast<Assignment*>(luaL_checkudata(L, lua_upvalueindex(1), typeName));\n        auto idx = numeric_cast<std::make_signed<size_t>::type>(lua_tointeger(L, lua_upvalueindex(2)));\n        if (0 <= idx && idx < self.size_()) {\n            lua_pushinteger(L, idx + 1);\n            lua_replace(L, lua_upvalueindex(2));\n            lua_pushnumber(L, self.at_(L, idx));\n            return 1;\n        }\n        return 0;\n    }\n\n    static int iter(lua_State *L) {\n        lua_pushvalue(L, 1);\n        lua_pushinteger(L, 0);\n        lua_pushcclosure(L, iter_, 2);\n        return 1;\n    }\n\n    static int pairs(lua_State *L) {\n        lua_pushcfunction(L, pairs_iter_);\n        lua_pushvalue(L, 1);\n        lua_pushinteger(L, 0);\n        return 3;\n    }\n\n    static int at(lua_State *L) {\n        auto idx = numeric_cast<std::make_signed<size_t>::type>(luaL_checkinteger(L, 2)) - 1;\n        auto &self = get_self(L);\n        if (0 <= idx && idx < self.size_()) {\n            lua_pushnumber(L, self.at_(L, idx));\n            return 1;\n        }\n        return 0;\n    }\n\n    static int trail(lua_State *L) {\n        return Trail::new_(L, get_self(L).ass);\n    }\n\n    static int index(lua_State *L) {\n        if (lua_isnumber(L, 2)) { return at(L); }\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "trail")          == 0) { return trail(L); }\n        if (strcmp(name, "is_total")       == 0) { return isTotal(L); }\n        if (strcmp(name, "has_conflict")   == 0) { return hasConflict(L); }\n        if (strcmp(name, "decision_level") == 0) { return decisionLevel(L); }\n        if (strcmp(name, "root_level")     == 0) { return rootLevel(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n\n    static constexpr char const *typeName = "clingo.Assignment";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *Assignment::typeName;\nluaL_Reg const Assignment::meta[] = {\n    {"has_lit", hasLit},\n    {"value", value},\n    {"level", level},\n    {"is_fixed", isFixed},\n    {"is_true", isTrue},\n    {"is_false", isFalse},\n    {"decision", decision},\n    {"iter", iter},\n    {"__len", size},\n    {"__pairs", pairs},\n    {"__ipairs", pairs},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap PropagateInit\n\nstruct PropagatorCheckMode : Object<PropagatorCheckMode> {\n    clingo_propagator_check_mode_e type;\n    PropagatorCheckMode(clingo_propagator_check_mode_e type) : type(type) { }\n    clingo_propagator_check_mode_e cmpKey() { return type; }\n    static int addToRegistry(lua_State *L) {\n        lua_createtable(L, 0, 4);\n        for (auto t : {clingo_propagator_check_mode_none, clingo_propagator_check_mode_total, clingo_propagator_check_mode_fixpoint, clingo_propagator_check_mode_both}) {\n            new_(L, t);\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "PropagatorCheckMode");\n        return 0;\n    }\n    static char const *field_(clingo_propagator_check_mode_e type) {\n        switch (type) {\n            case clingo_propagator_check_mode_none:     { return "Off"; }\n            case clingo_propagator_check_mode_total:    { return "Total"; }\n            case clingo_propagator_check_mode_fixpoint: { return "Fixpoint"; }\n            case clingo_propagator_check_mode_both:     { return "Both"; }\n        }\n        return "";\n    }\n\n    static int toString(lua_State *L) {\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.PropagatorCheckMode";\n};\n\nconstexpr char const *PropagatorCheckMode::typeName;\n\nluaL_Reg const PropagatorCheckMode::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\n\nstruct PropagateInit : Object<PropagateInit> {\n    lua_State *T;\n    clingo_propagate_init_t *init;\n    PropagateInit(lua_State *T, clingo_propagate_init_t *init) : T(T), init(init) { }\n\n    static int mapLit(lua_State *L) {\n        auto &self = get_self(L);\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushinteger(L, call_c(L, clingo_propagate_init_solver_literal, self.init, lit));\n        return 1;\n    }\n\n    static int numThreads(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, clingo_propagate_init_number_of_threads(self.init));\n        return 1;\n    }\n    static int addWatch(lua_State *L) {\n        auto &self = get_self(L);\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        if (lua_isnone(L, 3) || lua_isnil(L, 3)) {\n            handle_c_error(L, clingo_propagate_init_add_watch(self.init, lit));\n        }\n        else {\n            auto thread_id = numeric_cast<uint32_t>(luaL_checkinteger(L, 3));\n            handle_c_error(L, clingo_propagate_init_add_watch_to_thread(self.init, lit, thread_id-1));\n        }\n        return 0;\n    }\n\n    static int addLiteral(lua_State *L) {\n        auto &self = get_self(L);\n        bool freeze = lua_isnoneornil(L, 1) || lua_toboolean(L, 1);\n        lua_pushinteger(L, call_c(L, clingo_propagate_init_add_literal, self.init, freeze));\n        return 1;\n    }\n\n    static int addClause(lua_State *L) {\n        auto &self = get_self(L);\n        auto lits = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1\n        luaL_checktype(L, 2, LUA_TTABLE);\n        luaToCpp(L, 2, *lits);\n        lua_pushboolean(L, call_c(L, clingo_propagate_init_add_clause, self.init, lits->data(), lits->size()));\n        lua_replace(L, -2);                                          // -1\n        return 1;\n    }\n\n    static int addWeightConstraint(lua_State *L) {\n        auto &self = get_self(L);\n        luaL_checknumber(L, 2);\n        luaL_checktype(L, 3, LUA_TTABLE);\n        luaL_checknumber(L, 4);\n        clingo_weight_constraint_type_t type = clingo_weight_constraint_type_equivalence;\n        if (!lua_isnone(L, 5)) { type = luaL_checknumber(L, 5); }\n        bool eq{!lua_isnone(L, 6) && lua_toboolean(L, 6)};\n        clingo_literal_t lit;\n        clingo_weight_t bound;\n        auto lits = AnyWrap::new_<std::vector<clingo_weighted_literal_t>>(L);\n                                    // +1\n        luaToCpp(L, 2, lit);\n        luaToCpp(L, 3, *lits);\n        luaToCpp(L, 4, bound);\n        lua_pushboolean(L, call_c(L, clingo_propagate_init_add_weight_constraint, self.init, lit, lits->data(), lits->size(), bound, type, eq));\n                                    // +1\n        lua_replace(L, -2);         // -1\n        return 1;\n    }\n\n    static int addMinimize(lua_State *L) {\n        auto &self = get_self(L);\n        luaL_checknumber(L, 2);\n        luaL_checknumber(L, 3);\n        clingo_literal_t lit;\n        clingo_weight_t weight;\n        clingo_weight_t priority{0};\n        luaToCpp(L, 2, lit);\n        luaToCpp(L, 3, weight);\n        if (!lua_isnone(L, 4)) {\n            luaL_checknumber(L, 4);\n            luaToCpp(L, 4, priority);\n        }\n        call_c(L, clingo_propagate_init_add_minimize, self.init, lit, weight, priority);\n        return 0;\n    }\n\n    static int propagate(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushboolean(L, call_c(L, clingo_propagate_init_propagate, self.init));\n        return 1;\n    }\n\n    static int getCheckMode(lua_State *L) {\n        PropagatorCheckMode::new_(L, static_cast<clingo_propagator_check_mode_e>(clingo_propagate_init_get_check_mode(get_self(L).init)));\n        return 1;\n    }\n\n    static int setCheckMode(lua_State *L) {\n        auto init = get_self(L).init;\n        auto mode = static_cast<PropagatorCheckMode*>(luaL_checkudata(L, 3, PropagatorCheckMode::typeName));\n        clingo_propagate_init_set_check_mode(init, mode->type);\n        return 1;\n    }\n\n    static int assignment(lua_State *L) {\n        auto &self = get_self(L);\n        Assignment::new_(L, clingo_propagate_init_assignment(self.init));\n        return 1;\n    }\n\n    static int index(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "theory_atoms")               == 0) { return TheoryIter::iter(L, call_c(L, clingo_propagate_init_theory_atoms, self.init)); }\n        else if (strcmp(name, "symbolic_atoms")        == 0) { return SymbolicAtoms::new_(L, call_c(L, clingo_propagate_init_symbolic_atoms, self.init)); }\n        else if (strcmp(name, "number_of_threads")     == 0) { return numThreads(L); }\n        else if (strcmp(name, "check_mode")            == 0) { return getCheckMode(L); }\n        else if (strcmp(name, "assignment")            == 0) { return assignment(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n\n    static int newindex(lua_State *L) {\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "check_mode")   == 0) { return setCheckMode(L); }\n        return luaL_error(L, "unknown field: %s", name);\n    }\n\n    static int setState(lua_State *L) {\n        auto &self = get_self(L);\n        auto id = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        luaL_checkany(L, 3);\n        if (id < 1 || id > (int)clingo_propagate_init_number_of_threads(self.init)) {\n            luaL_error(L, "invalid solver thread id %d", id);\n        }\n        lua_xmove(L, self.T, 1);\n        lua_rawseti(self.T, 2, id);\n        return 0;\n    }\n\n    static constexpr char const *typeName = "clingo.PropagateInit";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *PropagateInit::typeName;\nluaL_Reg const PropagateInit::meta[] = {\n    {"solver_literal", mapLit},\n    {"add_watch", addWatch},\n    {"add_literal", addLiteral},\n    {"add_clause", addClause},\n    {"add_weight_constraint", addWeightConstraint},\n    {"add_minimize", addMinimize},\n    {"propagate", propagate},\n    {"set_state", setState},\n    {nullptr, nullptr}\n};\n\n// {{{1 wrap PropagateControl\n\nstruct PropagateControl : Object<PropagateControl> {\n    clingo_propagate_control_t* ctl;\n    PropagateControl(clingo_propagate_control_t* ctl) : ctl(ctl) { }\n\n    static int id(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, numeric_cast<lua_Integer>(clingo_propagate_control_thread_id(self.ctl)) + 1);\n        return 1;\n    }\n\n    static int assignment(lua_State *L) {\n        auto &self = get_self(L);\n        Assignment::new_(L, clingo_propagate_control_assignment(self.ctl));\n        return 1;\n    }\n\n    static int addClauseOrNogood(lua_State *L, bool invert) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, 1);                                       // +1\n        lua_gettable(L, 2);                                          // +0\n        luaL_checktype(L, -1, LUA_TTABLE);                           // +0\n        int lits_index = lua_gettop(L);\n        auto lits = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1\n        lua_pushnil(L);                                              // +1\n        while (lua_next(L, -3)) {                                    // -1\n            auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, -1)); // +0\n            PROTECT(lits->emplace_back(lit));\n            lua_pop(L, 1);\n        }\n        clingo_clause_type_t type = 0;\n        lua_getfield(L, 2, "tag");                                   // +1\n        if (lua_toboolean(L, -1)) {\n            type |= clingo_clause_type_volatile;\n        }\n        lua_pop(L, 1);                                               // -1\n        lua_getfield(L, 2, "lock");                                  // +1\n        if (lua_toboolean(L, -1)) {\n            type |= clingo_clause_type_static;\n        }\n        lua_pop(L, 1);                                               // -1\n        if (invert) {\n            for (auto &lit : *lits) { lit = -lit; }\n        }\n        lua_pushboolean(L, call_c(L, clingo_propagate_control_add_clause, self.ctl, lits->data(), lits->size(), type)); // +1\n        lua_replace(L, lits_index);\n        lua_settop(L, lits_index);\n        return 1;\n    }\n\n    static int addLiteral(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushinteger(L, call_c(L, clingo_propagate_control_add_literal, self.ctl));\n        return 1;\n    }\n\n    static int addWatch(lua_State *L) {\n        auto &self = get_self(L);\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        handle_c_error(L, clingo_propagate_control_add_watch(self.ctl, lit));\n        return 0;\n    }\n\n    static int removeWatch(lua_State *L) {\n        auto &self = get_self(L);\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        clingo_propagate_control_remove_watch(self.ctl, lit);\n        return 0;\n    }\n\n    static int hasWatch(lua_State *L) {\n        auto &self = get_self(L);\n        auto lit = numeric_cast<clingo_literal_t>(luaL_checkinteger(L, 2));\n        lua_pushboolean(L, clingo_propagate_control_has_watch(self.ctl, lit));\n        return 1;\n    }\n\n    static int addClause(lua_State *L) {\n        return addClauseOrNogood(L, false);\n    }\n\n    static int addNogood(lua_State *L) {\n        return addClauseOrNogood(L, true);\n    }\n\n    static int propagate(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushboolean(L, call_c(L, clingo_propagate_control_propagate, self.ctl)); // +1\n        return 1;\n    }\n\n    static int index(lua_State *L) {\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "thread_id") == 0) { return id(L); }\n        if (strcmp(name, "assignment") == 0) { return assignment(L); }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n\n    static constexpr char const *typeName = "clingo.PropagateControl";\n    static luaL_Reg const meta[];\n};\n\nconstexpr char const *PropagateControl::typeName;\nluaL_Reg const PropagateControl::meta[] = {\n    {"add_literal", addLiteral},\n    {"add_watch", addWatch},\n    {"has_watch", hasWatch},\n    {"remove_watch", removeWatch},\n    {"add_clause", addClause},\n    {"add_nogood", addNogood},\n    {"propagate", propagate},\n    {nullptr, nullptr}\n};\n\n// }}}\n// {{{1 wrap Propagator\n\nclass Propagator {\npublic:\n    enum Indices : int { PropagatorIndex=1, StateIndex=2, ThreadIndex=3 };\n    Propagator(lua_State *L, lua_State *T) : L(L), T(T) { }\n    static int init_(lua_State *L) {\n        auto *self = static_cast<Propagator*>(lua_touserdata(L, 1));\n        auto *init = static_cast<clingo_propagate_init_t*>(lua_touserdata(L, 2));\n        PROTECT(self->threads.reserve(clingo_propagate_init_number_of_threads(init)));\n        while (self->threads.size() < static_cast<size_t>(clingo_propagate_init_number_of_threads(init))) {\n            self->threads.emplace_back(lua_newthread(L));\n            lua_xmove(L, self->T, 1);\n            lua_rawseti(self->T, ThreadIndex, numeric_cast<int>(self->threads.size()));\n        }\n        lua_pushvalue(self->T, PropagatorIndex);         // +1\n\n        if (handle->mode & clingo_solve_mode_async) { return luaL_error(L, "asynchronous solving not supported"); }\n\n        lua_settop(L, handleIdx);\n\n        if (!lua_checkstack(L, 3)) { luaL_error(L, "lua stack size exceeded"); }\n        lua_pushcfunction(L, luaTraceback);        // +1\n        lua_pushcfunction(L, SolveHandle::solve_); // +1\n        lua_pushvalue(L, handleIdx);               // +1\n        int code = lua_pcall(L, 1, 1, -3);         // -1\n        lua_replace(L, -2);                        // -1\n        if (code) {\n            auto h = handle->handle;\n            handle->handle = NULL;\n            call_c(L, clingo_solve_handle_close, h);\n        }\n        lua_replace(L, -2);                        // -1\n        if (code) { lua_error(L); }\n        return 1;\n    }\n    static int assign_external(lua_State *L) {\n        auto ret = lua_pcall(self->L, 2, 0, err); // -3\n        lua_remove(self->L, err);                 // -1\n        return handle_lua_error(self->L, "Propagator::init", "initializing the propagator failed", ret);\n    }\n    static int getChanges(lua_State *L, clingo_literal_t const *changes, size_t size) {\n        lua_newtable(L);\n        for (size_t i = 0; i < size; ++i) {\n            lua_pushinteger(L, *(changes + i));\n            lua_rawseti(L, -2, numeric_cast<int>(i+1));\n        }\n        return 1;\n    }\n    static int getState(lua_State *L, lua_State *T, clingo_id_t id) {\n        lua_rawgeti(T, StateIndex, id+1);\n        lua_xmove(T, L, 1);\n        return 1;\n    }\n    static int propagate_(lua_State *L) {\n        auto *self = static_cast<Propagator*>(lua_touserdata(L, 1));\n        auto *control = static_cast<clingo_propagate_control_t *>(lua_touserdata(L, 2));\n        auto *changes = static_cast<clingo_literal_t const *>(lua_touserdata(L, 3));\n        auto size = lua_tointeger(L, 4);\n        lua_pushvalue(self->T, PropagatorIndex);         // +1\n        lua_xmove(self->T, L, 1);                        // +0\n        lua_getfield(L, -1, "propagate");                // +1\n        if (!lua_isnil(L, -1)) {\n            lua_insert(L, -2);\n            PropagateControl::new_(L, control);          // +1\n            getChanges(L, changes, size);                // +1\n            getState(L, self->T, clingo_propagate_control_thread_id(control)); // +1\n            lua_call(L, 4, 0);                           // -5\n        }\n        else {\n            lua_pop(L, 2);                               // -2\n        }\n        return 0;\n    }\n    static bool propagate(clingo_propagate_control_t *control, clingo_literal_t const *changes, size_t size, void *data) {\n        auto *self = static_cast<Propagator*>(data);\n        lua_State *L = self->threads[clingo_propagate_control_thread_id(control)];\n        if (!lua_checkstack(L, 6)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear ll(self->T), lt(L);\n        lua_pushcfunction(L, luaTraceback);\n        lua_pushcfunction(L, propagate_);\n        lua_pushlightuserdata(L, self);\n        lua_pushlightuserdata(L, control);\n        lua_pushlightuserdata(L, const_cast<clingo_literal_t *>(changes));\n        lua_pushinteger(L, size);\n        auto ret = lua_pcall(L, 4, 0, -6);\n        return handle_lua_error(L, "Propagator::propagate", "propagate failed", ret);\n    }\n    static int undo_(lua_State *L) {\n        auto *self = static_cast<Propagator*>(lua_touserdata(L, 1));\n        auto *control = static_cast<clingo_propagate_control_t*>(lua_touserdata(L, 2));\n        auto *changes = static_cast<clingo_literal_t const *>(lua_touserdata(L, 3));\n        auto size = lua_tointeger(L, 4);\n        lua_pushvalue(self->T, PropagatorIndex);         // +1\n        lua_xmove(self->T, L, 1);                        // +0\n        lua_getfield(L, -1, "undo");                     // +1\n        if (!lua_isnil(L, -1)) {\n            auto id = clingo_propagate_control_thread_id(control);\n            lua_insert(L, -2);\n            lua_pushinteger(L, id + 1);                  // +1\n            Assignment::new_(L, clingo_propagate_control_assignment(control));  // +1\n            getChanges(L, changes, size);                // +1\n            getState(L, self->T, id);                    // +1\n            lua_call(L, 5, 0);                           // -6\n        }\n        else {\n            lua_pop(L, 2);                               // -2\n        }\n        return 0;\n    }\n    static void undo(clingo_propagate_control_t const *control, clingo_literal_t const *changes, size_t size, void *data) {\n        auto *self = static_cast<Propagator*>(data);\n        lua_State *L = self->threads[clingo_propagate_control_thread_id(control)];\n        if (!lua_checkstack(L, 6)) {\n            std::cerr << "propagator: error in undo going to abort:\\n" << "lua stack size exceeded" << std::endl;\n            std::abort();\n        }\n    }\n    template <class F>\n    static int new_(lua_State *L, F f) {\n        lua_newtable(L);                                                           // +1\n        auto self = (ControlWrap*)lua_newuserdata(L, sizeof(ControlWrap)); // +1\n        lua_rawseti(L, -2, 1);                                                     // -1\n        protect(L, [self, f]() { f(self); });\n        luaL_getmetatable(L, typeName);                                            // +1\n        lua_setmetatable(L, -2);                                                   // -1\n        return 1;\n    }\n    static int gc(lua_State *L) {\n        auto &self = get_self(L);\n        if (self.free) { clingo_control_free(self.ctl); }\n        self.~ControlWrap();\n        return 0;\n            lua_call(L, 3, 0);                           // -4\n        }\n        else {\n            lua_pop(L, 2);                               // -2\n        }\n        return 0;\n    }\n    static bool check(clingo_propagate_control_t *control, void *data) {\n        auto *self = static_cast<Propagator*>(data);\n        lua_State *L = self->threads[clingo_propagate_control_thread_id(control)];\n        if (!lua_checkstack(L, 4)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear ll(self->T), lt(L);\n        lua_pushcfunction(L, luaTraceback);\n        lua_pushcfunction(L, check_);\n        lua_pushlightuserdata(L, self);\n        lua_pushlightuserdata(L, control);\n        auto ret = lua_pcall(L, 2, 0, -4);\n        return handle_lua_error(L, "Propagator::check", "check failed", ret);\n    }\n    static int decide_(lua_State *L) {\n        auto *self = static_cast<Propagator*>(lua_touserdata(L, 1));\n        auto thread_id = lua_tointeger(L, 2);\n        auto *assignment = static_cast<clingo_assignment_t const *>(lua_touserdata(L, 3));\n        auto *decision = static_cast<clingo_literal_t *>(lua_touserdata(L, 5));\n        lua_pushvalue(self->T, PropagatorIndex); // +1\n        lua_xmove(self->T, L, 1);                // +0\n        lua_getfield(L, -1, "decide");           // +1\n        if (!lua_isnil(L, -1)) {\n            lua_insert(L, -2);\n            lua_pushinteger(L, thread_id+1);     // +1\n            Assignment::new_(L, assignment);     // +1\n            lua_pushvalue(L, 4);                 // +1\n            getState(L, self->T, thread_id);     // +1\n            lua_call(L, 5, 1);                   // -5\n            *decision = lua_tointeger(L, -1);\n            lua_pop(L, 1);                       // +1\n        }\n        else {\n            lua_pop(L, 2);                       // -2\n        }\n        return 0;\n    }\n    static bool decide(clingo_id_t thread_id, clingo_assignment_t const *assignment, clingo_literal_t fallback, void *data, clingo_literal_t *decision) {\n        auto *self = static_cast<Propagator*>(data);\n        lua_State *L = self->threads[thread_id];\n        if (!lua_checkstack(L, 7)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear ll(self->T), lt(L);\n        lua_pushcfunction(L, luaTraceback);\n        lua_pushcfunction(L, decide_);\n        lua_pushlightuserdata(L, self); // 1\n        lua_pushnumber(L, thread_id);   // 2\n        lua_pushlightuserdata(L, const_cast<clingo_assignment_t*>(assignment)); // 3\n        lua_pushnumber(L, fallback); // 4\n        lua_pushlightuserdata(L, decision); //5\n        auto ret = lua_pcall(L, 5, 0, -7);\n        return handle_lua_error(L, "Propagator::decide", "decide failed", ret);\n    }\n\n    virtual ~Propagator() noexcept = default;\nprivate:\n    lua_State *L;\n    // global data for the executions stacks below\n    // (something similar could be achieved using the registry index + luaL_(un)ref)\n    lua_State *T;\n    // execution threads for progagators (executed in lock step)\n    std::vector<lua_State *> threads;\n};\n\n    }\n\n    static luaL_Reg meta[];\n    static constexpr char const *typeName = "clingo.Control";\n};\n\nconstexpr char const *ControlWrap::typeName;\n        lua_createtable(L, 0, 6);\n        for (auto t : { clingo_heuristic_type_level, clingo_heuristic_type_sign, clingo_heuristic_type_factor, clingo_heuristic_type_init, clingo_heuristic_type_true, clingo_heuristic_type_false }) {\n            Object::new_(L, t);\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "HeuristicType");\n        return 0;\n    }\n    static char const *field_(Type t) {\n    {"interrupt", interrupt},\n    {"register_propagator", registerPropagator},\n    {"register_observer", registerObserver},\n    {"__gc", gc},\n    {nullptr, nullptr}\n};\n    }\n    static int new_(lua_State *L, Type t) {\n        lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); // +1\n        lua_getfield(L, -1, "HeuristicType");         // +1\n        lua_replace(L, -2);                           // -1\n        lua_getfield(L, -1, field_(t));               // +1\n        lua_replace(L, -2);                           // -1\n        return 1;\n    }\n    static int toString(lua_State *L) {\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.HeuristicType";\n};\n\nluaL_Reg const HeuristicType::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\nconstexpr char const *HeuristicType::typeName;\n\nclass GroundProgramObserver {\npublic:\n    GroundProgramObserver(lua_State *L, lua_State *T) : L(L), T(T) { }\n\n#   define S(fun) fun, "GroundProgramObserver::" fun, "calling " fun " failed"\n    static bool init_program(bool incremental, void *data) {\n        return call(data, S("init_program"), incremental);\n    }\n    static bool begin_step(void *data) {\n        return call(data, S("begin_step"));\n    }\n    static bool end_step(void *data) {\n        return call(data, S("end_step"));\n    }\n\n    static bool rule(bool choice, clingo_atom_t const *head, size_t head_size, clingo_literal_t const *body, size_t body_size, void *data) {\n        return call(data, S("rule"), choice, range(head, head_size), range(body, body_size));\n    }\n    static bool weight_rule(bool choice, clingo_atom_t const *head, size_t head_size, clingo_weight_t lower_bound, clingo_weighted_literal_t const *body, size_t body_size, void *data) {\n        return call(data, S("weight_rule"), choice, range(head, head_size), lower_bound, range(body, body_size));\n    }\n    static bool minimize(clingo_weight_t priority, clingo_weighted_literal_t const* literals, size_t size, void *data) {\n        return call(data, S("minimize"), priority, range(literals, size));\n    }\n    static bool project(clingo_atom_t const *atoms, size_t size, void *data) {\n        return call(data, S("project"), range(atoms, size));\n    }\n    static bool output_atom(clingo_symbol_t symbol, clingo_atom_t atom, void *data) {\n        return call(data, S("output_atom"), symbol_wrapper{symbol}, atom);\n    }\n    static bool output_term(clingo_symbol_t symbol, clingo_literal_t const *condition, size_t size, void *data) {\n        return call(data, S("output_term"), symbol_wrapper{symbol}, range(condition, size));\n    }\n    static bool external(clingo_atom_t atom, clingo_external_type_t type, void *data) {\n        return call(data, S("external"), atom, static_cast<clingo_external_type_e>(type));\n    }\n    static bool assume(clingo_literal_t const *literals, size_t size, void *data) {\n        return call(data, S("assume"), range(literals, size));\n    }\n    static bool heuristic(clingo_atom_t atom, clingo_heuristic_type_t type, int bias, unsigned priority, clingo_literal_t const *condition, size_t size, void *data) {\n        return call(data, S("heuristic"), atom, static_cast<clingo_heuristic_type_e>(type), bias, priority, range(condition, size));\n    }\n    static bool acyc_edge(int node_u, int node_v, clingo_literal_t const *condition, size_t size, void *data) {\n        return call(data, S("acyc_edge"), node_u, node_v, range(condition, size));\n    }\n\n    static bool theory_term_number(clingo_id_t term_id, int number, void *data) {\n        return call(data, S("theory_term_number"), term_id, number);\n    }\n    static bool theory_term_string(clingo_id_t term_id, char const *name, void *data) {\n        return call(data, S("theory_term_string"), term_id, name);\n    }\n    static bool theory_term_compound(clingo_id_t term_id, int name_id_or_type, clingo_id_t const *arguments, size_t size, void *data) {\n        return call(data, S("theory_term_compound"), term_id, name_id_or_type, range(arguments, size));\n    }\n    static bool theory_element(clingo_id_t element_id, clingo_id_t const *terms, size_t terms_size, clingo_literal_t const *condition, size_t condition_size, void *data) {\n        return call(data, S("theory_element"), element_id, range(terms, terms_size), range(condition, condition_size));\n    }\n    static bool theory_atom(clingo_id_t atom_id_or_zero, clingo_id_t term_id, clingo_id_t const *elements, size_t size, void *data) {\n        return call(data, S("theory_atom"), atom_id_or_zero, term_id, range(elements, size));\n    }\n    static bool theory_atom_with_guard(clingo_id_t atom_id_or_zero, clingo_id_t term_id, clingo_id_t const *elements, size_t size, clingo_id_t operator_id, clingo_id_t right_hand_side_id, void *data) {\n        return call(data, S("theory_atom_with_guard"), atom_id_or_zero, term_id, range(elements, size), operator_id, right_hand_side_id);\n    }\n#   undef S\nprivate:\n    template <typename T>\n    struct Range {\n        T const * first;\n        size_t size;\n    };\n    template <typename T>\n    static Range<T> range(T*first, size_t size) {\n        return {first, size};\n    }\n    static void push(lua_State *L, bool b) {\n        lua_pushboolean(L, b);\n    }\n    static void push(lua_State *L, symbol_wrapper b) {\n        Term::new_(L, b.symbol);\n    }\n    static void push(lua_State *L, clingo_external_type_e x) {\n        ExternalType::new_(L, x);\n    }\n    static void push(lua_State *L, clingo_heuristic_type_e x) {\n        HeuristicType::new_(L, x);\n    }\n    static void push(lua_State *L, clingo_weighted_literal_t lit) {\n        lua_newtable(L);\n        push(L, lit.literal);\n        lua_rawseti(L, -2, 1);\n        push(L, lit.weight);\n        lua_rawseti(L, -2, 2);\n    }\n    template <class T>\n    static void push(lua_State *L, T n, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) {\n        lua_pushinteger(L, n);\n    }\n    template <class T>\n    static void push(lua_State *L, Range<T> span) {\n        lua_newtable(L);\n        int i = 0;\n        for (auto it = span.first, ie = it + span.size; it != ie; ++it) {\n            push(L, *it);\n            lua_rawseti(L, -2, ++i);\n        }\n    }\n    static void push(lua_State *L, char const *s) {\n        lua_pushstring(L, s);\n    }\n\n    static void push_args(GroundProgramObserver *) { }\n    template <class T, class... U>\n    static void push_args(GroundProgramObserver *self, T& arg, U&... args) {\n        lua_pushlightuserdata(self->L, &arg);\n        push_args(self, args...);\n    }\n\n    template <int>\n    static void l_push_args(lua_State *, int) { }\n    template <int, class T, class... U>\n    static void l_push_args(lua_State *L, int i) {\n        T *val = static_cast<T*>(lua_touserdata(L, lua_upvalueindex(i)));\n        push(L, *val);\n        l_push_args<0, U...>(L, i+1);\n    }\n\n    template <class... T>\n    static int l_call(lua_State *L) {\n        lua_pushvalue(L, 1);\n        lua_pushvalue(L, 2);\n        l_push_args<0, T...>(L, 1);\n        lua_call(L, (sizeof...(T)+1), 0);\n        return 0;\n    }\n\n    template <class... Args>\n    static bool call(void *data, char const *fun, char const *loc, char const *msg, Args... args) {\n        auto self = static_cast<GroundProgramObserver*>(data);\n        if (!lua_checkstack(self->L, 3)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear t(self->L);\n        // get observer on top of stack L\n        lua_pushvalue(self->T, 1);\n        lua_xmove(self->T, self->L, 1);                    // +1\n        int observer = lua_gettop(self->L);\n        lua_pushcfunction(self->L, luaTraceback);          // +1\n        int handler = lua_gettop(self->L);\n        lua_getfield(self->L, -2, fun);                    // +1\n        if (!lua_isnil(self->L, -1)) {\n            int function = lua_gettop(self->L);\n            int n = sizeof...(Args);\n            if (!lua_checkstack(self->L, std::max(3,n))) {\n                clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n                return false;\n            }\n            push_args(self, args...);                      // +n\n            lua_pushcclosure(self->L, l_call<Args...>, n); // +1-n\n            lua_pushvalue(self->L, function);              // +1\n            lua_pushvalue(self->L, observer);              // +1\n            auto ret = lua_pcall(self->L, 2, 0, handler);\n            return handle_lua_error(self->L, loc, msg, ret);\n        }\n        return true;\n    }\n\nprivate:\n    lua_State *L;\n    // state where the observer is stored\n    lua_State *T;\n};\n\n// {{{1 wrap ControlWrap\n\nstruct MessageCode : Object<MessageCode> {\n    clingo_warning_e type;\n    MessageCode(clingo_warning_e type) : type(type) { }\n    clingo_warning_e cmpKey() { return type; }\n    static int addToRegistry(lua_State *L) {\n        lua_createtable(L, 0, 7);\n        for (auto t : {clingo_warning_operation_undefined, clingo_warning_runtime_error, clingo_warning_atom_undefined, clingo_warning_file_included, clingo_warning_variable_unbounded, clingo_warning_global_variable, clingo_warning_other}) {\n            new_(L, t);\n            lua_setfield(L, -2, field_(t));\n        }\n        lua_setfield(L, -2, "MessageCode");\n        return 0;\n    }\n    static char const *field_(clingo_warning_e type) {\n        switch (type) {\n            case clingo_warning_operation_undefined: { return "OperationUndefined"; }\n            case clingo_warning_runtime_error      : { return "RuntimeError"; }\n            case clingo_warning_atom_undefined     : { return "AtomUndefined"; }\n            case clingo_warning_file_included      : { return "FileIncluded"; }\n            case clingo_warning_variable_unbounded : { return "VariableUnbounded"; }\n            case clingo_warning_global_variable    : { return "GlobalVariable"; }\n            case clingo_warning_other              : { return "Other"; }\n        }\n        return "";\n    }\n\n    static int toString(lua_State *L) {\n        lua_pushstring(L, field_(get_self(L).type));\n        return 1;\n    }\n    static luaL_Reg const meta[];\n    static constexpr char const *typeName = "clingo.MessageCode";\n};\n\nconstexpr char const *MessageCode::typeName;\n\nluaL_Reg const MessageCode::meta[] = {\n    {"__eq", eq},\n    {"__lt", lt},\n    {"__le", le},\n    {"__tostring", toString},\n    { nullptr, nullptr }\n};\nstatic int lua_logger_callback(lua_State *L) {\n    char const *str = *static_cast<char const **>(lua_touserdata(L, 3));\n    int code = lua_tointeger(L, 2);\n    lua_pop(L, 2);                                // +1\n    lua_getfield(L, LUA_REGISTRYINDEX, "clingo"); // +1\n    lua_getfield(L, -1, "MessageCode");           // +1\n    lua_replace(L, -2);                           // -1\n    lua_getfield(L, -1, MessageCode::field_(static_cast<clingo_warning_e>(code))); // +1\n    lua_replace(L, -2);                           // -1\n    lua_pushstring(L, str);                       // +1\n    lua_call(L, 2, 0);                            // -3\n    return 0;\n}\n\nstatic void logger_callback(clingo_warning_t code, char const *message, void *data) {\n    lua_State *L = static_cast<lua_State*>(data);\n    if (!lua_checkstack(L, 4)) {\n        std::cerr << "logger: stack size exceeded going to abort" << std::endl;\n        std::abort();\n    }\n    lua_pushcfunction(L, luaTraceback);        // +1\n    lua_pushcfunction(L, lua_logger_callback); // +1\n    lua_pushvalue(L, 1);                       // +1\n    lua_pushinteger(L, code);                  // +1\n    lua_pushlightuserdata(L, &message);        // +1\n    auto ret = lua_pcall(L, 3, 0, -5);         // -4\n    if (ret != 0) {\n        char const *msg = lua_tostring(L, -1);\n        std::cerr << "logger: error in logger going to abort:\\n" << msg << std::endl;\n        std::abort();\n    }\n    lua_pop(L, 1);                             // -1\n}\n\nstruct ControlWrap : Object<ControlWrap> {\n    clingo_control_t *ctl;\n    bool free;\n    std::forward_list<GroundProgramObserver> observers;\n    std::forward_list<Propagator> propagators;\n    ControlWrap(clingo_control_t *ctl, bool free) : ctl(ctl), free(free) { }\n    static ControlWrap &get_self(lua_State *L) {\n        void *p = nullptr;\n        if (lua_istable(L, 1)) {\n            lua_rawgeti(L, 1, 1);                   // +1\n            p = lua_touserdata(L, -1);\n            if (p) {\n                if (lua_getmetatable(L, 1)) {       // +1\n                    luaL_getmetatable(L, typeName); // +1\n                    if (!lua_rawequal(L, -1, -2)) { p = nullptr; }\n                    lua_pop(L, 2);                  // -2\n                }\n                else { p = nullptr; }\n            }\n            lua_pop(L, 1);                          // -1\n        }\n        if (!p) {\n            const char *msg = lua_pushfstring(L, "%s expected, got %s", typeName, luaL_typename(L, 1));\n            luaL_argerror(L, 1, msg);\n        }\n        return *static_cast<ControlWrap*>(p);\n    }\n    struct Context {\n        lua_State *L;\n        int context;\n    };\n    static bool on_context(clingo_location_t const *location, char const *name, clingo_symbol_t const *arguments, size_t arguments_size, void *data, clingo_symbol_callback_t symbol_callback, void *symbol_callback_data) {\n        auto &ctx = *static_cast<Context*>(data);\n        return luacall(ctx.L, location, ctx.context, name, arguments, arguments_size, symbol_callback, symbol_callback_data);\n    }\n    static int ground(lua_State *L) {\n        auto &ctl = get_self(L).ctl;\n        luaL_checktype(L, 2, LUA_TTABLE);\n        int context = !lua_isnone(L, 3) && !lua_isnil(L, 3) ? 3 : 0;\n        using symbol_vector = std::vector<symbol_wrapper>;\n        auto cpp_parts = AnyWrap::new_<std::vector<std::pair<std::string, symbol_vector>>>(L);\n        luaToCpp(L, 2, *cpp_parts);\n        clingo_part_t *parts = static_cast<decltype(parts)>(lua_newuserdata(L, sizeof(*parts) * cpp_parts->size()));\n        auto it = parts;\n        for (auto &part : *cpp_parts) {\n            *it++ = clingo_part_t {\n                part.first.c_str(),\n                reinterpret_cast<clingo_symbol_t*>(part.second.data()),\n                part.second.size()\n            };\n        }\n        Context ctx{L, context};\n        handle_c_error(L, clingo_control_ground(ctl, parts, cpp_parts->size(), context ? on_context : nullptr, context ? &ctx : nullptr));\n        return 0;\n    }\n    static int add(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        luaL_checktype(L, 3, LUA_TTABLE);\n        char const *prg = luaL_checkstring(L, 4);\n        auto vals = AnyWrap::new_<std::vector<std::string>>(L); // +1\n        lua_pushnil(L); // +1\n        while (lua_next(L, 3) != 0) { // +1/-1\n            char const *val = luaL_checkstring(L, -1);\n            protect(L, [val,&vals](){ vals->push_back(val); });\n            lua_pop(L, 1); // -1\n        }\n        size_t size = vals->size();\n        char const ** params = static_cast<decltype(params)>(lua_newuserdata(L, size * sizeof(*params))); // +1\n        auto it = params;\n        for (auto &x : *vals) { *it++ = x.c_str(); }\n        handle_c_error(L, clingo_control_add(self.ctl, name, params, size, prg));\n        lua_pop(L, 2); // -2\n        return 0;\n    }\n    static int load(lua_State *L) {\n        auto &self = get_self(L);\n        char const *filename = luaL_checkstring(L, 2);\n        handle_c_error(L, clingo_control_load(self.ctl, filename));\n        return 0;\n    }\n    static int get_const(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        if (call_c(L, clingo_control_has_const, self.ctl, name)) {\n            clingo_symbol_t sym = call_c(L, clingo_control_get_const, self.ctl, name);\n            Term::new_(L, sym);\n        }\n        else { lua_pushnil(L); }\n        return 1;\n    }\n    static int cleanup(lua_State *L) {\n        auto &self = get_self(L);\n        handle_c_error(L, clingo_control_cleanup(self.ctl));\n        return 0;\n    }\n    static int solve(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushstring(L, "statistics"); // +1\n        lua_pushnil(L);                  // +1\n        lua_rawset(L, 1);                // -2\n\n        auto handle = SolveHandle::new_(L); // +1\n        int handleIdx = lua_gettop(L);\n        handle->ass = AnyWrap::new_<std::vector<clingo_literal_t>>(L); // +1\n        handle->ctl = self.ctl;\n\n        // this can be made more flexible by both accepting a table as well as normal arguments\n        if (!lua_isnone(L, 2) && !lua_isnil(L, 2)) {\n            luaL_checktype(L, 2, LUA_TTABLE);\n            lua_getfield(L, 2, "assumptions"); // +1\n            if (!lua_isnil(L, -1)) {\n                auto atoms = call_c(L, clingo_control_symbolic_atoms, self.ctl);\n                if (auto *lits = luaToLits(L, -1, atoms, false, false)) { // +1/+0\n                    handle->ass->swap(*lits);\n                    lua_pop(L, 1); // -1\n                }\n            }\n            lua_pop(L, 1);                     // -1\n\n            lua_getfield(L, 2, "yield");       // +1\n            if (lua_toboolean(L, -1)) { handle->mode |= clingo_solve_mode_yield; }\n            lua_pop(L, 1);                     // -1\n\n            lua_getfield(L, 2, "async");       // +1\n            if (lua_toboolean(L, -1)) { handle->mode |= clingo_solve_mode_async; }\n            lua_pop(L, 1);                     // -1\n\n            lua_pushstring(L, "on_model");     // +1\n            lua_getfield(L, 2, "on_model");    // +1\n            handle->hasMH = !lua_isnil(L, -1);\n            lua_rawset(L, handleIdx);          // -2\n\n            lua_pushstring(L, "on_finish");    // +1\n            lua_getfield(L, 2, "on_finish");   // +1\n            handle->hasFH = !lua_isnil(L, -1);\n            lua_rawset(L, handleIdx);          // -2\n\n        }\n\n        // Note: This is fixable but unfortunately quite involved.\n        if ((handle->hasFH || handle->hasMH) && (handle->mode & clingo_solve_mode_yield)) {\n            return luaL_error(L, "callbacks and iterative solving cannot be used together at the moment.");\n        }\n\n        // Note: Asynchronous solving is possible; only callbacks are\n        // troublesome. For simplicity it is disabled for now.\n        if (handle->mode & clingo_solve_mode_async) {\n            return luaL_error(L, "asynchronous solving not supported");\n        }\n\n        lua_settop(L, handleIdx + 1);\n\n        if (!lua_checkstack(L, 3)) { luaL_error(L, "lua stack size exceeded"); }\n        lua_pushcfunction(L, luaTraceback);        // +1\n        lua_pushcfunction(L, SolveHandle::solve_); // +1\n        lua_pushvalue(L, handleIdx);               // +1\n        int code = lua_pcall(L, 1, 1, -3);         // -1\n        if (code) {\n            auto h = handle->handle;\n            handle->handle = NULL;\n            call_c(L, clingo_solve_handle_close, h);\n        }\n        if (code) { lua_error(L); }\n        lua_replace(L, handleIdx);\n        lua_settop(L, handleIdx);\n        return 1;\n    }\n    static int assign_external(lua_State *L) {\n        auto &self = get_self(L);\n        auto atoms = call_c(L, clingo_control_symbolic_atoms, self.ctl);\n        auto sym  = luaToAtom(L, 2, atoms);\n        luaL_checkany(L, 3);\n        clingo_truth_value_t truth;\n        if (lua_isnil (L, 3)) { truth = clingo_truth_value_free; }\n        else {\n            luaL_checktype(L, 3, LUA_TBOOLEAN);\n            truth = lua_toboolean(L, 3) ? clingo_truth_value_true : clingo_truth_value_false;\n        }\n        handle_c_error(L, clingo_control_assign_external(self.ctl, sym, truth));\n        return 0;\n    }\n    static int release_external(lua_State *L) {\n        auto &self = get_self(L);\n        auto atoms = call_c(L, clingo_control_symbolic_atoms, self.ctl);\n        auto sym  = luaToAtom(L, 2, atoms);\n        handle_c_error(L, clingo_control_release_external(self.ctl, sym));\n        return 0;\n    }\n    static int interrupt(lua_State *L) {\n        clingo_control_interrupt(get_self(L).ctl);\n        return 0;\n    }\n    static int newindex(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "enable_enumeration_assumption") == 0) {\n            bool enabled = lua_toboolean(L, 3) != 0;\n            handle_c_error(L, clingo_control_set_enable_enumeration_assumption(self.ctl, enabled));\n            return 0;\n        }\n        else if (strcmp(name, "enable_cleanup") == 0) {\n            bool enabled = lua_toboolean(L, 3) != 0;\n            handle_c_error(L, clingo_control_set_enable_cleanup(self.ctl, enabled));\n            return 0;\n        }\n        return luaL_error(L, "unknown field: %s", name);\n    }\n\n    static int index(lua_State *L) {\n        auto &self = get_self(L);\n        char const *name = luaL_checkstring(L, 2);\n        if (strcmp(name, "statistics") == 0) {\n            lua_pushstring(L, "statistics");            // +1\n            lua_rawget(L, 1);                           // +0\n            if (lua_isnil(L, -1)) {\n                auto stats = call_c(L, clingo_control_statistics, self.ctl);\n                auto root = call_c(L, clingo_statistics_root, stats);\n                lua_pop(L, 1);                          // -1\n                newStatistics(L, stats, root);          // +1\n                lua_pushstring(L, "statistics");        // +1\n                lua_pushvalue(L, -2);                   // +1\n                lua_rawset(L, 1);                       // -2\n            }\n            return 1;\n        }\n        else if (strcmp(name, "configuration") == 0) {\n            auto conf = call_c(L, clingo_control_configuration, self.ctl);\n            auto key = call_c(L, clingo_configuration_root, conf);\n            return Configuration::new_(L, conf, key);\n        }\n        else if (strcmp(name, "symbolic_atoms") == 0) {\n            auto atoms = call_c(L, clingo_control_symbolic_atoms, self.ctl);\n            return SymbolicAtoms::new_(L, atoms);\n        }\n        else if (strcmp(name, "theory_atoms") == 0) {\n            auto atoms = call_c(L, clingo_control_theory_atoms, self.ctl);\n            return TheoryIter::iter(L, atoms);\n        }\n        else if (strcmp(name, "is_conflicting") == 0) {\n            lua_pushboolean(L, clingo_control_is_conflicting(self.ctl));\n            return 1;\n        }\n        else if (strcmp(name, "enable_enumeration_assumption") == 0) {\n            lua_pushboolean(L, clingo_control_get_enable_enumeration_assumption(self.ctl));\n            return 1;\n        }\n        else if (strcmp(name, "enable_cleanup") == 0) {\n            lua_pushboolean(L, clingo_control_get_enable_cleanup(self.ctl));\n            return 1;\n        }\n        else {\n            lua_getmetatable(L, 1);\n            lua_getfield(L, -1, name);\n            return 1;\n        }\n    }\n    static int new_(lua_State *L) {\n        bool has_parameters = !lua_isnone(L, 1) && !lua_isnil(L, 1);\n        bool has_logger = !lua_isnone(L, 2) && !lua_isnil(L, 2);\n        bool has_limit = !lua_isnone(L, 3) && !lua_isnil(L, 3);\n        std::vector<std::string> *args = AnyWrap::new_<std::vector<std::string>>(L);\n        if (has_parameters) { luaToCpp(L, 1, *args); }\n        std::vector<char const *> *cargs = AnyWrap::new_<std::vector<char const*>>(L);\n        int message_limit = 20;\n        if (has_limit) { luaToCpp(L, 3, message_limit); }\n        for (auto &arg : *args) {\n            protect(L, [&arg, &cargs](){ cargs->push_back(arg.c_str()); });\n        }\n        return new_(L, [&](void *mem){\n            lua_State *T = nullptr;\n            if (has_logger) {\n                lua_pushstring(L, "logger");\n                T = lua_newthread(L);\n                lua_pushvalue(L, 2);\n                lua_xmove(L, T, 1);\n                lua_rawset(L, -3);\n            }\n            new (mem) ControlWrap(call_c(L, clingo_control_new, cargs->data(), cargs->size(), has_logger ? logger_callback : nullptr, T, message_limit), true);\n        });\n    }\n    template <class F>\n    static int new_(lua_State *L, F f) {\n        lua_newtable(L);                                                   // +1\n        auto self = (ControlWrap*)lua_newuserdata(L, sizeof(ControlWrap)); // +1\n        // see: https://stackoverflow.com/questions/27426704/lua-5-1-workaround-for-gc-metamethod-for-tables\n        luaL_getmetatable(L, typeNameI);                                   // +1\n        lua_setmetatable(L, -2);                                           // -1\n        lua_rawseti(L, -2, 1);                                             // -1\n        protect(L, [self, f]() { f(self); });\n        luaL_getmetatable(L, typeName);                                    // +1\n        lua_setmetatable(L, -2);                                           // -1\n        return 1;\n    }\n    static void reg(lua_State *L) {\n        lua_regMeta(L, typeName, meta, index, newindex);\n        lua_regMeta(L, typeNameI, metaI, nullptr, nullptr);\n    }\n\n    static int gc(lua_State *L) {\n        auto &self = *(ControlWrap*)lua_touserdata(L, 1);\n        if (self.free) { clingo_control_free(self.ctl); }\n        self.~ControlWrap();\n        return 0;\n    }\n    static bool hasField(lua_State *L, char const *name, int index) {\n        lua_getfield(L, index, name); // +1\n        bool ret = !lua_isnil(L, -1);\n        lua_pop(L, 1);                // -1\n        return ret;\n    }\n    static int registerPropagator(lua_State *L) {\n        auto &self = get_self(L);\n        lua_pushstring(L, "propagators");     // +1\n        lua_rawget(L, 1);                     // +0\n        if (lua_isnil(L, -1)) {\n            lua_pop(L, 1);                    // -1\n            lua_newtable(L);                  // +1\n            lua_pushstring(L, "propagators"); // +1\n            lua_pushvalue(L, -2);             // +1\n            lua_rawset(L, 1);                 // -2\n        }\n        auto *T = lua_newthread(L);           // +1\n        luaL_ref(L, -2);                      // -1\n        lua_pop(L, 1);                        // -1\n        lua_pushvalue(L, 2);                  // +1\n        lua_xmove(L, T, 1);                   // -1\n        lua_newtable(T);\n        lua_newtable(T);\n\n        clingo_propagator_t propagator = {\n            hasField(L, "init", 2) ? Propagator::init : nullptr,\n            hasField(L, "propagate", 2) ? Propagator::propagate : nullptr,\n            hasField(L, "undo", 2) ? Propagator::undo : nullptr,\n            hasField(L, "check", 2) ? Propagator::check : nullptr,\n            hasField(L, "decide", 2) ? Propagator::decide : nullptr,\n        };\n        PROTECT(self.propagators.emplace_front(L, T));\n        handle_c_error(L, clingo_control_register_propagator(self.ctl, &propagator, &self.propagators.front(), true));\n        return 0;\n    }\n\n    static int backend(lua_State *L) {\n        auto &self = get_self(L);\n        auto backend = call_c(L, clingo_control_backend, self.ctl);\n        if (!backend) { return luaL_error(L, "backend not available"); }\n        call_c(L, clingo_backend_begin, backend);\n        return Backend::new_(L, backend);\n    }\n\n    static int registerObserver(lua_State *L) {\n        bool replace = lua_toboolean(L, 3) != 0;\n        auto &self = get_self(L);\n        lua_pushstring(L, "observers");     // +1\n        lua_rawget(L, 1);                   // +0\n        if (lua_isnil(L, -1)) {\n            lua_pop(L, 1);                  // -1\n            lua_newtable(L);                // +1\n            lua_pushstring(L, "observers"); // +1\n            lua_pushvalue(L, -2);           // +1\n            lua_rawset(L, 1);               // -2\n        }\n        auto *T = lua_newthread(L);         // +1\n        luaL_ref(L, -2);                    // -1\n        lua_pop(L, 1);                      // -1\n        lua_pushvalue(L, 2);                // +1\n        lua_xmove(L, T, 1);                 // -1\n\n        static clingo_ground_program_observer_t observer = {\n            GroundProgramObserver::init_program,\n            GroundProgramObserver::begin_step,\n            GroundProgramObserver::end_step,\n            GroundProgramObserver::rule,\n            GroundProgramObserver::weight_rule,\n            GroundProgramObserver::minimize,\n            GroundProgramObserver::project,\n            GroundProgramObserver::output_atom,\n            GroundProgramObserver::output_term,\n            GroundProgramObserver::external,\n            GroundProgramObserver::assume,\n            GroundProgramObserver::heuristic,\n            GroundProgramObserver::acyc_edge,\n            GroundProgramObserver::theory_term_number,\n            GroundProgramObserver::theory_term_string,\n            GroundProgramObserver::theory_term_compound,\n            GroundProgramObserver::theory_element,\n            GroundProgramObserver::theory_atom,\n            GroundProgramObserver::theory_atom_with_guard\n        };\n        PROTECT(self.observers.emplace_front(L, T));\n        handle_c_error(L, clingo_control_register_observer(self.ctl, &observer, replace, &self.observers.front()));\n        return 0;\n    }\n\n    static luaL_Reg meta[];\n    static luaL_Reg metaI[];\n    static constexpr char const *typeName = "clingo.Control";\n    static constexpr char const *typeNameI = "clingo._Control";\n};\n\nconstexpr char const *ControlWrap::typeName;\nluaL_Reg ControlWrap::meta[] = {\n    {"ground",  ground},\n    {"add", add},\n    {"load", load},\n    {"solve", solve},\n    {"cleanup", cleanup},\n    {"get_const", get_const},\n    {"assign_external", assign_external},\n    {"release_external", release_external},\n    {"interrupt", interrupt},\n    {"register_propagator", registerPropagator},\n    {"register_observer", registerObserver},\n    {"backend", backend},\n    {nullptr, nullptr}\n};\nluaL_Reg ControlWrap::metaI[] = {\n    {"__gc", gc},\n    {nullptr, nullptr}\n};\n\nint luaMain(lua_State *L) {\n    auto ctl = (clingo_control_t*)lua_touserdata(L, 1);\n    lua_getglobal(L, "main");\n    ControlWrap::new_(L, [ctl](void *mem) { new (mem) ControlWrap(ctl, false); });\n    lua_call(L, 1, 0);\n    return 0;\n}\n\n// {{{1 wrap module functions\n\nint parseTerm(lua_State *L) {\n    bool has_logger = !lua_isnone(L, 2) && !lua_isnil(L, 2);\n    bool has_limit = !lua_isnone(L, 3) && !lua_isnil(L, 3);\n    char const *str = luaL_checkstring(L, 1);\n    int message_limit = 20;\n    if (has_limit) { luaToCpp(L, 3, message_limit); }\n    lua_State *T = nullptr;\n    if (has_logger) {\n        T = lua_newthread(L);\n        lua_pushvalue(L, 2);\n        lua_xmove(L, T, 1);\n    }\n    return Term::new_(L, call_c(L, clingo_parse_term, str, has_logger ? logger_callback : nullptr, T, message_limit));\n}\n\n// {{{1 clingo library\n\nint luaopen_clingo(lua_State* L) {\n    static luaL_Reg clingoLib[] = {\n        {"Function", Term::newFun},\n        {"Tuple", Term::newTuple},\n        {"Number", Term::newNumber},\n        {"String", Term::newString},\n        {"Control", ControlWrap::new_},\n        {"parse_term", parseTerm},\n        {nullptr, nullptr}\n    };\n\n    Term::reg(L);\n    SymbolType::reg(L);\n    MessageCode::reg(L);\n    Model::reg(L);\n    SolveControl::reg(L);\n    SolveHandle::reg(L);\n    ControlWrap::reg(L);\n    Configuration::reg(L);\n    SolveResult::reg(L);\n    SymbolicAtoms::reg(L);\n    SymbolicAtom::reg(L);\n    AnyWrap::reg(L);\n    TheoryTermType::reg(L);\n    ExternalType::reg(L);\n    ModelType::reg(L);\n    HeuristicType::reg(L);\n    TheoryTerm::reg(L);\n    TheoryElement::reg(L);\n    TheoryAtom::reg(L);\n    PropagateInit::reg(L);\n    PropagateControl::reg(L);\n    Trail::reg(L);\n    Assignment::reg(L);\n    Backend::reg(L);\n    PropagatorCheckMode::reg(L);\n\n#if LUA_VERSION_NUM < 502\n    luaL_register(L, "clingo", clingoLib);\n#else\n    luaL_newlib(L, clingoLib);\n#endif\n\n    lua_pushstring(L, CLINGO_VERSION);\n    lua_setfield(L, -2, "__version__");\n\n    SymbolType::addToRegistry(L);\n    MessageCode::addToRegistry(L);\n    Term::addToRegistry(L);\n    TheoryTermType::addToRegistry(L);\n    ExternalType::addToRegistry(L);\n    ModelType::addToRegistry(L);\n    HeuristicType::addToRegistry(L);\n    PropagatorCheckMode::addToRegistry(L);\n\n    lua_pushvalue(L, -1);\n    lua_setfield(L, LUA_REGISTRYINDEX, "clingo");\n\n    return 1;\n}\n\nint luarequire_clingo(lua_State *L) {\n    luaL_openlibs(L);\n#if LUA_VERSION_NUM < 502\n    lua_pushcfunction(L, luaopen_clingo);\n    lua_call(L, 0, 1);\n#else\n    luaL_requiref(L, "clingo", luaopen_clingo, true);\n#endif\n    return 1;\n}\n\n// {{{1 definition of Lua\n\nstruct LuaScriptC {\n    lua_State *L;\n    bool self_init_;\n    LuaScriptC(lua_State *L)\n    : L(L)\n    , self_init_(false)\n    { }\n    ~LuaScriptC() {\n        if (self_init_ && L) { lua_close(L); }\n    }\n    bool init() {\n        if (L) { return true; }\n        L = luaL_newstate();\n        if (!L) {\n            clingo_set_error(clingo_error_runtime, "could not initialize lua interpreter");\n            return false;\n        }\n        self_init_ = true;\n        if (!lua_checkstack(L, 2)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear lc(L);\n        lua_pushcfunction(L, luaTraceback);\n        lua_pushcfunction(L, luarequire_clingo);\n        int code = lua_pcall(L, 0, 0, -2);\n        bool ret = handle_lua_error(L, "main", "could not load clingo module", code);\n        return ret;\n    }\n    static bool execute(clingo_location_t const *loc, char const *code, void *data) {\n        auto &self = *static_cast<LuaScriptC*>(data);\n        if (!self.init()) { return false; }\n        std::string name;\n        try {\n            std::stringstream oss;\n            oss << *loc;\n            name = oss.str();\n        }\n        catch (...) {\n            clingo_set_error(clingo_error_bad_alloc, "bad alloc");\n            return false;\n        }\n        if (!lua_checkstack(self.L, 2)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear lc(self.L);\n        lua_pushcfunction(self.L, luaTraceback);\n        int ret = luaL_loadbuffer(self.L, code, std::strlen(code), name.c_str());\n        if (!handle_lua_error(self.L, name.c_str(), "parsing lua script failed", ret)) { return false; }\n        ret = lua_pcall(self.L, 0, 0, -2);\n        return handle_lua_error(self.L, name.c_str(), "running lua script failed", ret);\n    }\n    static bool call(clingo_location_t const *loc, char const *name, clingo_symbol_t const *arguments, size_t size, clingo_symbol_callback_t symbol_callback, void *symbol_callback_data, void *data) {\n        auto &self = *static_cast<LuaScriptC*>(data);\n        return luacall(self.L, loc, 0, name, arguments, size, symbol_callback, symbol_callback_data);\n    }\n    static bool callable(char const * name, bool *ret, void *data) {\n        auto &self = *static_cast<LuaScriptC*>(data);\n        if (!self.L) {\n            *ret = false;\n            return true;\n        }\n        if (!lua_checkstack(self.L, 2)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        LuaClear lc(self.L);\n        lua_getglobal(self.L, name);\n        *ret = lua_type(self.L, -1) == LUA_TFUNCTION;\n        return true;\n    }\n    static bool main(clingo_control_t *ctl, void *data) {\n        auto &self = *static_cast<LuaScriptC*>(data);\n        LuaClear lc(self.L);\n        if (!lua_checkstack(self.L, 3)) {\n            clingo_set_error(clingo_error_runtime, "lua stack size exceeded");\n            return false;\n        }\n        lua_pushcfunction(self.L, luaTraceback);\n        lua_pushcfunction(self.L, luaMain);\n        lua_pushlightuserdata(self.L, ctl);\n        auto ret = lua_pcall(self.L, 1, 0, -3);\n        return handle_lua_error(self.L, "main", "error calling main", ret);\n    }\n    static void free(void *data) {\n        delete static_cast<LuaScriptC*>(data);\n    }\n};\n\n// }}}1\n\n} // namespace\n\nextern "C" int clingo_init_lua_(lua_State *L) {\n    return luarequire_clingo(L);\n}\n\nextern "C" bool clingo_register_lua_(lua_State *L) {\n    auto strip_lua = [](char const *str) {\n        return strncmp("Lua ", str, 4) == 0 ? str + 4 : str;\n    };\n    try {\n        clingo_script_t script = {\n            LuaScriptC::execute,\n            LuaScriptC::call,\n            LuaScriptC::callable,\n            LuaScriptC::main,\n            LuaScriptC::free,\n            strip_lua(LUA_RELEASE),\n        };\n        return clingo_register_script("lua", &script, new LuaScriptC(L));\n    }\n    catch (...) {\n        clingo_set_error(clingo_error_runtime, "could not initialize lua interpreter");\n        return false;\n    }\n}\n\n// }}}1\n\n', 'message': 'fix lua 5.1 memory leak and invalid memory access in solve function\n', 'author_name': 'Roland Kaminski', 'lang': 'cc'}