vrl/parser/
template_string.rs1use std::fmt;
2
3use crate::diagnostic::Span;
4
5use super::ast::{Expr, Ident, Literal::RawString, Node, Op, Opcode};
6
7#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Hash)]
8pub enum StringSegment {
9 Literal(String, Span),
10 Template(String, Span),
11}
12
13impl fmt::Display for StringSegment {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 StringSegment::Literal(s, _) => write!(f, "{s}"),
17 StringSegment::Template(s, _) => write!(f, "{{{{ {s} }}}}"),
18 }
19 }
20}
21
22#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Hash)]
23pub struct TemplateString(pub Vec<StringSegment>);
24
25impl TemplateString {
26 #[must_use]
28 pub fn rewrite_to_concatenated_strings(&self) -> Expr {
29 self.0
30 .iter()
31 .map(|node| match node {
32 StringSegment::Literal(s, span) => {
33 (*span, Expr::Literal(Node::new(*span, RawString(s.clone()))))
34 }
35 StringSegment::Template(s, span) => {
36 (*span, Expr::Variable(Node::new(*span, Ident::new(s))))
37 }
38 })
39 .reduce(|accum, item| {
40 let (item_span, item) = item;
41 let (accum_span, accum) = accum;
42 let total_span = Span::new(accum_span.start(), item_span.end());
43 (
44 total_span,
45 Expr::Op(Node::new(
46 total_span,
47 Op(
48 Box::new(Node::new(accum_span, accum)),
49 Node::new(item_span, Opcode::Add),
50 Box::new(Node::new(item_span, item)),
51 ),
52 )),
53 )
54 })
55 .map_or_else(
56 || {
57 Expr::Literal(Node::new(
58 crate::diagnostic::Span::default(),
59 RawString(String::new()),
60 ))
61 },
62 |(_span, expr)| expr,
63 )
64 }
65
66 #[must_use]
70 pub fn as_literal_string(&self) -> Option<&str> {
71 match self.0.as_slice() {
72 [StringSegment::Literal(s, _)] => Some(s),
73 _ => None,
74 }
75 }
76}
77
78impl fmt::Display for TemplateString {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 for segment in &self.0 {
81 segment.fmt(f)?;
82 }
83
84 Ok(())
85 }
86}