jetcrab\bytecode\statements/
control_statements.rs

1use crate::ast::Node;
2use crate::vm::instructions::Instruction;
3use crate::vm::types::CodeAddress;
4
5use super::{ControlFlowCore, LabelManager};
6
7pub fn generate_break_statement<T>(this: &mut T, node: &Node)
8where
9    T: ControlFlowCore + LabelManager,
10{
11    if let Node::BreakStatement(stmt) = node {
12        if let Some(label) = &stmt.label {
13            // Break with label - jump to the labeled statement end
14            if let Node::Identifier(label_name) = &**label {
15                if let Some(label_end_address) = this.get_label_end_address(label_name) {
16                    // Break with specific label - jump to the end of the labeled statement
17                    this.instructions()
18                        .push(Instruction::Jump(label_end_address));
19                } else {
20                    // Label not found, use default break behavior
21                    this.instructions()
22                        .push(Instruction::Jump(CodeAddress::new(9999)));
23                }
24            } else {
25                // Invalid label type, use default break behavior
26                this.instructions()
27                    .push(Instruction::Jump(CodeAddress::new(9999)));
28            }
29        } else {
30            // Break without label - use default break behavior
31            this.instructions()
32                .push(Instruction::Jump(CodeAddress::new(9999)));
33        }
34    }
35}
36
37pub fn generate_continue_statement<T>(this: &mut T, node: &Node)
38where
39    T: ControlFlowCore + LabelManager,
40{
41    if let Node::ContinueStatement(stmt) = node {
42        if let Some(label) = &stmt.label {
43            // Continue with label - jump to the labeled statement start
44            if let Node::Identifier(label_name) = &**label {
45                if let Some(label_start_address) = this.get_label_start_address(label_name) {
46                    // Continue with specific label - jump to the start of the labeled statement
47                    this.instructions()
48                        .push(Instruction::Jump(label_start_address));
49                } else {
50                    // Label not found, use default continue behavior
51                    this.instructions()
52                        .push(Instruction::Jump(CodeAddress::new(8888)));
53                }
54            } else {
55                // Invalid label type, use default continue behavior
56                this.instructions()
57                    .push(Instruction::Jump(CodeAddress::new(8888)));
58            }
59        } else {
60            // Continue without label - use default continue behavior
61            this.instructions()
62                .push(Instruction::Jump(CodeAddress::new(8888)));
63        }
64    }
65}
66
67pub fn generate_return_statement<T>(this: &mut T, node: &Node)
68where
69    T: ControlFlowCore,
70{
71    if let Node::ReturnStatement(stmt) = node {
72        if let Some(arg) = &stmt.argument {
73            this.visit_node(arg);
74        }
75        this.instructions().push(Instruction::Return);
76    }
77}
78
79pub fn generate_labeled_statement<T>(this: &mut T, node: &Node)
80where
81    T: ControlFlowCore + LabelManager,
82{
83    if let Node::LabeledStatement(stmt) = node {
84        // Extract label name
85        let label_name = if let Node::Identifier(name) = &*stmt.label {
86            name.clone()
87        } else {
88            "unknown".to_string()
89        };
90
91        // Mark the start of the labeled statement
92        let label_start = this.instructions().len();
93
94        // Store the label start address
95        this.add_label(
96            format!("{}_start", label_name),
97            CodeAddress::new(label_start),
98        );
99
100        // Push current label for nested statements
101        this.push_current_label(label_name.clone());
102
103        // Generate the labeled statement body
104        this.visit_node(&stmt.body);
105
106        // Mark the end of the labeled statement
107        let label_end = this.instructions().len();
108
109        // Store the label end address
110        this.add_label(format!("{}_end", label_name), CodeAddress::new(label_end));
111
112        // Pop current label
113        this.pop_current_label();
114
115        // TODO: Handle break/continue with this label
116        // We need to patch any break/continue statements that reference this label
117    }
118}