Refactor and overhaul luajit crate
This commit is contained in:
parent
7768c5ec56
commit
1808bee82a
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1053,6 +1053,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"globset",
|
||||
"luaffi",
|
||||
"luaify",
|
||||
"luajit",
|
||||
"sysexits",
|
||||
"tempfile",
|
||||
@ -1168,7 +1169,6 @@ dependencies = [
|
||||
"bstr",
|
||||
"luaffi",
|
||||
"luajit-sys",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -18,6 +18,7 @@ net = ["tokio/net", "tokio/io-util"]
|
||||
derive_more = { version = "2.0.1", features = ["full"] }
|
||||
globset = { version = "0.4.16", optional = true }
|
||||
luaffi = { path = "../luaffi" }
|
||||
luaify = { path = "../luaify" }
|
||||
luajit = { path = "../luajit" }
|
||||
sysexits = "0.9.0"
|
||||
tempfile = { version = "3.20.0", optional = true }
|
||||
|
@ -1,7 +1,8 @@
|
||||
#![doc(hidden)]
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use luaffi::{Module, Registry};
|
||||
use luajit::{Chunk, State};
|
||||
use luaify::luaify_chunk;
|
||||
use luajit::{Chunk, Index, NewTable, State};
|
||||
use std::rc::Rc;
|
||||
use tokio::{
|
||||
task::{JoinHandle, LocalSet, futures::TaskLocalFuture, spawn_local},
|
||||
@ -13,6 +14,7 @@ pub type ErrorFn = dyn Fn(&luajit::Error);
|
||||
pub struct Builder {
|
||||
registry: Registry,
|
||||
report_err: Rc<ErrorFn>,
|
||||
prohibit_globals: bool,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
@ -23,6 +25,7 @@ impl Builder {
|
||||
Some(trace) => eprintln!("unhandled lua error: {err}\n{trace}"),
|
||||
None => eprintln!("unhandled lua error: {err}"),
|
||||
}),
|
||||
prohibit_globals: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,19 +38,42 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn prohibit_globals(&mut self, enabled: bool) -> &mut Self {
|
||||
self.prohibit_globals = enabled;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn module<T: Module>(&mut self) -> &mut Self {
|
||||
self.registry.preload::<T>();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(&self) -> luajit::Result<Runtime> {
|
||||
let mut state = State::new()?;
|
||||
let chunk = Chunk::new(self.registry.build()).with_path("[luby]");
|
||||
state.eval(&chunk, 0, Some(0))?;
|
||||
|
||||
if self.prohibit_globals {
|
||||
let mut s = state.guard();
|
||||
s.eval(
|
||||
&Chunk::new(luaify_chunk!({
|
||||
return |self, key, value| {
|
||||
error(("undeclared local variable '%s'").format(key), 2);
|
||||
};
|
||||
})),
|
||||
0,
|
||||
Some(1),
|
||||
)
|
||||
.unwrap();
|
||||
s.push(NewTable::new());
|
||||
(s.push("__index"), s.push_idx(-3), s.set(-3));
|
||||
(s.push("__newindex"), s.push_idx(-3), s.set(-3));
|
||||
s.set_metatable(Index::globals());
|
||||
}
|
||||
|
||||
Ok(Runtime {
|
||||
cx: Context {
|
||||
state: {
|
||||
let mut s = State::new()?;
|
||||
s.eval(Chunk::new(self.registry.build()).path("[luby]"), 0, 0)?;
|
||||
s
|
||||
},
|
||||
state,
|
||||
report_err: self.report_err.clone(),
|
||||
},
|
||||
tasks: LocalSet::new(),
|
||||
@ -97,7 +123,7 @@ pub struct Context {
|
||||
impl Context {
|
||||
pub fn new_thread(&self) -> Self {
|
||||
Self {
|
||||
state: self.state.new_thread(),
|
||||
state: State::new_thread(&self.state),
|
||||
report_err: self.report_err.clone(),
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ use luaffi::{
|
||||
marker::{function, many},
|
||||
metatype,
|
||||
};
|
||||
use luajit::LUA_MULTRET;
|
||||
use std::{cell::RefCell, ffi::c_int, time::Duration};
|
||||
use tokio::{task::JoinHandle, time::sleep};
|
||||
|
||||
@ -59,12 +58,12 @@ impl lb_tasklib {
|
||||
extern "Lua-C" fn __spawn(spawn_ref: c_int, handle_ref: c_int) -> lb_task {
|
||||
let handle = spawn(async move |cx| {
|
||||
// SAFETY: handle_ref is always unique, created in Self::spawn above.
|
||||
let state = unsafe { cx.new_ref_unchecked(spawn_ref) };
|
||||
let state = unsafe { luajit::Ref::from_raw(cx, spawn_ref) };
|
||||
let mut s = cx.guard();
|
||||
s.resize(0);
|
||||
s.push(state); // this drops the state table ref, but the table is still on the stack
|
||||
let narg = s.unpack(1, 1, None) - 1; // unpack the function and its args from the state table
|
||||
match s.call_async(narg, LUA_MULTRET).await {
|
||||
match s.call_async(narg, None).await {
|
||||
Ok(nret) => {
|
||||
s.pack(1, nret); // pack the return values back into the state table
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
//! # luaify
|
||||
//!
|
||||
//! A Rust for generating Lua code from Rust syntax.
|
||||
use crate::{
|
||||
generate::{generate, generate_chunk},
|
||||
transform::{transform, transform_chunk},
|
||||
|
@ -16,4 +16,3 @@ bitflags = { version = "2.9.1", features = ["std"] }
|
||||
bstr = "1.12.0"
|
||||
luaffi = { path = "../luaffi" }
|
||||
luajit-sys = { path = "../luajit-sys" }
|
||||
thiserror = "2.0.12"
|
||||
|
File diff suppressed because it is too large
Load Diff
41
src/main.rs
41
src/main.rs
@ -1,4 +1,5 @@
|
||||
use clap::Parser;
|
||||
use luajit::Chunk;
|
||||
use mimalloc::MiMalloc;
|
||||
use owo_colors::OwoColorize;
|
||||
use std::{backtrace::Backtrace, fmt::Display, num::NonZero, panic, process, thread};
|
||||
@ -78,12 +79,21 @@ struct Args {
|
||||
#[clap(long, short = 'j', help_heading = "Runtime", value_name = "CMD=FLAGS")]
|
||||
jit: Vec<String>,
|
||||
|
||||
/// Allow global variables.
|
||||
#[clap(
|
||||
long,
|
||||
help_heading = "Runtime",
|
||||
value_name = "ENABLED",
|
||||
default_value_t = true
|
||||
)]
|
||||
allow_globals: bool,
|
||||
|
||||
/// Number of worker threads.
|
||||
#[clap(
|
||||
long,
|
||||
short = 'T',
|
||||
help_heading = "Runtime",
|
||||
value_name = "THREADS",
|
||||
value_name = "COUNT",
|
||||
default_value_t = Self::threads()
|
||||
)]
|
||||
threads: NonZero<usize>,
|
||||
@ -92,14 +102,14 @@ struct Args {
|
||||
#[clap(
|
||||
long,
|
||||
help_heading = "Runtime",
|
||||
value_name = "THREADS",
|
||||
value_name = "COUNT",
|
||||
default_value_t = Self::blocking_threads()
|
||||
)]
|
||||
blocking_threads: NonZero<usize>,
|
||||
|
||||
/// Enable tokio-console integration.
|
||||
#[cfg(feature = "tokio-console")]
|
||||
#[clap(long, help_heading = "Debugging")]
|
||||
#[clap(long, help_heading = "Debugging", value_name = "ENABLED")]
|
||||
enable_console: bool,
|
||||
|
||||
/// tokio-console publish address.
|
||||
@ -229,27 +239,32 @@ fn init_lua(args: &Args) -> lb::runtime::Runtime {
|
||||
print!("{}", rt.registry()); // for cdef debugging
|
||||
}
|
||||
|
||||
rt.unhandled_error(error_cb).build().unwrap()
|
||||
rt.unhandled_error(error_cb)
|
||||
.prohibit_globals(!args.allow_globals)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
for arg in args.jit.iter() {
|
||||
let mut s = rt.guard();
|
||||
let res = if let Some((cmd, flags)) = parse_jitlib_cmd(arg)
|
||||
&& let Ok(_) = s.require(format!("jit.{cmd}"), 1)
|
||||
&& let Ok(_) = s.require(format!("jit.{cmd}"), Some(1))
|
||||
{
|
||||
(s.push("start"), s.get(-2), s.push(flags));
|
||||
s.call(1, 0) // require("jit.{cmd}").start(flags)
|
||||
(s.push("start"), s.get(-2));
|
||||
s.push(flags);
|
||||
s.call(1, Some(0)) // require("jit.{cmd}").start(flags)
|
||||
} else {
|
||||
s.require("jit", 1).unwrap();
|
||||
s.require("jit", Some(1)).unwrap();
|
||||
match arg.as_str() {
|
||||
cmd @ ("on" | "off" | "flush") => {
|
||||
(s.push(cmd), s.get(-2));
|
||||
s.call(0, 0) // require("jit").[on/off/flush]()
|
||||
s.call(0, Some(0)) // require("jit").[on/off/flush]()
|
||||
}
|
||||
flags => {
|
||||
(s.push("opt"), s.get(-2));
|
||||
(s.push("start"), s.get(-2), s.push(flags));
|
||||
s.call(1, 0) // require("jit").opt.start(flags)
|
||||
(s.push("start"), s.get(-2));
|
||||
s.push(flags);
|
||||
s.call(1, Some(0)) // require("jit").opt.start(flags)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -282,9 +297,9 @@ async fn main_async(args: Args, cx: &mut lb::runtime::Context) -> ExitCode {
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(ref err) = cx.load(&luajit::Chunk::new(chunk).path(path)) {
|
||||
if let Err(ref err) = cx.load(&Chunk::new(chunk).with_path(path)) {
|
||||
cx.report_error(err);
|
||||
} else if let Err(ref err) = cx.call_async(0, 0).await {
|
||||
} else if let Err(ref err) = cx.call_async(0, Some(0)).await {
|
||||
cx.report_error(err);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ end
|
||||
|
||||
local function create_test(name, f, group)
|
||||
local test = { type = "test", name = name or "", group = group, state = "pending", f = f }
|
||||
local fenv = setmetatable({}, { __index = global })
|
||||
local fenv = setmetatable({}, { __index = global, __newindex = global })
|
||||
setfenv(f, fenv)
|
||||
return test
|
||||
end
|
||||
@ -45,7 +45,7 @@ local function create_group(name, f, parent)
|
||||
table.insert(group.items, item)
|
||||
return item
|
||||
end,
|
||||
}, { __index = global })
|
||||
}, { __index = global, __newindex = global })
|
||||
|
||||
setfenv(f, fenv)
|
||||
f(group)
|
||||
|
@ -10,14 +10,17 @@ fn main() -> ExitCode {
|
||||
let lua = {
|
||||
let mut rt = lb::runtime::Builder::new();
|
||||
luby::open(&mut rt);
|
||||
rt.unhandled_error(error_cb).build().unwrap()
|
||||
rt.unhandled_error(error_cb)
|
||||
.prohibit_globals(true)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let path = "tests/main.lua";
|
||||
let main = lua.spawn(async move |s| {
|
||||
if let Err(ref err) = s.load(Chunk::new(fs::read(path).unwrap()).path(path)) {
|
||||
if let Err(ref err) = s.load(&Chunk::new(fs::read(path).unwrap()).with_path(path)) {
|
||||
s.report_error(err);
|
||||
} else if let Err(ref err) = s.call_async(0, 1).await {
|
||||
} else if let Err(ref err) = s.call_async(0, Some(1)).await {
|
||||
s.report_error(err);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user