use luau_common::BString;
use luau_compiler::{CompileOptions, CompilerError, StaticCompileHost, compile_with, dump_with};
use luau_syntax::parser::ParseOptions;
use super::Lua;
use crate::vector::Vector;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum CompileConstant {
Nil,
Boolean(bool),
Number(f64),
Integer(i64),
Vector(Vector),
String(BString),
}
impl CompileConstant {
fn into_library_member_constant(self) -> luau_compiler::LibraryMemberConstant {
match self {
Self::Nil => luau_compiler::LibraryMemberConstant::Nil,
Self::Boolean(value) => luau_compiler::LibraryMemberConstant::Boolean(value),
Self::Number(value) => luau_compiler::LibraryMemberConstant::Number(value),
Self::Integer(value) => luau_compiler::LibraryMemberConstant::Integer(value),
Self::Vector(value) => {
luau_compiler::LibraryMemberConstant::Vector(vector_constant(value))
}
Self::String(value) => luau_compiler::LibraryMemberConstant::String(value),
}
}
}
impl From<bool> for CompileConstant {
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
impl From<f64> for CompileConstant {
fn from(value: f64) -> Self {
Self::Number(value)
}
}
impl From<i32> for CompileConstant {
fn from(value: i32) -> Self {
Self::Number(f64::from(value))
}
}
impl From<i64> for CompileConstant {
fn from(value: i64) -> Self {
Self::Integer(value)
}
}
impl From<Vector> for CompileConstant {
fn from(value: Vector) -> Self {
Self::Vector(value)
}
}
impl From<&str> for CompileConstant {
fn from(value: &str) -> Self {
Self::String(value.into())
}
}
impl From<String> for CompileConstant {
fn from(value: String) -> Self {
Self::String(value.into())
}
}
impl From<BString> for CompileConstant {
fn from(value: BString) -> Self {
Self::String(value)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Compiler {
options: CompileOptions,
host: StaticCompileHost,
}
impl Compiler {
pub fn new() -> Self {
Self {
options: CompileOptions::default(),
host: StaticCompileHost::default(),
}
}
#[must_use]
pub fn set_optimization_level(mut self, level: u8) -> Self {
self.options.optimization_level = level;
self
}
#[must_use]
pub fn set_debug_level(mut self, level: u8) -> Self {
self.options.debug_level = level;
self
}
#[must_use]
pub fn set_type_info_level(mut self, level: u8) -> Self {
self.options.type_info_level = level;
self
}
#[must_use]
pub fn set_coverage_level(mut self, level: u8) -> Self {
self.options.coverage_level = level;
self
}
#[must_use]
pub fn set_vector_ctor(mut self, constructor: impl AsRef<str>) -> Self {
let constructor = constructor.as_ref();
if let Some((library, constructor)) = constructor.split_once('.') {
self.host = self
.host
.with_member_vector_constructor(library.as_bytes(), constructor.as_bytes());
} else {
self.host = self
.host
.with_global_vector_constructor(constructor.as_bytes());
}
self
}
#[must_use]
pub fn set_vector_type(mut self, type_name: impl Into<BString>) -> Self {
self.host = self.host.with_vector_type_name(type_name);
self
}
#[must_use]
pub fn add_mutable_global(mut self, global: impl Into<BString>) -> Self {
self.options.mutable_globals.push(global.into());
self
}
#[must_use]
pub fn set_mutable_globals<I, S>(mut self, globals: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<BString>,
{
self.options.mutable_globals = globals.into_iter().map(Into::into).collect();
self
}
#[must_use]
pub fn add_userdata_type(mut self, type_name: impl Into<BString>) -> Self {
self.host = self.host.with_userdata_type(type_name);
self
}
#[must_use]
pub fn set_userdata_types<I, S>(mut self, type_names: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<BString>,
{
self.host = self.host.with_userdata_types(type_names);
self
}
#[must_use]
pub fn add_disabled_builtin(mut self, builtin: impl Into<BString>) -> Self {
self.options.disabled_builtins.push(builtin.into());
self
}
#[must_use]
pub fn set_disabled_builtins<I, S>(mut self, builtins: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<BString>,
{
self.options.disabled_builtins = builtins.into_iter().map(Into::into).collect();
self
}
#[must_use]
pub fn add_library_constant(
mut self,
name: impl AsRef<str>,
constant: impl Into<CompileConstant>,
) -> Self {
let Some((library, member)) = name.as_ref().split_once('.') else {
return self;
};
self.host = self.host.with_library_member_constant(
library.as_bytes(),
member.as_bytes(),
constant.into().into_library_member_constant(),
);
self
}
pub fn compile(&self, source: impl AsRef<[u8]>) -> Result<Vec<u8>, CompilerError> {
luau_common::flags::initialize_luau_flags_default();
compile_with(
source,
self.options.clone(),
ParseOptions::default(),
&self.host,
)
}
pub fn dump(&self, source: impl AsRef<[u8]>) -> Result<BString, CompilerError> {
luau_common::flags::initialize_luau_flags_default();
dump_with(
source,
self.options.clone(),
ParseOptions::default(),
&self.host,
)
}
}
impl Lua {
pub fn set_compiler(&self, compiler: Compiler) {
self.runtime.set_compiler(compiler);
}
}
impl Default for Compiler {
fn default() -> Self {
Self::new()
}
}
fn vector_constant(value: Vector) -> [f32; 4] {
#[cfg(not(feature = "vector4"))]
{
[value.x(), value.y(), value.z(), 0.0]
}
#[cfg(feature = "vector4")]
{
[value.x(), value.y(), value.z(), value.w()]
}
}