miden_assembly_syntax/ast/
invocation_target.rs

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