From 508b54586102919bd945c2ccf4de36b557a0a805 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Wed, 10 Sep 2025 16:22:01 -0300 Subject: [PATCH] refactor: Refactor filter parsing to use comma separation and JSON values Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) --- src/parser/filter.pest | 57 +++++++++++++++---------------------- src/parser/filter_parser.rs | 29 ++----------------- 2 files changed, 26 insertions(+), 60 deletions(-) diff --git a/src/parser/filter.pest b/src/parser/filter.pest index fedef7f..3333e20 100644 --- a/src/parser/filter.pest +++ b/src/parser/filter.pest @@ -1,41 +1,30 @@ WHITESPACE = _{ " " | "\t" | "\n" | "\r" } -//! This Pest grammar defines the syntax for filter chains used in the Keep application. +filters = { filter ~ ("," ~ filters)? } +filter = { filter_name ~ ("(" ~ options ~ ")")? } +filter_name = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* } -// Main entry point for parsing multiple filters separated by pipes -filters = { SOI ~ filter ~ (pipe ~ filter)* ~ EOI } +options = { option ~ ("," ~ options)? } +option = { (option_name ~ "=")? ~ option_value } +option_name = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* } -// A single filter with optional options -filter = { filter_name ~ options? } +option_value = { + JSON_NUMBER | + JSON_STRING | + JSON_BOOLEAN +} -// Filter name (alphanumeric with underscores) -filter_name = @{ [a-zA-Z_][a-zA-Z0-9_]* } +JSON_NUMBER = @{ + ("-")? ~ + ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) ~ + ("." ~ ASCII_DIGIT*)? ~ + (("e" | "E") ~ ("+" | "-")? ~ ASCII_DIGIT+)? +} -// Options block with parentheses -options = { "(" ~ WO ~ option* ~ WO ~ ")" } +JSON_STRING = ${ + "\"" ~ + (("\\" ~ ANY) | (!("\"" | "\\") ~ ANY))* ~ + "\"" +} -// Single option: either named (name=value) or unnamed (just value) -option = { WO ~ (option_name ~ WO ~ "=" ~ WO ~ option_value | option_value) } - -// Option name (alphanumeric with underscores) -option_name = @{ [a-zA-Z_][a-zA-Z0-9_]* } - -// Option value: number, boolean, or quoted string -option_value = { number | boolean | string } - -// Simple number (integer or float) -number = @{ ("-")? ~ [0-9]+ ~ ('.' ~ [0-9]+)? } - -// Boolean true or false -boolean = { "true" | "false" } - -// Quoted string (double or single quotes) -string = { (dquote ~ (!dquote ~ [^"])* ~ dquote) | (squote ~ (!squote ~ [^'])* ~ squote) } -dquote = { '"' } -squote = { '\'' } - -// Pipe separator -pipe = { "|" } - -// Optional whitespace -WO = { (WHITESPACE)* } +JSON_BOOLEAN = ${ "true" | "false" } diff --git a/src/parser/filter_parser.rs b/src/parser/filter_parser.rs index adf1765..308c9bf 100644 --- a/src/parser/filter_parser.rs +++ b/src/parser/filter_parser.rs @@ -1,6 +1,7 @@ use pest::Parser; use pest_derive::Parser; use std::collections::HashMap; +use serde_json; #[derive(Parser)] #[grammar = "filter.pest"] @@ -66,31 +67,7 @@ pub fn parse_filter_string(input: &str) -> Result, Box Result> { - // Try to parse as number - if let Ok(num) = input.parse::() { - return Ok(serde_json::Value::Number(num.into())); - } - if let Ok(num) = input.parse::() { - if let Some(number) = serde_json::Number::from_f64(num) { - return Ok(serde_json::Value::Number(number)); - } - } - - // Try to parse as boolean - if let Ok(boolean) = input.parse::() { - return Ok(serde_json::Value::Bool(boolean)); - } - - // Treat as string (remove quotes if present) - let value = if input.starts_with('"') && input.ends_with('"') { - input[1..input.len()-1].to_string() - } else if input.starts_with('\'') && input.ends_with('\'') { - input[1..input.len()-1].to_string() - } else { - input.to_string() - }; - - Ok(serde_json::Value::String(value)) + serde_json::from_str(input).map_err(|e| Box::new(e) as Box) } #[cfg(test)] @@ -128,7 +105,7 @@ mod tests { #[test] fn test_parse_multiple_filters() { - let result = parse_filter_string(r#"head_lines(10)|grep(pattern="error")"#).unwrap(); + let result = parse_filter_string(r#"head_lines(10),grep(pattern="error")"#).unwrap(); assert_eq!(result.len(), 2); assert_eq!(result[0].name, "head_lines"); assert_eq!(result[0].options.len(), 1);