rnix/ast/
nodes.rs

1use crate::{NixLanguage, SyntaxKind, SyntaxKind::*, SyntaxNode, SyntaxToken};
2
3use super::{operators::BinOpKind, support::*, AstNode, UnaryOpKind};
4use rowan::ast::{AstChildren, AstNode as OtherAstNode};
5
6pub trait HasEntry: AstNode {
7    fn entries(&self) -> AstChildren<Entry>
8    where
9        Self: Sized,
10    {
11        children(self)
12    }
13
14    fn attrpath_values(&self) -> AstChildren<AttrpathValue>
15    where
16        Self: Sized,
17    {
18        children(self)
19    }
20
21    fn inherits(&self) -> AstChildren<Inherit>
22    where
23        Self: Sized,
24    {
25        children(self)
26    }
27}
28
29macro_rules! node {
30    (
31        #[from($kind:ident)]
32        $(#[$meta:meta])*
33        struct $name:ident;
34    ) => {
35        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
36        $(#[$meta])*
37        pub struct $name(pub(super) SyntaxNode);
38
39        impl std::fmt::Display for $name {
40            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41                std::fmt::Display::fmt(self.syntax(), f)
42            }
43        }
44
45        impl rowan::ast::AstNode for $name {
46            type Language = crate::NixLanguage;
47
48            fn can_cast(kind: crate::SyntaxKind) -> bool {
49                kind == $kind
50            }
51
52            fn cast(from: SyntaxNode) -> Option<Self> {
53                if Self::can_cast(from.kind()) {
54                    Some(Self(from))
55                } else {
56                    None
57                }
58            }
59            fn syntax(&self) -> &SyntaxNode {
60                &self.0
61            }
62        }
63
64        impl $name {
65            pub const KIND: SyntaxKind = $kind;
66        }
67    };
68    (
69        #[from($($variant:ident),* $(,)?)]
70        $(#[$meta:meta])*
71        enum $name:ident;
72    ) => {
73        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
74        $(#[$meta])*
75        pub enum $name {
76            $(
77                $variant($variant),
78            )*
79        }
80
81        impl std::fmt::Display for $name {
82            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83                std::fmt::Display::fmt(self.syntax(), f)
84            }
85        }
86
87        impl rowan::ast::AstNode for $name {
88            type Language = NixLanguage;
89
90            fn can_cast(kind: SyntaxKind) -> bool {
91                matches!(kind, $($variant::KIND)|*)
92            }
93
94            fn cast(syntax: SyntaxNode) -> Option<Self> {
95                let res = match syntax.kind() {
96                    $(
97                        $variant::KIND => $name::$variant($variant(syntax))
98                    ),*,
99                    _ => return None,
100                };
101                Some(res)
102            }
103
104            fn syntax(&self) -> &SyntaxNode {
105                match self {
106                    $(
107                        $name::$variant(it) => &it.0,
108                    )*
109                }
110            }
111        }
112
113        $(
114            impl From<$variant> for $name {
115                fn from(node: $variant) -> $name { $name::$variant(node) }
116            }
117
118            impl TryFrom<$name> for $variant {
119                type Error = ();
120
121                fn try_from(node: $name) -> Result<$variant, ()> {
122                    match node {
123                        $name::$variant(it) => Ok(it),
124                        _ => Err(()),
125                    }
126                }
127            }
128        )*
129    };
130}
131
132macro_rules! tg {
133    (
134        $(#[doc=$doc:tt])?
135        $name:ident,
136        $token:tt
137    ) => {
138        $(#[doc=$doc])?
139        pub fn $name(&self) -> Option<SyntaxToken> {
140            token_u(self, T![$token])
141        }
142    };
143}
144
145macro_rules! ng {
146    (
147        $(#[$meta:meta])*
148        $name:ident,
149        $ty:ty,
150        $i:expr
151    ) => {
152        $(#[$meta])*
153        pub fn $name(&self) -> Option<$ty> {
154            nth(self, $i)
155        }
156    };
157    (
158        $(#[$meta:meta])*
159        $name:ident,
160        [$ty:ty]
161    ) => {
162        $(#[$meta])*
163        pub fn $name(&self) -> AstChildren<$ty> {
164            children(self)
165        }
166    };
167}
168
169node! { #[from(NODE_LITERAL)] struct Literal; }
170
171node! {
172    #[from(
173        Apply,
174        Assert,
175        Error,
176        IfElse,
177        Select,
178        Str,
179        Path,
180        Literal,
181        Lambda,
182        LegacyLet,
183        LetIn,
184        List,
185        BinOp,
186        Paren,
187        Root,
188        AttrSet,
189        UnaryOp,
190        Ident,
191        With,
192        HasAttr,
193    )]
194    /// An expression. The fundamental nix ast type.
195    enum Expr;
196}
197
198node! {
199    #[from(
200        Ident,
201        Dynamic,
202        Str,
203    )]
204    enum Attr;
205}
206
207node! { #[from(NODE_IDENT)] struct Ident; }
208
209impl Ident {
210    // A NODE_IDENT may either have a nested TOKEN_OR if the identifier was "or" or TOKEN_IDENT for everything else
211    tg! { ident_token, TOKEN_IDENT }
212}
213
214node! { #[from(NODE_APPLY)] struct Apply; }
215
216impl Apply {
217    ng! { lambda, Expr, 0 }
218    ng! { argument, Expr, 1 }
219}
220
221node! { #[from(NODE_ASSERT)] struct Assert; }
222
223impl Assert {
224    tg! { assert_token, assert }
225    ng! { condition, Expr, 0 }
226    ng! { body, Expr, 1 }
227}
228
229node! { #[from(NODE_ATTRPATH)] struct Attrpath; }
230
231impl Attrpath {
232    ng! { attrs, [Attr] }
233}
234
235node! { #[from(NODE_DYNAMIC)] struct Dynamic; }
236
237impl Dynamic {
238    tg! { interpol_start_token, TOKEN_INTERPOL_START }
239    ng! { expr, Expr, 0 }
240    tg! { interpol_end_token, TOKEN_INTERPOL_END }
241}
242
243node! { #[from(NODE_ERROR)] struct Error; }
244
245node! { #[from(NODE_IF_ELSE)] struct IfElse; }
246
247impl IfElse {
248    tg! { if_token, if }
249    ng! { condition, Expr, 0 }
250    tg! { then_token, then }
251    ng! { body, Expr, 1 }
252    tg! { else_token, else }
253    ng! { else_body, Expr, 2 }
254}
255
256node! { #[from(NODE_SELECT)] struct Select; }
257
258impl Select {
259    ng! { expr, Expr, 0 }
260    tg! { dot_token, . }
261    ng! { attrpath, Attrpath, 0 }
262    tg! { or_token, or }
263    ng! { default_expr, Expr, 1 }
264}
265
266node! { #[from(NODE_INHERIT)] struct Inherit; }
267
268impl Inherit {
269    tg! { inherit_token, inherit }
270    ng! { from, InheritFrom, 0 }
271    ng! { attrs, [Attr] }
272}
273
274node! { #[from(NODE_INHERIT_FROM)] struct InheritFrom; }
275
276impl InheritFrom {
277    tg! { l_paren_token, '(' }
278    ng! { expr, Expr, 0 }
279    tg! { r_paren_token, ')' }
280}
281
282node! { #[from(NODE_PATH)] struct Path; }
283
284node! { #[from(NODE_STRING)] struct Str; }
285
286node! { #[from(NODE_INTERPOL)] struct Interpol; }
287
288impl Interpol {
289    ng! { expr, Expr, 0 }
290}
291
292node! { #[from(NODE_LAMBDA)] struct Lambda; }
293
294impl Lambda {
295    ng! { param, Param, 0 }
296    tg! { token_colon, : }
297    ng! { body, Expr, 0 }
298}
299
300node! { #[from(NODE_LEGACY_LET)] struct LegacyLet; }
301
302impl HasEntry for LegacyLet {}
303
304impl LegacyLet {
305    tg! { let_token, let }
306    tg! { curly_open_token, '{' }
307    tg! { curly_close_token, '}' }
308}
309
310node! { #[from(NODE_LET_IN)] struct LetIn; }
311
312impl HasEntry for LetIn {}
313
314impl LetIn {
315    tg! { let_token, let }
316    tg! { in_token, in }
317    ng! { body, Expr, 0 }
318}
319
320node! { #[from(NODE_LIST)] struct List; }
321
322impl List {
323    tg! { l_brack_token, '[' }
324    ng! { items, [Expr] }
325    tg! { r_brack_token, ']' }
326}
327
328node! { #[from(NODE_BIN_OP)] struct BinOp; }
329
330impl BinOp {
331    ng! { lhs, Expr, 0 }
332
333    pub fn operator(&self) -> Option<BinOpKind> {
334        children_tokens_u(self).find_map(|t| BinOpKind::from_kind(t.kind()))
335    }
336
337    ng! { rhs, Expr, 1 }
338}
339
340node! { #[from(NODE_PAREN)] struct Paren; }
341
342impl Paren {
343    tg! { l_paren_token, '(' }
344    ng! { expr, Expr, 0 }
345    tg! { r_paren_token, ')' }
346}
347
348node! { #[from(NODE_PAT_BIND)] struct PatBind; }
349
350impl PatBind {
351    ng! { ident, Ident, 0 }
352}
353
354node! { #[from(NODE_PAT_ENTRY)] struct PatEntry; }
355
356impl PatEntry {
357    ng! { ident, Ident, 0 }
358    tg! { question_token, ? }
359    ng! { default, Expr, 1 }
360}
361
362node! { #[from(NODE_IDENT_PARAM)] struct IdentParam; }
363
364impl IdentParam {
365    ng! { ident, Ident, 0 }
366}
367
368node! {
369    #[from(
370        Pattern,
371        IdentParam,
372    )]
373    enum Param;
374}
375
376node! { #[from(NODE_PATTERN)] struct Pattern; }
377
378impl Pattern {
379    tg! { at_token, @ }
380    ng! { pat_entries, [PatEntry] }
381    tg! { ellipsis_token, ... }
382    ng! { pat_bind, PatBind, 0 }
383}
384
385node! { #[from(NODE_ROOT)] struct Root; }
386
387impl Root {
388    ng! { expr, Expr, 0 }
389}
390
391node! { #[from(NODE_ATTR_SET)] struct AttrSet; }
392
393impl HasEntry for AttrSet {}
394
395impl AttrSet {
396    tg! { rec_token, rec }
397    tg! { l_curly_token, '{' }
398    tg! { r_curly_token, '}' }
399}
400
401node! {
402    #[from(
403        Inherit,
404        AttrpathValue,
405    )]
406    enum Entry;
407}
408
409node! { #[from(NODE_ATTRPATH_VALUE)] struct AttrpathValue; }
410
411impl AttrpathValue {
412    ng! { attrpath, Attrpath, 0 }
413    tg! { assign_token, = }
414    ng! { value, Expr, 0 }
415}
416
417node! { #[from(NODE_UNARY_OP)] struct UnaryOp; }
418
419impl UnaryOp {
420    pub fn operator(&self) -> Option<UnaryOpKind> {
421        children_tokens_u(self).find_map(|t| UnaryOpKind::from_kind(t.kind()))
422    }
423    ng! { expr, Expr, 0 }
424}
425
426node! { #[from(NODE_WITH)] struct With; }
427
428impl With {
429    tg! { with_token, with }
430    ng! { namespace, Expr, 0 }
431    tg! { semicolon_token, ; }
432    ng! { body, Expr, 1 }
433}
434
435node! { #[from(NODE_HAS_ATTR)] struct HasAttr; }
436
437impl HasAttr {
438    ng! { expr, Expr, 0 }
439    tg! { question_token, ? }
440    ng! { attrpath, Attrpath, 0 }
441}