diff options
Diffstat (limited to '')
-rw-r--r-- | src/queries.rs | 129 |
1 files changed, 129 insertions, 0 deletions
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<Filter> +} + +#[derive(Debug, Clone)] +pub struct Filter { + pub selector: Selector, + pub args: Option<Operator> +} + +#[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<T> = Result<T, Vec<ParseError>>; + +impl NixSyntaxRole { + fn from_str(from: &str) -> Option<NixSyntaxRole> { + use NixSyntaxRole::*; + Some(match from { + "Argument" => Argument, + "Function" => Function, + "Attribute" => Attribute, + _ => return None + }) + } +} + +impl Parse { + + pub fn to_query(&self) -> ParseResult<Query> { + + fn parse_operator(node: SyntaxNode) -> ParseResult<Operator> { + 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<Option<Operator>> { + 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::<ParseResult<Vec<Operator>>>(); + + 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<Filter> { + 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::<Result<Vec<Filter>, Vec<ParseError>>>() + .map(|filters| Query {filters}) + + } +} |