Skip to main content

luaur_ast/functions/
parse_integer_64.rs

1use crate::enums::constant_number_parse_result::ConstantNumberParseResult;
2use luaur_common::macros::luau_assert::LUAU_ASSERT;
3
4#[allow(non_snake_case)]
5pub fn parse_integer_64(result: &mut i64, data: &str, base: i32) -> ConstantNumberParseResult {
6    LUAU_ASSERT!(base == 2 || base == 10 || base == 16);
7
8    // We use a helper to simulate C strtoll/strtoull behavior on a substring.
9    // The C++ code expects the string to end with 'i\0' after the number.
10    if base == 10 {
11        // Find the 'i' suffix
12        let i_pos = data.find('i');
13        if i_pos.is_none()
14            || i_pos.unwrap() == 0
15            || data.get(i_pos.unwrap() + 1..).unwrap_or("") != ""
16        {
17            return ConstantNumberParseResult::Malformed;
18        }
19
20        let num_str = &data[..i_pos.unwrap()];
21        match i64::from_str_radix(num_str, 10) {
22            Ok(val) => {
23                *result = val;
24                ConstantNumberParseResult::Ok
25            }
26            Err(e) => {
27                if e.kind() == &core::num::IntErrorKind::PosOverflow
28                    || e.kind() == &core::num::IntErrorKind::NegOverflow
29                {
30                    ConstantNumberParseResult::IntOverflow
31                } else {
32                    ConstantNumberParseResult::Malformed
33                }
34            }
35        }
36    } else {
37        // hex and binary literals represent bit patterns covering the full uint64 range
38        let i_pos = data.find('i');
39        if i_pos.is_none()
40            || i_pos.unwrap() == 0
41            || data.get(i_pos.unwrap() + 1..).unwrap_or("") != ""
42        {
43            return ConstantNumberParseResult::Malformed;
44        }
45
46        let num_str = &data[..i_pos.unwrap()];
47        match u64::from_str_radix(num_str, base as u32) {
48            Ok(u) => {
49                *result = u as i64;
50                ConstantNumberParseResult::Ok
51            }
52            Err(e) => {
53                if e.kind() == &core::num::IntErrorKind::PosOverflow {
54                    if base == 2 {
55                        ConstantNumberParseResult::BinOverflow
56                    } else {
57                        ConstantNumberParseResult::HexOverflow
58                    }
59                } else {
60                    ConstantNumberParseResult::Malformed
61                }
62            }
63        }
64    }
65}