Skip to content

Commit bb7cbb1

Browse files
committed
wip: cst construction from bin tree
1 parent 066011e commit bb7cbb1

File tree

3 files changed

+335
-1
lines changed

3 files changed

+335
-1
lines changed

crates/ltk_ritobin/src/parse/cst.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@ pub use tree::*;
55
pub mod visitor;
66
pub use visitor::Visitor;
77

8+
pub mod builder;
9+
810
mod flat_errors;
911
pub use flat_errors::*;
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
use std::fmt::Write;
2+
3+
use ltk_meta::{property::values, Bin, BinObject, BinProperty, PropertyKind, PropertyValueEnum};
4+
5+
use crate::{
6+
kind_to_type_name,
7+
parse::{
8+
cst::{Child, Cst, Kind},
9+
Span, Token, TokenKind as Tok,
10+
},
11+
typecheck::visitor::{PropertyValueExt, RitoType},
12+
};
13+
14+
struct Builder {
15+
buf: String,
16+
}
17+
18+
pub fn tree(kind: Kind, children: Vec<Child>) -> Child {
19+
Child::Tree(Cst {
20+
span: Span::default(),
21+
kind,
22+
children,
23+
errors: vec![],
24+
})
25+
}
26+
pub fn token(kind: Tok) -> Child {
27+
Child::Token(Token {
28+
kind,
29+
span: Span::default(),
30+
})
31+
}
32+
33+
impl Builder {
34+
pub fn number(&mut self, v: impl AsRef<str>) -> Child {
35+
self.buf.write_str(v.as_ref()).unwrap();
36+
token(Tok::Number)
37+
}
38+
39+
pub fn spanned_token(&mut self, kind: Tok, str: impl AsRef<str>) -> Child {
40+
let start = self.buf.len() as u32;
41+
self.buf.write_str(str.as_ref()).unwrap();
42+
let end = self.buf.len() as u32;
43+
Child::Token(Token {
44+
kind,
45+
span: Span::new(start, end),
46+
})
47+
}
48+
49+
pub fn string(&mut self, v: impl AsRef<str>) -> Child {
50+
self.spanned_token(Tok::String, v)
51+
}
52+
53+
pub fn name(&mut self, v: impl AsRef<str>) -> Child {
54+
self.spanned_token(Tok::Name, v)
55+
}
56+
57+
pub fn hex_lit(&mut self, v: impl AsRef<str>) -> Child {
58+
self.spanned_token(Tok::HexLit, v)
59+
}
60+
61+
pub fn block(&self, children: Vec<Child>) -> Child {
62+
tree(
63+
Kind::Block,
64+
[vec![token(Tok::LCurly)], children, vec![token(Tok::RCurly)]].concat(),
65+
)
66+
}
67+
68+
fn value_to_cst<M: Clone>(&mut self, value: &PropertyValueEnum<M>) -> Child {
69+
match value {
70+
PropertyValueEnum::Bool(b) => tree(
71+
Kind::Literal,
72+
vec![token(if **b { Tok::True } else { Tok::False })],
73+
),
74+
PropertyValueEnum::None(_) => {
75+
tree(Kind::Literal, vec![token(Tok::LCurly), token(Tok::RCurly)])
76+
}
77+
PropertyValueEnum::U8(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
78+
PropertyValueEnum::U16(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
79+
PropertyValueEnum::U32(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
80+
PropertyValueEnum::U64(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
81+
PropertyValueEnum::I8(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
82+
PropertyValueEnum::I16(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
83+
PropertyValueEnum::I32(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
84+
PropertyValueEnum::I64(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
85+
PropertyValueEnum::F32(n) => tree(Kind::Literal, vec![token(Tok::Number)]),
86+
PropertyValueEnum::Vector2(v) => tree(Kind::Literal, vec![token(Tok::Number)]),
87+
PropertyValueEnum::Vector3(v) => tree(Kind::Literal, vec![token(Tok::Number)]),
88+
PropertyValueEnum::Vector4(v) => tree(Kind::Literal, vec![token(Tok::Number)]),
89+
PropertyValueEnum::String(s) => tree(
90+
Kind::Literal,
91+
vec![token(Tok::Quote), self.string(&**s), token(Tok::Quote)],
92+
),
93+
PropertyValueEnum::Container(container)
94+
| PropertyValueEnum::UnorderedContainer(values::UnorderedContainer(container)) => {
95+
let mut children = vec![token(Tok::LBrack)];
96+
97+
for (i, item) in container.clone().into_items().enumerate() {
98+
if i > 0 {
99+
children.push(token(Tok::Comma));
100+
}
101+
children.push(self.value_to_cst(&item));
102+
}
103+
104+
children.push(token(Tok::RBrack));
105+
tree(Kind::TypeArgList, children)
106+
}
107+
PropertyValueEnum::Matrix44(matrix44) => todo!(),
108+
PropertyValueEnum::Color(color) => todo!(),
109+
PropertyValueEnum::Hash(hash) => todo!(),
110+
PropertyValueEnum::WadChunkLink(wad_chunk_link) => todo!(),
111+
PropertyValueEnum::Struct(_) => todo!(),
112+
PropertyValueEnum::Embedded(embedded) => {
113+
let children = embedded
114+
.0
115+
.properties
116+
.iter()
117+
.map(|(k, v)| {
118+
let k = self.spanned_token(Tok::HexLit, k.to_string());
119+
let t = self.rito_type(v.value.rito_type());
120+
let v = self.property_to_cst(v);
121+
self.entry(k, Some(t), v)
122+
})
123+
.collect();
124+
tree(Kind::Class, vec![token(Tok::HexLit), self.block(children)])
125+
}
126+
PropertyValueEnum::ObjectLink(object_link) => todo!(),
127+
PropertyValueEnum::BitBool(bit_bool) => todo!(),
128+
PropertyValueEnum::Optional(optional) => {
129+
let children = match optional.clone().into_inner() {
130+
Some(v) => vec![self.value_to_cst(&v)],
131+
None => vec![],
132+
};
133+
self.block(children)
134+
}
135+
PropertyValueEnum::Map(map) => todo!(),
136+
}
137+
}
138+
139+
fn entry(&self, key: Child, kind: Option<Child>, value: Child) -> Child {
140+
tree(
141+
Kind::Entry,
142+
match kind {
143+
Some(kind) => vec![key, token(Tok::Colon), kind, token(Tok::Eq), value],
144+
None => vec![key, token(Tok::Eq), value],
145+
},
146+
)
147+
}
148+
149+
fn rito_type(&mut self, rito_type: RitoType) -> Child {
150+
let mut children = vec![self.spanned_token(Tok::Name, kind_to_type_name(rito_type.base))];
151+
152+
if let Some(sub) = rito_type.subtypes[0] {
153+
let mut args = vec![
154+
token(Tok::LBrack),
155+
tree(
156+
Kind::TypeArg,
157+
vec![self.spanned_token(Tok::Name, kind_to_type_name(sub))],
158+
),
159+
];
160+
if let Some(sub) = rito_type.subtypes[1] {
161+
args.push(token(Tok::Comma));
162+
args.push(tree(
163+
Kind::TypeArg,
164+
vec![self.spanned_token(Tok::Name, kind_to_type_name(sub))],
165+
));
166+
}
167+
args.push(token(Tok::RBrack));
168+
children.push(tree(Kind::TypeArgList, args));
169+
}
170+
171+
tree(Kind::TypeExpr, children)
172+
}
173+
fn property_to_cst<M: Clone>(&mut self, prop: &BinProperty<M>) -> Child {
174+
let k = self.spanned_token(Tok::HexLit, prop.name_hash.to_string());
175+
let t = self.rito_type(prop.value.rito_type());
176+
let v = self.value_to_cst(&prop.value);
177+
self.entry(k, Some(t), v)
178+
}
179+
180+
fn object_block(&mut self, obj: &BinObject) -> Child {
181+
let mut children = vec![token(Tok::LCurly)];
182+
183+
for prop in obj.properties.values() {
184+
children.push(self.property_to_cst(prop));
185+
}
186+
187+
children.push(token(Tok::RCurly));
188+
189+
tree(Kind::Block, children)
190+
}
191+
192+
fn class(&self, class_name: Child, items: Vec<Child>) -> Child {
193+
tree(Kind::Class, vec![class_name, self.block(items)])
194+
}
195+
196+
fn bin_object_to_cst(&mut self, obj: &BinObject) -> Child {
197+
let k = self.hex_lit(format!("0x{:x}", obj.path_hash));
198+
199+
let class_hash = self.hex_lit(format!("0x{:x}", obj.class_hash));
200+
let class_values = obj
201+
.properties
202+
.iter()
203+
.map(|(k, v)| {
204+
let k = tree(Kind::EntryKey, vec![self.hex_lit(format!("0x{k:x}"))]);
205+
let t = self.rito_type(v.value.rito_type());
206+
let v = self.value_to_cst(&v.value);
207+
self.entry(k, Some(t), v)
208+
})
209+
.collect();
210+
211+
let value = self.class(class_hash, class_values);
212+
self.entry(k, None, value)
213+
}
214+
215+
fn bin_to_cst(&mut self, bin: &Bin) -> Cst {
216+
let mut entries = Vec::new();
217+
218+
for obj in bin.objects.values() {
219+
entries.push(self.bin_object_to_cst(obj));
220+
}
221+
222+
let entries_key = self.spanned_token(Tok::Name, "entries");
223+
let entries_type = self.rito_type(RitoType {
224+
base: ltk_meta::PropertyKind::Map,
225+
subtypes: [Some(PropertyKind::Hash), Some(PropertyKind::Embedded)],
226+
});
227+
let entries = self.entry(
228+
tree(Kind::EntryKey, vec![entries_key]),
229+
Some(entries_type),
230+
tree(Kind::EntryValue, vec![self.block(entries)]),
231+
);
232+
233+
Cst {
234+
kind: Kind::File,
235+
span: Span::default(),
236+
children: vec![entries],
237+
errors: vec![],
238+
}
239+
}
240+
}
241+
242+
pub fn bin_to_cst(bin: &Bin) -> (String, Cst) {
243+
let mut builder = Builder { buf: String::new() };
244+
let cst = builder.bin_to_cst(bin);
245+
246+
(builder.buf, cst)
247+
}
248+
249+
#[cfg(test)]
250+
mod test {
251+
use ltk_meta::{property::values, Bin, BinObject};
252+
253+
use crate::{
254+
parse::{cst::builder::bin_to_cst, parse},
255+
print::Printer,
256+
};
257+
258+
fn roundtrip(bin: Bin) {
259+
println!("bin: {bin:#?}");
260+
261+
let (buf, cst) = bin_to_cst(&bin);
262+
263+
let mut str = String::new();
264+
cst.print(&mut str, 0, &buf);
265+
266+
println!("cst:\n{str}");
267+
268+
let mut str = String::new();
269+
270+
Printer::new(&buf, &mut str, 80).print(&cst).unwrap();
271+
println!("RITOBIN:\n{str}");
272+
273+
let cst2 = parse(&str);
274+
let (bin2, errors) = cst2.build_bin(&str);
275+
276+
pretty_assertions::assert_eq!(bin2, bin);
277+
}
278+
279+
#[test]
280+
fn simple() {
281+
roundtrip(
282+
Bin::builder()
283+
.object(
284+
BinObject::builder(0xDEADBEEF, 0x12344321)
285+
.property(0x44444444, values::String::from("hello"))
286+
.build(),
287+
)
288+
.build(),
289+
);
290+
291+
panic!();
292+
}
293+
#[test]
294+
fn list() {
295+
roundtrip(
296+
Bin::builder()
297+
.object(
298+
BinObject::builder(0xDEADBEEF, 0x12344321)
299+
.property(0x44444444, values::String::from("hello"))
300+
.property(
301+
0x9191919,
302+
values::Container::new(vec![
303+
values::U64::new(5),
304+
values::U64::new(6),
305+
values::U64::new(7),
306+
]),
307+
)
308+
.build(),
309+
)
310+
.build(),
311+
);
312+
313+
panic!();
314+
}
315+
}

crates/ltk_ritobin/src/print.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use ltk_meta::Bin;
2+
13
use crate::parse::{
2-
cst::{visitor::Visit, Cst, Kind, Visitor},
4+
cst::{builder::bin_to_cst, visitor::Visit, Cst, Kind, Visitor},
35
Span, TokenKind,
46
};
57

@@ -30,10 +32,25 @@ impl<'a, W: Write> Printer<'a, W> {
3032
if let Some(e) = self.visitor.error {
3133
return Err(e);
3234
}
35+
eprintln!("max q size: {}", self.visitor.queue_size_max);
3336
Ok(())
3437
}
3538
}
3639

40+
pub fn print_bin(bin: &Bin, width: usize) -> Result<String, PrintError> {
41+
let mut str = String::new();
42+
43+
let (buf, cst) = bin_to_cst(bin);
44+
45+
let mut tmp = String::new();
46+
cst.print(&mut tmp, 0, &buf);
47+
println!("[print] cst:\n{tmp}");
48+
49+
Printer::new(&buf, &mut str, width).print(&cst)?;
50+
51+
Ok(str)
52+
}
53+
3754
#[cfg(test)]
3855
mod test {
3956
use crate::{parse::parse, print::Printer};

0 commit comments

Comments
 (0)