2013-11-07 21:56:04 +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 <iostream>
|
2013-11-07 23:19:26 +00:00
|
|
|
#include <string>
|
2013-11-27 22:57:33 +00:00
|
|
|
#include <vector>
|
2013-12-23 05:27:12 +00:00
|
|
|
#include <unordered_set>
|
2013-11-27 03:15:49 +00:00
|
|
|
#include "util/lua.h"
|
2013-11-07 23:19:26 +00:00
|
|
|
#include "util/debug.h"
|
|
|
|
#include "util/exception.h"
|
2013-11-07 23:52:39 +00:00
|
|
|
#include "util/memory.h"
|
2013-11-12 20:54:34 +00:00
|
|
|
#include "util/buffer.h"
|
2013-11-14 18:04:32 +00:00
|
|
|
#include "util/interrupt.h"
|
2013-11-27 22:57:33 +00:00
|
|
|
#include "util/script_state.h"
|
|
|
|
#include "util/script_exception.h"
|
|
|
|
#include "util/name.h"
|
2014-05-08 00:28:11 +00:00
|
|
|
#include "util/name_generator.h"
|
2014-05-08 01:32:53 +00:00
|
|
|
#include "util/name_set.h"
|
2014-04-29 00:53:34 +00:00
|
|
|
#include "util/rb_map.h"
|
2013-12-23 05:27:12 +00:00
|
|
|
#include "util/lean_path.h"
|
2013-11-07 21:56:04 +00:00
|
|
|
|
2013-11-07 23:52:39 +00:00
|
|
|
extern "C" void * lua_realloc(void *, void * q, size_t, size_t new_size) { return lean::realloc(q, new_size); }
|
|
|
|
|
2013-11-07 21:56:04 +00:00
|
|
|
namespace lean {
|
2013-11-27 22:57:33 +00:00
|
|
|
static std::vector<script_state::reg_fn> g_modules;
|
|
|
|
void script_state::register_module(reg_fn f) {
|
|
|
|
g_modules.push_back(f);
|
|
|
|
}
|
|
|
|
|
2013-12-04 17:57:33 +00:00
|
|
|
static unsigned g_check_interrupt_freq = 1048576;
|
|
|
|
|
|
|
|
void script_state::set_check_interrupt_freq(unsigned count) {
|
|
|
|
g_check_interrupt_freq = count;
|
|
|
|
}
|
|
|
|
|
2013-11-27 03:24:18 +00:00
|
|
|
void open_extra(lua_State * L);
|
2013-11-27 03:15:49 +00:00
|
|
|
|
2013-11-15 23:55:15 +00:00
|
|
|
static char g_weak_ptr_key; // key for Lua registry (used at get_weak_ptr and save_weak_ptr)
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
struct script_state::imp {
|
2014-05-01 21:10:57 +00:00
|
|
|
lua_State * m_state;
|
2013-12-23 05:27:12 +00:00
|
|
|
std::unordered_set<std::string> m_imported_modules;
|
2013-11-07 23:52:39 +00:00
|
|
|
|
2013-11-15 23:55:15 +00:00
|
|
|
static std::weak_ptr<imp> * get_weak_ptr(lua_State * L) {
|
|
|
|
lua_pushlightuserdata(L, static_cast<void *>(&g_weak_ptr_key));
|
|
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
std::weak_ptr<imp> * ptr = static_cast<std::weak_ptr<imp>*>(lua_touserdata(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void save_weak_ptr(std::shared_ptr<imp> & ptr) {
|
|
|
|
lua_pushlightuserdata(m_state, static_cast<void *>(&g_weak_ptr_key));
|
|
|
|
void * mem = lua_newuserdata(m_state, sizeof(std::weak_ptr<imp>));
|
|
|
|
new (mem) std::weak_ptr<imp>(ptr);
|
|
|
|
lua_settable(m_state, LUA_REGISTRYINDEX);
|
|
|
|
}
|
|
|
|
|
2013-12-04 17:57:33 +00:00
|
|
|
static void check_interrupted_hook(lua_State * L, lua_Debug *) {
|
|
|
|
try {
|
|
|
|
check_interrupted();
|
|
|
|
} catch (interrupted & ex) {
|
|
|
|
push_exception(L, ex);
|
|
|
|
lua_error(L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-07 21:56:04 +00:00
|
|
|
imp() {
|
2013-11-12 02:20:52 +00:00
|
|
|
// TODO(Leo) investigate why TCMALLOC + lua_realloc do not work together
|
|
|
|
// #ifdef LEAN_USE_LUA_NEWSTATE
|
|
|
|
#if 0
|
2013-11-07 23:52:39 +00:00
|
|
|
m_state = lua_newstate(lua_realloc, nullptr);
|
2013-11-08 01:22:28 +00:00
|
|
|
#else
|
|
|
|
m_state = luaL_newstate();
|
|
|
|
#endif
|
2013-11-07 23:52:39 +00:00
|
|
|
if (m_state == nullptr)
|
|
|
|
throw exception("fail to create Lua interpreter");
|
2013-12-04 17:57:33 +00:00
|
|
|
if (g_check_interrupt_freq > 0) {
|
|
|
|
lua_sethook(m_state, check_interrupted_hook, LUA_MASKCOUNT, g_check_interrupt_freq);
|
|
|
|
}
|
2014-08-10 06:13:30 +00:00
|
|
|
if (!lua_checkstack(m_state, 1024))
|
|
|
|
throw exception("lua_checkstack failed");
|
2013-11-07 21:56:04 +00:00
|
|
|
luaL_openlibs(m_state);
|
2013-11-27 22:57:33 +00:00
|
|
|
open_exception(m_state);
|
|
|
|
open_name(m_state);
|
2014-05-08 00:28:11 +00:00
|
|
|
open_name_generator(m_state);
|
2014-05-08 01:32:53 +00:00
|
|
|
open_name_set(m_state);
|
2014-04-29 00:53:34 +00:00
|
|
|
open_rb_map(m_state);
|
2013-11-27 03:24:18 +00:00
|
|
|
open_extra(m_state);
|
2013-11-27 03:15:49 +00:00
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
for (auto f : g_modules) {
|
|
|
|
f(m_state);
|
|
|
|
}
|
2013-11-07 21:56:04 +00:00
|
|
|
}
|
2013-11-07 23:52:39 +00:00
|
|
|
|
2013-11-07 21:56:04 +00:00
|
|
|
~imp() {
|
2013-11-15 23:55:15 +00:00
|
|
|
typedef std::weak_ptr<imp> wptr;
|
|
|
|
wptr * ptr = get_weak_ptr(m_state);
|
|
|
|
ptr->~wptr(); // destruct weak pointer
|
2013-11-07 21:56:04 +00:00
|
|
|
lua_close(m_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dofile(char const * fname) {
|
2013-11-08 19:59:47 +00:00
|
|
|
::lean::dofile(m_state, fname);
|
2013-11-07 21:56:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dostring(char const * str) {
|
2013-11-08 19:59:47 +00:00
|
|
|
::lean::dostring(m_state, str);
|
2013-11-07 21:56:04 +00:00
|
|
|
}
|
2013-12-23 05:27:12 +00:00
|
|
|
|
2013-12-28 20:24:13 +00:00
|
|
|
bool import_explicit(std::string const & fname) {
|
2013-12-28 20:04:56 +00:00
|
|
|
if (m_imported_modules.find(fname) == m_imported_modules.end()) {
|
|
|
|
dofile(fname.c_str());
|
|
|
|
m_imported_modules.insert(fname);
|
2013-12-28 20:24:13 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
2013-12-23 05:27:12 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-28 20:04:56 +00:00
|
|
|
|
2013-12-28 20:24:13 +00:00
|
|
|
bool import_explicit(char const * fname) {
|
|
|
|
return import_explicit(std::string(fname));
|
2013-12-28 20:04:56 +00:00
|
|
|
}
|
|
|
|
|
2013-12-28 20:24:13 +00:00
|
|
|
bool import(char const * fname) {
|
2014-06-16 23:37:46 +00:00
|
|
|
return import_explicit(find_file(std::string(fname)));
|
2013-12-28 20:04:56 +00:00
|
|
|
}
|
2013-11-07 21:56:04 +00:00
|
|
|
};
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
script_state to_script_state(lua_State * L) {
|
|
|
|
return script_state(*script_state::imp::get_weak_ptr(L));
|
2013-11-15 23:55:15 +00:00
|
|
|
}
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
script_state::script_state():
|
2013-12-24 19:32:09 +00:00
|
|
|
m_ptr(std::make_shared<imp>()) {
|
2013-11-15 23:55:15 +00:00
|
|
|
m_ptr->save_weak_ptr(m_ptr);
|
|
|
|
}
|
|
|
|
|
2013-11-30 08:44:31 +00:00
|
|
|
script_state::script_state(weak_ref const & r) {
|
|
|
|
if (r.expired())
|
|
|
|
throw exception("weak reference to script_state object has expired (i.e., it has been deleted)");
|
|
|
|
m_ptr = r.lock();
|
2013-11-07 21:56:04 +00:00
|
|
|
}
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
script_state::~script_state() {
|
2013-11-07 21:56:04 +00:00
|
|
|
}
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
void script_state::dofile(char const * fname) {
|
2013-11-07 21:56:04 +00:00
|
|
|
m_ptr->dofile(fname);
|
|
|
|
}
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
void script_state::dostring(char const * str) {
|
2013-11-07 21:56:04 +00:00
|
|
|
m_ptr->dostring(str);
|
|
|
|
}
|
2013-11-10 18:12:43 +00:00
|
|
|
|
2013-12-28 20:24:13 +00:00
|
|
|
bool script_state::import(char const * str) {
|
|
|
|
return m_ptr->import(str);
|
2013-12-23 05:27:12 +00:00
|
|
|
}
|
|
|
|
|
2013-12-28 20:24:13 +00:00
|
|
|
bool script_state::import_explicit(char const * str) {
|
|
|
|
return m_ptr->import_explicit(str);
|
2013-12-28 20:04:56 +00:00
|
|
|
}
|
|
|
|
|
2013-11-27 22:57:33 +00:00
|
|
|
lua_State * script_state::get_state() {
|
2013-11-27 17:25:56 +00:00
|
|
|
return m_ptr->m_state;
|
|
|
|
}
|
|
|
|
|
2013-11-14 22:13:06 +00:00
|
|
|
static int check_interrupted(lua_State *) { // NOLINT
|
2013-11-14 18:04:32 +00:00
|
|
|
check_interrupted();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sleep(lua_State * L) {
|
2013-11-27 21:25:06 +00:00
|
|
|
sleep_for(luaL_checkinteger(L, 1));
|
2013-11-14 18:04:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-30 08:14:33 +00:00
|
|
|
static int yield(lua_State * L) {
|
|
|
|
check_interrupted();
|
|
|
|
int status = lua_pushthread(L);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
if (status != 1) {
|
|
|
|
return lua_yield(L, 0);
|
|
|
|
} else {
|
|
|
|
// main thread cannot yield
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-23 05:27:12 +00:00
|
|
|
static int import(lua_State * L) {
|
|
|
|
std::string fname = luaL_checkstring(L, 1);
|
|
|
|
script_state s = to_script_state(L);
|
2014-06-18 04:38:10 +00:00
|
|
|
s.import(fname.c_str());
|
2013-12-23 05:27:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-18 04:38:10 +00:00
|
|
|
void open_extra(lua_State * L) {
|
2013-11-14 18:04:32 +00:00
|
|
|
SET_GLOBAL_FUN(check_interrupted, "check_interrupted");
|
|
|
|
SET_GLOBAL_FUN(sleep, "sleep");
|
2013-11-30 08:14:33 +00:00
|
|
|
SET_GLOBAL_FUN(yield, "yield");
|
2014-06-18 04:38:10 +00:00
|
|
|
SET_GLOBAL_FUN(import, "import");
|
2013-11-27 03:24:18 +00:00
|
|
|
}
|
2013-11-07 23:19:26 +00:00
|
|
|
}
|