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