use super::StringEncoding;
use super::dialect::lua51::{
Lua51ConstPoolExtra, Lua51DebugExtra, Lua51HeaderExtra, Lua51InstrExtra, Lua51Opcode,
Lua51Operands, Lua51ProtoExtra, Lua51UpvalueExtra,
};
use super::dialect::lua52::{
Lua52ConstPoolExtra, Lua52DebugExtra, Lua52HeaderExtra, Lua52InstrExtra, Lua52Opcode,
Lua52Operands, Lua52ProtoExtra, Lua52UpvalueExtra,
};
use super::dialect::lua53::{
Lua53ConstPoolExtra, Lua53DebugExtra, Lua53HeaderExtra, Lua53InstrExtra, Lua53Opcode,
Lua53Operands, Lua53ProtoExtra, Lua53UpvalueExtra,
};
use super::dialect::lua54::{
Lua54ConstPoolExtra, Lua54DebugExtra, Lua54HeaderExtra, Lua54InstrExtra, Lua54Opcode,
Lua54Operands, Lua54ProtoExtra, Lua54UpvalueExtra,
};
use super::dialect::lua55::{
Lua55ConstPoolExtra, Lua55DebugExtra, Lua55HeaderExtra, Lua55InstrExtra, Lua55Opcode,
Lua55Operands, Lua55ProtoExtra, Lua55UpvalueExtra,
};
use super::dialect::luajit::{
LuaJitConstPoolExtra, LuaJitDebugExtra, LuaJitHeaderExtra, LuaJitInstrExtra, LuaJitKgcEntry,
LuaJitNumberConstEntry, LuaJitOpcode, LuaJitOperands, LuaJitProtoExtra, LuaJitUpvalueExtra,
};
use super::dialect::luau::{
LuauConstEntry, LuauConstPoolExtra, LuauDebugExtra, LuauHeaderExtra, LuauInstrExtra,
LuauOpcode, LuauOperands, LuauProtoExtra, LuauUpvalueExtra,
};
#[derive(Debug, Clone, PartialEq)]
pub struct RawChunk {
pub header: ChunkHeader,
pub main: RawProto,
pub origin: Origin,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ChunkHeader {
pub dialect: Dialect,
pub version: DialectVersion,
pub layout: ChunkLayout,
pub extra: DialectHeaderExtra,
pub origin: Origin,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ChunkLayout {
PucLua(PucLuaChunkLayout),
LuaJit(LuaJitChunkLayout),
Luau(LuauChunkLayout),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct PucLuaChunkLayout {
pub format: u8,
pub endianness: Endianness,
pub integer_size: u8,
pub lua_integer_size: Option<u8>,
pub size_t_size: u8,
pub instruction_size: u8,
pub number_size: u8,
pub integral_number: bool,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct LuauChunkLayout {
pub bytecode_version: u8,
pub type_version: Option<u8>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct LuaJitChunkLayout {
pub dump_version: u8,
pub flags: u32,
}
impl ChunkHeader {
pub fn puc_lua_layout(&self) -> Option<&PucLuaChunkLayout> {
match &self.layout {
ChunkLayout::PucLua(layout) => Some(layout),
ChunkLayout::LuaJit(_) | ChunkLayout::Luau(_) => None,
}
}
pub fn luajit_layout(&self) -> Option<&LuaJitChunkLayout> {
match &self.layout {
ChunkLayout::LuaJit(layout) => Some(layout),
ChunkLayout::Luau(_) => None,
ChunkLayout::PucLua(_) => None,
}
}
pub fn luau_layout(&self) -> Option<&LuauChunkLayout> {
match &self.layout {
ChunkLayout::PucLua(_) | ChunkLayout::LuaJit(_) => None,
ChunkLayout::Luau(layout) => Some(layout),
}
}
pub(crate) fn luajit_fr2(&self) -> Option<bool> {
Some(self.extra.luajit()?.fr2)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Dialect {
PucLua,
LuaJit,
Luau,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DialectVersion {
Lua51,
Lua52,
Lua53,
Lua54,
Lua55,
LuaJit,
Luau,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Endianness {
Little,
Big,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawProto {
pub common: RawProtoCommon,
pub extra: DialectProtoExtra,
pub origin: Origin,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawProtoCommon {
pub source: Option<RawString>,
pub line_range: ProtoLineRange,
pub signature: ProtoSignature,
pub frame: ProtoFrameInfo,
pub instructions: Vec<RawInstr>,
pub constants: RawConstPool,
pub upvalues: RawUpvalueInfo,
pub debug_info: RawDebugInfo,
pub children: Vec<RawProto>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ProtoLineRange {
pub defined_start: u32,
pub defined_end: u32,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ProtoSignature {
pub num_params: u8,
pub is_vararg: bool,
pub has_vararg_param_reg: bool,
pub named_vararg_table: bool,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ProtoFrameInfo {
pub max_stack_size: u8,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawConstPool {
pub common: RawConstPoolCommon,
pub extra: DialectConstPoolExtra,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawConstPoolCommon {
pub literals: Vec<RawLiteralConst>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RawLiteralConst {
Nil,
Boolean(bool),
Integer(i64),
Number(f64),
String(RawString),
Int64(i64),
UInt64(u64),
Complex { real: f64, imag: f64 },
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawUpvalueInfo {
pub common: RawUpvalueInfoCommon,
pub extra: DialectUpvalueExtra,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawUpvalueInfoCommon {
pub count: u8,
pub descriptors: Vec<RawUpvalueDescriptor>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct RawUpvalueDescriptor {
pub in_stack: bool,
pub index: u8,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawDebugInfo {
pub common: RawDebugInfoCommon,
pub extra: DialectDebugExtra,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawDebugInfoCommon {
pub line_info: Vec<u32>,
pub local_vars: Vec<RawLocalVar>,
pub upvalue_names: Vec<RawString>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawLocalVar {
pub name: RawString,
pub start_pc: u32,
pub end_pc: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawInstr {
pub opcode: RawInstrOpcode,
pub operands: RawInstrOperands,
pub extra: DialectInstrExtra,
pub origin: Origin,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum RawInstrOpcode {
Lua51(Lua51Opcode),
Lua52(Lua52Opcode),
Lua53(Lua53Opcode),
Lua54(Lua54Opcode),
Lua55(Lua55Opcode),
LuaJit(LuaJitOpcode),
Luau(LuauOpcode),
}
#[derive(Debug, Clone, PartialEq)]
pub enum RawInstrOperands {
Lua51(Lua51Operands),
Lua52(Lua52Operands),
Lua53(Lua53Operands),
Lua54(Lua54Operands),
Lua55(Lua55Operands),
LuaJit(LuaJitOperands),
Luau(LuauOperands),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
pub span: Span,
pub raw_word: Option<u64>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Span {
pub offset: usize,
pub size: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawString {
pub bytes: Vec<u8>,
pub text: Option<DecodedText>,
pub origin: Origin,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DecodedText {
pub encoding: StringEncoding,
pub value: String,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DialectHeaderExtra {
Lua51(Lua51HeaderExtra),
Lua52(Lua52HeaderExtra),
Lua53(Lua53HeaderExtra),
Lua54(Lua54HeaderExtra),
Lua55(Lua55HeaderExtra),
LuaJit(LuaJitHeaderExtra),
Luau(LuauHeaderExtra),
}
#[derive(Debug, Clone, PartialEq)]
pub enum DialectProtoExtra {
Lua51(Lua51ProtoExtra),
Lua52(Lua52ProtoExtra),
Lua53(Lua53ProtoExtra),
Lua54(Lua54ProtoExtra),
Lua55(Lua55ProtoExtra),
LuaJit(LuaJitProtoExtra),
Luau(LuauProtoExtra),
}
#[derive(Debug, Clone, PartialEq)]
pub enum DialectConstPoolExtra {
Lua51(Lua51ConstPoolExtra),
Lua52(Lua52ConstPoolExtra),
Lua53(Lua53ConstPoolExtra),
Lua54(Lua54ConstPoolExtra),
Lua55(Lua55ConstPoolExtra),
LuaJit(LuaJitConstPoolExtra),
Luau(LuauConstPoolExtra),
}
#[derive(Debug, Clone, PartialEq)]
pub enum DialectUpvalueExtra {
Lua51(Lua51UpvalueExtra),
Lua52(Lua52UpvalueExtra),
Lua53(Lua53UpvalueExtra),
Lua54(Lua54UpvalueExtra),
Lua55(Lua55UpvalueExtra),
LuaJit(LuaJitUpvalueExtra),
Luau(LuauUpvalueExtra),
}
#[derive(Debug, Clone, PartialEq)]
pub enum DialectDebugExtra {
Lua51(Lua51DebugExtra),
Lua52(Lua52DebugExtra),
Lua53(Lua53DebugExtra),
Lua54(Lua54DebugExtra),
Lua55(Lua55DebugExtra),
LuaJit(LuaJitDebugExtra),
Luau(LuauDebugExtra),
}
#[derive(Debug, Clone, PartialEq)]
pub enum DialectInstrExtra {
Lua51(Lua51InstrExtra),
Lua52(Lua52InstrExtra),
Lua53(Lua53InstrExtra),
Lua54(Lua54InstrExtra),
Lua55(Lua55InstrExtra),
LuaJit(LuaJitInstrExtra),
Luau(LuauInstrExtra),
}
macro_rules! define_dialect_ref_accessors {
($enum:ident {$($method:ident => $variant:ident($ty:ty)),+ $(,)?}) => {
impl $enum {
$(
pub(crate) fn $method(&self) -> Option<&$ty> {
if let Self::$variant(extra) = self {
Some(extra)
} else {
None
}
}
)+
}
};
}
define_dialect_ref_accessors!(RawInstrOpcode {
lua51 => Lua51(Lua51Opcode),
lua52 => Lua52(Lua52Opcode),
lua53 => Lua53(Lua53Opcode),
lua54 => Lua54(Lua54Opcode),
lua55 => Lua55(Lua55Opcode),
luajit => LuaJit(LuaJitOpcode),
luau => Luau(LuauOpcode),
});
define_dialect_ref_accessors!(RawInstrOperands {
lua51 => Lua51(Lua51Operands),
lua52 => Lua52(Lua52Operands),
lua53 => Lua53(Lua53Operands),
lua54 => Lua54(Lua54Operands),
lua55 => Lua55(Lua55Operands),
luajit => LuaJit(LuaJitOperands),
luau => Luau(LuauOperands),
});
define_dialect_ref_accessors!(DialectHeaderExtra {
luajit => LuaJit(LuaJitHeaderExtra),
});
define_dialect_ref_accessors!(DialectProtoExtra {
lua51 => Lua51(Lua51ProtoExtra),
lua52 => Lua52(Lua52ProtoExtra),
lua53 => Lua53(Lua53ProtoExtra),
lua54 => Lua54(Lua54ProtoExtra),
lua55 => Lua55(Lua55ProtoExtra),
luajit => LuaJit(LuaJitProtoExtra),
luau => Luau(LuauProtoExtra),
});
define_dialect_ref_accessors!(DialectConstPoolExtra {
luajit => LuaJit(LuaJitConstPoolExtra),
luau => Luau(LuauConstPoolExtra),
});
define_dialect_ref_accessors!(DialectUpvalueExtra {
lua54 => Lua54(Lua54UpvalueExtra),
});
define_dialect_ref_accessors!(DialectDebugExtra {
lua54 => Lua54(Lua54DebugExtra),
lua55 => Lua55(Lua55DebugExtra),
luajit => LuaJit(LuaJitDebugExtra),
luau => Luau(LuauDebugExtra),
});
define_dialect_ref_accessors!(DialectInstrExtra {
lua51 => Lua51(Lua51InstrExtra),
lua52 => Lua52(Lua52InstrExtra),
lua53 => Lua53(Lua53InstrExtra),
lua54 => Lua54(Lua54InstrExtra),
lua55 => Lua55(Lua55InstrExtra),
luajit => LuaJit(LuaJitInstrExtra),
luau => Luau(LuauInstrExtra),
});
impl RawConstPool {
pub(crate) fn luajit_kgc_entries(&self) -> Option<&[LuaJitKgcEntry]> {
Some(self.extra.luajit()?.kgc_entries.as_slice())
}
pub(crate) fn luajit_knum_entries(&self) -> Option<&[LuaJitNumberConstEntry]> {
Some(self.extra.luajit()?.knum_entries.as_slice())
}
pub(crate) fn luau_entries(&self) -> Option<&[LuauConstEntry]> {
Some(self.extra.luau()?.entries.as_slice())
}
}
impl RawInstr {
pub(crate) fn pc(&self) -> u32 {
match &self.extra {
DialectInstrExtra::Lua51(extra) => extra.pc,
DialectInstrExtra::Lua52(extra) => extra.pc,
DialectInstrExtra::Lua53(extra) => extra.pc,
DialectInstrExtra::Lua54(extra) => extra.pc,
DialectInstrExtra::Lua55(extra) => extra.pc,
DialectInstrExtra::LuaJit(extra) => extra.pc,
DialectInstrExtra::Luau(extra) => extra.pc,
}
}
pub(crate) fn word_len(&self) -> Option<u8> {
match &self.extra {
DialectInstrExtra::Lua51(extra) => Some(extra.word_len),
DialectInstrExtra::Lua52(extra) => Some(extra.word_len),
DialectInstrExtra::Lua53(extra) => Some(extra.word_len),
DialectInstrExtra::Lua54(extra) => Some(extra.word_len),
DialectInstrExtra::Lua55(extra) => Some(extra.word_len),
DialectInstrExtra::LuaJit(_) => None,
DialectInstrExtra::Luau(extra) => Some(extra.word_len),
}
}
}
macro_rules! define_raw_instr_views {
($($method:ident => ($opcode_method:ident, $operands_method:ident, $extra_method:ident, $opcode_ty:ty, $operands_ty:ty, $extra_ty:ty)),+ $(,)?) => {
impl RawInstr {
$(
pub(crate) fn $method(&self) -> Option<($opcode_ty, &$operands_ty, $extra_ty)> {
Some((
*self.opcode.$opcode_method()?,
self.operands.$operands_method()?,
*self.extra.$extra_method()?,
))
}
)+
}
};
}
define_raw_instr_views! {
lua51 => (lua51, lua51, lua51, Lua51Opcode, Lua51Operands, Lua51InstrExtra),
lua52 => (lua52, lua52, lua52, Lua52Opcode, Lua52Operands, Lua52InstrExtra),
lua53 => (lua53, lua53, lua53, Lua53Opcode, Lua53Operands, Lua53InstrExtra),
lua54 => (lua54, lua54, lua54, Lua54Opcode, Lua54Operands, Lua54InstrExtra),
lua55 => (lua55, lua55, lua55, Lua55Opcode, Lua55Operands, Lua55InstrExtra),
luajit => (luajit, luajit, luajit, LuaJitOpcode, LuaJitOperands, LuaJitInstrExtra),
luau => (luau, luau, luau, LuauOpcode, LuauOperands, LuauInstrExtra),
}
pub fn format_raw_instr(instr: &RawInstr) -> String {
let label = format_opcode_label(&instr.opcode);
let operands = format_operands_compact(&instr.operands);
if operands.is_empty() {
label.to_owned()
} else {
format!("{label} {operands}")
}
}
fn format_opcode_label(opcode: &RawInstrOpcode) -> &'static str {
match opcode {
RawInstrOpcode::Lua51(op) => op.label(),
RawInstrOpcode::Lua52(op) => op.label(),
RawInstrOpcode::Lua53(op) => op.label(),
RawInstrOpcode::Lua54(op) => op.label(),
RawInstrOpcode::Lua55(op) => op.label(),
RawInstrOpcode::LuaJit(op) => op.label(),
RawInstrOpcode::Luau(op) => op.label(),
}
}
fn format_operands_compact(operands: &RawInstrOperands) -> String {
match operands {
RawInstrOperands::Lua51(op) => format_lua51_operands(op),
RawInstrOperands::Lua52(op) => format_lua52_operands(op),
RawInstrOperands::Lua53(op) => format_lua53_operands(op),
RawInstrOperands::Lua54(op) => format_lua54_operands(op),
RawInstrOperands::Lua55(op) => format_lua55_operands(op),
RawInstrOperands::LuaJit(op) => format_luajit_operands(op),
RawInstrOperands::Luau(op) => format_luau_operands(op),
}
}
fn format_lua51_operands(op: &Lua51Operands) -> String {
match op {
Lua51Operands::A { a } => format!("{a}"),
Lua51Operands::AB { a, b } => format!("{a} {b}"),
Lua51Operands::AC { a, c } => format!("{a} {c}"),
Lua51Operands::ABC { a, b, c } => format!("{a} {b} {c}"),
Lua51Operands::ABx { a, bx } => format!("{a} {bx}"),
Lua51Operands::AsBx { a, sbx } => format!("{a} {sbx}"),
}
}
fn format_lua52_operands(op: &Lua52Operands) -> String {
match op {
Lua52Operands::A { a } => format!("{a}"),
Lua52Operands::AB { a, b } => format!("{a} {b}"),
Lua52Operands::AC { a, c } => format!("{a} {c}"),
Lua52Operands::ABC { a, b, c } => format!("{a} {b} {c}"),
Lua52Operands::ABx { a, bx } => format!("{a} {bx}"),
Lua52Operands::AsBx { a, sbx } => format!("{a} {sbx}"),
Lua52Operands::Ax { ax } => format!("{ax}"),
}
}
fn format_lua53_operands(op: &Lua53Operands) -> String {
match op {
Lua53Operands::A { a } => format!("{a}"),
Lua53Operands::AB { a, b } => format!("{a} {b}"),
Lua53Operands::AC { a, c } => format!("{a} {c}"),
Lua53Operands::ABC { a, b, c } => format!("{a} {b} {c}"),
Lua53Operands::ABx { a, bx } => format!("{a} {bx}"),
Lua53Operands::AsBx { a, sbx } => format!("{a} {sbx}"),
Lua53Operands::Ax { ax } => format!("{ax}"),
}
}
fn format_lua54_operands(op: &Lua54Operands) -> String {
match op {
Lua54Operands::None => String::new(),
Lua54Operands::A { a } => format!("{a}"),
Lua54Operands::Ak { a, k } => format!("{a} k={}", u8::from(*k)),
Lua54Operands::AB { a, b } => format!("{a} {b}"),
Lua54Operands::AC { a, c } => format!("{a} {c}"),
Lua54Operands::ABk { a, b, k } => format!("{a} {b} k={}", u8::from(*k)),
Lua54Operands::ABCk { a, b, c, k } => format!("{a} {b} {c} k={}", u8::from(*k)),
Lua54Operands::ABx { a, bx } => format!("{a} {bx}"),
Lua54Operands::AsBx { a, sbx } => format!("{a} {sbx}"),
Lua54Operands::AsJ { sj } => format!("{sj}"),
Lua54Operands::Ax { ax } => format!("{ax}"),
Lua54Operands::ABsCk { a, b, sc, k } => format!("{a} {b} {sc} k={}", u8::from(*k)),
Lua54Operands::AsBCk { a, sb, c, k } => format!("{a} {sb} {c} k={}", u8::from(*k)),
}
}
fn format_lua55_operands(op: &Lua55Operands) -> String {
match op {
Lua55Operands::None => String::new(),
Lua55Operands::A { a } => format!("{a}"),
Lua55Operands::Ak { a, k } => format!("{a} k={}", u8::from(*k)),
Lua55Operands::AB { a, b } => format!("{a} {b}"),
Lua55Operands::AC { a, c } => format!("{a} {c}"),
Lua55Operands::ABC { a, b, c } => format!("{a} {b} {c}"),
Lua55Operands::ABk { a, b, k } => format!("{a} {b} k={}", u8::from(*k)),
Lua55Operands::ABCk { a, b, c, k } => format!("{a} {b} {c} k={}", u8::from(*k)),
Lua55Operands::ABx { a, bx } => format!("{a} {bx}"),
Lua55Operands::AsBx { a, sbx } => format!("{a} {sbx}"),
Lua55Operands::AsJ { sj } => format!("{sj}"),
Lua55Operands::Ax { ax } => format!("{ax}"),
Lua55Operands::ABsCk { a, b, sc, k } => format!("{a} {b} {sc} k={}", u8::from(*k)),
Lua55Operands::AsBCk { a, sb, c, k } => format!("{a} {sb} {c} k={}", u8::from(*k)),
Lua55Operands::AvBCk { a, vb, vc, k } => format!("{a} {vb} {vc} k={}", u8::from(*k)),
}
}
fn format_luajit_operands(op: &LuaJitOperands) -> String {
match op {
LuaJitOperands::A { a } => format!("{a}"),
LuaJitOperands::AD { a, d } => format!("{a} {d}"),
LuaJitOperands::ABC { a, b, c } => format!("{a} {b} {c}"),
}
}
fn format_luau_operands(op: &LuauOperands) -> String {
match op {
LuauOperands::None => String::new(),
LuauOperands::A { a } => format!("{a}"),
LuauOperands::AB { a, b } => format!("{a} {b}"),
LuauOperands::AC { a, c } => format!("{a} {c}"),
LuauOperands::ABC { a, b, c } => format!("{a} {b} {c}"),
LuauOperands::AD { a, d } => format!("{a} {d}"),
LuauOperands::E { e } => format!("{e}"),
}
}