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