diff --git a/nac3core/src/codegen/model/function_builder.rs b/nac3core/src/codegen/model/function_builder.rs new file mode 100644 index 00000000..0efb135f --- /dev/null +++ b/nac3core/src/codegen/model/function_builder.rs @@ -0,0 +1,55 @@ +use inkwell::{ + types::{BasicMetadataTypeEnum, BasicType}, + values::{AnyValue, BasicMetadataValueEnum}, +}; + +use crate::codegen::{model::*, CodeGenContext}; + +// TODO: Variadic argument? +pub struct FunctionBuilder<'ctx, 'a> { + ctx: &'a CodeGenContext<'ctx, 'a>, + fn_name: &'a str, + arguments: Vec<(BasicMetadataTypeEnum<'ctx>, BasicMetadataValueEnum<'ctx>)>, +} + +impl<'ctx, 'a> FunctionBuilder<'ctx, 'a> { + pub fn begin(ctx: &'a CodeGenContext<'ctx, 'a>, fn_name: &'a str) -> Self { + FunctionBuilder { ctx, fn_name, arguments: Vec::new() } + } + + // NOTE: `_name` is for self-documentation + #[must_use] + pub fn arg>(mut self, _name: &'static str, model: M, value: M::Value) -> Self { + model.check(self.ctx.ctx, value); // Panics if the passed `value` has the incorrect type. + + self.arguments + .push((model.get_llvm_type(self.ctx.ctx).into(), value.get_llvm_value().into())); + self + } + + pub fn returning>(self, name: &'static str, return_model: M) -> M::Value { + let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip(); + + let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| { + let return_type = return_model.get_llvm_type(self.ctx.ctx); + let fn_type = return_type.fn_type(¶m_tys, false); + self.ctx.module.add_function(self.fn_name, fn_type, None) + }); + + let ret = self.ctx.builder.build_call(function, ¶m_vals, name).unwrap(); + return_model.review(self.ctx.ctx, ret.as_any_value_enum()) + } + + // TODO: Code duplication, but otherwise returning> cannot resolve S if return_optic = None + pub fn returning_void(self) { + let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip(); + + let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| { + let return_type = self.ctx.ctx.void_type(); + let fn_type = return_type.fn_type(¶m_tys, false); + self.ctx.module.add_function(self.fn_name, fn_type, None) + }); + + self.ctx.builder.build_call(function, ¶m_vals, "").unwrap(); + } +} diff --git a/nac3core/src/codegen/model/mod.rs b/nac3core/src/codegen/model/mod.rs index 2ebf02b8..877a439e 100644 --- a/nac3core/src/codegen/model/mod.rs +++ b/nac3core/src/codegen/model/mod.rs @@ -1,5 +1,6 @@ pub mod core; pub mod fixed_int; +pub mod function_builder; pub mod int; mod int_util; pub mod opaque; @@ -9,6 +10,7 @@ pub mod structure; pub use core::*; pub use fixed_int::*; +pub use function_builder::*; pub use int::*; pub use opaque::*; pub use pointer::*;