use syn::{ItemFn, PatType, Signature};
use crate::error::FrontendResult;
use super::{
context::LowerContext,
event_handler::resolve_event_handler,
metadata::{extract_doc_comments, function_header_comment},
statements::lower_block,
types::{
lower_binding_pattern, lower_type, receiver_source_string, return_type_string,
type_source_string,
},
};
pub fn lower_function(
function: &ItemFn,
ctx: &mut LowerContext<'_>,
) -> FrontendResult<factorio_ir::function::Function> {
lower_function_parts(function, ctx, None)
}
pub fn lower_impl_method(
method: &syn::ImplItemFn,
self_type: &str,
ctx: &mut LowerContext<'_>,
) -> FrontendResult<factorio_ir::function::Function> {
let function = ItemFn {
attrs: method.attrs.clone(),
vis: method.vis.clone(),
sig: method.sig.clone(),
block: Box::new(method.block.clone()),
};
lower_function_parts(&function, ctx, Some(self_type))
}
fn lower_function_parts(
function: &ItemFn,
ctx: &mut LowerContext<'_>,
self_type: Option<&str>,
) -> FrontendResult<factorio_ir::function::Function> {
let event_attr = resolve_event_handler(function);
Ok(factorio_ir::function::Function {
name: function.sig.ident.to_string(),
params: lower_parameters(&function.sig)?,
body: lower_block(&function.block, ctx, self_type)?,
doc: extract_doc_comments(&function.attrs),
debug: Some(factorio_ir::debug::FunctionDebug {
header_comment: function_header_comment(&function.vis, &function.sig),
return_type: return_type_string(&function.sig),
}),
event: event_attr.as_ref().map(|event| event.event_name.clone()),
event_filter: event_attr.and_then(|event| event.filter),
})
}
fn lower_parameters(
signature: &Signature,
) -> FrontendResult<Vec<factorio_ir::function::Parameter>> {
signature
.inputs
.iter()
.map(lower_parameter)
.collect::<FrontendResult<Vec<_>>>()
}
fn lower_parameter(input: &syn::FnArg) -> FrontendResult<factorio_ir::function::Parameter> {
match input {
syn::FnArg::Receiver(receiver) => Ok(factorio_ir::function::Parameter {
name: "self".to_string(),
r#type: factorio_ir::r#type::Type::Void,
source_type: Some(receiver_source_string(receiver)),
}),
syn::FnArg::Typed(PatType { pat, ty, .. }) => {
let name = lower_binding_pattern(pat)?;
let r#type = lower_type(ty)?;
Ok(factorio_ir::function::Parameter {
name,
r#type,
source_type: Some(type_source_string(ty)),
})
}
}
}