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}) + +    } +} | 
