luac_parser/
lua51.rs

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}