leo_ast/functions/
mod.rs

1// Copyright (C) 2019-2025 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
17mod annotation;
18pub use annotation::*;
19
20mod core_function;
21pub use core_function::*;
22
23mod variant;
24pub use variant::*;
25
26mod input;
27pub use input::*;
28
29mod output;
30pub use output::*;
31
32mod mode;
33pub use mode::*;
34
35use crate::{Block, FunctionStub, Identifier, Indent, Node, NodeID, TupleType, Type};
36use leo_span::{Span, Symbol};
37
38use itertools::Itertools as _;
39use serde::{Deserialize, Serialize};
40use std::fmt;
41
42/// A function definition.
43#[derive(Clone, Default, Serialize, Deserialize)]
44pub struct Function {
45    /// Annotations on the function.
46    pub annotations: Vec<Annotation>,
47    /// Is this function a transition, inlined, or a regular function?.
48    pub variant: Variant,
49    /// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
50    pub identifier: Identifier,
51    /// The function's input parameters.
52    pub input: Vec<Input>,
53    /// The function's output declarations.
54    pub output: Vec<Output>,
55    /// The function's output type.
56    pub output_type: Type,
57    /// The body of the function.
58    pub block: Block,
59    /// The entire span of the function definition.
60    pub span: Span,
61    /// The ID of the node.
62    pub id: NodeID,
63}
64
65impl PartialEq for Function {
66    fn eq(&self, other: &Self) -> bool {
67        self.identifier == other.identifier
68    }
69}
70
71impl Eq for Function {}
72
73impl Function {
74    /// Initialize a new function.
75    #[allow(clippy::too_many_arguments)]
76    pub fn new(
77        annotations: Vec<Annotation>,
78        variant: Variant,
79        identifier: Identifier,
80        input: Vec<Input>,
81        output: Vec<Output>,
82        block: Block,
83        span: Span,
84        id: NodeID,
85    ) -> Self {
86        let output_type = match output.len() {
87            0 => Type::Unit,
88            1 => output[0].type_.clone(),
89            _ => Type::Tuple(TupleType::new(output.iter().map(|o| o.type_.clone()).collect())),
90        };
91
92        Function { annotations, variant, identifier, input, output, output_type, block, span, id }
93    }
94
95    /// Returns function name.
96    pub fn name(&self) -> Symbol {
97        self.identifier.name
98    }
99}
100
101impl From<FunctionStub> for Function {
102    fn from(function: FunctionStub) -> Self {
103        Self {
104            annotations: function.annotations,
105            variant: function.variant,
106            identifier: function.identifier,
107            input: function.input,
108            output: function.output,
109            output_type: function.output_type,
110            block: Block::default(),
111            span: function.span,
112            id: function.id,
113        }
114    }
115}
116
117impl fmt::Debug for Function {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        write!(f, "{}", self)
120    }
121}
122
123impl fmt::Display for Function {
124    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125        match self.variant {
126            Variant::Inline => write!(f, "inline ")?,
127            Variant::Function => write!(f, "function ")?,
128            Variant::AsyncFunction => write!(f, "async function ")?,
129            Variant::Transition => write!(f, "transition ")?,
130            Variant::AsyncTransition => write!(f, "async transition ")?,
131            Variant::Script => write!(f, "script ")?,
132        }
133        write!(f, "{}({})", self.identifier, self.input.iter().format(", "))?;
134
135        match self.output.len() {
136            0 => {}
137            1 => {
138                if !matches!(self.output[0].type_, Type::Unit) {
139                    write!(f, " -> {}", self.output[0])?;
140                }
141            }
142            _ => {
143                write!(f, " -> ({})", self.output.iter().format(", "))?;
144            }
145        }
146
147        writeln!(f, " {{")?;
148        for stmt in self.block.statements.iter() {
149            writeln!(f, "{}{}", Indent(stmt), stmt.semicolon())?;
150        }
151        write!(f, "}}")
152    }
153}
154
155crate::simple_node_impl!(Function);