Skip to content
Draft
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
1 change: 1 addition & 0 deletions crates/ltk_meta/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ serde = { workspace = true, optional = true }

ltk_io_ext = { version = "0.3.0", path = "../ltk_io_ext" }
ltk_primitives = { version = "0.2.1", path = "../ltk_primitives" }
enum-kinds = "0.5.1"

[dev-dependencies]
approx = { workspace = true }
Expand Down
11 changes: 10 additions & 1 deletion crates/ltk_meta/src/property/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub enum BinPropertyKind {
// COMPLEX TYPES
Container = 128,
UnorderedContainer = 128 | 1,
Struct = 128 | 2,
Object = 128 | 2,
Embedded = 128 | 3,
ObjectLink = 128 | 4,
Optional = 128 | 5,
Expand Down Expand Up @@ -123,6 +123,15 @@ pub struct BinProperty {
pub value: PropertyValueEnum,
}

impl BinProperty {
pub fn new(name_hash: u32, value: impl Into<PropertyValueEnum>) -> Self {
Self {
name_hash,
value: value.into(),
}
}
}

use super::traits::PropertyValue as _;
impl BinProperty {
/// Read a BinProperty from a reader. This will read the name_hash, prop kind and then value, in that order.
Expand Down
8 changes: 4 additions & 4 deletions crates/ltk_meta/src/property/value/embedded.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::traits::{PropertyValue, ReadProperty, WriteProperty};

use super::StructValue;
use super::ObjectValue;

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, PartialEq, Debug)]
pub struct EmbeddedValue(pub StructValue);
pub struct EmbeddedValue(pub ObjectValue);

impl PropertyValue for EmbeddedValue {
fn size_no_header(&self) -> usize {
Expand All @@ -17,7 +17,7 @@ impl ReadProperty for EmbeddedValue {
reader: &mut R,
legacy: bool,
) -> Result<Self, crate::Error> {
StructValue::from_reader(reader, legacy).map(Self)
ObjectValue::from_reader(reader, legacy).map(Self)
}
}
impl WriteProperty for EmbeddedValue {
Expand All @@ -26,6 +26,6 @@ impl WriteProperty for EmbeddedValue {
writer: &mut R,
legacy: bool,
) -> Result<(), std::io::Error> {
StructValue::to_writer(&self.0, writer, legacy)
ObjectValue::to_writer(&self.0, writer, legacy)
}
}
14 changes: 8 additions & 6 deletions crates/ltk_meta/src/property/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod unordered_container;

pub use container::*;
pub use embedded::*;
use enum_kinds::EnumKind;
pub use map::*;
pub use none::*;
pub use optional::*;
Expand Down Expand Up @@ -53,7 +54,8 @@ macro_rules! enum_kind {

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind", content = "value"))]
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq, EnumKind)]
#[enum_kind(PropertyValueKind)]
#[enum_dispatch(PropertyValue)]
/// The value part of a [`super::BinProperty`]. Holds the type of the value, and the value itself.
pub enum PropertyValueEnum {
Expand All @@ -78,7 +80,7 @@ pub enum PropertyValueEnum {
WadChunkLink(pub WadChunkLinkValue),
Container(pub ContainerValue),
UnorderedContainer(pub UnorderedContainerValue),
Struct(pub StructValue),
Object(pub ObjectValue),
Embedded(pub EmbeddedValue),
ObjectLink(pub ObjectLinkValue),
Optional(pub OptionalValue),
Expand Down Expand Up @@ -113,7 +115,7 @@ impl PropertyValueEnum {
WadChunkLink,
Container,
UnorderedContainer,
Struct,
Object,
Embedded,
ObjectLink,
Optional,
Expand All @@ -122,7 +124,7 @@ impl PropertyValueEnum {
]
)
}
#[must_use]

pub fn from_reader<R: io::Read + std::io::Seek + ?Sized>(
reader: &mut R,
kind: BinPropertyKind,
Expand Down Expand Up @@ -153,7 +155,7 @@ impl PropertyValueEnum {
WadChunkLink,
Container,
UnorderedContainer,
Struct,
Object,
Embedded,
ObjectLink,
Optional,
Expand Down Expand Up @@ -192,7 +194,7 @@ impl PropertyValueEnum {
WadChunkLink,
Container,
UnorderedContainer,
Struct,
Object,
Embedded,
ObjectLink,
Optional,
Expand Down
9 changes: 5 additions & 4 deletions crates/ltk_meta/src/property/value/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use ltk_io_ext::{measure, window_at};

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, PartialEq, Debug, Default)]
pub struct StructValue {
/// Object - deserializes into a pointer to a heap allocated struct.
pub struct ObjectValue {
pub class_hash: u32,
pub properties: HashMap<u32, BinProperty>,
}

impl Value for StructValue {
impl Value for ObjectValue {
fn size_no_header(&self) -> usize {
match self.class_hash {
0 => 4,
Expand All @@ -23,7 +24,7 @@ impl Value for StructValue {
}
}

impl ReadProperty for StructValue {
impl ReadProperty for ObjectValue {
fn from_reader<R: std::io::Read + std::io::Seek + ?Sized>(
reader: &mut R,
legacy: bool,
Expand Down Expand Up @@ -58,7 +59,7 @@ impl ReadProperty for StructValue {
Ok(value)
}
}
impl WriteProperty for StructValue {
impl WriteProperty for ObjectValue {
fn to_writer<R: std::io::Write + std::io::Seek + ?Sized>(
&self,
writer: &mut R,
Expand Down
21 changes: 21 additions & 0 deletions crates/ltk_ritobin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "ltk_ritobin"
version = "0.0.1"
edition = "2021"
description = "Ritobin support for League Toolkit"
license = "AGPL-3.0-only"
readme = "../../README.md"

[dependencies]
ltk_meta = { path = "../ltk_meta" }

thiserror = { workspace = true }
miette = { workspace = true }
serde = { workspace = true, features = ["derive"], optional = true }

nom = "8.0.0"
nom_locate = "5.0.0"
enum-kinds = "0.5.1"

[dev-dependencies]
miette = { workspace = true, features = ["fancy"] }
22 changes: 22 additions & 0 deletions crates/ltk_ritobin/examples/parse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::io::{BufRead, BufReader};

use ltk_ritobin::validate::error::MultiBinError;

fn main() -> miette::Result<()> {
let input_path = std::env::args().nth(1).unwrap();
println!("Parsing {input_path:?}...");

let input = BufReader::new(std::fs::File::open(input_path).unwrap())
.lines()
.map_while(Result::ok)
.skip(1)
.collect::<Vec<_>>()
.join("\n");

let (_, statements) = ltk_ritobin::parse(&input).unwrap();
ltk_ritobin::validate(statements).map_err(|errs| MultiBinError {
source_code: input.to_string(),
related: errs,
})?;
Ok(())
}
4 changes: 4 additions & 0 deletions crates/ltk_ritobin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod parse;
pub use parse::parse;
pub mod validate;
pub use validate::validate;
44 changes: 44 additions & 0 deletions crates/ltk_ritobin/src/parse/literals/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::parse::{blank, statement, ws, Span, Statement};
use nom::{
branch::alt,
character::complete::{alpha1, char},
combinator::{consumed, opt},
multi::many1,
sequence::{delimited, preceded},
IResult, Parser,
};

use super::{literal, Literal};

#[derive(Debug, Clone)]
pub struct Block<'a> {
pub span: Span<'a>,
pub class: Option<Span<'a>>,
pub inner: BlockContent<'a>,
}

#[derive(Debug, Clone)]
pub enum BlockContent<'a> {
Empty,
Statements(Vec<Statement<'a>>),
Values(Vec<Literal<'a>>),
}
pub fn block(input: Span) -> IResult<Span, Block> {
consumed((
ws(opt(alpha1)),
delimited(
delimited(blank, char('{'), blank),
opt(alt((
many1(preceded(blank, statement)).map(BlockContent::Statements),
many1(preceded(blank, literal)).map(BlockContent::Values),
))),
preceded(blank, char('}')),
),
))
.map(|(span, (class, statements))| Block {
span,
class,
inner: statements.unwrap_or(BlockContent::Empty),
})
.parse(input)
}
11 changes: 11 additions & 0 deletions crates/ltk_ritobin/src/parse/literals/bool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use nom::{branch::alt, bytes::complete::tag, IResult, Parser};

use crate::parse::{ws, Span};

pub fn boolean(input: Span) -> IResult<Span, (bool, Span)> {
ws(alt((
tag("true").map(|s| (true, s)),
tag("false").map(|s| (false, s)),
)))
.parse(input)
}
98 changes: 98 additions & 0 deletions crates/ltk_ritobin/src/parse/literals/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use std::fmt::Display;

use enum_kinds::EnumKind;
use nom::{branch::alt, IResult, Parser};

use crate::parse::Span;

mod numeric;
pub use numeric::*;

mod block;
pub use block::*;

mod string;
pub use string::*;

mod bool;
pub use bool::*;

#[derive(Debug, Clone, EnumKind)]
#[enum_kind(LiteralKind)]
pub enum Literal<'a> {
Block(Block<'a>),
Keyword(Span<'a>),
String(Option<Span<'a>>),

Decimal(Span<'a>),
Hexadecimal(Span<'a>),
Octal(Span<'a>),
Binary(Span<'a>),

Bool(bool, Span<'a>),
}

impl Display for LiteralKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
LiteralKind::Block => "block",
LiteralKind::Keyword => "keyword",
LiteralKind::String => "string",
LiteralKind::Decimal => "decimal number",
LiteralKind::Hexadecimal => "hex number",
LiteralKind::Octal => "octal number",
LiteralKind::Binary => "binary number",
LiteralKind::Bool => "bool",
})
}
}

impl<'a> Literal<'a> {
pub fn kind(&self) -> LiteralKind {
self.into()
}
pub fn span(&self) -> &Span<'a> {
match self {
Literal::Block(block) => &block.span,
Literal::String(span) => span.as_ref().expect("TODO: empty string spans"),
Literal::Keyword(span)
| Literal::Decimal(span)
| Literal::Hexadecimal(span)
| Literal::Octal(span)
| Literal::Binary(span)
| Literal::Bool(_, span) => span,
}
}
}

pub fn literal(input: Span) -> IResult<Span, Literal<'_>> {
alt((
boolean.map(|(b, s)| Literal::Bool(b, s)),
string.map(Literal::String),
hexadecimal.map(Literal::Hexadecimal),
binary.map(Literal::Binary),
octal.map(Literal::Octal),
float.map(Literal::Decimal),
integer.map(Literal::Decimal),
block.map(Literal::Block),
))
.parse(input)
}

#[cfg(test)]
pub mod tests {
use crate::Span;

use super::string;

#[test]
fn string_lit_1() {
let input =
Span::new(r#" "my 40 cool strings are very cooo!!!_--=z-9-021391 23'''; \" \" " "#);
let (_, str) = string(input).unwrap();
assert_eq!(
str.map(|s| s.into_fragment()),
Some("my 40 cool strings are very cooo!!!_--=z-9-021391 23'''; \\\" \\\" ")
);
}
}
Loading
Loading