darklua_core/nodes/expressions/
interpolated_string.rs1use std::iter::FromIterator;
2
3use crate::nodes::{StringError, Token, Trivia};
4
5use super::{string_utils, Expression};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct StringSegment {
9 value: String,
10 token: Option<Token>,
11}
12
13impl StringSegment {
14 pub fn new(value: impl AsRef<str>) -> Result<Self, StringError> {
15 string_utils::read_escaped_string(value.as_ref().char_indices(), None).map(Self::from_value)
16 }
17
18 pub fn from_value(value: impl Into<String>) -> Self {
19 Self {
20 value: value.into(),
21 token: None,
22 }
23 }
24
25 pub fn with_token(mut self, token: Token) -> Self {
26 self.token = Some(token);
27 self
28 }
29
30 pub fn set_token(&mut self, token: Token) {
31 self.token = Some(token);
32 }
33
34 pub fn get_token(&self) -> Option<&Token> {
35 self.token.as_ref()
36 }
37
38 pub fn get_value(&self) -> &str {
39 self.value.as_str()
40 }
41
42 fn append(&mut self, mut other: Self) {
43 self.value.extend(other.value.drain(..));
44 self.token = None;
45 }
46
47 #[inline]
48 pub fn len(&self) -> usize {
49 self.value.len()
50 }
51
52 #[inline]
53 pub fn is_empty(&self) -> bool {
54 self.value.is_empty()
55 }
56
57 super::impl_token_fns!(iter = [token]);
58}
59
60#[derive(Clone, Debug, PartialEq, Eq)]
61pub struct ValueSegment {
62 value: Expression,
63 tokens: Option<ValueSegmentTokens>,
64}
65
66impl ValueSegment {
67 pub fn new(value: impl Into<Expression>) -> Self {
68 Self {
69 value: value.into(),
70 tokens: None,
71 }
72 }
73
74 pub fn with_tokens(mut self, tokens: ValueSegmentTokens) -> Self {
75 self.tokens = Some(tokens);
76 self
77 }
78
79 pub fn set_tokens(&mut self, tokens: ValueSegmentTokens) {
80 self.tokens = Some(tokens);
81 }
82
83 pub fn get_tokens(&self) -> Option<&ValueSegmentTokens> {
84 self.tokens.as_ref()
85 }
86
87 pub fn get_expression(&self) -> &Expression {
88 &self.value
89 }
90
91 pub fn mutate_expression(&mut self) -> &mut Expression {
92 &mut self.value
93 }
94
95 super::impl_token_fns!(iter = [tokens]);
96}
97
98#[derive(Clone, Debug, PartialEq, Eq)]
99pub struct ValueSegmentTokens {
100 pub opening_brace: Token,
101 pub closing_brace: Token,
102}
103
104impl ValueSegmentTokens {
105 super::impl_token_fns!(target = [opening_brace, closing_brace]);
106}
107
108#[derive(Clone, Debug, PartialEq, Eq)]
109pub enum InterpolationSegment {
110 String(StringSegment),
111 Value(ValueSegment),
112}
113
114impl InterpolationSegment {
115 pub fn clear_comments(&mut self) {
116 match self {
117 InterpolationSegment::String(segment) => segment.clear_comments(),
118 InterpolationSegment::Value(segment) => segment.clear_comments(),
119 }
120 }
121
122 pub fn clear_whitespaces(&mut self) {
123 match self {
124 InterpolationSegment::String(segment) => segment.clear_whitespaces(),
125 InterpolationSegment::Value(segment) => segment.clear_whitespaces(),
126 }
127 }
128
129 pub(crate) fn replace_referenced_tokens(&mut self, code: &str) {
130 match self {
131 InterpolationSegment::String(segment) => segment.replace_referenced_tokens(code),
132 InterpolationSegment::Value(segment) => segment.replace_referenced_tokens(code),
133 }
134 }
135
136 pub(crate) fn shift_token_line(&mut self, amount: usize) {
137 match self {
138 InterpolationSegment::String(segment) => segment.shift_token_line(amount),
139 InterpolationSegment::Value(segment) => segment.shift_token_line(amount),
140 }
141 }
142
143 pub(crate) fn filter_comments(&mut self, filter: impl Fn(&Trivia) -> bool) {
144 match self {
145 InterpolationSegment::String(segment) => segment.filter_comments(filter),
146 InterpolationSegment::Value(segment) => segment.filter_comments(filter),
147 }
148 }
149}
150
151impl From<StringSegment> for InterpolationSegment {
152 fn from(segment: StringSegment) -> Self {
153 Self::String(segment)
154 }
155}
156
157impl From<ValueSegment> for InterpolationSegment {
158 fn from(segment: ValueSegment) -> Self {
159 Self::Value(segment)
160 }
161}
162
163impl<T: Into<Expression>> From<T> for InterpolationSegment {
164 fn from(value: T) -> Self {
165 Self::Value(ValueSegment::new(value.into()))
166 }
167}
168
169impl From<&str> for InterpolationSegment {
170 fn from(string: &str) -> Self {
171 Self::String(StringSegment::from_value(string))
172 }
173}
174
175impl From<&String> for InterpolationSegment {
176 fn from(string: &String) -> Self {
177 Self::String(StringSegment::from_value(string))
178 }
179}
180
181impl From<String> for InterpolationSegment {
182 fn from(string: String) -> Self {
183 Self::String(StringSegment::from_value(string))
184 }
185}
186
187#[derive(Clone, Debug, PartialEq, Eq)]
188pub struct InterpolatedStringExpression {
189 segments: Vec<InterpolationSegment>,
190 tokens: Option<InterpolatedStringTokens>,
191}
192
193impl InterpolatedStringExpression {
194 pub fn new(segments: Vec<InterpolationSegment>) -> Self {
195 Self {
196 segments,
197 tokens: None,
198 }
199 }
200
201 pub fn empty() -> Self {
202 Self::new(Vec::default())
203 }
204
205 pub fn with_segment(mut self, segment: impl Into<InterpolationSegment>) -> Self {
206 self.push_segment(segment);
207 self
208 }
209
210 pub fn with_tokens(mut self, tokens: InterpolatedStringTokens) -> Self {
211 self.tokens = Some(tokens);
212 self
213 }
214
215 pub fn get_tokens(&self) -> Option<&InterpolatedStringTokens> {
216 self.tokens.as_ref()
217 }
218
219 pub fn set_tokens(&mut self, tokens: InterpolatedStringTokens) {
220 self.tokens = Some(tokens);
221 }
222
223 super::impl_token_fns!(iter = [tokens, segments]);
224
225 pub fn iter_segments(&self) -> impl Iterator<Item = &InterpolationSegment> {
226 self.segments.iter()
227 }
228
229 pub fn iter_mut_segments(&mut self) -> impl Iterator<Item = &mut InterpolationSegment> {
230 self.segments.iter_mut()
231 }
232
233 #[inline]
234 pub fn len(&self) -> usize {
235 self.segments.len()
236 }
237
238 #[inline]
239 pub fn is_empty(&self) -> bool {
240 self.segments.iter().all(|segment| match segment {
241 InterpolationSegment::String(string_segment) => string_segment.is_empty(),
242 InterpolationSegment::Value(_) => false,
243 })
244 }
245
246 pub fn push_segment(&mut self, segment: impl Into<InterpolationSegment>) {
247 let new_segment = segment.into();
248 match new_segment {
249 InterpolationSegment::String(string_segment) => {
250 if string_segment.get_value().is_empty() {
251 return;
252 }
253 if let Some(InterpolationSegment::String(last)) = self.segments.last_mut() {
254 last.append(string_segment);
255 } else {
256 self.segments.push(string_segment.into());
257 }
258 }
259 InterpolationSegment::Value(_) => {
260 self.segments.push(new_segment);
261 }
262 }
263 }
264}
265
266impl FromIterator<InterpolationSegment> for InterpolatedStringExpression {
267 fn from_iter<T: IntoIterator<Item = InterpolationSegment>>(iter: T) -> Self {
268 Self {
269 segments: iter.into_iter().collect(),
270 tokens: None,
271 }
272 }
273}
274
275#[derive(Clone, Debug, PartialEq, Eq)]
276pub struct InterpolatedStringTokens {
277 pub opening_tick: Token,
278 pub closing_tick: Token,
279}
280
281impl InterpolatedStringTokens {
282 super::impl_token_fns!(target = [opening_tick, closing_tick]);
283}
284
285#[cfg(test)]
286mod test {
287 use super::*;
288
289 #[test]
290 fn push_segment_with_empty_string_does_not_mutate() {
291 let mut string = InterpolatedStringExpression::empty();
292 string.push_segment("");
293
294 pretty_assertions::assert_eq!(string, InterpolatedStringExpression::empty());
295 }
296}