tinymist_analysis/syntax/
def.rs

1//! Definitions of syntax structures.
2
3use core::fmt;
4use std::{
5    collections::BTreeMap,
6    ops::{Deref, Range},
7    sync::Arc,
8};
9
10use rustc_hash::FxHashMap;
11use serde::{Deserialize, Serialize};
12use tinymist_derive::DeclEnum;
13use tinymist_std::DefId;
14use tinymist_world::package::PackageSpec;
15use typst::{
16    foundations::{Element, Func, Module, Type, Value},
17    syntax::{Span, SyntaxNode},
18    utils::LazyHash,
19};
20
21use crate::{
22    adt::interner::impl_internable,
23    docs::DocString,
24    prelude::*,
25    ty::{InsTy, Interned, SelectTy, Ty, TypeVar},
26};
27
28use super::{ExprDescriber, ExprPrinter};
29
30/// Information about expressions in a source file.
31///
32/// This structure wraps expression analysis data and provides access to
33/// expression resolution, documentation, and scoping information.
34#[derive(Debug, Clone, Hash)]
35pub struct ExprInfo(Arc<LazyHash<ExprInfoRepr>>);
36
37impl ExprInfo {
38    /// Creates a new [`ExprInfo`] instance from expression information
39    /// representation.
40    ///
41    /// Wraps the provided representation in an Arc and LazyHash for efficient
42    /// sharing and hashing.
43    pub fn new(repr: ExprInfoRepr) -> Self {
44        Self(Arc::new(LazyHash::new(repr)))
45    }
46}
47
48impl Deref for ExprInfo {
49    type Target = Arc<LazyHash<ExprInfoRepr>>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.0
53    }
54}
55
56/// Representation of [`ExprInfo`] for a specific file.
57///
58/// Contains all the analyzed information including resolution maps,
59/// documentation strings, imports, and exports.
60#[derive(Debug)]
61pub struct ExprInfoRepr {
62    /// The file ID this expression information belongs to.
63    pub fid: TypstFileId,
64    /// Revision number for tracking changes to the file.
65    pub revision: usize,
66    /// The source code content.
67    pub source: Source,
68    /// The root expression of the file.
69    pub root: Expr,
70    /// Documentation string for the module.
71    pub module_docstring: Arc<DocString>,
72    /// The lexical scope of exported symbols from this file.
73    pub exports: Arc<LazyHash<LexicalScope>>,
74    /// Map from file IDs to imported lexical scopes.
75    pub imports: FxHashMap<TypstFileId, Arc<LazyHash<LexicalScope>>>,
76    /// Map from spans to expressions for scope analysis.
77    pub exprs: FxHashMap<Span, Expr>,
78    /// Map from spans to resolved reference expressions.
79    pub resolves: FxHashMap<Span, Interned<RefExpr>>,
80    /// Map from declarations to their documentation strings.
81    pub docstrings: FxHashMap<DeclExpr, Arc<DocString>>,
82    /// Layout information for module import items in this file.
83    pub module_items: FxHashMap<Interned<Decl>, ModuleItemLayout>,
84}
85
86impl std::hash::Hash for ExprInfoRepr {
87    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
88        // already contained in the source.
89        // self.fid.hash(state);
90        self.revision.hash(state);
91        self.source.hash(state);
92        self.root.hash(state);
93        self.exports.hash(state);
94        let mut resolves = self.resolves.iter().collect::<Vec<_>>();
95        resolves.sort_by_key(|(fid, _)| fid.into_raw());
96        resolves.hash(state);
97        let mut imports = self.imports.iter().collect::<Vec<_>>();
98        imports.sort_by_key(|(fid, _)| *fid);
99        imports.hash(state);
100        let mut module_items = self.module_items.iter().collect::<Vec<_>>();
101        module_items.sort_by_key(|(decl, _)| decl.span().into_raw());
102        module_items.hash(state);
103    }
104}
105
106impl ExprInfoRepr {
107    /// Gets the definition expression for a given declaration.
108    pub fn get_def(&self, decl: &Interned<Decl>) -> Option<Expr> {
109        if decl.is_def() {
110            return Some(Expr::Decl(decl.clone()));
111        }
112        let resolved = self.resolves.get(&decl.span())?;
113        Some(Expr::Ref(resolved.clone()))
114    }
115
116    /// Gets all references to a given declaration.
117    pub fn get_refs(
118        &self,
119        decl: Interned<Decl>,
120    ) -> impl Iterator<Item = (&Span, &Interned<RefExpr>)> {
121        let of = Some(Expr::Decl(decl.clone()));
122        self.resolves
123            .iter()
124            .filter(move |(_, r)| match (decl.as_ref(), r.decl.as_ref()) {
125                (Decl::Label(..), Decl::Label(..))
126                | (Decl::Label(..), Decl::ContentRef(..))
127                | (Decl::ContentRef(..), Decl::Label(..))
128                | (Decl::ContentRef(..), Decl::ContentRef(..)) => r.decl.name() == decl.name(),
129                (Decl::Label(..), _) => false,
130                _ => r.decl == decl || r.root == of,
131            })
132    }
133
134    /// Checks if a declaration is exported from this module.
135    pub fn is_exported(&self, decl: &Interned<Decl>) -> bool {
136        let of = Expr::Decl(decl.clone());
137        self.exports
138            .get(decl.name())
139            .is_some_and(|export| match export {
140                Expr::Ref(ref_expr) => ref_expr.root == Some(of),
141                exprt => *exprt == of,
142            })
143    }
144
145    /// Shows the expression information.
146    #[allow(dead_code)]
147    fn show(&self) {
148        use std::io::Write;
149        let vpath = self
150            .fid
151            .vpath()
152            .resolve(Path::new("target/exprs/"))
153            .unwrap();
154        let root = vpath.with_extension("root.expr");
155        std::fs::create_dir_all(root.parent().unwrap()).unwrap();
156        std::fs::write(root, format!("{}", self.root)).unwrap();
157        let scopes = vpath.with_extension("scopes.expr");
158        std::fs::create_dir_all(scopes.parent().unwrap()).unwrap();
159        {
160            let mut scopes = std::fs::File::create(scopes).unwrap();
161            for (span, expr) in self.exprs.iter() {
162                writeln!(scopes, "{span:?} -> {expr}").unwrap();
163            }
164        }
165        let imports = vpath.with_extension("imports.expr");
166        std::fs::create_dir_all(imports.parent().unwrap()).unwrap();
167        std::fs::write(imports, format!("{:#?}", self.imports)).unwrap();
168        let exports = vpath.with_extension("exports.expr");
169        std::fs::create_dir_all(exports.parent().unwrap()).unwrap();
170        std::fs::write(exports, format!("{:#?}", self.exports)).unwrap();
171    }
172}
173
174/// Describes how an import item is laid out in the source text.
175#[derive(Debug, Clone, Hash)]
176pub struct ModuleItemLayout {
177    /// The module declaration that owns this item.
178    pub parent: Interned<Decl>,
179    /// The byte range covering the whole `foo as bar` clause.
180    pub item_range: Range<usize>,
181    /// The byte range covering the bound identifier (`bar` in `foo as bar`).
182    pub binding_range: Range<usize>,
183}
184
185/// Represents different kinds of expressions in the language.
186///
187/// This enum covers all possible expression types that can appear in Typst
188/// source code, from basic literals to complex control flow constructs.
189#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190pub enum Expr {
191    /// A sequence of expressions: `{ x; y; z }`
192    Block(Interned<Vec<Expr>>),
193    /// An array literal: `(1, 2, 3)`
194    Array(Interned<ArgsExpr>),
195    /// A dict literal: `(a: 1, b: 2)`
196    Dict(Interned<ArgsExpr>),
197    /// An args literal: `(1, 2, 3)`
198    Args(Interned<ArgsExpr>),
199    /// A pattern: `(x, y, ..z)`
200    Pattern(Interned<Pattern>),
201    /// An element literal: `[*Hi* there!]`
202    Element(Interned<ElementExpr>),
203    /// An unary operation: `-x`
204    Unary(Interned<UnExpr>),
205    /// A binary operation: `x + y`
206    Binary(Interned<BinExpr>),
207    /// A function call: `f(x, y)`
208    Apply(Interned<ApplyExpr>),
209    /// A function: `(x, y) => x + y`
210    Func(Interned<FuncExpr>),
211    /// A let: `let x = 1`
212    Let(Interned<LetExpr>),
213    /// A show: `show heading: it => emph(it.body)`
214    Show(Interned<ShowExpr>),
215    /// A set: `set text(...)`
216    Set(Interned<SetExpr>),
217    /// A reference: `#x`
218    Ref(Interned<RefExpr>),
219    /// A content reference: `@x`
220    ContentRef(Interned<ContentRefExpr>),
221    /// A select: `x.y`
222    Select(Interned<SelectExpr>),
223    /// An import expression: `import "path.typ": x`
224    Import(Interned<ImportExpr>),
225    /// An include expression: `include "path.typ"`
226    Include(Interned<IncludeExpr>),
227    /// A contextual expression: `context text.lang`
228    Contextual(Interned<Expr>),
229    /// A conditional expression: `if x { y } else { z }`
230    Conditional(Interned<IfExpr>),
231    /// A while loop: `while x { y }`
232    WhileLoop(Interned<WhileExpr>),
233    /// A for loop: `for x in y { z }`
234    ForLoop(Interned<ForExpr>),
235    /// A type: `str`
236    Type(Ty),
237    /// A declaration: `x`
238    Decl(DeclExpr),
239    /// A star import: `*`
240    Star,
241}
242
243impl Expr {
244    /// Returns a string representation of the expression.
245    pub fn repr(&self) -> EcoString {
246        let mut s = EcoString::new();
247        let _ = ExprDescriber::new(&mut s).write_expr(self);
248        s
249    }
250
251    /// Returns the span location of the expression.
252    pub fn span(&self) -> Span {
253        match self {
254            Expr::Decl(decl) => decl.span(),
255            Expr::Select(select) => select.span,
256            Expr::Apply(apply) => apply.span,
257            _ => Span::detached(),
258        }
259    }
260
261    /// Returns the file ID associated with this expression, if any.
262    pub fn file_id(&self) -> Option<TypstFileId> {
263        match self {
264            Expr::Decl(decl) => decl.file_id(),
265            _ => self.span().id(),
266        }
267    }
268
269    /// Returns whether the expression is definitely defined.
270    pub fn is_defined(&self) -> bool {
271        match self {
272            Expr::Ref(refs) => refs.root.is_some() || refs.term.is_some(),
273            Expr::Decl(decl) => decl.is_def(),
274            // There are unsure cases, like `x.y`, which may be defined or not.
275            _ => false,
276        }
277    }
278}
279
280impl fmt::Display for Expr {
281    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282        ExprPrinter::new(f).write_expr(self)
283    }
284}
285
286/// Type alias for lexical scopes.
287///
288/// Represents a lexical scope as a persistent map from names to expressions.
289pub type LexicalScope = rpds::RedBlackTreeMapSync<Interned<str>, Expr>;
290
291/// Different types of scopes for expression evaluation.
292///
293/// Represents the various kinds of scopes that can contain variable bindings,
294/// including lexical scopes, modules, functions, and types.
295#[derive(Debug, Clone)]
296pub enum ExprScope {
297    /// A lexical scope extracted from a source file.
298    Lexical(LexicalScope),
299    /// A module instance which is either built-in or evaluated during analysis.
300    Module(Module),
301    /// A scope bound to a function.
302    Func(Func),
303    /// A scope bound to a type.
304    Type(Type),
305}
306
307impl ExprScope {
308    /// Creates an empty lexical scope.
309    pub fn empty() -> Self {
310        ExprScope::Lexical(LexicalScope::default())
311    }
312
313    /// Checks if the scope contains no bindings.
314    pub fn is_empty(&self) -> bool {
315        match self {
316            ExprScope::Lexical(scope) => scope.is_empty(),
317            ExprScope::Module(module) => is_empty_scope(module.scope()),
318            ExprScope::Func(func) => func.scope().is_none_or(is_empty_scope),
319            ExprScope::Type(ty) => is_empty_scope(ty.scope()),
320        }
321    }
322
323    /// Looks up a name in the scope and returns both expression and type
324    /// information.
325    pub fn get(&self, name: &Interned<str>) -> (Option<Expr>, Option<Ty>) {
326        let (of, val) = match self {
327            ExprScope::Lexical(scope) => {
328                crate::log_debug_ct!("evaluating: {name:?} in {scope:?}");
329                (scope.get(name).cloned(), None)
330            }
331            ExprScope::Module(module) => {
332                let v = module.scope().get(name);
333                // let decl =
334                //     v.and_then(|_| Some(Decl::external(module.file_id()?,
335                // name.clone()).into()));
336                (None, v)
337            }
338            ExprScope::Func(func) => (None, func.scope().unwrap().get(name)),
339            ExprScope::Type(ty) => (None, ty.scope().get(name)),
340        };
341
342        // ref_expr.of = of.clone();
343        // ref_expr.val = val.map(|v| Ty::Value(InsTy::new(v.clone())));
344        // return ref_expr;
345        (
346            of,
347            val.cloned()
348                .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))),
349        )
350    }
351
352    /// Merges all bindings from this scope into the provided export map.
353    pub fn merge_into(&self, exports: &mut LexicalScope) {
354        match self {
355            ExprScope::Lexical(scope) => {
356                for (name, expr) in scope.iter() {
357                    exports.insert_mut(name.clone(), expr.clone());
358                }
359            }
360            ExprScope::Module(module) => {
361                crate::log_debug_ct!("imported: {module:?}");
362                let v = Interned::new(Ty::Value(InsTy::new(Value::Module(module.clone()))));
363                for (name, _) in module.scope().iter() {
364                    let name: Interned<str> = name.into();
365                    exports.insert_mut(name.clone(), select_of(v.clone(), name));
366                }
367            }
368            ExprScope::Func(func) => {
369                if let Some(scope) = func.scope() {
370                    let v = Interned::new(Ty::Value(InsTy::new(Value::Func(func.clone()))));
371                    for (name, _) in scope.iter() {
372                        let name: Interned<str> = name.into();
373                        exports.insert_mut(name.clone(), select_of(v.clone(), name));
374                    }
375                }
376            }
377            ExprScope::Type(ty) => {
378                let v = Interned::new(Ty::Value(InsTy::new(Value::Type(*ty))));
379                for (name, _) in ty.scope().iter() {
380                    let name: Interned<str> = name.into();
381                    exports.insert_mut(name.clone(), select_of(v.clone(), name));
382                }
383            }
384        }
385    }
386}
387
388fn select_of(source: Interned<Ty>, name: Interned<str>) -> Expr {
389    Expr::Type(Ty::Select(SelectTy::new(source, name)))
390}
391
392/// Kind of a definition.
393#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
394#[serde(rename_all = "camelCase")]
395pub enum DefKind {
396    /// A definition for some constant: `let x = 1`
397    #[default]
398    Constant,
399    /// A definition for some function: `(x, y) => x + y`
400    Function,
401    /// A definition for some variable: `let x = (x, y) => x + y`
402    Variable,
403    /// A definition for some module.
404    Module,
405    /// A definition for some struct (type).
406    Struct,
407    /// A definition for some reference: `<label>`
408    Reference,
409}
410
411impl fmt::Display for DefKind {
412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413        match self {
414            Self::Constant => write!(f, "constant"),
415            Self::Function => write!(f, "function"),
416            Self::Variable => write!(f, "variable"),
417            Self::Module => write!(f, "module"),
418            Self::Struct => write!(f, "struct"),
419            Self::Reference => write!(f, "reference"),
420        }
421    }
422}
423
424/// Type alias for declaration expressions.
425pub type DeclExpr = Interned<Decl>;
426
427/// Represents different kinds of declarations in the language.
428#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
429pub enum Decl {
430    /// A function declaration: `(x, y) => x + y`
431    Func(SpannedDecl),
432    /// An import alias declaration: `import "path.typ": x`
433    ImportAlias(SpannedDecl),
434    /// A variable declaration: `let x = 1`
435    Var(SpannedDecl),
436    /// An identifier reference declaration: `x`
437    IdentRef(SpannedDecl),
438    /// A module declaration: `import calc`
439    Module(ModuleDecl),
440    /// A module alias declaration: `import "path.typ" as x`
441    ModuleAlias(SpannedDecl),
442    /// A path stem declaration: `path.typ`
443    PathStem(SpannedDecl),
444    /// An import path declaration: `import "path.typ"`
445    ImportPath(SpannedDecl),
446    /// An include path declaration: `include "path.typ"`
447    IncludePath(SpannedDecl),
448    /// An import declaration: `import "path.typ"`
449    Import(SpannedDecl),
450    /// A content reference declaration: `@x`
451    ContentRef(SpannedDecl),
452    /// A label declaration: `label`
453    Label(SpannedDecl),
454    /// A string name declaration: `"x"`
455    StrName(SpannedDecl),
456    /// A module import declaration: `import "path.typ": *`
457    ModuleImport(SpanDecl),
458    /// A closure declaration: `(x, y) => x + y`
459    Closure(SpanDecl),
460    /// A pattern declaration: `let (x, y, ..z) = 1`
461    Pattern(SpanDecl),
462    /// A spread declaration: `..z`
463    Spread(SpanDecl),
464    /// A content declaration: `#[text]`
465    Content(SpanDecl),
466    /// A constant declaration: `let x = 1`
467    Constant(SpanDecl),
468    /// A bib entry declaration: `@entry`
469    BibEntry(NameRangeDecl),
470    /// A docs declaration created by the compiler.
471    Docs(DocsDecl),
472    /// A generated declaration created by the compiler.
473    Generated(GeneratedDecl),
474}
475
476impl Decl {
477    /// Creates a function declaration from an identifier.
478    pub fn func(ident: ast::Ident) -> Self {
479        Self::Func(SpannedDecl {
480            name: ident.get().into(),
481            at: ident.span(),
482        })
483    }
484
485    /// Creates a variable declaration from a string literal.
486    pub fn lit(name: &str) -> Self {
487        Self::Var(SpannedDecl {
488            name: name.into(),
489            at: Span::detached(),
490        })
491    }
492
493    /// Creates a variable declaration from an interned string.
494    pub fn lit_(name: Interned<str>) -> Self {
495        Self::Var(SpannedDecl {
496            name,
497            at: Span::detached(),
498        })
499    }
500
501    /// Creates a variable declaration from an identifier.
502    pub fn var(ident: ast::Ident) -> Self {
503        Self::Var(SpannedDecl {
504            name: ident.get().into(),
505            at: ident.span(),
506        })
507    }
508
509    /// Creates an import alias declaration from an identifier.
510    pub fn import_alias(ident: ast::Ident) -> Self {
511        Self::ImportAlias(SpannedDecl {
512            name: ident.get().into(),
513            at: ident.span(),
514        })
515    }
516
517    /// Creates an identifier reference declaration from an identifier.
518    pub fn ident_ref(ident: ast::Ident) -> Self {
519        Self::IdentRef(SpannedDecl {
520            name: ident.get().into(),
521            at: ident.span(),
522        })
523    }
524
525    /// Creates an identifier reference declaration from a math identifier.
526    pub fn math_ident_ref(ident: ast::MathIdent) -> Self {
527        Self::IdentRef(SpannedDecl {
528            name: ident.get().into(),
529            at: ident.span(),
530        })
531    }
532
533    /// Creates a module declaration with a file ID.
534    pub fn module(fid: TypstFileId) -> Self {
535        let name = {
536            let stem = fid.vpath().as_rooted_path().file_stem();
537            stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
538                .unwrap_or_default()
539        };
540        Self::Module(ModuleDecl { name, fid })
541    }
542
543    /// Creates a module declaration with a name and a file ID.
544    pub fn module_with_name(name: Interned<str>, fid: TypstFileId) -> Self {
545        Self::Module(ModuleDecl { name, fid })
546    }
547
548    /// Creates a module alias declaration from an identifier.
549    pub fn module_alias(ident: ast::Ident) -> Self {
550        Self::ModuleAlias(SpannedDecl {
551            name: ident.get().into(),
552            at: ident.span(),
553        })
554    }
555
556    /// Creates an import declaration from an identifier.
557    pub fn import(ident: ast::Ident) -> Self {
558        Self::Import(SpannedDecl {
559            name: ident.get().into(),
560            at: ident.span(),
561        })
562    }
563
564    /// Creates a label declaration with a name and span.
565    pub fn label(name: &str, at: Span) -> Self {
566        Self::Label(SpannedDecl {
567            name: name.into(),
568            at,
569        })
570    }
571
572    /// Creates a content reference declaration from a reference AST node.
573    pub fn ref_(ident: ast::Ref) -> Self {
574        Self::ContentRef(SpannedDecl {
575            name: ident.target().into(),
576            at: {
577                let marker_span = ident
578                    .to_untyped()
579                    .children()
580                    .find(|child| child.kind() == SyntaxKind::RefMarker)
581                    .map(|child| child.span());
582
583                marker_span.unwrap_or(ident.span())
584            },
585        })
586    }
587
588    /// Creates a string name declaration from a syntax node and name.
589    pub fn str_name(s: SyntaxNode, name: &str) -> Decl {
590        Self::StrName(SpannedDecl {
591            name: name.into(),
592            at: s.span(),
593        })
594    }
595
596    /// Calculates the path stem from a string path or package specification.
597    ///
598    /// For package specs (starting with '@'), extracts the package name.
599    /// For file paths, extracts the file stem. Returns empty string if
600    /// extraction fails.
601    pub fn calc_path_stem(s: &str) -> Interned<str> {
602        use std::str::FromStr;
603        let name = if s.starts_with('@') {
604            let spec = PackageSpec::from_str(s).ok();
605            spec.map(|spec| Interned::new_str(spec.name.as_str()))
606        } else {
607            let stem = Path::new(s).file_stem();
608            stem.and_then(|stem| Some(Interned::new_str(stem.to_str()?)))
609        };
610        name.unwrap_or_default()
611    }
612
613    /// Creates a path stem declaration from a syntax node and name.
614    pub fn path_stem(s: SyntaxNode, name: Interned<str>) -> Self {
615        Self::PathStem(SpannedDecl { name, at: s.span() })
616    }
617
618    /// Creates an import path declaration with a span and name.
619    pub fn import_path(s: Span, name: Interned<str>) -> Self {
620        Self::ImportPath(SpannedDecl { name, at: s })
621    }
622
623    /// Creates an include path declaration with a span and name.
624    pub fn include_path(s: Span, name: Interned<str>) -> Self {
625        Self::IncludePath(SpannedDecl { name, at: s })
626    }
627
628    /// Creates a module import declaration with just a span.
629    pub fn module_import(s: Span) -> Self {
630        Self::ModuleImport(SpanDecl(s))
631    }
632
633    /// Creates a closure declaration with just a span.
634    pub fn closure(s: Span) -> Self {
635        Self::Closure(SpanDecl(s))
636    }
637
638    /// Creates a pattern declaration with just a span.
639    pub fn pattern(s: Span) -> Self {
640        Self::Pattern(SpanDecl(s))
641    }
642
643    /// Creates a spread declaration with just a span.
644    pub fn spread(s: Span) -> Self {
645        Self::Spread(SpanDecl(s))
646    }
647
648    /// Creates a content declaration with just a span.
649    pub fn content(s: Span) -> Self {
650        Self::Content(SpanDecl(s))
651    }
652
653    /// Creates a constant declaration with just a span.
654    pub fn constant(s: Span) -> Self {
655        Self::Constant(SpanDecl(s))
656    }
657
658    /// Creates a documentation declaration linking a base declaration with a
659    /// type variable.
660    pub fn docs(base: Interned<Decl>, var: Interned<TypeVar>) -> Self {
661        Self::Docs(DocsDecl { base, var })
662    }
663
664    /// Creates a generated declaration with a definition ID.
665    pub fn generated(def_id: DefId) -> Self {
666        Self::Generated(GeneratedDecl(def_id))
667    }
668
669    /// Creates a bibliography entry declaration.
670    pub fn bib_entry(
671        name: Interned<str>,
672        fid: TypstFileId,
673        name_range: Range<usize>,
674        range: Option<Range<usize>>,
675    ) -> Self {
676        Self::BibEntry(NameRangeDecl {
677            name,
678            at: Box::new((fid, name_range, range)),
679        })
680    }
681
682    /// Checks if this declaration represents a definition rather than a
683    /// reference (usage of a definition).
684    pub fn is_def(&self) -> bool {
685        matches!(
686            self,
687            Self::Func(..)
688                | Self::BibEntry(..)
689                | Self::Closure(..)
690                | Self::Var(..)
691                | Self::Label(..)
692                | Self::StrName(..)
693                | Self::Module(..)
694                | Self::ModuleImport(..)
695                | Self::PathStem(..)
696                | Self::ImportPath(..)
697                | Self::IncludePath(..)
698                | Self::Spread(..)
699                | Self::Generated(..)
700        )
701    }
702
703    /// Returns the kind of definition this declaration represents.
704    pub fn kind(&self) -> DefKind {
705        use Decl::*;
706        match self {
707            ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
708                DefKind::Module
709            }
710            // Type(_) => DocStringKind::Struct,
711            Func(..) | Closure(..) => DefKind::Function,
712            Label(..) | BibEntry(..) | ContentRef(..) => DefKind::Reference,
713            IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => DefKind::Variable,
714            Pattern(..) | Docs(..) | Generated(..) | Constant(..) | StrName(..)
715            | ModuleImport(..) | Content(..) | Spread(..) => DefKind::Constant,
716        }
717    }
718
719    /// Gets file location of the declaration.
720    pub fn file_id(&self) -> Option<TypstFileId> {
721        match self {
722            Self::Module(ModuleDecl { fid, .. }) => Some(*fid),
723            Self::BibEntry(NameRangeDecl { at, .. }) => Some(at.0),
724            that => that.span().id(),
725        }
726    }
727
728    /// Gets full range of the declaration.
729    pub fn full_range(&self) -> Option<Range<usize>> {
730        if let Decl::BibEntry(decl) = self {
731            return decl.at.2.clone();
732        }
733
734        None
735    }
736
737    /// Creates a reference expression that points to this declaration.
738    pub fn as_def(this: &Interned<Self>, val: Option<Ty>) -> Interned<RefExpr> {
739        let def: Expr = this.clone().into();
740        Interned::new(RefExpr {
741            decl: this.clone(),
742            step: Some(def.clone()),
743            root: Some(def),
744            term: val,
745        })
746    }
747}
748
749impl Ord for Decl {
750    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
751        let base = match (self, other) {
752            (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
753            (Self::Module(l), Self::Module(r)) => l.fid.cmp(&r.fid),
754            (Self::Docs(l), Self::Docs(r)) => l.var.cmp(&r.var).then_with(|| l.base.cmp(&r.base)),
755            _ => self.span().into_raw().cmp(&other.span().into_raw()),
756        };
757
758        base.then_with(|| self.name().cmp(other.name()))
759    }
760}
761
762trait StrictCmp {
763    /// Low-performance comparison but it is free from the concurrency issue.
764    /// This is only used for making stable test snapshots.
765    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering;
766}
767
768impl Decl {
769    /// Low-performance comparison that is free from concurrency issues.
770    pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
771        let base = match (self, other) {
772            (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
773            (Self::Module(l), Self::Module(r)) => l.fid.strict_cmp(&r.fid),
774            (Self::Docs(l), Self::Docs(r)) => l
775                .var
776                .strict_cmp(&r.var)
777                .then_with(|| l.base.strict_cmp(&r.base)),
778            _ => self.span().strict_cmp(&other.span()),
779        };
780
781        base.then_with(|| self.name().cmp(other.name()))
782    }
783}
784
785impl StrictCmp for TypstFileId {
786    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
787        self.package()
788            .map(ToString::to_string)
789            .cmp(&other.package().map(ToString::to_string))
790            .then_with(|| self.vpath().cmp(other.vpath()))
791    }
792}
793impl<T: StrictCmp> StrictCmp for Option<T> {
794    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
795        match (self, other) {
796            (Some(l), Some(r)) => l.strict_cmp(r),
797            (Some(_), None) => std::cmp::Ordering::Greater,
798            (None, Some(_)) => std::cmp::Ordering::Less,
799            (None, None) => std::cmp::Ordering::Equal,
800        }
801    }
802}
803
804impl StrictCmp for Span {
805    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
806        self.id()
807            .strict_cmp(&other.id())
808            .then_with(|| self.into_raw().cmp(&other.into_raw()))
809    }
810}
811
812impl PartialOrd for Decl {
813    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
814        Some(self.cmp(other))
815    }
816}
817
818impl From<Decl> for Expr {
819    fn from(decl: Decl) -> Self {
820        Expr::Decl(decl.into())
821    }
822}
823
824impl From<DeclExpr> for Expr {
825    fn from(decl: DeclExpr) -> Self {
826        Expr::Decl(decl)
827    }
828}
829
830/// A declaration with an associated name and span location.
831#[derive(Clone, PartialEq, Eq, Hash)]
832pub struct SpannedDecl {
833    /// The name of the declaration.
834    name: Interned<str>,
835    /// The span location of the declaration.
836    at: Span,
837}
838
839impl SpannedDecl {
840    /// Gets the name of the declaration.
841    fn name(&self) -> &Interned<str> {
842        &self.name
843    }
844
845    /// Gets the span location of the declaration.
846    fn span(&self) -> Span {
847        self.at
848    }
849}
850
851impl fmt::Debug for SpannedDecl {
852    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
853        f.write_str(self.name.as_ref())
854    }
855}
856
857/// A declaration with a name and range information.
858#[derive(Clone, PartialEq, Eq, Hash)]
859pub struct NameRangeDecl {
860    /// The name of the declaration.
861    pub name: Interned<str>,
862    /// Boxed tuple containing (file_id, name_range, full_range).
863    pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
864}
865
866impl NameRangeDecl {
867    /// Gets the name of the declaration.
868    fn name(&self) -> &Interned<str> {
869        &self.name
870    }
871
872    /// Gets the span location of the declaration.
873    fn span(&self) -> Span {
874        Span::detached()
875    }
876}
877
878impl fmt::Debug for NameRangeDecl {
879    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880        f.write_str(self.name.as_ref())
881    }
882}
883
884/// A module declaration with name and file ID.
885#[derive(Clone, PartialEq, Eq, Hash)]
886pub struct ModuleDecl {
887    /// The name of the module.
888    pub name: Interned<str>,
889    /// The file ID where the module is defined.
890    pub fid: TypstFileId,
891}
892
893impl ModuleDecl {
894    /// Gets the name of the declaration.
895    fn name(&self) -> &Interned<str> {
896        &self.name
897    }
898
899    /// Gets the span location of the declaration.
900    fn span(&self) -> Span {
901        Span::detached()
902    }
903}
904
905impl fmt::Debug for ModuleDecl {
906    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907        f.write_str(self.name.as_ref())
908    }
909}
910
911/// A documentation declaration linking a base declaration with type variables.
912#[derive(Clone, PartialEq, Eq, Hash)]
913pub struct DocsDecl {
914    base: Interned<Decl>,
915    var: Interned<TypeVar>,
916}
917
918impl DocsDecl {
919    /// Gets the name of the declaration.
920    fn name(&self) -> &Interned<str> {
921        Interned::empty()
922    }
923
924    /// Gets the span location of the declaration.
925    fn span(&self) -> Span {
926        Span::detached()
927    }
928}
929
930impl fmt::Debug for DocsDecl {
931    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
932        write!(f, "{:?}, {:?}", self.base, self.var)
933    }
934}
935
936/// A span-only declaration for anonymous constructs.
937#[derive(Clone, PartialEq, Eq, Hash)]
938pub struct SpanDecl(Span);
939
940impl SpanDecl {
941    /// Gets the name of the declaration.
942    fn name(&self) -> &Interned<str> {
943        Interned::empty()
944    }
945
946    /// Gets the span location of the declaration.
947    fn span(&self) -> Span {
948        self.0
949    }
950}
951
952impl fmt::Debug for SpanDecl {
953    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954        write!(f, "..")
955    }
956}
957
958/// A generated declaration with a unique definition ID.
959#[derive(Clone, PartialEq, Eq, Hash)]
960pub struct GeneratedDecl(DefId);
961
962impl GeneratedDecl {
963    /// Gets the name of the declaration.
964    fn name(&self) -> &Interned<str> {
965        Interned::empty()
966    }
967
968    /// Gets the span location of the declaration.
969    fn span(&self) -> Span {
970        Span::detached()
971    }
972}
973
974impl fmt::Debug for GeneratedDecl {
975    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
976        self.0.fmt(f)
977    }
978}
979
980/// Type alias for unary expressions.
981pub type UnExpr = UnInst<Expr>;
982/// Type alias for binary expressions.
983pub type BinExpr = BinInst<Expr>;
984
985/// Type alias for export maps.
986///
987/// Maps exported names to their corresponding expressions.
988pub type ExportMap = BTreeMap<Interned<str>, Expr>;
989
990/// Represents different kinds of function arguments.
991///
992/// Covers positional arguments, named arguments, and spread arguments.
993#[derive(Debug, Clone, PartialEq, Eq, Hash)]
994pub enum ArgExpr {
995    /// A positional argument: `x`
996    Pos(Expr),
997    /// A named argument: `a: x`
998    Named(Box<(DeclExpr, Expr)>),
999    /// A named argument with a default value: `((a): x)`
1000    NamedRt(Box<(Expr, Expr)>),
1001    /// A spread argument: `..x`
1002    Spread(Expr),
1003}
1004
1005/// Represents different kinds of patterns for destructuring.
1006#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1007pub enum Pattern {
1008    /// A general pattern expression can occur in right-hand side of a
1009    /// function signature.
1010    Expr(Expr),
1011    /// A simple pattern: `x`
1012    Simple(Interned<Decl>),
1013    /// A pattern signature: `(x, y: val, ..z)`
1014    Sig(Box<PatternSig>),
1015}
1016
1017impl fmt::Display for Pattern {
1018    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1019        ExprPrinter::new(f).write_pattern(self)
1020    }
1021}
1022
1023impl Pattern {
1024    /// Returns a string representation of the pattern.
1025    pub fn repr(&self) -> EcoString {
1026        let mut s = EcoString::new();
1027        let _ = ExprDescriber::new(&mut s).write_pattern(self);
1028        s
1029    }
1030}
1031
1032/// Signature pattern for function parameters.
1033///
1034/// Describes the structure of function parameters including positional,
1035/// named, and spread parameters.
1036#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1037pub struct PatternSig {
1038    /// Positional parameters in order.
1039    pub pos: EcoVec<Interned<Pattern>>,
1040    /// Named parameters with their default patterns.
1041    pub named: EcoVec<(DeclExpr, Interned<Pattern>)>,
1042    /// Left spread parameter (collects extra positional arguments).
1043    pub spread_left: Option<(DeclExpr, Interned<Pattern>)>,
1044    /// Right spread parameter (collects remaining arguments).
1045    pub spread_right: Option<(DeclExpr, Interned<Pattern>)>,
1046}
1047
1048impl Pattern {}
1049
1050impl_internable!(Decl,);
1051
1052/// Represents a content sequence expression.
1053///
1054/// Used for sequences of content elements with associated type information.
1055#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1056pub struct ContentSeqExpr {
1057    /// The type of the content sequence
1058    pub ty: Ty,
1059}
1060
1061/// Represents a reference expression.
1062///
1063/// A reference expression tracks how an identifier resolves through the lexical
1064/// scope, imports, and field accesses. It maintains a chain of resolution steps
1065/// to support features like go-to-definition, go-to-reference, and type
1066/// inference.
1067///
1068/// # Resolution Chain
1069///
1070/// The fields form a resolution chain: `root` -> `step` -> `decl`, where:
1071/// - `root` is the original source of the value
1072/// - `step` is any intermediate transformation
1073/// - `decl` is the final identifier being referenced
1074/// - `term` is the resolved type (if known)
1075///   - Hint: A value `1`'s typst type is `int`, but here we keep the type as
1076///     `1` to improve the type inference.
1077///
1078/// # Examples
1079///
1080/// ## Simple identifier reference
1081/// ```rust,ignore
1082/// // For: let x = value; let y = x;
1083/// RefExpr {
1084///     decl: y,           // The identifier 'y'
1085///     root: Some(x),     // Points back to 'x'
1086///     step: Some(x),     // Same as root for simple refs
1087///     term: None,        // Type may not be known yet
1088/// }
1089/// ```
1090///
1091/// ## Import with rename
1092/// ```rust,ignore
1093/// // For: import "mod.typ": old as new
1094/// // First creates ref for 'old':
1095/// RefExpr { decl: old, root: Some(mod.old), step: Some(field), term: Some(Func(() -> dict)) }
1096/// // Then creates ref for 'new':
1097/// RefExpr { decl: new, root: Some(mod.old), step: Some(old), term: Some(Func(() -> dict)) }
1098/// ```
1099///
1100/// ## Builtin definitions
1101/// ```rust,ignore
1102/// // For: std.length
1103/// RefExpr { decl: length, root: None, step: None, term: Some(Type(length)) }
1104/// ```
1105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1106pub struct RefExpr {
1107    /// The declaration being referenced (the final identifier in the chain).
1108    ///
1109    /// This is always set and represents the identifier at the current point
1110    /// of reference (e.g., the variable name, import alias, or field name).
1111    pub decl: DeclExpr,
1112
1113    /// The intermediate expression in the resolution chain.
1114    ///
1115    /// Set in the following cases:
1116    /// - **Import/include**: The module expression being imported
1117    /// - **Field access**: The selected field's expression
1118    /// - **Scope resolution**: The scope expression being resolved
1119    /// - **Renamed imports**: The original name before renaming
1120    ///
1121    /// `None` when the identifier is an undefined reference.
1122    pub step: Option<Expr>,
1123
1124    /// The root expression at the start of the reference chain.
1125    ///
1126    /// A root definition never references another root definition.
1127    pub root: Option<Expr>,
1128
1129    /// The final resolved type of the referenced value.
1130    ///
1131    /// Set whenever a type is known for the referenced value.
1132    ///
1133    /// Some reference doesn't have a root definition, but has a term. For
1134    /// example, `std.length` is termed as `Type(length)` while has no a
1135    /// definition.
1136    pub term: Option<Ty>,
1137}
1138
1139/// Represents a content reference expression.
1140#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1141pub struct ContentRefExpr {
1142    /// The identifier being referenced.
1143    pub ident: DeclExpr,
1144    /// The declaration this reference points to (if resolved).
1145    pub of: Option<DeclExpr>,
1146    /// The body content associated with the reference.
1147    pub body: Option<Expr>,
1148}
1149
1150/// Represents a field selection expression.
1151#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1152pub struct SelectExpr {
1153    /// The left-hand side expression being selected from.
1154    pub lhs: Expr,
1155    /// The key or field name being selected.
1156    pub key: DeclExpr,
1157    /// The span location of this selection.
1158    pub span: Span,
1159}
1160
1161impl SelectExpr {
1162    /// Creates a new SelectExpr with the given key and left-hand side.
1163    pub fn new(key: DeclExpr, lhs: Expr) -> Interned<Self> {
1164        Interned::new(Self {
1165            key,
1166            lhs,
1167            span: Span::detached(),
1168        })
1169    }
1170}
1171
1172/// Represents an arguments expression.
1173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1174pub struct ArgsExpr {
1175    /// The list of arguments.
1176    pub args: Vec<ArgExpr>,
1177    /// The span location of the argument list.
1178    pub span: Span,
1179}
1180
1181impl ArgsExpr {
1182    /// Creates a new ArgsExpr with the given span and arguments.
1183    pub fn new(span: Span, args: Vec<ArgExpr>) -> Interned<Self> {
1184        Interned::new(Self { args, span })
1185    }
1186}
1187
1188/// Represents an element expression.
1189#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1190pub struct ElementExpr {
1191    /// The Typst element type.
1192    pub elem: Element,
1193    /// The content expressions within this element.
1194    pub content: EcoVec<Expr>,
1195}
1196
1197/// Represents a function application expression.
1198#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1199pub struct ApplyExpr {
1200    /// The function expression being called.
1201    pub callee: Expr,
1202    /// The arguments passed to the function.
1203    pub args: Expr,
1204    /// The span location of the function call.
1205    pub span: Span,
1206}
1207
1208/// Represents a function expression.
1209#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1210pub struct FuncExpr {
1211    /// The declaration for this function.
1212    pub decl: DeclExpr,
1213    /// The parameter signature defining function inputs.
1214    pub params: PatternSig,
1215    /// The function body expression.
1216    pub body: Expr,
1217}
1218
1219/// Represents a let binding expression.
1220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1221pub struct LetExpr {
1222    /// Span of the pattern.
1223    pub span: Span,
1224    /// The pattern being bound (left side of assignment).
1225    pub pattern: Interned<Pattern>,
1226    /// The optional body expression (right side of assignment).
1227    pub body: Option<Expr>,
1228}
1229
1230/// Represents a show rule expression.
1231#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1232pub struct ShowExpr {
1233    /// Optional selector expression to determine what to show.
1234    pub selector: Option<Expr>,
1235    /// The edit function to apply to selected elements.
1236    pub edit: Expr,
1237}
1238
1239/// Represents a set rule expression.
1240#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1241pub struct SetExpr {
1242    /// The target element or function to set.
1243    pub target: Expr,
1244    /// The arguments to apply to the target.
1245    pub args: Expr,
1246    /// Optional condition for when to apply the set rule.
1247    pub cond: Option<Expr>,
1248}
1249
1250/// Represents an import expression.
1251#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1252pub struct ImportExpr {
1253    /// The reference expression for what is being imported.
1254    pub decl: Interned<RefExpr>,
1255}
1256
1257/// Represents an include expression.
1258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1259pub struct IncludeExpr {
1260    /// The source expression indicating what file or content to include.
1261    pub source: Expr,
1262}
1263
1264/// Represents a conditional (if) expression.
1265#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1266pub struct IfExpr {
1267    /// The condition expression to evaluate.
1268    pub cond: Expr,
1269    /// The expression to evaluate if condition is true.
1270    pub then: Expr,
1271    /// The expression to evaluate if condition is false.
1272    pub else_: Expr,
1273}
1274
1275/// Represents a while loop expression.
1276#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1277pub struct WhileExpr {
1278    /// The condition expression evaluated each iteration.
1279    pub cond: Expr,
1280    /// The body expression executed while condition is true.
1281    pub body: Expr,
1282}
1283
1284/// Represents a for loop expression.
1285#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1286pub struct ForExpr {
1287    /// The pattern to match each iteration value against.
1288    pub pattern: Interned<Pattern>,
1289    /// The expression that produces values to iterate over.
1290    pub iter: Expr,
1291    /// The body expression executed for each iteration.
1292    pub body: Expr,
1293}
1294
1295/// The kind of unary operation.
1296#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1297pub enum UnaryOp {
1298    /// The (arithmetic) positive operation.
1299    /// `+t`
1300    Pos,
1301    /// The (arithmetic) negate operation.
1302    /// `-t`
1303    Neg,
1304    /// The (logical) not operation.
1305    /// `not t`
1306    Not,
1307    /// The return operation.
1308    /// `return t`
1309    Return,
1310    /// The typst context operation.
1311    /// `context t`
1312    Context,
1313    /// The spreading operation.
1314    /// `..t`
1315    Spread,
1316    /// The not element of operation.
1317    /// `not in t`
1318    NotElementOf,
1319    /// The element of operation.
1320    /// `in t`
1321    ElementOf,
1322    /// The type of operation.
1323    /// `type(t)`
1324    TypeOf,
1325}
1326
1327/// A unary operation type.
1328#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1329pub struct UnInst<T> {
1330    /// The operand of the unary operation.
1331    pub lhs: T,
1332    /// The kind of the unary operation.
1333    pub op: UnaryOp,
1334}
1335
1336impl<T: Ord> PartialOrd for UnInst<T> {
1337    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1338        Some(self.cmp(other))
1339    }
1340}
1341
1342impl<T: Ord> Ord for UnInst<T> {
1343    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1344        let op_as_int = self.op as u8;
1345        let other_op_as_int = other.op as u8;
1346        op_as_int
1347            .cmp(&other_op_as_int)
1348            .then_with(|| self.lhs.cmp(&other.lhs))
1349    }
1350}
1351
1352impl UnInst<Expr> {
1353    /// Creates a unary operation type with the given operator and operand.
1354    pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1355        Interned::new(Self { lhs, op })
1356    }
1357}
1358
1359impl<T> UnInst<T> {
1360    /// Gets the operands of the unary operation.
1361    pub fn operands(&self) -> [&T; 1] {
1362        [&self.lhs]
1363    }
1364}
1365
1366/// Type alias for binary operation types.
1367pub type BinaryOp = ast::BinOp;
1368
1369/// A binary operation type.
1370#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1371pub struct BinInst<T> {
1372    /// The operands of the binary operation (left, right).
1373    pub operands: (T, T),
1374    /// The kind of the binary operation.
1375    pub op: BinaryOp,
1376}
1377
1378impl<T: Ord> PartialOrd for BinInst<T> {
1379    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1380        Some(self.cmp(other))
1381    }
1382}
1383
1384impl<T: Ord> Ord for BinInst<T> {
1385    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1386        let op_as_int = self.op as u8;
1387        let other_op_as_int = other.op as u8;
1388        op_as_int
1389            .cmp(&other_op_as_int)
1390            .then_with(|| self.operands.cmp(&other.operands))
1391    }
1392}
1393
1394impl BinInst<Expr> {
1395    /// Creates a binary operation type with the given operator and operands.
1396    pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Interned<Self> {
1397        Interned::new(Self {
1398            operands: (lhs, rhs),
1399            op,
1400        })
1401    }
1402}
1403
1404impl<T> BinInst<T> {
1405    /// Gets the operands of the binary operation.
1406    pub fn operands(&self) -> [&T; 2] {
1407        [&self.operands.0, &self.operands.1]
1408    }
1409}
1410
1411/// Checks if a scope is empty.
1412fn is_empty_scope(scope: &typst::foundations::Scope) -> bool {
1413    scope.iter().next().is_none()
1414}
1415
1416impl_internable!(
1417    Expr,
1418    ArgsExpr,
1419    ElementExpr,
1420    ContentSeqExpr,
1421    RefExpr,
1422    ContentRefExpr,
1423    SelectExpr,
1424    ImportExpr,
1425    IncludeExpr,
1426    IfExpr,
1427    WhileExpr,
1428    ForExpr,
1429    FuncExpr,
1430    LetExpr,
1431    ShowExpr,
1432    SetExpr,
1433    Pattern,
1434    EcoVec<(Decl, Expr)>,
1435    Vec<ArgExpr>,
1436    Vec<Expr>,
1437    UnInst<Expr>,
1438    BinInst<Expr>,
1439    ApplyExpr,
1440);