From 238dabec513eac8af699756281d5aec12720686c Mon Sep 17 00:00:00 2001 From: stuebinm Date: Tue, 16 Apr 2024 18:51:24 +0200 Subject: add an actual AST for the query language this incidentally also moves a lot of the parsing logic out of piplines.rs and instead keeps it in queries.rs, where it should probably be anyways, so the pipeline module can focus on just … well, applying the filter pipeline --- src/queries.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) (limited to 'src/queries.rs') diff --git a/src/queries.rs b/src/queries.rs index c1e16df..3f7be8e 100644 --- a/src/queries.rs +++ b/src/queries.rs @@ -1,6 +1,7 @@ // this is mostly based on the s-exp tutorial // https://github.com/rust-analyzer/rowan/blob/master/examples/s_expressions.rs +use itertools::Itertools; use rowan::{GreenNode, GreenNodeBuilder}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -255,4 +256,132 @@ fn test_parser() { } +#[derive(Debug, Clone)] +pub struct Query { + pub filters: Vec +} + +#[derive(Debug, Clone)] +pub struct Filter { + pub selector: Selector, + pub args: Option +} + +#[derive(Debug, Clone)] +pub enum Selector { + Down, + DownRecursive, + Up, + UpRecursive, + NixSyntaxNode(rnix::SyntaxKind), + NixSyntaxRole(NixSyntaxRole), + Named(String) +} + +#[derive(Debug, Clone)] +pub enum NixSyntaxRole { + Argument, + Function, + Attribute, + // TODO +} + +#[derive(Debug, Clone)] +pub enum Operator { + Remove, + Keep +} + +type ParseError = String; +type ParseResult = Result>; + +impl NixSyntaxRole { + fn from_str(from: &str) -> Option { + use NixSyntaxRole::*; + Some(match from { + "Argument" => Argument, + "Function" => Function, + "Attribute" => Attribute, + _ => return None + }) + } +} + +impl Parse { + + pub fn to_query(&self) -> ParseResult { + + fn parse_operator(node: SyntaxNode) -> ParseResult { + match node.to_string().as_str() { + "remove" => Ok(Operator::Remove), + "keep" => Ok(Operator::Keep), + unknown => Err(vec![format!("unknown operator {unknown}")]) + } + } + fn parse_args(node: SyntaxNode) -> ParseResult> { + let list_node = node + .children() + .find(|n| n.kind() == LIST); + + if let Some(node) = list_node { + let args = node + .children() + .map(|child| { + match child.kind() { + ATOM => parse_operator(child), + _ => unreachable!() + } + }) + .collect::>>(); + + match args { + Err(e) => Err(e), + Ok(ops) if ops.len() == 1 => Ok(Some(ops.into_iter().exactly_one().unwrap())), + _ => Err(vec!["cannot have multiple operators at the same node (for now)".to_string()]) + } + } else { + Ok(None) + } + } + fn parse_filter(node: SyntaxNode) -> ParseResult { + let text = match node.green().children().next() { + Some(rowan::NodeOrToken::Token(token)) => token.text().to_string(), + _ => unreachable!(), + }; + + use Selector::*; + let selector = match text.as_str() { + ">" => Down, + ">>" => DownRecursive, + "<" => Up, + "<<" => UpRecursive, + "Inherit" => NixSyntaxNode(rnix::SyntaxKind::NODE_INHERIT), + "String" => NixSyntaxNode(rnix::SyntaxKind::NODE_STRING), + // TODO other syntax nodes + name => if let Some(role) = self::NixSyntaxRole::from_str(name) { + NixSyntaxRole(role) + } else { + Named(name.to_owned()) + }, + }; + + let args = parse_args(node)?; + + let filter = Filter { + selector, + args + }; + Ok(filter) + } + + let root = self.syntax(); + assert_eq!(root.kind(), ROOT); + + root.children() + .map(parse_filter) + .collect::, Vec>>() + .map(|filters| Query {filters}) + + } +} -- cgit v1.2.3