miden_assembly/ast/
invocation_target.rs

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