/* get event from given stack position */
struct event *dlua_check_event(lua_State *L, int arg);
+/*
+ * Returns field from a Lua table
+ *
+ * There are different variants of these that allow for different key types
+ * and different value types. In general, the function name scheme is:
+ *
+ * dlua_table_get_<return type>_by_<key type>
+ *
+ * The _by_{str,int} variants use the supplied field value as the table key.
+ *
+ * The _by_thread variants use the current thread's thread object as the
+ * table key.
+ *
+ * Returns:
+ * -1 = incompatible value type
+ * 0 = nil or not found
+ * 1 = value found
+ */
+int dlua_table_get_luainteger_by_str(lua_State *L, int idx, const char *field, lua_Integer *value_r);
+int dlua_table_get_int_by_str(lua_State *L, int idx, const char *field, int *value_r);
+int dlua_table_get_intmax_by_str(lua_State *L, int idx, const char *field, intmax_t *value_r);
+int dlua_table_get_uint_by_str(lua_State *L, int idx, const char *field, unsigned int *value_r);
+int dlua_table_get_uintmax_by_str(lua_State *L, int idx, const char *field, uintmax_t *value_r);
+int dlua_table_get_number_by_str(lua_State *L, int idx, const char *field, lua_Number *value_r);
+int dlua_table_get_bool_by_str(lua_State *L, int idx, const char *field, bool *value_r);
+int dlua_table_get_string_by_str(lua_State *L, int idx, const char *field, const char **value_r);
+int dlua_table_get_data_by_str(lua_State *L, int idx, const char *field, const unsigned char **value_r, size_t *len_r);
+
+int dlua_table_get_luainteger_by_int(lua_State *L, int idx, lua_Integer field, lua_Integer *value_r);
+int dlua_table_get_int_by_int(lua_State *L, int idx, lua_Integer field, int *value_r);
+int dlua_table_get_intmax_by_int(lua_State *L, int idx, lua_Integer field, intmax_t *value_r);
+int dlua_table_get_uint_by_int(lua_State *L, int idx, lua_Integer field, unsigned int *value_r);
+int dlua_table_get_uintmax_by_int(lua_State *L, int idx, lua_Integer field, uintmax_t *value_r);
+int dlua_table_get_number_by_int(lua_State *L, int idx, lua_Integer field, lua_Number *value_r);
+int dlua_table_get_bool_by_int(lua_State *L, int idx, lua_Integer field, bool *value_r);
+int dlua_table_get_string_by_int(lua_State *L, int idx, lua_Integer field, const char **value_r);
+int dlua_table_get_data_by_int(lua_State *L, int idx, lua_Integer field, const unsigned char **value_r, size_t *len_r);
+
+int dlua_table_get_luainteger_by_thread(lua_State *L, int idx, lua_Integer *value_r);
+int dlua_table_get_int_by_thread(lua_State *L, int idx, int *value_r);
+int dlua_table_get_intmax_by_thread(lua_State *L, int idx, intmax_t *value_r);
+int dlua_table_get_uint_by_thread(lua_State *L, int idx, unsigned int *value_r);
+int dlua_table_get_uintmax_by_thread(lua_State *L, int idx, uintmax_t *value_r);
+int dlua_table_get_number_by_thread(lua_State *L, int idx, lua_Number *value_r);
+int dlua_table_get_bool_by_thread(lua_State *L, int idx, bool *value_r);
+int dlua_table_get_string_by_thread(lua_State *L, int idx, const char **value_r);
+int dlua_table_get_data_by_thread(lua_State *L, int idx, const unsigned char **value_r, size_t *len_r);
+
+/*
+ * Pushes onto the stack the value t[k], where t is the value at the given
+ * index and k is field argument. Unlike lua_gettable(), this function
+ * checks the type of the retrieved value against the passed in type.
+ * [-1,+0..1,e]
+ *
+ * There are different variants of these that allow for different key types.
+ * In general, the function name scheme is:
+ *
+ * dlua_table_get_by_<key type>
+ *
+ * The _by_{str,int} variants use the supplied field value as the table key.
+ *
+ * The _by_thread variants use the current thread's thread object as the
+ * table key.
+ *
+ * Returns:
+ * -1 = incompatible value type (nothing is pushed)
+ * 0 = nil or not found (nothing is pushed)
+ * 1 = value found (retrieved value is pushed to the top of the stack)
+ */
+int dlua_table_get_by_str(lua_State *L, int idx, int type, const char *field);
+int dlua_table_get_by_int(lua_State *L, int idx, int type, lua_Integer field);
+int dlua_table_get_by_thread(lua_State *L, int idx, int type);
+
/* dumps current stack as i_debug lines */
void dlua_dump_stack(lua_State *L);
--- /dev/null
+/* Copyright (c) 2021 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "dlua-script-private.h"
+
+/*
+ * Adjust the index by the specified delta.
+ *
+ * In a couple of places we need to adjust the passed in index to reflect
+ * additional items pushed onto the stack. We cannot blindly adjust the
+ * index because the index could be one of three things and only one of them
+ * is supposed to be ajusted:
+ *
+ * 1. negative number: index relative to top of stack, adjust
+ * 2. positive number: absolute index, don't adjust
+ * 3. special registry index: don't adjust
+ */
+static inline int adj(int idx, int delta)
+{
+ if ((idx == LUA_REGISTRYINDEX) || (idx > 0))
+ return idx;
+ else
+ return idx - delta;
+}
+
+/*
+ * Pushes onto the stack the value t[k], where t is the value at the given
+ * index and k is the value at the top of the stack. Unlike lua_gettable(),
+ * this function checks the type of the retreived value against the passed
+ * in type. [-1,+0..1,e]
+ *
+ * Return value:
+ * -1 = incompatible type
+ * 0 = nil or none
+ * 1 = found
+ */
+static int dlua_table_get(lua_State *L, int idx, int type)
+{
+ /* can only work with tables */
+ if (!lua_istable(L, idx))
+ return -1;
+
+ lua_gettable(L, idx);
+
+ /* check if the field was there */
+ if (lua_isnoneornil(L, -1)) {
+ lua_pop(L, 1);
+ return 0;
+ }
+
+ /* check that the field is the expected type */
+ if (lua_type(L, -1) != type) {
+ lua_pop(L, 1);
+ return -1;
+ }
+
+ return 1;
+}
+
+/* Get by string name [-0,+1,e] */
+int dlua_table_get_by_str(lua_State *L, int idx, int type, const char *field)
+{
+ /* push the key */
+ lua_pushstring(L, field);
+
+ return dlua_table_get(L, adj(idx, 1), type);
+}
+
+/* Get by int name [-0,+1,e] */
+int dlua_table_get_by_int(lua_State *L, int idx, int type, lua_Integer field)
+{
+ /* push the key */
+ lua_pushinteger(L, field);
+
+ return dlua_table_get(L, adj(idx, 1), type);
+}
+
+/* Get by thread [-0,+1,e] */
+int dlua_table_get_by_thread(lua_State *L, int idx, int type)
+{
+ /* push the key */
+ lua_pushthread(L);
+
+ return dlua_table_get(L, adj(idx, 1), type);
+}
+
+/* generate a set of functions to access fields of an integral data type */
+#define GET_INTTYPE(fxn, ctype, minval, maxval, unsigned_check) \
+int fxn##_by_str(lua_State *L, int idx, const char *field, \
+ ctype *value_r) \
+{ \
+ lua_Integer tmp; \
+ int ret; \
+ \
+ ret = dlua_table_get_luainteger_by_str(L, idx, field, &tmp); \
+ if (ret < 1) \
+ return ret; \
+ \
+ if (unsigned_check) { \
+ if ((tmp < 0) || (((uintmax_t) tmp) > (maxval))) \
+ return -1; \
+ } else { \
+ if ((tmp < (minval)) || (tmp > (intmax_t) (maxval))) \
+ return -1; \
+ } \
+ \
+ *value_r = (ctype) tmp; \
+ \
+ return 1; \
+} \
+int fxn##_by_int(lua_State *L, int idx, lua_Integer field, \
+ ctype *value_r) \
+{ \
+ lua_Integer tmp; \
+ int ret; \
+ \
+ ret = dlua_table_get_luainteger_by_int(L, idx, field, &tmp); \
+ if (ret < 1) \
+ return ret; \
+ \
+ if (unsigned_check) { \
+ if ((tmp < 0) || (((uintmax_t) tmp) > (maxval))) \
+ return -1; \
+ } else { \
+ if ((tmp < (minval)) || (tmp > (intmax_t) (maxval))) \
+ return -1; \
+ } \
+ \
+ *value_r = (ctype) tmp; \
+ \
+ return 1; \
+} \
+int fxn##_by_thread(lua_State *L, int idx, ctype *value_r) \
+{ \
+ lua_Integer tmp; \
+ int ret; \
+ \
+ ret = dlua_table_get_luainteger_by_thread(L, idx, &tmp); \
+ if (ret < 1) \
+ return ret; \
+ \
+ if (unsigned_check) { \
+ if ((tmp < 0) || (((uintmax_t) tmp) > (maxval))) \
+ return -1; \
+ } else { \
+ if ((tmp < (minval)) || (tmp > (intmax_t) (maxval))) \
+ return -1; \
+ } \
+ \
+ *value_r = (ctype) tmp; \
+ \
+ return 1; \
+}
+
+/* generate a set of functions to access fields of a binary data type */
+#define GET_DATAPTR(fxn) \
+int fxn##_by_str(lua_State *L, int idx, const char *field, \
+ const unsigned char **value_r, size_t *len_r) \
+{ \
+ int ret; \
+ \
+ ret = dlua_table_get_by_str(L, idx, LUA_TSTRING, field); \
+ if (ret < 1) \
+ return ret; \
+ \
+ *value_r = (const unsigned char *) lua_tolstring(L, -1, len_r); \
+ lua_pop(L, 1); \
+ \
+ return 1; \
+} \
+int fxn##_by_int(lua_State *L, int idx, lua_Integer field, \
+ const unsigned char **value_r, size_t *len_r) \
+{ \
+ int ret; \
+ \
+ ret = dlua_table_get_by_int(L, idx, LUA_TSTRING, field); \
+ if (ret < 1) \
+ return ret; \
+ \
+ *value_r = (const unsigned char *) lua_tolstring(L, -1, len_r); \
+ lua_pop(L, 1); \
+ \
+ return 1; \
+} \
+int fxn##_by_thread(lua_State *L, int idx, \
+ const unsigned char **value_r, size_t *len_r) \
+{ \
+ int ret; \
+ \
+ ret = dlua_table_get_by_thread(L, idx, LUA_TSTRING); \
+ if (ret < 1) \
+ return ret; \
+ \
+ *value_r = (const unsigned char *) lua_tolstring(L, -1, len_r); \
+ lua_pop(L, 1); \
+ \
+ return 1; \
+}
+
+/* generate a set of functions to access fields of a generic-ish type */
+#define GET_GENERIC(fxn, ctype, ltype, cvt) \
+int fxn##_by_str(lua_State *L, int idx, const char *field, ctype *value_r)\
+{ \
+ int ret; \
+ \
+ ret = dlua_table_get_by_str(L, idx, (ltype), field); \
+ if (ret < 1) \
+ return ret; \
+ \
+ *value_r = cvt(L, -1); \
+ lua_pop(L, 1); \
+ \
+ return 1; \
+} \
+int fxn##_by_int(lua_State *L, int idx, lua_Integer field, ctype *value_r)\
+{ \
+ int ret; \
+ \
+ ret = dlua_table_get_by_int(L, idx, (ltype), field); \
+ if (ret < 1) \
+ return ret; \
+ \
+ *value_r = cvt(L, -1); \
+ lua_pop(L, 1); \
+ \
+ return 1; \
+} \
+int fxn##_by_thread(lua_State *L, int idx, ctype *value_r) \
+{ \
+ int ret; \
+ \
+ ret = dlua_table_get_by_thread(L, idx, (ltype)); \
+ if (ret < 1) \
+ return ret; \
+ \
+ *value_r = cvt(L, -1); \
+ lua_pop(L, 1); \
+ \
+ return 1; \
+}
+
+GET_INTTYPE(dlua_table_get_int, int, INT_MIN, INT_MAX, FALSE);
+GET_INTTYPE(dlua_table_get_intmax, intmax_t, INTMAX_MIN, INTMAX_MAX, FALSE);
+GET_INTTYPE(dlua_table_get_uint, unsigned int, 0, UINT_MAX, TRUE);
+GET_INTTYPE(dlua_table_get_uintmax, uintmax_t, 0, UINTMAX_MAX, TRUE);
+
+/* we need to use lua_tointegerx which takes an extra argument */
+int dlua_table_get_luainteger_by_str(lua_State *L, int idx, const char *field,
+ lua_Integer *value_r)
+{
+ int isnum;
+ int ret;
+
+ ret = dlua_table_get_by_str(L, idx, LUA_TNUMBER, field);
+ if (ret < 1)
+ return ret;
+
+ *value_r = lua_tointegerx(L, -1, &isnum);
+ lua_pop(L, 1);
+
+ return (isnum == 1) ? 1 : -1;
+}
+
+/* we need to use lua_tointegerx which takes an extra argument */
+int dlua_table_get_luainteger_by_int(lua_State *L, int idx, lua_Integer field,
+ lua_Integer *value_r)
+{
+ int isnum;
+ int ret;
+
+ ret = dlua_table_get_by_int(L, idx, LUA_TNUMBER, field);
+ if (ret < 1)
+ return ret;
+
+ *value_r = lua_tointegerx(L, -1, &isnum);
+ lua_pop(L, 1);
+
+ return (isnum == 1) ? 1 : -1;
+}
+
+/* we need to use lua_tointegerx which takes an extra argument */
+int dlua_table_get_luainteger_by_thread(lua_State *L, int idx,
+ lua_Integer *value_r)
+{
+ int isnum;
+ int ret;
+
+ ret = dlua_table_get_by_thread(L, idx, LUA_TNUMBER);
+ if (ret < 1)
+ return ret;
+
+ *value_r = lua_tointegerx(L, -1, &isnum);
+ lua_pop(L, 1);
+
+ return (isnum == 1) ? 1 : -1;
+}
+
+GET_GENERIC(dlua_table_get_number, lua_Number, LUA_TNUMBER, lua_tonumber);
+GET_GENERIC(dlua_table_get_bool, bool, LUA_TBOOLEAN, lua_toboolean);
+GET_GENERIC(dlua_table_get_string, const char *, LUA_TSTRING, lua_tostring);
+GET_DATAPTR(dlua_table_get_data);
return 0;
}
+#define GENERATE_GETTERS(name, ctype) \
+static void check_table_get_##name##_ok(struct dlua_script *script, \
+ int idx, ctype expected_value, \
+ const char *str_key, \
+ lua_Integer int_key) \
+{ \
+ ctype value; \
+ int ret; \
+ \
+ /* check string key */ \
+ ret = dlua_table_get_##name##_by_str(script->L, idx, \
+ str_key, &value); \
+ test_assert(ret == 1); \
+ test_assert(value == expected_value); \
+ \
+ /* check int key */ \
+ ret = dlua_table_get_##name##_by_int(script->L, idx, \
+ int_key, &value); \
+ test_assert(ret == 1); \
+ test_assert(value == expected_value); \
+} \
+static void check_table_get_##name##_err(struct dlua_script *script, \
+ int idx, int expected_ret, \
+ const char *str_key, \
+ lua_Integer int_key) \
+{ \
+ ctype value; \
+ int ret; \
+ \
+ /* check string key */ \
+ ret = dlua_table_get_##name##_by_str(script->L, idx, \
+ str_key, &value); \
+ test_assert(ret == expected_ret); \
+ \
+ /* check int key */ \
+ ret = dlua_table_get_##name##_by_int(script->L, idx, \
+ int_key, &value); \
+ test_assert(ret == expected_ret); \
+}
+
+GENERATE_GETTERS(luainteger, lua_Integer);
+GENERATE_GETTERS(int, int);
+GENERATE_GETTERS(intmax, intmax_t);
+GENERATE_GETTERS(uint, unsigned int);
+GENERATE_GETTERS(uintmax, uintmax_t);
+GENERATE_GETTERS(number, lua_Number);
+GENERATE_GETTERS(bool, bool);
+
+/* the string comparison requires us to open-code this */
+static void check_table_get_string_ok(struct dlua_script *script,
+ int idx, const char *expected_value,
+ const char *str_key,
+ lua_Integer int_key)
+{
+ const char *value;
+ int ret;
+
+ /* check string key */
+ ret = dlua_table_get_string_by_str(script->L, idx,
+ str_key, &value);
+ test_assert(ret == 1);
+ test_assert_strcmp(value, expected_value);
+
+ /* check int key */
+ ret = dlua_table_get_string_by_int(script->L, idx,
+ int_key, &value);
+ test_assert(ret == 1);
+ test_assert_strcmp(value, expected_value);
+
+ /* TODO: check thread key, which is difficult */
+}
+
+/* the string comparison of the _ok function requires us to open-code this */
+static void check_table_get_string_err(struct dlua_script *script,
+ int idx, int expected_ret,
+ const char *str_key,
+ lua_Integer int_key)
+{
+ const char *value;
+ int ret;
+
+ /* check string key */
+ ret = dlua_table_get_string_by_str(script->L, idx,
+ str_key, &value);
+ test_assert(ret == expected_ret);
+
+ /* check int key */
+ ret = dlua_table_get_string_by_int(script->L, idx,
+ int_key, &value);
+ test_assert(ret == expected_ret);
+
+ /* TODO: check thread key, which is difficult */
+}
+
+static void check_table_missing(struct dlua_script *script, int idx,
+ const char *str_key,
+ lua_Integer int_key)
+{
+ check_table_get_luainteger_err(script, idx, 0, str_key, int_key);
+ check_table_get_int_err(script, idx, 0, str_key, int_key);
+ check_table_get_intmax_err(script, idx, 0, str_key, int_key);
+ check_table_get_uint_err(script, idx, 0, str_key, int_key);
+ check_table_get_uintmax_err(script, idx, 0, str_key, int_key);
+ check_table_get_number_err(script, idx, 0, str_key, int_key);
+ check_table_get_bool_err(script, idx, 0, str_key, int_key);
+ check_table_get_string_err(script, idx, 0, str_key, int_key);
+}
+
static void test_lua(void)
{
static const char *luascript =
" flag = dovecot.clear_flag(flag, 4)\n"
" test_assert(\"has_flag(flag, 4) == false\", dovecot.has_flag(flag, 4) == false)\n"
" test_assert(\"has_flag(flag, 16) == true\", dovecot.has_flag(flag, 16) == true)\n"
+"end\n"
+"function lua_test_get_table()\n"
+" t = {}\n"
+" -- zero\n"
+" t[\"zero\"] = 0\n"
+" t[-2] = 0\n"
+" -- small positive values\n"
+" t[\"small-positive-int\"] = 1\n"
+" t[-1] = 1\n"
+" -- small negative values\n"
+" t[\"small-negative-int\"] = -5\n"
+" t[0] = -5\n"
+" -- large positive float\n"
+" t[\"large-positive-int\"] = 2^48\n"
+" t[1] = 2^48\n"
+" -- large negative float\n"
+" t[\"large-negative-int\"] = -2^48\n"
+" t[2] = -2^48\n"
+" -- small float\n"
+" t[\"small-float\"] = 1.525\n"
+" t[3] = 1.525\n"
+" -- bool: true\n"
+" t[\"bool-true\"] = true\n"
+" t[4] = true\n"
+" -- bool: false\n"
+" t[\"bool-false\"] = false\n"
+" t[5] = false\n"
+" -- string\n"
+" t[\"str\"] = \"string\"\n"
+" t[6] = \"string\"\n"
+" return t\n"
"end\n";
const char *error = NULL;
test_begin("lua script");
test_assert(dlua_script_create_string(luascript, &script, NULL, &error) == 0);
+ if (error != NULL)
+ i_fatal("dlua_script_init failed: %s", error);
+
dlua_dovecot_register(script);
dlua_register(script, "test_assert", dlua_test_assert);
lua_getglobal(script->L, "lua_test_flags");
test_assert(lua_pcall(script->L, 0, 0, 0) == 0);
+ lua_getglobal(script->L, "lua_test_get_table");
+ test_assert(lua_pcall(script->L, 0, 1, 0) == 0);
+
+ /*
+ * Check table getters
+ */
+
+ /* lua_Integer */
+ check_table_get_luainteger_ok(script, -1, 0, "zero", -2);
+ check_table_get_luainteger_ok(script, -1, 1, "small-positive-int", -1);
+ check_table_get_luainteger_ok(script, -1, -5, "small-negative-int", 0);
+ check_table_get_luainteger_ok(script, -1, 1ll<<48, "large-positive-int", 1);
+ check_table_get_luainteger_ok(script, -1, -(1ll<<48), "large-negative-int", 2);
+#if LUA_VERSION_NUM != 502
+ check_table_get_luainteger_err(script, -1, -1, "small-float", 3);
+#else
+ check_table_get_uintmax_ok(script, -1, 1, "small-float", 3);
+#endif
+ check_table_get_luainteger_err(script, -1, -1, "bool-true", 4);
+ check_table_get_luainteger_err(script, -1, -1, "bool-false", 5);
+ check_table_get_luainteger_err(script, -1, -1, "str", 6);
+
+ /* int */
+ check_table_get_int_ok(script, -1, 0, "zero", -2);
+ check_table_get_int_ok(script, -1, 1, "small-positive-int", -1);
+ check_table_get_int_ok(script, -1, -5, "small-negative-int", 0);
+ check_table_get_int_err(script, -1, -1, "large-positive-int", 1);
+ check_table_get_int_err(script, -1, -1, "large-negative-int", 2);
+#if LUA_VERSION_NUM != 502
+ check_table_get_int_err(script, -1, -1, "small-float", 3);
+#else
+ check_table_get_uintmax_ok(script, -1, 1, "small-float", 3);
+#endif
+ check_table_get_int_err(script, -1, -1, "bool-true", 4);
+ check_table_get_int_err(script, -1, -1, "bool-false", 5);
+ check_table_get_int_err(script, -1, -1, "str", 6);
+
+ /* intmax_t */
+ check_table_get_intmax_ok(script, -1, 0, "zero", -2);
+ check_table_get_intmax_ok(script, -1, 1, "small-positive-int", -1);
+ check_table_get_intmax_ok(script, -1, -5, "small-negative-int", 0);
+ check_table_get_intmax_ok(script, -1, 1ll<<48, "large-positive-int", 1);
+ check_table_get_intmax_ok(script, -1, -(1ll<<48), "large-negative-int", 2);
+#if LUA_VERSION_NUM != 502
+ check_table_get_intmax_err(script, -1, -1, "small-float", 3);
+#else
+ check_table_get_uintmax_ok(script, -1, 1, "small-float", 3);
+#endif
+ check_table_get_intmax_err(script, -1, -1, "bool-true", 4);
+ check_table_get_intmax_err(script, -1, -1, "bool-false", 5);
+ check_table_get_intmax_err(script, -1, -1, "str", 6);
+
+ /* unsigned int */
+ check_table_get_uint_ok(script, -1, 0, "zero", -2);
+ check_table_get_uint_ok(script, -1, 1, "small-positive-int", -1);
+ check_table_get_uint_err(script, -1, -1, "small-negative-int", 0);
+ check_table_get_uint_err(script, -1, -1, "large-positive-int", 1);
+ check_table_get_uint_err(script, -1, -1, "large-negative-int", 2);
+#if LUA_VERSION_NUM != 502
+ check_table_get_uint_err(script, -1, -1, "small-float", 3);
+#else
+ check_table_get_uintmax_ok(script, -1, 1, "small-float", 3);
+#endif
+ check_table_get_uint_err(script, -1, -1, "bool-true", 4);
+ check_table_get_uint_err(script, -1, -1, "bool-false", 5);
+ check_table_get_uint_err(script, -1, -1, "str", 6);
+
+ /* uintmax_t */
+ check_table_get_uintmax_ok(script, -1, 0, "zero", -2);
+ check_table_get_uintmax_ok(script, -1, 1, "small-positive-int", -1);
+ check_table_get_uintmax_err(script, -1, -1, "small-negative-int", 0);
+ check_table_get_uintmax_ok(script, -1, 1ll<<48, "large-positive-int", 1);
+ check_table_get_uintmax_err(script, -1, -1, "large-negative-int", 2);
+#if LUA_VERSION_NUM != 502
+ check_table_get_uintmax_err(script, -1, -1, "small-float", 3);
+#else
+ check_table_get_uintmax_ok(script, -1, 1, "small-float", 3);
+#endif
+ check_table_get_uintmax_err(script, -1, -1, "bool-true", 4);
+ check_table_get_uintmax_err(script, -1, -1, "bool-false", 5);
+ check_table_get_uintmax_err(script, -1, -1, "str", 6);
+
+ /* lua_Number */
+ check_table_get_number_ok(script, -1, 0, "zero", -2);
+ check_table_get_number_ok(script, -1, 1, "small-positive-int", -1);
+ check_table_get_number_ok(script, -1, -5, "small-negative-int", 0);
+ check_table_get_number_ok(script, -1, 1ll<<48, "large-positive-int", 1);
+ check_table_get_number_ok(script, -1, -(1ll<<48), "large-negative-int", 2);
+ check_table_get_number_ok(script, -1, 1.525, "small-float", 3);
+ check_table_get_number_err(script, -1, -1, "bool-true", 4);
+ check_table_get_number_err(script, -1, -1, "bool-false", 5);
+ check_table_get_number_err(script, -1, -1, "str", 6);
+
+ /* bool */
+ check_table_get_bool_err(script, -1, -1, "zero", -2);
+ check_table_get_bool_err(script, -1, -1, "small-positive-int", -1);
+ check_table_get_bool_err(script, -1, -1, "small-negative-int", 0);
+ check_table_get_bool_err(script, -1, -1, "large-positive-int", 1);
+ check_table_get_bool_err(script, -1, -1, "large-negative-int", 2);
+ check_table_get_bool_err(script, -1, -1, "small-float", 3);
+ check_table_get_bool_ok(script, -1, TRUE, "bool-true", 4);
+ check_table_get_bool_ok(script, -1, FALSE, "bool-false", 5);
+ check_table_get_bool_err(script, -1, -1, "str", 6);
+
+ /* const char * */
+ check_table_get_string_err(script, -1, -1, "zero", -2);
+ check_table_get_string_err(script, -1, -1, "small-positive-int", -1);
+ check_table_get_string_err(script, -1, -1, "small-negative-int", 0);
+ check_table_get_string_err(script, -1, -1, "large-positive-int", 1);
+ check_table_get_string_err(script, -1, -1, "large-negative-int", 2);
+ check_table_get_string_err(script, -1, -1, "small-float", 3);
+ check_table_get_string_err(script, -1, -1, "bool-true", 4);
+ check_table_get_string_err(script, -1, -1, "bool-false", 5);
+ check_table_get_string_ok(script, -1, "string", "str", 6);
+
+ check_table_missing(script, -1, "missing", -10);
+
+ lua_pop(script->L, 1);
+
dlua_script_unref(&script);
test_end();