mago_syntax/ast/ast/
string.rs

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