<commit_before>/*
 * Copyright (c) 2012-2017 <NAME> and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"
#include "device.h"
#include "error.h"
#include "log.h"
#include "lua_environment.h"
#include "lua_resource.h"
#include "lua_stack.h"
#include "resource_manager.h"
#include <stdarg.h>

namespace { const crown::log_internal::System LUA = { "Lua" }; }

namespace crown
{
extern void load_api(LuaEnvironment& env);

// When an error occurs, logs the error message and pauses the engine.
static int error_handler(lua_State* L)
{
	lua_getfield(L, LUA_GLOBALSINDEX, "debug");
	if (!lua_istable(L, -1))
	{
		lua_pop(L, 1);
		return 0;
	}

	lua_getfield(L, -1, "traceback");
	if (!lua_isfunction(L, -1))
	{
		lua_pop(L, 2);
		return 0;
	}

	lua_pushvalue(L, 1); // Pass error message
	lua_pushinteger(L, 2);
	lua_call(L, 2, 1); // Call debug.traceback

	loge(LUA, lua_tostring(L, -1)); // Print error message
	lua_pop(L, 1); // Remove error message from stack
	lua_pop(L, 1); // Remove debug.traceback from stack

	device()->pause();
	return 0;
}

// Redirects require to the resource manager.
static int require(lua_State* L)
{
	LuaStack stack(L);
	const LuaResource* lr = (LuaResource*)device()->_resource_manager->get(RESOURCE_TYPE_SCRIPT, stack.get_resource_id(1));
	luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "");
	return 1;
}

LuaEnvironment::LuaEnvironment()
	: L(NULL)
	, _vec3_used(0)
	, _quat_used(0)
	, _mat4_used(0)
{
	L = luaL_newstate();
	CE_ASSERT(L, "Unable to create lua state");
}

LuaEnvironment::~LuaEnvironment()
{
	lua_close(L);
}

void LuaEnvironment::load_libs()
{
	lua_gc(L, LUA_GCSTOP, 0);

	// Open default libraries
	luaL_openlibs(L);

	// Register crown libraries
	load_api(*this);

	// Register custom loader
	lua_getfield(L, LUA_GLOBALSINDEX, "package");
	lua_getfield(L, -1, "loaders");
	lua_remove(L, -2);

	int num_loaders = 0;
	lua_pushnil(L);
	while (lua_next(L, -2) != 0)
	{
		lua_pop(L, 1);
		num_loaders++;
	}
	lua_pushinteger(L, num_loaders + 1);
	lua_pushcfunction(L, require);
	lua_rawset(L, -3);
	lua_pop(L, 1);

	// Create metatable for lightuserdata
	lua_pushlightuserdata(L, 0);
	lua_getfield(L, LUA_REGISTRYINDEX, "Lightuserdata_mt");
	lua_setmetatable(L, -2);
	lua_pop(L, 1);

	// Ensure stack is clean
	CE_ASSERT(lua_gettop(L) == 0, "Stack not clean");

	lua_gc(L, LUA_GCRESTART, 0);
}

LuaStack LuaEnvironment::execute(const LuaResource* lr)
{
	LuaStack stack(L);
	lua_pushcfunction(L, error_handler);
	luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "<unknown>");
	lua_pcall(L, 0, 1, -2);
	lua_pop(L, 1);
	return stack;
}

LuaStack LuaEnvironment::execute_string(const char* s)
{
	LuaStack stack(L);
	lua_pushcfunction(L, error_handler);
	luaL_loadstring(L, s);
	lua_pcall(L, 0, 0, -2);
	lua_pop(L, 1);
	return stack;
}

void LuaEnvironment::add_module_function(const char* module, const char* name, const lua_CFunction func)
{
	luaL_Reg entry[2];
	entry[0].name = name;
	entry[0].func = func;
	entry[1].name = NULL;
	entry[1].func = NULL;

	luaL_register(L, module, entry);
	lua_pop(L, 1);
}

void LuaEnvironment::add_module_function(const char* module, const char* name, const char* func)
{
	// Create module if it does not exist
	luaL_Reg entry;
	entry.name = NULL;
	entry.func = NULL;
	luaL_register(L, module, &entry);
	lua_pop(L, 1);

	lua_getglobal(L, module);
	lua_getglobal(L, func);
	lua_setfield(L, -2, name);
	lua_setglobal(L, module);
}

void LuaEnvironment::set_module_constructor(const char* module, const lua_CFunction func)
{
	// Create module if it does not exist
	luaL_Reg entry;
	entry.name = NULL;
	entry.func = NULL;
	luaL_register(L, module, &entry);
	lua_pop(L, 1);

	// Create dummy tables to be used as module's metatable
	lua_createtable(L, 0, 1);
	lua_pushstring(L, "__call");
	lua_pushcfunction(L, func);
	lua_settable(L, 1); // dummy.__call = func
	lua_getglobal(L, module);
	lua_pushvalue(L, -2); // Duplicate dummy metatable
	lua_setmetatable(L, -2); // setmetatable(module, dummy)
	lua_pop(L, -1);
}

void LuaEnvironment::call_global(const char* func, u8 argc, ...)
{
	CE_ENSURE(NULL != func);

	LuaStack stack(L);

	va_list vl;
	va_start(vl, argc);
<commit_msg>Revert "Create module if it does not exist"<commit_after>/*
 * Copyright (c) 2012-2017 <NAME> and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"
#include "device.h"
#include "error.h"
#include "log.h"
#include "lua_environment.h"
#include "lua_resource.h"
#include "lua_stack.h"
#include "resource_manager.h"
#include <stdarg.h>

namespace { const crown::log_internal::System LUA = { "Lua" }; }

namespace crown
{
extern void load_api(LuaEnvironment& env);

// When an error occurs, logs the error message and pauses the engine.
static int error_handler(lua_State* L)
{
	lua_getfield(L, LUA_GLOBALSINDEX, "debug");
	if (!lua_istable(L, -1))
	{
		lua_pop(L, 1);
		return 0;
	}

	lua_getfield(L, -1, "traceback");
	if (!lua_isfunction(L, -1))
	{
		lua_pop(L, 2);
		return 0;
	}

	lua_pushvalue(L, 1); // Pass error message
	lua_pushinteger(L, 2);
	lua_call(L, 2, 1); // Call debug.traceback

	loge(LUA, lua_tostring(L, -1)); // Print error message
	lua_pop(L, 1); // Remove error message from stack
	lua_pop(L, 1); // Remove debug.traceback from stack

	device()->pause();
	return 0;
}

// Redirects require to the resource manager.
static int require(lua_State* L)
{
	LuaStack stack(L);
	const LuaResource* lr = (LuaResource*)device()->_resource_manager->get(RESOURCE_TYPE_SCRIPT, stack.get_resource_id(1));
	luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "");
	return 1;
}

LuaEnvironment::LuaEnvironment()
	: L(NULL)
	, _vec3_used(0)
	, _quat_used(0)
	, _mat4_used(0)
{
	L = luaL_newstate();
	CE_ASSERT(L, "Unable to create lua state");
}

LuaEnvironment::~LuaEnvironment()
{
	lua_close(L);
}

void LuaEnvironment::load_libs()
{
	lua_gc(L, LUA_GCSTOP, 0);

	// Open default libraries
	luaL_openlibs(L);

	// Register crown libraries
	load_api(*this);

	// Register custom loader
	lua_getfield(L, LUA_GLOBALSINDEX, "package");
	lua_getfield(L, -1, "loaders");
	lua_remove(L, -2);

	int num_loaders = 0;
	lua_pushnil(L);
	while (lua_next(L, -2) != 0)
	{
		lua_pop(L, 1);
		num_loaders++;
	}
	lua_pushinteger(L, num_loaders + 1);
	lua_pushcfunction(L, require);
	lua_rawset(L, -3);
	lua_pop(L, 1);

	// Create metatable for lightuserdata
	lua_pushlightuserdata(L, 0);
	lua_getfield(L, LUA_REGISTRYINDEX, "Lightuserdata_mt");
	lua_setmetatable(L, -2);
	lua_pop(L, 1);

	// Ensure stack is clean
	CE_ASSERT(lua_gettop(L) == 0, "Stack not clean");

	lua_gc(L, LUA_GCRESTART, 0);
}

LuaStack LuaEnvironment::execute(const LuaResource* lr)
{
	LuaStack stack(L);
	lua_pushcfunction(L, error_handler);
	luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "<unknown>");
	lua_pcall(L, 0, 1, -2);
	lua_pop(L, 1);
	return stack;
}

LuaStack LuaEnvironment::execute_string(const char* s)
{
	LuaStack stack(L);
	lua_pushcfunction(L, error_handler);
	luaL_loadstring(L, s);
	lua_pcall(L, 0, 0, -2);
	lua_pop(L, 1);
	return stack;
}

void LuaEnvironment::add_module_function(const char* module, const char* name, const lua_CFunction func)
{
	luaL_newmetatable(L, module);
	luaL_Reg entry[2];

	entry[0].name = name;
	entry[0].func = func;
	entry[1].name = NULL;
	entry[1].func = NULL;

	luaL_register(L, NULL, entry);
	lua_setglobal(L, module);
	lua_pop(L, -1);
}

void LuaEnvironment::add_module_function(const char* module, const char* name, const char* func)
{
	luaL_newmetatable(L, module);
	lua_getglobal(L, func);
	lua_setfield(L, -2, name);
	lua_setglobal(L, module);
}

void LuaEnvironment::set_module_constructor(const char* module, const lua_CFunction func)
{
	// Create dummy tables to be used as module's metatable
	lua_createtable(L, 0, 1);
	lua_pushstring(L, "__call");
	lua_pushcfunction(L, func);
	lua_settable(L, 1); // dummy.__call = func
	lua_getglobal(L, module);
	lua_pushvalue(L, -2); // Duplicate dummy metatable
	lua_setmetatable(L, -2); // setmetatable(module, dummy)
	lua_pop(L, -1);
}

void LuaEnvironment::call_global(const char* func, u8 argc, ...)
{
	CE_ENSURE(NULL != func);

	LuaStack stack(L);

	va_list vl;
	va_start(vl, argc);

{'fraction_non_alphanumeric': 0.15387409200968524, 'fraction_numerical': 0.01719128329297821, 'mean_word_length': 5.08321060382916, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5367091', 'n_tokens_mistral': 3447, 'n_tokens_neox': 3298, 'n_words': 749}