diff options
author | stuebinm | 2024-04-12 16:17:06 +0200 |
---|---|---|
committer | stuebinm | 2024-04-12 16:17:06 +0200 |
commit | 422dbd5209fddac75412d8e7de0137f732c7dbc4 (patch) | |
tree | e315575c8f3e62df29ea1ab5f6c4886b2cbb2767 /src/queries.rs | |
parent | 0567f916d4365c8dc0be99d194fe6d157befbc81 (diff) |
some restructuring, arg handling, re-enable batchmode
Diffstat (limited to '')
-rw-r--r-- | src/queries.rs | 233 |
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()) - } -} |