boa_ast/expression/literal/
template.rs1use crate::{
4 Span, Spanned,
5 expression::Expression,
6 visitor::{VisitWith, Visitor, VisitorMut},
7};
8use boa_interner::{Interner, Sym, ToInternedString};
9use core::{fmt::Write as _, ops::ControlFlow};
10
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[derive(Clone, Debug, PartialEq)]
21pub struct TemplateLiteral {
22 elements: Box<[TemplateElement]>,
23 span: Span,
24}
25
26#[cfg(feature = "arbitrary")]
28impl<'a> arbitrary::Arbitrary<'a> for TemplateLiteral {
29 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
30 let len = u.arbitrary_len::<Box<[TemplateElement]>>()?;
31
32 let mut elements = Vec::with_capacity(len);
33 for i in 0..len {
34 if i & 1 == 0 {
35 elements.push(TemplateElement::String(
36 <Sym as arbitrary::Arbitrary>::arbitrary(u)?,
37 ));
38 } else {
39 elements.push(TemplateElement::Expr(Expression::arbitrary(u)?));
40 }
41 }
42
43 Ok(Self::new(elements.into_boxed_slice(), Span::arbitrary(u)?))
44 }
45}
46
47impl From<TemplateLiteral> for Expression {
48 #[inline]
49 fn from(tem: TemplateLiteral) -> Self {
50 Self::TemplateLiteral(tem)
51 }
52}
53
54impl TemplateLiteral {
55 #[inline]
57 #[must_use]
58 pub fn new(elements: Box<[TemplateElement]>, span: Span) -> Self {
59 Self { elements, span }
60 }
61
62 #[must_use]
64 pub const fn elements(&self) -> &[TemplateElement] {
65 &self.elements
66 }
67}
68
69impl Spanned for TemplateLiteral {
70 #[inline]
71 fn span(&self) -> Span {
72 self.span
73 }
74}
75
76impl ToInternedString for TemplateLiteral {
77 #[inline]
78 fn to_interned_string(&self, interner: &Interner) -> String {
79 let mut buf = "`".to_owned();
80
81 for elt in &self.elements {
82 match elt {
83 TemplateElement::String(s) => {
84 let _ = write!(buf, "{}", interner.resolve_expect(*s));
85 }
86 TemplateElement::Expr(n) => {
87 let _ = write!(buf, "${{{}}}", n.to_interned_string(interner));
88 }
89 }
90 }
91 buf.push('`');
92
93 buf
94 }
95}
96
97impl VisitWith for TemplateLiteral {
98 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
99 where
100 V: Visitor<'a>,
101 {
102 for element in &*self.elements {
103 visitor.visit_template_element(element)?;
104 }
105 ControlFlow::Continue(())
106 }
107
108 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
109 where
110 V: VisitorMut<'a>,
111 {
112 for element in &mut *self.elements {
113 visitor.visit_template_element_mut(element)?;
114 }
115 ControlFlow::Continue(())
116 }
117}
118
119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
127#[derive(Clone, Debug, PartialEq)]
128pub enum TemplateElement {
129 String(Sym),
131 Expr(Expression),
133}
134
135impl VisitWith for TemplateElement {
136 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
137 where
138 V: Visitor<'a>,
139 {
140 match self {
141 Self::String(sym) => visitor.visit_sym(sym),
142 Self::Expr(expr) => visitor.visit_expression(expr),
143 }
144 }
145
146 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
147 where
148 V: VisitorMut<'a>,
149 {
150 match self {
151 Self::String(sym) => visitor.visit_sym_mut(sym),
152 Self::Expr(expr) => visitor.visit_expression_mut(expr),
153 }
154 }
155}