Skip to main content

boa_engine/bytecompiler/statement/
mod.rs

1use super::jump_control::{JumpRecord, JumpRecordAction, JumpRecordKind};
2use crate::{bytecompiler::ByteCompiler, vm::CallFrame};
3use boa_ast::Statement;
4
5mod block;
6mod r#break;
7mod r#continue;
8mod r#if;
9mod labelled;
10mod r#loop;
11mod switch;
12mod r#try;
13mod with;
14
15impl ByteCompiler<'_> {
16    /// Compiles a [`Statement`] `boa_ast` node.
17    pub fn compile_stmt(&mut self, node: &Statement, use_expr: bool, root_statement: bool) {
18        match node {
19            Statement::Var(var) => self.compile_var_decl(var),
20            Statement::If(node) => self.compile_if(node, use_expr),
21            Statement::ForLoop(for_loop) => {
22                self.compile_for_loop(for_loop, None, use_expr);
23            }
24            Statement::ForInLoop(for_in_loop) => {
25                self.compile_for_in_loop(for_in_loop, None, use_expr);
26            }
27            Statement::ForOfLoop(for_of_loop) => {
28                self.compile_for_of_loop(for_of_loop, None, use_expr);
29            }
30            Statement::WhileLoop(while_loop) => {
31                self.compile_while_loop(while_loop, None, use_expr);
32            }
33            Statement::DoWhileLoop(do_while_loop) => {
34                self.compile_do_while_loop(do_while_loop, None, use_expr);
35            }
36            Statement::Block(block) => {
37                self.compile_block(block, use_expr);
38            }
39            Statement::Labelled(labelled) => {
40                self.compile_labelled(labelled, use_expr);
41            }
42            Statement::Continue(node) => {
43                if root_statement && (use_expr || self.jump_control_info_has_use_expr()) {
44                    self.bytecode
45                        .emit_set_accumulator(CallFrame::undefined_register().variable());
46                }
47                self.compile_continue(*node, use_expr);
48            }
49            Statement::Break(node) => {
50                if root_statement && (use_expr || self.jump_control_info_has_use_expr()) {
51                    self.bytecode
52                        .emit_set_accumulator(CallFrame::undefined_register().variable());
53                }
54                self.compile_break(*node, use_expr);
55            }
56            Statement::Throw(throw) => {
57                let mut compiler = self.position_guard(throw.target());
58
59                let error = compiler.register_allocator.alloc();
60                compiler.compile_expr(throw.target(), &error);
61                compiler.bytecode.emit_throw(error.variable());
62                compiler.register_allocator.dealloc(error);
63            }
64            Statement::Switch(switch) => {
65                self.compile_switch(switch, use_expr);
66            }
67            Statement::Return(ret) => {
68                if let Some(expr) = ret.target() {
69                    if self.is_async_generator() {
70                        let value = self.register_allocator.alloc();
71                        self.compile_expr(expr, &value);
72                        self.bytecode.emit_await(value.variable());
73                        let resume_kind = self.register_allocator.alloc();
74                        self.pop_into_register(&resume_kind);
75                        self.pop_into_register(&value);
76                        self.generator_next(&value, &resume_kind);
77                        self.register_allocator.dealloc(resume_kind);
78                        self.push_from_register(&value);
79                        self.register_allocator.dealloc(value);
80                    } else {
81                        self.compile_expr_to_stack(expr);
82                    }
83                } else {
84                    self.push_from_register(&CallFrame::undefined_register());
85                }
86
87                self.r#return(true);
88            }
89            Statement::Try(t) => self.compile_try(t, use_expr),
90            Statement::Expression(expr) => {
91                if use_expr {
92                    let value = self.register_allocator.alloc();
93                    self.compile_expr(expr, &value);
94                    self.bytecode.emit_set_accumulator(value.variable());
95                    self.register_allocator.dealloc(value);
96                } else {
97                    self.compile_expr_for_side_effects(expr);
98                }
99            }
100            Statement::With(with) => self.compile_with(with, use_expr),
101            Statement::Empty | Statement::Debugger => {}
102        }
103    }
104
105    pub(crate) fn r#return(&mut self, return_value_on_stack: bool) {
106        let actions = self.return_jump_record_actions();
107
108        JumpRecord::new(
109            JumpRecordKind::Return {
110                return_value_on_stack,
111            },
112            actions,
113        )
114        .perform_actions(Self::DUMMY_ADDRESS, self);
115    }
116
117    fn return_jump_record_actions(&self) -> Vec<JumpRecordAction> {
118        let mut actions = Vec::default();
119        for (i, info) in self.jump_info.iter().enumerate().rev() {
120            let count = self.jump_info_open_environment_count(i);
121            actions.push(JumpRecordAction::PopEnvironments { count });
122
123            if !info.in_finally()
124                && let Some((finally_throw_flag, finally_throw_index)) = info.finally_throw
125            {
126                actions.push(JumpRecordAction::HandleFinally {
127                    index: info.jumps.len() as u32,
128                    finally_throw_flag,
129                    finally_throw_index,
130                });
131                actions.push(JumpRecordAction::Transfer { index: i as u32 });
132            }
133
134            if info.iterator_loop() {
135                actions.push(JumpRecordAction::CloseIterator {
136                    r#async: info.for_await_of_loop(),
137                });
138            }
139        }
140
141        actions.reverse();
142        actions
143    }
144}