From bf9563291d66ce644be1e85e759fb924290ea659 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Tue, 10 Feb 2026 13:48:25 +0000 Subject: [PATCH 1/2] Fix incorrect uses of ExpectedName <-> ExpectedLiteral --- engine/src/ast/index_expr.rs | 6 +++--- engine/src/rhs_types/bytes.rs | 10 +++++----- engine/src/rhs_types/regex/mod.rs | 4 ++-- engine/src/rhs_types/wildcard.rs | 2 +- engine/src/scheme.rs | 10 ++++------ 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/engine/src/ast/index_expr.rs b/engine/src/ast/index_expr.rs index dd1116cd..b9ce5a5c 100644 --- a/engine/src/ast/index_expr.rs +++ b/engine/src/ast/index_expr.rs @@ -619,7 +619,7 @@ mod tests { assert_err!( FilterParser::new(&SCHEME).lex_as::("test[-1]"), - LexErrorKind::ExpectedLiteral("expected positive integer as index"), + LexErrorKind::ExpectedName("positive integer as index"), "-1]" ); } @@ -647,13 +647,13 @@ mod tests { fn test_access_with_non_string() { assert_err!( FilterParser::new(&SCHEME).lex_as::(r#"test[a]"#), - LexErrorKind::ExpectedLiteral("expected quoted utf8 string or positive integer"), + LexErrorKind::ExpectedName("quoted utf8 string or positive integer"), "a]" ); assert_err!( FilterParser::new(&SCHEME).lex_as::(r#"map[a]"#), - LexErrorKind::ExpectedLiteral("expected quoted utf8 string or positive integer"), + LexErrorKind::ExpectedName("quoted utf8 string or positive integer"), "a]" ); } diff --git a/engine/src/rhs_types/bytes.rs b/engine/src/rhs_types/bytes.rs index b3ab6338..16830c34 100644 --- a/engine/src/rhs_types/bytes.rs +++ b/engine/src/rhs_types/bytes.rs @@ -277,7 +277,7 @@ pub(crate) fn lex_raw_string_as_str(input: &str) -> LexResult<'_, (&str, u8)> { // consume '"'` if input.as_bytes().get(start_hash_count) != Some(&b'"') { return Err(( - LexErrorKind::ExpectedName("\" or #"), + LexErrorKind::ExpectedLiteral("\" or #"), &full_input[start_hash_count..], )); } @@ -324,7 +324,7 @@ pub(crate) fn lex_quoted_or_raw_string(input: &str) -> LexResult<'_, BytesExpr> match input.as_bytes().first() { Some(b'"') => lex_quoted_string(&input[1..]), Some(b'r') => lex_raw_string(&input[1..]), - Some(_) => Err((LexErrorKind::ExpectedName("\" or r"), input)), + Some(_) => Err((LexErrorKind::ExpectedLiteral("\" or r"), input)), None => Err((LexErrorKind::EOF, input)), } } @@ -587,17 +587,17 @@ mod test { // Invalid character after 'r' or '#' assert_err!( BytesExpr::lex("r"), - LexErrorKind::ExpectedName("\" or #"), + LexErrorKind::ExpectedLiteral("\" or #"), "" ); assert_err!( BytesExpr::lex("r#ab"), - LexErrorKind::ExpectedName("\" or #"), + LexErrorKind::ExpectedLiteral("\" or #"), "ab" ); assert_err!( BytesExpr::lex("r##ab"), - LexErrorKind::ExpectedName("\" or #"), + LexErrorKind::ExpectedLiteral("\" or #"), "ab" ); diff --git a/engine/src/rhs_types/regex/mod.rs b/engine/src/rhs_types/regex/mod.rs index 3ed5b096..d1584ec5 100644 --- a/engine/src/rhs_types/regex/mod.rs +++ b/engine/src/rhs_types/regex/mod.rs @@ -116,7 +116,7 @@ impl<'i, 's> LexWith<'i, &FilterParser<'s>> for Regex { match c { b'"' => lex_regex_from_literal(&input[1..], parser), b'r' => lex_regex_from_raw_string(&input[1..], parser), - _ => Err((LexErrorKind::ExpectedName("\" or r"), input)), + _ => Err((LexErrorKind::ExpectedLiteral("\" or r"), input)), } } else { Err((LexErrorKind::EOF, input)) @@ -228,7 +228,7 @@ mod test { assert_err!( Regex::lex_with("x", &FilterParser::new(&scheme)), - LexErrorKind::ExpectedName("\" or r"), + LexErrorKind::ExpectedLiteral("\" or r"), "x" ); } diff --git a/engine/src/rhs_types/wildcard.rs b/engine/src/rhs_types/wildcard.rs index 068e50f6..68d71127 100644 --- a/engine/src/rhs_types/wildcard.rs +++ b/engine/src/rhs_types/wildcard.rs @@ -285,7 +285,7 @@ mod test { assert_err!( Wildcard::::lex_with("61:20:71:75:6F:74", &FilterParser::new(&scheme)), - LexErrorKind::ExpectedName("\" or r"), + LexErrorKind::ExpectedLiteral("\" or r"), "61:20:71:75:6F:74" ); } diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index 57031911..83a8c68c 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -66,9 +66,7 @@ impl<'i> Lex<'i> for FieldIndex { Ok(_) => RhsValue::lex_with(input, Type::Bytes), Err(_) => RhsValue::lex_with(input, Type::Int).map_err(|_| { ( - LexErrorKind::ExpectedLiteral( - "expected quoted utf8 string or positive integer", - ), + LexErrorKind::ExpectedName("quoted utf8 string or positive integer"), input, ) }), @@ -78,13 +76,13 @@ impl<'i> Lex<'i> for FieldIndex { RhsValue::Int(i) => match u32::try_from(i) { Ok(u) => Ok((FieldIndex::ArrayIndex(u), rest)), Err(_) => Err(( - LexErrorKind::ExpectedLiteral("expected positive integer as index"), + LexErrorKind::ExpectedName("positive integer as index"), input, )), }, RhsValue::Bytes(b) => match String::from_utf8(b.into()) { Ok(s) => Ok((FieldIndex::MapKey(s), rest)), - Err(_) => Err((LexErrorKind::ExpectedLiteral("expected utf8 string"), input)), + Err(_) => Err((LexErrorKind::ExpectedName("utf8 string"), input)), }, _ => unreachable!(), } @@ -1805,7 +1803,7 @@ fn test_field_lex_indexes() { assert_ok!(FieldIndex::lex("0"), FieldIndex::ArrayIndex(0)); assert_err!( FieldIndex::lex("-1"), - LexErrorKind::ExpectedLiteral("expected positive integer as index"), + LexErrorKind::ExpectedName("positive integer as index"), "-1" ); From 308b8c620e54b9829974a17449a7afd10b3e9ea8 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Mon, 9 Feb 2026 15:46:49 +0000 Subject: [PATCH 2/2] Improve error for invalid bytes on rhs --- engine/src/ast/field_expr.rs | 27 ++++++++++++++++++++++++- engine/src/scheme.rs | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 6ac30266..827ea79c 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -22,6 +22,7 @@ use sliceslice::MemchrSearcher; use std::cmp::Ordering; use std::collections::BTreeSet; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::num::IntErrorKind; #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "wasm32"))] use std::sync::LazyLock; @@ -363,7 +364,22 @@ impl ComparisonExpr { (Type::Ip, ComparisonOp::Ordering(op)) | (Type::Bytes, ComparisonOp::Ordering(op)) | (Type::Int, ComparisonOp::Ordering(op)) => { - let (rhs, input) = RhsValue::lex_with(input, lhs_type)?; + let (rhs, input) = + RhsValue::lex_with(input, lhs_type).map_err(|(kind, rest)| { + match (lhs_type, kind) { + (Type::Bytes, LexErrorKind::ParseInt { err, radix }) + if *err.kind() == IntErrorKind::InvalidDigit && radix == 16 => + { + ( + LexErrorKind::ExpectedName( + "quoted utf8 or raw or hex string", + ), + input, + ) + } + (_, kind) => (kind, rest), + } + })?; (ComparisonOpExpr::Ordering { op, rhs }, input) } (Type::Int, ComparisonOp::Int(op)) => { @@ -1214,6 +1230,15 @@ mod tests { ); } + // just check that parsing correctly reports errors + { + assert_err!( + FilterParser::new(&SCHEME).lex_as::(r#"http.host eq http.host"#), + LexErrorKind::ExpectedName("quoted utf8 or raw or hex string"), + "http.host" + ); + } + let expr = assert_ok!( FilterParser::new(&SCHEME).lex_as(r#"http.host == "example.org""#), ComparisonExpr { diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index 83a8c68c..c7df2b03 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -1231,6 +1231,30 @@ fn test_parse_error() { ); } + { + let err = scheme.parse("str eq str").unwrap_err(); + assert_eq!( + err, + ParseError { + kind: LexErrorKind::ExpectedName("quoted utf8 or raw or hex string"), + input: "str eq str", + line_number: 0, + span_start: 7, + span_len: 3 + } + ); + assert_eq!( + err.to_string(), + indoc!( + r#" + Filter parsing error (1:8): + str eq str + ^^^ expected quoted utf8 or raw or hex string + "# + ) + ); + } + { let err = scheme.parse(indoc!(r"concat(0, 0) == 0")).unwrap_err(); assert_eq!( @@ -1629,6 +1653,21 @@ fn test_parse_error_ordering_op() { ); } + { + let filter = format!("str {op} str"); + let err = scheme.parse(&filter).unwrap_err(); + assert_eq!( + err, + ParseError { + kind: LexErrorKind::ExpectedName("quoted utf8 or raw or hex string"), + input: &filter, + line_number: 0, + span_start: 7, + span_len: 3, + } + ); + } + { let filter = format!("str_arr {op} 0"); let err = scheme.parse(&filter).unwrap_err();