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
252impl fmt::Display for Expr {
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 ExprPrinter::new(f).write_expr(self)
255 }
256}
257
258pub type LexicalScope = rpds::RedBlackTreeMapSync<Interned<str>, Expr>;
262
263#[derive(Debug, Clone)]
268pub enum ExprScope {
269 Lexical(LexicalScope),
271 Module(Module),
273 Func(Func),
275 Type(Type),
277}
278
279impl ExprScope {
280 pub fn empty() -> Self {
282 ExprScope::Lexical(LexicalScope::default())
283 }
284
285 pub fn is_empty(&self) -> bool {
287 match self {
288 ExprScope::Lexical(scope) => scope.is_empty(),
289 ExprScope::Module(module) => is_empty_scope(module.scope()),
290 ExprScope::Func(func) => func.scope().is_none_or(is_empty_scope),
291 ExprScope::Type(ty) => is_empty_scope(ty.scope()),
292 }
293 }
294
295 pub fn get(&self, name: &Interned<str>) -> (Option<Expr>, Option<Ty>) {
298 let (of, val) = match self {
299 ExprScope::Lexical(scope) => {
300 crate::log_debug_ct!("evaluating: {name:?} in {scope:?}");
301 (scope.get(name).cloned(), None)
302 }
303 ExprScope::Module(module) => {
304 let v = module.scope().get(name);
305 (None, v)
309 }
310 ExprScope::Func(func) => (None, func.scope().unwrap().get(name)),
311 ExprScope::Type(ty) => (None, ty.scope().get(name)),
312 };
313
314 (
318 of,
319 val.cloned()
320 .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))),
321 )
322 }
323
324 pub fn merge_into(&self, exports: &mut LexicalScope) {
326 match self {
327 ExprScope::Lexical(scope) => {
328 for (name, expr) in scope.iter() {
329 exports.insert_mut(name.clone(), expr.clone());
330 }
331 }
332 ExprScope::Module(module) => {
333 crate::log_debug_ct!("imported: {module:?}");
334 let v = Interned::new(Ty::Value(InsTy::new(Value::Module(module.clone()))));
335 for (name, _) in module.scope().iter() {
336 let name: Interned<str> = name.into();
337 exports.insert_mut(name.clone(), select_of(v.clone(), name));
338 }
339 }
340 ExprScope::Func(func) => {
341 if let Some(scope) = func.scope() {
342 let v = Interned::new(Ty::Value(InsTy::new(Value::Func(func.clone()))));
343 for (name, _) in scope.iter() {
344 let name: Interned<str> = name.into();
345 exports.insert_mut(name.clone(), select_of(v.clone(), name));
346 }
347 }
348 }
349 ExprScope::Type(ty) => {
350 let v = Interned::new(Ty::Value(InsTy::new(Value::Type(*ty))));
351 for (name, _) in ty.scope().iter() {
352 let name: Interned<str> = name.into();
353 exports.insert_mut(name.clone(), select_of(v.clone(), name));
354 }
355 }
356 }
357 }
358}
359
360fn select_of(source: Interned<Ty>, name: Interned<str>) -> Expr {
361 Expr::Type(Ty::Select(SelectTy::new(source, name)))
362}
363
364#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
366#[serde(rename_all = "camelCase")]
367pub enum DefKind {
368 #[default]
370 Constant,
371 Function,
373 Variable,
375 Module,
377 Struct,
379 Reference,
381}
382
383impl fmt::Display for DefKind {
384 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385 match self {
386 Self::Constant => write!(f, "constant"),
387 Self::Function => write!(f, "function"),
388 Self::Variable => write!(f, "variable"),
389 Self::Module => write!(f, "module"),
390 Self::Struct => write!(f, "struct"),
391 Self::Reference => write!(f, "reference"),
392 }
393 }
394}
395
396pub type DeclExpr = Interned<Decl>;
398
399#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
401pub enum Decl {
402 Func(SpannedDecl),
404 ImportAlias(SpannedDecl),
406 Var(SpannedDecl),
408 IdentRef(SpannedDecl),
410 Module(ModuleDecl),
412 ModuleAlias(SpannedDecl),
414 PathStem(SpannedDecl),
416 ImportPath(SpannedDecl),
418 IncludePath(SpannedDecl),
420 Import(SpannedDecl),
422 ContentRef(SpannedDecl),
424 Label(SpannedDecl),
426 StrName(SpannedDecl),
428 ModuleImport(SpanDecl),
430 Closure(SpanDecl),
432 Pattern(SpanDecl),
434 Spread(SpanDecl),
436 Content(SpanDecl),
438 Constant(SpanDecl),
440 BibEntry(NameRangeDecl),
442 Docs(DocsDecl),
444 Generated(GeneratedDecl),
446}
447
448impl Decl {
449 pub fn func(ident: ast::Ident) -> Self {
451 Self::Func(SpannedDecl {
452 name: ident.get().into(),
453 at: ident.span(),
454 })
455 }
456
457 pub fn lit(name: &str) -> Self {
459 Self::Var(SpannedDecl {
460 name: name.into(),
461 at: Span::detached(),
462 })
463 }
464
465 pub fn lit_(name: Interned<str>) -> Self {
467 Self::Var(SpannedDecl {
468 name,
469 at: Span::detached(),
470 })
471 }
472
473 pub fn var(ident: ast::Ident) -> Self {
475 Self::Var(SpannedDecl {
476 name: ident.get().into(),
477 at: ident.span(),
478 })
479 }
480
481 pub fn import_alias(ident: ast::Ident) -> Self {
483 Self::ImportAlias(SpannedDecl {
484 name: ident.get().into(),
485 at: ident.span(),
486 })
487 }
488
489 pub fn ident_ref(ident: ast::Ident) -> Self {
491 Self::IdentRef(SpannedDecl {
492 name: ident.get().into(),
493 at: ident.span(),
494 })
495 }
496
497 pub fn math_ident_ref(ident: ast::MathIdent) -> Self {
499 Self::IdentRef(SpannedDecl {
500 name: ident.get().into(),
501 at: ident.span(),
502 })
503 }
504
505 pub fn module(name: Interned<str>, fid: TypstFileId) -> Self {
507 Self::Module(ModuleDecl { name, fid })
508 }
509
510 pub fn module_alias(ident: ast::Ident) -> Self {
512 Self::ModuleAlias(SpannedDecl {
513 name: ident.get().into(),
514 at: ident.span(),
515 })
516 }
517
518 pub fn import(ident: ast::Ident) -> Self {
520 Self::Import(SpannedDecl {
521 name: ident.get().into(),
522 at: ident.span(),
523 })
524 }
525
526 pub fn label(name: &str, at: Span) -> Self {
528 Self::Label(SpannedDecl {
529 name: name.into(),
530 at,
531 })
532 }
533
534 pub fn ref_(ident: ast::Ref) -> Self {
536 Self::ContentRef(SpannedDecl {
537 name: ident.target().into(),
538 at: ident.span(),
539 })
540 }
541
542 pub fn str_name(s: SyntaxNode, name: &str) -> Decl {
544 Self::StrName(SpannedDecl {
545 name: name.into(),
546 at: s.span(),
547 })
548 }
549
550 pub fn calc_path_stem(s: &str) -> Interned<str> {
556 use std::str::FromStr;
557 let name = if s.starts_with('@') {
558 let spec = PackageSpec::from_str(s).ok();
559 spec.map(|spec| Interned::new_str(spec.name.as_str()))
560 } else {
561 let stem = Path::new(s).file_stem();
562 stem.and_then(|stem| Some(Interned::new_str(stem.to_str()?)))
563 };
564 name.unwrap_or_default()
565 }
566
567 pub fn path_stem(s: SyntaxNode, name: Interned<str>) -> Self {
569 Self::PathStem(SpannedDecl { name, at: s.span() })
570 }
571
572 pub fn import_path(s: Span, name: Interned<str>) -> Self {
574 Self::ImportPath(SpannedDecl { name, at: s })
575 }
576
577 pub fn include_path(s: Span, name: Interned<str>) -> Self {
579 Self::IncludePath(SpannedDecl { name, at: s })
580 }
581
582 pub fn module_import(s: Span) -> Self {
584 Self::ModuleImport(SpanDecl(s))
585 }
586
587 pub fn closure(s: Span) -> Self {
589 Self::Closure(SpanDecl(s))
590 }
591
592 pub fn pattern(s: Span) -> Self {
594 Self::Pattern(SpanDecl(s))
595 }
596
597 pub fn spread(s: Span) -> Self {
599 Self::Spread(SpanDecl(s))
600 }
601
602 pub fn content(s: Span) -> Self {
604 Self::Content(SpanDecl(s))
605 }
606
607 pub fn constant(s: Span) -> Self {
609 Self::Constant(SpanDecl(s))
610 }
611
612 pub fn docs(base: Interned<Decl>, var: Interned<TypeVar>) -> Self {
615 Self::Docs(DocsDecl { base, var })
616 }
617
618 pub fn generated(def_id: DefId) -> Self {
620 Self::Generated(GeneratedDecl(def_id))
621 }
622
623 pub fn bib_entry(
625 name: Interned<str>,
626 fid: TypstFileId,
627 name_range: Range<usize>,
628 range: Option<Range<usize>>,
629 ) -> Self {
630 Self::BibEntry(NameRangeDecl {
631 name,
632 at: Box::new((fid, name_range, range)),
633 })
634 }
635
636 pub fn is_def(&self) -> bool {
639 matches!(
640 self,
641 Self::Func(..)
642 | Self::BibEntry(..)
643 | Self::Closure(..)
644 | Self::Var(..)
645 | Self::Label(..)
646 | Self::StrName(..)
647 | Self::Module(..)
648 | Self::ModuleImport(..)
649 | Self::PathStem(..)
650 | Self::ImportPath(..)
651 | Self::IncludePath(..)
652 | Self::Spread(..)
653 | Self::Generated(..)
654 )
655 }
656
657 pub fn kind(&self) -> DefKind {
659 use Decl::*;
660 match self {
661 ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
662 DefKind::Module
663 }
664 Func(..) | Closure(..) => DefKind::Function,
666 Label(..) | BibEntry(..) | ContentRef(..) => DefKind::Reference,
667 IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => DefKind::Variable,
668 Pattern(..) | Docs(..) | Generated(..) | Constant(..) | StrName(..)
669 | ModuleImport(..) | Content(..) | Spread(..) => DefKind::Constant,
670 }
671 }
672
673 pub fn file_id(&self) -> Option<TypstFileId> {
675 match self {
676 Self::Module(ModuleDecl { fid, .. }) => Some(*fid),
677 Self::BibEntry(NameRangeDecl { at, .. }) => Some(at.0),
678 that => that.span().id(),
679 }
680 }
681
682 pub fn full_range(&self) -> Option<Range<usize>> {
684 if let Decl::BibEntry(decl) = self {
685 return decl.at.2.clone();
686 }
687
688 None
689 }
690
691 pub fn as_def(this: &Interned<Self>, val: Option<Ty>) -> Interned<RefExpr> {
693 let def: Expr = this.clone().into();
694 Interned::new(RefExpr {
695 decl: this.clone(),
696 step: Some(def.clone()),
697 root: Some(def),
698 term: val,
699 })
700 }
701}
702
703impl Ord for Decl {
704 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
705 let base = match (self, other) {
706 (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
707 (Self::Module(l), Self::Module(r)) => l.fid.cmp(&r.fid),
708 (Self::Docs(l), Self::Docs(r)) => l.var.cmp(&r.var).then_with(|| l.base.cmp(&r.base)),
709 _ => self.span().into_raw().cmp(&other.span().into_raw()),
710 };
711
712 base.then_with(|| self.name().cmp(other.name()))
713 }
714}
715
716trait StrictCmp {
717 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering;
720}
721
722impl Decl {
723 pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
725 let base = match (self, other) {
726 (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
727 (Self::Module(l), Self::Module(r)) => l.fid.strict_cmp(&r.fid),
728 (Self::Docs(l), Self::Docs(r)) => l
729 .var
730 .strict_cmp(&r.var)
731 .then_with(|| l.base.strict_cmp(&r.base)),
732 _ => self.span().strict_cmp(&other.span()),
733 };
734
735 base.then_with(|| self.name().cmp(other.name()))
736 }
737}
738
739impl StrictCmp for TypstFileId {
740 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
741 self.package()
742 .map(ToString::to_string)
743 .cmp(&other.package().map(ToString::to_string))
744 .then_with(|| self.vpath().cmp(other.vpath()))
745 }
746}
747impl<T: StrictCmp> StrictCmp for Option<T> {
748 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
749 match (self, other) {
750 (Some(l), Some(r)) => l.strict_cmp(r),
751 (Some(_), None) => std::cmp::Ordering::Greater,
752 (None, Some(_)) => std::cmp::Ordering::Less,
753 (None, None) => std::cmp::Ordering::Equal,
754 }
755 }
756}
757
758impl StrictCmp for Span {
759 fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
760 self.id()
761 .strict_cmp(&other.id())
762 .then_with(|| self.into_raw().cmp(&other.into_raw()))
763 }
764}
765
766impl PartialOrd for Decl {
767 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
768 Some(self.cmp(other))
769 }
770}
771
772impl From<Decl> for Expr {
773 fn from(decl: Decl) -> Self {
774 Expr::Decl(decl.into())
775 }
776}
777
778impl From<DeclExpr> for Expr {
779 fn from(decl: DeclExpr) -> Self {
780 Expr::Decl(decl)
781 }
782}
783
784#[derive(Clone, PartialEq, Eq, Hash)]
786pub struct SpannedDecl {
787 name: Interned<str>,
789 at: Span,
791}
792
793impl SpannedDecl {
794 fn name(&self) -> &Interned<str> {
796 &self.name
797 }
798
799 fn span(&self) -> Span {
801 self.at
802 }
803}
804
805impl fmt::Debug for SpannedDecl {
806 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
807 f.write_str(self.name.as_ref())
808 }
809}
810
811#[derive(Clone, PartialEq, Eq, Hash)]
813pub struct NameRangeDecl {
814 pub name: Interned<str>,
816 pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
818}
819
820impl NameRangeDecl {
821 fn name(&self) -> &Interned<str> {
823 &self.name
824 }
825
826 fn span(&self) -> Span {
828 Span::detached()
829 }
830}
831
832impl fmt::Debug for NameRangeDecl {
833 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
834 f.write_str(self.name.as_ref())
835 }
836}
837
838#[derive(Clone, PartialEq, Eq, Hash)]
840pub struct ModuleDecl {
841 pub name: Interned<str>,
843 pub fid: TypstFileId,
845}
846
847impl ModuleDecl {
848 fn name(&self) -> &Interned<str> {
850 &self.name
851 }
852
853 fn span(&self) -> Span {
855 Span::detached()
856 }
857}
858
859impl fmt::Debug for ModuleDecl {
860 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
861 f.write_str(self.name.as_ref())
862 }
863}
864
865#[derive(Clone, PartialEq, Eq, Hash)]
867pub struct DocsDecl {
868 base: Interned<Decl>,
869 var: Interned<TypeVar>,
870}
871
872impl DocsDecl {
873 fn name(&self) -> &Interned<str> {
875 Interned::empty()
876 }
877
878 fn span(&self) -> Span {
880 Span::detached()
881 }
882}
883
884impl fmt::Debug for DocsDecl {
885 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
886 write!(f, "{:?}, {:?}", self.base, self.var)
887 }
888}
889
890#[derive(Clone, PartialEq, Eq, Hash)]
892pub struct SpanDecl(Span);
893
894impl SpanDecl {
895 fn name(&self) -> &Interned<str> {
897 Interned::empty()
898 }
899
900 fn span(&self) -> Span {
902 self.0
903 }
904}
905
906impl fmt::Debug for SpanDecl {
907 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
908 write!(f, "..")
909 }
910}
911
912#[derive(Clone, PartialEq, Eq, Hash)]
914pub struct GeneratedDecl(DefId);
915
916impl GeneratedDecl {
917 fn name(&self) -> &Interned<str> {
919 Interned::empty()
920 }
921
922 fn span(&self) -> Span {
924 Span::detached()
925 }
926}
927
928impl fmt::Debug for GeneratedDecl {
929 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
930 self.0.fmt(f)
931 }
932}
933
934pub type UnExpr = UnInst<Expr>;
936pub type BinExpr = BinInst<Expr>;
938
939pub type ExportMap = BTreeMap<Interned<str>, Expr>;
943
944#[derive(Debug, Clone, PartialEq, Eq, Hash)]
948pub enum ArgExpr {
949 Pos(Expr),
951 Named(Box<(DeclExpr, Expr)>),
953 NamedRt(Box<(Expr, Expr)>),
955 Spread(Expr),
957}
958
959#[derive(Debug, Clone, PartialEq, Eq, Hash)]
961pub enum Pattern {
962 Expr(Expr),
965 Simple(Interned<Decl>),
967 Sig(Box<PatternSig>),
969}
970
971impl fmt::Display for Pattern {
972 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
973 ExprPrinter::new(f).write_pattern(self)
974 }
975}
976
977impl Pattern {
978 pub fn repr(&self) -> EcoString {
980 let mut s = EcoString::new();
981 let _ = ExprDescriber::new(&mut s).write_pattern(self);
982 s
983 }
984}
985
986#[derive(Debug, Clone, PartialEq, Eq, Hash)]
991pub struct PatternSig {
992 pub pos: EcoVec<Interned<Pattern>>,
994 pub named: EcoVec<(DeclExpr, Interned<Pattern>)>,
996 pub spread_left: Option<(DeclExpr, Interned<Pattern>)>,
998 pub spread_right: Option<(DeclExpr, Interned<Pattern>)>,
1000}
1001
1002impl Pattern {}
1003
1004impl_internable!(Decl,);
1005
1006#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1010pub struct ContentSeqExpr {
1011 pub ty: Ty,
1013}
1014
1015#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1021pub struct RefExpr {
1022 pub decl: DeclExpr,
1024 pub step: Option<Expr>,
1026 pub root: Option<Expr>,
1028 pub term: Option<Ty>,
1030}
1031
1032#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1034pub struct ContentRefExpr {
1035 pub ident: DeclExpr,
1037 pub of: Option<DeclExpr>,
1039 pub body: Option<Expr>,
1041}
1042
1043#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1045pub struct SelectExpr {
1046 pub lhs: Expr,
1048 pub key: DeclExpr,
1050 pub span: Span,
1052}
1053
1054impl SelectExpr {
1055 pub fn new(key: DeclExpr, lhs: Expr) -> Interned<Self> {
1057 Interned::new(Self {
1058 key,
1059 lhs,
1060 span: Span::detached(),
1061 })
1062 }
1063}
1064
1065#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1067pub struct ArgsExpr {
1068 pub args: Vec<ArgExpr>,
1070 pub span: Span,
1072}
1073
1074impl ArgsExpr {
1075 pub fn new(span: Span, args: Vec<ArgExpr>) -> Interned<Self> {
1077 Interned::new(Self { args, span })
1078 }
1079}
1080
1081#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1083pub struct ElementExpr {
1084 pub elem: Element,
1086 pub content: EcoVec<Expr>,
1088}
1089
1090#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1092pub struct ApplyExpr {
1093 pub callee: Expr,
1095 pub args: Expr,
1097 pub span: Span,
1099}
1100
1101#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1103pub struct FuncExpr {
1104 pub decl: DeclExpr,
1106 pub params: PatternSig,
1108 pub body: Expr,
1110}
1111
1112#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1114pub struct LetExpr {
1115 pub span: Span,
1117 pub pattern: Interned<Pattern>,
1119 pub body: Option<Expr>,
1121}
1122
1123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1125pub struct ShowExpr {
1126 pub selector: Option<Expr>,
1128 pub edit: Expr,
1130}
1131
1132#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1134pub struct SetExpr {
1135 pub target: Expr,
1137 pub args: Expr,
1139 pub cond: Option<Expr>,
1141}
1142
1143#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1145pub struct ImportExpr {
1146 pub decl: Interned<RefExpr>,
1148}
1149
1150#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1152pub struct IncludeExpr {
1153 pub source: Expr,
1155}
1156
1157#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1159pub struct IfExpr {
1160 pub cond: Expr,
1162 pub then: Expr,
1164 pub else_: Expr,
1166}
1167
1168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1170pub struct WhileExpr {
1171 pub cond: Expr,
1173 pub body: Expr,
1175}
1176
1177#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1179pub struct ForExpr {
1180 pub pattern: Interned<Pattern>,
1182 pub iter: Expr,
1184 pub body: Expr,
1186}
1187
1188#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1190pub enum UnaryOp {
1191 Pos,
1194 Neg,
1197 Not,
1200 Return,
1203 Context,
1206 Spread,
1209 NotElementOf,
1212 ElementOf,
1215 TypeOf,
1218}
1219
1220#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1222pub struct UnInst<T> {
1223 pub lhs: T,
1225 pub op: UnaryOp,
1227}
1228
1229impl<T: Ord> PartialOrd for UnInst<T> {
1230 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1231 Some(self.cmp(other))
1232 }
1233}
1234
1235impl<T: Ord> Ord for UnInst<T> {
1236 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1237 let op_as_int = self.op as u8;
1238 let other_op_as_int = other.op as u8;
1239 op_as_int
1240 .cmp(&other_op_as_int)
1241 .then_with(|| self.lhs.cmp(&other.lhs))
1242 }
1243}
1244
1245impl UnInst<Expr> {
1246 pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1248 Interned::new(Self { lhs, op })
1249 }
1250}
1251
1252impl<T> UnInst<T> {
1253 pub fn operands(&self) -> [&T; 1] {
1255 [&self.lhs]
1256 }
1257}
1258
1259pub type BinaryOp = ast::BinOp;
1261
1262#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1264pub struct BinInst<T> {
1265 pub operands: (T, T),
1267 pub op: BinaryOp,
1269}
1270
1271impl<T: Ord> PartialOrd for BinInst<T> {
1272 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1273 Some(self.cmp(other))
1274 }
1275}
1276
1277impl<T: Ord> Ord for BinInst<T> {
1278 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1279 let op_as_int = self.op as u8;
1280 let other_op_as_int = other.op as u8;
1281 op_as_int
1282 .cmp(&other_op_as_int)
1283 .then_with(|| self.operands.cmp(&other.operands))
1284 }
1285}
1286
1287impl BinInst<Expr> {
1288 pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Interned<Self> {
1290 Interned::new(Self {
1291 operands: (lhs, rhs),
1292 op,
1293 })
1294 }
1295}
1296
1297impl<T> BinInst<T> {
1298 pub fn operands(&self) -> [&T; 2] {
1300 [&self.operands.0, &self.operands.1]
1301 }
1302}
1303
1304fn is_empty_scope(scope: &typst::foundations::Scope) -> bool {
1306 scope.iter().next().is_none()
1307}
1308
1309impl_internable!(
1310 Expr,
1311 ArgsExpr,
1312 ElementExpr,
1313 ContentSeqExpr,
1314 RefExpr,
1315 ContentRefExpr,
1316 SelectExpr,
1317 ImportExpr,
1318 IncludeExpr,
1319 IfExpr,
1320 WhileExpr,
1321 ForExpr,
1322 FuncExpr,
1323 LetExpr,
1324 ShowExpr,
1325 SetExpr,
1326 Pattern,
1327 EcoVec<(Decl, Expr)>,
1328 Vec<ArgExpr>,
1329 Vec<Expr>,
1330 UnInst<Expr>,
1331 BinInst<Expr>,
1332 ApplyExpr,
1333);