Skip to content

Commit 25c3d48

Browse files
committed
Update.
1 parent 7164325 commit 25c3d48

File tree

4 files changed

+91
-21
lines changed

4 files changed

+91
-21
lines changed

src/ast.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,31 @@ impl<'a> From<Value<'a>> for serde_json::Value {
6868
}
6969
Value::BooleanLit(b) => serde_json::Value::Bool(b.value),
7070
Value::NullKeyword(_) => serde_json::Value::Null,
71-
Value::NumberLit(num) => match serde_json::Number::from_str(num.value) {
72-
Ok(number) => serde_json::Value::Number(number),
73-
Err(_) => serde_json::Value::String(num.value.to_string()),
74-
},
71+
Value::NumberLit(num) => {
72+
// Check if this is a hexadecimal literal (0x or 0X prefix)
73+
let num_str = num.value.trim_start_matches('-');
74+
if num_str.len() > 2 && (num_str.starts_with("0x") || num_str.starts_with("0X")) {
75+
// Parse hexadecimal and convert to decimal
76+
let hex_part = &num_str[2..];
77+
match i64::from_str_radix(hex_part, 16) {
78+
Ok(decimal_value) => {
79+
let final_value = if num.value.starts_with('-') {
80+
-decimal_value
81+
} else {
82+
decimal_value
83+
};
84+
serde_json::Value::Number(serde_json::Number::from(final_value))
85+
}
86+
Err(_) => serde_json::Value::String(num.value.to_string()),
87+
}
88+
} else {
89+
// Standard decimal number
90+
match serde_json::Number::from_str(num.value) {
91+
Ok(number) => serde_json::Value::Number(number),
92+
Err(_) => serde_json::Value::String(num.value.to_string()),
93+
}
94+
}
95+
}
7596
Value::Object(obj) => {
7697
let mut map = serde_json::map::Map::new();
7798
for prop in obj.properties {

src/cst/mod.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,10 +1442,30 @@ impl CstNumberLit {
14421442
pub fn to_serde_value(&self) -> Option<serde_json::Value> {
14431443
use std::str::FromStr;
14441444
let raw = self.0.borrow().value.clone();
1445-
match serde_json::Number::from_str(&raw) {
1446-
Ok(number) => Some(serde_json::Value::Number(number)),
1447-
// If the number is invalid, return it as a string (same behavior as AST conversion)
1448-
Err(_) => Some(serde_json::Value::String(raw)),
1445+
1446+
// check if this is a hexadecimal literal (0x or 0X prefix)
1447+
let num_str = raw.trim_start_matches('-');
1448+
if num_str.len() > 2 && (num_str.starts_with("0x") || num_str.starts_with("0X")) {
1449+
// parse hexadecimal and convert to decimal
1450+
let hex_part = &num_str[2..];
1451+
match i64::from_str_radix(hex_part, 16) {
1452+
Ok(decimal_value) => {
1453+
let final_value = if raw.starts_with('-') {
1454+
-decimal_value
1455+
} else {
1456+
decimal_value
1457+
};
1458+
Some(serde_json::Value::Number(serde_json::Number::from(final_value)))
1459+
}
1460+
Err(_) => Some(serde_json::Value::String(raw)),
1461+
}
1462+
} else {
1463+
// standard decimal number
1464+
match serde_json::Number::from_str(&raw) {
1465+
Ok(number) => Some(serde_json::Value::Number(number)),
1466+
// if the number is invalid, return it as a string (same behavior as AST conversion)
1467+
Err(_) => Some(serde_json::Value::String(raw)),
1468+
}
14491469
}
14501470
}
14511471
}

src/parse_to_ast.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -576,21 +576,30 @@ mod tests {
576576

577577
#[test]
578578
fn it_should_parse_unquoted_keys_with_hex_and_trailing_comma() {
579-
let parse_result = parse_to_ast(
580-
r#"{
579+
let text = r#"{
581580
CP_CanFuncReqId: 0x7DF, // 2015
582-
}"#,
583-
&Default::default(),
584-
&Default::default(),
585-
)
586-
.unwrap();
581+
}"#;
582+
{
583+
let parse_result = parse_to_ast(text, &Default::default(), &Default::default()).unwrap();
587584

588-
let value = parse_result.value.unwrap();
589-
let obj = value.as_object().unwrap();
590-
assert_eq!(obj.properties.len(), 1);
591-
assert_eq!(obj.properties[0].name.as_str(), "CP_CanFuncReqId");
585+
let value = parse_result.value.unwrap();
586+
let obj = value.as_object().unwrap();
587+
assert_eq!(obj.properties.len(), 1);
588+
assert_eq!(obj.properties[0].name.as_str(), "CP_CanFuncReqId");
592589

593-
let number_value = obj.properties[0].value.as_number_lit().unwrap();
594-
assert_eq!(number_value.value, "0x7DF");
590+
let number_value = obj.properties[0].value.as_number_lit().unwrap();
591+
assert_eq!(number_value.value, "0x7DF");
592+
}
593+
#[cfg(feature = "serde")]
594+
{
595+
let value = crate::parse_to_serde_value(text, &Default::default()).unwrap().unwrap();
596+
// hexadecimal numbers are converted to decimal in serde output
597+
assert_eq!(
598+
value,
599+
serde_json::json!({
600+
"CP_CanFuncReqId": 2015
601+
})
602+
);
603+
}
595604
}
596605
}

src/serde.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,24 @@ mod tests {
8484

8585
assert_eq!(result, Some(SerdeValue::Object(expected_value)));
8686
}
87+
88+
#[test]
89+
fn it_should_parse_hexadecimal_numbers_to_decimal() {
90+
let result = parse_to_serde_value(
91+
r#"{
92+
"hex1": 0x7DF,
93+
"hex2": 0xFF,
94+
"hex3": 0x10
95+
}"#,
96+
&Default::default(),
97+
)
98+
.unwrap();
99+
100+
let mut expected_value = serde_json::map::Map::new();
101+
expected_value.insert("hex1".to_string(), SerdeValue::Number(serde_json::Number::from(2015)));
102+
expected_value.insert("hex2".to_string(), SerdeValue::Number(serde_json::Number::from(255)));
103+
expected_value.insert("hex3".to_string(), SerdeValue::Number(serde_json::Number::from(16)));
104+
105+
assert_eq!(result, Some(SerdeValue::Object(expected_value)));
106+
}
87107
}

0 commit comments

Comments
 (0)