summaryrefslogtreecommitdiff
path: root/src/queries.rs
diff options
context:
space:
mode:
authorstuebinm2024-04-12 16:17:06 +0200
committerstuebinm2024-04-12 16:17:06 +0200
commit422dbd5209fddac75412d8e7de0137f732c7dbc4 (patch)
treee315575c8f3e62df29ea1ab5f6c4886b2cbb2767 /src/queries.rs
parent0567f916d4365c8dc0be99d194fe6d157befbc81 (diff)
some restructuring, arg handling, re-enable batchmode
Diffstat (limited to '')
-rw-r--r--src/queries.rs233
1 files changed, 40 insertions, 193 deletions
diff --git a/src/queries.rs b/src/queries.rs
index b07224a..c1e16df 100644
--- a/src/queries.rs
+++ b/src/queries.rs
@@ -1,9 +1,43 @@
// this is mostly based on the s-exp tutorial
// https://github.com/rust-analyzer/rowan/blob/master/examples/s_expressions.rs
-use rnix::{match_ast, ast};
-use rowan::{GreenNode, GreenNodeBuilder, ast::AstNode};
+use rowan::{GreenNode, GreenNodeBuilder};
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[allow(non_camel_case_types)]
+#[repr(u16)]
+pub enum SyntaxKind {
+ L_BRACKET = 0, // '['
+ R_BRACKET, // ']'
+ WORD, // 'Attrset', 'meta', '.', '>', ...
+ WHITESPACE, // whitespaces is explicit
+ ERROR, // as well as errors
+
+ // composite nodes
+ LIST, // `[..]`
+ ATOM, // wraps WORD
+ ROOT, // top-level (a complete query)
+}
+use SyntaxKind::*;
+
+impl From<SyntaxKind> for rowan::SyntaxKind {
+ fn from(kind: SyntaxKind) -> Self {
+ Self(kind as u16)
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum QueryLang {}
+impl rowan::Language for QueryLang {
+ type Kind = SyntaxKind;
+ fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
+ assert!(raw.0 <= ROOT as u16);
+ unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
+ }
+ fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
+ kind.into()
+ }
+}
fn lex(text: &str) -> Vec<(SyntaxKind, String)> {
fn tok(t: SyntaxKind) -> m_lexer::TokenKind {
@@ -43,42 +77,7 @@ fn lex(text: &str) -> Vec<(SyntaxKind, String)> {
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[allow(non_camel_case_types)]
-#[repr(u16)]
-enum SyntaxKind {
- L_BRACKET = 0, // '['
- R_BRACKET, // ']'
- WORD, // 'Attrset', 'meta', '.', '>', ...
- WHITESPACE, // whitespaces is explicit
- ERROR, // as well as errors
-
- // composite nodes
- LIST, // `[..]`
- ATOM, // wraps WORD
- ROOT, // top-level (a complete query)
-}
-use SyntaxKind::*;
-
-impl From<SyntaxKind> for rowan::SyntaxKind {
- fn from(kind: SyntaxKind) -> Self {
- Self(kind as u16)
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-enum Lang {}
-impl rowan::Language for Lang {
- type Kind = SyntaxKind;
- fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
- assert!(raw.0 <= ROOT as u16);
- unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
- }
- fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
- kind.into()
- }
-}
-
+#[derive(Clone)]
pub struct Parse {
pub green_node: GreenNode,
pub errors: Vec<String>,
@@ -207,14 +206,14 @@ pub fn parse(text: &str) -> Parse {
/// but it contains parent pointers, offsets, and
/// has identity semantics.
-type SyntaxNode = rowan::SyntaxNode<Lang>;
+pub type SyntaxNode = rowan::SyntaxNode<QueryLang>;
#[allow(unused)]
-type SyntaxToken = rowan::SyntaxToken<Lang>;
+type SyntaxToken = rowan::SyntaxToken<QueryLang>;
#[allow(unused)]
type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
impl Parse {
- fn syntax(&self) -> SyntaxNode {
+ pub fn syntax(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green_node.clone())
}
}
@@ -257,155 +256,3 @@ fn test_parser() {
-type NixExprs = Box<dyn Iterator<Item = rnix::SyntaxNode>>;
-
-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);
-
-// Sexp is slightly different, so let's do it by hand.
-#[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: NixExprs) -> NixExprs {
- todo!()
- }
-}
-
-// Let's enhance AST nodes with ancillary functions and
-// eval.
-impl Root {
- fn qexps(&self) -> impl Iterator<Item = Qexp> + '_ {
- self.0.children().filter_map(Qexp::cast)
- }
-}
-
-enum Op {
- Down,
- DownRecursive,
- Up,
- UpRecursive,
- Named(String)
-}
-
-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,
- name => Op::Named(name.to_owned()),
- };
- Some(op)
- }
- fn text(&self) -> String {
- match self.0.green().children().next() {
- Some(rowan::NodeOrToken::Token(token)) => token.text().to_string(),
- _ => unreachable!(),
- }
- }
- fn apply(&self, acc: NixExprs) -> 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()),
- Some(Op::Named(name)) =>
- Box::new(acc
- .filter(move |node| match_ast! { match node {
- ast::AttrpathValue(value) => {
- name == value.attrpath().unwrap().to_string()
- },
- ast::Apply(value) => {
- // TODO: special case lambda = NODE_SELECT here?
- name == value.lambda().unwrap().to_string()
- },
- // TODO: this is difficult — I want to use free-form names
- // to select things below, too, but that might not always be
- // possible
- ast::Ident(value) => {
- name == value.to_string()
- },
- _ => false
- }})),
- _ => todo!()
- }
- }
-}
-
-impl List {
- fn sexps(&self) -> impl Iterator<Item = Qexp> + '_ {
- self.0.children().filter_map(Qexp::cast)
- }
-}
-
-
-impl Parse {
- fn root(&self) -> Root {
- Root::cast(self.syntax()).unwrap()
- }
-
- pub fn apply(&self, _content: &str, nexp: rnix::SyntaxNode) -> anyhow::Result<Vec<rnix::SyntaxNode>> {
-
- let mut acc: NixExprs = Box::new(std::iter::once(nexp));
-
- for qexp in self.root().qexps() {
- match qexp.kind() {
- QexpKind::Atom(filter) => {
- acc = filter.apply(acc);
- }
- _ => panic!("???")
- }
- }
-
- // let results =
- // acc.map(|node| content[node.text_range().start().into()..node.text_range().end().into()].to_owned())
- // .collect();
-
- Ok(acc.collect())
- }
-}