Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@ fn library() -> lu::Library<Config> {
.with_function_norm("boolean", boolean)
.with_function_norm("u8", u8)
.with_function_norm("u16", u16)
.with_function_norm("u24", u24)
.with_function_norm("u32", u32)
.with_function_norm("i8", i8)
.with_function_norm("i16", i16)
.with_function_norm("i24", i24)
.with_function_norm("i32", i32)
.with_function_norm("f32", f32)
.with_function_norm("f64", f64)
Expand Down Expand Up @@ -315,6 +317,37 @@ extern "C-unwind" fn u16(ctx: Context) -> lu::FnReturn {
ctx.ret_with(1)
}

extern "C-unwind" fn u24(ctx: Context) -> lu::FnReturn {
let min = ctx.arg_number_opt(1);
let max = ctx.arg_number_opt(2);

if let Some(min) = min
&& !(0f64..=16777215f64).contains(&min)
{
ctx.error_msg("u24 min must be between 0 and 16777215")
}

if let Some(max) = max
&& !(0f64..=16777215f64).contains(&max)
{
ctx.error_msg("u24 max must be between 0 and 16777215")
}

if let Some(min) = min
&& let Some(max) = max
&& min > max
{
ctx.error_msg("min must be less than or equal to max")
}

ctx.push_userdata(Type::Number(NumberType {
kind: NumberKind::U24,
range: Range { min, max },
}));

ctx.ret_with(1)
}

extern "C-unwind" fn u32(ctx: Context) -> lu::FnReturn {
let min = ctx.arg_number_opt(1);
let max = ctx.arg_number_opt(2);
Expand Down Expand Up @@ -408,6 +441,37 @@ extern "C-unwind" fn i16(ctx: Context) -> lu::FnReturn {
ctx.ret_with(1)
}

extern "C-unwind" fn i24(ctx: Context) -> lu::FnReturn {
let min = ctx.arg_number_opt(1);
let max = ctx.arg_number_opt(2);

if let Some(min) = min
&& !(-8388608f64..=8388607f64).contains(&min)
{
ctx.error_msg("i24 min must be between -8388608 and 8388607")
}

if let Some(max) = max
&& !(-8388608f64..=8388607f64).contains(&max)
{
ctx.error_msg("i24 max must be between -8388608 and 8388607")
}

if let Some(min) = min
&& let Some(max) = max
&& min > max
{
ctx.error_msg("min must be less than or equal to max")
}

ctx.push_userdata(Type::Number(NumberType {
kind: NumberKind::I24,
range: Range { min, max },
}));

ctx.ret_with(1)
}

extern "C-unwind" fn i32(ctx: Context) -> lu::FnReturn {
let min = ctx.arg_number_opt(1);
let max = ctx.arg_number_opt(2);
Expand Down
24 changes: 22 additions & 2 deletions src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ impl Display for Instr {

Instr::Assert { expr, msg } => write!(f, "if not {expr} then error(\"{msg}\") end;")?,

Instr::AllocK { size } => write!(f, "if pos + {size} > len then resize({size}) end;")?,
Instr::AllocK { size } => write!(f, "if pos + {size} >= len then resize({size}) end;")?,

Instr::AllocD { size } => write!(f, "if pos + {size} > len then resize({size}) end;")?,
Instr::AllocD { size } => write!(f, "if pos + {size} >= len then resize({size}) end;")?,

Instr::ReserveK { into, size } => {
write!(f, "local {into} = pos;")?;
Expand Down Expand Up @@ -228,6 +228,13 @@ pub enum FuncK {
I16,
I32,

// u24 and i24 are special cases that are not natively supported in the
// buffer library. at serdes time special instrs are emitted to handle
// these types. at instr display time these two types are written and read
// as u32 and i32.
U24,
I24,

F32,
F64,
}
Expand All @@ -237,10 +244,12 @@ impl From<NumberKind> for FuncK {
match value {
NumberKind::U8 => FuncK::U8,
NumberKind::U16 => FuncK::U16,
NumberKind::U24 => FuncK::U24,
NumberKind::U32 => FuncK::U32,

NumberKind::I8 => FuncK::I8,
NumberKind::I16 => FuncK::I16,
NumberKind::I24 => FuncK::I24,
NumberKind::I32 => FuncK::I32,

NumberKind::F32 | NumberKind::NaNF32 => FuncK::F32,
Expand All @@ -254,6 +263,7 @@ impl FuncK {
match self {
Self::U8 | Self::I8 => 1,
Self::U16 | Self::I16 => 2,
Self::U24 | Self::I24 => 3,
Self::U32 | Self::I32 => 4,
Self::F32 => 4,
Self::F64 => 8,
Expand All @@ -266,10 +276,12 @@ impl Display for FuncK {
match self {
Self::U8 => write!(f, "u8"),
Self::U16 => write!(f, "u16"),
Self::U24 => write!(f, "u32"),
Self::U32 => write!(f, "u32"),

Self::I8 => write!(f, "i8"),
Self::I16 => write!(f, "i16"),
Self::I24 => write!(f, "i32"),
Self::I32 => write!(f, "i32"),

Self::F32 => write!(f, "f32"),
Expand Down Expand Up @@ -311,6 +323,8 @@ pub enum Expr {
Type(Box<Expr>),
Utf8(Box<Expr>),
Bit(Box<Expr>),

Band(Box<Expr>, Box<Expr>),
}

impl From<bool> for Expr {
Expand Down Expand Up @@ -397,6 +411,10 @@ impl Expr {
pub fn bit(self) -> Self {
Expr::Bit(Box::new(self))
}

pub fn band(self, rhs: impl Into<Expr>) -> Self {
Expr::Band(Box::new(self), Box::new(rhs.into()))
}
}

impl Display for Expr {
Expand Down Expand Up @@ -430,6 +448,8 @@ impl Display for Expr {
Expr::Type(expr) => write!(f, "type({expr})"),
Expr::Utf8(expr) => write!(f, "utf8.len({expr})"),
Expr::Bit(expr) => write!(f, "bit[{expr}]"),

Expr::Band(lhs, rhs) => write!(f, "bit32.band({lhs}, {rhs})"),
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/mir/serdes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,15 @@ impl Serdes for hir::NumberType {
check!(des, b.assert(value.expr().eq(&value), "value is nan"));
}

value
if matches!(self.kind, NumberKind::U24 | NumberKind::I24) {
if des.native {
b.expr(value.expr().band(0x00FFFFFF))
} else {
b.expr(value.expr().mud(256 * 256 * 256))
}
} else {
value
}
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@ impl Options {
pub enum NumberKind {
U8,
U16,
U24,
U32,

I8,
I16,
I24,
I32,

F32,
Expand All @@ -120,6 +122,7 @@ impl NumberKind {
match self {
Self::U8 | Self::I8 => 1,
Self::U16 | Self::I16 => 2,
Self::U24 | Self::I24 => 3,
Self::U32 | Self::I32 => 4,
Self::F32 | Self::NaNF32 => 4,
Self::F64 | Self::NaNF64 => 8,
Expand All @@ -130,25 +133,29 @@ impl NumberKind {
match self {
Self::U8 => 0.0,
Self::U16 => 0.0,
Self::U24 => 0.0,
Self::U32 => 0.0,
Self::I8 => i8::MIN as f64,
Self::I16 => i16::MIN as f64,
Self::I24 => -2f64.powi(23),
Self::I32 => i32::MIN as f64,
Self::F32 | Self::NaNF32 => f32::MIN as f64,
Self::F64 | Self::NaNF64 => f64::MIN as f64,
Self::F64 | Self::NaNF64 => f64::MIN,
}
}

pub fn max(&self) -> f64 {
match self {
Self::U8 => u8::MAX as f64,
Self::U16 => u16::MAX as f64,
Self::U24 => 2f64.powi(24) - 1.0,
Self::U32 => u32::MAX as f64,
Self::I8 => i8::MAX as f64,
Self::I16 => i16::MAX as f64,
Self::I24 => 2f64.powi(23) - 1.0,
Self::I32 => i32::MAX as f64,
Self::F32 | Self::NaNF32 => f32::MAX as f64,
Self::F64 | Self::NaNF64 => f64::MAX as f64,
Self::F64 | Self::NaNF64 => f64::MAX,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/zap.d.luau
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ declare zap: {

u8: (min: number?, max: number?) -> ZapNumberType,
u16: (min: number?, max: number?) -> ZapNumberType,
u24: (min: number?, max: number?) -> ZapNumberType,
u32: (min: number?, max: number?) -> ZapNumberType,

i8: (min: number?, max: number?) -> ZapNumberType,
i16: (min: number?, max: number?) -> ZapNumberType,
i24: (min: number?, max: number?) -> ZapNumberType,
i32: (min: number?, max: number?) -> ZapNumberType,

f32: (min: number?, max: number?) -> ZapNumberType,
Expand Down
Loading