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}