From 104411dc7a663c21415e0f5d99a0f59f41f0a6c0 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sun, 18 Oct 2026 23:06:53 +0200 Subject: [PATCH] Read doubled-sign integers like --280 in the COS lexer (#3299) * Read doubled-sign integers like --280 in the COS lexer Fixes #3111 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 * COS lexer: strip the doubled sign without allocating Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Haiku 5.5 Co-authored-by: Brandon Thomas --- crates/cos/src/parser.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/crates/cos/src/parser.rs b/crates/cos/src/parser.rs index 8ac8a195b..c9689d7fe 100644 --- a/crates/cos/src/parser.rs +++ b/crates/cos/src/parser.rs @@ -337,11 +337,14 @@ impl<'a> Lexer<'a> { } return Ok(Object::Real(0.0)); } - match s.trim_start_matches('+').parse::() { + // Tolerate a doubled sign ("--280") like the real branch does. + let t = s.trim_start_matches('+'); + let cleaned = t.strip_prefix('-').filter(|r| r.starts_with('-')).unwrap_or(t); + match cleaned.parse::() { Ok(v) => Ok(Object::Int(v)), Err(_) => { // Out-of-range integers are treated as reals (ยง7.3.3 allows implementation limits). - s.parse::().map(Object::Real).map_err(|_| CosError::Syntax { offset: start, detail: format!("bad number {s:?}") }) + cleaned.parse::().map(Object::Real).map_err(|_| CosError::Syntax { offset: start, detail: format!("bad number {s:?}") }) } } } @@ -475,6 +478,20 @@ mod tests { Lexer::new(s.as_bytes(), 0).object().unwrap_or_else(|e| panic!("{s}: {e}")) } + #[test] + fn doubled_sign_integer_reads_like_the_real_form() { + // Some writers emit a TJ kerning as "--280"; the real form "--280.0" is already read. + assert_eq!(obj("--280.0"), Object::Real(-280.0)); + assert_eq!(obj("--280"), Object::Int(-280)); + match obj("[(Hello) --280 (World)]") { + Object::Array(items) => { + assert_eq!(items.len(), 3); + assert_eq!(items[1], Object::Int(-280)); + } + other => panic!("not an array: {other:?}"), + } + } + #[test] fn scalars() { assert_eq!(obj("true"), Object::Bool(true));