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}
83
84impl std::hash::Hash for ExprInfoRepr {
85 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
86 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 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 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 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 #[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
172pub enum Expr {
173 Block(Interned<Vec<Expr>>),
175 Array(Interned<ArgsExpr>),
177 Dict(Interned<ArgsExpr>),
179 Args(Interned<ArgsExpr>),
181 Pattern(Interned<Pattern>),
183 Element(Interned<ElementExpr>),
185 Unary(Interned<UnExpr>),
187 Binary(Interned<BinExpr>),
189 Apply(Interned<ApplyExpr>),
191 Func(Interned<FuncExpr>),
193 Let(Interned<LetExpr>),
195 Show(Interned<ShowExpr>),
197 Set(Interned<SetExpr>),
199 Ref(Interned<RefExpr>),
201 ContentRef(Interned<ContentRefExpr>),
203 Select(Interned<SelectExpr>),
205 Import(Interned<ImportExpr>),
207 Include(Interned<IncludeExpr>),
209 Contextual(Interned<Expr>),
211 Conditional(Interned<IfExpr>),
213 WhileLoop(Interned<WhileExpr>),
215 ForLoop(Interned<ForExpr>),
217 Type(Ty),
219 Decl(DeclExpr),
221 Star,
223}
224
225impl Expr {
226 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 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 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 pub fn is_defined(&self) -> bool {
253 match self {
254 Expr::Ref(refs) => refs.root.is_some() || refs.term.is_some(),
255 Expr::Decl(decl) => decl.is_def(),
256 _ => false,
258 }
259 }
260}
261
262impl fmt::Display for Expr {
263 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264 ExprPrinter::new(f).write_expr(self)
265 }
266}
267
268pub type LexicalScope = rpds::RedBlackTreeMapSync<Interned<str>, Expr>;
272
273#[derive(Debug, Clone)]
278pub enum ExprScope {
279 Lexical(LexicalScope),
281 Module(Module),
283 Func(Func),
285 Type(Type),
287}
288
289impl ExprScope {
290 pub fn empty() -> Self {
292 ExprScope::Lexical(LexicalScope::default())
293 }
294
295 pub fn is_empty(&self) -> bool {
297 match self {
298 ExprScope::Lexical(scope) => scope.is_empty(),
299 ExprScope::Module(module) => is_empty_scope(module.scope()),
300 ExprScope::Func(func) => func.scope().is_none_or(is_empty_scope),
301 ExprScope::Type(ty) => is_empty_scope(ty.scope()),
302 }
303 }
304
305 pub fn get(&self, name: &Interned<str>) -> (Option<Expr>, Option<Ty>) {
308 let (of, val) = match self {
309 ExprScope::Lexical(scope) => {
310 crate::log_debug_ct!("evaluating: {name:?} in {scope:?}");
311 (scope.get(name).cloned(), None)
312 }
313 ExprScope::Module(module) => {
314 let v = module.scope().get(name);
315 (None, v)
319 }
320 ExprScope::Func(func) => (None, func.scope().unwrap().get(name)),
321 ExprScope::Type(ty) => (None, ty.scope().get(name)),
322 };
323
324 (
328 of,
329 val.cloned()
330 .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))),
331 )
332 }
333
334 pub fn merge_into(&self, exports: &mut LexicalScope) {
336 match self {
337 ExprScope::Lexical(scope) => {
338 for (name, expr) in scope.iter() {
339 exports.insert_mut(name.clone(), expr.clone());
340 }
341 }
342 ExprScope::Module(module) => {
343 crate::log_debug_ct!("imported: {module:?}");
344 let v = Interned::new(Ty::Value(InsTy::new(Value::Module(module.clone()))));
345 for (name, _) in module.scope().iter() {
346 let name: Interned<str> = name.into();
347 exports.insert_mut(name.clone(), select_of(v.clone(), name));
348 }
349 }
350 ExprScope::Func(func) => {
351 if let Some(scope) = func.scope() {
352 let v = Interned::new(Ty::Value(InsTy::new(Value::Func(func.clone()))));
353 for (name, _) in scope.iter() {
354 let name: Interned<str> = name.into();
355 exports.insert_mut(name.clone(), select_of(v.clone(), name));
356 }
357 }
358 }
359 ExprScope::Type(ty) => {
360 let v = Interned::new(Ty::Value(InsTy::new(Value::Type(*ty))));
361 for (name, _) in ty.scope().iter() {
362 let name: Interned<str> = name.into();
363 exports.insert_mut(name.clone(), select_of(v.clone(), name));
364 }
365 }
366 }
367 }
368}
369
370fn select_of(source: Interned<Ty>, name: Interned<str>) -> Expr {
371 Expr::Type(Ty::Select(SelectTy::new(source, name)))
372}
373
374#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
376#[serde(rename_all = "camelCase")]
377pub enum DefKind {
378 #[default]
380 Constant,
381 Function,
383 Variable,
385 Module,
387 Struct,
389 Reference,
391}
392
393impl fmt::Display for DefKind {
394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395 match self {
396 Self::Constant => write!(f, "constant"),
397 Self::Function => write!(f, "function"),
398 Self::Variable => write!(f, "variable"),
399 Self::Module => write!(f, "module"),
400 Self::Struct => write!(f, "struct"),
401 Self::Reference => write!(f, "reference"),
402 }
403 }
404}
405
406pub type DeclExpr = Interned<Decl>;
408
409#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
411pub enum Decl {
412 Func(SpannedDecl),
414 ImportAlias(SpannedDecl),
416 Var(SpannedDecl),
418 IdentRef(SpannedDecl),
420 Module(ModuleDecl),
422 ModuleAlias(SpannedDecl),
424 PathStem(SpannedDecl),
426 ImportPath(SpannedDecl),
428 IncludePath(SpannedDecl),
430 Import(SpannedDecl),
432 ContentRef(SpannedDecl),
434 Label(SpannedDecl),
436 StrName(SpannedDecl),
438 ModuleImport(SpanDecl),
440 Closure(SpanDecl),
442 Pattern(SpanDecl),
444 Spread(SpanDecl),
446 Content(SpanDecl),
448 Constant(SpanDecl),
450 BibEntry(NameRangeDecl),
452 Docs(DocsDecl),
454 Generated(GeneratedDecl),
456}
457
458impl Decl {
459 pub fn func(ident: ast::Ident) -> Self {
461 Self::Func(SpannedDecl {
462 name: ident.get().into(),
463 at: ident.span(),
464 })
465 }
466
467 pub fn lit(name: &str) -> Self {
469 Self::Var(SpannedDecl {
470 name: name.into(),
471 at: Span::detached(),
472 })
473 }
474
475 pub fn lit_(name: Interned<str>) -> Self {
477 Self::Var(SpannedDecl {
478 name,
479 at: Span::detached(),
480 })
481 }
482
483 pub fn var(ident: ast::Ident) -> Self {
485 Self::Var(SpannedDecl {
486 name: ident.get().into(),
487 at: ident.span(),
488 })
489 }
490
491 pub fn import_alias(ident: ast::Ident) -> Self {
493 Self::ImportAlias(SpannedDecl {
494 name: ident.get().into(),
495 at: ident.span(),
496 })
497 }
498
499 pub fn ident_ref(ident: ast::Ident) -> Self {
501 Self::IdentRef(SpannedDecl {
502 name: ident.get().into(),
503 at: ident.span(),
504 })
505 }
506
507 pub fn math_ident_ref(ident: ast::MathIdent) -> Self {
509 Self::IdentRef(SpannedDecl {
510 name: ident.get().into(),
511 at: ident.span(),
512 })
513 }
514
515 pub fn module(fid: TypstFileId) -> Self {
517 let name = {
518 let stem = fid.vpath().as_rooted_path().file_stem();
519 stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
520 .unwrap_or_default()
521 };
522 Self::Module(ModuleDecl { name, fid })
523 }
524
525 pub fn module_with_name(name: Interned<str>, fid: TypstFileId) -> Self {
527 Self::Module(ModuleDecl { name, fid })
528 }
529
530 pub fn module_alias(ident: ast::Ident) -> Self {
532 Self::ModuleAlias(SpannedDecl {
533 name: ident.get().into(),
534 at: ident.span(),
535 })
536 }
537
538 pub fn import(ident: ast::Ident) -> Self {
540 Self::Import(SpannedDecl {
541 name: ident.get().into(),
542 at: ident.span(),
543 })
544 }
545
546 pub fn label(name: &str, at: Span) -> Self {
548 Self::Label(SpannedDecl {
549 name: name.into(),
550 at,
551 })
552 }
553
554 pub fn ref_(ident: ast::Ref) -> Self {
556 Self::ContentRef(SpannedDecl {
557 name: ident.target().into(),
558 at: ident.span(),
559 })
560 }
561
562 pub fn str_name(s: SyntaxNode, name: &str) -> Decl {
564 Self::StrName(SpannedDecl {
565 name: name.into(),
566 at: s.span(),
567 })
568 }
569
570 pub fn calc_path_stem(s: &str) -> Interned<str> {
576 use std::str::FromStr;
577 let name = if s.starts_with('@') {
578 let spec = PackageSpec::from_str(s).ok();
579 spec.map(|spec| Interned::new_str(spec.name.as_str()))
580 } else {
581 let stem = Path::new(s).file_stem();
582 stem.and_then(|stem| Some(Interned::new_str(stem.to_str()?)))
583 };
584 name.unwrap_or_default()
585 }
586
587 pub fn path_stem(s: SyntaxNode, name: Interned<str>) -> Self {
589 Self::PathStem(SpannedDecl { name, at: s.span() })
590 }
591
592 pub fn import_path(s: Span, name: Interned<str>) -> Self {
594 Self::ImportPath(SpannedDecl { name, at: s })
595 }
596
597 pub fn include_path(s: Span, name: Interned<str>) -> Self {
599 Self::IncludePath(SpannedDecl { name, at: s })
600 }
601
602 pub fn module_import(s: Span) -> Self {
604 Self::ModuleImport(SpanDecl(s))
605 }
606
607 pub fn closure(s: Span) -> Self {
609 Self::Closure(SpanDecl(s))
610 }
611
612 pub fn pattern(s: Span) -> Self {
614 Self::Pattern(SpanDecl(s))
615 }
616
617 pub fn spread(s: Span) -> Self {
619 Self::Spread(SpanDecl(s))
620 }
621
622 pub fn content(s: Span) -> Self {
624 Self::Content(SpanDecl(s))
625 }
626
627 pub fn constant(s: Span) -> Self {
629 Self::Constant(SpanDecl(s))
630 }
631
632 pub fn docs(base: Interned<Decl>, var: Interned<TypeVar>) -> Self {
635 Self::Docs(DocsDecl { base, var })
636 }
637
638 pub fn generated(def_id: DefId) -> Self {
640 Self::Generated(GeneratedDecl(def_id))
641 }
642
643 pub fn bib_entry(
645 name: Interned<str>,
646 fid: TypstFileId,
647 name_range: Range<usize>,
648 range: Option<Range<usize>>,
649 ) -> Self {
650 Self::BibEntry(NameRangeDecl {
651 name,
652 at: Box::new((fid, name_range, range)),
653 })
654 }
655
656 pub fn is_def(&self) -> bool {
659 matches!(
660 self,
661 Self::Func(..)
662 | Self::BibEntry(..)
663 | Self::Closure(..)
664 | Self::Var(..)
665 | Self::Label(..)
666 | Self::StrName(..)
667 | Self::Module(..)
668 | Self::ModuleImport(..)
669 | Self::PathStem(..)
670 | Self::ImportPath(..)
671 | Self::IncludePath(..)
672 | Self::Spread(..)
673 | Self::Generated(..)
674 )
675 }
676
677 pub fn kind(&self) -> DefKind {
679 use Decl::*;
680 match self {
681 ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
682 DefKind::Module
683 }
684 Func(..) | Closure(..) => DefKind::Function,
686 Label(..) | BibEntry(..) | ContentRef(..) => DefKind::Reference,
687 IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => DefKind::Variable,
688 Pattern(..) | Docs(..) | Generated(..) | Constant(..) | StrName(..)
689 | ModuleImport(..) | Content(..) | Spread(..) => DefKind::Constant,
690 }
691 }
692
693 pub fn file_id(&self) -> Option<TypstFileId> {
695 match self {
696 Self::Module(ModuleDecl { fid, .. }) => Some(*fid),
697 Self::BibEntry(NameRangeDecl { at, .. }) => Some(at.0),
698 that => that.span().id(),
699 }
700 }
701
702 pub fn full_range(&self) -> Option<Range<usize>> {
704 if let Decl::BibEntry(decl) = self {
705 return decl.at.2.clone();
706 }
707
708 None
709 }
710
711 pub fn as_def(this: &Interned<Self>, val: Option<Ty>) -> Interned<RefExpr> {
713 let def: Expr = this.clone().into();
714 Interned::new(RefExpr {
715 decl: this.clone(),
716 step: Some(def.clone()),
717 root: Some(def),
718 term: val,
719 })
720 }
721}
722
723impl Ord for Decl {
724 fn 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.cmp(&r.fid),
728 (Self::Docs(l), Self::Docs(r)) => l.var.cmp(&r.var).then_with(|| l.base.cmp(&r.base)),
729 _ => self.span().into_raw().cmp(&other.span().into_raw()),
730 };
731
732 base.then_with(|| self.name().cmp(other.name()))
733 }
734}
735
736trait StrictCmp {
737 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering;
740}
741
742impl Decl {
743 pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
745 let base = match (self, other) {
746 (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
747 (Self::Module(l), Self::Module(r)) => l.fid.strict_cmp(&r.fid),
748 (Self::Docs(l), Self::Docs(r)) => l
749 .var
750 .strict_cmp(&r.var)
751 .then_with(|| l.base.strict_cmp(&r.base)),
752 _ => self.span().strict_cmp(&other.span()),
753 };
754
755 base.then_with(|| self.name().cmp(other.name()))
756 }
757}
758
759impl StrictCmp for TypstFileId {
760 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
761 self.package()
762 .map(ToString::to_string)
763 .cmp(&other.package().map(ToString::to_string))
764 .then_with(|| self.vpath().cmp(other.vpath()))
765 }
766}
767impl<T: StrictCmp> StrictCmp for Option<T> {
768 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
769 match (self, other) {
770 (Some(l), Some(r)) => l.strict_cmp(r),
771 (Some(_), None) => std::cmp::Ordering::Greater,
772 (None, Some(_)) => std::cmp::Ordering::Less,
773 (None, None) => std::cmp::Ordering::Equal,
774 }
775 }
776}
777
778impl StrictCmp for Span {
779 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
780 self.id()
781 .strict_cmp(&other.id())
782 .then_with(|| self.into_raw().cmp(&other.into_raw()))
783 }
784}
785
786impl PartialOrd for Decl {
787 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
788 Some(self.cmp(other))
789 }
790}
791
792impl From<Decl> for Expr {
793 fn from(decl: Decl) -> Self {
794 Expr::Decl(decl.into())
795 }
796}
797
798impl From<DeclExpr> for Expr {
799 fn from(decl: DeclExpr) -> Self {
800 Expr::Decl(decl)
801 }
802}
803
804#[derive(Clone, PartialEq, Eq, Hash)]
806pub struct SpannedDecl {
807 name: Interned<str>,
809 at: Span,
811}
812
813impl SpannedDecl {
814 fn name(&self) -> &Interned<str> {
816 &self.name
817 }
818
819 fn span(&self) -> Span {
821 self.at
822 }
823}
824
825impl fmt::Debug for SpannedDecl {
826 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827 f.write_str(self.name.as_ref())
828 }
829}
830
831#[derive(Clone, PartialEq, Eq, Hash)]
833pub struct NameRangeDecl {
834 pub name: Interned<str>,
836 pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
838}
839
840impl NameRangeDecl {
841 fn name(&self) -> &Interned<str> {
843 &self.name
844 }
845
846 fn span(&self) -> Span {
848 Span::detached()
849 }
850}
851
852impl fmt::Debug for NameRangeDecl {
853 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854 f.write_str(self.name.as_ref())
855 }
856}
857
858#[derive(Clone, PartialEq, Eq, Hash)]
860pub struct ModuleDecl {
861 pub name: Interned<str>,
863 pub fid: TypstFileId,
865}
866
867impl ModuleDecl {
868 fn name(&self) -> &Interned<str> {
870 &self.name
871 }
872
873 fn span(&self) -> Span {
875 Span::detached()
876 }
877}
878
879impl fmt::Debug for ModuleDecl {
880 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
881 f.write_str(self.name.as_ref())
882 }
883}
884
885#[derive(Clone, PartialEq, Eq, Hash)]
887pub struct DocsDecl {
888 base: Interned<Decl>,
889 var: Interned<TypeVar>,
890}
891
892impl DocsDecl {
893 fn name(&self) -> &Interned<str> {
895 Interned::empty()
896 }
897
898 fn span(&self) -> Span {
900 Span::detached()
901 }
902}
903
904impl fmt::Debug for DocsDecl {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 write!(f, "{:?}, {:?}", self.base, self.var)
907 }
908}
909
910#[derive(Clone, PartialEq, Eq, Hash)]
912pub struct SpanDecl(Span);
913
914impl SpanDecl {
915 fn name(&self) -> &Interned<str> {
917 Interned::empty()
918 }
919
920 fn span(&self) -> Span {
922 self.0
923 }
924}
925
926impl fmt::Debug for SpanDecl {
927 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
928 write!(f, "..")
929 }
930}
931
932#[derive(Clone, PartialEq, Eq, Hash)]
934pub struct GeneratedDecl(DefId);
935
936impl GeneratedDecl {
937 fn name(&self) -> &Interned<str> {
939 Interned::empty()
940 }
941
942 fn span(&self) -> Span {
944 Span::detached()
945 }
946}
947
948impl fmt::Debug for GeneratedDecl {
949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
950 self.0.fmt(f)
951 }
952}
953
954pub type UnExpr = UnInst<Expr>;
956pub type BinExpr = BinInst<Expr>;
958
959pub type ExportMap = BTreeMap<Interned<str>, Expr>;
963
964#[derive(Debug, Clone, PartialEq, Eq, Hash)]
968pub enum ArgExpr {
969 Pos(Expr),
971 Named(Box<(DeclExpr, Expr)>),
973 NamedRt(Box<(Expr, Expr)>),
975 Spread(Expr),
977}
978
979#[derive(Debug, Clone, PartialEq, Eq, Hash)]
981pub enum Pattern {
982 Expr(Expr),
985 Simple(Interned<Decl>),
987 Sig(Box<PatternSig>),
989}
990
991impl fmt::Display for Pattern {
992 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
993 ExprPrinter::new(f).write_pattern(self)
994 }
995}
996
997impl Pattern {
998 pub fn repr(&self) -> EcoString {
1000 let mut s = EcoString::new();
1001 let _ = ExprDescriber::new(&mut s).write_pattern(self);
1002 s
1003 }
1004}
1005
1006#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1011pub struct PatternSig {
1012 pub pos: EcoVec<Interned<Pattern>>,
1014 pub named: EcoVec<(DeclExpr, Interned<Pattern>)>,
1016 pub spread_left: Option<(DeclExpr, Interned<Pattern>)>,
1018 pub spread_right: Option<(DeclExpr, Interned<Pattern>)>,
1020}
1021
1022impl Pattern {}
1023
1024impl_internable!(Decl,);
1025
1026#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1030pub struct ContentSeqExpr {
1031 pub ty: Ty,
1033}
1034
1035#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1080pub struct RefExpr {
1081 pub decl: DeclExpr,
1086
1087 pub step: Option<Expr>,
1097
1098 pub root: Option<Expr>,
1102
1103 pub term: Option<Ty>,
1111}
1112
1113#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1115pub struct ContentRefExpr {
1116 pub ident: DeclExpr,
1118 pub of: Option<DeclExpr>,
1120 pub body: Option<Expr>,
1122}
1123
1124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1126pub struct SelectExpr {
1127 pub lhs: Expr,
1129 pub key: DeclExpr,
1131 pub span: Span,
1133}
1134
1135impl SelectExpr {
1136 pub fn new(key: DeclExpr, lhs: Expr) -> Interned<Self> {
1138 Interned::new(Self {
1139 key,
1140 lhs,
1141 span: Span::detached(),
1142 })
1143 }
1144}
1145
1146#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1148pub struct ArgsExpr {
1149 pub args: Vec<ArgExpr>,
1151 pub span: Span,
1153}
1154
1155impl ArgsExpr {
1156 pub fn new(span: Span, args: Vec<ArgExpr>) -> Interned<Self> {
1158 Interned::new(Self { args, span })
1159 }
1160}
1161
1162#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1164pub struct ElementExpr {
1165 pub elem: Element,
1167 pub content: EcoVec<Expr>,
1169}
1170
1171#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1173pub struct ApplyExpr {
1174 pub callee: Expr,
1176 pub args: Expr,
1178 pub span: Span,
1180}
1181
1182#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1184pub struct FuncExpr {
1185 pub decl: DeclExpr,
1187 pub params: PatternSig,
1189 pub body: Expr,
1191}
1192
1193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1195pub struct LetExpr {
1196 pub span: Span,
1198 pub pattern: Interned<Pattern>,
1200 pub body: Option<Expr>,
1202}
1203
1204#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1206pub struct ShowExpr {
1207 pub selector: Option<Expr>,
1209 pub edit: Expr,
1211}
1212
1213#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1215pub struct SetExpr {
1216 pub target: Expr,
1218 pub args: Expr,
1220 pub cond: Option<Expr>,
1222}
1223
1224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1226pub struct ImportExpr {
1227 pub decl: Interned<RefExpr>,
1229}
1230
1231#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1233pub struct IncludeExpr {
1234 pub source: Expr,
1236}
1237
1238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1240pub struct IfExpr {
1241 pub cond: Expr,
1243 pub then: Expr,
1245 pub else_: Expr,
1247}
1248
1249#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1251pub struct WhileExpr {
1252 pub cond: Expr,
1254 pub body: Expr,
1256}
1257
1258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1260pub struct ForExpr {
1261 pub pattern: Interned<Pattern>,
1263 pub iter: Expr,
1265 pub body: Expr,
1267}
1268
1269#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1271pub enum UnaryOp {
1272 Pos,
1275 Neg,
1278 Not,
1281 Return,
1284 Context,
1287 Spread,
1290 NotElementOf,
1293 ElementOf,
1296 TypeOf,
1299}
1300
1301#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1303pub struct UnInst<T> {
1304 pub lhs: T,
1306 pub op: UnaryOp,
1308}
1309
1310impl<T: Ord> PartialOrd for UnInst<T> {
1311 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1312 Some(self.cmp(other))
1313 }
1314}
1315
1316impl<T: Ord> Ord for UnInst<T> {
1317 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1318 let op_as_int = self.op as u8;
1319 let other_op_as_int = other.op as u8;
1320 op_as_int
1321 .cmp(&other_op_as_int)
1322 .then_with(|| self.lhs.cmp(&other.lhs))
1323 }
1324}
1325
1326impl UnInst<Expr> {
1327 pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1329 Interned::new(Self { lhs, op })
1330 }
1331}
1332
1333impl<T> UnInst<T> {
1334 pub fn operands(&self) -> [&T; 1] {
1336 [&self.lhs]
1337 }
1338}
1339
1340pub type BinaryOp = ast::BinOp;
1342
1343#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1345pub struct BinInst<T> {
1346 pub operands: (T, T),
1348 pub op: BinaryOp,
1350}
1351
1352impl<T: Ord> PartialOrd for BinInst<T> {
1353 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1354 Some(self.cmp(other))
1355 }
1356}
1357
1358impl<T: Ord> Ord for BinInst<T> {
1359 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1360 let op_as_int = self.op as u8;
1361 let other_op_as_int = other.op as u8;
1362 op_as_int
1363 .cmp(&other_op_as_int)
1364 .then_with(|| self.operands.cmp(&other.operands))
1365 }
1366}
1367
1368impl BinInst<Expr> {
1369 pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Interned<Self> {
1371 Interned::new(Self {
1372 operands: (lhs, rhs),
1373 op,
1374 })
1375 }
1376}
1377
1378impl<T> BinInst<T> {
1379 pub fn operands(&self) -> [&T; 2] {
1381 [&self.operands.0, &self.operands.1]
1382 }
1383}
1384
1385fn is_empty_scope(scope: &typst::foundations::Scope) -> bool {
1387 scope.iter().next().is_none()
1388}
1389
1390impl_internable!(
1391 Expr,
1392 ArgsExpr,
1393 ElementExpr,
1394 ContentSeqExpr,
1395 RefExpr,
1396 ContentRefExpr,
1397 SelectExpr,
1398 ImportExpr,
1399 IncludeExpr,
1400 IfExpr,
1401 WhileExpr,
1402 ForExpr,
1403 FuncExpr,
1404 LetExpr,
1405 ShowExpr,
1406 SetExpr,
1407 Pattern,
1408 EcoVec<(Decl, Expr)>,
1409 Vec<ArgExpr>,
1410 Vec<Expr>,
1411 UnInst<Expr>,
1412 BinInst<Expr>,
1413 ApplyExpr,
1414);