1use super::*;
2
3pub fn lua_string<'a>(header: &LuaHeader) -> impl Parser<&'a [u8], &'a [u8], ErrorTree<&'a [u8]>> {
4 length_data(lua_size_t(header).map(|x| x as usize))
5 .map(|v| if v.is_empty() { v } else { &v[..v.len() - 1] })
6 .context("string")
7}
8
9pub fn lua_local<'a>(header: &LuaHeader) -> impl Parser<&'a [u8], LuaLocal, ErrorTree<&'a [u8]>> {
10 tuple((lua_string(header), lua_int(header), lua_int(header)))
11 .map(|(name, start_pc, end_pc)| LuaLocal {
12 name: String::from_utf8_lossy(name).into(),
13 start_pc,
14 end_pc,
15 ..Default::default()
16 })
17 .context("local")
18}
19
20pub fn lua_chunk<'h, 'a: 'h>(
21 header: &'h LuaHeader,
22) -> impl Parser<&'a [u8], LuaChunk, ErrorTree<&'a [u8]>> + 'h {
23 |input| {
24 let (input, name) = lua_string(header).parse(input)?;
25 let (
26 input,
27 (line_defined, last_line_defined, num_upvalues, num_params, is_vararg, max_stack),
28 ) = tuple((lua_int(header), lua_int(header), be_u8, be_u8, be_u8, be_u8))(input)?;
29 log::trace!(
30 "chunk: {}, line: {line_defined}-{last_line_defined}",
31 String::from_utf8_lossy(name)
32 );
33
34 map(
35 tuple((
36 length_count(lua_int(header).map(|x| x as usize), |input| {
37 alt((must(
38 header.instruction_size == 4,
39 complete::u32(header.endian()),
40 ),))(input)
41 })
42 .context("count instruction"),
43 length_count(lua_int(header).map(|x| x as usize), |input| {
44 let (input, b) = be_u8(input)?;
45 let result = match b {
46 0 => success(LuaConstant::Null)(input),
47 1 => map(be_u8, |v| LuaConstant::Bool(v != 0))(input),
48 3 => map(lua_number(header), |v| LuaConstant::Number(v))(input),
49 4 => map(lua_string(header), |v| LuaConstant::from(v.to_vec()))(input),
50 _ => Err(nom::Err::Error(ErrorTree::from_char(
51 input,
52 char::from_digit(b as _, 10).unwrap_or('x'),
53 ))),
54 };
55 result
56 })
57 .context("count constants"),
58 |i| {
59 length_count(lua_int(header).map(|x| x as usize), lua_chunk(header))
60 .context("count prototypes")
61 .parse(i)
62 },
63 length_count(
64 lua_int(header).map(|x| x as usize),
65 lua_int(header).map(|n| (n as u32, 0u32)),
66 )
67 .context("count source lines"),
68 length_count(lua_int(header).map(|x| x as usize), lua_local(header))
69 .context("count locals"),
70 length_count(
71 lua_int(header).map(|x| x as usize),
72 lua_string(header).map(|v| v.to_vec()),
73 )
74 .context("count upval names"),
75 )),
76 move |(instructions, constants, prototypes, source_lines, locals, upvalue_names)| {
77 LuaChunk {
78 name: name.to_vec(),
79 line_defined,
80 last_line_defined,
81 num_upvalues,
82 num_params,
83 flags: 0,
84 is_vararg: if (is_vararg & 2) != 0 {
85 Some(LuaVarArgInfo {
86 has_arg: (is_vararg & 1) != 0,
87 needs_arg: (is_vararg & 4) != 0,
88 })
89 } else {
90 None
91 },
92 max_stack,
93 instructions,
94 constants,
95 num_constants: vec![],
96 prototypes,
97 source_lines,
98 locals,
99 upvalue_names,
100 upvalue_infos: vec![],
101 }
102 },
103 )
104 .context("chunk")
105 .parse(input)
106 }
107}