luac_parser/
lua52.rs

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}