1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
use super::{parsers::decode_hex_rpo_digest_label, LibraryPath, ParsingError, RpoDigest, Token};

/// Describes targets of `exec`, `call`, and `syscall` instructions.
pub enum InvocationTarget<'a> {
    MastRoot(RpoDigest),
    ProcedureName(&'a str),
    ProcedurePath { name: &'a str, module: &'a str },
}

impl<'a> InvocationTarget<'a> {
    /// Parses the provided label into an invocation target.
    ///
    /// A label of an invoked procedure must comply with the following rules:
    /// - It can be a hexadecimal string representing a MAST root digest ([RpoDigest]). In this case,
    ///   the label must start with "0x" and must be followed by a valid hexadecimal string
    ///   representation of an [RpoDigest].
    /// - It can contain a single procedure name. In this case, the label must comply with procedure
    ///   name rules.
    /// - It can contain module name followed by procedure name (e.g., "module::procedure"). In this
    ///   case both module and procedure name must comply with relevant name rules.
    ///
    /// All other combinations will result in an error.
    pub fn parse(label: &'a str, token: &'a Token) -> Result<Self, ParsingError> {
        if label.starts_with("0x") {
            return Ok(InvocationTarget::MastRoot(
                decode_hex_rpo_digest_label(label)
                    .map_err(|err| ParsingError::invalid_proc_root_invocation(token, label, err))?,
            ));
        }

        let num_components = LibraryPath::validate(label)
            .map_err(|_| ParsingError::invalid_proc_invocation(token, label))?;

        match num_components {
            1 => Ok(InvocationTarget::ProcedureName(label)),
            2 => {
                let parts = label.split_once(LibraryPath::PATH_DELIM).expect("no components");
                Ok(InvocationTarget::ProcedurePath {
                    name: parts.1,
                    module: parts.0,
                })
            }
            _ => Err(ParsingError::invalid_proc_invocation(token, label)),
        }
    }
}