mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Add back luau builtin
This commit is contained in:
parent
73361d5a52
commit
d6dbe5c861
3 changed files with 160 additions and 0 deletions
39
src/lune/builtins/luau/mod.rs
Normal file
39
src/lune/builtins/luau/mod.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use mlua::prelude::*;
|
||||
|
||||
use crate::lune::util::TableBuilder;
|
||||
|
||||
mod options;
|
||||
use options::{LuauCompileOptions, LuauLoadOptions};
|
||||
|
||||
const BYTECODE_ERROR_BYTE: u8 = 0;
|
||||
|
||||
pub fn create(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("compile", compile_source)?
|
||||
.with_function("load", load_source)?
|
||||
.build_readonly()
|
||||
}
|
||||
|
||||
fn compile_source<'lua>(
|
||||
lua: &'lua Lua,
|
||||
(source, options): (LuaString<'lua>, LuauCompileOptions),
|
||||
) -> LuaResult<LuaString<'lua>> {
|
||||
let bytecode = options.into_compiler().compile(source);
|
||||
|
||||
match bytecode.first() {
|
||||
Some(&BYTECODE_ERROR_BYTE) => Err(LuaError::RuntimeError(
|
||||
String::from_utf8_lossy(&bytecode).into_owned(),
|
||||
)),
|
||||
Some(_) => lua.create_string(bytecode),
|
||||
None => panic!("Compiling resulted in empty bytecode"),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_source<'lua>(
|
||||
lua: &'lua Lua,
|
||||
(source, options): (LuaString<'lua>, LuauLoadOptions),
|
||||
) -> LuaResult<LuaFunction<'lua>> {
|
||||
lua.load(source.as_bytes())
|
||||
.set_name(options.debug_name)
|
||||
.into_function()
|
||||
}
|
116
src/lune/builtins/luau/options.rs
Normal file
116
src/lune/builtins/luau/options.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
use mlua::prelude::*;
|
||||
use mlua::Compiler as LuaCompiler;
|
||||
|
||||
const DEFAULT_DEBUG_NAME: &str = "luau.load(...)";
|
||||
|
||||
pub struct LuauCompileOptions {
|
||||
pub(crate) optimization_level: u8,
|
||||
pub(crate) coverage_level: u8,
|
||||
pub(crate) debug_level: u8,
|
||||
}
|
||||
|
||||
impl LuauCompileOptions {
|
||||
pub fn into_compiler(self) -> LuaCompiler {
|
||||
LuaCompiler::default()
|
||||
.set_optimization_level(self.optimization_level)
|
||||
.set_coverage_level(self.coverage_level)
|
||||
.set_debug_level(self.debug_level)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LuauCompileOptions {
|
||||
fn default() -> Self {
|
||||
// NOTE: This is the same as LuaCompiler::default() values, but they are
|
||||
// not accessible from outside of mlua so we need to recreate them here.
|
||||
Self {
|
||||
optimization_level: 1,
|
||||
coverage_level: 0,
|
||||
debug_level: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for LuauCompileOptions {
|
||||
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
|
||||
Ok(match value {
|
||||
LuaValue::Nil => Self::default(),
|
||||
LuaValue::Table(t) => {
|
||||
let mut options = Self::default();
|
||||
|
||||
let get_and_check = |name: &'static str| -> LuaResult<Option<u8>> {
|
||||
match t.get(name)? {
|
||||
Some(n @ (0 | 1 | 2)) => Ok(Some(n)),
|
||||
Some(n) => Err(LuaError::runtime(format!(
|
||||
"'{name}' must be one of: 0, 1, or 2 - got {n}"
|
||||
))),
|
||||
None => Ok(None),
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(optimization_level) = get_and_check("optimizationLevel")? {
|
||||
options.optimization_level = optimization_level;
|
||||
}
|
||||
if let Some(coverage_level) = get_and_check("coverageLevel")? {
|
||||
options.coverage_level = coverage_level;
|
||||
}
|
||||
if let Some(debug_level) = get_and_check("debugLevel")? {
|
||||
options.debug_level = debug_level;
|
||||
}
|
||||
|
||||
options
|
||||
}
|
||||
_ => {
|
||||
return Err(LuaError::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "CompileOptions",
|
||||
message: Some(format!(
|
||||
"Invalid compile options - expected table, got {}",
|
||||
value.type_name()
|
||||
)),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LuauLoadOptions {
|
||||
pub(crate) debug_name: String,
|
||||
}
|
||||
|
||||
impl Default for LuauLoadOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
debug_name: DEFAULT_DEBUG_NAME.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for LuauLoadOptions {
|
||||
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
|
||||
Ok(match value {
|
||||
LuaValue::Nil => Self::default(),
|
||||
LuaValue::Table(t) => {
|
||||
let mut options = Self::default();
|
||||
|
||||
if let Some(debug_name) = t.get("debugName")? {
|
||||
options.debug_name = debug_name;
|
||||
}
|
||||
|
||||
options
|
||||
}
|
||||
LuaValue::String(s) => Self {
|
||||
debug_name: s.to_string_lossy().to_string(),
|
||||
},
|
||||
_ => {
|
||||
return Err(LuaError::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "LoadOptions",
|
||||
message: Some(format!(
|
||||
"Invalid load options - expected string or table, got {}",
|
||||
value.type_name()
|
||||
)),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2,11 +2,13 @@ use std::str::FromStr;
|
|||
|
||||
use mlua::prelude::*;
|
||||
|
||||
mod luau;
|
||||
mod stdio;
|
||||
mod task;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum LuneBuiltin {
|
||||
Luau,
|
||||
Task,
|
||||
Stdio,
|
||||
}
|
||||
|
@ -17,6 +19,7 @@ where
|
|||
{
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Luau => "luau",
|
||||
Self::Task => "task",
|
||||
Self::Stdio => "stdio",
|
||||
}
|
||||
|
@ -24,6 +27,7 @@ where
|
|||
|
||||
pub fn create(&self, lua: &'lua Lua) -> LuaResult<LuaMultiValue<'lua>> {
|
||||
let res = match self {
|
||||
Self::Luau => luau::create(lua),
|
||||
Self::Task => task::create(lua),
|
||||
Self::Stdio => stdio::create(lua),
|
||||
};
|
||||
|
@ -41,6 +45,7 @@ impl FromStr for LuneBuiltin {
|
|||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.trim().to_ascii_lowercase().as_str() {
|
||||
"luau" => Ok(Self::Luau),
|
||||
"task" => Ok(Self::Task),
|
||||
"stdio" => Ok(Self::Stdio),
|
||||
_ => Err(format!("Unknown builtin library '{s}'")),
|
||||
|
|
Loading…
Reference in a new issue