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(..)) => r.decl == decl,
126 (Decl::Label(..), Decl::ContentRef(..)) => r.decl.name() == decl.name(),
127 (Decl::Label(..), _) => false,
128 _ => r.decl == decl || r.root == of,
129 })
130 }
131
132 pub fn is_exported(&self, decl: &Interned<Decl>) -> bool {
134 let of = Expr::Decl(decl.clone());
135 self.exports
136 .get(decl.name())
137 .is_some_and(|export| match export {
138 Expr::Ref(ref_expr) => ref_expr.root == Some(of),
139 exprt => *exprt == of,
140 })
141 }
142
143 #[allow(dead_code)]
145 fn show(&self) {
146 use std::io::Write;
147 let vpath = self
148 .fid
149 .vpath()
150 .resolve(Path::new("target/exprs/"))
151 .unwrap();
152 let root = vpath.with_extension("root.expr");
153 std::fs::create_dir_all(root.parent().unwrap()).unwrap();
154 std::fs::write(root, format!("{}", self.root)).unwrap();
155 let scopes = vpath.with_extension("scopes.expr");
156 std::fs::create_dir_all(scopes.parent().unwrap()).unwrap();
157 {
158 let mut scopes = std::fs::File::create(scopes).unwrap();
159 for (span, expr) in self.exprs.iter() {
160 writeln!(scopes, "{span:?} -> {expr}").unwrap();
161 }
162 }
163 let imports = vpath.with_extension("imports.expr");
164 std::fs::create_dir_all(imports.parent().unwrap()).unwrap();
165 std::fs::write(imports, format!("{:#?}", self.imports)).unwrap();
166 let exports = vpath.with_extension("exports.expr");
167 std::fs::create_dir_all(exports.parent().unwrap()).unwrap();
168 std::fs::write(exports, format!("{:#?}", self.exports)).unwrap();
169 }
170}
171
172#[derive(Debug, Clone, Hash)]
174pub struct ModuleItemLayout {
175 pub parent: Interned<Decl>,
177 pub item_range: Range<usize>,
179 pub binding_range: Range<usize>,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188pub enum Expr {
189 Block(Interned<Vec<Expr>>),
191 Array(Interned<ArgsExpr>),
193 Dict(Interned<ArgsExpr>),
195 Args(Interned<ArgsExpr>),
197 Pattern(Interned<Pattern>),
199 Element(Interned<ElementExpr>),
201 Unary(Interned<UnExpr>),
203 Binary(Interned<BinExpr>),
205 Apply(Interned<ApplyExpr>),
207 Func(Interned<FuncExpr>),
209 Let(Interned<LetExpr>),
211 Show(Interned<ShowExpr>),
213 Set(Interned<SetExpr>),
215 Ref(Interned<RefExpr>),
217 ContentRef(Interned<ContentRefExpr>),
219 Select(Interned<SelectExpr>),
221 Import(Interned<ImportExpr>),
223 Include(Interned<IncludeExpr>),
225 Contextual(Interned<Expr>),
227 Conditional(Interned<IfExpr>),
229 WhileLoop(Interned<WhileExpr>),
231 ForLoop(Interned<ForExpr>),
233 Type(Ty),
235 Decl(DeclExpr),
237 Star,
239}
240
241impl Expr {
242 pub fn repr(&self) -> EcoString {
244 let mut s = EcoString::new();
245 let _ = ExprDescriber::new(&mut s).write_expr(self);
246 s
247 }
248
249 pub fn span(&self) -> Span {
251 match self {
252 Expr::Decl(decl) => decl.span(),
253 Expr::Select(select) => select.span,
254 Expr::Apply(apply) => apply.span,
255 _ => Span::detached(),
256 }
257 }
258
259 pub fn file_id(&self) -> Option<TypstFileId> {
261 match self {
262 Expr::Decl(decl) => decl.file_id(),
263 _ => self.span().id(),
264 }
265 }
266
267 pub fn is_defined(&self) -> bool {
269 match self {
270 Expr::Ref(refs) => refs.root.is_some() || refs.term.is_some(),
271 Expr::Decl(decl) => decl.is_def(),
272 _ => false,
274 }
275 }
276}
277
278impl fmt::Display for Expr {
279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280 ExprPrinter::new(f).write_expr(self)
281 }
282}
283
284pub type LexicalScope = rpds::RedBlackTreeMapSync<Interned<str>, Expr>;
288
289#[derive(Debug, Clone)]
294pub enum ExprScope {
295 Lexical(LexicalScope),
297 Module(Module),
299 Func(Func),
301 Type(Type),
303}
304
305impl ExprScope {
306 pub fn empty() -> Self {
308 ExprScope::Lexical(LexicalScope::default())
309 }
310
311 pub fn is_empty(&self) -> bool {
313 match self {
314 ExprScope::Lexical(scope) => scope.is_empty(),
315 ExprScope::Module(module) => is_empty_scope(module.scope()),
316 ExprScope::Func(func) => func.scope().is_none_or(is_empty_scope),
317 ExprScope::Type(ty) => is_empty_scope(ty.scope()),
318 }
319 }
320
321 pub fn get(&self, name: &Interned<str>) -> (Option<Expr>, Option<Ty>) {
324 let (of, val) = match self {
325 ExprScope::Lexical(scope) => {
326 crate::log_debug_ct!("evaluating: {name:?} in {scope:?}");
327 (scope.get(name).cloned(), None)
328 }
329 ExprScope::Module(module) => {
330 let v = module.scope().get(name);
331 (None, v)
335 }
336 ExprScope::Func(func) => (None, func.scope().unwrap().get(name)),
337 ExprScope::Type(ty) => (None, ty.scope().get(name)),
338 };
339
340 (
344 of,
345 val.cloned()
346 .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))),
347 )
348 }
349
350 pub fn merge_into(&self, exports: &mut LexicalScope) {
352 match self {
353 ExprScope::Lexical(scope) => {
354 for (name, expr) in scope.iter() {
355 exports.insert_mut(name.clone(), expr.clone());
356 }
357 }
358 ExprScope::Module(module) => {
359 crate::log_debug_ct!("imported: {module:?}");
360 let v = Interned::new(Ty::Value(InsTy::new(Value::Module(module.clone()))));
361 for (name, _) in module.scope().iter() {
362 let name: Interned<str> = name.into();
363 exports.insert_mut(name.clone(), select_of(v.clone(), name));
364 }
365 }
366 ExprScope::Func(func) => {
367 if let Some(scope) = func.scope() {
368 let v = Interned::new(Ty::Value(InsTy::new(Value::Func(func.clone()))));
369 for (name, _) in scope.iter() {
370 let name: Interned<str> = name.into();
371 exports.insert_mut(name.clone(), select_of(v.clone(), name));
372 }
373 }
374 }
375 ExprScope::Type(ty) => {
376 let v = Interned::new(Ty::Value(InsTy::new(Value::Type(*ty))));
377 for (name, _) in ty.scope().iter() {
378 let name: Interned<str> = name.into();
379 exports.insert_mut(name.clone(), select_of(v.clone(), name));
380 }
381 }
382 }
383 }
384}
385
386fn select_of(source: Interned<Ty>, name: Interned<str>) -> Expr {
387 Expr::Type(Ty::Select(SelectTy::new(source, name)))
388}
389
390#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
392#[serde(rename_all = "camelCase")]
393pub enum DefKind {
394 #[default]
396 Constant,
397 Function,
399 Variable,
401 Module,
403 Struct,
405 Reference,
407}
408
409impl fmt::Display for DefKind {
410 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411 match self {
412 Self::Constant => write!(f, "constant"),
413 Self::Function => write!(f, "function"),
414 Self::Variable => write!(f, "variable"),
415 Self::Module => write!(f, "module"),
416 Self::Struct => write!(f, "struct"),
417 Self::Reference => write!(f, "reference"),
418 }
419 }
420}
421
422pub type DeclExpr = Interned<Decl>;
424
425#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
427pub enum Decl {
428 Func(SpannedDecl),
430 ImportAlias(SpannedDecl),
432 Var(SpannedDecl),
434 IdentRef(SpannedDecl),
436 Module(ModuleDecl),
438 ModuleAlias(SpannedDecl),
440 PathStem(SpannedDecl),
442 ImportPath(SpannedDecl),
444 IncludePath(SpannedDecl),
446 Import(SpannedDecl),
448 ContentRef(SpannedDecl),
450 Label(SpannedDecl),
452 StrName(SpannedDecl),
454 ModuleImport(SpanDecl),
456 Closure(SpanDecl),
458 Pattern(SpanDecl),
460 Spread(SpanDecl),
462 Content(SpanDecl),
464 Constant(SpanDecl),
466 BibEntry(NameRangeDecl),
468 Docs(DocsDecl),
470 Generated(GeneratedDecl),
472}
473
474impl Decl {
475 pub fn func(ident: ast::Ident) -> Self {
477 Self::Func(SpannedDecl {
478 name: ident.get().into(),
479 at: ident.span(),
480 })
481 }
482
483 pub fn lit(name: &str) -> Self {
485 Self::Var(SpannedDecl {
486 name: name.into(),
487 at: Span::detached(),
488 })
489 }
490
491 pub fn lit_(name: Interned<str>) -> Self {
493 Self::Var(SpannedDecl {
494 name,
495 at: Span::detached(),
496 })
497 }
498
499 pub fn var(ident: ast::Ident) -> Self {
501 Self::Var(SpannedDecl {
502 name: ident.get().into(),
503 at: ident.span(),
504 })
505 }
506
507 pub fn import_alias(ident: ast::Ident) -> Self {
509 Self::ImportAlias(SpannedDecl {
510 name: ident.get().into(),
511 at: ident.span(),
512 })
513 }
514
515 pub fn ident_ref(ident: ast::Ident) -> Self {
517 Self::IdentRef(SpannedDecl {
518 name: ident.get().into(),
519 at: ident.span(),
520 })
521 }
522
523 pub fn math_ident_ref(ident: ast::MathIdent) -> Self {
525 Self::IdentRef(SpannedDecl {
526 name: ident.get().into(),
527 at: ident.span(),
528 })
529 }
530
531 pub fn module(fid: TypstFileId) -> Self {
533 let name = {
534 let stem = fid.vpath().as_rooted_path().file_stem();
535 stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
536 .unwrap_or_default()
537 };
538 Self::Module(ModuleDecl { name, fid })
539 }
540
541 pub fn module_with_name(name: Interned<str>, fid: TypstFileId) -> Self {
543 Self::Module(ModuleDecl { name, fid })
544 }
545
546 pub fn module_alias(ident: ast::Ident) -> Self {
548 Self::ModuleAlias(SpannedDecl {
549 name: ident.get().into(),
550 at: ident.span(),
551 })
552 }
553
554 pub fn import(ident: ast::Ident) -> Self {
556 Self::Import(SpannedDecl {
557 name: ident.get().into(),
558 at: ident.span(),
559 })
560 }
561
562 pub fn label(name: &str, at: Span) -> Self {
564 Self::Label(SpannedDecl {
565 name: name.into(),
566 at,
567 })
568 }
569
570 pub fn ref_(ident: ast::Ref) -> Self {
572 Self::ContentRef(SpannedDecl {
573 name: ident.target().into(),
574 at: ident.span(),
575 })
576 }
577
578 pub fn str_name(s: SyntaxNode, name: &str) -> Decl {
580 Self::StrName(SpannedDecl {
581 name: name.into(),
582 at: s.span(),
583 })
584 }
585
586 pub fn calc_path_stem(s: &str) -> Interned<str> {
592 use std::str::FromStr;
593 let name = if s.starts_with('@') {
594 let spec = PackageSpec::from_str(s).ok();
595 spec.map(|spec| Interned::new_str(spec.name.as_str()))
596 } else {
597 let stem = Path::new(s).file_stem();
598 stem.and_then(|stem| Some(Interned::new_str(stem.to_str()?)))
599 };
600 name.unwrap_or_default()
601 }
602
603 pub fn path_stem(s: SyntaxNode, name: Interned<str>) -> Self {
605 Self::PathStem(SpannedDecl { name, at: s.span() })
606 }
607
608 pub fn import_path(s: Span, name: Interned<str>) -> Self {
610 Self::ImportPath(SpannedDecl { name, at: s })
611 }
612
613 pub fn include_path(s: Span, name: Interned<str>) -> Self {
615 Self::IncludePath(SpannedDecl { name, at: s })
616 }
617
618 pub fn module_import(s: Span) -> Self {
620 Self::ModuleImport(SpanDecl(s))
621 }
622
623 pub fn closure(s: Span) -> Self {
625 Self::Closure(SpanDecl(s))
626 }
627
628 pub fn pattern(s: Span) -> Self {
630 Self::Pattern(SpanDecl(s))
631 }
632
633 pub fn spread(s: Span) -> Self {
635 Self::Spread(SpanDecl(s))
636 }
637
638 pub fn content(s: Span) -> Self {
640 Self::Content(SpanDecl(s))
641 }
642
643 pub fn constant(s: Span) -> Self {
645 Self::Constant(SpanDecl(s))
646 }
647
648 pub fn docs(base: Interned<Decl>, var: Interned<TypeVar>) -> Self {
651 Self::Docs(DocsDecl { base, var })
652 }
653
654 pub fn generated(def_id: DefId) -> Self {
656 Self::Generated(GeneratedDecl(def_id))
657 }
658
659 pub fn bib_entry(
661 name: Interned<str>,
662 fid: TypstFileId,
663 name_range: Range<usize>,
664 range: Option<Range<usize>>,
665 ) -> Self {
666 Self::BibEntry(NameRangeDecl {
667 name,
668 at: Box::new((fid, name_range, range)),
669 })
670 }
671
672 pub fn is_def(&self) -> bool {
675 matches!(
676 self,
677 Self::Func(..)
678 | Self::BibEntry(..)
679 | Self::Closure(..)
680 | Self::Var(..)
681 | Self::Label(..)
682 | Self::StrName(..)
683 | Self::Module(..)
684 | Self::ModuleImport(..)
685 | Self::PathStem(..)
686 | Self::ImportPath(..)
687 | Self::IncludePath(..)
688 | Self::Spread(..)
689 | Self::Generated(..)
690 )
691 }
692
693 pub fn kind(&self) -> DefKind {
695 use Decl::*;
696 match self {
697 ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
698 DefKind::Module
699 }
700 Func(..) | Closure(..) => DefKind::Function,
702 Label(..) | BibEntry(..) | ContentRef(..) => DefKind::Reference,
703 IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => DefKind::Variable,
704 Pattern(..) | Docs(..) | Generated(..) | Constant(..) | StrName(..)
705 | ModuleImport(..) | Content(..) | Spread(..) => DefKind::Constant,
706 }
707 }
708
709 pub fn file_id(&self) -> Option<TypstFileId> {
711 match self {
712 Self::Module(ModuleDecl { fid, .. }) => Some(*fid),
713 Self::BibEntry(NameRangeDecl { at, .. }) => Some(at.0),
714 that => that.span().id(),
715 }
716 }
717
718 pub fn full_range(&self) -> Option<Range<usize>> {
720 if let Decl::BibEntry(decl) = self {
721 return decl.at.2.clone();
722 }
723
724 None
725 }
726
727 pub fn as_def(this: &Interned<Self>, val: Option<Ty>) -> Interned<RefExpr> {
729 let def: Expr = this.clone().into();
730 Interned::new(RefExpr {
731 decl: this.clone(),
732 step: Some(def.clone()),
733 root: Some(def),
734 term: val,
735 })
736 }
737}
738
739impl Ord for Decl {
740 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
741 let base = match (self, other) {
742 (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
743 (Self::Module(l), Self::Module(r)) => l.fid.cmp(&r.fid),
744 (Self::Docs(l), Self::Docs(r)) => l.var.cmp(&r.var).then_with(|| l.base.cmp(&r.base)),
745 _ => self.span().into_raw().cmp(&other.span().into_raw()),
746 };
747
748 base.then_with(|| self.name().cmp(other.name()))
749 }
750}
751
752trait StrictCmp {
753 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering;
756}
757
758impl Decl {
759 pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
761 let base = match (self, other) {
762 (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
763 (Self::Module(l), Self::Module(r)) => l.fid.strict_cmp(&r.fid),
764 (Self::Docs(l), Self::Docs(r)) => l
765 .var
766 .strict_cmp(&r.var)
767 .then_with(|| l.base.strict_cmp(&r.base)),
768 _ => self.span().strict_cmp(&other.span()),
769 };
770
771 base.then_with(|| self.name().cmp(other.name()))
772 }
773}
774
775impl StrictCmp for TypstFileId {
776 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
777 self.package()
778 .map(ToString::to_string)
779 .cmp(&other.package().map(ToString::to_string))
780 .then_with(|| self.vpath().cmp(other.vpath()))
781 }
782}
783impl<T: StrictCmp> StrictCmp for Option<T> {
784 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
785 match (self, other) {
786 (Some(l), Some(r)) => l.strict_cmp(r),
787 (Some(_), None) => std::cmp::Ordering::Greater,
788 (None, Some(_)) => std::cmp::Ordering::Less,
789 (None, None) => std::cmp::Ordering::Equal,
790 }
791 }
792}
793
794impl StrictCmp for Span {
795 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
796 self.id()
797 .strict_cmp(&other.id())
798 .then_with(|| self.into_raw().cmp(&other.into_raw()))
799 }
800}
801
802impl PartialOrd for Decl {
803 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
804 Some(self.cmp(other))
805 }
806}
807
808impl From<Decl> for Expr {
809 fn from(decl: Decl) -> Self {
810 Expr::Decl(decl.into())
811 }
812}
813
814impl From<DeclExpr> for Expr {
815 fn from(decl: DeclExpr) -> Self {
816 Expr::Decl(decl)
817 }
818}
819
820#[derive(Clone, PartialEq, Eq, Hash)]
822pub struct SpannedDecl {
823 name: Interned<str>,
825 at: Span,
827}
828
829impl SpannedDecl {
830 fn name(&self) -> &Interned<str> {
832 &self.name
833 }
834
835 fn span(&self) -> Span {
837 self.at
838 }
839}
840
841impl fmt::Debug for SpannedDecl {
842 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
843 f.write_str(self.name.as_ref())
844 }
845}
846
847#[derive(Clone, PartialEq, Eq, Hash)]
849pub struct NameRangeDecl {
850 pub name: Interned<str>,
852 pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
854}
855
856impl NameRangeDecl {
857 fn name(&self) -> &Interned<str> {
859 &self.name
860 }
861
862 fn span(&self) -> Span {
864 Span::detached()
865 }
866}
867
868impl fmt::Debug for NameRangeDecl {
869 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
870 f.write_str(self.name.as_ref())
871 }
872}
873
874#[derive(Clone, PartialEq, Eq, Hash)]
876pub struct ModuleDecl {
877 pub name: Interned<str>,
879 pub fid: TypstFileId,
881}
882
883impl ModuleDecl {
884 fn name(&self) -> &Interned<str> {
886 &self.name
887 }
888
889 fn span(&self) -> Span {
891 Span::detached()
892 }
893}
894
895impl fmt::Debug for ModuleDecl {
896 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
897 f.write_str(self.name.as_ref())
898 }
899}
900
901#[derive(Clone, PartialEq, Eq, Hash)]
903pub struct DocsDecl {
904 base: Interned<Decl>,
905 var: Interned<TypeVar>,
906}
907
908impl DocsDecl {
909 fn name(&self) -> &Interned<str> {
911 Interned::empty()
912 }
913
914 fn span(&self) -> Span {
916 Span::detached()
917 }
918}
919
920impl fmt::Debug for DocsDecl {
921 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
922 write!(f, "{:?}, {:?}", self.base, self.var)
923 }
924}
925
926#[derive(Clone, PartialEq, Eq, Hash)]
928pub struct SpanDecl(Span);
929
930impl SpanDecl {
931 fn name(&self) -> &Interned<str> {
933 Interned::empty()
934 }
935
936 fn span(&self) -> Span {
938 self.0
939 }
940}
941
942impl fmt::Debug for SpanDecl {
943 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
944 write!(f, "..")
945 }
946}
947
948#[derive(Clone, PartialEq, Eq, Hash)]
950pub struct GeneratedDecl(DefId);
951
952impl GeneratedDecl {
953 fn name(&self) -> &Interned<str> {
955 Interned::empty()
956 }
957
958 fn span(&self) -> Span {
960 Span::detached()
961 }
962}
963
964impl fmt::Debug for GeneratedDecl {
965 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
966 self.0.fmt(f)
967 }
968}
969
970pub type UnExpr = UnInst<Expr>;
972pub type BinExpr = BinInst<Expr>;
974
975pub type ExportMap = BTreeMap<Interned<str>, Expr>;
979
980#[derive(Debug, Clone, PartialEq, Eq, Hash)]
984pub enum ArgExpr {
985 Pos(Expr),
987 Named(Box<(DeclExpr, Expr)>),
989 NamedRt(Box<(Expr, Expr)>),
991 Spread(Expr),
993}
994
995#[derive(Debug, Clone, PartialEq, Eq, Hash)]
997pub enum Pattern {
998 Expr(Expr),
1001 Simple(Interned<Decl>),
1003 Sig(Box<PatternSig>),
1005}
1006
1007impl fmt::Display for Pattern {
1008 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1009 ExprPrinter::new(f).write_pattern(self)
1010 }
1011}
1012
1013impl Pattern {
1014 pub fn repr(&self) -> EcoString {
1016 let mut s = EcoString::new();
1017 let _ = ExprDescriber::new(&mut s).write_pattern(self);
1018 s
1019 }
1020}
1021
1022#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1027pub struct PatternSig {
1028 pub pos: EcoVec<Interned<Pattern>>,
1030 pub named: EcoVec<(DeclExpr, Interned<Pattern>)>,
1032 pub spread_left: Option<(DeclExpr, Interned<Pattern>)>,
1034 pub spread_right: Option<(DeclExpr, Interned<Pattern>)>,
1036}
1037
1038impl Pattern {}
1039
1040impl_internable!(Decl,);
1041
1042#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1046pub struct ContentSeqExpr {
1047 pub ty: Ty,
1049}
1050
1051#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1096pub struct RefExpr {
1097 pub decl: DeclExpr,
1102
1103 pub step: Option<Expr>,
1113
1114 pub root: Option<Expr>,
1118
1119 pub term: Option<Ty>,
1127}
1128
1129#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1131pub struct ContentRefExpr {
1132 pub ident: DeclExpr,
1134 pub of: Option<DeclExpr>,
1136 pub body: Option<Expr>,
1138}
1139
1140#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1142pub struct SelectExpr {
1143 pub lhs: Expr,
1145 pub key: DeclExpr,
1147 pub span: Span,
1149}
1150
1151impl SelectExpr {
1152 pub fn new(key: DeclExpr, lhs: Expr) -> Interned<Self> {
1154 Interned::new(Self {
1155 key,
1156 lhs,
1157 span: Span::detached(),
1158 })
1159 }
1160}
1161
1162#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1164pub struct ArgsExpr {
1165 pub args: Vec<ArgExpr>,
1167 pub span: Span,
1169}
1170
1171impl ArgsExpr {
1172 pub fn new(span: Span, args: Vec<ArgExpr>) -> Interned<Self> {
1174 Interned::new(Self { args, span })
1175 }
1176}
1177
1178#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1180pub struct ElementExpr {
1181 pub elem: Element,
1183 pub content: EcoVec<Expr>,
1185}
1186
1187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1189pub struct ApplyExpr {
1190 pub callee: Expr,
1192 pub args: Expr,
1194 pub span: Span,
1196}
1197
1198#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1200pub struct FuncExpr {
1201 pub decl: DeclExpr,
1203 pub params: PatternSig,
1205 pub body: Expr,
1207}
1208
1209#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1211pub struct LetExpr {
1212 pub span: Span,
1214 pub pattern: Interned<Pattern>,
1216 pub body: Option<Expr>,
1218}
1219
1220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1222pub struct ShowExpr {
1223 pub selector: Option<Expr>,
1225 pub edit: Expr,
1227}
1228
1229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1231pub struct SetExpr {
1232 pub target: Expr,
1234 pub args: Expr,
1236 pub cond: Option<Expr>,
1238}
1239
1240#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1242pub struct ImportExpr {
1243 pub decl: Interned<RefExpr>,
1245}
1246
1247#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1249pub struct IncludeExpr {
1250 pub source: Expr,
1252}
1253
1254#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1256pub struct IfExpr {
1257 pub cond: Expr,
1259 pub then: Expr,
1261 pub else_: Expr,
1263}
1264
1265#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1267pub struct WhileExpr {
1268 pub cond: Expr,
1270 pub body: Expr,
1272}
1273
1274#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1276pub struct ForExpr {
1277 pub pattern: Interned<Pattern>,
1279 pub iter: Expr,
1281 pub body: Expr,
1283}
1284
1285#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1287pub enum UnaryOp {
1288 Pos,
1291 Neg,
1294 Not,
1297 Return,
1300 Context,
1303 Spread,
1306 NotElementOf,
1309 ElementOf,
1312 TypeOf,
1315}
1316
1317#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1319pub struct UnInst<T> {
1320 pub lhs: T,
1322 pub op: UnaryOp,
1324}
1325
1326impl<T: Ord> PartialOrd for UnInst<T> {
1327 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1328 Some(self.cmp(other))
1329 }
1330}
1331
1332impl<T: Ord> Ord for UnInst<T> {
1333 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1334 let op_as_int = self.op as u8;
1335 let other_op_as_int = other.op as u8;
1336 op_as_int
1337 .cmp(&other_op_as_int)
1338 .then_with(|| self.lhs.cmp(&other.lhs))
1339 }
1340}
1341
1342impl UnInst<Expr> {
1343 pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1345 Interned::new(Self { lhs, op })
1346 }
1347}
1348
1349impl<T> UnInst<T> {
1350 pub fn operands(&self) -> [&T; 1] {
1352 [&self.lhs]
1353 }
1354}
1355
1356pub type BinaryOp = ast::BinOp;
1358
1359#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1361pub struct BinInst<T> {
1362 pub operands: (T, T),
1364 pub op: BinaryOp,
1366}
1367
1368impl<T: Ord> PartialOrd for BinInst<T> {
1369 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1370 Some(self.cmp(other))
1371 }
1372}
1373
1374impl<T: Ord> Ord for BinInst<T> {
1375 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1376 let op_as_int = self.op as u8;
1377 let other_op_as_int = other.op as u8;
1378 op_as_int
1379 .cmp(&other_op_as_int)
1380 .then_with(|| self.operands.cmp(&other.operands))
1381 }
1382}
1383
1384impl BinInst<Expr> {
1385 pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Interned<Self> {
1387 Interned::new(Self {
1388 operands: (lhs, rhs),
1389 op,
1390 })
1391 }
1392}
1393
1394impl<T> BinInst<T> {
1395 pub fn operands(&self) -> [&T; 2] {
1397 [&self.operands.0, &self.operands.1]
1398 }
1399}
1400
1401fn is_empty_scope(scope: &typst::foundations::Scope) -> bool {
1403 scope.iter().next().is_none()
1404}
1405
1406impl_internable!(
1407 Expr,
1408 ArgsExpr,
1409 ElementExpr,
1410 ContentSeqExpr,
1411 RefExpr,
1412 ContentRefExpr,
1413 SelectExpr,
1414 ImportExpr,
1415 IncludeExpr,
1416 IfExpr,
1417 WhileExpr,
1418 ForExpr,
1419 FuncExpr,
1420 LetExpr,
1421 ShowExpr,
1422 SetExpr,
1423 Pattern,
1424 EcoVec<(Decl, Expr)>,
1425 Vec<ArgExpr>,
1426 Vec<Expr>,
1427 UnInst<Expr>,
1428 BinInst<Expr>,
1429 ApplyExpr,
1430);