1use std::num::NonZeroUsize;
81use std::ops::Deref;
82use std::path::Path;
83use std::str::FromStr;
84
85use ecow::EcoString;
86use unscanny::Scanner;
87
88use crate::package::PackageSpec;
89use crate::{Span, SyntaxKind, SyntaxNode, is_ident, is_newline};
90
91pub trait AstNode<'a>: Sized {
93 fn from_untyped(node: &'a SyntaxNode) -> Option<Self>;
95
96 fn to_untyped(self) -> &'a SyntaxNode;
98
99 fn span(self) -> Span {
101 self.to_untyped().span()
102 }
103}
104
105impl SyntaxNode {
107 pub fn is<'a, T: AstNode<'a>>(&'a self) -> bool {
109 self.cast::<T>().is_some()
110 }
111
112 pub fn cast<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
114 T::from_untyped(self)
115 }
116
117 fn try_cast_first<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
119 self.children().find_map(Self::cast)
120 }
121
122 fn try_cast_last<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
124 self.children().rev().find_map(Self::cast)
125 }
126
127 fn cast_first<'a, T: AstNode<'a> + Default>(&'a self) -> T {
129 self.try_cast_first().unwrap_or_default()
130 }
131
132 fn cast_last<'a, T: AstNode<'a> + Default>(&'a self) -> T {
134 self.try_cast_last().unwrap_or_default()
135 }
136}
137
138macro_rules! node {
152 ($(#[$attr:meta])* struct $name:ident) => {
153 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
155 #[repr(transparent)]
156 $(#[$attr])*
157 pub struct $name<'a>(&'a SyntaxNode);
158
159 impl<'a> AstNode<'a> for $name<'a> {
160 #[inline]
161 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
162 if node.kind() == SyntaxKind::$name {
163 Some(Self(node))
164 } else {
165 Option::None
166 }
167 }
168
169 #[inline]
170 fn to_untyped(self) -> &'a SyntaxNode {
171 self.0
172 }
173 }
174
175 impl Default for $name<'_> {
176 #[inline]
177 fn default() -> Self {
178 static PLACEHOLDER: SyntaxNode
179 = SyntaxNode::placeholder(SyntaxKind::$name);
180 Self(&PLACEHOLDER)
181 }
182 }
183 };
184}
185
186node! {
187 struct Markup
189}
190
191impl<'a> Markup<'a> {
192 pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
194 let mut was_stmt = false;
195 self.0
196 .children()
197 .filter(move |node| {
198 let kind = node.kind();
200 let keep = !was_stmt || node.kind() != SyntaxKind::Space;
201 was_stmt = kind.is_stmt();
202 keep
203 })
204 .filter_map(Expr::cast_with_space)
205 }
206}
207
208#[derive(Debug, Copy, Clone, Hash)]
210pub enum Expr<'a> {
211 Text(Text<'a>),
213 Space(Space<'a>),
216 Linebreak(Linebreak<'a>),
218 Parbreak(Parbreak<'a>),
220 Escape(Escape<'a>),
222 Shorthand(Shorthand<'a>),
225 SmartQuote(SmartQuote<'a>),
227 Strong(Strong<'a>),
229 Emph(Emph<'a>),
231 Raw(Raw<'a>),
233 Link(Link<'a>),
235 Label(Label<'a>),
237 Ref(Ref<'a>),
239 Heading(Heading<'a>),
241 ListItem(ListItem<'a>),
243 EnumItem(EnumItem<'a>),
245 TermItem(TermItem<'a>),
247 Equation(Equation<'a>),
249 Math(Math<'a>),
251 MathText(MathText<'a>),
253 MathIdent(MathIdent<'a>),
255 MathShorthand(MathShorthand<'a>),
257 MathAlignPoint(MathAlignPoint<'a>),
259 MathDelimited(MathDelimited<'a>),
261 MathAttach(MathAttach<'a>),
263 MathPrimes(MathPrimes<'a>),
265 MathFrac(MathFrac<'a>),
267 MathRoot(MathRoot<'a>),
269 Ident(Ident<'a>),
271 None(None<'a>),
273 Auto(Auto<'a>),
275 Bool(Bool<'a>),
277 Int(Int<'a>),
279 Float(Float<'a>),
281 Numeric(Numeric<'a>),
283 Str(Str<'a>),
285 CodeBlock(CodeBlock<'a>),
287 ContentBlock(ContentBlock<'a>),
289 Parenthesized(Parenthesized<'a>),
291 Array(Array<'a>),
293 Dict(Dict<'a>),
295 Unary(Unary<'a>),
297 Binary(Binary<'a>),
299 FieldAccess(FieldAccess<'a>),
301 FuncCall(FuncCall<'a>),
303 Closure(Closure<'a>),
305 LetBinding(LetBinding<'a>),
307 DestructAssignment(DestructAssignment<'a>),
309 SetRule(SetRule<'a>),
311 ShowRule(ShowRule<'a>),
313 Contextual(Contextual<'a>),
315 Conditional(Conditional<'a>),
317 WhileLoop(WhileLoop<'a>),
319 ForLoop(ForLoop<'a>),
321 ModuleImport(ModuleImport<'a>),
323 ModuleInclude(ModuleInclude<'a>),
325 LoopBreak(LoopBreak<'a>),
327 LoopContinue(LoopContinue<'a>),
329 FuncReturn(FuncReturn<'a>),
331}
332
333impl<'a> Expr<'a> {
334 fn cast_with_space(node: &'a SyntaxNode) -> Option<Self> {
335 match node.kind() {
336 SyntaxKind::Space => Some(Self::Space(Space(node))),
337 _ => Self::from_untyped(node),
338 }
339 }
340}
341
342impl<'a> AstNode<'a> for Expr<'a> {
343 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
344 match node.kind() {
345 SyntaxKind::Space => Option::None, SyntaxKind::Linebreak => Some(Self::Linebreak(Linebreak(node))),
347 SyntaxKind::Parbreak => Some(Self::Parbreak(Parbreak(node))),
348 SyntaxKind::Text => Some(Self::Text(Text(node))),
349 SyntaxKind::Escape => Some(Self::Escape(Escape(node))),
350 SyntaxKind::Shorthand => Some(Self::Shorthand(Shorthand(node))),
351 SyntaxKind::SmartQuote => Some(Self::SmartQuote(SmartQuote(node))),
352 SyntaxKind::Strong => Some(Self::Strong(Strong(node))),
353 SyntaxKind::Emph => Some(Self::Emph(Emph(node))),
354 SyntaxKind::Raw => Some(Self::Raw(Raw(node))),
355 SyntaxKind::Link => Some(Self::Link(Link(node))),
356 SyntaxKind::Label => Some(Self::Label(Label(node))),
357 SyntaxKind::Ref => Some(Self::Ref(Ref(node))),
358 SyntaxKind::Heading => Some(Self::Heading(Heading(node))),
359 SyntaxKind::ListItem => Some(Self::ListItem(ListItem(node))),
360 SyntaxKind::EnumItem => Some(Self::EnumItem(EnumItem(node))),
361 SyntaxKind::TermItem => Some(Self::TermItem(TermItem(node))),
362 SyntaxKind::Equation => Some(Self::Equation(Equation(node))),
363 SyntaxKind::Math => Some(Self::Math(Math(node))),
364 SyntaxKind::MathText => Some(Self::MathText(MathText(node))),
365 SyntaxKind::MathIdent => Some(Self::MathIdent(MathIdent(node))),
366 SyntaxKind::MathShorthand => Some(Self::MathShorthand(MathShorthand(node))),
367 SyntaxKind::MathAlignPoint => {
368 Some(Self::MathAlignPoint(MathAlignPoint(node)))
369 }
370 SyntaxKind::MathDelimited => Some(Self::MathDelimited(MathDelimited(node))),
371 SyntaxKind::MathAttach => Some(Self::MathAttach(MathAttach(node))),
372 SyntaxKind::MathPrimes => Some(Self::MathPrimes(MathPrimes(node))),
373 SyntaxKind::MathFrac => Some(Self::MathFrac(MathFrac(node))),
374 SyntaxKind::MathRoot => Some(Self::MathRoot(MathRoot(node))),
375 SyntaxKind::Ident => Some(Self::Ident(Ident(node))),
376 SyntaxKind::None => Some(Self::None(None(node))),
377 SyntaxKind::Auto => Some(Self::Auto(Auto(node))),
378 SyntaxKind::Bool => Some(Self::Bool(Bool(node))),
379 SyntaxKind::Int => Some(Self::Int(Int(node))),
380 SyntaxKind::Float => Some(Self::Float(Float(node))),
381 SyntaxKind::Numeric => Some(Self::Numeric(Numeric(node))),
382 SyntaxKind::Str => Some(Self::Str(Str(node))),
383 SyntaxKind::CodeBlock => Some(Self::CodeBlock(CodeBlock(node))),
384 SyntaxKind::ContentBlock => Some(Self::ContentBlock(ContentBlock(node))),
385 SyntaxKind::Parenthesized => Some(Self::Parenthesized(Parenthesized(node))),
386 SyntaxKind::Array => Some(Self::Array(Array(node))),
387 SyntaxKind::Dict => Some(Self::Dict(Dict(node))),
388 SyntaxKind::Unary => Some(Self::Unary(Unary(node))),
389 SyntaxKind::Binary => Some(Self::Binary(Binary(node))),
390 SyntaxKind::FieldAccess => Some(Self::FieldAccess(FieldAccess(node))),
391 SyntaxKind::FuncCall => Some(Self::FuncCall(FuncCall(node))),
392 SyntaxKind::Closure => Some(Self::Closure(Closure(node))),
393 SyntaxKind::LetBinding => Some(Self::LetBinding(LetBinding(node))),
394 SyntaxKind::DestructAssignment => {
395 Some(Self::DestructAssignment(DestructAssignment(node)))
396 }
397 SyntaxKind::SetRule => Some(Self::SetRule(SetRule(node))),
398 SyntaxKind::ShowRule => Some(Self::ShowRule(ShowRule(node))),
399 SyntaxKind::Contextual => Some(Self::Contextual(Contextual(node))),
400 SyntaxKind::Conditional => Some(Self::Conditional(Conditional(node))),
401 SyntaxKind::WhileLoop => Some(Self::WhileLoop(WhileLoop(node))),
402 SyntaxKind::ForLoop => Some(Self::ForLoop(ForLoop(node))),
403 SyntaxKind::ModuleImport => Some(Self::ModuleImport(ModuleImport(node))),
404 SyntaxKind::ModuleInclude => Some(Self::ModuleInclude(ModuleInclude(node))),
405 SyntaxKind::LoopBreak => Some(Self::LoopBreak(LoopBreak(node))),
406 SyntaxKind::LoopContinue => Some(Self::LoopContinue(LoopContinue(node))),
407 SyntaxKind::FuncReturn => Some(Self::FuncReturn(FuncReturn(node))),
408 _ => Option::None,
409 }
410 }
411
412 fn to_untyped(self) -> &'a SyntaxNode {
413 match self {
414 Self::Text(v) => v.to_untyped(),
415 Self::Space(v) => v.to_untyped(),
416 Self::Linebreak(v) => v.to_untyped(),
417 Self::Parbreak(v) => v.to_untyped(),
418 Self::Escape(v) => v.to_untyped(),
419 Self::Shorthand(v) => v.to_untyped(),
420 Self::SmartQuote(v) => v.to_untyped(),
421 Self::Strong(v) => v.to_untyped(),
422 Self::Emph(v) => v.to_untyped(),
423 Self::Raw(v) => v.to_untyped(),
424 Self::Link(v) => v.to_untyped(),
425 Self::Label(v) => v.to_untyped(),
426 Self::Ref(v) => v.to_untyped(),
427 Self::Heading(v) => v.to_untyped(),
428 Self::ListItem(v) => v.to_untyped(),
429 Self::EnumItem(v) => v.to_untyped(),
430 Self::TermItem(v) => v.to_untyped(),
431 Self::Equation(v) => v.to_untyped(),
432 Self::Math(v) => v.to_untyped(),
433 Self::MathText(v) => v.to_untyped(),
434 Self::MathIdent(v) => v.to_untyped(),
435 Self::MathShorthand(v) => v.to_untyped(),
436 Self::MathAlignPoint(v) => v.to_untyped(),
437 Self::MathDelimited(v) => v.to_untyped(),
438 Self::MathAttach(v) => v.to_untyped(),
439 Self::MathPrimes(v) => v.to_untyped(),
440 Self::MathFrac(v) => v.to_untyped(),
441 Self::MathRoot(v) => v.to_untyped(),
442 Self::Ident(v) => v.to_untyped(),
443 Self::None(v) => v.to_untyped(),
444 Self::Auto(v) => v.to_untyped(),
445 Self::Bool(v) => v.to_untyped(),
446 Self::Int(v) => v.to_untyped(),
447 Self::Float(v) => v.to_untyped(),
448 Self::Numeric(v) => v.to_untyped(),
449 Self::Str(v) => v.to_untyped(),
450 Self::CodeBlock(v) => v.to_untyped(),
451 Self::ContentBlock(v) => v.to_untyped(),
452 Self::Array(v) => v.to_untyped(),
453 Self::Dict(v) => v.to_untyped(),
454 Self::Parenthesized(v) => v.to_untyped(),
455 Self::Unary(v) => v.to_untyped(),
456 Self::Binary(v) => v.to_untyped(),
457 Self::FieldAccess(v) => v.to_untyped(),
458 Self::FuncCall(v) => v.to_untyped(),
459 Self::Closure(v) => v.to_untyped(),
460 Self::LetBinding(v) => v.to_untyped(),
461 Self::DestructAssignment(v) => v.to_untyped(),
462 Self::SetRule(v) => v.to_untyped(),
463 Self::ShowRule(v) => v.to_untyped(),
464 Self::Contextual(v) => v.to_untyped(),
465 Self::Conditional(v) => v.to_untyped(),
466 Self::WhileLoop(v) => v.to_untyped(),
467 Self::ForLoop(v) => v.to_untyped(),
468 Self::ModuleImport(v) => v.to_untyped(),
469 Self::ModuleInclude(v) => v.to_untyped(),
470 Self::LoopBreak(v) => v.to_untyped(),
471 Self::LoopContinue(v) => v.to_untyped(),
472 Self::FuncReturn(v) => v.to_untyped(),
473 }
474 }
475}
476
477impl Expr<'_> {
478 pub fn hash(self) -> bool {
480 matches!(
481 self,
482 Self::Ident(_)
483 | Self::None(_)
484 | Self::Auto(_)
485 | Self::Bool(_)
486 | Self::Int(_)
487 | Self::Float(_)
488 | Self::Numeric(_)
489 | Self::Str(_)
490 | Self::CodeBlock(_)
491 | Self::ContentBlock(_)
492 | Self::Array(_)
493 | Self::Dict(_)
494 | Self::Parenthesized(_)
495 | Self::FieldAccess(_)
496 | Self::FuncCall(_)
497 | Self::LetBinding(_)
498 | Self::SetRule(_)
499 | Self::ShowRule(_)
500 | Self::Contextual(_)
501 | Self::Conditional(_)
502 | Self::WhileLoop(_)
503 | Self::ForLoop(_)
504 | Self::ModuleImport(_)
505 | Self::ModuleInclude(_)
506 | Self::LoopBreak(_)
507 | Self::LoopContinue(_)
508 | Self::FuncReturn(_)
509 )
510 }
511
512 pub fn is_literal(self) -> bool {
514 matches!(
515 self,
516 Self::None(_)
517 | Self::Auto(_)
518 | Self::Bool(_)
519 | Self::Int(_)
520 | Self::Float(_)
521 | Self::Numeric(_)
522 | Self::Str(_)
523 )
524 }
525}
526
527impl Default for Expr<'_> {
528 fn default() -> Self {
529 Expr::None(None::default())
530 }
531}
532
533node! {
534 struct Text
536}
537
538impl<'a> Text<'a> {
539 pub fn get(self) -> &'a EcoString {
541 self.0.text()
542 }
543}
544
545node! {
546 struct Space
549}
550
551node! {
552 struct Linebreak
554}
555
556node! {
557 struct Parbreak
559}
560
561node! {
562 struct Escape
564}
565
566impl Escape<'_> {
567 pub fn get(self) -> char {
569 let mut s = Scanner::new(self.0.text());
570 s.expect('\\');
571 if s.eat_if("u{") {
572 let hex = s.eat_while(char::is_ascii_hexdigit);
573 u32::from_str_radix(hex, 16)
574 .ok()
575 .and_then(std::char::from_u32)
576 .unwrap_or_default()
577 } else {
578 s.eat().unwrap_or_default()
579 }
580 }
581}
582
583node! {
584 struct Shorthand
587}
588
589impl Shorthand<'_> {
590 pub const LIST: &'static [(&'static str, char)] = &[
592 ("...", '…'),
593 ("~", '\u{00A0}'),
594 ("-", '\u{2212}'), ("--", '\u{2013}'),
596 ("---", '\u{2014}'),
597 ("-?", '\u{00AD}'),
598 ];
599
600 pub fn get(self) -> char {
602 let text = self.0.text();
603 Self::LIST
604 .iter()
605 .find(|&&(s, _)| s == text)
606 .map_or_else(char::default, |&(_, c)| c)
607 }
608}
609
610node! {
611 struct SmartQuote
613}
614
615impl SmartQuote<'_> {
616 pub fn double(self) -> bool {
618 self.0.text() == "\""
619 }
620}
621
622node! {
623 struct Strong
625}
626
627impl<'a> Strong<'a> {
628 pub fn body(self) -> Markup<'a> {
630 self.0.cast_first()
631 }
632}
633
634node! {
635 struct Emph
637}
638
639impl<'a> Emph<'a> {
640 pub fn body(self) -> Markup<'a> {
642 self.0.cast_first()
643 }
644}
645
646node! {
647 struct Raw
649}
650
651impl<'a> Raw<'a> {
652 pub fn lines(self) -> impl DoubleEndedIterator<Item = Text<'a>> {
654 self.0.children().filter_map(SyntaxNode::cast)
655 }
656
657 pub fn lang(self) -> Option<RawLang<'a>> {
659 let delim: RawDelim = self.0.try_cast_first()?;
661 if delim.0.len() < 3 {
662 return Option::None;
663 }
664
665 self.0.try_cast_first()
666 }
667
668 pub fn block(self) -> bool {
670 self.0
671 .try_cast_first()
672 .is_some_and(|delim: RawDelim| delim.0.len() >= 3)
673 && self.0.children().any(|e| {
674 e.kind() == SyntaxKind::RawTrimmed && e.text().chars().any(is_newline)
675 })
676 }
677}
678
679node! {
680 struct RawLang
682}
683
684impl<'a> RawLang<'a> {
685 pub fn get(self) -> &'a EcoString {
687 self.0.text()
688 }
689}
690
691node! {
692 struct RawDelim
694}
695
696node! {
697 struct Link
699}
700
701impl<'a> Link<'a> {
702 pub fn get(self) -> &'a EcoString {
704 self.0.text()
705 }
706}
707
708node! {
709 struct Label
711}
712
713impl<'a> Label<'a> {
714 pub fn get(self) -> &'a str {
716 self.0.text().trim_start_matches('<').trim_end_matches('>')
717 }
718}
719
720node! {
721 struct Ref
723}
724
725impl<'a> Ref<'a> {
726 pub fn target(self) -> &'a str {
730 self.0
731 .children()
732 .find(|node| node.kind() == SyntaxKind::RefMarker)
733 .map(|node| node.text().trim_start_matches('@'))
734 .unwrap_or_default()
735 }
736
737 pub fn supplement(self) -> Option<ContentBlock<'a>> {
739 self.0.try_cast_last()
740 }
741}
742
743node! {
744 struct Heading
746}
747
748impl<'a> Heading<'a> {
749 pub fn body(self) -> Markup<'a> {
751 self.0.cast_first()
752 }
753
754 pub fn depth(self) -> NonZeroUsize {
756 self.0
757 .children()
758 .find(|node| node.kind() == SyntaxKind::HeadingMarker)
759 .and_then(|node| node.len().try_into().ok())
760 .unwrap_or(NonZeroUsize::new(1).unwrap())
761 }
762}
763
764node! {
765 struct ListItem
767}
768
769impl<'a> ListItem<'a> {
770 pub fn body(self) -> Markup<'a> {
772 self.0.cast_first()
773 }
774}
775
776node! {
777 struct EnumItem
779}
780
781impl<'a> EnumItem<'a> {
782 pub fn number(self) -> Option<u64> {
784 self.0.children().find_map(|node| match node.kind() {
785 SyntaxKind::EnumMarker => node.text().trim_end_matches('.').parse().ok(),
786 _ => Option::None,
787 })
788 }
789
790 pub fn body(self) -> Markup<'a> {
792 self.0.cast_first()
793 }
794}
795
796node! {
797 struct TermItem
799}
800
801impl<'a> TermItem<'a> {
802 pub fn term(self) -> Markup<'a> {
804 self.0.cast_first()
805 }
806
807 pub fn description(self) -> Markup<'a> {
809 self.0.cast_last()
810 }
811}
812
813node! {
814 struct Equation
816}
817
818impl<'a> Equation<'a> {
819 pub fn body(self) -> Math<'a> {
821 self.0.cast_first()
822 }
823
824 pub fn block(self) -> bool {
826 let is_space = |node: Option<&SyntaxNode>| {
827 node.map(SyntaxNode::kind) == Some(SyntaxKind::Space)
828 };
829 is_space(self.0.children().nth(1)) && is_space(self.0.children().nth_back(1))
830 }
831}
832
833node! {
834 struct Math
836}
837
838impl<'a> Math<'a> {
839 pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
841 self.0.children().filter_map(Expr::cast_with_space)
842 }
843
844 pub fn was_deparenthesized(self) -> bool {
846 let mut iter = self.0.children();
847 matches!(iter.next().map(SyntaxNode::kind), Some(SyntaxKind::LeftParen))
848 && matches!(
849 iter.next_back().map(SyntaxNode::kind),
850 Some(SyntaxKind::RightParen)
851 )
852 }
853}
854
855node! {
856 struct MathText
858}
859
860pub enum MathTextKind<'a> {
862 Character(char),
863 Number(&'a EcoString),
864}
865
866impl<'a> MathText<'a> {
867 pub fn get(self) -> MathTextKind<'a> {
869 let text = self.0.text();
870 let mut chars = text.chars();
871 let c = chars.next().unwrap();
872 if c.is_numeric() {
873 MathTextKind::Number(text)
876 } else {
877 assert!(chars.next().is_none());
878 MathTextKind::Character(c)
879 }
880 }
881}
882
883node! {
884 struct MathIdent
886}
887
888impl<'a> MathIdent<'a> {
889 pub fn get(self) -> &'a EcoString {
891 self.0.text()
892 }
893
894 pub fn as_str(self) -> &'a str {
896 self.get()
897 }
898}
899
900impl Deref for MathIdent<'_> {
901 type Target = str;
902
903 fn deref(&self) -> &Self::Target {
906 self.as_str()
907 }
908}
909
910node! {
911 struct MathShorthand
913}
914
915impl MathShorthand<'_> {
916 pub const LIST: &'static [(&'static str, char)] = &[
918 ("...", '…'),
919 ("-", '−'),
920 ("*", '∗'),
921 ("~", '∼'),
922 ("!=", '≠'),
923 (":=", '≔'),
924 ("::=", '⩴'),
925 ("=:", '≕'),
926 ("<<", '≪'),
927 ("<<<", '⋘'),
928 (">>", '≫'),
929 (">>>", '⋙'),
930 ("<=", '≤'),
931 (">=", '≥'),
932 ("->", '→'),
933 ("-->", '⟶'),
934 ("|->", '↦'),
935 (">->", '↣'),
936 ("->>", '↠'),
937 ("<-", '←'),
938 ("<--", '⟵'),
939 ("<-<", '↢'),
940 ("<<-", '↞'),
941 ("<->", '↔'),
942 ("<-->", '⟷'),
943 ("~>", '⇝'),
944 ("~~>", '⟿'),
945 ("<~", '⇜'),
946 ("<~~", '⬳'),
947 ("=>", '⇒'),
948 ("|=>", '⤇'),
949 ("==>", '⟹'),
950 ("<==", '⟸'),
951 ("<=>", '⇔'),
952 ("<==>", '⟺'),
953 ("[|", '⟦'),
954 ("|]", '⟧'),
955 ("||", '‖'),
956 ];
957
958 pub fn get(self) -> char {
960 let text = self.0.text();
961 Self::LIST
962 .iter()
963 .find(|&&(s, _)| s == text)
964 .map_or_else(char::default, |&(_, c)| c)
965 }
966}
967
968node! {
969 struct MathAlignPoint
971}
972
973node! {
974 struct MathDelimited
976}
977
978impl<'a> MathDelimited<'a> {
979 pub fn open(self) -> Expr<'a> {
981 self.0.cast_first()
982 }
983
984 pub fn body(self) -> Math<'a> {
986 self.0.cast_first()
987 }
988
989 pub fn close(self) -> Expr<'a> {
991 self.0.cast_last()
992 }
993}
994
995node! {
996 struct MathAttach
998}
999
1000impl<'a> MathAttach<'a> {
1001 pub fn base(self) -> Expr<'a> {
1003 self.0.cast_first()
1004 }
1005
1006 pub fn bottom(self) -> Option<Expr<'a>> {
1008 self.0
1009 .children()
1010 .skip_while(|node| !matches!(node.kind(), SyntaxKind::Underscore))
1011 .find_map(SyntaxNode::cast)
1012 }
1013
1014 pub fn top(self) -> Option<Expr<'a>> {
1016 self.0
1017 .children()
1018 .skip_while(|node| !matches!(node.kind(), SyntaxKind::Hat))
1019 .find_map(SyntaxNode::cast)
1020 }
1021
1022 pub fn primes(self) -> Option<MathPrimes<'a>> {
1024 self.0
1025 .children()
1026 .skip_while(|node| node.cast::<Expr<'_>>().is_none())
1027 .nth(1)
1028 .and_then(|n| n.cast())
1029 }
1030}
1031
1032node! {
1033 struct MathPrimes
1035}
1036
1037impl MathPrimes<'_> {
1038 pub fn count(self) -> usize {
1040 self.0
1041 .children()
1042 .filter(|node| matches!(node.kind(), SyntaxKind::Prime))
1043 .count()
1044 }
1045}
1046
1047node! {
1048 struct MathFrac
1050}
1051
1052impl<'a> MathFrac<'a> {
1053 pub fn num(self) -> Expr<'a> {
1055 self.0.cast_first()
1056 }
1057
1058 pub fn denom(self) -> Expr<'a> {
1060 self.0.cast_last()
1061 }
1062}
1063
1064node! {
1065 struct MathRoot
1067}
1068
1069impl<'a> MathRoot<'a> {
1070 pub fn index(self) -> Option<u8> {
1072 match self.0.children().next().map(|node| node.text().as_str()) {
1073 Some("∜") => Some(4),
1074 Some("∛") => Some(3),
1075 Some("√") => Option::None,
1076 _ => Option::None,
1077 }
1078 }
1079
1080 pub fn radicand(self) -> Expr<'a> {
1082 self.0.cast_first()
1083 }
1084}
1085
1086node! {
1087 struct Ident
1089}
1090
1091impl<'a> Ident<'a> {
1092 pub fn get(self) -> &'a EcoString {
1094 self.0.text()
1095 }
1096
1097 pub fn as_str(self) -> &'a str {
1099 self.get()
1100 }
1101}
1102
1103impl Deref for Ident<'_> {
1104 type Target = str;
1105
1106 fn deref(&self) -> &Self::Target {
1109 self.as_str()
1110 }
1111}
1112
1113node! {
1114 struct None
1116}
1117
1118node! {
1119 struct Auto
1121}
1122
1123node! {
1124 struct Bool
1126}
1127
1128impl Bool<'_> {
1129 pub fn get(self) -> bool {
1131 self.0.text() == "true"
1132 }
1133}
1134
1135node! {
1136 struct Int
1138}
1139
1140impl Int<'_> {
1141 pub fn get(self) -> i64 {
1143 let text = self.0.text();
1144 if let Some(rest) = text.strip_prefix("0x") {
1145 i64::from_str_radix(rest, 16)
1146 } else if let Some(rest) = text.strip_prefix("0o") {
1147 i64::from_str_radix(rest, 8)
1148 } else if let Some(rest) = text.strip_prefix("0b") {
1149 i64::from_str_radix(rest, 2)
1150 } else {
1151 text.parse()
1152 }
1153 .unwrap_or_default()
1154 }
1155}
1156
1157node! {
1158 struct Float
1160}
1161
1162impl Float<'_> {
1163 pub fn get(self) -> f64 {
1165 self.0.text().parse().unwrap_or_default()
1166 }
1167}
1168
1169node! {
1170 struct Numeric
1172}
1173
1174impl Numeric<'_> {
1175 pub fn get(self) -> (f64, Unit) {
1177 let text = self.0.text();
1178 let count = text
1179 .chars()
1180 .rev()
1181 .take_while(|c| matches!(c, 'a'..='z' | '%'))
1182 .count();
1183
1184 let split = text.len() - count;
1185 let value = text[..split].parse().unwrap_or_default();
1186 let unit = match &text[split..] {
1187 "pt" => Unit::Pt,
1188 "mm" => Unit::Mm,
1189 "cm" => Unit::Cm,
1190 "in" => Unit::In,
1191 "deg" => Unit::Deg,
1192 "rad" => Unit::Rad,
1193 "em" => Unit::Em,
1194 "fr" => Unit::Fr,
1195 "%" => Unit::Percent,
1196 _ => Unit::Percent,
1197 };
1198
1199 (value, unit)
1200 }
1201}
1202
1203#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1205pub enum Unit {
1206 Pt,
1208 Mm,
1210 Cm,
1212 In,
1214 Rad,
1216 Deg,
1218 Em,
1220 Fr,
1222 Percent,
1224}
1225
1226node! {
1227 struct Str
1229}
1230
1231impl Str<'_> {
1232 pub fn get(self) -> EcoString {
1234 let text = self.0.text();
1235 let unquoted = &text[1..text.len() - 1];
1236 if !unquoted.contains('\\') {
1237 return unquoted.into();
1238 }
1239
1240 let mut out = EcoString::with_capacity(unquoted.len());
1241 let mut s = Scanner::new(unquoted);
1242
1243 while let Some(c) = s.eat() {
1244 if c != '\\' {
1245 out.push(c);
1246 continue;
1247 }
1248
1249 let start = s.locate(-1);
1250 match s.eat() {
1251 Some('\\') => out.push('\\'),
1252 Some('"') => out.push('"'),
1253 Some('n') => out.push('\n'),
1254 Some('r') => out.push('\r'),
1255 Some('t') => out.push('\t'),
1256 Some('u') if s.eat_if('{') => {
1257 let sequence = s.eat_while(char::is_ascii_hexdigit);
1258 s.eat_if('}');
1259
1260 match u32::from_str_radix(sequence, 16)
1261 .ok()
1262 .and_then(std::char::from_u32)
1263 {
1264 Some(c) => out.push(c),
1265 Option::None => out.push_str(s.from(start)),
1266 }
1267 }
1268 _ => out.push_str(s.from(start)),
1269 }
1270 }
1271
1272 out
1273 }
1274}
1275
1276node! {
1277 struct CodeBlock
1279}
1280
1281impl<'a> CodeBlock<'a> {
1282 pub fn body(self) -> Code<'a> {
1284 self.0.cast_first()
1285 }
1286}
1287
1288node! {
1289 struct Code
1291}
1292
1293impl<'a> Code<'a> {
1294 pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
1296 self.0.children().filter_map(SyntaxNode::cast)
1297 }
1298}
1299
1300node! {
1301 struct ContentBlock
1303}
1304
1305impl<'a> ContentBlock<'a> {
1306 pub fn body(self) -> Markup<'a> {
1308 self.0.cast_first()
1309 }
1310}
1311
1312node! {
1313 struct Parenthesized
1315}
1316
1317impl<'a> Parenthesized<'a> {
1318 pub fn expr(self) -> Expr<'a> {
1322 self.0.cast_first()
1323 }
1324
1325 pub fn pattern(self) -> Pattern<'a> {
1329 self.0.cast_first()
1330 }
1331}
1332
1333node! {
1334 struct Array
1336}
1337
1338impl<'a> Array<'a> {
1339 pub fn items(self) -> impl DoubleEndedIterator<Item = ArrayItem<'a>> {
1341 self.0.children().filter_map(SyntaxNode::cast)
1342 }
1343}
1344
1345#[derive(Debug, Copy, Clone, Hash)]
1347pub enum ArrayItem<'a> {
1348 Pos(Expr<'a>),
1350 Spread(Spread<'a>),
1352}
1353
1354impl<'a> AstNode<'a> for ArrayItem<'a> {
1355 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1356 match node.kind() {
1357 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1358 _ => node.cast().map(Self::Pos),
1359 }
1360 }
1361
1362 fn to_untyped(self) -> &'a SyntaxNode {
1363 match self {
1364 Self::Pos(v) => v.to_untyped(),
1365 Self::Spread(v) => v.to_untyped(),
1366 }
1367 }
1368}
1369
1370node! {
1371 struct Dict
1373}
1374
1375impl<'a> Dict<'a> {
1376 pub fn items(self) -> impl DoubleEndedIterator<Item = DictItem<'a>> {
1378 self.0.children().filter_map(SyntaxNode::cast)
1379 }
1380}
1381
1382#[derive(Debug, Copy, Clone, Hash)]
1384pub enum DictItem<'a> {
1385 Named(Named<'a>),
1387 Keyed(Keyed<'a>),
1389 Spread(Spread<'a>),
1391}
1392
1393impl<'a> AstNode<'a> for DictItem<'a> {
1394 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1395 match node.kind() {
1396 SyntaxKind::Named => Some(Self::Named(Named(node))),
1397 SyntaxKind::Keyed => Some(Self::Keyed(Keyed(node))),
1398 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1399 _ => Option::None,
1400 }
1401 }
1402
1403 fn to_untyped(self) -> &'a SyntaxNode {
1404 match self {
1405 Self::Named(v) => v.to_untyped(),
1406 Self::Keyed(v) => v.to_untyped(),
1407 Self::Spread(v) => v.to_untyped(),
1408 }
1409 }
1410}
1411
1412node! {
1413 struct Named
1415}
1416
1417impl<'a> Named<'a> {
1418 pub fn name(self) -> Ident<'a> {
1420 self.0.cast_first()
1421 }
1422
1423 pub fn expr(self) -> Expr<'a> {
1428 self.0.cast_last()
1429 }
1430
1431 pub fn pattern(self) -> Pattern<'a> {
1436 self.0.cast_last()
1437 }
1438}
1439
1440node! {
1441 struct Keyed
1443}
1444
1445impl<'a> Keyed<'a> {
1446 pub fn key(self) -> Expr<'a> {
1448 self.0.cast_first()
1449 }
1450
1451 pub fn expr(self) -> Expr<'a> {
1456 self.0.cast_last()
1457 }
1458}
1459
1460node! {
1461 struct Spread
1463}
1464
1465impl<'a> Spread<'a> {
1466 pub fn expr(self) -> Expr<'a> {
1471 self.0.cast_first()
1472 }
1473
1474 pub fn sink_ident(self) -> Option<Ident<'a>> {
1479 self.0.try_cast_first()
1480 }
1481
1482 pub fn sink_expr(self) -> Option<Expr<'a>> {
1487 self.0.try_cast_first()
1488 }
1489}
1490
1491node! {
1492 struct Unary
1494}
1495
1496impl<'a> Unary<'a> {
1497 pub fn op(self) -> UnOp {
1499 self.0
1500 .children()
1501 .find_map(|node| UnOp::from_kind(node.kind()))
1502 .unwrap_or(UnOp::Pos)
1503 }
1504
1505 pub fn expr(self) -> Expr<'a> {
1507 self.0.cast_last()
1508 }
1509}
1510
1511#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1513pub enum UnOp {
1514 Pos,
1516 Neg,
1518 Not,
1520}
1521
1522impl UnOp {
1523 pub fn from_kind(token: SyntaxKind) -> Option<Self> {
1525 Some(match token {
1526 SyntaxKind::Plus => Self::Pos,
1527 SyntaxKind::Minus => Self::Neg,
1528 SyntaxKind::Not => Self::Not,
1529 _ => return Option::None,
1530 })
1531 }
1532
1533 pub fn precedence(self) -> u8 {
1535 match self {
1536 Self::Pos | Self::Neg => 7,
1537 Self::Not => 4,
1538 }
1539 }
1540
1541 pub fn as_str(self) -> &'static str {
1543 match self {
1544 Self::Pos => "+",
1545 Self::Neg => "-",
1546 Self::Not => "not",
1547 }
1548 }
1549}
1550
1551node! {
1552 struct Binary
1554}
1555
1556impl<'a> Binary<'a> {
1557 pub fn op(self) -> BinOp {
1559 let mut not = false;
1560 self.0
1561 .children()
1562 .find_map(|node| match node.kind() {
1563 SyntaxKind::Not => {
1564 not = true;
1565 Option::None
1566 }
1567 SyntaxKind::In if not => Some(BinOp::NotIn),
1568 _ => BinOp::from_kind(node.kind()),
1569 })
1570 .unwrap_or(BinOp::Add)
1571 }
1572
1573 pub fn lhs(self) -> Expr<'a> {
1575 self.0.cast_first()
1576 }
1577
1578 pub fn rhs(self) -> Expr<'a> {
1580 self.0.cast_last()
1581 }
1582}
1583
1584#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1586pub enum BinOp {
1587 Add,
1589 Sub,
1591 Mul,
1593 Div,
1595 And,
1597 Or,
1599 Eq,
1601 Neq,
1603 Lt,
1605 Leq,
1607 Gt,
1609 Geq,
1611 Assign,
1613 In,
1615 NotIn,
1617 AddAssign,
1619 SubAssign,
1621 MulAssign,
1623 DivAssign,
1625}
1626
1627impl BinOp {
1628 pub fn from_kind(token: SyntaxKind) -> Option<Self> {
1630 Some(match token {
1631 SyntaxKind::Plus => Self::Add,
1632 SyntaxKind::Minus => Self::Sub,
1633 SyntaxKind::Star => Self::Mul,
1634 SyntaxKind::Slash => Self::Div,
1635 SyntaxKind::And => Self::And,
1636 SyntaxKind::Or => Self::Or,
1637 SyntaxKind::EqEq => Self::Eq,
1638 SyntaxKind::ExclEq => Self::Neq,
1639 SyntaxKind::Lt => Self::Lt,
1640 SyntaxKind::LtEq => Self::Leq,
1641 SyntaxKind::Gt => Self::Gt,
1642 SyntaxKind::GtEq => Self::Geq,
1643 SyntaxKind::Eq => Self::Assign,
1644 SyntaxKind::In => Self::In,
1645 SyntaxKind::PlusEq => Self::AddAssign,
1646 SyntaxKind::HyphEq => Self::SubAssign,
1647 SyntaxKind::StarEq => Self::MulAssign,
1648 SyntaxKind::SlashEq => Self::DivAssign,
1649 _ => return Option::None,
1650 })
1651 }
1652
1653 pub fn precedence(self) -> u8 {
1655 match self {
1656 Self::Mul => 6,
1657 Self::Div => 6,
1658 Self::Add => 5,
1659 Self::Sub => 5,
1660 Self::Eq => 4,
1661 Self::Neq => 4,
1662 Self::Lt => 4,
1663 Self::Leq => 4,
1664 Self::Gt => 4,
1665 Self::Geq => 4,
1666 Self::In => 4,
1667 Self::NotIn => 4,
1668 Self::And => 3,
1669 Self::Or => 2,
1670 Self::Assign => 1,
1671 Self::AddAssign => 1,
1672 Self::SubAssign => 1,
1673 Self::MulAssign => 1,
1674 Self::DivAssign => 1,
1675 }
1676 }
1677
1678 pub fn assoc(self) -> Assoc {
1680 match self {
1681 Self::Add => Assoc::Left,
1682 Self::Sub => Assoc::Left,
1683 Self::Mul => Assoc::Left,
1684 Self::Div => Assoc::Left,
1685 Self::And => Assoc::Left,
1686 Self::Or => Assoc::Left,
1687 Self::Eq => Assoc::Left,
1688 Self::Neq => Assoc::Left,
1689 Self::Lt => Assoc::Left,
1690 Self::Leq => Assoc::Left,
1691 Self::Gt => Assoc::Left,
1692 Self::Geq => Assoc::Left,
1693 Self::In => Assoc::Left,
1694 Self::NotIn => Assoc::Left,
1695 Self::Assign => Assoc::Right,
1696 Self::AddAssign => Assoc::Right,
1697 Self::SubAssign => Assoc::Right,
1698 Self::MulAssign => Assoc::Right,
1699 Self::DivAssign => Assoc::Right,
1700 }
1701 }
1702
1703 pub fn as_str(self) -> &'static str {
1705 match self {
1706 Self::Add => "+",
1707 Self::Sub => "-",
1708 Self::Mul => "*",
1709 Self::Div => "/",
1710 Self::And => "and",
1711 Self::Or => "or",
1712 Self::Eq => "==",
1713 Self::Neq => "!=",
1714 Self::Lt => "<",
1715 Self::Leq => "<=",
1716 Self::Gt => ">",
1717 Self::Geq => ">=",
1718 Self::In => "in",
1719 Self::NotIn => "not in",
1720 Self::Assign => "=",
1721 Self::AddAssign => "+=",
1722 Self::SubAssign => "-=",
1723 Self::MulAssign => "*=",
1724 Self::DivAssign => "/=",
1725 }
1726 }
1727}
1728
1729#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1731pub enum Assoc {
1732 Left,
1734 Right,
1736}
1737
1738node! {
1739 struct FieldAccess
1741}
1742
1743impl<'a> FieldAccess<'a> {
1744 pub fn target(self) -> Expr<'a> {
1746 self.0.cast_first()
1747 }
1748
1749 pub fn field(self) -> Ident<'a> {
1751 self.0.cast_last()
1752 }
1753}
1754
1755node! {
1756 struct FuncCall
1758}
1759
1760impl<'a> FuncCall<'a> {
1761 pub fn callee(self) -> Expr<'a> {
1763 self.0.cast_first()
1764 }
1765
1766 pub fn args(self) -> Args<'a> {
1768 self.0.cast_last()
1769 }
1770}
1771
1772node! {
1773 struct Args
1775}
1776
1777impl<'a> Args<'a> {
1778 pub fn items(self) -> impl DoubleEndedIterator<Item = Arg<'a>> {
1780 self.0.children().filter_map(SyntaxNode::cast)
1781 }
1782
1783 pub fn trailing_comma(self) -> bool {
1785 self.0
1786 .children()
1787 .rev()
1788 .skip(1)
1789 .find(|n| !n.kind().is_trivia())
1790 .is_some_and(|n| n.kind() == SyntaxKind::Comma)
1791 }
1792}
1793
1794#[derive(Debug, Copy, Clone, Hash)]
1796pub enum Arg<'a> {
1797 Pos(Expr<'a>),
1799 Named(Named<'a>),
1801 Spread(Spread<'a>),
1803}
1804
1805impl<'a> AstNode<'a> for Arg<'a> {
1806 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1807 match node.kind() {
1808 SyntaxKind::Named => Some(Self::Named(Named(node))),
1809 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1810 _ => node.cast().map(Self::Pos),
1811 }
1812 }
1813
1814 fn to_untyped(self) -> &'a SyntaxNode {
1815 match self {
1816 Self::Pos(v) => v.to_untyped(),
1817 Self::Named(v) => v.to_untyped(),
1818 Self::Spread(v) => v.to_untyped(),
1819 }
1820 }
1821}
1822
1823node! {
1824 struct Closure
1826}
1827
1828impl<'a> Closure<'a> {
1829 pub fn name(self) -> Option<Ident<'a>> {
1833 self.0.children().next()?.cast()
1834 }
1835
1836 pub fn params(self) -> Params<'a> {
1838 self.0.cast_first()
1839 }
1840
1841 pub fn body(self) -> Expr<'a> {
1843 self.0.cast_last()
1844 }
1845}
1846
1847node! {
1848 struct Params
1850}
1851
1852impl<'a> Params<'a> {
1853 pub fn children(self) -> impl DoubleEndedIterator<Item = Param<'a>> {
1855 self.0.children().filter_map(SyntaxNode::cast)
1856 }
1857}
1858
1859#[derive(Debug, Copy, Clone, Hash)]
1861pub enum Param<'a> {
1862 Pos(Pattern<'a>),
1864 Named(Named<'a>),
1866 Spread(Spread<'a>),
1868}
1869
1870impl<'a> AstNode<'a> for Param<'a> {
1871 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1872 match node.kind() {
1873 SyntaxKind::Named => Some(Self::Named(Named(node))),
1874 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1875 _ => node.cast().map(Self::Pos),
1876 }
1877 }
1878
1879 fn to_untyped(self) -> &'a SyntaxNode {
1880 match self {
1881 Self::Pos(v) => v.to_untyped(),
1882 Self::Named(v) => v.to_untyped(),
1883 Self::Spread(v) => v.to_untyped(),
1884 }
1885 }
1886}
1887
1888#[derive(Debug, Copy, Clone, Hash)]
1890pub enum Pattern<'a> {
1891 Normal(Expr<'a>),
1893 Placeholder(Underscore<'a>),
1895 Parenthesized(Parenthesized<'a>),
1897 Destructuring(Destructuring<'a>),
1899}
1900
1901impl<'a> AstNode<'a> for Pattern<'a> {
1902 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1903 match node.kind() {
1904 SyntaxKind::Underscore => Some(Self::Placeholder(Underscore(node))),
1905 SyntaxKind::Parenthesized => Some(Self::Parenthesized(Parenthesized(node))),
1906 SyntaxKind::Destructuring => Some(Self::Destructuring(Destructuring(node))),
1907 _ => node.cast().map(Self::Normal),
1908 }
1909 }
1910
1911 fn to_untyped(self) -> &'a SyntaxNode {
1912 match self {
1913 Self::Normal(v) => v.to_untyped(),
1914 Self::Placeholder(v) => v.to_untyped(),
1915 Self::Parenthesized(v) => v.to_untyped(),
1916 Self::Destructuring(v) => v.to_untyped(),
1917 }
1918 }
1919}
1920
1921impl<'a> Pattern<'a> {
1922 pub fn bindings(self) -> Vec<Ident<'a>> {
1924 match self {
1925 Self::Normal(Expr::Ident(ident)) => vec![ident],
1926 Self::Parenthesized(v) => v.pattern().bindings(),
1927 Self::Destructuring(v) => v.bindings(),
1928 _ => vec![],
1929 }
1930 }
1931}
1932
1933impl Default for Pattern<'_> {
1934 fn default() -> Self {
1935 Self::Normal(Expr::default())
1936 }
1937}
1938
1939node! {
1940 struct Underscore
1942}
1943
1944node! {
1945 struct Destructuring
1947}
1948
1949impl<'a> Destructuring<'a> {
1950 pub fn items(self) -> impl DoubleEndedIterator<Item = DestructuringItem<'a>> {
1952 self.0.children().filter_map(SyntaxNode::cast)
1953 }
1954
1955 pub fn bindings(self) -> Vec<Ident<'a>> {
1957 self.items()
1958 .flat_map(|binding| match binding {
1959 DestructuringItem::Pattern(pattern) => pattern.bindings(),
1960 DestructuringItem::Named(named) => named.pattern().bindings(),
1961 DestructuringItem::Spread(spread) => {
1962 spread.sink_ident().into_iter().collect()
1963 }
1964 })
1965 .collect()
1966 }
1967}
1968
1969#[derive(Debug, Copy, Clone, Hash)]
1971pub enum DestructuringItem<'a> {
1972 Pattern(Pattern<'a>),
1974 Named(Named<'a>),
1976 Spread(Spread<'a>),
1978}
1979
1980impl<'a> AstNode<'a> for DestructuringItem<'a> {
1981 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1982 match node.kind() {
1983 SyntaxKind::Named => Some(Self::Named(Named(node))),
1984 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1985 _ => node.cast().map(Self::Pattern),
1986 }
1987 }
1988
1989 fn to_untyped(self) -> &'a SyntaxNode {
1990 match self {
1991 Self::Pattern(v) => v.to_untyped(),
1992 Self::Named(v) => v.to_untyped(),
1993 Self::Spread(v) => v.to_untyped(),
1994 }
1995 }
1996}
1997
1998node! {
1999 struct LetBinding
2001}
2002
2003#[derive(Debug)]
2005pub enum LetBindingKind<'a> {
2006 Normal(Pattern<'a>),
2008 Closure(Ident<'a>),
2010}
2011
2012impl<'a> LetBindingKind<'a> {
2013 pub fn bindings(self) -> Vec<Ident<'a>> {
2015 match self {
2016 LetBindingKind::Normal(pattern) => pattern.bindings(),
2017 LetBindingKind::Closure(ident) => vec![ident],
2018 }
2019 }
2020}
2021
2022impl<'a> LetBinding<'a> {
2023 pub fn kind(self) -> LetBindingKind<'a> {
2025 match self.0.cast_first() {
2026 Pattern::Normal(Expr::Closure(closure)) => {
2027 LetBindingKind::Closure(closure.name().unwrap_or_default())
2028 }
2029 pattern => LetBindingKind::Normal(pattern),
2030 }
2031 }
2032
2033 pub fn init(self) -> Option<Expr<'a>> {
2035 match self.kind() {
2036 LetBindingKind::Normal(Pattern::Normal(_) | Pattern::Parenthesized(_)) => {
2037 self.0.children().filter_map(SyntaxNode::cast).nth(1)
2038 }
2039 LetBindingKind::Normal(_) => self.0.try_cast_first(),
2040 LetBindingKind::Closure(_) => self.0.try_cast_first(),
2041 }
2042 }
2043}
2044
2045node! {
2046 struct DestructAssignment
2048}
2049
2050impl<'a> DestructAssignment<'a> {
2051 pub fn pattern(self) -> Pattern<'a> {
2053 self.0.cast_first()
2054 }
2055
2056 pub fn value(self) -> Expr<'a> {
2058 self.0.cast_last()
2059 }
2060}
2061
2062node! {
2063 struct SetRule
2065}
2066
2067impl<'a> SetRule<'a> {
2068 pub fn target(self) -> Expr<'a> {
2070 self.0.cast_first()
2071 }
2072
2073 pub fn args(self) -> Args<'a> {
2075 self.0.cast_last()
2076 }
2077
2078 pub fn condition(self) -> Option<Expr<'a>> {
2080 self.0
2081 .children()
2082 .skip_while(|child| child.kind() != SyntaxKind::If)
2083 .find_map(SyntaxNode::cast)
2084 }
2085}
2086
2087node! {
2088 struct ShowRule
2090}
2091
2092impl<'a> ShowRule<'a> {
2093 pub fn selector(self) -> Option<Expr<'a>> {
2095 self.0
2096 .children()
2097 .rev()
2098 .skip_while(|child| child.kind() != SyntaxKind::Colon)
2099 .find_map(SyntaxNode::cast)
2100 }
2101
2102 pub fn transform(self) -> Expr<'a> {
2104 self.0.cast_last()
2105 }
2106}
2107
2108node! {
2109 struct Contextual
2111}
2112
2113impl<'a> Contextual<'a> {
2114 pub fn body(self) -> Expr<'a> {
2116 self.0.cast_first()
2117 }
2118}
2119
2120node! {
2121 struct Conditional
2123}
2124
2125impl<'a> Conditional<'a> {
2126 pub fn condition(self) -> Expr<'a> {
2128 self.0.cast_first()
2129 }
2130
2131 pub fn if_body(self) -> Expr<'a> {
2133 self.0
2134 .children()
2135 .filter_map(SyntaxNode::cast)
2136 .nth(1)
2137 .unwrap_or_default()
2138 }
2139
2140 pub fn else_body(self) -> Option<Expr<'a>> {
2142 self.0.children().filter_map(SyntaxNode::cast).nth(2)
2143 }
2144}
2145
2146node! {
2147 struct WhileLoop
2149}
2150
2151impl<'a> WhileLoop<'a> {
2152 pub fn condition(self) -> Expr<'a> {
2154 self.0.cast_first()
2155 }
2156
2157 pub fn body(self) -> Expr<'a> {
2159 self.0.cast_last()
2160 }
2161}
2162
2163node! {
2164 struct ForLoop
2166}
2167
2168impl<'a> ForLoop<'a> {
2169 pub fn pattern(self) -> Pattern<'a> {
2171 self.0.cast_first()
2172 }
2173
2174 pub fn iterable(self) -> Expr<'a> {
2176 self.0
2177 .children()
2178 .skip_while(|&c| c.kind() != SyntaxKind::In)
2179 .find_map(SyntaxNode::cast)
2180 .unwrap_or_default()
2181 }
2182
2183 pub fn body(self) -> Expr<'a> {
2185 self.0.cast_last()
2186 }
2187}
2188
2189node! {
2190 struct ModuleImport
2192}
2193
2194impl<'a> ModuleImport<'a> {
2195 pub fn source(self) -> Expr<'a> {
2197 self.0.cast_first()
2198 }
2199
2200 pub fn imports(self) -> Option<Imports<'a>> {
2202 self.0.children().find_map(|node| match node.kind() {
2203 SyntaxKind::Star => Some(Imports::Wildcard),
2204 SyntaxKind::ImportItems => node.cast().map(Imports::Items),
2205 _ => Option::None,
2206 })
2207 }
2208
2209 pub fn bare_name(self) -> Result<EcoString, BareImportError> {
2217 match self.source() {
2218 Expr::Ident(ident) => Ok(ident.get().clone()),
2219 Expr::FieldAccess(access) => Ok(access.field().get().clone()),
2220 Expr::Str(string) => {
2221 let string = string.get();
2222 let name = if string.starts_with('@') {
2223 PackageSpec::from_str(&string)
2224 .map_err(|_| BareImportError::PackageInvalid)?
2225 .name
2226 } else {
2227 Path::new(string.as_str())
2228 .file_stem()
2229 .and_then(|path| path.to_str())
2230 .ok_or(BareImportError::PathInvalid)?
2231 .into()
2232 };
2233
2234 if !is_ident(&name) {
2235 return Err(BareImportError::PathInvalid);
2236 }
2237
2238 Ok(name)
2239 }
2240 _ => Err(BareImportError::Dynamic),
2241 }
2242 }
2243
2244 pub fn new_name(self) -> Option<Ident<'a>> {
2247 self.0
2248 .children()
2249 .skip_while(|child| child.kind() != SyntaxKind::As)
2250 .find_map(SyntaxNode::cast)
2251 }
2252}
2253
2254#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
2256pub enum BareImportError {
2257 Dynamic,
2259 PathInvalid,
2262 PackageInvalid,
2264}
2265
2266#[derive(Debug, Copy, Clone, Hash)]
2268pub enum Imports<'a> {
2269 Wildcard,
2271 Items(ImportItems<'a>),
2273}
2274
2275node! {
2276 struct ImportItems
2278}
2279
2280impl<'a> ImportItems<'a> {
2281 pub fn iter(self) -> impl DoubleEndedIterator<Item = ImportItem<'a>> {
2283 self.0.children().filter_map(|child| match child.kind() {
2284 SyntaxKind::RenamedImportItem => child.cast().map(ImportItem::Renamed),
2285 SyntaxKind::ImportItemPath => child.cast().map(ImportItem::Simple),
2286 _ => Option::None,
2287 })
2288 }
2289}
2290
2291node! {
2292 struct ImportItemPath
2294}
2295
2296impl<'a> ImportItemPath<'a> {
2297 pub fn iter(self) -> impl DoubleEndedIterator<Item = Ident<'a>> {
2299 self.0.children().filter_map(SyntaxNode::cast)
2300 }
2301
2302 pub fn name(self) -> Ident<'a> {
2304 self.0.cast_last()
2305 }
2306}
2307
2308#[derive(Debug, Copy, Clone, Hash)]
2310pub enum ImportItem<'a> {
2311 Simple(ImportItemPath<'a>),
2314 Renamed(RenamedImportItem<'a>),
2317}
2318
2319impl<'a> ImportItem<'a> {
2320 pub fn path(self) -> ImportItemPath<'a> {
2322 match self {
2323 Self::Simple(path) => path,
2324 Self::Renamed(renamed_item) => renamed_item.path(),
2325 }
2326 }
2327
2328 pub fn original_name(self) -> Ident<'a> {
2331 match self {
2332 Self::Simple(path) => path.name(),
2333 Self::Renamed(renamed_item) => renamed_item.original_name(),
2334 }
2335 }
2336
2337 pub fn bound_name(self) -> Ident<'a> {
2340 match self {
2341 Self::Simple(path) => path.name(),
2342 Self::Renamed(renamed_item) => renamed_item.new_name(),
2343 }
2344 }
2345}
2346
2347node! {
2348 struct RenamedImportItem
2350}
2351
2352impl<'a> RenamedImportItem<'a> {
2353 pub fn path(self) -> ImportItemPath<'a> {
2355 self.0.cast_first()
2356 }
2357
2358 pub fn original_name(self) -> Ident<'a> {
2360 self.path().name()
2361 }
2362
2363 pub fn new_name(self) -> Ident<'a> {
2365 self.0.cast_last()
2366 }
2367}
2368
2369node! {
2370 struct ModuleInclude
2372}
2373
2374impl<'a> ModuleInclude<'a> {
2375 pub fn source(self) -> Expr<'a> {
2377 self.0.cast_last()
2378 }
2379}
2380
2381node! {
2382 struct LoopBreak
2384}
2385
2386node! {
2387 struct LoopContinue
2389}
2390
2391node! {
2392 struct FuncReturn
2394}
2395
2396impl<'a> FuncReturn<'a> {
2397 pub fn body(self) -> Option<Expr<'a>> {
2399 self.0.try_cast_last()
2400 }
2401}
2402
2403#[cfg(test)]
2404mod tests {
2405 use super::*;
2406
2407 #[test]
2408 fn test_expr_default() {
2409 assert!(Expr::default().to_untyped().cast::<Expr>().is_some());
2410 }
2411}