From 26fd39244212902aa052ea21010b0700ea15594a Mon Sep 17 00:00:00 2001 From: m Date: Mon, 15 Jul 2024 17:18:27 -0700 Subject: [PATCH] implement filter qualifiers --- examples/inputs/qualifiers.html | 15 +++++++++++ examples/outputs/qualifiers.json | 45 ++++++++++++++++++++++++++++++++ examples/scrps/qualifiers.scrp | 7 +++++ src/frontend/parser.rs | 4 ++- src/interpreter/filter.rs | 2 +- src/interpreter/mod.rs | 16 +++++++++--- 6 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 examples/inputs/qualifiers.html create mode 100644 examples/outputs/qualifiers.json create mode 100644 examples/scrps/qualifiers.scrp diff --git a/examples/inputs/qualifiers.html b/examples/inputs/qualifiers.html new file mode 100644 index 0000000..c25456e --- /dev/null +++ b/examples/inputs/qualifiers.html @@ -0,0 +1,15 @@ + + + + + + + diff --git a/examples/outputs/qualifiers.json b/examples/outputs/qualifiers.json new file mode 100644 index 0000000..5e4ec0b --- /dev/null +++ b/examples/outputs/qualifiers.json @@ -0,0 +1,45 @@ +{ + "items": [ + { + "special": null, + "txt": "Hello! 1" + }, + { + "special": "special!", + "txt": "Hello! 2" + }, + { + "special": null, + "txt": "Hello! 3" + }, + { + "special": null, + "txt": "Hello! 4" + }, + { + "special": null, + "txt": "Hello! 5" + }, + { + "special": null, + "txt": "Hello! 6" + }, + { + "special": null, + "txt": "Hello! 7" + } + ], + "sixth": { + "special": null, + "txt": "Hello! 6" + }, + "specials": [ + null, + "special!", + null, + null, + null, + null, + null + ] +} diff --git a/examples/scrps/qualifiers.scrp b/examples/scrps/qualifiers.scrp new file mode 100644 index 0000000..9f53deb --- /dev/null +++ b/examples/scrps/qualifiers.scrp @@ -0,0 +1,7 @@ +items: li { + special: .special { txt: $text; }? | take(key: "txt")?; + txt: $text; +}*; + +specials: $items | take(key: "special")*; +sixth: $items | nth(i: 5); diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index f7a10cf..c833fd7 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -88,7 +88,9 @@ impl<'a> Parser<'a> { let lx = self.scanner.peek_non_whitespace(); match lx.token { - Token::Id | Token::Less => self.parse_element().map(RValue::Element), + Token::Id | Token::Less | Token::Dot | Token::Hash => { + self.parse_element().map(RValue::Element) + } _ => self.parse_leaf().map(RValue::Leaf), } } diff --git a/src/interpreter/filter.rs b/src/interpreter/filter.rs index 1a7f043..5b20f94 100644 --- a/src/interpreter/filter.rs +++ b/src/interpreter/filter.rs @@ -139,7 +139,7 @@ fn float<'doc>(value: PValue<'doc>) -> anyhow::Result> { fn nth<'doc>(mut value: ListIter<'doc>, i: i64) -> anyhow::Result> { match value.nth(i.try_into().context("negative indices are not supported")?) { Some(x) => Ok(x), - None => anyhow::bail!(""), + None => anyhow::bail!("No element at index {i}"), } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 049ec9b..5bd767f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -4,10 +4,10 @@ use anyhow::Context; use execution_mode::ExecutionMode; use reqwest::IntoUrl; -use value::EValue; +use value::{EValue, ListIter}; use crate::frontend::{ - ast::{AstRef, Element, FilterList, Inline, Leaf, RValue, Statement, StatementList}, + ast::{AstRef, Element, FilterList, Inline, Leaf, Qualifier, RValue, Statement, StatementList}, AstArena, }; @@ -233,7 +233,16 @@ impl<'ast> Interpreter<'ast> { .map(|arg| Ok((arg.id, ctx.leaf_to_value(&arg.value)?))) .collect::>>()?; - filter::dispatch_filter(filter.id, value, args, ctx) + match filter.qualifier { + Qualifier::One => filter::dispatch_filter(filter.id, value, args, ctx), + Qualifier::Optional if matches!(value, Value::Null) => Ok(Value::Null), + Qualifier::Optional => filter::dispatch_filter(filter.id, value, args, ctx), + Qualifier::Collection => value + .try_unwrap::()? + .map(|value| filter::dispatch_filter(filter.id, value, args.clone(), ctx)) + .collect::>>() + .map(Value::List), + } }) .map(EValue::from) } @@ -408,5 +417,6 @@ mod tests { integration_test! { abc, attr, + qualifiers, } }