mago_syntax/ast/ast/
string.rs

1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::ast::expression::Expression;
8use crate::ast::sequence::Sequence;
9
10#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
11#[serde(tag = "type", content = "value")]
12#[repr(u8)]
13pub enum CompositeString<'arena> {
14    ShellExecute(ShellExecuteString<'arena>),
15    Interpolated(InterpolatedString<'arena>),
16    Document(DocumentString<'arena>),
17}
18
19#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
20pub struct ShellExecuteString<'arena> {
21    pub left_backtick: Span,
22    pub parts: Sequence<'arena, StringPart<'arena>>,
23    pub right_backtick: Span,
24}
25
26#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
27pub struct InterpolatedString<'arena> {
28    pub left_double_quote: Span,
29    pub parts: Sequence<'arena, StringPart<'arena>>,
30    pub right_double_quote: Span,
31}
32
33#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
34#[serde(tag = "type", content = "value")]
35pub enum DocumentKind {
36    Heredoc,
37    Nowdoc,
38}
39
40#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
41#[serde(tag = "type", content = "value")]
42#[repr(u8)]
43pub enum DocumentIndentation {
44    None,
45    Whitespace(usize),
46    Tab(usize),
47    Mixed(usize, usize),
48}
49
50#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
51pub struct DocumentString<'arena> {
52    pub open: Span,
53    pub kind: DocumentKind,
54    pub indentation: DocumentIndentation,
55    pub label: &'arena str,
56    pub parts: Sequence<'arena, StringPart<'arena>>,
57    pub close: Span,
58}
59
60#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
61#[serde(tag = "type", content = "value")]
62#[repr(u8)]
63pub enum StringPart<'arena> {
64    Literal(LiteralStringPart<'arena>),
65    Expression(&'arena Expression<'arena>),
66    BracedExpression(BracedExpressionStringPart<'arena>),
67}
68
69#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
70pub struct LiteralStringPart<'arena> {
71    pub span: Span,
72    pub value: &'arena str,
73}
74
75#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
76pub struct BracedExpressionStringPart<'arena> {
77    pub left_brace: Span,
78    pub expression: &'arena Expression<'arena>,
79    pub right_brace: Span,
80}
81
82impl<'arena> CompositeString<'arena> {
83    #[must_use]
84    pub fn parts(&self) -> &Sequence<'arena, StringPart<'arena>> {
85        match self {
86            CompositeString::ShellExecute(s) => &s.parts,
87            CompositeString::Interpolated(i) => &i.parts,
88            CompositeString::Document(d) => &d.parts,
89        }
90    }
91}
92
93impl HasSpan for CompositeString<'_> {
94    fn span(&self) -> Span {
95        match self {
96            CompositeString::ShellExecute(s) => s.span(),
97            CompositeString::Interpolated(i) => i.span(),
98            CompositeString::Document(d) => d.span(),
99        }
100    }
101}
102
103impl HasSpan for ShellExecuteString<'_> {
104    fn span(&self) -> Span {
105        self.left_backtick.join(self.right_backtick)
106    }
107}
108
109impl HasSpan for InterpolatedString<'_> {
110    fn span(&self) -> Span {
111        self.left_double_quote.join(self.right_double_quote)
112    }
113}
114
115impl HasSpan for DocumentString<'_> {
116    fn span(&self) -> Span {
117        self.open
118    }
119}
120
121impl HasSpan for StringPart<'_> {
122    fn span(&self) -> Span {
123        match self {
124            StringPart::Literal(l) => l.span(),
125            StringPart::Expression(e) => e.span(),
126            StringPart::BracedExpression(b) => b.span(),
127        }
128    }
129}
130
131impl HasSpan for LiteralStringPart<'_> {
132    fn span(&self) -> Span {
133        self.span
134    }
135}
136
137impl HasSpan for BracedExpressionStringPart<'_> {
138    fn span(&self) -> Span {
139        self.left_brace.join(self.right_brace)
140    }
141}