Skip to content

Commit

Permalink
Add cargo-spellcheck and fix spelling
Browse files Browse the repository at this point in the history
  • Loading branch information
vE5li committed Jul 10, 2023
1 parent 1bf2474 commit d4398e8
Show file tree
Hide file tree
Showing 21 changed files with 269 additions and 242 deletions.
10 changes: 10 additions & 0 deletions .config/extra_words.dic
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
9
lua
lunify
endianness
io
variadic
opcode
globals
upvalues
+
7 changes: 7 additions & 0 deletions .config/spellcheck.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dev_comments = true

[Hunspell]
use_builtin = true
skip_os_lookups = false
search_dirs = ["."]
extra_dictionaries = ["extra_words.dic"]
8 changes: 8 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,11 @@ jobs:
with:
command: clippy
args: --all -- -D warnings

- name: Install cargo-spellcheck
uses: taiki-e/install-action@v2
with:
tool: cargo-spellcheck
- uses: actions/checkout@v3
- name: Run cargo-spellcheck
run: cargo spellcheck --code 1
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "lunify"
authors = ["Lucas Pütz"]
description = "A crate for converting Lua bytecode to different versions and formats"
description = "A crate for converting Lua byte code to different versions and formats"
categories = ["encoding"]
keywords = ["lua", "bytecode"]
version = "1.0.1"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
[![crates.io](https://img.shields.io/crates/v/lunify.svg)](https://crates.io/crates/lunify)

A crate for converting Lua bytecode to different versions and formats.
A crate for converting Lua byte code to different versions and formats.

Currently Lua 5.0 and Lua 5.1 are supported inputs.

Expand All @@ -15,13 +15,13 @@ Currently Lua 5.0 and Lua 5.1 are supported inputs.
```rust
use lunify::{Format, LunifyError, Endianness, BitWidth, unify};

// Lua bytecode in any suppored format
// Lua byte code in any suppored format
let input_bytes = include_bytes!("../test_files/lua50.luab");

// Desired output format. May specify pointer width, endianness, sizes of datatypes, ...
let output_format = Format {
endianness: Endianness::Little,
// Convert from bytecode that runs on a 32 bit machine to bytcode that runs on a 64 bit machine
// Convert from byte code that runs on a 32 bit machine to byte code that runs on a 64 bit machine
size_t_width: BitWidth::Bit64,
..Format::default()
};
Expand Down
36 changes: 18 additions & 18 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,52 @@ use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum LunifyError {
/// The specified instruction layout is not valid. This can happen when size
/// limitations are not respected, when operant types are specified more
/// than once, or when the B and C operants are not adjacent.
/// limitations are not respected, when operand types are specified more
/// than once, or when the B and C operands are not adjacent.
InvalidInstructionLayout,
/// The provided bytecode does not start with the signature `\[27]Lua`.
/// The provided byte code does not start with the signature `\[27]Lua`.
IncorrectSignature,
/// The version of Lua that the bytecode was compiled for is not supported
/// The version of Lua that the byte code was compiled for is not supported
/// by Lunify.
UnsupportedVersion(u8),
/// The specified format does not specify a valid endianness.
InvaildEndianness(u8),
/// The instruction memory layout is not supported by Lunify. This error can
/// only occur in Lua 5.0.
UnsupportedInstructionFormat([u8; 4]),
/// The pointer width of the system that the bytecode was compiled for is
/// The pointer width of the system that the byte code was compiled for is
/// not supported by Lunify.
UnsupportedSizeTWidth(u8),
/// The integer width of the system that the bytecode was compiled for is
/// The integer width of the system that the byte code was compiled for is
/// not supported by Lunify.
UnsupportedIntegerWidth(u8),
/// The instruction width of the system that the bytecode was compiled for
/// The instruction width of the system that the byte code was compiled for
/// is not supported by Lunify.
UnsupportedInstructionWidth(u8),
/// The number width of the system that the bytecode was compiled for
/// The number width of the system that the byte code was compiled for
/// is not supported by Lunify.
UnsupportedNumberWidth(u8),
/// The bytecode contains an instruction that is not recognized by Lunify.
/// The byte code contains an instruction that is not recognized by Lunify.
InvalidOpcode(u64),
/// The bytecode contains a constant with a type that is not recognized by
/// The byte code contains a constant with a type that is not recognized by
/// Lunify.
InvalidConstantType(u8),
/// The bytecode contains a number with a non-integral value that can't be
/// The byte code contains a number with a non-integral value that can't be
/// represented when `is_number_integral` is set to true.
FloatPrecisionLoss,
/// The bytecode contains an integral value that is too big to be
/// The byte code contains an integral value that is too big to be
/// represented when `is_number_integral` is set to false.
IntegerOverflow,
/// The bytecode is truncated.
/// The byte code is truncated.
InputTooShort,
/// The bytecode has access padding.
/// The byte code has access padding.
InputTooLong,
/// The bytecode generated by converting is using stack values that are
/// The byte code generated by converting is using stack values that are
/// bigger than Lua 5.1 `MAXSTACK`.
StackTooLarge(u64),
/// The bytecode generated by converting to Lua 5.1 needs to store a value
/// in an operant that exeed the maximum possible value.
ValueTooBigForOperant,
/// The byte code generated by converting to Lua 5.1 needs to store a value
/// in an operand that exceed the maximum possible value.
ValueTooBigForOperand,
/// The Lua 5.0 `FORLOOP` instruction specified a positive jump, even though
/// we expect it to always be negative.
UnexpectedForwardJump,
Expand Down
2 changes: 1 addition & 1 deletion src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use width::BitWidth;
use crate::serialization::{ByteStream, ByteWriter};
use crate::{LunifyError, Settings};

/// Lua bytecode format.
/// Lua byte code format.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Format {
Expand Down
30 changes: 17 additions & 13 deletions src/function/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,26 @@ impl FunctionBuilder {
Ok(((program_counter as i64) + new_bx) as usize)
}

pub(super) fn finalize(mut self, maxstacksize: &mut u8, settings: &Settings) -> Result<(Vec<Instruction>, Vec<i64>), LunifyError> {
pub(super) fn finalize(
mut self,
maximum_stack_size: &mut u8,
settings: &Settings,
) -> Result<(Vec<Instruction>, Vec<i64>), LunifyError> {
#[cfg(feature = "debug")]
println!("\n======== Output ========");

for context_index in 0..self.contexts.len() {
// The stack positions might have changed significantly, so go over every
// instruction and make sure that the maxstacksize is big enough. If the stack
// had to be popped out too much in the conversion, we return an error.
// We also know that values on the stack will only be used after they have been
// put there by anther instruction, meaning if we make space for the
// instructions that push the values onto the stack, the stack will never
// overflow.
// instruction and make sure that the maximum stack size is big enough. If the
// stack had to be popped out too much in the conversion, we return
// an error. We also know that values on the stack will only be used
// after they have been put there by anther instruction, meaning if
// we make space for the instructions that push the values onto the
// stack, the stack will never overflow.
if let Some(destination) = self.contexts[context_index].instruction.stack_destination() {
let new_stack_size = destination.end + 1;
match new_stack_size <= settings.output.stack_limit {
true => *maxstacksize = (*maxstacksize).max(new_stack_size as u8),
true => *maximum_stack_size = (*maximum_stack_size).max(new_stack_size as u8),
false => return Err(LunifyError::StackTooLarge(new_stack_size)),
}
}
Expand Down Expand Up @@ -400,24 +404,24 @@ mod tests {
fn finalize_expands_stack() -> Result<(), LunifyError> {
let mut builder = FunctionBuilder::default();
let instruction = lua51::Instruction::LoadK { a: 10, mode: Bx(1) };
let mut maxstacksize = 0;
let mut maximum_stack_size = 0;

builder.instruction(instruction);
builder.finalize(&mut maxstacksize, &Default::default())?;
builder.finalize(&mut maximum_stack_size, &Default::default())?;

assert_eq!(maxstacksize, 11);
assert_eq!(maximum_stack_size, 11);
Ok(())
}

#[test]
fn finalize_expands_stack_too_large() {
let mut builder = FunctionBuilder::default();
let instruction = lua51::Instruction::LoadK { a: 250, mode: Bx(1) };
let mut maxstacksize = 0;
let mut maximum_stack_size = 0;

builder.instruction(instruction);

let result = builder.finalize(&mut maxstacksize, &Default::default());
let result = builder.finalize(&mut maximum_stack_size, &Default::default());
assert_eq!(result, Result::Err(LunifyError::StackTooLarge(251)));
}

Expand Down
16 changes: 8 additions & 8 deletions src/function/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use crate::{lua51, LunifyError, Settings};
pub(crate) fn convert(
instructions: Vec<lua51::Instruction>,
line_info: Vec<i64>,
maxstacksize: &mut u8,
maximum_stack_size: &mut u8,
settings: &Settings,
) -> Result<(Vec<lua51::Instruction>, Vec<i64>), LunifyError> {
// If fields_per_flush is the same, there is nothing to convert, so return
// If `fields_per_flush` is the same, there is nothing to convert, so return
// early.
if settings.lua51.fields_per_flush == settings.output.fields_per_flush {
return Ok((instructions, line_info));
Expand All @@ -35,7 +35,7 @@ pub(crate) fn convert(
};

// Good case: we are on the first page and the number of entries is smaller than
// either LFIELDS_PER_FLUSH, meaning we can just insert a SETLIST instruction
// either `LFIELDS_PER_FLUSH`, meaning we can just insert a `SETLIST` instruction
// without any modification to the previous code.
if page == 0 && flat_index <= u64::min(settings.lua51.fields_per_flush, settings.output.fields_per_flush) {
builder.instruction(lua51::Instruction::SetList {
Expand All @@ -54,15 +54,15 @@ pub(crate) fn convert(
// already before any instructions if it is a parameter to a function call. So
// we make sure that at least the first instruction will always match.
// I am unsure that code like this can actually be emitted by the Lua compiler,
// because any assignment of a table should start with a NEWTABLE instruction,
// because any assignment of a table should start with a `NEWTABLE` instruction,
// but better safe than sorry.
if matches!(instruction.stack_destination(), Some(destination) if destination.start == a) || instruction_index == 0 {
// Should either be NEWTABLE or SETLIST.
// Should either be `NEWTABLE` or `SETLIST`.
if let lua51::Instruction::SetList { mode: BC(b, c), .. } = *instruction {
let mut offset = b.0 as i64;
let mut page = c.0;

// Remove the SETLIST instruction.
// Remove the `SETLIST` instruction.
builder.remove_instruction(instruction_index);

// Go back up the stack and update the stack positions.
Expand All @@ -72,7 +72,7 @@ pub(crate) fn convert(

if let Some(stack_destination) = instruction.stack_destination() {
if offset + stack_destination.start as i64 - 1 == (a + settings.output.fields_per_flush) as i64 {
// Add a new SETLIST instruction.
// Add a new `SETLIST` instruction.
builder.insert_extra_instruction(instruction_index, lua51::Instruction::SetList {
a,
mode: BC(Generic(settings.output.fields_per_flush), Generic(page)),
Expand Down Expand Up @@ -104,7 +104,7 @@ pub(crate) fn convert(
};
}

builder.finalize(maxstacksize, settings)
builder.finalize(maximum_stack_size, settings)
}

#[cfg(test)]
Expand Down
20 changes: 10 additions & 10 deletions src/function/instruction/lua50.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use super::operant::{Bx, Generic, Opcode, SignedBx, A, BC};
use super::{ConstantRegister, InstructionLayout, OperantType, Register, Unused};
use super::operand::{Bx, Generic, Opcode, SignedBx, A, BC};
use super::{ConstantRegister, InstructionLayout, OperandType, Register, Unused};
use crate::LunifyError;

/// Lua 5.0 compile constants. The Lua interpreter is compiled with certain
/// predefined constants that affect how the bytecode is generated. This
/// predefined constants that affect how the byte code is generated. This
/// structure represents a small subset of the constants that are relevant for
/// Lunify. If the bytecode you are trying to modify was complied with
/// Lunify. If the byte code you are trying to modify was complied with
/// non-standard constants, you can use these settings to make it compatible.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Settings<'a> {
/// Maximum number of elements that can be on the stack at the same time
/// (`MAXSTACK`).
pub stack_limit: u64,
/// Number of elements to put on the stack before inserting a SETLIST
/// Number of elements to put on the stack before inserting a `SETLIST`
/// instruction (`LFIELDS_PER_FLUSH`).
pub fields_per_flush: u64,
/// Lua binary file signature (`LUA_SIGNATURE`).
pub binary_signature: &'a str,
/// Memory layout of instructions inside the Lua bytecode (`SIZE_*`,
/// Memory layout of instructions inside the Lua byte code (`SIZE_*`,
/// `POS_*`).
pub layout: InstructionLayout,
}
Expand All @@ -33,10 +33,10 @@ impl<'a> Default for Settings<'a> {
fields_per_flush: 32,
binary_signature: "\x1bLua",
layout: InstructionLayout::from_specification([
OperantType::Opcode(6),
OperantType::C(9),
OperantType::B(9),
OperantType::A(8),
OperandType::Opcode(6),
OperandType::C(9),
OperandType::B(9),
OperandType::A(8),
])
.unwrap(),
}
Expand Down
24 changes: 12 additions & 12 deletions src/function/instruction/lua51.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use std::ops::Range;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use super::operant::{Bx, ConstantRegister, Generic, Opcode, Register, SignedBx, Unused, A, BC};
use super::{InstructionLayout, OperantType};
use super::operand::{Bx, ConstantRegister, Generic, Opcode, Register, SignedBx, Unused, A, BC};
use super::{InstructionLayout, OperandType};
use crate::LunifyError;

/// Lua 5.1 compile constants. The Lua interpreter is compiled with certain
/// predefined constants that affect how the bytecode is generated. This
/// predefined constants that affect how the byte code is generated. This
/// structure represents a small subset of the constants that are relevant for
/// Lunify. If the bytecode you are trying to modify was complied with
/// Lunify. If the byte code you are trying to modify was complied with
/// non-standard constants, you can use these settings to make it compatible.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand All @@ -23,7 +23,7 @@ pub struct Settings<'a> {
pub fields_per_flush: u64,
/// Lua binary file signature (`LUA_SIGNATURE`).
pub binary_signature: &'a str,
/// Memory layout of instructions inside the Lua bytecode (`SIZE_*`,
/// Memory layout of instructions inside the Lua byte code (`SIZE_*`,
/// `POS_*`).
pub layout: InstructionLayout,
}
Expand All @@ -35,10 +35,10 @@ impl<'a> Default for Settings<'a> {
stack_limit: 250,
binary_signature: "\x1bLua",
layout: InstructionLayout::from_specification([
OperantType::Opcode(6),
OperantType::A(8),
OperantType::C(9),
OperantType::B(9),
OperandType::Opcode(6),
OperandType::A(8),
OperandType::C(9),
OperandType::B(9),
])
.unwrap(),
}
Expand Down Expand Up @@ -98,9 +98,9 @@ lua_instructions! {

impl Instruction {
/// Get the stack index that a given instruction will move data into.
/// SetTable and SetList are technically not moving any data, but rather
/// modifying it, but we need this behaviour for detecting the correct
/// SetList instruction inside the upcast function.
/// `SetTable` and `SetList` are technically not moving any data, but rather
/// modifying it, but we need this behavior for detecting the correct
/// `SetList` instruction inside the `upcast` function.
pub(crate) fn stack_destination(&self) -> Option<Range<u64>> {
match *self {
Instruction::Move { a, .. } => Some(a..a),
Expand Down
Loading

0 comments on commit d4398e8

Please sign in to comment.