summaryrefslogtreecommitdiff
path: root/src/queries.rs
diff options
context:
space:
mode:
authorstuebinm2024-04-16 18:51:24 +0200
committerstuebinm2024-04-16 18:51:24 +0200
commit238dabec513eac8af699756281d5aec12720686c (patch)
tree91db54c21027c96d73add8e4702327ac1a812293 /src/queries.rs
parenta0459645638fe1397aa4f5e01a8f9093911ccf6c (diff)
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
Diffstat (limited to 'src/queries.rs')
-rw-r--r--src/queries.rs129
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})
+
+ }
+}