Skip to content

Commit 805f713

Browse files
committed
fix integer parse
1 parent e8e6337 commit 805f713

File tree

1 file changed

+69
-37
lines changed

1 file changed

+69
-37
lines changed

crates/emmylua_parser/src/syntax/node/token/number_analyzer.rs

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -168,58 +168,90 @@ pub fn int_token_value(token: &LuaSyntaxToken) -> Result<NumberResult, LuaParseE
168168
match signed_value {
169169
Ok(value) => Ok(NumberResult::Int(value)),
170170
Err(e) => {
171-
let range = token.text_range();
172-
173-
// 如果是溢出错误,尝试解析为无符号整数
174-
if *e.kind() == std::num::IntErrorKind::PosOverflow && is_luajit_unsigned {
175-
let unsigned_value = match repr {
176-
IntegerRepr::Hex => {
177-
let text = &text[2..];
178-
u64::from_str_radix(text, 16)
179-
}
180-
IntegerRepr::Bin => {
181-
let text = &text[2..];
182-
u64::from_str_radix(text, 2)
183-
}
184-
IntegerRepr::Normal => text.parse::<u64>(),
185-
};
186-
187-
match unsigned_value {
188-
Ok(value) => Ok(NumberResult::Uint(value)),
189-
Err(_) => Err(LuaParseError::new(
190-
LuaParseErrorKind::SyntaxError,
191-
&t!(
192-
"The integer literal '%{text}' is too large to be represented",
193-
text = token.text()
194-
),
195-
range,
196-
)),
197-
}
198-
} else if matches!(
171+
// 按照Lua的行为:如果整数溢出,尝试解析为浮点数
172+
if matches!(
199173
*e.kind(),
200174
std::num::IntErrorKind::NegOverflow | std::num::IntErrorKind::PosOverflow
201175
) {
202-
if let Ok(f) = text.parse::<f64>() {
203-
return Ok(NumberResult::Float(f));
176+
// 如果是luajit无符号整数,尝试解析为u64
177+
if is_luajit_unsigned {
178+
let unsigned_value = match repr {
179+
IntegerRepr::Hex => {
180+
let text = &text[2..];
181+
u64::from_str_radix(text, 16)
182+
}
183+
IntegerRepr::Bin => {
184+
let text = &text[2..];
185+
u64::from_str_radix(text, 2)
186+
}
187+
IntegerRepr::Normal => text.parse::<u64>(),
188+
};
189+
190+
if let Ok(value) = unsigned_value {
191+
return Ok(NumberResult::Uint(value));
192+
}
193+
} else {
194+
// Lua 5.4行为:对于十六进制/二进制整数溢出,解析为u64然后reinterpret为i64
195+
// 例如:0xFFFFFFFFFFFFFFFF = -1
196+
if matches!(repr, IntegerRepr::Hex | IntegerRepr::Bin) {
197+
let unsigned_value = match repr {
198+
IntegerRepr::Hex => {
199+
let text = &text[2..];
200+
u64::from_str_radix(text, 16)
201+
}
202+
IntegerRepr::Bin => {
203+
let text = &text[2..];
204+
u64::from_str_radix(text, 2)
205+
}
206+
_ => unreachable!(),
207+
};
208+
209+
if let Ok(value) = unsigned_value {
210+
// Reinterpret u64 as i64 (补码转换)
211+
return Ok(NumberResult::Int(value as i64));
212+
} else {
213+
// 超过64位,转换为浮点数
214+
// 例如:0x13121110090807060504030201
215+
let hex_str = match repr {
216+
IntegerRepr::Hex => &text[2..],
217+
IntegerRepr::Bin => &text[2..],
218+
_ => unreachable!(),
219+
};
220+
221+
// 手动将十六进制转为浮点数
222+
let base = if matches!(repr, IntegerRepr::Hex) {
223+
16.0
224+
} else {
225+
2.0
226+
};
227+
let mut result = 0.0f64;
228+
for c in hex_str.chars() {
229+
if let Some(digit) = c.to_digit(base as u32) {
230+
result = result * base + (digit as f64);
231+
}
232+
}
233+
return Ok(NumberResult::Float(result));
234+
}
235+
} else if let Ok(f) = text.parse::<f64>() {
236+
// 十进制整数溢出,解析为浮点数
237+
return Ok(NumberResult::Float(f));
238+
}
204239
}
205240

206241
Err(LuaParseError::new(
207242
LuaParseErrorKind::SyntaxError,
208-
&t!(
209-
"The integer literal '%{text}' is too large to be represented in type 'float'",
210-
text = token.text()
211-
),
212-
range,
243+
&t!("malformed number"),
244+
token.text_range(),
213245
))
214246
} else {
215247
Err(LuaParseError::new(
216248
LuaParseErrorKind::SyntaxError,
217249
&t!(
218-
"The integer literal '%{text}' is invalid, %{err}",
250+
"Failed to parse integer literal %{text}: %{err}",
219251
text = token.text(),
220252
err = e
221253
),
222-
range,
254+
token.text_range(),
223255
))
224256
}
225257
}

0 commit comments

Comments
 (0)