boa_ast/expression/
tagged_template.rs1use super::Expression;
2use crate::{
3 Span, Spanned,
4 visitor::{VisitWith, Visitor, VisitorMut},
5};
6use boa_interner::{Interner, Sym, ToInternedString};
7use core::{fmt::Write as _, ops::ControlFlow};
8
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
18#[derive(Clone, Debug, PartialEq)]
19pub struct TaggedTemplate {
20 tag: Box<Expression>,
21 raws: Box<[Sym]>,
22 cookeds: Box<[Option<Sym>]>,
23 exprs: Box<[Expression]>,
24 identifier: u64,
25 span: Span,
26}
27
28impl TaggedTemplate {
29 #[inline]
32 #[must_use]
33 pub fn new(
34 tag: Expression,
35 raws: Box<[Sym]>,
36 cookeds: Box<[Option<Sym>]>,
37 exprs: Box<[Expression]>,
38 identifier: u64,
39 span: Span,
40 ) -> Self {
41 Self {
42 tag: tag.into(),
43 raws,
44 cookeds,
45 exprs,
46 identifier,
47 span,
48 }
49 }
50
51 #[inline]
53 #[must_use]
54 pub const fn tag(&self) -> &Expression {
55 &self.tag
56 }
57
58 #[inline]
60 #[must_use]
61 pub const fn raws(&self) -> &[Sym] {
62 &self.raws
63 }
64
65 #[inline]
67 #[must_use]
68 pub const fn cookeds(&self) -> &[Option<Sym>] {
69 &self.cookeds
70 }
71
72 #[inline]
74 #[must_use]
75 pub const fn exprs(&self) -> &[Expression] {
76 &self.exprs
77 }
78
79 #[inline]
81 #[must_use]
82 pub const fn identifier(&self) -> u64 {
83 self.identifier
84 }
85}
86
87impl Spanned for TaggedTemplate {
88 #[inline]
89 fn span(&self) -> Span {
90 self.span
91 }
92}
93
94impl ToInternedString for TaggedTemplate {
95 #[inline]
96 fn to_interned_string(&self, interner: &Interner) -> String {
97 let mut buf = format!("{}`", self.tag.to_interned_string(interner));
98 let mut exprs = self.exprs.iter();
99
100 for raw in &self.raws {
101 let _ = write!(buf, "{}", interner.resolve_expect(*raw));
102 if let Some(expr) = exprs.next() {
103 let _ = write!(buf, "${{{}}}", expr.to_interned_string(interner));
104 }
105 }
106 buf.push('`');
107
108 buf
109 }
110}
111
112impl From<TaggedTemplate> for Expression {
113 #[inline]
114 fn from(template: TaggedTemplate) -> Self {
115 Self::TaggedTemplate(template)
116 }
117}
118
119impl VisitWith for TaggedTemplate {
120 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
121 where
122 V: Visitor<'a>,
123 {
124 visitor.visit_expression(&self.tag)?;
125 for raw in &*self.raws {
126 visitor.visit_sym(raw)?;
127 }
128 for cooked in self.cookeds.iter().flatten() {
129 visitor.visit_sym(cooked)?;
130 }
131 for expr in &*self.exprs {
132 visitor.visit_expression(expr)?;
133 }
134 ControlFlow::Continue(())
135 }
136
137 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
138 where
139 V: VisitorMut<'a>,
140 {
141 visitor.visit_expression_mut(&mut self.tag)?;
142 for raw in &mut *self.raws {
143 visitor.visit_sym_mut(raw)?;
144 }
145 for cooked in self.cookeds.iter_mut().flatten() {
146 visitor.visit_sym_mut(cooked)?;
147 }
148 for expr in &mut *self.exprs {
149 visitor.visit_expression_mut(expr)?;
150 }
151 ControlFlow::Continue(())
152 }
153}