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