1use typst_library::diag::{At, SourceResult, warning};
2use typst_library::foundations::{
3 Content, Label, NativeElement, Repr, Smart, Symbol, Unlabellable, Value,
4};
5use typst_library::model::{
6 EmphElem, EnumItem, HeadingElem, LinkElem, ListItem, ParbreakElem, RefElem,
7 StrongElem, Supplement, TermItem, Url,
8};
9use typst_library::text::{
10 LinebreakElem, RawContent, RawElem, SmartQuoteElem, SpaceElem, TextElem,
11};
12use typst_syntax::ast::{self, AstNode};
13use typst_utils::PicoStr;
14
15use crate::{Eval, Vm};
16
17impl Eval for ast::Markup<'_> {
18 type Output = Content;
19
20 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
21 eval_markup(vm, &mut self.exprs())
22 }
23}
24
25fn eval_markup<'a>(
27 vm: &mut Vm,
28 exprs: &mut impl Iterator<Item = ast::Expr<'a>>,
29) -> SourceResult<Content> {
30 let flow = vm.flow.take();
31 let mut seq = Vec::with_capacity(exprs.size_hint().1.unwrap_or_default());
32
33 while let Some(expr) = exprs.next() {
34 match expr {
35 ast::Expr::SetRule(set) => {
36 let styles = set.eval(vm)?;
37 if vm.flow.is_some() {
38 break;
39 }
40
41 seq.push(eval_markup(vm, exprs)?.styled_with_map(styles))
42 }
43 ast::Expr::ShowRule(show) => {
44 let recipe = show.eval(vm)?;
45 if vm.flow.is_some() {
46 break;
47 }
48
49 let tail = eval_markup(vm, exprs)?;
50 seq.push(tail.styled_with_recipe(&mut vm.engine, vm.context, recipe)?)
51 }
52 expr => match expr.eval(vm)? {
53 Value::Label(label) => {
54 if let Some(elem) =
55 seq.iter_mut().rev().find(|node| !node.can::<dyn Unlabellable>())
56 {
57 if elem.label().is_some() {
58 vm.engine.sink.warn(warning!(
59 elem.span(), "content labelled multiple times";
60 hint: "only the last label is used, the rest are ignored";
61 ));
62 }
63
64 *elem = std::mem::take(elem).labelled(label);
65 } else {
66 vm.engine.sink.warn(warning!(
67 expr.span(),
68 "label `{}` is not attached to anything",
69 label.repr(),
70 ));
71 }
72 }
73 value => seq.push(value.display().spanned(expr.span())),
74 },
75 }
76
77 if vm.flow.is_some() {
78 break;
79 }
80 }
81
82 if flow.is_some() {
83 vm.flow = flow;
84 }
85
86 Ok(Content::sequence(seq))
87}
88
89impl Eval for ast::Text<'_> {
90 type Output = Content;
91
92 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
93 Ok(TextElem::packed(self.get().clone()))
94 }
95}
96
97impl Eval for ast::Space<'_> {
98 type Output = Content;
99
100 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
101 Ok(SpaceElem::shared().clone())
102 }
103}
104
105impl Eval for ast::Linebreak<'_> {
106 type Output = Content;
107
108 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
109 Ok(LinebreakElem::shared().clone())
110 }
111}
112
113impl Eval for ast::Parbreak<'_> {
114 type Output = Content;
115
116 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
117 Ok(ParbreakElem::shared().clone())
118 }
119}
120
121impl Eval for ast::Escape<'_> {
122 type Output = Value;
123
124 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
125 Ok(Value::Symbol(Symbol::runtime_char(self.get())))
126 }
127}
128
129impl Eval for ast::Shorthand<'_> {
130 type Output = Value;
131
132 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
133 Ok(Value::Symbol(Symbol::runtime_char(self.get())))
134 }
135}
136
137impl Eval for ast::SmartQuote<'_> {
138 type Output = Content;
139
140 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
141 Ok(SmartQuoteElem::new().with_double(self.double()).pack())
142 }
143}
144
145impl Eval for ast::Strong<'_> {
146 type Output = Content;
147
148 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
149 let body = self.body().eval(vm)?;
150 Ok(StrongElem::new(body).pack())
151 }
152}
153
154impl Eval for ast::Emph<'_> {
155 type Output = Content;
156
157 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
158 let body = self.body().eval(vm)?;
159 Ok(EmphElem::new(body).pack())
160 }
161}
162
163impl Eval for ast::Raw<'_> {
164 type Output = Content;
165
166 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
167 let lines = self.lines().map(|line| (line.get().clone(), line.span())).collect();
168 let mut elem = RawElem::new(RawContent::Lines(lines)).with_block(self.block());
169 if let Some(lang) = self.lang() {
170 elem.lang.set(Some(lang.get().clone()));
171 }
172 Ok(elem.pack())
173 }
174}
175
176impl Eval for ast::Link<'_> {
177 type Output = Content;
178
179 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
180 let url = Url::new(self.get().clone()).at(self.span())?;
181 Ok(LinkElem::from_url(url).pack())
182 }
183}
184
185impl Eval for ast::Label<'_> {
186 type Output = Value;
187
188 fn eval(self, _: &mut Vm) -> SourceResult<Self::Output> {
189 Ok(Value::Label(
190 Label::new(PicoStr::intern(self.get())).expect("unexpected empty label"),
191 ))
192 }
193}
194
195impl Eval for ast::Ref<'_> {
196 type Output = Content;
197
198 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
199 let target = Label::new(PicoStr::intern(self.target()))
200 .expect("unexpected empty reference");
201 let mut elem = RefElem::new(target);
202 if let Some(supplement) = self.supplement() {
203 elem.supplement
204 .set(Smart::Custom(Some(Supplement::Content(supplement.eval(vm)?))));
205 }
206 Ok(elem.pack())
207 }
208}
209
210impl Eval for ast::Heading<'_> {
211 type Output = Content;
212
213 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
214 let depth = self.depth();
215 let body = self.body().eval(vm)?;
216 Ok(HeadingElem::new(body).with_depth(depth).pack())
217 }
218}
219
220impl Eval for ast::ListItem<'_> {
221 type Output = Content;
222
223 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
224 Ok(ListItem::new(self.body().eval(vm)?).pack())
225 }
226}
227
228impl Eval for ast::EnumItem<'_> {
229 type Output = Content;
230
231 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
232 let body = self.body().eval(vm)?;
233 let mut elem = EnumItem::new(body);
234 if let Some(number) = self.number() {
235 elem.number.set(Smart::Custom(number));
236 }
237 Ok(elem.pack())
238 }
239}
240
241impl Eval for ast::TermItem<'_> {
242 type Output = Content;
243
244 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
245 let term = self.term().eval(vm)?;
246 let description = self.description().eval(vm)?;
247 Ok(TermItem::new(term, description).pack())
248 }
249}