Skip to main content

factorio_codegen/generator/
statement.rs

1use factorio_ir::{module::Module, scope::Scope, statement::Statement};
2
3use crate::{LuaGenerator, LuaGeneratorResult};
4
5fn body_has_continue(body: &[Statement]) -> bool {
6    body.iter().any(|s| match s {
7        Statement::Continue => true,
8        Statement::Conditional {
9            then_block,
10            else_block,
11            ..
12        } => body_has_continue(then_block) || body_has_continue(else_block),
13        _ => false,
14    })
15}
16
17impl LuaGenerator {
18    /// Generate code for a given [`Statement`].
19    pub(crate) fn generate_statement(
20        &mut self,
21        statement: &Statement,
22        module: Option<&Module>,
23        module_name: Option<&str>,
24        scope: Scope,
25    ) -> LuaGeneratorResult<()> {
26        match statement {
27            Statement::FunctionDecl(function) => {
28                self.generate_function(function, module, scope, module_name)?;
29            }
30            Statement::StructDecl(struct_decl) => {
31                self.generate_struct(struct_decl, module, scope, module_name)?;
32            }
33            Statement::VariableDecl {
34                name,
35                value,
36                source_type,
37                ..
38            } => {
39                let value = self.generate_expression(value);
40                let type_comment = self.variable_type_comment(source_type.as_deref());
41                let line = match (scope, module_name) {
42                    (Scope::Public, Some(module_name)) => {
43                        format!("{module_name}.{name}{type_comment} = {value}")
44                    }
45                    _ => format!("local {name}{type_comment} = {value}"),
46                };
47                self.write_line(&line);
48            }
49            Statement::Assignment { target, value } => {
50                let target = self.generate_expression(target);
51                let value = self.generate_expression(value);
52                self.write_line(&format!("{target} = {value}"));
53            }
54            Statement::Conditional {
55                condition,
56                then_block,
57                else_block,
58            } => {
59                let condition = self.generate_expression(condition);
60                self.write_line(&format!("if {condition} then"));
61
62                self.indent_level += 1;
63                for statement in then_block {
64                    self.generate_statement(statement, module, module_name, Scope::Private)?;
65                }
66                self.indent_level -= 1;
67
68                if !else_block.is_empty() {
69                    self.write_line("else");
70                    self.indent_level += 1;
71                    for statement in else_block {
72                        self.generate_statement(statement, module, module_name, Scope::Private)?;
73                    }
74                    self.indent_level -= 1;
75                }
76                self.write_line("end");
77            }
78            Statement::Return(value) => {
79                let line = value.as_ref().map_or_else(
80                    || "return".to_string(),
81                    |value| format!("return {}", self.generate_expression(value)),
82                );
83                self.write_line(&line);
84            }
85            Statement::Expr(expression) => {
86                self.write_line(&self.generate_expression(expression));
87            }
88            Statement::ForIn { var, iter, body } => {
89                self.for_depth += 1;
90                let depth = self.for_depth;
91                let iter = self.generate_expression(iter);
92                self.write_line(&format!("for _, {var} in pairs({iter}) do"));
93                self.indent_level += 1;
94                for stmt in body {
95                    self.generate_statement(stmt, module, module_name, Scope::Private)?;
96                }
97                if body_has_continue(body) {
98                    self.write_line(&format!("::__continue_{depth}::"));
99                }
100                self.indent_level -= 1;
101                self.write_line("end");
102                self.for_depth -= 1;
103            }
104            Statement::Continue => {
105                self.write_line(&format!("goto __continue_{}", self.for_depth));
106            }
107        }
108
109        Ok(())
110    }
111}