1#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unreachable)]
86
87use std::num::NonZeroUsize;
88use std::ops::Deref;
89use std::path::Path;
90use std::str::FromStr;
91
92use ecow::EcoString;
93use typst_utils::NonZeroExt;
94use unscanny::Scanner;
95
96use crate::package::PackageSpec;
97use crate::{Span, SyntaxKind, SyntaxNode, is_ident, is_newline};
98
99pub trait AstNode<'a>: Sized {
101 fn from_untyped(node: &'a SyntaxNode) -> Option<Self>;
103
104 fn to_untyped(self) -> &'a SyntaxNode;
106
107 fn span(self) -> Span {
109 self.to_untyped().span()
110 }
111
112 fn placeholder() -> Self;
117}
118
119impl SyntaxNode {
121 pub fn is<'a, T: AstNode<'a>>(&'a self) -> bool {
123 self.cast::<T>().is_some()
124 }
125
126 pub fn cast<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
128 T::from_untyped(self)
129 }
130
131 fn try_cast_first<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
133 self.children().find_map(Self::cast)
134 }
135
136 fn try_cast_last<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
138 self.children().rev().find_map(Self::cast)
139 }
140
141 fn cast_first<'a, T: AstNode<'a>>(&'a self) -> T {
143 self.try_cast_first().unwrap_or_else(T::placeholder)
144 }
145
146 fn cast_last<'a, T: AstNode<'a>>(&'a self) -> T {
148 self.try_cast_last().unwrap_or_else(T::placeholder)
149 }
150}
151
152macro_rules! node {
166 ($(#[$attr:meta])* struct $name:ident) => {
167 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
169 #[repr(transparent)]
170 $(#[$attr])*
171 pub struct $name<'a>(&'a SyntaxNode);
172
173 impl<'a> AstNode<'a> for $name<'a> {
174 #[inline]
175 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
176 if node.kind() == SyntaxKind::$name {
177 Some(Self(node))
178 } else {
179 Option::None
180 }
181 }
182
183 #[inline]
184 fn to_untyped(self) -> &'a SyntaxNode {
185 self.0
186 }
187
188 #[inline]
189 fn placeholder() -> Self {
190 static PLACEHOLDER: SyntaxNode
191 = SyntaxNode::placeholder(SyntaxKind::$name);
192 Self(&PLACEHOLDER)
193 }
194 }
195 };
196}
197
198node! {
199 struct LineComment
201}
202
203impl<'a> LineComment<'a> {
204 pub fn text(&self) -> &'a str {
206 let text = self.0.leaf_text();
207 text.strip_prefix("//").unwrap_or(text)
208 }
209}
210
211node! {
212 struct BlockComment
214}
215
216impl<'a> BlockComment<'a> {
217 pub fn text(&self) -> &'a str {
219 let text = self.0.leaf_text();
220 text.strip_prefix("/*")
221 .and_then(|text| text.strip_suffix("*/"))
222 .unwrap_or(text)
223 }
224}
225
226node! {
227 struct Markup
229}
230
231impl<'a> Markup<'a> {
232 pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
234 let mut was_stmt = false;
235 self.0
236 .children()
237 .filter(move |node| {
238 let kind = node.kind();
240 let keep = !was_stmt || node.kind() != SyntaxKind::Space;
241 was_stmt = kind.is_stmt();
242 keep
243 })
244 .filter_map(Expr::cast_with_space)
245 }
246}
247
248#[derive(Debug, Copy, Clone, Hash)]
250pub enum Expr<'a> {
251 Text(Text<'a>),
253 Space(Space<'a>),
256 Linebreak(Linebreak<'a>),
258 Parbreak(Parbreak<'a>),
260 Escape(Escape<'a>),
262 Shorthand(Shorthand<'a>),
265 SmartQuote(SmartQuote<'a>),
267 Strong(Strong<'a>),
269 Emph(Emph<'a>),
271 Raw(Raw<'a>),
273 Link(Link<'a>),
275 Label(Label<'a>),
277 Ref(Ref<'a>),
279 Heading(Heading<'a>),
281 ListItem(ListItem<'a>),
283 EnumItem(EnumItem<'a>),
285 TermItem(TermItem<'a>),
287 Equation(Equation<'a>),
289 Math(Math<'a>),
291 MathText(MathText<'a>),
293 MathIdent(MathIdent<'a>),
295 MathFieldAccess(MathFieldAccess<'a>),
297 MathShorthand(MathShorthand<'a>),
299 MathAlignPoint(MathAlignPoint<'a>),
301 MathCall(MathCall<'a>),
303 MathDelimited(MathDelimited<'a>),
305 MathAttach(MathAttach<'a>),
307 MathPrimes(MathPrimes<'a>),
309 MathFrac(MathFrac<'a>),
311 MathRoot(MathRoot<'a>),
313 Ident(Ident<'a>),
315 None(None<'a>),
317 Auto(Auto<'a>),
319 Bool(Bool<'a>),
321 Int(Int<'a>),
323 Float(Float<'a>),
325 Numeric(Numeric<'a>),
327 Str(Str<'a>),
329 CodeBlock(CodeBlock<'a>),
331 ContentBlock(ContentBlock<'a>),
333 Parenthesized(Parenthesized<'a>),
335 Array(Array<'a>),
337 Dict(Dict<'a>),
339 Unary(Unary<'a>),
341 Binary(Binary<'a>),
343 FieldAccess(FieldAccess<'a>),
345 FuncCall(FuncCall<'a>),
347 Closure(Closure<'a>),
349 LetBinding(LetBinding<'a>),
351 DestructAssignment(DestructAssignment<'a>),
353 SetRule(SetRule<'a>),
355 ShowRule(ShowRule<'a>),
357 Contextual(Contextual<'a>),
359 Conditional(Conditional<'a>),
361 WhileLoop(WhileLoop<'a>),
363 ForLoop(ForLoop<'a>),
365 ModuleImport(ModuleImport<'a>),
367 ModuleInclude(ModuleInclude<'a>),
369 LoopBreak(LoopBreak<'a>),
371 LoopContinue(LoopContinue<'a>),
373 FuncReturn(FuncReturn<'a>),
375}
376
377impl<'a> Expr<'a> {
378 fn cast_with_space(node: &'a SyntaxNode) -> Option<Self> {
379 match node.kind() {
380 SyntaxKind::Space => Some(Self::Space(Space(node))),
381 _ => Self::from_untyped(node),
382 }
383 }
384}
385
386impl<'a> AstNode<'a> for Expr<'a> {
387 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
388 match node.kind() {
389 SyntaxKind::Space => Option::None, SyntaxKind::Linebreak => Some(Self::Linebreak(Linebreak(node))),
391 SyntaxKind::Parbreak => Some(Self::Parbreak(Parbreak(node))),
392 SyntaxKind::Text => Some(Self::Text(Text(node))),
393 SyntaxKind::Escape => Some(Self::Escape(Escape(node))),
394 SyntaxKind::Shorthand => Some(Self::Shorthand(Shorthand(node))),
395 SyntaxKind::SmartQuote => Some(Self::SmartQuote(SmartQuote(node))),
396 SyntaxKind::Strong => Some(Self::Strong(Strong(node))),
397 SyntaxKind::Emph => Some(Self::Emph(Emph(node))),
398 SyntaxKind::Raw => Some(Self::Raw(Raw(node))),
399 SyntaxKind::Link => Some(Self::Link(Link(node))),
400 SyntaxKind::Label => Some(Self::Label(Label(node))),
401 SyntaxKind::Ref => Some(Self::Ref(Ref(node))),
402 SyntaxKind::Heading => Some(Self::Heading(Heading(node))),
403 SyntaxKind::ListItem => Some(Self::ListItem(ListItem(node))),
404 SyntaxKind::EnumItem => Some(Self::EnumItem(EnumItem(node))),
405 SyntaxKind::TermItem => Some(Self::TermItem(TermItem(node))),
406 SyntaxKind::Equation => Some(Self::Equation(Equation(node))),
407 SyntaxKind::Math => Some(Self::Math(Math(node))),
408 SyntaxKind::MathText => Some(Self::MathText(MathText(node))),
409 SyntaxKind::MathIdent => Some(Self::MathIdent(MathIdent(node))),
410 SyntaxKind::MathFieldAccess => {
411 Some(Self::MathFieldAccess(MathFieldAccess(node)))
412 }
413 SyntaxKind::MathShorthand => Some(Self::MathShorthand(MathShorthand(node))),
414 SyntaxKind::MathAlignPoint => {
415 Some(Self::MathAlignPoint(MathAlignPoint(node)))
416 }
417 SyntaxKind::MathCall => Some(Self::MathCall(MathCall(node))),
418 SyntaxKind::MathDelimited => Some(Self::MathDelimited(MathDelimited(node))),
419 SyntaxKind::MathAttach => Some(Self::MathAttach(MathAttach(node))),
420 SyntaxKind::MathPrimes => Some(Self::MathPrimes(MathPrimes(node))),
421 SyntaxKind::MathFrac => Some(Self::MathFrac(MathFrac(node))),
422 SyntaxKind::MathRoot => Some(Self::MathRoot(MathRoot(node))),
423 SyntaxKind::Ident => Some(Self::Ident(Ident(node))),
424 SyntaxKind::None => Some(Self::None(None(node))),
425 SyntaxKind::Auto => Some(Self::Auto(Auto(node))),
426 SyntaxKind::Bool => Some(Self::Bool(Bool(node))),
427 SyntaxKind::Int => Some(Self::Int(Int(node))),
428 SyntaxKind::Float => Some(Self::Float(Float(node))),
429 SyntaxKind::Numeric => Some(Self::Numeric(Numeric(node))),
430 SyntaxKind::Str => Some(Self::Str(Str(node))),
431 SyntaxKind::CodeBlock => Some(Self::CodeBlock(CodeBlock(node))),
432 SyntaxKind::ContentBlock => Some(Self::ContentBlock(ContentBlock(node))),
433 SyntaxKind::Parenthesized => Some(Self::Parenthesized(Parenthesized(node))),
434 SyntaxKind::Array => Some(Self::Array(Array(node))),
435 SyntaxKind::Dict => Some(Self::Dict(Dict(node))),
436 SyntaxKind::Unary => Some(Self::Unary(Unary(node))),
437 SyntaxKind::Binary => Some(Self::Binary(Binary(node))),
438 SyntaxKind::FieldAccess => Some(Self::FieldAccess(FieldAccess(node))),
439 SyntaxKind::FuncCall => Some(Self::FuncCall(FuncCall(node))),
440 SyntaxKind::Closure => Some(Self::Closure(Closure(node))),
441 SyntaxKind::LetBinding => Some(Self::LetBinding(LetBinding(node))),
442 SyntaxKind::DestructAssignment => {
443 Some(Self::DestructAssignment(DestructAssignment(node)))
444 }
445 SyntaxKind::SetRule => Some(Self::SetRule(SetRule(node))),
446 SyntaxKind::ShowRule => Some(Self::ShowRule(ShowRule(node))),
447 SyntaxKind::Contextual => Some(Self::Contextual(Contextual(node))),
448 SyntaxKind::Conditional => Some(Self::Conditional(Conditional(node))),
449 SyntaxKind::WhileLoop => Some(Self::WhileLoop(WhileLoop(node))),
450 SyntaxKind::ForLoop => Some(Self::ForLoop(ForLoop(node))),
451 SyntaxKind::ModuleImport => Some(Self::ModuleImport(ModuleImport(node))),
452 SyntaxKind::ModuleInclude => Some(Self::ModuleInclude(ModuleInclude(node))),
453 SyntaxKind::LoopBreak => Some(Self::LoopBreak(LoopBreak(node))),
454 SyntaxKind::LoopContinue => Some(Self::LoopContinue(LoopContinue(node))),
455 SyntaxKind::FuncReturn => Some(Self::FuncReturn(FuncReturn(node))),
456 _ => Option::None,
457 }
458 }
459
460 fn to_untyped(self) -> &'a SyntaxNode {
461 match self {
462 Self::Text(v) => v.to_untyped(),
463 Self::Space(v) => v.to_untyped(),
464 Self::Linebreak(v) => v.to_untyped(),
465 Self::Parbreak(v) => v.to_untyped(),
466 Self::Escape(v) => v.to_untyped(),
467 Self::Shorthand(v) => v.to_untyped(),
468 Self::SmartQuote(v) => v.to_untyped(),
469 Self::Strong(v) => v.to_untyped(),
470 Self::Emph(v) => v.to_untyped(),
471 Self::Raw(v) => v.to_untyped(),
472 Self::Link(v) => v.to_untyped(),
473 Self::Label(v) => v.to_untyped(),
474 Self::Ref(v) => v.to_untyped(),
475 Self::Heading(v) => v.to_untyped(),
476 Self::ListItem(v) => v.to_untyped(),
477 Self::EnumItem(v) => v.to_untyped(),
478 Self::TermItem(v) => v.to_untyped(),
479 Self::Equation(v) => v.to_untyped(),
480 Self::Math(v) => v.to_untyped(),
481 Self::MathText(v) => v.to_untyped(),
482 Self::MathIdent(v) => v.to_untyped(),
483 Self::MathFieldAccess(v) => v.to_untyped(),
484 Self::MathShorthand(v) => v.to_untyped(),
485 Self::MathAlignPoint(v) => v.to_untyped(),
486 Self::MathCall(v) => v.to_untyped(),
487 Self::MathDelimited(v) => v.to_untyped(),
488 Self::MathAttach(v) => v.to_untyped(),
489 Self::MathPrimes(v) => v.to_untyped(),
490 Self::MathFrac(v) => v.to_untyped(),
491 Self::MathRoot(v) => v.to_untyped(),
492 Self::Ident(v) => v.to_untyped(),
493 Self::None(v) => v.to_untyped(),
494 Self::Auto(v) => v.to_untyped(),
495 Self::Bool(v) => v.to_untyped(),
496 Self::Int(v) => v.to_untyped(),
497 Self::Float(v) => v.to_untyped(),
498 Self::Numeric(v) => v.to_untyped(),
499 Self::Str(v) => v.to_untyped(),
500 Self::CodeBlock(v) => v.to_untyped(),
501 Self::ContentBlock(v) => v.to_untyped(),
502 Self::Array(v) => v.to_untyped(),
503 Self::Dict(v) => v.to_untyped(),
504 Self::Parenthesized(v) => v.to_untyped(),
505 Self::Unary(v) => v.to_untyped(),
506 Self::Binary(v) => v.to_untyped(),
507 Self::FieldAccess(v) => v.to_untyped(),
508 Self::FuncCall(v) => v.to_untyped(),
509 Self::Closure(v) => v.to_untyped(),
510 Self::LetBinding(v) => v.to_untyped(),
511 Self::DestructAssignment(v) => v.to_untyped(),
512 Self::SetRule(v) => v.to_untyped(),
513 Self::ShowRule(v) => v.to_untyped(),
514 Self::Contextual(v) => v.to_untyped(),
515 Self::Conditional(v) => v.to_untyped(),
516 Self::WhileLoop(v) => v.to_untyped(),
517 Self::ForLoop(v) => v.to_untyped(),
518 Self::ModuleImport(v) => v.to_untyped(),
519 Self::ModuleInclude(v) => v.to_untyped(),
520 Self::LoopBreak(v) => v.to_untyped(),
521 Self::LoopContinue(v) => v.to_untyped(),
522 Self::FuncReturn(v) => v.to_untyped(),
523 }
524 }
525
526 fn placeholder() -> Self {
527 Self::None(None::placeholder())
528 }
529}
530
531impl Expr<'_> {
532 pub fn hash(self) -> bool {
534 matches!(
535 self,
536 Self::Ident(_)
537 | Self::None(_)
538 | Self::Auto(_)
539 | Self::Bool(_)
540 | Self::Int(_)
541 | Self::Float(_)
542 | Self::Numeric(_)
543 | Self::Str(_)
544 | Self::CodeBlock(_)
545 | Self::ContentBlock(_)
546 | Self::Array(_)
547 | Self::Dict(_)
548 | Self::Parenthesized(_)
549 | Self::FieldAccess(_)
550 | Self::FuncCall(_)
551 | Self::LetBinding(_)
552 | Self::SetRule(_)
553 | Self::ShowRule(_)
554 | Self::Contextual(_)
555 | Self::Conditional(_)
556 | Self::WhileLoop(_)
557 | Self::ForLoop(_)
558 | Self::ModuleImport(_)
559 | Self::ModuleInclude(_)
560 | Self::LoopBreak(_)
561 | Self::LoopContinue(_)
562 | Self::FuncReturn(_)
563 )
564 }
565
566 pub fn is_literal(self) -> bool {
568 matches!(
569 self,
570 Self::None(_)
571 | Self::Auto(_)
572 | Self::Bool(_)
573 | Self::Int(_)
574 | Self::Float(_)
575 | Self::Numeric(_)
576 | Self::Str(_)
577 )
578 }
579}
580
581node! {
582 struct Text
584}
585
586impl<'a> Text<'a> {
587 pub fn get(self) -> &'a EcoString {
589 self.0.leaf_text()
590 }
591}
592
593node! {
594 struct Space
597}
598
599node! {
600 struct Linebreak
602}
603
604node! {
605 struct Parbreak
607}
608
609node! {
610 struct Escape
612}
613
614impl Escape<'_> {
615 pub fn get(self) -> char {
617 let mut s = Scanner::new(self.0.leaf_text());
618 s.expect('\\');
619 if s.eat_if("u{") {
620 let hex = s.eat_while(char::is_ascii_hexdigit);
621 u32::from_str_radix(hex, 16)
622 .ok()
623 .and_then(std::char::from_u32)
624 .unwrap_or_default()
625 } else {
626 s.eat().unwrap_or_default()
627 }
628 }
629}
630
631node! {
632 struct Shorthand
635}
636
637impl Shorthand<'_> {
638 pub const LIST: &'static [(&'static str, char)] = &[
640 ("...", '…'),
641 ("~", '\u{00A0}'),
642 ("-", '\u{2212}'), ("--", '\u{2013}'),
644 ("---", '\u{2014}'),
645 ("-?", '\u{00AD}'),
646 ];
647
648 pub fn get(self) -> char {
650 let text = self.0.leaf_text();
651 Self::LIST
652 .iter()
653 .find(|&&(s, _)| s == text)
654 .map_or_else(char::default, |&(_, c)| c)
655 }
656}
657
658node! {
659 struct SmartQuote
661}
662
663impl SmartQuote<'_> {
664 pub fn double(self) -> bool {
666 self.0.leaf_text() == "\""
667 }
668}
669
670node! {
671 struct Strong
673}
674
675impl<'a> Strong<'a> {
676 pub fn body(self) -> Markup<'a> {
678 self.0.cast_first()
679 }
680}
681
682node! {
683 struct Emph
685}
686
687impl<'a> Emph<'a> {
688 pub fn body(self) -> Markup<'a> {
690 self.0.cast_first()
691 }
692}
693
694node! {
695 struct Raw
697}
698
699impl<'a> Raw<'a> {
700 pub fn lines(self) -> impl DoubleEndedIterator<Item = Text<'a>> {
702 self.0.children().filter_map(SyntaxNode::cast)
703 }
704
705 pub fn lang(self) -> Option<RawLang<'a>> {
707 let delim: RawDelim = self.0.try_cast_first()?;
709 if delim.0.len() < 3 {
710 return Option::None;
711 }
712
713 self.0.try_cast_first()
714 }
715
716 pub fn block(self) -> bool {
718 self.0
719 .try_cast_first()
720 .is_some_and(|delim: RawDelim| delim.0.len() >= 3)
721 && self.0.children().any(|e| {
722 e.kind() == SyntaxKind::RawTrimmed
723 && e.leaf_text().chars().any(is_newline)
724 })
725 }
726}
727
728node! {
729 struct RawLang
731}
732
733impl<'a> RawLang<'a> {
734 pub fn get(self) -> &'a EcoString {
736 self.0.leaf_text()
737 }
738}
739
740node! {
741 struct RawDelim
743}
744
745node! {
746 struct Link
748}
749
750impl<'a> Link<'a> {
751 pub fn get(self) -> &'a EcoString {
753 self.0.leaf_text()
754 }
755}
756
757node! {
758 struct Label
760}
761
762impl<'a> Label<'a> {
763 pub fn get(self) -> &'a str {
765 self.0.leaf_text().trim_start_matches('<').trim_end_matches('>')
766 }
767}
768
769node! {
770 struct Ref
772}
773
774impl<'a> Ref<'a> {
775 pub fn target(self) -> &'a str {
779 self.0
780 .children()
781 .find(|node| node.kind() == SyntaxKind::RefMarker)
782 .map(|node| node.leaf_text().trim_start_matches('@'))
783 .unwrap_or_default()
784 }
785
786 pub fn supplement(self) -> Option<ContentBlock<'a>> {
788 self.0.try_cast_last()
789 }
790}
791
792node! {
793 struct Heading
795}
796
797impl<'a> Heading<'a> {
798 pub fn body(self) -> Markup<'a> {
800 self.0.cast_first()
801 }
802
803 pub fn depth(self) -> NonZeroUsize {
805 self.0
806 .children()
807 .find(|node| node.kind() == SyntaxKind::HeadingMarker)
808 .and_then(|node| node.len().try_into().ok())
809 .unwrap_or(NonZeroUsize::ONE)
810 }
811}
812
813node! {
814 struct ListItem
816}
817
818impl<'a> ListItem<'a> {
819 pub fn body(self) -> Markup<'a> {
821 self.0.cast_first()
822 }
823}
824
825node! {
826 struct EnumItem
828}
829
830impl<'a> EnumItem<'a> {
831 pub fn number(self) -> Option<u64> {
833 self.0.children().find_map(|node| match node.kind() {
834 SyntaxKind::EnumMarker => node.leaf_text().trim_end_matches('.').parse().ok(),
835 _ => Option::None,
836 })
837 }
838
839 pub fn body(self) -> Markup<'a> {
841 self.0.cast_first()
842 }
843}
844
845node! {
846 struct TermItem
848}
849
850impl<'a> TermItem<'a> {
851 pub fn term(self) -> Markup<'a> {
853 self.0.cast_first()
854 }
855
856 pub fn description(self) -> Markup<'a> {
858 self.0.cast_last()
859 }
860}
861
862node! {
863 struct Equation
865}
866
867impl<'a> Equation<'a> {
868 pub fn body(self) -> Math<'a> {
870 self.0.cast_first()
871 }
872
873 pub fn block(self) -> bool {
875 let is_space = |node: Option<&SyntaxNode>| {
876 node.map(SyntaxNode::kind) == Some(SyntaxKind::Space)
877 };
878 is_space(self.0.children().nth(1)) && is_space(self.0.children().nth_back(1))
879 }
880}
881
882node! {
883 struct Math
885}
886
887impl<'a> Math<'a> {
888 pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
890 self.0.children().filter_map(Expr::cast_with_space)
891 }
892
893 pub fn was_deparenthesized(self) -> bool {
895 let mut iter = self.0.children();
896 matches!(iter.next().map(SyntaxNode::kind), Some(SyntaxKind::LeftParen))
897 && matches!(
898 iter.next_back().map(SyntaxNode::kind),
899 Some(SyntaxKind::RightParen)
900 )
901 }
902}
903
904node! {
905 struct MathText
907}
908
909pub enum MathTextKind<'a> {
911 Grapheme(&'a EcoString),
912 Number(&'a EcoString),
913}
914
915impl<'a> MathText<'a> {
916 pub fn get(self) -> MathTextKind<'a> {
918 let text = self.0.leaf_text();
919 if text.chars().next().unwrap_or_default().is_numeric() {
920 MathTextKind::Number(text)
923 } else {
924 MathTextKind::Grapheme(text)
925 }
926 }
927}
928
929node! {
930 struct MathIdent
932}
933
934impl<'a> MathIdent<'a> {
935 pub fn get(self) -> &'a EcoString {
937 self.0.leaf_text()
938 }
939
940 pub fn as_str(self) -> &'a str {
942 self.get()
943 }
944}
945
946impl Deref for MathIdent<'_> {
947 type Target = str;
948
949 fn deref(&self) -> &Self::Target {
952 self.as_str()
953 }
954}
955
956node! {
957 struct MathFieldAccess
959}
960
961impl<'a> MathFieldAccess<'a> {
962 pub fn target(self) -> MathAccess<'a> {
964 self.0.cast_first()
965 }
966
967 pub fn field(self) -> MathIdent<'a> {
969 self.0.cast_last()
970 }
971}
972
973#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
975pub enum MathAccess<'a> {
976 MathIdent(MathIdent<'a>),
977 MathFieldAccess(MathFieldAccess<'a>),
978}
979
980impl<'a> AstNode<'a> for MathAccess<'a> {
981 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
982 match node.kind() {
983 SyntaxKind::MathIdent => Some(Self::MathIdent(MathIdent(node))),
984 SyntaxKind::MathFieldAccess => {
985 Some(Self::MathFieldAccess(MathFieldAccess(node)))
986 }
987 _ => Option::None,
988 }
989 }
990
991 fn to_untyped(self) -> &'a SyntaxNode {
992 match self {
993 Self::MathIdent(v) => v.to_untyped(),
994 Self::MathFieldAccess(v) => v.to_untyped(),
995 }
996 }
997
998 fn placeholder() -> Self {
999 Self::MathIdent(MathIdent::placeholder())
1000 }
1001}
1002
1003node! {
1004 struct MathShorthand
1006}
1007
1008impl MathShorthand<'_> {
1009 pub const LIST: &'static [(&'static str, char)] = &[
1011 ("...", '…'),
1012 ("-", '−'),
1013 ("*", '∗'),
1014 ("~", '∼'),
1015 ("!=", '≠'),
1016 (":=", '≔'),
1017 ("::=", '⩴'),
1018 ("=:", '≕'),
1019 ("<<", '≪'),
1020 ("<<<", '⋘'),
1021 (">>", '≫'),
1022 (">>>", '⋙'),
1023 ("<=", '≤'),
1024 (">=", '≥'),
1025 ("->", '→'),
1026 ("-->", '⟶'),
1027 ("|->", '↦'),
1028 (">->", '↣'),
1029 ("->>", '↠'),
1030 ("<-", '←'),
1031 ("<--", '⟵'),
1032 ("<-<", '↢'),
1033 ("<<-", '↞'),
1034 ("<->", '↔'),
1035 ("<-->", '⟷'),
1036 ("~>", '⇝'),
1037 ("~~>", '⟿'),
1038 ("<~", '⇜'),
1039 ("<~~", '⬳'),
1040 ("=>", '⇒'),
1041 ("|=>", '⤇'),
1042 ("==>", '⟹'),
1043 ("<==", '⟸'),
1044 ("<=>", '⇔'),
1045 ("<==>", '⟺'),
1046 ("[|", '⟦'),
1047 ("|]", '⟧'),
1048 ("||", '‖'),
1049 ];
1050
1051 pub fn get(self) -> char {
1053 let text = self.0.leaf_text();
1054 Self::LIST
1055 .iter()
1056 .find(|&&(s, _)| s == text)
1057 .map_or_else(char::default, |&(_, c)| c)
1058 }
1059}
1060
1061node! {
1062 struct MathCall
1064}
1065
1066impl<'a> MathCall<'a> {
1067 pub fn callee(self) -> MathAccess<'a> {
1070 self.0.cast_first()
1071 }
1072
1073 pub fn args(self) -> MathArgs<'a> {
1075 self.0.cast_last()
1076 }
1077}
1078
1079node! {
1080 struct MathArgs
1082}
1083
1084#[derive(Debug, Copy, Clone, Hash)]
1087pub struct MathArg<'a> {
1088 pub arg: Arg<'a>,
1090 pub ends_in_semicolon: bool,
1094}
1095
1096#[derive(Debug, Copy, Clone, Hash)]
1102pub enum MathArgItem<'a> {
1103 Arg(Arg<'a>),
1105 Space(Space<'a>),
1107 Comma(char, &'a SyntaxNode),
1109 Semicolon(char, &'a SyntaxNode),
1112 LeftParen(char, &'a SyntaxNode),
1114 RightParen(char, &'a SyntaxNode),
1116}
1117
1118impl<'a> MathArgs<'a> {
1119 pub fn arg_items(self) -> impl Iterator<Item = MathArg<'a>> {
1121 let mut content_items = self.content_items().peekable();
1122 std::iter::from_fn(move || {
1123 let arg = content_items.find_map(|node| match node {
1124 MathArgItem::Arg(arg) => Some(arg),
1125 _ => Option::None,
1126 })?;
1127
1128 let ends_in_semicolon = loop {
1130 match content_items.peek() {
1131 Option::None | Some(MathArgItem::Arg(_)) => break false,
1132 Some(MathArgItem::Semicolon(_, _)) => break true,
1133 Some(_) => {}
1134 }
1135 content_items.next();
1136 };
1137
1138 Some(MathArg { arg, ends_in_semicolon })
1139 })
1140 }
1141
1142 pub fn content_items(self) -> impl Iterator<Item = MathArgItem<'a>> {
1145 let mut children = self.0.children().peekable();
1146 let mut prev_hash = false;
1147 std::iter::from_fn(move || {
1148 for node in children.by_ref() {
1149 if let Some(arg) = node.cast() {
1150 return Some(MathArgItem::Arg(arg));
1151 }
1152 let semicolon_ends_code = prev_hash;
1153 prev_hash = false;
1154 let item = match node.kind() {
1155 SyntaxKind::Space => MathArgItem::Space(Space(node)),
1156 SyntaxKind::Comma => MathArgItem::Comma(',', node),
1157 SyntaxKind::LeftParen => MathArgItem::LeftParen('(', node),
1158 SyntaxKind::RightParen => MathArgItem::RightParen(')', node),
1159 SyntaxKind::Semicolon if !semicolon_ends_code => {
1160 MathArgItem::Semicolon(';', node)
1161 }
1162 SyntaxKind::Hash => {
1163 prev_hash = true;
1164 continue;
1165 }
1166 _ => continue,
1167 };
1168 return Some(item);
1169 }
1170 Option::None
1171 })
1172 }
1173}
1174
1175node! {
1176 struct MathAlignPoint
1178}
1179
1180node! {
1181 struct MathDelimited
1183}
1184
1185impl<'a> MathDelimited<'a> {
1186 pub fn open(self) -> Expr<'a> {
1188 self.0.cast_first()
1189 }
1190
1191 pub fn body(self) -> Math<'a> {
1193 self.0.cast_first()
1194 }
1195
1196 pub fn close(self) -> Expr<'a> {
1198 self.0.cast_last()
1199 }
1200}
1201
1202node! {
1203 struct MathAttach
1205}
1206
1207impl<'a> MathAttach<'a> {
1208 pub fn base(self) -> Expr<'a> {
1210 self.0.cast_first()
1211 }
1212
1213 pub fn bottom(self) -> Option<Expr<'a>> {
1215 self.0
1216 .children()
1217 .skip_while(|node| !matches!(node.kind(), SyntaxKind::Underscore))
1218 .find_map(SyntaxNode::cast)
1219 }
1220
1221 pub fn top(self) -> Option<Expr<'a>> {
1223 self.0
1224 .children()
1225 .skip_while(|node| !matches!(node.kind(), SyntaxKind::Hat))
1226 .find_map(SyntaxNode::cast)
1227 }
1228
1229 pub fn primes(self) -> Option<MathPrimes<'a>> {
1231 self.0
1232 .children()
1233 .skip_while(|node| node.cast::<Expr<'_>>().is_none())
1234 .nth(1)
1235 .and_then(|n| n.cast())
1236 }
1237}
1238
1239node! {
1240 struct MathPrimes
1242}
1243
1244impl MathPrimes<'_> {
1245 pub fn count(self) -> usize {
1247 self.0.leaf_text().len()
1249 }
1250}
1251
1252node! {
1253 struct MathFrac
1255}
1256
1257impl<'a> MathFrac<'a> {
1258 pub fn num(self) -> Expr<'a> {
1260 self.0.cast_first()
1261 }
1262
1263 pub fn denom(self) -> Expr<'a> {
1265 self.0.cast_last()
1266 }
1267}
1268
1269node! {
1270 struct MathRoot
1272}
1273
1274impl<'a> MathRoot<'a> {
1275 pub fn index(self) -> Option<u8> {
1277 match self.0.children().next().map(|node| node.leaf_text().as_str()) {
1278 Some("∜") => Some(4),
1279 Some("∛") => Some(3),
1280 Some("√") => Option::None,
1281 _ => Option::None,
1282 }
1283 }
1284
1285 pub fn radicand(self) -> Expr<'a> {
1287 self.0.cast_first()
1288 }
1289}
1290
1291node! {
1292 struct Ident
1294}
1295
1296impl<'a> Ident<'a> {
1297 pub fn get(self) -> &'a EcoString {
1299 self.0.leaf_text()
1300 }
1301
1302 pub fn as_str(self) -> &'a str {
1304 self.get()
1305 }
1306}
1307
1308impl Deref for Ident<'_> {
1309 type Target = str;
1310
1311 fn deref(&self) -> &Self::Target {
1314 self.as_str()
1315 }
1316}
1317
1318node! {
1319 struct None
1321}
1322
1323node! {
1324 struct Auto
1326}
1327
1328node! {
1329 struct Bool
1331}
1332
1333impl Bool<'_> {
1334 pub fn get(self) -> bool {
1336 self.0.leaf_text() == "true"
1337 }
1338}
1339
1340node! {
1341 struct Int
1343}
1344
1345impl Int<'_> {
1346 pub fn get(self) -> i64 {
1348 let text = self.0.leaf_text();
1349 if let Some(rest) = text.strip_prefix("0x") {
1350 i64::from_str_radix(rest, 16)
1351 } else if let Some(rest) = text.strip_prefix("0o") {
1352 i64::from_str_radix(rest, 8)
1353 } else if let Some(rest) = text.strip_prefix("0b") {
1354 i64::from_str_radix(rest, 2)
1355 } else {
1356 text.parse()
1357 }
1358 .unwrap_or_default()
1359 }
1360}
1361
1362node! {
1363 struct Float
1365}
1366
1367impl Float<'_> {
1368 pub fn get(self) -> f64 {
1370 self.0.leaf_text().parse().unwrap_or_default()
1371 }
1372}
1373
1374node! {
1375 struct Numeric
1377}
1378
1379impl Numeric<'_> {
1380 pub fn get(self) -> (f64, Unit) {
1382 let text = self.0.leaf_text();
1383 let count = text
1384 .chars()
1385 .rev()
1386 .take_while(|c| matches!(c, 'a'..='z' | '%'))
1387 .count();
1388
1389 let split = text.len() - count;
1390 let value = text[..split].parse().unwrap_or_default();
1391 let unit = match &text[split..] {
1392 "pt" => Unit::Pt,
1393 "mm" => Unit::Mm,
1394 "cm" => Unit::Cm,
1395 "in" => Unit::In,
1396 "deg" => Unit::Deg,
1397 "rad" => Unit::Rad,
1398 "em" => Unit::Em,
1399 "fr" => Unit::Fr,
1400 "%" => Unit::Percent,
1401 _ => Unit::Percent,
1402 };
1403
1404 (value, unit)
1405 }
1406}
1407
1408#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1410pub enum Unit {
1411 Pt,
1413 Mm,
1415 Cm,
1417 In,
1419 Rad,
1421 Deg,
1423 Em,
1425 Fr,
1427 Percent,
1429}
1430
1431node! {
1432 struct Str
1434}
1435
1436impl Str<'_> {
1437 pub fn get(self) -> EcoString {
1439 let text = self.0.leaf_text();
1440 let unquoted = &text[1..text.len() - 1];
1441 if !unquoted.contains('\\') {
1442 return unquoted.into();
1443 }
1444
1445 let mut out = EcoString::with_capacity(unquoted.len());
1446 let mut s = Scanner::new(unquoted);
1447
1448 while let Some(c) = s.eat() {
1449 if c != '\\' {
1450 out.push(c);
1451 continue;
1452 }
1453
1454 let start = s.locate(-1);
1455 match s.eat() {
1456 Some('\\') => out.push('\\'),
1457 Some('"') => out.push('"'),
1458 Some('n') => out.push('\n'),
1459 Some('r') => out.push('\r'),
1460 Some('t') => out.push('\t'),
1461 Some('u') if s.eat_if('{') => {
1462 let sequence = s.eat_while(char::is_ascii_hexdigit);
1463 s.eat_if('}');
1464
1465 match u32::from_str_radix(sequence, 16)
1466 .ok()
1467 .and_then(std::char::from_u32)
1468 {
1469 Some(c) => out.push(c),
1470 Option::None => out.push_str(s.from(start)),
1471 }
1472 }
1473 _ => out.push_str(s.from(start)),
1474 }
1475 }
1476
1477 out
1478 }
1479}
1480
1481node! {
1482 struct CodeBlock
1484}
1485
1486impl<'a> CodeBlock<'a> {
1487 pub fn body(self) -> Code<'a> {
1489 self.0.cast_first()
1490 }
1491}
1492
1493node! {
1494 struct Code
1496}
1497
1498impl<'a> Code<'a> {
1499 pub fn exprs(self) -> impl DoubleEndedIterator<Item = Expr<'a>> {
1501 self.0.children().filter_map(SyntaxNode::cast)
1502 }
1503}
1504
1505node! {
1506 struct ContentBlock
1508}
1509
1510impl<'a> ContentBlock<'a> {
1511 pub fn body(self) -> Markup<'a> {
1513 self.0.cast_first()
1514 }
1515}
1516
1517node! {
1518 struct Parenthesized
1520}
1521
1522impl<'a> Parenthesized<'a> {
1523 pub fn expr(self) -> Expr<'a> {
1527 self.0.cast_first()
1528 }
1529
1530 pub fn pattern(self) -> Pattern<'a> {
1534 self.0.cast_first()
1535 }
1536}
1537
1538node! {
1539 struct Array
1541}
1542
1543impl<'a> Array<'a> {
1544 pub fn items(self) -> impl DoubleEndedIterator<Item = ArrayItem<'a>> {
1546 self.0.children().filter_map(SyntaxNode::cast)
1547 }
1548}
1549
1550#[derive(Debug, Copy, Clone, Hash)]
1552pub enum ArrayItem<'a> {
1553 Pos(Expr<'a>),
1555 Spread(Spread<'a>),
1557}
1558
1559impl<'a> AstNode<'a> for ArrayItem<'a> {
1560 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1561 match node.kind() {
1562 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1563 _ => node.cast().map(Self::Pos),
1564 }
1565 }
1566
1567 fn to_untyped(self) -> &'a SyntaxNode {
1568 match self {
1569 Self::Pos(v) => v.to_untyped(),
1570 Self::Spread(v) => v.to_untyped(),
1571 }
1572 }
1573
1574 fn placeholder() -> Self {
1575 Self::Pos(Expr::placeholder())
1576 }
1577}
1578
1579node! {
1580 struct Dict
1582}
1583
1584impl<'a> Dict<'a> {
1585 pub fn items(self) -> impl DoubleEndedIterator<Item = DictItem<'a>> {
1587 self.0.children().filter_map(SyntaxNode::cast)
1588 }
1589}
1590
1591#[derive(Debug, Copy, Clone, Hash)]
1593pub enum DictItem<'a> {
1594 Named(Named<'a>),
1596 Keyed(Keyed<'a>),
1598 Spread(Spread<'a>),
1600}
1601
1602impl<'a> AstNode<'a> for DictItem<'a> {
1603 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
1604 match node.kind() {
1605 SyntaxKind::Named => Some(Self::Named(Named(node))),
1606 SyntaxKind::Keyed => Some(Self::Keyed(Keyed(node))),
1607 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
1608 _ => Option::None,
1609 }
1610 }
1611
1612 fn to_untyped(self) -> &'a SyntaxNode {
1613 match self {
1614 Self::Named(v) => v.to_untyped(),
1615 Self::Keyed(v) => v.to_untyped(),
1616 Self::Spread(v) => v.to_untyped(),
1617 }
1618 }
1619
1620 fn placeholder() -> Self {
1621 Self::Spread(Spread::placeholder())
1622 }
1623}
1624
1625node! {
1626 struct Named
1628}
1629
1630impl<'a> Named<'a> {
1631 pub fn name(self) -> Ident<'a> {
1633 self.0.cast_first()
1634 }
1635
1636 pub fn expr(self) -> Expr<'a> {
1641 self.0.cast_last()
1642 }
1643
1644 pub fn pattern(self) -> Pattern<'a> {
1649 self.0.cast_last()
1650 }
1651}
1652
1653node! {
1654 struct Keyed
1656}
1657
1658impl<'a> Keyed<'a> {
1659 pub fn key(self) -> Expr<'a> {
1661 self.0.cast_first()
1662 }
1663
1664 pub fn expr(self) -> Expr<'a> {
1669 self.0.cast_last()
1670 }
1671}
1672
1673node! {
1674 struct Spread
1676}
1677
1678impl<'a> Spread<'a> {
1679 pub fn expr(self) -> Expr<'a> {
1684 self.0.cast_first()
1685 }
1686
1687 pub fn sink_ident(self) -> Option<Ident<'a>> {
1692 self.0.try_cast_first()
1693 }
1694
1695 pub fn sink_expr(self) -> Option<Expr<'a>> {
1700 self.0.try_cast_first()
1701 }
1702}
1703
1704node! {
1705 struct Unary
1707}
1708
1709impl<'a> Unary<'a> {
1710 pub fn op(self) -> UnOp {
1712 self.0
1713 .children()
1714 .find_map(|node| UnOp::from_kind(node.kind()))
1715 .unwrap_or(UnOp::Pos)
1716 }
1717
1718 pub fn expr(self) -> Expr<'a> {
1720 self.0.cast_last()
1721 }
1722}
1723
1724#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1726pub enum UnOp {
1727 Pos,
1729 Neg,
1731 Not,
1733}
1734
1735impl UnOp {
1736 pub fn from_kind(token: SyntaxKind) -> Option<Self> {
1738 Some(match token {
1739 SyntaxKind::Plus => Self::Pos,
1740 SyntaxKind::Minus => Self::Neg,
1741 SyntaxKind::Not => Self::Not,
1742 _ => return Option::None,
1743 })
1744 }
1745
1746 pub fn precedence(self) -> u8 {
1748 match self {
1749 Self::Pos | Self::Neg => 7,
1750 Self::Not => 4,
1751 }
1752 }
1753
1754 pub fn as_str(self) -> &'static str {
1756 match self {
1757 Self::Pos => "+",
1758 Self::Neg => "-",
1759 Self::Not => "not",
1760 }
1761 }
1762}
1763
1764node! {
1765 struct Binary
1767}
1768
1769impl<'a> Binary<'a> {
1770 pub fn op(self) -> BinOp {
1772 let mut not = false;
1773 self.0
1774 .children()
1775 .find_map(|node| match node.kind() {
1776 SyntaxKind::Not => {
1777 not = true;
1778 Option::None
1779 }
1780 SyntaxKind::In if not => Some(BinOp::NotIn),
1781 _ => BinOp::from_kind(node.kind()),
1782 })
1783 .unwrap_or(BinOp::Add)
1784 }
1785
1786 pub fn lhs(self) -> Expr<'a> {
1788 self.0.cast_first()
1789 }
1790
1791 pub fn rhs(self) -> Expr<'a> {
1793 self.0.cast_last()
1794 }
1795}
1796
1797#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1799pub enum BinOp {
1800 Add,
1802 Sub,
1804 Mul,
1806 Div,
1808 And,
1810 Or,
1812 Eq,
1814 Neq,
1816 Lt,
1818 Leq,
1820 Gt,
1822 Geq,
1824 Assign,
1826 In,
1828 NotIn,
1830 AddAssign,
1832 SubAssign,
1834 MulAssign,
1836 DivAssign,
1838}
1839
1840impl BinOp {
1841 pub fn from_kind(token: SyntaxKind) -> Option<Self> {
1843 Some(match token {
1844 SyntaxKind::Plus => Self::Add,
1845 SyntaxKind::Minus => Self::Sub,
1846 SyntaxKind::Star => Self::Mul,
1847 SyntaxKind::Slash => Self::Div,
1848 SyntaxKind::And => Self::And,
1849 SyntaxKind::Or => Self::Or,
1850 SyntaxKind::EqEq => Self::Eq,
1851 SyntaxKind::ExclEq => Self::Neq,
1852 SyntaxKind::Lt => Self::Lt,
1853 SyntaxKind::LtEq => Self::Leq,
1854 SyntaxKind::Gt => Self::Gt,
1855 SyntaxKind::GtEq => Self::Geq,
1856 SyntaxKind::Eq => Self::Assign,
1857 SyntaxKind::In => Self::In,
1858 SyntaxKind::PlusEq => Self::AddAssign,
1859 SyntaxKind::HyphEq => Self::SubAssign,
1860 SyntaxKind::StarEq => Self::MulAssign,
1861 SyntaxKind::SlashEq => Self::DivAssign,
1862 _ => return Option::None,
1863 })
1864 }
1865
1866 pub fn precedence(self) -> u8 {
1868 match self {
1869 Self::Mul => 6,
1870 Self::Div => 6,
1871 Self::Add => 5,
1872 Self::Sub => 5,
1873 Self::Eq => 4,
1874 Self::Neq => 4,
1875 Self::Lt => 4,
1876 Self::Leq => 4,
1877 Self::Gt => 4,
1878 Self::Geq => 4,
1879 Self::In => 4,
1880 Self::NotIn => 4,
1881 Self::And => 3,
1882 Self::Or => 2,
1883 Self::Assign => 1,
1884 Self::AddAssign => 1,
1885 Self::SubAssign => 1,
1886 Self::MulAssign => 1,
1887 Self::DivAssign => 1,
1888 }
1889 }
1890
1891 pub fn assoc(self) -> Assoc {
1893 match self {
1894 Self::Add => Assoc::Left,
1895 Self::Sub => Assoc::Left,
1896 Self::Mul => Assoc::Left,
1897 Self::Div => Assoc::Left,
1898 Self::And => Assoc::Left,
1899 Self::Or => Assoc::Left,
1900 Self::Eq => Assoc::Left,
1901 Self::Neq => Assoc::Left,
1902 Self::Lt => Assoc::Left,
1903 Self::Leq => Assoc::Left,
1904 Self::Gt => Assoc::Left,
1905 Self::Geq => Assoc::Left,
1906 Self::In => Assoc::Left,
1907 Self::NotIn => Assoc::Left,
1908 Self::Assign => Assoc::Right,
1909 Self::AddAssign => Assoc::Right,
1910 Self::SubAssign => Assoc::Right,
1911 Self::MulAssign => Assoc::Right,
1912 Self::DivAssign => Assoc::Right,
1913 }
1914 }
1915
1916 pub fn as_str(self) -> &'static str {
1918 match self {
1919 Self::Add => "+",
1920 Self::Sub => "-",
1921 Self::Mul => "*",
1922 Self::Div => "/",
1923 Self::And => "and",
1924 Self::Or => "or",
1925 Self::Eq => "==",
1926 Self::Neq => "!=",
1927 Self::Lt => "<",
1928 Self::Leq => "<=",
1929 Self::Gt => ">",
1930 Self::Geq => ">=",
1931 Self::In => "in",
1932 Self::NotIn => "not in",
1933 Self::Assign => "=",
1934 Self::AddAssign => "+=",
1935 Self::SubAssign => "-=",
1936 Self::MulAssign => "*=",
1937 Self::DivAssign => "/=",
1938 }
1939 }
1940}
1941
1942#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1944pub enum Assoc {
1945 Left,
1947 Right,
1949}
1950
1951node! {
1952 struct FieldAccess
1954}
1955
1956impl<'a> FieldAccess<'a> {
1957 pub fn target(self) -> Expr<'a> {
1959 self.0.cast_first()
1960 }
1961
1962 pub fn field(self) -> Ident<'a> {
1964 self.0.cast_last()
1965 }
1966}
1967
1968node! {
1969 struct FuncCall
1971}
1972
1973impl<'a> FuncCall<'a> {
1974 pub fn callee(self) -> Expr<'a> {
1976 self.0.cast_first()
1977 }
1978
1979 pub fn args(self) -> Args<'a> {
1981 self.0.cast_last()
1982 }
1983}
1984
1985node! {
1986 struct Args
1988}
1989
1990impl<'a> Args<'a> {
1991 pub fn items(self) -> impl DoubleEndedIterator<Item = Arg<'a>> {
1993 self.0.children().filter_map(SyntaxNode::cast)
1994 }
1995
1996 pub fn trailing_comma(self) -> bool {
1998 self.0
1999 .children()
2000 .rev()
2001 .skip(1)
2002 .find(|n| !n.kind().is_trivia())
2003 .is_some_and(|n| n.kind() == SyntaxKind::Comma)
2004 }
2005}
2006
2007#[derive(Debug, Copy, Clone, Hash)]
2009pub enum Arg<'a> {
2010 Pos(Expr<'a>),
2012 Named(Named<'a>),
2014 Spread(Spread<'a>),
2016}
2017
2018impl<'a> AstNode<'a> for Arg<'a> {
2019 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2020 match node.kind() {
2021 SyntaxKind::Named => Some(Self::Named(Named(node))),
2022 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
2023 _ => node.cast().map(Self::Pos),
2024 }
2025 }
2026
2027 fn to_untyped(self) -> &'a SyntaxNode {
2028 match self {
2029 Self::Pos(v) => v.to_untyped(),
2030 Self::Named(v) => v.to_untyped(),
2031 Self::Spread(v) => v.to_untyped(),
2032 }
2033 }
2034
2035 fn placeholder() -> Self {
2036 Self::Pos(Expr::placeholder())
2037 }
2038}
2039
2040node! {
2041 struct Closure
2043}
2044
2045impl<'a> Closure<'a> {
2046 pub fn name(self) -> Option<Ident<'a>> {
2050 self.0.children().next()?.cast()
2051 }
2052
2053 pub fn params(self) -> Params<'a> {
2055 self.0.cast_first()
2056 }
2057
2058 pub fn body(self) -> Expr<'a> {
2060 self.0.cast_last()
2061 }
2062}
2063
2064node! {
2065 struct Params
2067}
2068
2069impl<'a> Params<'a> {
2070 pub fn children(self) -> impl DoubleEndedIterator<Item = Param<'a>> {
2072 self.0.children().filter_map(SyntaxNode::cast)
2073 }
2074}
2075
2076#[derive(Debug, Copy, Clone, Hash)]
2078pub enum Param<'a> {
2079 Pos(Pattern<'a>),
2081 Named(Named<'a>),
2083 Spread(Spread<'a>),
2085}
2086
2087impl<'a> AstNode<'a> for Param<'a> {
2088 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2089 match node.kind() {
2090 SyntaxKind::Named => Some(Self::Named(Named(node))),
2091 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
2092 _ => node.cast().map(Self::Pos),
2093 }
2094 }
2095
2096 fn to_untyped(self) -> &'a SyntaxNode {
2097 match self {
2098 Self::Pos(v) => v.to_untyped(),
2099 Self::Named(v) => v.to_untyped(),
2100 Self::Spread(v) => v.to_untyped(),
2101 }
2102 }
2103
2104 fn placeholder() -> Self {
2105 Self::Pos(Pattern::placeholder())
2106 }
2107}
2108
2109#[derive(Debug, Copy, Clone, Hash)]
2111pub enum Pattern<'a> {
2112 Normal(Expr<'a>),
2114 Placeholder(Underscore<'a>),
2116 Parenthesized(Parenthesized<'a>),
2118 Destructuring(Destructuring<'a>),
2120}
2121
2122impl<'a> AstNode<'a> for Pattern<'a> {
2123 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2124 match node.kind() {
2125 SyntaxKind::Underscore => Some(Self::Placeholder(Underscore(node))),
2126 SyntaxKind::Parenthesized => Some(Self::Parenthesized(Parenthesized(node))),
2127 SyntaxKind::Destructuring => Some(Self::Destructuring(Destructuring(node))),
2128 _ => node.cast().map(Self::Normal),
2129 }
2130 }
2131
2132 fn to_untyped(self) -> &'a SyntaxNode {
2133 match self {
2134 Self::Normal(v) => v.to_untyped(),
2135 Self::Placeholder(v) => v.to_untyped(),
2136 Self::Parenthesized(v) => v.to_untyped(),
2137 Self::Destructuring(v) => v.to_untyped(),
2138 }
2139 }
2140
2141 fn placeholder() -> Self {
2142 Self::Normal(Expr::placeholder())
2143 }
2144}
2145
2146impl<'a> Pattern<'a> {
2147 pub fn bindings(self) -> Vec<Ident<'a>> {
2149 match self {
2150 Self::Normal(Expr::Ident(ident)) => vec![ident],
2151 Self::Parenthesized(v) => v.pattern().bindings(),
2152 Self::Destructuring(v) => v.bindings(),
2153 _ => vec![],
2154 }
2155 }
2156}
2157
2158node! {
2159 struct Underscore
2161}
2162
2163node! {
2164 struct Destructuring
2166}
2167
2168impl<'a> Destructuring<'a> {
2169 pub fn items(self) -> impl DoubleEndedIterator<Item = DestructuringItem<'a>> {
2171 self.0.children().filter_map(SyntaxNode::cast)
2172 }
2173
2174 pub fn bindings(self) -> Vec<Ident<'a>> {
2176 self.items()
2177 .flat_map(|binding| match binding {
2178 DestructuringItem::Pattern(pattern) => pattern.bindings(),
2179 DestructuringItem::Named(named) => named.pattern().bindings(),
2180 DestructuringItem::Spread(spread) => {
2181 spread.sink_ident().into_iter().collect()
2182 }
2183 })
2184 .collect()
2185 }
2186}
2187
2188#[derive(Debug, Copy, Clone, Hash)]
2190pub enum DestructuringItem<'a> {
2191 Pattern(Pattern<'a>),
2193 Named(Named<'a>),
2195 Spread(Spread<'a>),
2197}
2198
2199impl<'a> AstNode<'a> for DestructuringItem<'a> {
2200 fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
2201 match node.kind() {
2202 SyntaxKind::Named => Some(Self::Named(Named(node))),
2203 SyntaxKind::Spread => Some(Self::Spread(Spread(node))),
2204 _ => node.cast().map(Self::Pattern),
2205 }
2206 }
2207
2208 fn to_untyped(self) -> &'a SyntaxNode {
2209 match self {
2210 Self::Pattern(v) => v.to_untyped(),
2211 Self::Named(v) => v.to_untyped(),
2212 Self::Spread(v) => v.to_untyped(),
2213 }
2214 }
2215
2216 fn placeholder() -> Self {
2217 Self::Pattern(Pattern::placeholder())
2218 }
2219}
2220
2221node! {
2222 struct LetBinding
2224}
2225
2226#[derive(Debug)]
2228pub enum LetBindingKind<'a> {
2229 Normal(Pattern<'a>),
2231 Closure(Ident<'a>),
2233}
2234
2235impl<'a> LetBindingKind<'a> {
2236 pub fn bindings(self) -> Vec<Ident<'a>> {
2238 match self {
2239 LetBindingKind::Normal(pattern) => pattern.bindings(),
2240 LetBindingKind::Closure(ident) => vec![ident],
2241 }
2242 }
2243}
2244
2245impl<'a> LetBinding<'a> {
2246 pub fn kind(self) -> LetBindingKind<'a> {
2248 match self.0.cast_first() {
2249 Pattern::Normal(Expr::Closure(closure)) => {
2250 LetBindingKind::Closure(closure.name().unwrap_or_else(Ident::placeholder))
2251 }
2252 pattern => LetBindingKind::Normal(pattern),
2253 }
2254 }
2255
2256 pub fn init(self) -> Option<Expr<'a>> {
2258 match self.kind() {
2259 LetBindingKind::Normal(Pattern::Normal(_) | Pattern::Parenthesized(_)) => {
2260 self.0.children().filter_map(SyntaxNode::cast).nth(1)
2261 }
2262 LetBindingKind::Normal(_) => self.0.try_cast_first(),
2263 LetBindingKind::Closure(_) => self.0.try_cast_first(),
2264 }
2265 }
2266}
2267
2268node! {
2269 struct DestructAssignment
2271}
2272
2273impl<'a> DestructAssignment<'a> {
2274 pub fn pattern(self) -> Pattern<'a> {
2276 self.0.cast_first()
2277 }
2278
2279 pub fn value(self) -> Expr<'a> {
2281 self.0.cast_last()
2282 }
2283}
2284
2285node! {
2286 struct SetRule
2288}
2289
2290impl<'a> SetRule<'a> {
2291 pub fn target(self) -> Expr<'a> {
2293 self.0.cast_first()
2294 }
2295
2296 pub fn args(self) -> Args<'a> {
2298 self.0.cast_last()
2299 }
2300
2301 pub fn condition(self) -> Option<Expr<'a>> {
2303 self.0
2304 .children()
2305 .skip_while(|child| child.kind() != SyntaxKind::If)
2306 .find_map(SyntaxNode::cast)
2307 }
2308}
2309
2310node! {
2311 struct ShowRule
2313}
2314
2315impl<'a> ShowRule<'a> {
2316 pub fn selector(self) -> Option<Expr<'a>> {
2318 self.0
2319 .children()
2320 .rev()
2321 .skip_while(|child| child.kind() != SyntaxKind::Colon)
2322 .find_map(SyntaxNode::cast)
2323 }
2324
2325 pub fn transform(self) -> Expr<'a> {
2327 self.0.cast_last()
2328 }
2329}
2330
2331node! {
2332 struct Contextual
2334}
2335
2336impl<'a> Contextual<'a> {
2337 pub fn body(self) -> Expr<'a> {
2339 self.0.cast_first()
2340 }
2341}
2342
2343node! {
2344 struct Conditional
2346}
2347
2348impl<'a> Conditional<'a> {
2349 pub fn condition(self) -> Expr<'a> {
2351 self.0.cast_first()
2352 }
2353
2354 pub fn if_body(self) -> Expr<'a> {
2356 self.0
2357 .children()
2358 .filter_map(SyntaxNode::cast)
2359 .nth(1)
2360 .unwrap_or_else(Expr::placeholder)
2361 }
2362
2363 pub fn else_body(self) -> Option<Expr<'a>> {
2365 self.0.children().filter_map(SyntaxNode::cast).nth(2)
2366 }
2367}
2368
2369node! {
2370 struct WhileLoop
2372}
2373
2374impl<'a> WhileLoop<'a> {
2375 pub fn condition(self) -> Expr<'a> {
2377 self.0.cast_first()
2378 }
2379
2380 pub fn body(self) -> Expr<'a> {
2382 self.0.cast_last()
2383 }
2384}
2385
2386node! {
2387 struct ForLoop
2389}
2390
2391impl<'a> ForLoop<'a> {
2392 pub fn pattern(self) -> Pattern<'a> {
2394 self.0.cast_first()
2395 }
2396
2397 pub fn iterable(self) -> Expr<'a> {
2399 self.0
2400 .children()
2401 .skip_while(|&c| c.kind() != SyntaxKind::In)
2402 .find_map(SyntaxNode::cast)
2403 .unwrap_or_else(Expr::placeholder)
2404 }
2405
2406 pub fn body(self) -> Expr<'a> {
2408 self.0.cast_last()
2409 }
2410}
2411
2412node! {
2413 struct ModuleImport
2415}
2416
2417impl<'a> ModuleImport<'a> {
2418 pub fn source(self) -> Expr<'a> {
2420 self.0.cast_first()
2421 }
2422
2423 pub fn imports(self) -> Option<Imports<'a>> {
2425 self.0.children().find_map(|node| match node.kind() {
2426 SyntaxKind::Star => Some(Imports::Wildcard),
2427 SyntaxKind::ImportItems => node.cast().map(Imports::Items),
2428 _ => Option::None,
2429 })
2430 }
2431
2432 pub fn bare_name(self) -> Result<EcoString, BareImportError> {
2440 match self.source() {
2441 Expr::Ident(ident) => Ok(ident.get().clone()),
2442 Expr::FieldAccess(access) => Ok(access.field().get().clone()),
2443 Expr::Str(string) => {
2444 let string = string.get();
2445 let name = if string.starts_with('@') {
2446 PackageSpec::from_str(&string)
2447 .map_err(|_| BareImportError::PackageInvalid)?
2448 .name
2449 } else {
2450 Path::new(string.as_str())
2451 .file_stem()
2452 .and_then(|path| path.to_str())
2453 .ok_or(BareImportError::PathInvalid)?
2454 .into()
2455 };
2456
2457 if !is_ident(&name) {
2458 return Err(BareImportError::PathInvalid);
2459 }
2460
2461 Ok(name)
2462 }
2463 _ => Err(BareImportError::Dynamic),
2464 }
2465 }
2466
2467 pub fn new_name(self) -> Option<Ident<'a>> {
2470 self.0
2471 .children()
2472 .skip_while(|child| child.kind() != SyntaxKind::As)
2473 .find_map(SyntaxNode::cast)
2474 }
2475}
2476
2477#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
2479pub enum BareImportError {
2480 Dynamic,
2482 PathInvalid,
2485 PackageInvalid,
2487}
2488
2489#[derive(Debug, Copy, Clone, Hash)]
2491pub enum Imports<'a> {
2492 Wildcard,
2494 Items(ImportItems<'a>),
2496}
2497
2498node! {
2499 struct ImportItems
2501}
2502
2503impl<'a> ImportItems<'a> {
2504 pub fn iter(self) -> impl DoubleEndedIterator<Item = ImportItem<'a>> {
2506 self.0.children().filter_map(|child| match child.kind() {
2507 SyntaxKind::RenamedImportItem => child.cast().map(ImportItem::Renamed),
2508 SyntaxKind::ImportItemPath => child.cast().map(ImportItem::Simple),
2509 _ => Option::None,
2510 })
2511 }
2512}
2513
2514node! {
2515 struct ImportItemPath
2517}
2518
2519impl<'a> ImportItemPath<'a> {
2520 pub fn iter(self) -> impl DoubleEndedIterator<Item = Ident<'a>> {
2522 self.0.children().filter_map(SyntaxNode::cast)
2523 }
2524
2525 pub fn name(self) -> Ident<'a> {
2527 self.0.cast_last()
2528 }
2529}
2530
2531#[derive(Debug, Copy, Clone, Hash)]
2533pub enum ImportItem<'a> {
2534 Simple(ImportItemPath<'a>),
2537 Renamed(RenamedImportItem<'a>),
2540}
2541
2542impl<'a> ImportItem<'a> {
2543 pub fn path(self) -> ImportItemPath<'a> {
2545 match self {
2546 Self::Simple(path) => path,
2547 Self::Renamed(renamed_item) => renamed_item.path(),
2548 }
2549 }
2550
2551 pub fn original_name(self) -> Ident<'a> {
2554 match self {
2555 Self::Simple(path) => path.name(),
2556 Self::Renamed(renamed_item) => renamed_item.original_name(),
2557 }
2558 }
2559
2560 pub fn bound_name(self) -> Ident<'a> {
2563 match self {
2564 Self::Simple(path) => path.name(),
2565 Self::Renamed(renamed_item) => renamed_item.new_name(),
2566 }
2567 }
2568}
2569
2570node! {
2571 struct RenamedImportItem
2573}
2574
2575impl<'a> RenamedImportItem<'a> {
2576 pub fn path(self) -> ImportItemPath<'a> {
2578 self.0.cast_first()
2579 }
2580
2581 pub fn original_name(self) -> Ident<'a> {
2583 self.path().name()
2584 }
2585
2586 pub fn new_name(self) -> Ident<'a> {
2588 self.0.cast_last()
2589 }
2590}
2591
2592node! {
2593 struct ModuleInclude
2595}
2596
2597impl<'a> ModuleInclude<'a> {
2598 pub fn source(self) -> Expr<'a> {
2600 self.0.cast_last()
2601 }
2602}
2603
2604node! {
2605 struct LoopBreak
2607}
2608
2609node! {
2610 struct LoopContinue
2612}
2613
2614node! {
2615 struct FuncReturn
2617}
2618
2619impl<'a> FuncReturn<'a> {
2620 pub fn body(self) -> Option<Expr<'a>> {
2622 self.0.try_cast_last()
2623 }
2624}
2625
2626#[cfg(test)]
2627mod tests {
2628 use super::*;
2629
2630 #[test]
2631 fn test_expr_placeholder() {
2632 assert!(Expr::placeholder().to_untyped().cast::<Expr>().is_some());
2633 }
2634}