From 56c7727f94b8bb3a7fe775ed62de7858bca46e73 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Sat, 11 Mar 2023 22:33:23 +0100 Subject: [PATCH] WIP: implement function generalization --- src/context.rs | 25 +++++++++++++++++ src/grammar.pest | 12 +++++--- src/parser.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/context.rs b/src/context.rs index 400595b..3f85d62 100644 --- a/src/context.rs +++ b/src/context.rs @@ -218,6 +218,7 @@ pub enum Filter { All, Len, Sum, + Function(Func), } #[allow(dead_code)] @@ -241,6 +242,21 @@ pub enum Error { Eval(String), } +#[allow(dead_code)] +#[derive(Debug, PartialEq, Clone)] +pub enum FuncArg { + None, + Key(String), + Ord(Filter), + SubExpr(Vec), +} + +#[derive(Debug, PartialEq, Clone)] +pub struct Func { + pub name: String, + pub args: Vec, +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -362,6 +378,15 @@ macro_rules! do_comparision { }; } +impl Func { + pub fn new() -> Self { + Self { + name: String::new(), + args: Vec::new(), + } + } +} + impl FilterInner { fn eval(&self, entry: &Value) -> bool { let obj = if let Some(output) = entry.as_object() { diff --git a/src/grammar.pest b/src/grammar.pest index 6973468..d37069a 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -51,8 +51,8 @@ pick = { ((",") ~ (" ")* ~ (literal_keyed | (sub_expression_keyed | sub_expression_keyed_reversed) ))* ~ (" ")* ~ ")" } -sub_expression = { path ~ (formatsFn | lenFn | allFn | pickFn | sumFn | filterFn | child | any_child | grouped_any | descendant_child | array_index | slice | array_to | array_from)* } -sub_expression_reversed = { reverse_path ~ (formatsFn | lenFn | allFn | pickFn | sumFn | filterFn | grouped_any | child | any_child | descendant_child | array_index | slice | array_to | array_from)* } +sub_expression = { path ~ (formatsFn | lenFn | allFn | pickFn | sumFn | filterFn | child | any_child | grouped_any | descendant_child | array_index | slice | array_to | array_from | fn)* } +sub_expression_reversed = { reverse_path ~ (formatsFn | lenFn | allFn | pickFn | sumFn | filterFn | grouped_any | child | any_child | descendant_child | array_index | slice | array_to | array_from | fn)* } sub_expression_keyed = { sub_expression ~ as? } sub_expression_keyed_reversed = { sub_expression_reversed ~ as? } @@ -67,14 +67,18 @@ squashFn = { slash ~ squash } pickFn = { slash ~ pick } formats = { sharp ~ "formats" ~ whitespace ~ lparen ~ literal ~ ((",")* ~ whitespace ~ literal)+ ~ whitespace ~ rparen ~ whitespace ~ (as | asDeref)} formatsFn = { slash ~ formats } -fnCall = { sharp ~ ident ~ whitespace ~ lparen ~ ((literal|sub_expression) ~ whitespace ~ ((",")* ~ whitespace ~ (literal|sub_expression))*)? ~ whitespace ~ rparen ~ whitespace ~ (as | asDeref)? } +fnLit = { literal } +fnExpr = { sub_expression } +fnCall = { sharp ~ ident ~ whitespace ~ lparen ~ ((filterStmtCollection|fnLit|fnExpr ) ~ whitespace ~ ((",")* ~ whitespace ~ (filterStmtCollection|fnLit|fnExpr))*)? ~ whitespace ~ rparen ~ whitespace ~ (as | asDeref)? } +fn = {slash ~ fnCall} filterStmt = { ( filter_elem ~ whitespace ~ cmp ~ whitespace ~ (float | truthy | literal | number ) ) } +filterStmtCollection = { filterStmt ~ whitespace ~ (logical_cmp ~ whitespace ~ filterStmt~ whitespace)* } filter = { sharp ~ "filter" ~ lparen ~ whitespace ~ ( filterStmt ~ whitespace ~ (logical_cmp ~ whitespace ~ filterStmt~ whitespace)* ) ~ whitespace ~ rparen } filter_elem = { literal } filterFn = { slash ~ filter } expression = { (path|reverse_path) ~ - (formatsFn | lenFn | allFn | pickFn | sumFn | filterFn | grouped_any | child | any_child | descendant_child | array_index | slice | array_to | array_from)* ~ + (formatsFn | lenFn | allFn | pickFn | sumFn | filterFn | grouped_any | child | any_child | descendant_child | array_index | slice | array_to | array_from | fn)* ~ EOI } diff --git a/src/parser.rs b/src/parser.rs index bbcaf4e..522f718 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,9 +3,11 @@ use std::cell::RefCell; use std::rc::Rc; +use pest::iterators::Pair; + use crate::context::{ Filter, FilterAST, FilterInner, FilterInnerRighthand, FilterLogicalOp, FilterOp, FormatOp, - PickFilterInner, + Func, FuncArg, PickFilterInner, }; use crate::*; @@ -26,6 +28,49 @@ pub(crate) fn parse<'a>(input: &'a str) -> Result, pest::error::Erro let mut actions: Vec = vec![]; for token in root.into_inner() { match token.as_rule() { + Rule::r#fn => { + let inner: Pair = token.clone().into_inner().nth(1).unwrap(); + let mut func = Func::new(); + + func.name + .insert_str(0, inner.clone().into_inner().next().unwrap().as_str()); + + for value in inner.into_inner() { + match &value.as_rule() { + Rule::ident => {} + Rule::fnLit => { + let literal = &value + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .as_str(); + func.args.push(FuncArg::Key(literal.to_string())); + } + Rule::fnExpr => { + let expr = parse( + &value + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .as_str(), + )?; + func.args.push(FuncArg::SubExpr(expr)); + } + Rule::filterStmtCollection => { + todo!("handle filter statements"); + } + _ => { + todo!("handle unmatched arm of function generalization",); + } + } + } + + actions.push(Filter::Function(func)); + } Rule::path | Rule::reverse_path => actions.push(Filter::Root), Rule::allFn => actions.push(Filter::All), Rule::lenFn => actions.push(Filter::Len), @@ -142,10 +187,12 @@ pub(crate) fn parse<'a>(input: &'a str) -> Result, pest::error::Erro let mut arguments: Vec = vec![]; let mut elem = token.into_inner().nth(1).unwrap().into_inner(); let format = elem.next().unwrap().into_inner().as_str().to_string(); + // default alias for keyed subpath let mut alias = "unknown".to_string(); // sugar to return object containing only '{alias: eval expr}' let mut should_deref = false; + for e in elem { match e.as_rule() { Rule::literal => { @@ -746,4 +793,27 @@ mod test { ] ); } + + #[test] + fn parse_fncall() { + let actions = parse(">/#someFn('some', 'argument', >/and/path)").unwrap(); + assert_eq!( + actions, + vec![ + Filter::Root, + Filter::Function(Func { + name: "someFn".to_string(), + args: vec![ + FuncArg::Key("some".to_string()), + FuncArg::Key("argument".to_string()), + FuncArg::SubExpr(vec![ + Filter::Root, + Filter::Child("and".to_string()), + Filter::Child("path".to_string()), + ]) + ], + }) + ] + ); + } }