use std::cell::RefCell;
use std::rc::Rc;
mod basic;
mod coroutine;
mod debug;
pub(super) mod dump;
mod file;
mod io;
mod math;
pub(super) mod modules;
mod os;
mod string;
mod table;
mod utf8;
use crate::{
value::{CallResult, FuncBuiltin, FuncBuiltinRaw, FuncDef, Table},
Result, Value, LUA_VERSION, VM,
};
pub struct StdLib(Rc<RefCell<Table>>);
impl StdLib {
fn new() -> Result<Self> {
let tbl = Rc::new(RefCell::new(Table::default()));
let package = Rc::new(RefCell::new(Table::default()));
let loaded = Rc::new(RefCell::new(Table::default()));
package
.borrow_mut()
.set(Value::str("loaded"), Value::Table(loaded.clone()))?;
loaded
.borrow_mut()
.set(Value::str("package"), Value::Table(package.clone()))?;
tbl.borrow_mut()
.set(Value::str("package"), Value::Table(package.clone()))?;
Ok(Self(tbl))
}
pub fn build() -> Result<Rc<RefCell<Table>>> {
let mut stdlib = Self::new()?;
let (major, minor) = LUA_VERSION;
stdlib
.root()
.cons(
"_VERSION",
Value::string(format!("Lua {}.{}", major, minor)),
)?
.cons("_ENV", Value::Table(stdlib.0.clone()))?
.cons("_G", Value::Table(stdlib.0.clone()))?
.cons("arg", Value::Table(Rc::new(RefCell::new(Table::default()))))?;
basic::module(&mut stdlib)?;
coroutine::module(&mut stdlib)?;
debug::module(&mut stdlib)?;
io::module(&mut stdlib)?;
math::module(&mut stdlib)?;
modules::module(&mut stdlib)?;
os::module(&mut stdlib)?;
string::module(&mut stdlib)?;
table::module(&mut stdlib)?;
utf8::module(&mut stdlib)?;
Ok(stdlib.0)
}
pub fn root(&mut self) -> Module {
Module {
name: "",
tbl: self.0.clone(),
}
}
pub fn module(&mut self, module: &'static str) -> Module {
let name = Value::str(module);
let val = self.0.borrow().get(&name);
match val {
Value::Table(tbl) => Module {
name: module,
tbl: tbl.clone(),
},
_ => {
let tbl = Rc::new(RefCell::new(Table::default()));
self.0
.borrow_mut()
.set(name.clone(), Value::Table(tbl.clone()))
.unwrap();
let pkg = self
.0
.borrow()
.get(&Value::str("package"))
.to_table()
.unwrap();
let loaded = pkg.borrow().get(&Value::str("loaded")).to_table().unwrap();
loaded
.borrow_mut()
.set(name, Value::Table(tbl.clone()))
.unwrap();
Module { name: module, tbl }
}
}
}
}
#[derive(Default)]
pub struct Module {
name: &'static str,
tbl: Rc<RefCell<Table>>,
}
impl Module {
pub fn cons(&mut self, name: &'static str, cons: Value) -> Result<&mut Self> {
self.tbl.borrow_mut().set(Value::str(name), cons)?;
Ok(self)
}
pub fn func(
&mut self,
name: &'static str,
func: impl Fn(&mut VM) -> Result<Value> + 'static,
) -> Result<&mut Self> {
self.tbl.borrow_mut().set(
Value::str(name),
Value::Func(Rc::new(FuncDef::Builtin(FuncBuiltin {
module: self.name,
name,
func: Rc::new(func),
}))),
)?;
Ok(self)
}
pub fn func_raw(
&mut self,
name: &'static str,
func: impl Fn(&mut VM) -> Result<CallResult> + 'static,
) -> Result<&mut Self> {
self.tbl.borrow_mut().set(
Value::str(name),
Value::Func(Rc::new(FuncDef::BuiltinRaw(FuncBuiltinRaw {
module: self.name,
name,
func: Rc::new(func),
}))),
)?;
Ok(self)
}
}