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 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 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}