Skip to main content

leo_ast/expressions/
dynamic_op.rs

1// Copyright (C) 2019-2026 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18
19use itertools::Itertools as _;
20
21/// A dynamic operation against an interface at a runtime target address.
22///
23/// Covers three surface forms:
24///
25/// - **Function call** (`DynamicOpKind::Call`):
26///   `Interface@(target[, network])::func(args)` — invokes an interface function.
27///
28/// - **Bare storage read** (`DynamicOpKind::Read`):
29///   `Interface@(target[, network])::name` — reads a singleton storage variable
30///   declared in the interface, producing `Option<T>`.
31///
32/// - **Storage member operation** (`DynamicOpKind::Op`):
33///   `Interface@(target[, network])::member.op(args)` — performs an operation on
34///   a mapping (`get`, `get_or_use`, `contains`) or vector (`get`, `len`) storage
35///   variable declared in the interface.
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct DynamicOpExpression {
38    /// The interface type.
39    pub interface: Type,
40    /// The target program expression (`field` or `identifier`).
41    pub target_program: Expression,
42    /// The optional network expression; defaults to `'aleo'` when `None`.
43    pub network: Option<Expression>,
44    /// Which dynamic operation this expression represents.
45    pub kind: DynamicOpKind,
46    /// The span of the entire expression.
47    pub span: Span,
48    /// The ID of the node.
49    pub id: NodeID,
50}
51
52/// Distinguishes the three surface forms of [`DynamicOpExpression`].
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54pub enum DynamicOpKind {
55    /// `Interface@(p)::func(args)` — call a function declared in the interface.
56    Call { function: Identifier, arguments: Vec<Expression> },
57    /// `Interface@(p)::name` — bare read of a singleton storage variable.
58    Read { storage: Identifier },
59    /// `Interface@(p)::member.op(args)` — op on a mapping or vector storage variable.
60    ///
61    /// Mappings support `get`, `get_or_use`, `contains`. Vectors support `get`, `len`.
62    Op { member: Identifier, op: Identifier, arguments: Vec<Expression> },
63}
64
65impl fmt::Display for DynamicOpExpression {
66    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67        let target = if let Some(network) = &self.network {
68            format!("({}, {})", self.target_program, network)
69        } else {
70            format!("({})", self.target_program)
71        };
72
73        match &self.kind {
74            DynamicOpKind::Call { function, arguments } => {
75                write!(f, "{}@{}::{}({})", self.interface, target, function, arguments.iter().format(", "))
76            }
77            DynamicOpKind::Read { storage } => {
78                write!(f, "{}@{}::{}", self.interface, target, storage)
79            }
80            DynamicOpKind::Op { member, op, arguments } => {
81                write!(f, "{}@{}::{}.{}({})", self.interface, target, member, op, arguments.iter().format(", "))
82            }
83        }
84    }
85}
86
87impl From<DynamicOpExpression> for Expression {
88    fn from(value: DynamicOpExpression) -> Self {
89        Expression::DynamicOp(Box::new(value))
90    }
91}
92
93crate::simple_node_impl!(DynamicOpExpression);