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}