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