diff --git a/src/ir/gen/conversions.rs b/src/ir/gen/conversions.rs index 62b3af7..0261dd9 100644 --- a/src/ir/gen/conversions.rs +++ b/src/ir/gen/conversions.rs @@ -3,10 +3,11 @@ //! This module provides trait implementations and helper functions to convert //! AST-level type representations (`ast::TypeSpecifier`, `ast::VarDecl`, //! `ast::VarDef`, `ast::VarDeclStmt`) into their corresponding IR-level -//! data types (`Dtype`). +//! data types (`Dtype`), and AST function declarations (`ast::FnDecl`) +//! into IR function signatures ([`FunctionType`]). use crate::ast; -use crate::ir::types::Dtype; +use crate::ir::types::{Dtype, FunctionType}; /// Converts an optional AST type specifier into the corresponding base IR data type (`Dtype`). /// @@ -79,11 +80,12 @@ impl From<&ast::TypeSpecifier> for Dtype { } // --------------------------------------------------------------------------- -// `TryFrom` trait implementations: AST declarations -> IR Dtype +// `TryFrom` trait implementations: AST declarations -> IR types // --------------------------------------------------------------------------- // -// These are fallible conversions because certain combinations (e.g., struct -// definitions with initializers) are not supported and produce an error. +// These are fallible conversions because certain combinations (e.g. struct +// definitions with initializers, array parameters in function signatures) +// are not supported and produce an error. /// Converts a variable declaration (`VarDecl`) to its IR data type. /// @@ -130,3 +132,54 @@ impl TryFrom<&ast::VarDeclStmt> for Dtype { } } } + +/// Lowers an AST function declaration into a [`FunctionType`]. +/// +/// Besides the straightforward type conversion, this enforces two +/// language rules that the back-end relies on: +/// +/// 1. Array parameters are rejected with +/// [`crate::ir::Error::ArrayParameterNotAllowed`] — TeaLang requires +/// arrays to be passed by reference (`&[T]`). +/// 2. Return types are whitelisted to `void` and `i32`. Struct returns +/// are grammatically legal but not yet implemented in the AArch64 +/// back-end; allowing them here would produce IR that can't be +/// lowered, so they are rejected up-front with +/// [`crate::ir::Error::UnsupportedReturnType`]. +impl TryFrom<&ast::FnDecl> for FunctionType { + type Error = crate::ir::Error; + + fn try_from(decl: &ast::FnDecl) -> Result { + let return_dtype = decl + .return_dtype + .as_ref() + .map_or(Dtype::Void, Dtype::from); + + match &return_dtype { + Dtype::Void | Dtype::I32 => {} + _ => { + return Err(crate::ir::Error::UnsupportedReturnType { + symbol: decl.identifier.clone(), + dtype: return_dtype, + }); + } + } + + let mut arguments = Vec::new(); + if let Some(params) = &decl.param_decl { + for p in ¶ms.decls { + let id = p.identifier.clone(); + let dtype = Dtype::try_from(p)?; + if matches!(&dtype, Dtype::Array { .. }) { + return Err(crate::ir::Error::ArrayParameterNotAllowed { symbol: id }); + } + arguments.push((id, dtype)); + } + } + + Ok(Self { + return_dtype, + arguments, + }) + } +} diff --git a/src/ir/types.rs b/src/ir/types.rs index bc98b4d..b393361 100644 --- a/src/ir/types.rs +++ b/src/ir/types.rs @@ -1,4 +1,3 @@ -use crate::ast; use std::fmt::{self, Display, Formatter}; #[derive(Clone, PartialEq, Debug)] @@ -79,53 +78,3 @@ pub struct FunctionType { pub arguments: Vec<(String, Dtype)>, } -impl TryFrom<&ast::FnDecl> for FunctionType { - type Error = crate::ir::Error; - - /// Lowers an AST function declaration into a [`FunctionType`]. - /// - /// Besides the straightforward type conversion, this enforces two - /// language rules that the back-end relies on: - /// - /// 1. Array parameters are rejected with - /// [`crate::ir::Error::ArrayParameterNotAllowed`] — TeaLang requires - /// arrays to be passed by reference (`&[T]`). - /// 2. Return types are whitelisted to `void` and `i32`. Struct returns - /// are grammatically legal but not yet implemented in the AArch64 - /// back-end; allowing them here would produce IR that can't be - /// lowered, so they are rejected up-front with - /// [`crate::ir::Error::UnsupportedReturnType`]. - fn try_from(decl: &ast::FnDecl) -> Result { - let return_dtype = decl - .return_dtype - .as_ref() - .map_or(Dtype::Void, Dtype::from); - - match &return_dtype { - Dtype::Void | Dtype::I32 => {} - _ => { - return Err(crate::ir::Error::UnsupportedReturnType { - symbol: decl.identifier.clone(), - dtype: return_dtype, - }); - } - } - - let mut arguments = Vec::new(); - if let Some(params) = &decl.param_decl { - for p in ¶ms.decls { - let id = p.identifier.clone(); - let dtype = Dtype::try_from(p)?; - if matches!(&dtype, Dtype::Array { .. }) { - return Err(crate::ir::Error::ArrayParameterNotAllowed { symbol: id }); - } - arguments.push((id, dtype)); - } - } - - Ok(Self { - return_dtype, - arguments, - }) - } -}