1use std::ops::DerefMut;
2
3use parking_lot::Mutex;
4use rpds::RedBlackTreeMapSync;
5use rustc_hash::FxHashMap;
6use std::ops::Deref;
7use tinymist_analysis::adt::interner::Interned;
8use tinymist_std::hash::hash128;
9use typst::{
10 foundations::{Element, NativeElement, Type, Value},
11 model::{EmphElem, EnumElem, HeadingElem, ListElem, ParbreakElem, StrongElem, TermsElem},
12 syntax::{Span, SyntaxNode, ast::MathTextKind},
13 text::LinebreakElem,
14 utils::LazyHash,
15};
16
17use crate::{
18 analysis::{QueryStatGuard, SharedContext},
19 docs::DocString,
20 prelude::*,
21 syntax::{DefKind, find_module_level_docs, resolve_id_by_path},
22 ty::{BuiltinTy, InsTy, Ty},
23};
24
25use super::{DocCommentMatcher, InterpretMode, def::*};
26
27pub type ExprRoute = FxHashMap<TypstFileId, Option<Arc<LazyHash<LexicalScope>>>>;
30
31#[typst_macros::time(span = source.root().span())]
45pub(crate) fn expr_of(
46 ctx: Arc<SharedContext>,
47 source: Source,
48 route: &mut ExprRoute,
49 guard: QueryStatGuard,
50 prev: Option<ExprInfo>,
51) -> ExprInfo {
52 crate::log_debug_ct!("expr_of: {:?}", source.id());
53
54 route.insert(source.id(), None);
55
56 let cache_hit = prev.and_then(|prev| {
57 if prev.source.lines().len_bytes() != source.lines().len_bytes()
58 || hash128(&prev.source) != hash128(&source)
59 {
60 return None;
61 }
62 for (fid, prev_exports) in &prev.imports {
63 let ei = ctx.exports_of(&ctx.source_by_id(*fid).ok()?, route);
64
65 if let Some(exports) = ei
68 && (prev_exports.size() != exports.size()
69 || hash128(&prev_exports) != hash128(&exports))
70 {
71 return None;
72 }
73 }
74
75 Some(prev)
76 });
77
78 if let Some(prev) = cache_hit {
79 route.remove(&source.id());
80 return prev;
81 }
82 guard.miss();
83
84 let revision = ctx.revision();
85
86 let resolves_base = Arc::new(Mutex::new(vec![]));
87 let resolves = resolves_base.clone();
88
89 let docstrings_base = Arc::new(Mutex::new(FxHashMap::default()));
91 let docstrings = docstrings_base.clone();
92
93 let exprs_base = Arc::new(Mutex::new(FxHashMap::default()));
94 let exprs = exprs_base.clone();
95
96 let imports_base = Arc::new(Mutex::new(FxHashMap::default()));
97 let imports = imports_base.clone();
98
99 let module_docstring = find_module_level_docs(&source)
100 .and_then(|docs| ctx.compute_docstring(source.id(), docs, DefKind::Module))
101 .unwrap_or_default();
102
103 let (exports, root) = {
104 let mut w = ExprWorker {
105 fid: source.id(),
106 ctx,
107 imports,
108 docstrings,
109 exprs,
110 import_buffer: Vec::new(),
111 lexical: LexicalContext::default(),
112 resolves,
113 buffer: vec![],
114 init_stage: true,
115 comment_matcher: DocCommentMatcher::default(),
116 route,
117 };
118
119 let root = source.root().cast::<ast::Markup>().unwrap();
121 w.check_root_scope(root.to_untyped().children());
122 let root_scope = Arc::new(LazyHash::new(w.summarize_scope()));
123 w.route.insert(w.fid, Some(root_scope.clone()));
124
125 w.lexical = LexicalContext::default();
127 w.comment_matcher.reset();
128 w.buffer.clear();
129 w.import_buffer.clear();
130 let root = w.check_in_mode(root.to_untyped().children(), InterpretMode::Markup);
131 let root_scope = Arc::new(LazyHash::new(w.summarize_scope()));
132
133 w.collect_buffer();
134 (root_scope, root)
135 };
136
137 let info = ExprInfoRepr {
138 fid: source.id(),
139 revision,
140 source: source.clone(),
141 resolves: HashMap::from_iter(std::mem::take(resolves_base.lock().deref_mut())),
142 module_docstring,
143 docstrings: std::mem::take(docstrings_base.lock().deref_mut()),
144 imports: HashMap::from_iter(std::mem::take(imports_base.lock().deref_mut())),
145 exports,
146 exprs: std::mem::take(exprs_base.lock().deref_mut()),
147 root,
148 };
149 crate::log_debug_ct!("expr_of end {:?}", source.id());
150
151 route.remove(&info.fid);
152 ExprInfo::new(info)
153}
154
155type ConcolicExpr = (Option<Expr>, Option<Ty>);
156type ResolveVec = Vec<(Span, Interned<RefExpr>)>;
157type SyntaxNodeChildren<'a> = std::slice::Iter<'a, SyntaxNode>;
158
159#[derive(Debug, Clone)]
160struct LexicalContext {
161 mode: InterpretMode,
162 scopes: EcoVec<ExprScope>,
163 last: ExprScope,
164}
165
166impl Default for LexicalContext {
167 fn default() -> Self {
168 LexicalContext {
169 mode: InterpretMode::Markup,
170 scopes: eco_vec![],
171 last: ExprScope::Lexical(RedBlackTreeMapSync::default()),
172 }
173 }
174}
175
176pub(crate) struct ExprWorker<'a> {
178 fid: TypstFileId,
179 ctx: Arc<SharedContext>,
180 imports: Arc<Mutex<FxHashMap<TypstFileId, Arc<LazyHash<LexicalScope>>>>>,
181 import_buffer: Vec<(TypstFileId, Arc<LazyHash<LexicalScope>>)>,
182 docstrings: Arc<Mutex<FxHashMap<DeclExpr, Arc<DocString>>>>,
183 exprs: Arc<Mutex<FxHashMap<Span, Expr>>>,
184 resolves: Arc<Mutex<ResolveVec>>,
185 buffer: ResolveVec,
186 lexical: LexicalContext,
187 init_stage: bool,
188
189 route: &'a mut ExprRoute,
190 comment_matcher: DocCommentMatcher,
191}
192
193impl ExprWorker<'_> {
194 fn with_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
195 self.lexical.scopes.push(std::mem::replace(
196 &mut self.lexical.last,
197 ExprScope::empty(),
198 ));
199 let len = self.lexical.scopes.len();
200 let result = f(self);
201 self.lexical.scopes.truncate(len);
202 self.lexical.last = self.lexical.scopes.pop().unwrap();
203 result
204 }
205
206 fn push_scope(&mut self, scope: ExprScope) {
207 let last = std::mem::replace(&mut self.lexical.last, scope);
208 if !last.is_empty() {
209 self.lexical.scopes.push(last);
210 }
211 }
212
213 #[must_use]
214 fn scope_mut(&mut self) -> &mut LexicalScope {
215 if matches!(self.lexical.last, ExprScope::Lexical(_)) {
216 return self.lexical_scope_unchecked();
217 }
218 self.lexical.scopes.push(std::mem::replace(
219 &mut self.lexical.last,
220 ExprScope::empty(),
221 ));
222 self.lexical_scope_unchecked()
223 }
224
225 fn lexical_scope_unchecked(&mut self) -> &mut LexicalScope {
226 let scope = &mut self.lexical.last;
227 if let ExprScope::Lexical(scope) = scope {
228 scope
229 } else {
230 unreachable!()
231 }
232 }
233
234 fn check_docstring(&mut self, decl: &DeclExpr, docs: Option<String>, kind: DefKind) {
235 if let Some(docs) = docs {
236 let docstring = self.ctx.compute_docstring(self.fid, docs, kind);
237 if let Some(docstring) = docstring {
238 self.docstrings.lock().insert(decl.clone(), docstring);
239 }
240 }
241 }
242
243 fn summarize_scope(&self) -> LexicalScope {
244 let mut exports = LexicalScope::default();
245 for scope in self
246 .lexical
247 .scopes
248 .iter()
249 .chain(std::iter::once(&self.lexical.last))
250 {
251 scope.merge_into(&mut exports);
252 }
253 exports
254 }
255
256 fn check(&mut self, m: ast::Expr) -> Expr {
257 let s = m.span();
258 let ret = self.do_check(m);
259 self.exprs.lock().insert(s, ret.clone());
260 ret
261 }
262
263 fn do_check(&mut self, m: ast::Expr) -> Expr {
264 use ast::Expr::*;
265 match m {
266 None(_) => Expr::Type(Ty::Builtin(BuiltinTy::None)),
267 Auto(..) => Expr::Type(Ty::Builtin(BuiltinTy::Auto)),
268 Bool(bool) => Expr::Type(Ty::Value(InsTy::new(Value::Bool(bool.get())))),
269 Int(int) => Expr::Type(Ty::Value(InsTy::new(Value::Int(int.get())))),
270 Float(float) => Expr::Type(Ty::Value(InsTy::new(Value::Float(float.get())))),
271 Numeric(numeric) => Expr::Type(Ty::Value(InsTy::new(Value::numeric(numeric.get())))),
272 Str(s) => Expr::Type(Ty::Value(InsTy::new(Value::Str(s.get().into())))),
273
274 Equation(equation) => self.check_math(equation.body().to_untyped().children()),
275 Math(math) => self.check_math(math.to_untyped().children()),
276 CodeBlock(code_block) => self.check_code(code_block.body()),
277 ContentBlock(content_block) => self.check_markup(content_block.body()),
278
279 Ident(ident) => self.check_ident(ident),
280 MathIdent(math_ident) => self.check_math_ident(math_ident),
281 Label(label) => self.check_label(label),
282 Ref(ref_node) => self.check_ref(ref_node),
283
284 LetBinding(let_binding) => self.check_let(let_binding),
285 Closure(closure) => self.check_closure(closure),
286 ModuleImport(module_import) => self.check_module_import(module_import),
287 ModuleInclude(module_include) => self.check_module_include(module_include),
288
289 Parenthesized(paren_expr) => self.check(paren_expr.expr()),
290 Array(array) => self.check_array(array),
291 Dict(dict) => self.check_dict(dict),
292 Unary(unary) => self.check_unary(unary),
293 Binary(binary) => self.check_binary(binary),
294 FieldAccess(field_access) => self.check_field_access(field_access),
295 FuncCall(func_call) => self.check_func_call(func_call),
296 DestructAssignment(destruct_assignment) => {
297 self.check_destruct_assign(destruct_assignment)
298 }
299 SetRule(set_rule) => self.check_set(set_rule),
300 ShowRule(show_rule) => self.check_show(show_rule),
301 Contextual(contextual) => {
302 Expr::Unary(UnInst::new(UnaryOp::Context, self.defer(contextual.body())))
303 }
304 Conditional(conditional) => self.check_conditional(conditional),
305 WhileLoop(while_loop) => self.check_while_loop(while_loop),
306 ForLoop(for_loop) => self.check_for_loop(for_loop),
307 LoopBreak(..) => Expr::Type(Ty::Builtin(BuiltinTy::Break)),
308 LoopContinue(..) => Expr::Type(Ty::Builtin(BuiltinTy::Continue)),
309 FuncReturn(func_return) => Expr::Unary(UnInst::new(
310 UnaryOp::Return,
311 func_return
312 .body()
313 .map_or_else(none_expr, |body| self.check(body)),
314 )),
315
316 Text(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
317 typst::text::TextElem,
318 >())))),
319 MathText(t) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some({
320 match t.get() {
321 MathTextKind::Character(..) => Element::of::<typst::foundations::SymbolElem>(),
322 MathTextKind::Number(..) => Element::of::<typst::foundations::SymbolElem>(),
323 }
324 })))),
325 Raw(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
326 typst::text::RawElem,
327 >())))),
328 Link(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
329 typst::model::LinkElem,
330 >())))),
331 Space(..) => Expr::Type(Ty::Builtin(BuiltinTy::Space)),
332 Linebreak(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
333 LinebreakElem,
334 >())))),
335 Parbreak(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
336 ParbreakElem,
337 >())))),
338 Escape(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
339 typst::text::TextElem,
340 >())))),
341 Shorthand(..) => Expr::Type(Ty::Builtin(BuiltinTy::Type(Type::of::<
342 typst::foundations::Symbol,
343 >()))),
344 SmartQuote(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
345 typst::text::SmartQuoteElem,
346 >())))),
347
348 Strong(strong) => {
349 let body = self.check_inline_markup(strong.body());
350 self.check_element::<StrongElem>(eco_vec![body])
351 }
352 Emph(emph) => {
353 let body = self.check_inline_markup(emph.body());
354 self.check_element::<EmphElem>(eco_vec![body])
355 }
356 Heading(heading) => {
357 let body = self.check_markup(heading.body());
358 self.check_element::<HeadingElem>(eco_vec![body])
359 }
360 ListItem(item) => {
361 let body = self.check_markup(item.body());
362 self.check_element::<ListElem>(eco_vec![body])
363 }
364 EnumItem(item) => {
365 let body = self.check_markup(item.body());
366 self.check_element::<EnumElem>(eco_vec![body])
367 }
368 TermItem(item) => {
369 let term = self.check_markup(item.term());
370 let description = self.check_markup(item.description());
371 self.check_element::<TermsElem>(eco_vec![term, description])
372 }
373
374 MathAlignPoint(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
375 typst::math::AlignPointElem,
376 >(
377 ))))),
378 MathShorthand(..) => Expr::Type(Ty::Builtin(BuiltinTy::Type(Type::of::<
379 typst::foundations::Symbol,
380 >()))),
381 MathDelimited(math_delimited) => {
382 self.check_math(math_delimited.body().to_untyped().children())
383 }
384 MathAttach(attach) => {
385 let base = attach.base().to_untyped().clone();
386 let bottom = attach.bottom().unwrap_or_default().to_untyped().clone();
387 let top = attach.top().unwrap_or_default().to_untyped().clone();
388 self.check_math([base, bottom, top].iter())
389 }
390 MathPrimes(..) => Expr::Type(Ty::Builtin(BuiltinTy::None)),
391 MathFrac(frac) => {
392 let num = frac.num().to_untyped().clone();
393 let denom = frac.denom().to_untyped().clone();
394 self.check_math([num, denom].iter())
395 }
396 MathRoot(root) => self.check(root.radicand()),
397 }
398 }
399
400 fn check_label(&mut self, label: ast::Label) -> Expr {
401 Expr::Decl(Decl::label(label.get(), label.span()).into())
402 }
403
404 fn check_element<T: NativeElement>(&mut self, content: EcoVec<Expr>) -> Expr {
405 let elem = Element::of::<T>();
406 Expr::Element(ElementExpr { elem, content }.into())
407 }
408
409 fn check_let(&mut self, typed: ast::LetBinding) -> Expr {
410 match typed.kind() {
411 ast::LetBindingKind::Closure(..) => {
412 typed.init().map_or_else(none_expr, |expr| self.check(expr))
413 }
414 ast::LetBindingKind::Normal(pat) => {
415 let docs = self.comment_matcher.collect();
416 let body = typed.init().map(|init| self.defer(init));
418
419 let span = pat.span();
420 let decl = Decl::pattern(span).into();
421 self.check_docstring(&decl, docs, DefKind::Variable);
422 let pattern = self.check_pattern(pat);
423 Expr::Let(Interned::new(LetExpr {
424 span,
425 pattern,
426 body,
427 }))
428 }
429 }
430 }
431
432 fn check_closure(&mut self, typed: ast::Closure) -> Expr {
433 let docs = self.comment_matcher.collect();
434 let decl = match typed.name() {
435 Some(name) => Decl::func(name).into(),
436 None => Decl::closure(typed.span()).into(),
437 };
438 self.check_docstring(&decl, docs, DefKind::Function);
439 self.resolve_as(Decl::as_def(&decl, None));
440
441 let (params, body) = self.with_scope(|this| {
442 this.scope_mut()
443 .insert_mut(decl.name().clone(), decl.clone().into());
444 let mut inputs = eco_vec![];
445 let mut names = eco_vec![];
446 let mut spread_left = None;
447 let mut spread_right = None;
448 for arg in typed.params().children() {
449 match arg {
450 ast::Param::Pos(arg) => {
451 inputs.push(this.check_pattern(arg));
452 }
453 ast::Param::Named(arg) => {
454 let key: DeclExpr = Decl::var(arg.name()).into();
455 let val = Pattern::Expr(this.check(arg.expr())).into();
456 names.push((key.clone(), val));
457
458 this.resolve_as(Decl::as_def(&key, None));
459 this.scope_mut().insert_mut(key.name().clone(), key.into());
460 }
461 ast::Param::Spread(s) => {
462 let decl: DeclExpr = if let Some(ident) = s.sink_ident() {
463 Decl::var(ident).into()
464 } else {
465 Decl::spread(s.span()).into()
466 };
467
468 let spread = Pattern::Expr(this.check(s.expr())).into();
469 if inputs.is_empty() {
470 spread_left = Some((decl.clone(), spread));
471 } else {
472 spread_right = Some((decl.clone(), spread));
473 }
474
475 this.resolve_as(Decl::as_def(&decl, None));
476 this.scope_mut()
477 .insert_mut(decl.name().clone(), decl.into());
478 }
479 }
480 }
481
482 if inputs.is_empty() {
483 spread_right = spread_left.take();
484 }
485
486 let pattern = PatternSig {
487 pos: inputs,
488 named: names,
489 spread_left,
490 spread_right,
491 };
492
493 (pattern, this.defer(typed.body()))
494 });
495
496 self.scope_mut()
497 .insert_mut(decl.name().clone(), decl.clone().into());
498 Expr::Func(FuncExpr { decl, params, body }.into())
499 }
500
501 fn check_pattern(&mut self, typed: ast::Pattern) -> Interned<Pattern> {
502 match typed {
503 ast::Pattern::Normal(expr) => self.check_pattern_expr(expr),
504 ast::Pattern::Placeholder(..) => Pattern::Expr(Expr::Star).into(),
505 ast::Pattern::Parenthesized(paren_expr) => self.check_pattern(paren_expr.pattern()),
506 ast::Pattern::Destructuring(destructing) => {
507 let mut inputs = eco_vec![];
508 let mut names = eco_vec![];
509 let mut spread_left = None;
510 let mut spread_right = None;
511
512 for item in destructing.items() {
513 match item {
514 ast::DestructuringItem::Pattern(pos) => {
515 inputs.push(self.check_pattern(pos));
516 }
517 ast::DestructuringItem::Named(named) => {
518 let key = Decl::var(named.name()).into();
519 let val = self.check_pattern_expr(named.expr());
520 names.push((key, val));
521 }
522 ast::DestructuringItem::Spread(spreading) => {
523 let decl: DeclExpr = if let Some(ident) = spreading.sink_ident() {
524 Decl::var(ident).into()
525 } else {
526 Decl::spread(spreading.span()).into()
527 };
528
529 if inputs.is_empty() {
530 spread_left =
531 Some((decl, self.check_pattern_expr(spreading.expr())));
532 } else {
533 spread_right =
534 Some((decl, self.check_pattern_expr(spreading.expr())));
535 }
536 }
537 }
538 }
539
540 if inputs.is_empty() {
541 spread_right = spread_left.take();
542 }
543
544 let pattern = PatternSig {
545 pos: inputs,
546 named: names,
547 spread_left,
548 spread_right,
549 };
550
551 Pattern::Sig(Box::new(pattern)).into()
552 }
553 }
554 }
555
556 fn check_pattern_expr(&mut self, typed: ast::Expr) -> Interned<Pattern> {
557 match typed {
558 ast::Expr::Ident(ident) => {
559 let decl = Decl::var(ident).into();
560 self.resolve_as(Decl::as_def(&decl, None));
561 self.scope_mut()
562 .insert_mut(decl.name().clone(), decl.clone().into());
563 Pattern::Simple(decl).into()
564 }
565 ast::Expr::Parenthesized(parenthesized) => self.check_pattern(parenthesized.pattern()),
566 _ => Pattern::Expr(self.check(typed)).into(),
567 }
568 }
569
570 fn check_module_import(&mut self, typed: ast::ModuleImport) -> Expr {
571 let is_wildcard_import = matches!(typed.imports(), Some(ast::Imports::Wildcard));
572
573 let source = typed.source();
574 let mod_expr = self.check_import(typed.source(), true, is_wildcard_import);
575 crate::log_debug_ct!("checking import: {source:?} => {mod_expr:?}");
576
577 let mod_var = typed.new_name().map(Decl::module_alias).or_else(|| {
578 typed.imports().is_none().then(|| {
579 let name = match mod_expr.as_ref()? {
580 Expr::Decl(decl) if matches!(decl.as_ref(), Decl::Module { .. }) => {
581 decl.name().clone()
582 }
583 _ => return None,
584 };
585 Some(Decl::path_stem(source.to_untyped().clone(), name))
587 })?
588 });
589
590 let creating_mod_var = mod_var.is_some();
591 let mod_var = Interned::new(mod_var.unwrap_or_else(|| Decl::module_import(typed.span())));
592
593 let mod_ref = RefExpr {
598 decl: mod_var.clone(),
599 step: mod_expr.clone(),
600 root: mod_expr.clone(),
601 term: None,
602 };
603 crate::log_debug_ct!("create import variable: {mod_ref:?}");
604 let mod_ref = Interned::new(mod_ref);
605 if creating_mod_var {
606 self.scope_mut()
607 .insert_mut(mod_var.name().clone(), Expr::Ref(mod_ref.clone()));
608 }
609
610 self.resolve_as(mod_ref.clone());
611
612 let fid = mod_expr.as_ref().and_then(|mod_expr| match mod_expr {
613 Expr::Type(Ty::Value(v)) => match &v.val {
614 Value::Module(m) => m.file_id(),
615 _ => None,
616 },
617 Expr::Decl(decl) => {
618 if matches!(decl.as_ref(), Decl::Module { .. }) {
619 decl.file_id()
620 } else {
621 None
622 }
623 }
624 _ => None,
625 });
626
627 if let Some(fid) = fid {
629 crate::log_debug_ct!("prefetch type check: {fid:?}");
630 self.ctx.prefetch_type_check(fid);
631 }
632
633 let scope = if let Some(fid) = &fid {
634 Some(ExprScope::Lexical(self.exports_of(*fid)))
635 } else {
636 match &mod_expr {
637 Some(Expr::Type(Ty::Value(v))) => match &v.val {
638 Value::Module(m) => Some(ExprScope::Module(m.clone())),
639 Value::Func(func) => {
640 if func.scope().is_some() {
641 Some(ExprScope::Func(func.clone()))
642 } else {
643 None
644 }
645 }
646 Value::Type(s) => Some(ExprScope::Type(*s)),
647 _ => None,
648 },
649 _ => None,
650 }
651 };
652
653 let scope = if let Some(scope) = scope {
654 scope
655 } else {
656 log::warn!(
657 "cannot analyze import on: {typed:?}, expr {mod_expr:?}, in file {:?}",
658 typed.span().id()
659 );
660 ExprScope::empty()
661 };
662
663 if let Some(imports) = typed.imports() {
664 match imports {
665 ast::Imports::Wildcard => {
666 crate::log_debug_ct!("checking wildcard: {mod_expr:?}");
667 self.push_scope(scope);
668 }
669 ast::Imports::Items(items) => {
670 let module = Expr::Decl(mod_var.clone());
671 self.import_decls(&scope, module, items);
672 }
673 }
674 };
675
676 Expr::Import(ImportExpr { decl: mod_ref }.into())
677 }
678
679 fn check_import(
680 &mut self,
681 source: ast::Expr,
682 is_import: bool,
683 is_wildcard_import: bool,
684 ) -> Option<Expr> {
685 let src = self.eval_expr(source, InterpretMode::Code);
686 let src_expr = self.fold_expr_and_val(src).or_else(|| {
687 self.ctx
688 .analyze_expr(source.to_untyped())
689 .into_iter()
690 .find_map(|(v, _)| match v {
691 Value::Str(s) => Some(Expr::Type(Ty::Value(InsTy::new(Value::Str(s))))),
692 _ => None,
693 })
694 })?;
695
696 crate::log_debug_ct!("checking import source: {src_expr:?}");
697 let const_res = match &src_expr {
698 Expr::Type(Ty::Value(val)) => {
699 self.check_import_source_val(source, &val.val, Some(&src_expr), is_import)
700 }
701 Expr::Decl(decl) if matches!(decl.as_ref(), Decl::Module { .. }) => {
702 return Some(src_expr.clone());
703 }
704
705 _ => None,
706 };
707 const_res
708 .or_else(|| self.check_import_by_def(&src_expr))
709 .or_else(|| is_wildcard_import.then(|| self.check_import_dyn(source, &src_expr))?)
710 }
711
712 fn check_import_dyn(&mut self, source: ast::Expr, src_expr: &Expr) -> Option<Expr> {
713 let src_or_module = self.ctx.analyze_import(source.to_untyped());
714 crate::log_debug_ct!("checking import source dyn: {src_or_module:?}");
715
716 match src_or_module {
717 (_, Some(Value::Module(m))) => {
718 match m.file_id() {
720 Some(fid) => Some(Expr::Decl(
721 Decl::module_with_name(m.name().unwrap().into(), fid).into(),
722 )),
723 None => Some(Expr::Type(Ty::Value(InsTy::new(Value::Module(m))))),
724 }
725 }
726 (_, Some(v)) => Some(Expr::Type(Ty::Value(InsTy::new(v)))),
727 (Some(s), _) => self.check_import_source_val(source, &s, Some(src_expr), true),
728 (None, None) => None,
729 }
730 }
731
732 fn check_import_source_val(
733 &mut self,
734 source: ast::Expr,
735 src: &Value,
736 src_expr: Option<&Expr>,
737 is_import: bool,
738 ) -> Option<Expr> {
739 match &src {
740 _ if src.scope().is_some() => src_expr
741 .cloned()
742 .or_else(|| Some(Expr::Type(Ty::Value(InsTy::new(src.clone()))))),
743 Value::Str(s) => self.check_import_by_str(source, s.as_str(), is_import),
744 _ => None,
745 }
746 }
747
748 fn check_import_by_str(
749 &mut self,
750 source: ast::Expr,
751 src: &str,
752 is_import: bool,
753 ) -> Option<Expr> {
754 let fid = resolve_id_by_path(&self.ctx.world, self.fid, src)?;
755 let name = Decl::calc_path_stem(src);
756 let module = Expr::Decl(Decl::module_with_name(name.clone(), fid).into());
757
758 let import_path = if is_import {
759 Decl::import_path(source.span(), name)
760 } else {
761 Decl::include_path(source.span(), name)
762 };
763
764 let ref_expr = RefExpr {
769 decl: import_path.into(),
770 step: Some(module.clone()),
771 root: Some(module.clone()),
772 term: None,
773 };
774 self.resolve_as(ref_expr.into());
775 Some(module)
776 }
777
778 fn check_import_by_def(&mut self, src_expr: &Expr) -> Option<Expr> {
779 match src_expr {
780 Expr::Decl(m) if matches!(m.kind(), DefKind::Module) => Some(src_expr.clone()),
781 Expr::Ref(r) => r.root.clone(),
782 _ => None,
783 }
784 }
785
786 fn import_decls(&mut self, scope: &ExprScope, module: Expr, items: ast::ImportItems) {
787 crate::log_debug_ct!("import scope {scope:?}");
788
789 for item in items.iter() {
790 let (path_ast, old, rename) = match item {
791 ast::ImportItem::Simple(path) => {
792 let old: DeclExpr = Decl::import(path.name()).into();
793 (path, old, None)
794 }
795 ast::ImportItem::Renamed(renamed) => {
796 let path = renamed.path();
797 let old: DeclExpr = Decl::import(path.name()).into();
798 let new: DeclExpr = Decl::import_alias(renamed.new_name()).into();
799 (path, old, Some(new))
800 }
801 };
802
803 let mut path = Vec::with_capacity(1);
804 for seg in path_ast.iter() {
805 let seg = Interned::new(Decl::ident_ref(seg));
806 path.push(seg);
807 }
808 let (mut root, val) = match path.last().map(|decl| decl.name()) {
810 Some(name) => scope.get(name),
811 None => (None, None),
812 };
813
814 crate::log_debug_ct!("path {path:?} -> {root:?} {val:?}");
815 if root.is_none() && val.is_none() {
816 let mut sel = module.clone();
817 for seg in path.into_iter() {
818 sel = Expr::Select(SelectExpr::new(seg, sel));
819 }
820 root = Some(sel)
821 }
822
823 let (root, step) = extract_ref(root);
824
825 let mut ref_expr = Interned::new(RefExpr {
831 decl: old.clone(),
832 root,
833 step,
834 term: val,
835 });
836 self.resolve_as(ref_expr.clone());
837
838 if let Some(new) = &rename {
841 ref_expr = Interned::new(RefExpr {
846 decl: new.clone(),
847 root: ref_expr.root.clone(),
848 step: Some(ref_expr.decl.clone().into()),
849 term: ref_expr.term.clone(),
850 });
851 self.resolve_as(ref_expr.clone());
852 }
853
854 let name = rename.as_ref().unwrap_or(&old).name().clone();
856 let expr = Expr::Ref(ref_expr);
857 self.scope_mut().insert_mut(name, expr.clone());
858 }
859 }
860
861 fn check_module_include(&mut self, typed: ast::ModuleInclude) -> Expr {
862 let _mod_expr = self.check_import(typed.source(), false, false);
863 let source = self.check(typed.source());
864 Expr::Include(IncludeExpr { source }.into())
865 }
866
867 fn check_array(&mut self, typed: ast::Array) -> Expr {
868 let mut items = vec![];
869 for item in typed.items() {
870 match item {
871 ast::ArrayItem::Pos(item) => {
872 items.push(ArgExpr::Pos(self.check(item)));
873 }
874 ast::ArrayItem::Spread(s) => {
875 items.push(ArgExpr::Spread(self.check(s.expr())));
876 }
877 }
878 }
879
880 Expr::Array(ArgsExpr::new(typed.span(), items))
881 }
882
883 fn check_dict(&mut self, typed: ast::Dict) -> Expr {
884 let mut items = vec![];
885 for item in typed.items() {
886 match item {
887 ast::DictItem::Named(item) => {
888 let key = Decl::ident_ref(item.name()).into();
889 let val = self.check(item.expr());
890 items.push(ArgExpr::Named(Box::new((key, val))));
891 }
892 ast::DictItem::Keyed(item) => {
893 let val = self.check(item.expr());
894 let key = item.key();
895 let analyzed = self.const_eval_expr(key);
896 let analyzed = match &analyzed {
897 Some(Value::Str(s)) => Some(s),
898 _ => None,
899 };
900 let Some(analyzed) = analyzed else {
901 let key = self.check(key);
902 items.push(ArgExpr::NamedRt(Box::new((key, val))));
903 continue;
904 };
905 let key = Decl::str_name(key.to_untyped().clone(), analyzed).into();
906 items.push(ArgExpr::Named(Box::new((key, val))));
907 }
908 ast::DictItem::Spread(s) => {
909 items.push(ArgExpr::Spread(self.check(s.expr())));
910 }
911 }
912 }
913
914 Expr::Dict(ArgsExpr::new(typed.span(), items))
915 }
916
917 fn check_args(&mut self, typed: ast::Args) -> Expr {
918 let mut args = vec![];
919 for arg in typed.items() {
920 match arg {
921 ast::Arg::Pos(arg) => {
922 args.push(ArgExpr::Pos(self.check(arg)));
923 }
924 ast::Arg::Named(arg) => {
925 let key = Decl::ident_ref(arg.name()).into();
926 let val = self.check(arg.expr());
927 args.push(ArgExpr::Named(Box::new((key, val))));
928 }
929 ast::Arg::Spread(s) => {
930 args.push(ArgExpr::Spread(self.check(s.expr())));
931 }
932 }
933 }
934 Expr::Args(ArgsExpr::new(typed.span(), args))
935 }
936
937 fn check_unary(&mut self, typed: ast::Unary) -> Expr {
938 let op = match typed.op() {
939 ast::UnOp::Pos => UnaryOp::Pos,
940 ast::UnOp::Neg => UnaryOp::Neg,
941 ast::UnOp::Not => UnaryOp::Not,
942 };
943 let lhs = self.check(typed.expr());
944 Expr::Unary(UnInst::new(op, lhs))
945 }
946
947 fn check_binary(&mut self, typed: ast::Binary) -> Expr {
948 let lhs = self.check(typed.lhs());
949 let rhs = self.check(typed.rhs());
950 Expr::Binary(BinInst::new(typed.op(), lhs, rhs))
951 }
952
953 fn check_destruct_assign(&mut self, typed: ast::DestructAssignment) -> Expr {
954 let pat = Expr::Pattern(self.check_pattern(typed.pattern()));
955 let val = self.check(typed.value());
956 let inst = BinInst::new(ast::BinOp::Assign, pat, val);
957 Expr::Binary(inst)
958 }
959
960 fn check_field_access(&mut self, typed: ast::FieldAccess) -> Expr {
961 let lhs = self.check(typed.target());
962 let key = Decl::ident_ref(typed.field()).into();
963 let span = typed.span();
964 Expr::Select(SelectExpr { lhs, key, span }.into())
965 }
966
967 fn check_func_call(&mut self, typed: ast::FuncCall) -> Expr {
968 let callee = self.check(typed.callee());
969 let args = self.check_args(typed.args());
970 let span = typed.span();
971 Expr::Apply(ApplyExpr { callee, args, span }.into())
972 }
973
974 fn check_set(&mut self, typed: ast::SetRule) -> Expr {
975 let target = self.check(typed.target());
976 let args = self.check_args(typed.args());
977 let cond = typed.condition().map(|cond| self.check(cond));
978 Expr::Set(SetExpr { target, args, cond }.into())
979 }
980
981 fn check_show(&mut self, typed: ast::ShowRule) -> Expr {
982 let selector = typed.selector().map(|selector| self.check(selector));
983 let edit = self.defer(typed.transform());
984 Expr::Show(ShowExpr { selector, edit }.into())
985 }
986
987 fn check_conditional(&mut self, typed: ast::Conditional) -> Expr {
988 let cond = self.check(typed.condition());
989 let then = self.defer(typed.if_body());
990 let else_ = typed
991 .else_body()
992 .map_or_else(none_expr, |expr| self.defer(expr));
993 Expr::Conditional(IfExpr { cond, then, else_ }.into())
994 }
995
996 fn check_while_loop(&mut self, typed: ast::WhileLoop) -> Expr {
997 let cond = self.check(typed.condition());
998 let body = self.defer(typed.body());
999 Expr::WhileLoop(WhileExpr { cond, body }.into())
1000 }
1001
1002 fn check_for_loop(&mut self, typed: ast::ForLoop) -> Expr {
1003 self.with_scope(|this| {
1004 let pattern = this.check_pattern(typed.pattern());
1005 let iter = this.check(typed.iterable());
1006 let body = this.defer(typed.body());
1007 Expr::ForLoop(
1008 ForExpr {
1009 pattern,
1010 iter,
1011 body,
1012 }
1013 .into(),
1014 )
1015 })
1016 }
1017
1018 fn check_inline_markup(&mut self, markup: ast::Markup) -> Expr {
1019 self.check_in_mode(markup.to_untyped().children(), InterpretMode::Markup)
1020 }
1021
1022 fn check_markup(&mut self, markup: ast::Markup) -> Expr {
1023 self.with_scope(|this| this.check_inline_markup(markup))
1024 }
1025
1026 fn check_code(&mut self, code: ast::Code) -> Expr {
1027 self.with_scope(|this| {
1028 this.check_in_mode(code.to_untyped().children(), InterpretMode::Code)
1029 })
1030 }
1031
1032 fn check_math(&mut self, children: SyntaxNodeChildren) -> Expr {
1033 self.check_in_mode(children, InterpretMode::Math)
1034 }
1035
1036 fn check_root_scope(&mut self, children: SyntaxNodeChildren) {
1037 self.init_stage = true;
1038 self.check_in_mode(children, InterpretMode::Markup);
1039 self.init_stage = false;
1040 }
1041
1042 fn check_in_mode(&mut self, children: SyntaxNodeChildren, mode: InterpretMode) -> Expr {
1043 let old_mode = self.lexical.mode;
1044 self.lexical.mode = mode;
1045
1046 self.comment_matcher.reset();
1048
1049 let mut items = Vec::with_capacity(4);
1050 for n in children {
1051 if let Some(expr) = n.cast::<ast::Expr>() {
1052 items.push(self.check(expr));
1053 self.comment_matcher.reset();
1054 continue;
1055 }
1056 if !self.init_stage && self.comment_matcher.process(n) {
1057 self.comment_matcher.reset();
1058 }
1059 }
1060
1061 self.lexical.mode = old_mode;
1062 Expr::Block(items.into())
1063 }
1064
1065 fn check_ref(&mut self, ref_node: ast::Ref) -> Expr {
1066 let ident = Interned::new(Decl::ref_(ref_node));
1067 let body = ref_node
1068 .supplement()
1069 .map(|block| self.check(ast::Expr::ContentBlock(block)));
1070 let ref_expr = ContentRefExpr {
1071 ident: ident.clone(),
1072 of: None,
1073 body,
1074 };
1075 self.resolve_as(
1076 RefExpr {
1077 decl: ident,
1078 step: None,
1079 root: None,
1080 term: None,
1081 }
1082 .into(),
1083 );
1084 Expr::ContentRef(ref_expr.into())
1085 }
1086
1087 fn check_ident(&mut self, ident: ast::Ident) -> Expr {
1088 self.resolve_ident(Decl::ident_ref(ident).into(), InterpretMode::Code)
1089 }
1090
1091 fn check_math_ident(&mut self, ident: ast::MathIdent) -> Expr {
1092 self.resolve_ident(Decl::math_ident_ref(ident).into(), InterpretMode::Math)
1093 }
1094
1095 fn resolve_as(&mut self, r: Interned<RefExpr>) {
1096 self.resolve_as_(r.decl.span(), r);
1097 }
1098
1099 fn resolve_as_(&mut self, s: Span, r: Interned<RefExpr>) {
1100 self.buffer.push((s, r.clone()));
1101 }
1102
1103 fn resolve_ident(&mut self, decl: DeclExpr, mode: InterpretMode) -> Expr {
1104 let r: Interned<RefExpr> = self.resolve_ident_(decl, mode).into();
1105 let s = r.decl.span();
1106 self.buffer.push((s, r.clone()));
1107 Expr::Ref(r)
1108 }
1109
1110 fn resolve_ident_(&mut self, decl: DeclExpr, mode: InterpretMode) -> RefExpr {
1142 let (step, val) = self.eval_ident(decl.name(), mode);
1143 let (root, step) = extract_ref(step);
1144
1145 RefExpr {
1146 decl,
1147 root,
1148 step,
1149 term: val,
1150 }
1151 }
1152
1153 fn defer(&mut self, expr: ast::Expr) -> Expr {
1154 if self.init_stage {
1155 Expr::Star
1156 } else {
1157 self.check(expr)
1158 }
1159 }
1160
1161 fn collect_buffer(&mut self) {
1162 let mut resolves = self.resolves.lock();
1163 resolves.extend(self.buffer.drain(..));
1164 drop(resolves);
1165 let mut imports = self.imports.lock();
1166 imports.extend(self.import_buffer.drain(..));
1167 }
1168
1169 fn const_eval_expr(&self, expr: ast::Expr) -> Option<Value> {
1170 SharedContext::const_eval(expr)
1171 }
1172
1173 fn eval_expr(&mut self, expr: ast::Expr, mode: InterpretMode) -> ConcolicExpr {
1174 if let Some(term) = self.const_eval_expr(expr) {
1175 return (None, Some(Ty::Value(InsTy::new(term))));
1176 }
1177 crate::log_debug_ct!("checking expr: {expr:?}");
1178
1179 match expr {
1180 ast::Expr::FieldAccess(field_access) => {
1181 let field = Decl::ident_ref(field_access.field());
1182
1183 let (expr, term) = self.eval_expr(field_access.target(), mode);
1184 let term = term.and_then(|v| {
1185 match v {
1188 Ty::Value(val) => {
1189 Some(Ty::Value(InsTy::new(val.val.field(field.name(), ()).ok()?)))
1190 }
1191 _ => None,
1192 }
1193 });
1194 let sel = expr.map(|expr| Expr::Select(SelectExpr::new(field.into(), expr)));
1195 (sel, term)
1196 }
1197 ast::Expr::Ident(ident) => {
1198 let expr_term = self.eval_ident(&ident.get().into(), mode);
1199 crate::log_debug_ct!("checking expr: {expr:?} -> res: {expr_term:?}");
1200 expr_term
1201 }
1202 _ => (None, None),
1203 }
1204 }
1205
1206 fn eval_ident(&self, name: &Interned<str>, mode: InterpretMode) -> ConcolicExpr {
1220 let res = self.lexical.last.get(name);
1221 if res.0.is_some() || res.1.is_some() {
1222 return res;
1223 }
1224
1225 for scope in self.lexical.scopes.iter().rev() {
1226 let res = scope.get(name);
1227 if res.0.is_some() || res.1.is_some() {
1228 return res;
1229 }
1230 }
1231
1232 let scope = match mode {
1233 InterpretMode::Math => self.ctx.world.library.math.scope(),
1234 InterpretMode::Markup | InterpretMode::Code => self.ctx.world.library.global.scope(),
1235 _ => return (None, None),
1236 };
1237
1238 let val = scope
1239 .get(name)
1240 .cloned()
1241 .map(|val| Ty::Value(InsTy::new(val.read().clone())));
1242 if let Some(val) = val {
1243 return (None, Some(val));
1244 }
1245
1246 if name.as_ref() == "std" {
1247 let val = Ty::Value(InsTy::new(self.ctx.world.library.std.read().clone()));
1248 return (None, Some(val));
1249 }
1250
1251 (None, None)
1252 }
1253
1254 fn fold_expr_and_val(&mut self, src: ConcolicExpr) -> Option<Expr> {
1255 crate::log_debug_ct!("folding cc: {src:?}");
1256 match src {
1257 (None, Some(val)) => Some(Expr::Type(val)),
1258 (expr, _) => self.fold_expr(expr),
1259 }
1260 }
1261
1262 fn fold_expr(&mut self, expr: Option<Expr>) -> Option<Expr> {
1263 crate::log_debug_ct!("folding cc: {expr:?}");
1264 match expr {
1265 Some(Expr::Decl(decl)) if !decl.is_def() => {
1266 crate::log_debug_ct!("folding decl: {decl:?}");
1267 let (x, y) = self.eval_ident(decl.name(), InterpretMode::Code);
1268 self.fold_expr_and_val((x, y))
1269 }
1270 Some(Expr::Ref(r)) => {
1271 crate::log_debug_ct!("folding ref: {r:?}");
1272 self.fold_expr_and_val((r.root.clone(), r.term.clone()))
1273 }
1274 Some(Expr::Select(r)) => {
1275 let lhs = self.fold_expr(Some(r.lhs.clone()));
1276 crate::log_debug_ct!("folding select: {r:?} ([{lhs:?}].[{:?}])", r.key);
1277 self.syntax_level_select(lhs?, &r.key, r.span)
1278 }
1279 Some(expr) => {
1280 crate::log_debug_ct!("folding expr: {expr:?}");
1281 Some(expr)
1282 }
1283 _ => None,
1284 }
1285 }
1286
1287 fn syntax_level_select(&mut self, lhs: Expr, key: &Interned<Decl>, span: Span) -> Option<Expr> {
1288 match &lhs {
1289 Expr::Decl(decl) => match decl.as_ref() {
1290 Decl::Module(module) => {
1291 let exports = self.exports_of(module.fid);
1292 let selected = exports.get(key.name())?;
1293
1294 let select_ref = Interned::new(RefExpr {
1295 decl: key.clone(),
1296 root: Some(lhs.clone()),
1297 step: Some(selected.clone()),
1298 term: None,
1299 });
1300 self.resolve_as(select_ref.clone());
1301 self.resolve_as_(span, select_ref);
1302 Some(selected.clone())
1303 }
1304 _ => None,
1305 },
1306 _ => None,
1307 }
1308 }
1309
1310 fn exports_of(&mut self, fid: TypstFileId) -> LexicalScope {
1311 let imported = self
1312 .ctx
1313 .source_by_id(fid)
1314 .ok()
1315 .and_then(|src| self.ctx.exports_of(&src, self.route))
1316 .unwrap_or_default();
1317 let res = imported.as_ref().deref().clone();
1318 self.import_buffer.push((fid, imported));
1319 res
1320 }
1321}
1322
1323fn extract_ref(step: Option<Expr>) -> (Option<Expr>, Option<Expr>) {
1335 match step {
1336 Some(Expr::Ref(r)) => (r.root.clone(), Some(r.decl.clone().into())),
1337 step => (step.clone(), step),
1338 }
1339}
1340
1341fn none_expr() -> Expr {
1342 Expr::Type(Ty::Builtin(BuiltinTy::None))
1343}
1344
1345#[cfg(test)]
1346mod tests {
1347 #[test]
1348 fn test_expr_size() {
1349 use super::*;
1350 assert!(size_of::<Expr>() <= size_of::<usize>() * 2);
1351 }
1352}