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);