Skip to content

Instantly share code, notes, and snippets.

@NotMyWing
Last active April 21, 2022 02:04
Show Gist options
  • Save NotMyWing/a66f8b1c2ae47b38424ff543c31d4239 to your computer and use it in GitHub Desktop.
Save NotMyWing/a66f8b1c2ae47b38424ff543c31d4239 to your computer and use it in GitHub Desktop.
Leveret Lua Evaluation Commons
const commons = {
initialize: function (ctx) {
const newCtx = {};
// Create a shallow copy of the provided context.
for(var key in ctx) {
newCtx[key] = ctx[key];
}
// Since fengari-web is primarily a browser library,
// we need to shim browser-specific things. Temporarily, at least.
newCtx.window = {
dispatchEvent: () => { }
}
// Fetch and evaluate Fengari.
const fengariSrc = http.request("https://github.com/fengari-lua/fengari-web/releases/download/v0.1.4/fengari-web.js").data
new Function("window = this.window;" + fengariSrc).call({ window: newCtx });
this.fengari = newCtx.fengari;
},
createLuaContext: function () {
if (!this.fengari) this.initialize();
const L = this.fengari.lauxlib.luaL_newstate();
this.fengari.lualib.luaL_openlibs(L);
this.fengari.interop.luaopen_js(L);
this.fengari.lua.lua_setglobal(L, "js");
return L;
},
replacePrintFunction: function (L, callback) {
if (!this.fengari) this.initialize();
const buffer = [];
const lua = this.fengari.lua;
// Printer function.
// Taken directly from the Fengari source.
let print = (L) => {
let n = lua.lua_gettop(L);
lua.lua_getglobal(L, this.fengari.to_luastring("tostring", true));
let linebuf = [];
for (let i = 1; i <= n; i++) {
lua.lua_pushvalue(L, -1);
lua.lua_pushvalue(L, i);
lua.lua_call(L, 1, 1);
let s = lua.lua_tolstring(L, -1);
if (s === null)
return this.fengari.lauxlib.luaL_error(L,
this.fengari.to_luastring("'tostring' must return a string to 'print'"));
if (i > 1) linebuf.push("\t");
linebuf.push(this.fengari.to_jsstring(s));
lua.lua_pop(L, 1);
}
callback(linebuf.join(""));
return 0;
};
// Finally, replace "print" within the context.
lua.lua_pushjsfunction(L, print);
lua.lua_setglobal(L, "print");
return buffer
},
parseInput: function (input) {
let code, args;
// Parse code block if exists.
let parsed = input.match(/^(.*?)`{3}([\S]+)?\n([\s\S]+)`{3}$/mi);
if (parsed) {
// Args precede the code block.
args = parsed[1].trim();
code = parsed[3];
} // Otherwise treat the entire input as code.
else code = input;
return { code, args }
},
runLua: function (L, code) {
if (!this.fengari) this.initialize();
const lua = this.fengari.lua;
const result = this.fengari.lauxlib
.luaL_loadstring(L, this.fengari.to_luastring(code));
if (result === 0) {
if (lua.lua_gettop(L) > 0) {
const type = lua.lua_type(L, -1);
if (type == lua.LUA_TFUNCTION) {
lua.lua_call(L, 0, 1);
}
}
}
},
getStackTrace: function (L) {
const lua = this.fengari.lua;
const buf = [];
const top = lua.lua_gettop(L);
const bottom = 1;
lua.lua_getglobal(L, "tostring");
for (let i = top; i >= bottom; i--) {
lua.lua_pushvalue(L, -1);
lua.lua_pushvalue(L, i);
lua.lua_pcall(L, 1, 1, 0);
const str = this.fengari.interop.tojs(L, -1);
if (str) {
buf.push(str);
} else {
buf.push(this.fengari.lauxlib.luaL_typename(L, i));
}
lua.lua_pop(L, 1);
}
lua.lua_pop(L, 1);
return buf;
}
}
return commons;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment