Add yuescript support

This commit is contained in:
Tarik02 2022-07-22 16:01:55 +03:00
parent d3b48cf2f3
commit f9a80842de
8 changed files with 195 additions and 2 deletions

View file

@ -39,6 +39,7 @@ async = ["futures-core", "futures-task", "futures-util"]
send = []
serialize = ["serde", "erased-serde"]
macros = ["mlua_derive/macros"]
yuescript = ["yuescript-src"]
[dependencies]
mlua_derive = { version = "=0.8.0", optional = true, path = "mlua_derive" }
@ -59,6 +60,7 @@ pkg-config = { version = "0.3.17" }
lua-src = { version = ">= 544.0.0, < 550.0.0", optional = true }
luajit-src = { version = ">= 210.4.0, < 220.0.0", optional = true }
luau0-src = { version = "0.3.6", optional = true }
yuescript-src = { version = "0.13.6", optional = true }
[dev-dependencies]
rustyline = "9.0"
@ -106,3 +108,11 @@ required-features = ["serialize"]
[[example]]
name = "userdata"
required-features = ["macros"]
[[example]]
name = "yuescript"
required-features = ["yuescript"]
[[example]]
name = "yuescript_repl"
required-features = ["yuescript"]

View file

@ -108,8 +108,32 @@ fn main() {
#[cfg(all(feature = "luau", feature = "module"))]
compile_error!("Luau does not support module mode");
#[cfg(any(not(feature = "module"), target_os = "windows"))]
find::probe_lua();
#[cfg(all(feature = "yuescript", feature = "module"))]
compile_error!("Yuescript does not support module mode");
#[cfg(all(feature = "yuescript", feature = "luau"))]
compile_error!("Yuescript does not support LuaU");
#[cfg(not(feature = "module"))]
{
#[cfg(not(target_os = "windows"))]
let include_dir = find::probe_lua();
#[cfg(target_os = "windows")]
let include_dir: Option<PathBuf> = None;
let _ = include_dir;
#[cfg(feature = "yuescript")]
{
let mut yuescript = yuescript_src::Build::new();
if let Some(include_dir) = include_dir {
yuescript.include_dirs(vec![include_dir]);
}
yuescript.build();
};
}
println!("cargo:rerun-if-changed=build");
}

31
examples/yuescript.rs Normal file
View file

@ -0,0 +1,31 @@
use mlua::{Function, Lua, LuaOptions, MultiValue, Result, StdLib, Table, Value};
fn main() -> Result<()> {
let lua = Lua::new_with(StdLib::ALL_SAFE | StdLib::YUE, LuaOptions::new())?;
let source = r#"
f = ->
print "hello world"
f!
"#;
let yue = lua
.globals()
.get::<_, Function>("require")?
.call::<_, Table>("yue")?;
let config = lua.create_table()?;
config.set("implicit_return_root", true)?;
config.set("reserve_line_number", true)?;
config.set("lint_global", true)?;
let res = yue
.get::<_, Function>("to_lua")?
.call::<_, MultiValue>(source)?;
if let Value::String(code) = res.get(0).unwrap() {
println!("{:?}", code.to_str());
} else {
println!("Result code is not string");
}
Ok(())
}

103
examples/yuescript_repl.rs Normal file
View file

@ -0,0 +1,103 @@
use mlua::{Error, Function, Lua, LuaOptions, MultiValue, Result, StdLib, Table, Value};
use rustyline::Editor;
fn get_yue(lua: &Lua) -> Result<Table> {
Ok(lua
.globals()
.get::<_, Table>("package")?
.get::<_, Table>("loaded")?
.get::<_, Table>("yue")?)
}
fn yue_options(lua: &Lua, line_offset: i32) -> Result<Table> {
let options = lua.create_table()?;
options.set("lint_global", false)?;
options.set("implicit_return_root", true)?;
options.set("reserve_line_number", true)?;
options.set("space_over_tab", false)?;
options.set("same_module", true)?;
options.set("line_offset", line_offset)?;
Ok(options)
}
fn load_yue<'a>(lua: &'a Lua, source: &String) -> Result<Function<'a>> {
let mut res = get_yue(lua)?
.get::<_, Function>("loadstring")?
.call::<_, MultiValue>((
Value::String(lua.create_string(format!("global *\n{}", source).as_str())?),
Value::String(lua.create_string("=(repl)")?),
Value::Table(yue_options(lua, -1)?),
))?;
match res.pop_front() {
Some(Value::Function(chunk)) => Ok(chunk),
_ => match res.pop_front() {
Some(Value::String(message)) => Err(Error::SyntaxError {
message: message.to_str()?.into(),
incomplete_input: false,
}),
_ => Err(Error::SyntaxError {
message: "Compilation failed".into(),
incomplete_input: false,
}),
},
}
}
fn main() -> Result<()> {
let lua = Lua::new_with(StdLib::ALL_SAFE | StdLib::YUE, LuaOptions::new())?;
let mut editor = Editor::<()>::new();
loop {
let mut line = String::new();
let mut is_multi_line = false;
loop {
match editor.readline(if is_multi_line { ">> " } else { "> " }) {
Ok(input) => match input.as_str() {
"$" if !is_multi_line => is_multi_line = true,
"" if is_multi_line => is_multi_line = false,
_ => {
line.push_str(&input);
if is_multi_line {
line.push('\n');
}
}
},
Err(_) => return Ok(()),
}
if is_multi_line {
continue;
}
match load_yue(&lua, &line) {
Ok(function) => {
editor.add_history_entry(line);
match function.call::<_, MultiValue>(()) {
Ok(values) => {
println!(
"{}",
values
.iter()
.map(|value| format!("{:?}", value))
.collect::<Vec<_>>()
.join("\t")
);
}
Err(e) => {
eprintln!("error: {}", e);
break;
}
}
break;
}
Err(e) => {
eprintln!("error: {}", e);
break;
}
}
}
}
}

View file

@ -19,6 +19,9 @@ pub use lua51::*;
#[cfg(feature = "luau")]
pub use luau::*;
#[cfg(feature = "yuescript")]
pub use yuescript::*;
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
pub const LUA_MAX_UPVALUES: c_int = 255;
@ -99,3 +102,6 @@ pub mod lua51;
#[cfg(feature = "luau")]
pub mod luau;
#[cfg(feature = "yuescript")]
pub mod yuescript;

8
src/ffi/yuescript/mod.rs Normal file
View file

@ -0,0 +1,8 @@
use super::lua::lua_State;
use std::os::raw::c_int;
pub const LUA_YUELIBNAME: &str = "yue";
extern "C" {
pub fn luaopen_yue(L: *mut lua_State) -> c_int;
}

View file

@ -3252,6 +3252,12 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) -> Result<
}
}
#[cfg(feature = "yuescript")]
if libs.contains(StdLib::YUE) {
requiref(state, ffi::LUA_YUELIBNAME, ffi::luaopen_yue, 1)?;
ffi::lua_pop(state, 1);
}
Ok(())
}

View file

@ -49,6 +49,11 @@ impl StdLib {
#[cfg_attr(docsrs, doc(cfg(feature = "luajit")))]
pub const JIT: StdLib = StdLib(1 << 9);
/// Requires `feature = "yuescript"`
#[cfg(any(feature = "yuescript", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "yuescript")))]
pub const YUE: StdLib = StdLib(1 << 10);
/// (**unsafe**) [`ffi`](http://luajit.org/ext_ffi.html) library
///
/// Requires `feature = "luajit"`