1#[macro_use]
2mod macros;
3pub mod ast;
4mod kinds;
5pub mod parser;
6#[cfg(test)]
7mod tests;
8mod token_set;
9pub mod tokenizer;
10
11use std::marker::PhantomData;
12
13pub use self::{kinds::SyntaxKind, tokenizer::tokenize};
14
15use ast::AstNode;
16use parser::ParseError;
17use rowan::GreenNode;
18pub use rowan::{NodeOrToken, TextRange, TextSize, TokenAtOffset, WalkEvent};
19pub(crate) use token_set::TokenSet;
20
21use self::tokenizer::Tokenizer;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub enum NixLanguage {}
25
26impl rowan::Language for NixLanguage {
27 type Kind = SyntaxKind;
28 fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
29 let discriminant: u16 = raw.0;
30 assert!(discriminant <= (SyntaxKind::__LAST as u16));
31 unsafe { std::mem::transmute::<u16, SyntaxKind>(discriminant) }
32 }
33 fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
34 rowan::SyntaxKind(kind as u16)
35 }
36}
37
38pub type SyntaxNode = rowan::SyntaxNode<NixLanguage>;
39pub type SyntaxToken = rowan::SyntaxToken<NixLanguage>;
40pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
41pub type SyntaxElementChildren = rowan::SyntaxElementChildren<NixLanguage>;
42pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<NixLanguage>;
43
44pub use ast::Root;
45
46impl Root {
47 pub fn parse(s: &str) -> Parse<Root> {
48 let (green, errors) = parser::parse(Tokenizer::new(s));
49 Parse { green, errors, _ty: PhantomData }
50 }
51}
52
53#[derive(Clone)]
55pub struct Parse<T> {
56 green: GreenNode,
57 errors: Vec<ParseError>,
58 _ty: PhantomData<fn() -> T>,
59}
60
61impl<T> Parse<T> {
62 pub fn syntax(&self) -> SyntaxNode {
63 SyntaxNode::new_root(self.green.clone())
64 }
65}
66
67impl<T: AstNode> Parse<T> {
68 pub fn tree(&self) -> T {
69 T::cast(self.syntax()).unwrap()
70 }
71
72 pub fn errors(&self) -> &[ParseError] {
74 &*self.errors
75 }
76
77 pub fn ok(self) -> Result<T, ParseError> {
79 if let Some(err) = self.errors().first() {
80 return Err(err.clone());
81 }
82 Ok(self.tree())
83 }
84}
85
86#[macro_export]
101macro_rules! match_ast {
102 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
103
104 (match ($node:expr) {
105 $( ast::$ast:ident($it:pat) => $res:expr, )*
106 _ => $catch_all:expr $(,)?
107 }) => {{
108 $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
109 { $catch_all }
110 }};
111}