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 decl: Interned<RefExpr>,
1255}
1256
1257#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1259pub struct IncludeExpr {
1260 pub source: Expr,
1262}
1263
1264#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1266pub struct IfExpr {
1267 pub cond: Expr,
1269 pub then: Expr,
1271 pub else_: Expr,
1273}
1274
1275#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1277pub struct WhileExpr {
1278 pub cond: Expr,
1280 pub body: Expr,
1282}
1283
1284#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1286pub struct ForExpr {
1287 pub pattern: Interned<Pattern>,
1289 pub iter: Expr,
1291 pub body: Expr,
1293}
1294
1295#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1297pub enum UnaryOp {
1298 Pos,
1301 Neg,
1304 Not,
1307 Return,
1310 Context,
1313 Spread,
1316 NotElementOf,
1319 ElementOf,
1322 TypeOf,
1325}
1326
1327#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1329pub struct UnInst<T> {
1330 pub lhs: T,
1332 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 pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1355 Interned::new(Self { lhs, op })
1356 }
1357}
1358
1359impl<T> UnInst<T> {
1360 pub fn operands(&self) -> [&T; 1] {
1362 [&self.lhs]
1363 }
1364}
1365
1366pub type BinaryOp = ast::BinOp;
1368
1369#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1371pub struct BinInst<T> {
1372 pub operands: (T, T),
1374 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 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 pub fn operands(&self) -> [&T; 2] {
1407 [&self.operands.0, &self.operands.1]
1408 }
1409}
1410
1411fn 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);