1use 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#[derive(Debug, Clone, Hash)]
35pub struct ExprInfo(Arc<LazyHash<ExprInfoRepr>>);
36
37impl ExprInfo {
38 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#[derive(Debug)]
61pub struct ExprInfoRepr {
62 pub fid: TypstFileId,
64 pub revision: usize,
66 pub source: Source,
68 pub root: Expr,
70 pub module_docstring: Arc<DocString>,
72 pub exports: Arc<LazyHash<LexicalScope>>,
74 pub imports: FxHashMap<TypstFileId, Arc<LazyHash<LexicalScope>>>,
76 pub exprs: FxHashMap<Span, Expr>,
78 pub resolves: FxHashMap<Span, Interned<RefExpr>>,
80 pub docstrings: FxHashMap<DeclExpr, Arc<DocString>>,
82 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 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 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 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 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 #[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#[derive(Debug, Clone, Hash)]
176pub struct ModuleItemLayout {
177 pub parent: Interned<Decl>,
179 pub item_range: Range<usize>,
181 pub binding_range: Range<usize>,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190pub enum Expr {
191 Block(Interned<Vec<Expr>>),
193 Array(Interned<ArgsExpr>),
195 Dict(Interned<ArgsExpr>),
197 Args(Interned<ArgsExpr>),
199 Pattern(Interned<Pattern>),
201 Element(Interned<ElementExpr>),
203 Unary(Interned<UnExpr>),
205 Binary(Interned<BinExpr>),
207 Apply(Interned<ApplyExpr>),
209 Func(Interned<FuncExpr>),
211 Let(Interned<LetExpr>),
213 Show(Interned<ShowExpr>),
215 Set(Interned<SetExpr>),
217 Ref(Interned<RefExpr>),
219 ContentRef(Interned<ContentRefExpr>),
221 Select(Interned<SelectExpr>),
223 Import(Interned<ImportExpr>),
225 Include(Interned<IncludeExpr>),
227 Contextual(Interned<Expr>),
229 Conditional(Interned<IfExpr>),
231 WhileLoop(Interned<WhileExpr>),
233 ForLoop(Interned<ForExpr>),
235 Type(Ty),
237 Decl(DeclExpr),
239 Star,
241}
242
243impl Expr {
244 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 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 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 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 _ => 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
286pub type LexicalScope = rpds::RedBlackTreeMapSync<Interned<str>, Expr>;
290
291#[derive(Debug, Clone)]
296pub enum ExprScope {
297 Lexical(LexicalScope),
299 Module(Module),
301 Func(Func),
303 Type(Type),
305}
306
307impl ExprScope {
308 pub fn empty() -> Self {
310 ExprScope::Lexical(LexicalScope::default())
311 }
312
313 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 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 (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 (
346 of,
347 val.cloned()
348 .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))),
349 )
350 }
351
352 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#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
394#[serde(rename_all = "camelCase")]
395pub enum DefKind {
396 #[default]
398 Constant,
399 Function,
401 Variable,
403 Module,
405 Struct,
407 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
424pub type DeclExpr = Interned<Decl>;
426
427#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
429pub enum Decl {
430 Func(SpannedDecl),
432 ImportAlias(SpannedDecl),
434 Var(SpannedDecl),
436 IdentRef(SpannedDecl),
438 Module(ModuleDecl),
440 ModuleAlias(SpannedDecl),
442 PathStem(SpannedDecl),
444 ImportPath(SpannedDecl),
446 IncludePath(SpannedDecl),
448 Import(SpannedDecl),
450 ContentRef(SpannedDecl),
452 Label(SpannedDecl),
454 StrName(SpannedDecl),
456 ModuleImport(SpanDecl),
458 Closure(SpanDecl),
460 Pattern(SpanDecl),
462 Spread(SpanDecl),
464 Content(SpanDecl),
466 Constant(SpanDecl),
468 BibEntry(NameRangeDecl),
470 Docs(DocsDecl),
472 Generated(GeneratedDecl),
474}
475
476impl Decl {
477 pub fn func(ident: ast::Ident) -> Self {
479 Self::Func(SpannedDecl {
480 name: ident.get().into(),
481 at: ident.span(),
482 })
483 }
484
485 pub fn lit(name: &str) -> Self {
487 Self::Var(SpannedDecl {
488 name: name.into(),
489 at: Span::detached(),
490 })
491 }
492
493 pub fn lit_(name: Interned<str>) -> Self {
495 Self::Var(SpannedDecl {
496 name,
497 at: Span::detached(),
498 })
499 }
500
501 pub fn var(ident: ast::Ident) -> Self {
503 Self::Var(SpannedDecl {
504 name: ident.get().into(),
505 at: ident.span(),
506 })
507 }
508
509 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 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 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 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 pub fn module_with_name(name: Interned<str>, fid: TypstFileId) -> Self {
545 Self::Module(ModuleDecl { name, fid })
546 }
547
548 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 pub fn import(ident: ast::Ident) -> Self {
558 Self::Import(SpannedDecl {
559 name: ident.get().into(),
560 at: ident.span(),
561 })
562 }
563
564 pub fn label(name: &str, at: Span) -> Self {
566 Self::Label(SpannedDecl {
567 name: name.into(),
568 at,
569 })
570 }
571
572 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 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 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 pub fn path_stem(s: SyntaxNode, name: Interned<str>) -> Self {
615 Self::PathStem(SpannedDecl { name, at: s.span() })
616 }
617
618 pub fn import_path(s: Span, name: Interned<str>) -> Self {
620 Self::ImportPath(SpannedDecl { name, at: s })
621 }
622
623 pub fn include_path(s: Span, name: Interned<str>) -> Self {
625 Self::IncludePath(SpannedDecl { name, at: s })
626 }
627
628 pub fn module_import(s: Span) -> Self {
630 Self::ModuleImport(SpanDecl(s))
631 }
632
633 pub fn closure(s: Span) -> Self {
635 Self::Closure(SpanDecl(s))
636 }
637
638 pub fn pattern(s: Span) -> Self {
640 Self::Pattern(SpanDecl(s))
641 }
642
643 pub fn spread(s: Span) -> Self {
645 Self::Spread(SpanDecl(s))
646 }
647
648 pub fn content(s: Span) -> Self {
650 Self::Content(SpanDecl(s))
651 }
652
653 pub fn constant(s: Span) -> Self {
655 Self::Constant(SpanDecl(s))
656 }
657
658 pub fn docs(base: Interned<Decl>, var: Interned<TypeVar>) -> Self {
661 Self::Docs(DocsDecl { base, var })
662 }
663
664 pub fn generated(def_id: DefId) -> Self {
666 Self::Generated(GeneratedDecl(def_id))
667 }
668
669 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 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 pub fn kind(&self) -> DefKind {
705 use Decl::*;
706 match self {
707 ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
708 DefKind::Module
709 }
710 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 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 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 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 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering;
766}
767
768impl Decl {
769 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#[derive(Clone, PartialEq, Eq, Hash)]
832pub struct SpannedDecl {
833 name: Interned<str>,
835 at: Span,
837}
838
839impl SpannedDecl {
840 fn name(&self) -> &Interned<str> {
842 &self.name
843 }
844
845 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#[derive(Clone, PartialEq, Eq, Hash)]
859pub struct NameRangeDecl {
860 pub name: Interned<str>,
862 pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
864}
865
866impl NameRangeDecl {
867 fn name(&self) -> &Interned<str> {
869 &self.name
870 }
871
872 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#[derive(Clone, PartialEq, Eq, Hash)]
886pub struct ModuleDecl {
887 pub name: Interned<str>,
889 pub fid: TypstFileId,
891}
892
893impl ModuleDecl {
894 fn name(&self) -> &Interned<str> {
896 &self.name
897 }
898
899 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#[derive(Clone, PartialEq, Eq, Hash)]
913pub struct DocsDecl {
914 base: Interned<Decl>,
915 var: Interned<TypeVar>,
916}
917
918impl DocsDecl {
919 fn name(&self) -> &Interned<str> {
921 Interned::empty()
922 }
923
924 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#[derive(Clone, PartialEq, Eq, Hash)]
938pub struct SpanDecl(Span);
939
940impl SpanDecl {
941 fn name(&self) -> &Interned<str> {
943 Interned::empty()
944 }
945
946 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#[derive(Clone, PartialEq, Eq, Hash)]
960pub struct GeneratedDecl(DefId);
961
962impl GeneratedDecl {
963 fn name(&self) -> &Interned<str> {
965 Interned::empty()
966 }
967
968 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
980pub type UnExpr = UnInst<Expr>;
982pub type BinExpr = BinInst<Expr>;
984
985pub type ExportMap = BTreeMap<Interned<str>, Expr>;
989
990#[derive(Debug, Clone, PartialEq, Eq, Hash)]
994pub enum ArgExpr {
995 Pos(Expr),
997 Named(Box<(DeclExpr, Expr)>),
999 NamedRt(Box<(Expr, Expr)>),
1001 Spread(Expr),
1003}
1004
1005#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1007pub enum Pattern {
1008 Expr(Expr),
1011 Simple(Interned<Decl>),
1013 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 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1037pub struct PatternSig {
1038 pub pos: EcoVec<Interned<Pattern>>,
1040 pub named: EcoVec<(DeclExpr, Interned<Pattern>)>,
1042 pub spread_left: Option<(DeclExpr, Interned<Pattern>)>,
1044 pub spread_right: Option<(DeclExpr, Interned<Pattern>)>,
1046}
1047
1048impl Pattern {}
1049
1050impl_internable!(Decl,);
1051
1052#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1056pub struct ContentSeqExpr {
1057 pub ty: Ty,
1059}
1060
1061#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1106pub struct RefExpr {
1107 pub decl: DeclExpr,
1112
1113 pub step: Option<Expr>,
1123
1124 pub root: Option<Expr>,
1128
1129 pub term: Option<Ty>,
1137}
1138
1139#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1141pub struct ContentRefExpr {
1142 pub ident: DeclExpr,
1144 pub of: Option<DeclExpr>,
1146 pub body: Option<Expr>,
1148}
1149
1150#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1152pub struct SelectExpr {
1153 pub lhs: Expr,
1155 pub key: DeclExpr,
1157 pub span: Span,
1159}
1160
1161impl SelectExpr {
1162 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1174pub struct ArgsExpr {
1175 pub args: Vec<ArgExpr>,
1177 pub span: Span,
1179}
1180
1181impl ArgsExpr {
1182 pub fn new(span: Span, args: Vec<ArgExpr>) -> Interned<Self> {
1184 Interned::new(Self { args, span })
1185 }
1186}
1187
1188#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1190pub struct ElementExpr {
1191 pub elem: Element,
1193 pub content: EcoVec<Expr>,
1195}
1196
1197#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1199pub struct ApplyExpr {
1200 pub callee: Expr,
1202 pub args: Expr,
1204 pub span: Span,
1206}
1207
1208#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1210pub struct FuncExpr {
1211 pub decl: DeclExpr,
1213 pub params: PatternSig,
1215 pub body: Expr,
1217}
1218
1219#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1221pub struct LetExpr {
1222 pub span: Span,
1224 pub pattern: Interned<Pattern>,
1226 pub body: Option<Expr>,
1228}
1229
1230#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1232pub struct ShowExpr {
1233 pub selector: Option<Expr>,
1235 pub edit: Expr,
1237}
1238
1239#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1241pub struct SetExpr {
1242 pub target: Expr,
1244 pub args: Expr,
1246 pub cond: Option<Expr>,
1248}
1249
1250#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1252pub struct ImportExpr {
1253 pub source: Expr,
1255 pub decl: Interned<RefExpr>,
1257}
1258
1259#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1261pub struct IncludeExpr {
1262 pub source: Expr,
1264}
1265
1266#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1268pub struct IfExpr {
1269 pub cond: Expr,
1271 pub then: Expr,
1273 pub else_: Expr,
1275}
1276
1277#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1279pub struct WhileExpr {
1280 pub cond: Expr,
1282 pub body: Expr,
1284}
1285
1286#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1288pub struct ForExpr {
1289 pub pattern: Interned<Pattern>,
1291 pub iter: Expr,
1293 pub body: Expr,
1295}
1296
1297#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1299pub enum UnaryOp {
1300 Pos,
1303 Neg,
1306 Not,
1309 Return,
1312 Context,
1315 Spread,
1318 NotElementOf,
1321 ElementOf,
1324 TypeOf,
1327}
1328
1329#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1331pub struct UnInst<T> {
1332 pub lhs: T,
1334 pub op: UnaryOp,
1336}
1337
1338impl<T: Ord> PartialOrd for UnInst<T> {
1339 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1340 Some(self.cmp(other))
1341 }
1342}
1343
1344impl<T: Ord> Ord for UnInst<T> {
1345 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1346 let op_as_int = self.op as u8;
1347 let other_op_as_int = other.op as u8;
1348 op_as_int
1349 .cmp(&other_op_as_int)
1350 .then_with(|| self.lhs.cmp(&other.lhs))
1351 }
1352}
1353
1354impl UnInst<Expr> {
1355 pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1357 Interned::new(Self { lhs, op })
1358 }
1359}
1360
1361impl<T> UnInst<T> {
1362 pub fn operands(&self) -> [&T; 1] {
1364 [&self.lhs]
1365 }
1366}
1367
1368pub type BinaryOp = ast::BinOp;
1370
1371#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1373pub struct BinInst<T> {
1374 pub operands: (T, T),
1376 pub op: BinaryOp,
1378}
1379
1380impl<T: Ord> PartialOrd for BinInst<T> {
1381 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1382 Some(self.cmp(other))
1383 }
1384}
1385
1386impl<T: Ord> Ord for BinInst<T> {
1387 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1388 let op_as_int = self.op as u8;
1389 let other_op_as_int = other.op as u8;
1390 op_as_int
1391 .cmp(&other_op_as_int)
1392 .then_with(|| self.operands.cmp(&other.operands))
1393 }
1394}
1395
1396impl BinInst<Expr> {
1397 pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Interned<Self> {
1399 Interned::new(Self {
1400 operands: (lhs, rhs),
1401 op,
1402 })
1403 }
1404}
1405
1406impl<T> BinInst<T> {
1407 pub fn operands(&self) -> [&T; 2] {
1409 [&self.operands.0, &self.operands.1]
1410 }
1411}
1412
1413fn is_empty_scope(scope: &typst::foundations::Scope) -> bool {
1415 scope.iter().next().is_none()
1416}
1417
1418impl_internable!(
1419 Expr,
1420 ArgsExpr,
1421 ElementExpr,
1422 ContentSeqExpr,
1423 RefExpr,
1424 ContentRefExpr,
1425 SelectExpr,
1426 ImportExpr,
1427 IncludeExpr,
1428 IfExpr,
1429 WhileExpr,
1430 ForExpr,
1431 FuncExpr,
1432 LetExpr,
1433 ShowExpr,
1434 SetExpr,
1435 Pattern,
1436 EcoVec<(Decl, Expr)>,
1437 Vec<ArgExpr>,
1438 Vec<Expr>,
1439 UnInst<Expr>,
1440 BinInst<Expr>,
1441 ApplyExpr,
1442);