jetcrab\bytecode\statements/
loop_statements.rs

1use crate::ast::Node;
2use crate::vm::instructions::Instruction;
3use crate::vm::types::CodeAddress;
4
5use super::ControlFlowCore;
6
7pub fn generate_for_statement<T>(this: &mut T, node: &Node)
8where
9    T: ControlFlowCore,
10{
11    if let Node::ForStatement(stmt) = node {
12        // Generate initialization
13        if let Some(init) = &stmt.init {
14            this.visit_node(init);
15        }
16
17        // Mark the start of the loop (test condition)
18        let loop_start = this.instructions().len();
19
20        // Generate test condition
21        if let Some(test) = &stmt.test {
22            this.visit_node(test);
23
24            // Jump out of loop if condition is false
25            let jump_out_pos = this.instructions().len();
26            this.instructions()
27                .push(Instruction::JumpIfFalse(CodeAddress::new(0))); // Placeholder
28
29            // Generate loop body
30            this.visit_node(&stmt.body);
31
32            // Generate update
33            if let Some(update) = &stmt.update {
34                this.visit_node(update);
35            }
36
37            // Jump back to loop start (test condition)
38            this.instructions()
39                .push(Instruction::Jump(CodeAddress::new(loop_start)));
40
41            // Mark the end of the loop
42            let loop_end = this.instructions().len();
43
44            // Update jump out address
45            this.instructions()[jump_out_pos] =
46                Instruction::JumpIfFalse(CodeAddress::new(loop_end));
47
48            // Patch all break statements (Jump to 9999) in this loop
49            for i in loop_start..loop_end {
50                if let Instruction::Jump(addr) = &this.instructions()[i] {
51                    if addr.as_usize() == 9999 {
52                        this.instructions()[i] = Instruction::Jump(CodeAddress::new(loop_end));
53                    }
54                }
55            }
56
57            // Patch all continue statements (Jump to 8888) in this loop
58            // Continue should jump to the update expression (or condition test)
59            let continue_target = if let Some(_) = &stmt.update {
60                // If there's an update, continue goes to the update expression
61                // We need to find where the update expression starts
62                // For now, we'll use the condition test position
63                loop_start
64            } else {
65                // If no update, continue goes to the condition test
66                loop_start
67            };
68
69            for i in loop_start..loop_end {
70                if let Instruction::Jump(addr) = &this.instructions()[i] {
71                    if addr.as_usize() == 8888 {
72                        this.instructions()[i] = Instruction::Jump(CodeAddress::new(continue_target));
73                    }
74                }
75            }
76        } else {
77            // Infinite loop (no test condition)
78            this.visit_node(&stmt.body);
79
80            // Generate update
81            if let Some(update) = &stmt.update {
82                this.visit_node(update);
83            }
84
85            // Jump back to loop start
86            this.instructions()
87                .push(Instruction::Jump(CodeAddress::new(loop_start)));
88        }
89    }
90}
91
92pub fn generate_while_statement<T>(this: &mut T, node: &Node)
93where
94    T: ControlFlowCore,
95{
96    if let Node::WhileStatement(stmt) = node {
97        // Mark the start of the loop
98        let loop_start = this.instructions().len();
99
100        // Check if condition is a literal true
101        let is_true_literal = matches!(&*stmt.test, Node::Boolean(true));
102
103        let jump_out_pos = if !is_true_literal {
104            // Generate test condition
105            this.visit_node(&stmt.test);
106
107            // Jump out of loop if condition is false
108            let pos = this.instructions().len();
109            this.instructions()
110                .push(Instruction::JumpIfFalse(CodeAddress::new(0))); // Placeholder
111            Some(pos)
112        } else {
113            // For while(true), we don't generate a condition test
114            None
115        };
116
117        // Generate loop body
118        this.visit_node(&stmt.body);
119
120        // Jump back to loop start
121        this.instructions()
122            .push(Instruction::Jump(CodeAddress::new(loop_start)));
123
124        // Mark the end of the loop (for break statements)
125        let loop_end = this.instructions().len();
126
127        // Update jump out address if we have one
128        if let Some(jump_pos) = jump_out_pos {
129            this.instructions()[jump_pos] =
130                Instruction::JumpIfFalse(CodeAddress::new(loop_end));
131        }
132
133        // Patch all break statements (Jump to 9999) in this loop
134        for i in loop_start..loop_end {
135            if let Instruction::Jump(addr) = &this.instructions()[i] {
136                if addr.as_usize() == 9999 {
137                    this.instructions()[i] = Instruction::Jump(CodeAddress::new(loop_end));
138                }
139            }
140        }
141
142        // Patch all continue statements (Jump to 8888) in this loop
143        // Continue should jump to the loop start (or condition test)
144        let continue_target = if !is_true_literal {
145            // For normal while loops, continue goes to the condition test
146            loop_start
147        } else {
148            // For while(true), continue goes to the loop start
149            loop_start
150        };
151
152        for i in loop_start..loop_end {
153            if let Instruction::Jump(addr) = &this.instructions()[i] {
154                if addr.as_usize() == 8888 {
155                    this.instructions()[i] = Instruction::Jump(CodeAddress::new(continue_target));
156                }
157            }
158        }
159    }
160}
161
162pub fn generate_do_while_statement<T>(this: &mut T, node: &Node)
163where
164    T: ControlFlowCore,
165{
166    if let Node::DoWhileStatement(stmt) = node {
167        // Mark the start of the loop body
168        let loop_start = this.instructions().len();
169
170        // Generate loop body (executes at least once)
171        this.visit_node(&stmt.body);
172
173        // Generate test condition
174        this.visit_node(&stmt.test);
175
176        // Jump back to loop start if condition is true
177        this.instructions()
178            .push(Instruction::JumpIfTrue(CodeAddress::new(loop_start)));
179
180        // Mark the end of the loop (for break statements)
181        let loop_end = this.instructions().len();
182
183        // Patch all break statements (Jump to 9999) in this loop
184        for i in loop_start..loop_end {
185            if let Instruction::Jump(addr) = &this.instructions()[i] {
186                if addr.as_usize() == 9999 {
187                    this.instructions()[i] = Instruction::Jump(CodeAddress::new(loop_end));
188                }
189            }
190        }
191
192        // Patch all continue statements (Jump to 8888) in this loop
193        // Continue should jump to the test condition
194        for i in loop_start..loop_end {
195            if let Instruction::Jump(addr) = &this.instructions()[i] {
196                if addr.as_usize() == 8888 {
197                    // Find the position where the test condition starts
198                    let test_start = loop_start + 1; // After the body
199                    this.instructions()[i] = Instruction::Jump(CodeAddress::new(test_start));
200                }
201            }
202        }
203    }
204}
205
206pub fn generate_for_in_statement<T>(this: &mut T, node: &Node)
207where
208    T: ControlFlowCore,
209{
210    if let Node::ForInStatement(stmt) = node {
211        // For now, implement a simplified version
212        // TODO: Implement proper for...in semantics
213        this.visit_node(&stmt.left);
214        this.visit_node(&stmt.right);
215        this.visit_node(&stmt.body);
216    }
217}
218
219pub fn generate_for_of_statement<T>(this: &mut T, node: &Node)
220where
221    T: ControlFlowCore,
222{
223    if let Node::ForOfStatement(stmt) = node {
224        // For now, implement a simplified version
225        // TODO: Implement proper for...of semantics
226        this.visit_node(&stmt.left);
227        this.visit_node(&stmt.right);
228        this.visit_node(&stmt.body);
229    }
230}