2014-04-29 23:57:19 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "util/list.h"
|
2014-05-12 19:58:10 +00:00
|
|
|
#include "util/sstream.h"
|
2014-04-29 23:57:19 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
/** \brief Convert a Lua table into a list<T> */
|
|
|
|
template<typename T, typename Proc>
|
|
|
|
list<T> table_to_list(lua_State * L, int idx, Proc const & to_value) {
|
|
|
|
if (lua_istable(L, idx)) {
|
|
|
|
int n = objlen(L, idx);
|
|
|
|
list<T> r;
|
|
|
|
for (int i = n; i >= 1; i--) {
|
|
|
|
lua_rawgeti(L, idx, i);
|
|
|
|
r = cons(to_value(L, -1), r);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
} else {
|
2014-05-12 19:58:10 +00:00
|
|
|
throw exception(sstream() << "arg #" << idx << " must be a lua table");
|
2014-04-29 23:57:19 +00:00
|
|
|
}
|
|
|
|
}
|
2014-04-30 23:31:44 +00:00
|
|
|
|
|
|
|
#define DEFINE_LUA_LIST(T, PushVal, ToVal) \
|
|
|
|
typedef list<T> list_ ## T; \
|
|
|
|
DECL_UDATA(list_ ## T) \
|
|
|
|
static int list_ ## T ## _cons(lua_State * L) { return push_list_ ## T(L, list<T>(ToVal(L, 1), to_list_ ## T(L, 2))); } \
|
|
|
|
static int list_ ## T ## _nil(lua_State * L) { return push_list_ ## T(L, list<T>()); } \
|
|
|
|
static int list_ ## T ## _mk(lua_State * L) { \
|
|
|
|
int nargs = lua_gettop(L); \
|
|
|
|
return (nargs == 0) ? list_ ## T ## _nil(L) : list_ ## T ## _cons(L); \
|
|
|
|
} \
|
2014-05-02 01:40:18 +00:00
|
|
|
static int list_ ## T ## _is_nil(lua_State * L) { return push_boolean(L, is_nil(to_list_ ## T(L, 1))); } \
|
2014-04-30 23:31:44 +00:00
|
|
|
static int list_ ## T ## _car(lua_State * L) { \
|
|
|
|
list<T> & l = to_list_ ## T(L, 1); \
|
|
|
|
if (is_nil(l)) throw exception("arg #1 must be a cons cell"); \
|
2014-05-02 20:33:49 +00:00
|
|
|
return PushVal(L, car(l)); \
|
2014-04-30 23:31:44 +00:00
|
|
|
} \
|
|
|
|
static int list_ ## T ## _cdr(lua_State * L) { \
|
|
|
|
list<T> & l = to_list_ ## T(L, 1); \
|
|
|
|
if (is_nil(l)) throw exception("arg #1 must be a cons cell"); \
|
|
|
|
return push_list_ ## T(L, cdr(l)); \
|
|
|
|
} \
|
2014-05-02 01:40:18 +00:00
|
|
|
static int list_ ## T ## _eq(lua_State * L) { return push_boolean(L, to_list_ ## T(L, 1) == to_list_ ## T(L, 2)); } \
|
|
|
|
static int list_ ## T ## _is_eqp(lua_State * L) { return push_boolean(L, is_eqp(to_list_ ## T(L, 1), to_list_ ## T(L, 2))); } \
|
2014-05-02 20:37:15 +00:00
|
|
|
static int list_ ## T ## _len(lua_State * L) { return push_integer(L, length(to_list_ ## T(L, 1))); } \
|
2014-04-30 23:31:44 +00:00
|
|
|
static const struct luaL_Reg list_ ## T ## _m[] = { \
|
|
|
|
{"__gc", list_ ## T ## _gc}, \
|
|
|
|
{"__eq", safe_function<list_ ## T ## _eq>}, \
|
2014-05-02 20:37:15 +00:00
|
|
|
{"__len", safe_function<list_ ## T ## _len>}, \
|
2014-04-30 23:31:44 +00:00
|
|
|
{"is_nil", safe_function<list_ ## T ## _is_nil>}, \
|
|
|
|
{"empty", safe_function<list_ ## T ## _is_nil>}, \
|
|
|
|
{"car", safe_function<list_ ## T ## _car>}, \
|
|
|
|
{"cdr", safe_function<list_ ## T ## _cdr>}, \
|
|
|
|
{"head", safe_function<list_ ## T ## _car>}, \
|
|
|
|
{"tail", safe_function<list_ ## T ## _cdr>}, \
|
|
|
|
{"is_eqp", safe_function<list_ ## T ## _is_eqp>}, \
|
|
|
|
{0, 0} \
|
|
|
|
}; \
|
|
|
|
list<T> to_list_ ## T ## _ext(lua_State * L, int idx) { \
|
|
|
|
if (is_list_ ## T(L, idx)) \
|
|
|
|
return to_list_ ## T(L, idx); \
|
|
|
|
else \
|
|
|
|
return table_to_list<T>(L, idx, ToVal); \
|
|
|
|
} \
|
|
|
|
static void open_list_ ## T(lua_State * L) { \
|
|
|
|
luaL_newmetatable(L, list_ ## T ## _mt); \
|
|
|
|
lua_pushvalue(L, -1); \
|
|
|
|
lua_setfield(L, -2, "__index"); \
|
|
|
|
setfuncs(L, list_ ## T ## _m, 0); \
|
|
|
|
\
|
|
|
|
set_global_function<list_ ## T ## _mk>(L, "list_" #T); \
|
|
|
|
set_global_function<list_ ## T ## _pred>(L, "is_list_" #T); \
|
|
|
|
}
|
2014-04-29 23:57:19 +00:00
|
|
|
}
|