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::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
|
mod luau;
|
||||||
mod stdio;
|
mod stdio;
|
||||||
mod task;
|
mod task;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum LuneBuiltin {
|
pub enum LuneBuiltin {
|
||||||
|
Luau,
|
||||||
Task,
|
Task,
|
||||||
Stdio,
|
Stdio,
|
||||||
}
|
}
|
||||||
|
@ -17,6 +19,7 @@ where
|
||||||
{
|
{
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Luau => "luau",
|
||||||
Self::Task => "task",
|
Self::Task => "task",
|
||||||
Self::Stdio => "stdio",
|
Self::Stdio => "stdio",
|
||||||
}
|
}
|
||||||
|
@ -24,6 +27,7 @@ where
|
||||||
|
|
||||||
pub fn create(&self, lua: &'lua Lua) -> LuaResult<LuaMultiValue<'lua>> {
|
pub fn create(&self, lua: &'lua Lua) -> LuaResult<LuaMultiValue<'lua>> {
|
||||||
let res = match self {
|
let res = match self {
|
||||||
|
Self::Luau => luau::create(lua),
|
||||||
Self::Task => task::create(lua),
|
Self::Task => task::create(lua),
|
||||||
Self::Stdio => stdio::create(lua),
|
Self::Stdio => stdio::create(lua),
|
||||||
};
|
};
|
||||||
|
@ -41,6 +45,7 @@ impl FromStr for LuneBuiltin {
|
||||||
type Err = String;
|
type Err = String;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.trim().to_ascii_lowercase().as_str() {
|
match s.trim().to_ascii_lowercase().as_str() {
|
||||||
|
"luau" => Ok(Self::Luau),
|
||||||
"task" => Ok(Self::Task),
|
"task" => Ok(Self::Task),
|
||||||
"stdio" => Ok(Self::Stdio),
|
"stdio" => Ok(Self::Stdio),
|
||||||
_ => Err(format!("Unknown builtin library '{s}'")),
|
_ => Err(format!("Unknown builtin library '{s}'")),
|
||||||
|
|
Loading…
Reference in a new issue