Skip to main content

factorio_codegen/generator/
function.rs

1use factorio_ir::{function::Function, module::Module, scope::Scope};
2
3use crate::{LuaGenerator, LuaGeneratorError, LuaGeneratorResult};
4
5impl LuaGenerator {
6    /// Generate code for a given [`Function`]
7    pub(crate) fn generate_function(
8        &mut self,
9        func: &Function,
10        module: Option<&Module>,
11        scope: Scope,
12        module_name: Option<&str>,
13    ) -> LuaGeneratorResult<()> {
14        // We cannot have a private function and export it.
15        if scope == Scope::Private && module_name.is_some() {
16            return Err(LuaGeneratorError::FunctionLocalAndExported(
17                func.name.clone(),
18            ));
19        }
20
21        let prefix = match scope {
22            Scope::Private => "local ",
23            Scope::Public => "",
24        };
25
26        let function_uses_self = func
27            .params
28            .first()
29            .is_some_and(|parameter| parameter.name == "self");
30
31        // Skip emitting self parameters since lua automatically passes that with :func()
32        let params = if function_uses_self && module_name.is_some() {
33            func.params
34                .iter()
35                .skip(1)
36                .map(|parameter| self.format_parameter(parameter))
37                .collect::<Vec<_>>()
38                .join(", ")
39        } else {
40            func.params
41                .iter()
42                .map(|parameter| self.format_parameter(parameter))
43                .collect::<Vec<_>>()
44                .join(", ")
45        };
46
47        let return_comment = self.function_return_comment(
48            func.debug
49                .as_ref()
50                .and_then(|debug| debug.return_type.as_deref()),
51        );
52
53        let function_name = match module_name {
54            Some(module_name) if function_uses_self => {
55                format!("{module_name}:{}", func.name)
56            }
57            Some(module_name) => format!("{module_name}.{}", func.name),
58            None => func.name.clone(),
59        };
60
61        self.write_doc_comments(func.doc.as_deref());
62
63        if self.debug_level_at_least(0)
64            && let Some(debug) = &func.debug
65        {
66            self.write_line(&format!("-- {}", debug.header_comment));
67        }
68
69        self.write_line(&format!(
70            "{prefix}function {function_name}({params}){return_comment}"
71        ));
72
73        self.indent_level += 1;
74        self.generate_block(&func.body, module)?;
75        self.indent_level -= 1;
76
77        self.write_line("end");
78
79        Ok(())
80    }
81}