miden_assembly_syntax/ast/
invocation_target.rs

1use alloc::sync::Arc;
2use core::fmt;
3
4use miden_debug_types::{SourceSpan, Span, Spanned};
5
6use crate::{Path, Word, ast::Ident};
7
8// INVOKE
9// ================================================================================================
10
11/// Represents the kind of an invocation
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
13#[repr(u8)]
14pub enum InvokeKind {
15    Exec = 0,
16    Call,
17    SysCall,
18    ProcRef,
19}
20
21impl fmt::Display for InvokeKind {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Self::Exec => f.write_str("exec"),
25            Self::Call => f.write_str("call"),
26            Self::SysCall => f.write_str("syscall"),
27            Self::ProcRef => f.write_str("procref"),
28        }
29    }
30}
31
32/// Represents a specific invocation
33#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
34pub struct Invoke {
35    pub kind: InvokeKind,
36    pub target: InvocationTarget,
37}
38
39impl Spanned for Invoke {
40    fn span(&self) -> SourceSpan {
41        self.target.span()
42    }
43}
44
45impl Invoke {
46    pub fn new(kind: InvokeKind, target: InvocationTarget) -> Self {
47        Self { kind, target }
48    }
49}
50
51// INVOCATION TARGET
52// ================================================================================================
53
54/// Describes targets of `exec`, `call`, and `syscall` instructions.
55///
56/// A label of an invoked procedure must comply with the following rules:
57/// - It can be a hexadecimal string representing a MAST root digest ([Word]). In this case, the
58///   label must start with "0x" and must be followed by a valid hexadecimal string representation
59///   of an [Word].
60/// - It can contain a single procedure name. In this case, the label must comply with procedure
61///   name rules.
62/// - It can contain module name followed by procedure name (e.g., "module::procedure"). In this
63///   case both module and procedure name must comply with relevant name rules.
64///
65/// All other combinations will result in an error.
66#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
67pub enum InvocationTarget {
68    /// An absolute procedure reference, but opaque in that we do not know where the callee is
69    /// defined. However, it does not actually matter, we consider such references to be _a priori_
70    /// valid.
71    MastRoot(Span<Word>),
72    /// A locally-defined procedure.
73    Symbol(Ident),
74    /// An externally-defined procedure.
75    Path(Span<Arc<Path>>),
76}
77
78impl InvocationTarget {
79    pub fn unwrap_path(&self) -> &Path {
80        match self {
81            Self::Symbol(name) => name.as_ref(),
82            Self::Path(path) => path.inner().as_ref(),
83            Self::MastRoot(_) => panic!("expected invocation target to be a path"),
84        }
85    }
86}
87
88impl Spanned for InvocationTarget {
89    fn span(&self) -> SourceSpan {
90        match self {
91            Self::MastRoot(spanned) => spanned.span(),
92            Self::Symbol(spanned) => spanned.span(),
93            Self::Path(spanned) => spanned.span(),
94        }
95    }
96}
97
98impl crate::prettier::PrettyPrint for InvocationTarget {
99    fn render(&self) -> crate::prettier::Document {
100        use miden_core::utils::DisplayHex;
101
102        use crate::prettier::*;
103
104        match self {
105            Self::MastRoot(digest) => display(DisplayHex(digest.as_bytes().as_slice())),
106            Self::Symbol(name) => display(name),
107            Self::Path(path) => display(path),
108        }
109    }
110}
111impl fmt::Display for InvocationTarget {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        use crate::prettier::PrettyPrint;
114
115        self.pretty_print(f)
116    }
117}