luac_parser/
lua54.rs

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