1use complete::le_u8;
2
3use super::{lua52::load_upvalue, *};
4
5pub fn load_string(input: &[u8]) -> IResult<&[u8], &[u8]> {
6 let (mut input, n) = be_u8(input)?;
7 let mut n = n as u64;
8 if n == 0xFF {
9 let parse = |s| complete::le_u64(s);
11 (input, n) = parse(input)?;
12 }
13 if n == 0 {
14 return Ok((input, &[]));
15 }
16 take(n as usize - 1)(input)
17}
18
19pub fn lua_local<'a>(header: &LuaHeader) -> impl Parser<&'a [u8], LuaLocal, ErrorTree<&'a [u8]>> {
20 tuple((load_string, lua_int(header), lua_int(header)))
21 .map(|(name, start_pc, end_pc)| LuaLocal {
22 name: String::from_utf8_lossy(name).into(),
23 start_pc,
24 end_pc,
25 ..Default::default()
26 })
27 .context("local")
28}
29
30pub fn lua_chunk<'h, 'a: 'h>(
31 header: &'h LuaHeader,
32) -> impl Parser<&'a [u8], LuaChunk, ErrorTree<&'a [u8]>> + 'h {
33 |input| {
34 let (input, (name, line_defined, last_line_defined, num_params, is_vararg, max_stack)) =
35 tuple((
36 load_string,
37 lua_int(header),
38 lua_int(header),
39 be_u8,
40 be_u8,
41 be_u8,
42 ))(input)?;
43 log::trace!(
44 "chunk: {}, line: {line_defined}-{last_line_defined}",
45 String::from_utf8_lossy(name)
46 );
47
48 map(
49 tuple((
50 length_count(lua_int(header).map(|x| x as usize), |input| {
51 alt((must(
52 header.instruction_size == 4,
53 complete::u32(header.endian()),
54 ),))(input)
55 })
56 .context("count instruction"),
57 length_count(
58 lua_int(header).map(|x| x as usize),
59 alt((
60 take_lv_nil,
61 take_lv_bool,
62 take_lv_float,
63 take_lv_str,
64 take_lv_u64,
65 )),
66 )
67 .context("count constants"),
68 length_count(lua_int(header).map(|x| x as usize), load_upvalue)
69 .context("count upvalues"),
70 |i| {
71 length_count(lua_int(header).map(|x| x as usize), lua_chunk(header))
72 .context("count prototypes")
73 .parse(i)
74 },
75 length_count(
76 lua_int(header).map(|x| x as usize),
77 lua_int(header).map(|n| (n as u32, 0u32)),
78 )
79 .context("count source lines"),
80 length_count(lua_int(header).map(|x| x as usize), lua_local(header))
81 .context("count locals"),
82 length_count(
83 lua_int(header).map(|x| x as usize),
84 load_string.map(|v| v.to_vec()),
85 )
86 .context("count upval names"),
87 )),
88 move |(
89 instructions,
90 constants,
91 upvalue_infos,
92 prototypes,
93 source_lines,
94 locals,
95 upvalue_names,
96 )| {
97 LuaChunk {
98 name: name.to_vec(),
99 line_defined,
100 last_line_defined,
101 num_upvalues: upvalue_infos.len() as _,
102 num_params,
103 flags: 0,
104 is_vararg: if is_vararg != 0 {
105 Some(LuaVarArgInfo::new())
106 } else {
107 None
108 },
109 max_stack,
110 instructions,
111 constants,
112 prototypes,
113 source_lines,
114 locals,
115 upvalue_names,
116 upvalue_infos,
117 num_constants: vec![],
118 }
119 },
120 )
121 .context("chunk")
122 .parse(input)
123 }
124}
125
126fn take_lv_nil(input: &[u8]) -> IResult<&[u8], LuaConstant> {
127 let (input, _) = tag(b"\0")(input)?;
128 Ok((input, LuaConstant::Null))
129}
130
131fn take_lv_bool(input: &[u8]) -> IResult<&[u8], LuaConstant> {
132 let (input, (_, b)) = tuple((tag(b"\x01"), le_u8))(input)?;
133 Ok((input, LuaConstant::Bool(b != 0)))
134}
135
136fn take_lv_float(input: &[u8]) -> IResult<&[u8], LuaConstant> {
137 let (input, (_, f)) = tuple((tag(b"\x03"), complete::le_f64))(input)?;
138 Ok((input, LuaConstant::Number(LuaNumber::Float(f as _))))
139}
140
141fn le_u8_minus_one(input: &[u8]) -> IResult<&[u8], u64> {
142 let (mut input, out) = le_u8(input)?;
143 let mut out = out as u64;
144 if out == 0xFF {
145 (input, out) = complete::le_u64(input)?;
146 }
147 Ok((input, out - 1))
148}
149
150fn take_lv_str(input: &[u8]) -> IResult<&[u8], LuaConstant> {
151 let (input, (_, data)) = tuple((
152 alt((tag(b"\x04"), tag("\x14"))),
153 length_data(le_u8_minus_one),
154 ))(input)?;
155
156 Ok((input, LuaConstant::from(data.to_vec())))
157}
158
159fn take_lv_u64(input: &[u8]) -> IResult<&[u8], LuaConstant> {
160 let (input, (_, val)) = tuple((tag(b"\x13"), complete::le_u64))(input)?;
161 Ok((input, LuaConstant::Number(LuaNumber::Integer(val as _))))
162}