luac_parser/
lua53.rs

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        // TODO: usize
10        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}