1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Ritobin text format parser and writer for League Toolkit.
//!
//! This crate provides functionality to parse and write the ritobin text format,
//! which is a human-readable representation of League of Legends bin files.
//!
//! # Quick start
//!
//! Parse ritobin text, build a [`Bin`], and round-trip it back to text:
//!
//! ```rust
//! use ltk_ritobin::{Cst, Print as _};
//!
//! let text = r#"
//! #PROP_text
//! type: string = "PROP"
//! version: u32 = 3
//! linked: list[string] = { }
//! entries: map[hash, embed] = { }
//! "#.trim();
//!
//! let cst = Cst::parse(text);
//! assert!(cst.errors.is_empty());
//!
//! let partial = cst.build_bin(text);
//! assert!(partial.diagnostics.is_empty());
//!
//! // Write back to text
//! let output = partial.bin.print().unwrap();
//!
//! assert_eq!(text, output);
//! ```
//!
//! # Converting `.bin` to ritobin
//!
//! `.bin` files identify fields and types by FNV-1a hashes. Supplying a [`HashProvider`]
//! lets the printer emit the original names instead of `0xdeadbeef` literals:
//!
//! ```no_run
//! use std::io::BufReader;
//! use std::fs::File;
//! use ltk_meta::Bin;
//! use ltk_ritobin::{Print, print::PrintConfig, HashMapProvider};
//!
//! let mut reader = BufReader::new(File::open("data.bin")?);
//! let bin = Bin::from_reader(&mut reader)?;
//!
//! let mut hashes = HashMapProvider::new();
//! hashes.load_from_directory("hashes/"); // loads hashes.bin{entries,fields,hashes,types}.txt
//!
//! let text = bin.print_with_config(PrintConfig::default().with_hashes(hashes))?;
//! std::fs::write("data.rito", text)?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! # Error reporting
//!
//! For resilient parsing, errors exist as nodes into the concrete syntax tree (cst), which propagate into the [`Node`]s' `errors` field (depending on [`parse::ErrorPropagation`]). This
//! allows for more versatile behaviour with things like pretty-printing technically invalid trees,
//! since parsing will always result in a cst.
//!
//! The same handling of errors is done in the type-checker (when building a [`ltk_meta::Bin`]), to
//! always provide a best effort construction.
//!
//! ```rust
//! use ltk_ritobin::Cst;
//!
//! let text = "test: u32 = 4!!2";
//!
//! // by default uses ErrorPropagation::Move,
//! // so all errors will end up in the root
//! let cst = Cst::parse(text);
//!
//! assert_eq!(cst.errors.len(), 1); // the unexpected "!!" in the value
//! ```
//!
//! `Cst::build_bin` follows the same philosophy: it returns a [`ast::PartialBin`], pairing a
//! best-effort `Bin` with any diagnostics, so type errors don't prevent you from getting a
//! `Bin` back. This matters for editor use cases: between keystrokes a buffer is almost always
//! temporarily invalid, and tooling still needs to render it, navigate it, and report problems
//! with precise spans. Use [`ast::PartialBin::finish`] where you instead want a `Result` that
//! only succeeds on a clean build.
use ;
use Bin;
pub use *;
pub use *;
pub use Cst;
pub use Node;
pub use Print;
use crateSpan;