fix(lua/sexpr): make sexpr bindings robust

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-11-05 13:03:32 -08:00
parent 055cc7f957
commit 0cc475e581
2 changed files with 78 additions and 12 deletions

View file

@ -48,7 +48,7 @@ static sexpr to_sexpr_elem(lua_State * L, int idx) {
if (lua_isnil(L, idx)) {
return sexpr();
} else if (lua_isboolean(L, idx)) {
return sexpr(lua_toboolean(L, idx));
return sexpr(static_cast<bool>(lua_toboolean(L, idx)));
} else if (lua_isnumber(L, idx)) {
// Remark: we convert to integer by default
return sexpr(static_cast<int>(lua_tointeger(L, idx)));
@ -95,7 +95,7 @@ static int sexpr_is_name(lua_State * L) { lua_pushboolean(L, is_name(to_sexpr(
static int sexpr_is_mpz(lua_State * L) { lua_pushboolean(L, is_mpz(to_sexpr(L, 1))); return 1; }
static int sexpr_is_mpq(lua_State * L) { lua_pushboolean(L, is_mpq(to_sexpr(L, 1))); return 1; }
static int sexpr_length(lua_State * L) {
static int sexpr_length(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_list(e))
return luaL_error(L, "s-expression is not a list");
@ -103,27 +103,72 @@ static int sexpr_length(lua_State * L) {
return 1;
}
static int sexpr_head(lua_State * L) {
static int sexpr_head(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_cons(e))
return luaL_error(L, "s-expression is not a cons cell");
return push_sexpr(L, head(e));
}
static int sexpr_tail(lua_State * L) {
static int sexpr_tail(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_cons(e))
return luaL_error(L, "s-expression is not a cons cell");
return push_sexpr(L, tail(e));
}
static int sexpr_to_bool(lua_State * L) { lua_pushboolean(L, to_bool(to_sexpr(L, 1))); return 1; }
static int sexpr_to_string(lua_State * L) { lua_pushfstring(L, to_string(to_sexpr(L, 1)).c_str()); return 1; }
static int sexpr_to_int(lua_State * L) { lua_pushinteger(L, to_int(to_sexpr(L, 1))); return 1; }
static int sexpr_to_double(lua_State * L) { lua_pushnumber(L, to_double(to_sexpr(L, 1))); return 1; }
static int sexpr_to_name(lua_State * L) { return push_name(L, to_name(to_sexpr(L, 1))); }
static int sexpr_to_mpz(lua_State * L) { return push_mpz(L, to_mpz(to_sexpr(L, 1))); }
static int sexpr_to_mpq(lua_State * L) { return push_mpq(L, to_mpq(to_sexpr(L, 1))); }
static int sexpr_to_bool(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_bool(e))
return luaL_error(L, "s-expression is not a Boolean");
lua_pushboolean(L, to_bool(e));
return 1;
}
static int sexpr_to_string(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_string(e))
return luaL_error(L, "s-expression is not a string");
lua_pushfstring(L, to_string(e).c_str());
return 1;
}
static int sexpr_to_int(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_int(e))
return luaL_error(L, "s-expression is not an integer");
lua_pushinteger(L, to_int(e));
return 1;
}
static int sexpr_to_double(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_double(e))
return luaL_error(L, "s-expression is not a double");
lua_pushnumber(L, to_double(e));
return 1;
}
static int sexpr_to_name(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_name(e))
return luaL_error(L, "s-expression is not a name");
return push_name(L, to_name(e));
}
static int sexpr_to_mpz(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_mpz(e))
return luaL_error(L, "s-expression is not a multi-precision integer");
return push_mpz(L, to_mpz(e));
}
static int sexpr_to_mpq(lua_State * L) {
sexpr const & e = to_sexpr(L, 1);
if (!is_mpq(e))
return luaL_error(L, "s-expression is not a multi-precision rational");
return push_mpq(L, to_mpq(e));
}
static const struct luaL_Reg sexpr_m[] = {
{"__gc", sexpr_gc}, // never throws

View file

@ -1,3 +1,14 @@
function check_error(f)
ok, msg = pcall(function ()
f()
end)
if ok then
error("unexpected success...")
else
print("caught expected error: ", msg)
end
end
s = sexpr(1, 2, 3)
print(s)
s = sexpr(1, 2, 3, nil)
@ -11,8 +22,9 @@ print(sexpr(1):is_nil())
print(sexpr(true):is_bool())
print(sexpr(true):to_bool())
print(sexpr(false):to_bool())
check_error(function() sexpr(10):to_bool() end)
print(sexpr(name("foo",1)):to_name())
print(sexpr(10):to_name())
check_error(function () print(sexpr(10):to_name()) end)
print(sexpr(mpq(10)/3):to_mpq())
print(sexpr(mpz("10000000000000000000000000000000000")):to_mpz())
print(sexpr(10, 20, 30, 40, nil):length())
@ -20,3 +32,12 @@ print(sexpr(10, 20, nil):head())
print(sexpr(10, 20, nil):tail())
print(sexpr(10, 20):head())
print(sexpr(10, 20):tail())
check_error(function () sexpr(10):head() end)
check_error(function () sexpr(10):tail() end)
check_error(function () sexpr(10):to_mpz() end)
check_error(function () sexpr(10):to_mpq() end)
check_error(function () sexpr(10):to_string() end)
check_error(function () sexpr(10):to_bool() end)
check_error(function () sexpr(10):to_double() end)
print(sexpr("hello"):to_string())