Add yuescript support
This commit is contained in:
parent
d3b48cf2f3
commit
f9a80842de
10
Cargo.toml
10
Cargo.toml
|
@ -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"]
|
||||
|
|
|
@ -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
31
examples/yuescript.rs
Normal 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
103
examples/yuescript_repl.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
8
src/ffi/yuescript/mod.rs
Normal 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;
|
||||
}
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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"`
|
||||
|
|
Loading…
Reference in a new issue