diff options
author | stuebinm | 2024-04-16 18:51:24 +0200 |
---|---|---|
committer | stuebinm | 2024-04-16 18:51:24 +0200 |
commit | 238dabec513eac8af699756281d5aec12720686c (patch) | |
tree | 91db54c21027c96d73add8e4702327ac1a812293 /src/pipeline.rs | |
parent | a0459645638fe1397aa4f5e01a8f9093911ccf6c (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 '')
-rw-r--r-- | src/pipeline.rs | 210 |
1 files changed, 27 insertions, 183 deletions
diff --git a/src/pipeline.rs b/src/pipeline.rs index cce3e31..c111275 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -1,168 +1,36 @@ - -use itertools::Itertools; use rnix::{match_ast, ast}; use rowan::ast::AstNode; use crate::queries::*; -use crate::queries::SyntaxKind::*; - -#[derive(Debug)] -pub struct Change { - pub node: rnix::SyntaxNode, - pub kind: ChangeKind -} - -#[derive(Copy, Clone, Debug)] -pub enum ChangeKind { - Remove, - Keep -} type NixExprs = Box<dyn Iterator<Item = rnix::SyntaxNode>>; type Pipe = (Vec<Change>, NixExprs); -macro_rules! ast_node { - ($ast:ident, $kind:ident) => { - #[derive(PartialEq, Eq, Hash)] - #[repr(transparent)] - struct $ast(SyntaxNode); - impl $ast { - #[allow(unused)] - fn cast(node: SyntaxNode) -> Option<Self> { - if node.kind() == $kind { - Some(Self(node)) - } else { - None - } - } - } - }; -} - -ast_node!(Root, ROOT); -ast_node!(Atom, ATOM); -ast_node!(List, LIST); - -#[derive(PartialEq, Eq, Hash, Debug)] -#[repr(transparent)] -struct Qexp(SyntaxNode); - -enum QexpKind { - Atom(Atom), - List(List), -} - -impl Qexp { - fn cast(node: SyntaxNode) -> Option<Self> { - if Atom::cast(node.clone()).is_some() || List::cast(node.clone()).is_some() { - Some(Qexp(node)) - } else { - None - } - } - - fn kind(&self) -> QexpKind { - Atom::cast(self.0.clone()) - .map(QexpKind::Atom) - .or_else(|| List::cast(self.0.clone()).map(QexpKind::List)) - .unwrap() - } - - fn apply(&self, _acc: Pipe) -> Pipe { - todo!() - } -} - -impl Root { - fn qexps(&self) -> impl Iterator<Item = Qexp> + '_ { - self.0.children().filter_map(Qexp::cast) - } -} - -// address nodes by their role relative to their parent -enum NixSyntaxRole { - Argument, - Function, - Attribute, - // TODO -} - -impl NixSyntaxRole { - fn from_str(from: &str) -> Option<NixSyntaxRole> { - use NixSyntaxRole::*; - Some(match from { - "Argument" => Argument, - "Function" => Function, - "Attribute" => Attribute, - _ => return None - }) - } -} - -enum Op { - Down, - DownRecursive, - Up, - UpRecursive, - NixSyntaxNode(rnix::SyntaxKind), - NixSyntaxRole(NixSyntaxRole), - Named(String) +#[derive(Debug)] +pub struct Change { + pub node: rnix::SyntaxNode, + pub kind: Operator } -impl Atom { - fn eval(&self) -> Option<i64> { - self.text().parse().ok() - } - fn as_op(&self) -> Option<Op> { - let op = match self.text().as_str() { - ">" => Op::Down, - ">>" => Op::DownRecursive, - "<" => Op::Up, - "<<" => Op::UpRecursive, - "Inherit" => Op::NixSyntaxNode(rnix::SyntaxKind::NODE_INHERIT), - "String" => Op::NixSyntaxNode(rnix::SyntaxKind::NODE_STRING), - // TODO other syntax nodes - name => if let Some(role) = NixSyntaxRole::from_str(name) { - Op::NixSyntaxRole(role) - } else { - Op::Named(name.to_owned()) - }, - }; - Some(op) - } - fn as_change(&self) -> Option<ChangeKind> { - let change = match self.text().as_str() { - "remove" => ChangeKind::Remove, - "keep" => ChangeKind::Keep, - _ => return None - }; - Some(change) - } - fn iter_args(&self) -> impl Iterator<Item = Atom> { - self.0.children().find_map(List::cast).into_iter().map(|arglist| arglist.iter()).flatten() - } - fn text(&self) -> String { - match self.0.green().children().next() { - Some(rowan::NodeOrToken::Token(token)) => token.text().to_string(), - _ => unreachable!(), - } - } +impl Filter { fn apply(&self, (mut changes, acc): Pipe) -> Pipe { - let mut acc: NixExprs = match self.as_op() { - Some(Op::Down) => Box::new(acc.map(|s| s.children()).flatten()), - Some(Op::DownRecursive) => Box::new(acc.map(|s| s.descendants()).flatten()), - Some(Op::Up) => Box::new(acc.filter_map(|s| s.parent())), - Some(Op::UpRecursive) => Box::new(acc.map(|s| s.ancestors()).flatten()), + use Selector::*; + + // several of these closures take ownership of the operator, hence clone + let mut acc: NixExprs = match self.selector.clone() { + Down => Box::new(acc.map(|s| s.children()).flatten()), + DownRecursive => Box::new(acc.map(|s| s.descendants()).flatten()), + Up => Box::new(acc.filter_map(|s| s.parent())), + UpRecursive => Box::new(acc.map(|s| s.ancestors()).flatten()), // TODO: how to select roles relative to previous node? - Some(Op::NixSyntaxNode(kind)) => Box::new(acc.filter(move |s| s.kind() == kind)), - Some(Op::NixSyntaxRole(role)) => {use NixSyntaxRole::*; match role { + NixSyntaxNode(kind) => Box::new(acc.filter(move |s| s.kind() == kind)), + NixSyntaxRole(role) => {use crate::queries::NixSyntaxRole::*; match role { Argument => Box::new(acc.filter_map(move |s| match_ast! { match s { ast::Apply(value) => value.argument().map(|s| s.syntax().to_owned()), _ => None }})), _ => todo!() }} - Some(Op::Named(name)) => - Box::new(acc + Named(name) => Box::new(acc .filter(move |node| match_ast! { match node { ast::AttrpathValue(value) => { name == value.attrpath().unwrap().to_string() @@ -178,52 +46,28 @@ impl Atom { name == value.to_string() }, _ => false - }})), - _ => todo!() + }}) + ), }; - if let Ok(arg) = self.iter_args().exactly_one() { - if let Some(change) = arg.as_change() { - let (mut nchanges, nacc): (Vec<_>, Vec<_>) = acc - .map(|node| (Change { node: node.clone(), kind: change }, node)) - .unzip(); - acc = Box::new(nacc.into_iter()); - changes.append(&mut nchanges); - } + if let Some(operator) = &self.args { + let (mut nchanges, nacc): (Vec<_>, Vec<_>) = acc + .map(|node| (Change { node: node.clone(), kind: operator.clone() }, node)) + .unzip(); + acc = Box::new(nacc.into_iter()); + changes.append(&mut nchanges); } (changes, acc) } } -impl List { - fn sexps(&self) -> impl Iterator<Item = Qexp> + '_ { - self.0.children().filter_map(Qexp::cast) - } - - fn iter(&self) -> impl Iterator<Item = Atom> { - self.0.children().filter_map(Atom::cast) - } -} - - - -impl Parse { - fn root(&self) -> Root { - Root::cast(self.syntax()).unwrap() - } - +impl Query { pub fn apply(&self, _content: &str, nexp: rnix::SyntaxNode) -> anyhow::Result<(Vec<Change>, Vec<rnix::SyntaxNode>)> { - let mut pipe: Pipe = (Vec::new(), Box::new(std::iter::once(nexp))); - for qexp in self.root().qexps() { - match qexp.kind() { - QexpKind::Atom(filter) => { - pipe = filter.apply(pipe); - } - _ => panic!("???") - } + for filter in &self.filters { + pipe = filter.apply(pipe); } // let results = |