2013-11-03 20:02:57 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <sstream>
|
|
|
|
#include <lua.hpp>
|
|
|
|
#include "util/debug.h"
|
|
|
|
#include "util/numerics/mpz.h"
|
|
|
|
#include "util/numerics/mpq.h"
|
2013-11-03 20:16:23 +00:00
|
|
|
#include "bindings/lua/util.h"
|
2013-11-03 20:02:57 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2013-11-05 03:45:15 +00:00
|
|
|
constexpr char const * mpz_mt = "mpz.mt";
|
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
template<unsigned idx>
|
|
|
|
static mpz const & to_mpz(lua_State * L) {
|
|
|
|
static thread_local mpz arg;
|
|
|
|
if (lua_isuserdata(L, idx)) {
|
2013-11-05 03:45:15 +00:00
|
|
|
return *static_cast<mpz*>(luaL_checkudata(L, idx, mpz_mt));
|
2013-11-04 23:05:04 +00:00
|
|
|
} else if (lua_isstring(L, idx)) {
|
|
|
|
char const * str = luaL_checkstring(L, idx);
|
|
|
|
arg = mpz(str);
|
|
|
|
return arg;
|
|
|
|
} else {
|
2013-11-05 21:35:34 +00:00
|
|
|
arg = static_cast<long int>(luaL_checkinteger(L, 1));
|
2013-11-04 23:05:04 +00:00
|
|
|
return arg;
|
2013-11-03 20:02:57 +00:00
|
|
|
}
|
2013-11-04 23:05:04 +00:00
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-05 03:45:15 +00:00
|
|
|
bool is_mpz(lua_State * L, int idx) {
|
|
|
|
return testudata(L, idx, mpz_mt);
|
|
|
|
}
|
|
|
|
|
|
|
|
mpz & to_mpz(lua_State * L, int idx) {
|
|
|
|
return *static_cast<mpz*>(luaL_checkudata(L, idx, mpz_mt));
|
|
|
|
}
|
|
|
|
|
2013-11-05 05:28:17 +00:00
|
|
|
int push_mpz(lua_State * L, mpz const & val) {
|
2013-11-04 23:05:04 +00:00
|
|
|
void * mem = lua_newuserdata(L, sizeof(mpz));
|
|
|
|
new (mem) mpz(val);
|
2013-11-05 03:45:15 +00:00
|
|
|
luaL_getmetatable(L, mpz_mt);
|
2013-11-04 23:05:04 +00:00
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_gc(lua_State * L) {
|
2013-11-05 03:45:15 +00:00
|
|
|
mpz * n = static_cast<mpz*>(luaL_checkudata(L, 1, mpz_mt));
|
2013-11-04 23:05:04 +00:00
|
|
|
n->~mpz();
|
|
|
|
return 0;
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_tostring(lua_State * L) {
|
2013-11-05 03:45:15 +00:00
|
|
|
mpz * n = static_cast<mpz*>(luaL_checkudata(L, 1, mpz_mt));
|
2013-11-04 23:05:04 +00:00
|
|
|
std::ostringstream out;
|
|
|
|
out << *n;
|
|
|
|
lua_pushfstring(L, out.str().c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_eq(lua_State * L) {
|
|
|
|
lua_pushboolean(L, to_mpz<1>(L) == to_mpz<2>(L));
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_lt(lua_State * L) {
|
|
|
|
lua_pushboolean(L, to_mpz<1>(L) < to_mpz<2>(L));
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_add(lua_State * L) {
|
|
|
|
return push_mpz(L, to_mpz<1>(L) + to_mpz<2>(L));
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_sub(lua_State * L) {
|
|
|
|
return push_mpz(L, to_mpz<1>(L) - to_mpz<2>(L));
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_mul(lua_State * L) {
|
|
|
|
return push_mpz(L, to_mpz<1>(L) * to_mpz<2>(L));
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_div(lua_State * L) {
|
|
|
|
mpz const & arg2 = to_mpz<2>(L);
|
2013-11-12 05:44:10 +00:00
|
|
|
if (arg2 == 0) throw exception("division by zero");
|
2013-11-04 23:05:04 +00:00
|
|
|
return push_mpz(L, to_mpz<1>(L) / arg2);
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_umn(lua_State * L) {
|
|
|
|
return push_mpz(L, 0 - to_mpz<1>(L));
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpz_power(lua_State * L) {
|
|
|
|
int k = luaL_checkinteger(L, 2);
|
2013-11-12 05:44:10 +00:00
|
|
|
if (k < 0) throw exception("argument #2 must be positive");
|
2013-11-04 23:05:04 +00:00
|
|
|
return push_mpz(L, pow(to_mpz<1>(L), k));
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mk_mpz(lua_State * L) {
|
|
|
|
mpz const & arg = to_mpz<1>(L);
|
|
|
|
return push_mpz(L, arg);
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-08 20:40:28 +00:00
|
|
|
static int mpz_pred(lua_State * L) {
|
|
|
|
lua_pushboolean(L, is_mpz(L, 1));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static const struct luaL_Reg mpz_m[] = {
|
|
|
|
{"__gc", mpz_gc}, // never throws
|
|
|
|
{"__tostring", safe_function<mpz_tostring>},
|
|
|
|
{"__eq", safe_function<mpz_eq>},
|
|
|
|
{"__lt", safe_function<mpz_lt>},
|
|
|
|
{"__add", safe_function<mpz_add>},
|
|
|
|
{"__add", safe_function<mpz_sub>},
|
|
|
|
{"__mul", safe_function<mpz_mul>},
|
|
|
|
{"__div", safe_function<mpz_div>},
|
|
|
|
{"__pow", safe_function<mpz_power>},
|
|
|
|
{"__unm", safe_function<mpz_umn>},
|
|
|
|
{0, 0}
|
|
|
|
};
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
void open_mpz(lua_State * L) {
|
2013-11-05 03:45:15 +00:00
|
|
|
luaL_newmetatable(L, mpz_mt);
|
2013-11-04 23:05:04 +00:00
|
|
|
setfuncs(L, mpz_m, 0);
|
|
|
|
|
2013-11-08 04:48:49 +00:00
|
|
|
set_global_function<mk_mpz>(L, "mpz");
|
2013-11-08 20:40:28 +00:00
|
|
|
set_global_function<mpz_pred>(L, "is_mpz");
|
2013-11-04 23:05:04 +00:00
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-05 03:45:15 +00:00
|
|
|
constexpr char const * mpq_mt = "mpq.mt";
|
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
template<unsigned idx>
|
|
|
|
static mpq const & to_mpq(lua_State * L) {
|
|
|
|
static thread_local mpq arg;
|
|
|
|
if (lua_isuserdata(L, idx)) {
|
2013-11-05 03:45:15 +00:00
|
|
|
return *static_cast<mpq*>(luaL_checkudata(L, idx, mpq_mt));
|
2013-11-04 23:05:04 +00:00
|
|
|
} else if (lua_isstring(L, idx)) {
|
|
|
|
char const * str = luaL_checkstring(L, idx);
|
|
|
|
arg = mpq(str);
|
|
|
|
return arg;
|
|
|
|
} else {
|
2013-11-05 21:35:34 +00:00
|
|
|
arg = static_cast<long int>(luaL_checkinteger(L, 1));
|
2013-11-04 23:05:04 +00:00
|
|
|
return arg;
|
2013-11-03 20:02:57 +00:00
|
|
|
}
|
2013-11-04 23:05:04 +00:00
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-05 03:45:15 +00:00
|
|
|
bool is_mpq(lua_State * L, int idx) {
|
|
|
|
return testudata(L, idx, mpq_mt);
|
|
|
|
}
|
|
|
|
|
|
|
|
mpq & to_mpq(lua_State * L, int idx) {
|
|
|
|
return *static_cast<mpq*>(luaL_checkudata(L, idx, mpq_mt));
|
|
|
|
}
|
|
|
|
|
2013-11-05 05:28:17 +00:00
|
|
|
int push_mpq(lua_State * L, mpq const & val) {
|
2013-11-04 23:05:04 +00:00
|
|
|
void * mem = lua_newuserdata(L, sizeof(mpq));
|
|
|
|
new (mem) mpq(val);
|
2013-11-05 03:45:15 +00:00
|
|
|
luaL_getmetatable(L, mpq_mt);
|
2013-11-04 23:05:04 +00:00
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-03 20:02:57 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpq_gc(lua_State * L) {
|
2013-11-05 03:45:15 +00:00
|
|
|
mpq * n = static_cast<mpq*>(luaL_checkudata(L, 1, mpq_mt));
|
2013-11-04 23:05:04 +00:00
|
|
|
n->~mpq();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_tostring(lua_State * L) {
|
2013-11-05 03:45:15 +00:00
|
|
|
mpq * n = static_cast<mpq*>(luaL_checkudata(L, 1, mpq_mt));
|
2013-11-04 23:05:04 +00:00
|
|
|
std::ostringstream out;
|
|
|
|
out << *n;
|
|
|
|
lua_pushfstring(L, out.str().c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_eq(lua_State * L) {
|
|
|
|
lua_pushboolean(L, to_mpq<1>(L) == to_mpq<2>(L));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_lt(lua_State * L) {
|
|
|
|
lua_pushboolean(L, to_mpq<1>(L) < to_mpq<2>(L));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_add(lua_State * L) {
|
|
|
|
return push_mpq(L, to_mpq<1>(L) + to_mpq<2>(L));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_sub(lua_State * L) {
|
|
|
|
return push_mpq(L, to_mpq<1>(L) - to_mpq<2>(L));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_mul(lua_State * L) {
|
|
|
|
return push_mpq(L, to_mpq<1>(L) * to_mpq<2>(L));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_div(lua_State * L) {
|
|
|
|
mpq const & arg2 = to_mpq<2>(L);
|
2013-11-12 05:44:10 +00:00
|
|
|
if (arg2 == 0) throw exception("division by zero");
|
2013-11-04 23:05:04 +00:00
|
|
|
return push_mpq(L, to_mpq<1>(L) / arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mpq_umn(lua_State * L) {
|
|
|
|
return push_mpq(L, 0 - to_mpq<1>(L));
|
2013-11-03 20:02:57 +00:00
|
|
|
}
|
2013-11-03 22:42:54 +00:00
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static int mpq_power(lua_State * L) {
|
|
|
|
int k = luaL_checkinteger(L, 2);
|
2013-11-12 05:44:10 +00:00
|
|
|
if (k < 0) throw exception("argument #2 must be positive");
|
2013-11-04 23:05:04 +00:00
|
|
|
return push_mpq(L, pow(to_mpq<1>(L), k));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mk_mpq(lua_State * L) {
|
|
|
|
mpq const & arg = to_mpq<1>(L);
|
|
|
|
return push_mpq(L, arg);
|
|
|
|
}
|
|
|
|
|
2013-11-08 20:40:28 +00:00
|
|
|
static int mpq_pred(lua_State * L) {
|
|
|
|
lua_pushboolean(L, is_mpq(L, 1));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-11-04 23:05:04 +00:00
|
|
|
static const struct luaL_Reg mpq_m[] = {
|
|
|
|
{"__gc", mpq_gc}, // never throws
|
|
|
|
{"__tostring", safe_function<mpq_tostring>},
|
|
|
|
{"__eq", safe_function<mpq_eq>},
|
|
|
|
{"__lt", safe_function<mpq_lt>},
|
|
|
|
{"__add", safe_function<mpq_add>},
|
|
|
|
{"__add", safe_function<mpq_sub>},
|
|
|
|
{"__mul", safe_function<mpq_mul>},
|
|
|
|
{"__div", safe_function<mpq_div>},
|
|
|
|
{"__pow", safe_function<mpq_power>},
|
|
|
|
{"__unm", safe_function<mpq_umn>},
|
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
2013-11-04 21:54:51 +00:00
|
|
|
void open_mpq(lua_State * L) {
|
2013-11-05 03:45:15 +00:00
|
|
|
luaL_newmetatable(L, mpq_mt);
|
2013-11-04 23:05:04 +00:00
|
|
|
setfuncs(L, mpq_m, 0);
|
|
|
|
|
2013-11-08 04:48:49 +00:00
|
|
|
set_global_function<mk_mpq>(L, "mpq");
|
2013-11-08 20:40:28 +00:00
|
|
|
set_global_function<mpq_pred>(L, "is_mpq");
|
2013-11-03 20:02:57 +00:00
|
|
|
}
|
|
|
|
}
|