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 hexadecimal string (the parser also
59/// accepts a 63-digit string, padded) that is the serialized byte form returned by
60/// [`Word::to_hex`] — the four field elements each encoded as an 8-byte little-endian chunk (see
61/// [`Word::as_bytes`]), not as canonical big-endian integers. Concretely, for a word with
62/// elements `[e0, e1, e2, e3]`, the literal is `0x` followed by `hex(e0.to_le_bytes()) ||
63/// hex(e1.to_le_bytes()) || hex(e2.to_le_bytes()) || hex(e3.to_le_bytes())`. Encoding a literal
64/// by instead formatting each field element as a canonical big-endian integer and concatenating
65/// (e.g. `format!("{e0:016x}{e1:016x}...")`) can silently produce a different, incorrect
66/// [Word]/MAST root (or fail to parse, if a reversed limb exceeds the field modulus) — always
67/// construct such literals from [`Word::to_hex`] instead of hand-encoding the field elements.
68/// - It can contain a single procedure name. In this case, the label must comply with procedure
69/// name rules.
70/// - It can contain module name followed by procedure name (e.g., "module::procedure"). In this
71/// case both module and procedure name must comply with relevant name rules.
72///
73/// All other combinations will result in an error.
74#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
75pub enum InvocationTarget {
76 /// An absolute procedure reference, but opaque in that we do not know where the callee is
77 /// defined. However, it does not actually matter, we consider such references to be _a priori_
78 /// valid.
79 MastRoot(Span<Word>),
80 /// A locally-defined procedure.
81 Symbol(Ident),
82 /// An externally-defined procedure.
83 Path(Span<Arc<Path>>),
84}
85
86impl InvocationTarget {
87 pub fn unwrap_path(&self) -> &Path {
88 match self {
89 Self::Symbol(name) => name.as_ref(),
90 Self::Path(path) => path.inner().as_ref(),
91 Self::MastRoot(_) => panic!("expected invocation target to be a path"),
92 }
93 }
94}
95
96impl Spanned for InvocationTarget {
97 fn span(&self) -> SourceSpan {
98 match self {
99 Self::MastRoot(spanned) => spanned.span(),
100 Self::Symbol(spanned) => spanned.span(),
101 Self::Path(spanned) => spanned.span(),
102 }
103 }
104}
105
106impl crate::prettier::PrettyPrint for InvocationTarget {
107 fn render(&self) -> crate::prettier::Document {
108 use miden_core::utils::DisplayHex;
109
110 use crate::prettier::*;
111
112 match self {
113 Self::MastRoot(digest) => display(DisplayHex(digest.as_bytes().as_slice())),
114 Self::Symbol(name) => display(name),
115 Self::Path(path) => display(path),
116 }
117 }
118}
119impl fmt::Display for InvocationTarget {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 use crate::prettier::PrettyPrint;
122
123 self.pretty_print(f)
124 }
125}