Skip to main content

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