summaryrefslogtreecommitdiff
path: root/src/pipeline.rs
diff options
context:
space:
mode:
authorstuebinm2024-04-16 18:51:24 +0200
committerstuebinm2024-04-16 18:51:24 +0200
commit238dabec513eac8af699756281d5aec12720686c (patch)
tree91db54c21027c96d73add8e4702327ac1a812293 /src/pipeline.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 '')
-rw-r--r--src/pipeline.rs210
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 =