emmylua_parser/syntax/node/token/
number_analyzer.rs1use crate::{
2 parser_error::{LuaParseError, LuaParseErrorKind},
3 LuaSyntaxToken,
4};
5
6pub fn float_token_value(token: &LuaSyntaxToken) -> Result<f64, LuaParseError> {
7 let text = token.text();
8 let hex = text.starts_with("0x") || text.starts_with("0X");
9
10 let value = if hex {
15 let hex_float_text = &text[2..];
16 let exponent_position = hex_float_text
17 .find('p')
18 .or_else(|| hex_float_text.find('P'));
19 let (float_part, exponent_part) = if let Some(pos) = exponent_position {
20 (&hex_float_text[..pos], &hex_float_text[(pos + 1)..])
21 } else {
22 (hex_float_text, "")
23 };
24
25 let (integer_part, fraction_value) = if let Some(dot_pos) = float_part.find('.') {
26 let (int_part, frac_part) = float_part.split_at(dot_pos);
27 let int_value = if !int_part.is_empty() {
28 i64::from_str_radix(int_part, 16).unwrap_or(0)
29 } else {
30 0
31 };
32 let frac_part = &frac_part[1..];
33 let frac_value = if !frac_part.is_empty() {
34 let frac_part_value = i64::from_str_radix(frac_part, 16).unwrap_or(0);
35 frac_part_value as f64 * 16f64.powi(-(frac_part.len() as i32))
36 } else {
37 0.0
38 };
39 (int_value, frac_value)
40 } else {
41 (i64::from_str_radix(float_part, 16).unwrap_or(0), 0.0)
42 };
43
44 let mut value = integer_part as f64 + fraction_value;
45 if !exponent_part.is_empty() {
46 if let Ok(exp) = exponent_part.parse::<i32>() {
47 value *= 2f64.powi(exp);
48 }
49 }
50 value
51 } else {
52 let (float_part, exponent_part) =
53 if let Some(pos) = text.find('e').or_else(|| text.find('E')) {
54 (&text[..pos], &text[(pos + 1)..])
55 } else {
56 (text, "")
57 };
58
59 let mut value = float_part.parse::<f64>().map_err(|e| {
60 LuaParseError::new(
61 LuaParseErrorKind::SyntaxError,
62 &t!(
63 "The float literal '%{text}' is invalid, %{err}",
64 text = text,
65 err = e
66 ),
67 token.text_range(),
68 )
69 })?;
70
71 if !exponent_part.is_empty() {
72 if let Ok(exp) = exponent_part.parse::<i32>() {
73 value *= 10f64.powi(exp);
74 }
75 }
76 value
77 };
78
79 Ok(value)
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83enum IntegerRepr {
84 Normal,
85 Hex,
86 Bin,
87}
88
89pub fn int_token_value(token: &LuaSyntaxToken) -> Result<i64, LuaParseError> {
90 let text = token.text();
91 let repr = if text.starts_with("0x") || text.starts_with("0X") {
92 IntegerRepr::Hex
93 } else if text.starts_with("0b") || text.starts_with("0B") {
94 IntegerRepr::Bin
95 } else {
96 IntegerRepr::Normal
97 };
98
99 let text = text.trim_end_matches(['u', 'l', 'U', 'L']);
100
101 let value = match repr {
102 IntegerRepr::Hex => {
103 let text = &text[2..];
104 i64::from_str_radix(text, 16)
105 }
106 IntegerRepr::Bin => {
107 let text = &text[2..];
108 i64::from_str_radix(text, 2)
109 }
110 IntegerRepr::Normal => text.parse::<i64>(),
111 };
112 match value {
113 Ok(value) => Ok(value),
114 Err(e) => {
115 let range = token.text_range();
116 if *e.kind() == std::num::IntErrorKind::PosOverflow
117 || *e.kind() == std::num::IntErrorKind::NegOverflow
118 {
119 Err(LuaParseError::new(
120 LuaParseErrorKind::SyntaxError,
121 &t!(
122 "The integer literal '%{text}' is too large to be represented in type 'long'",
123 text = text
124 ),
125 range,
126 ))
127 } else {
128 Err(LuaParseError::new(
129 LuaParseErrorKind::SyntaxError,
130 &t!(
131 "The integer literal '%{text}' is invalid, %{err}",
132 text = text,
133 err = e
134 ),
135 range,
136 ))
137 }
138 }
139 }
140}