boa_engine/bytecompiler/statement/
mod.rs1use 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 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 !self.is_async_generator()
71 && self
72 .return_jump_record_actions()
73 .iter()
74 .all(|action| matches!(action, JumpRecordAction::PopEnvironments { .. }))
75 {
76 match ret.target() {
77 Some(expr) => self.compile_expr_operand(expr, |compiler, value| {
78 compiler.bytecode.emit_set_accumulator(value);
79 }),
80 None => self
81 .bytecode
82 .emit_set_accumulator(CallFrame::undefined_register().variable()),
83 }
84 self.r#return(false);
85 return;
86 }
87 if let Some(expr) = ret.target() {
88 if self.is_async_generator() {
89 let value = self.register_allocator.alloc();
90 self.compile_expr(expr, &value);
91 self.bytecode.emit_await(value.variable());
92 let resume_kind = self.register_allocator.alloc();
93 self.pop_into_register(&resume_kind);
94 self.pop_into_register(&value);
95 self.generator_next(&value, &resume_kind);
96 self.register_allocator.dealloc(resume_kind);
97 self.push_from_register(&value);
98 self.register_allocator.dealloc(value);
99 } else {
100 self.compile_expr_to_stack(expr);
101 }
102 } else {
103 self.push_from_register(&CallFrame::undefined_register());
104 }
105
106 self.r#return(true);
107 }
108 Statement::Try(t) => self.compile_try(t, use_expr),
109 Statement::Expression(expr) => {
110 if use_expr {
111 let value = self.register_allocator.alloc();
112 self.compile_expr(expr, &value);
113 self.bytecode.emit_set_accumulator(value.variable());
114 self.register_allocator.dealloc(value);
115 } else {
116 self.compile_expr_for_side_effects(expr);
117 }
118 }
119 Statement::With(with) => self.compile_with(with, use_expr),
120 Statement::Empty | Statement::Debugger => {}
121 }
122 }
123
124 pub(crate) fn r#return(&mut self, return_value_on_stack: bool) {
125 let actions = self.return_jump_record_actions();
126
127 JumpRecord::new(
128 JumpRecordKind::Return {
129 return_value_on_stack,
130 },
131 actions,
132 )
133 .perform_actions(Self::DUMMY_ADDRESS, self);
134 }
135
136 fn return_jump_record_actions(&self) -> Vec<JumpRecordAction> {
137 let mut actions = Vec::default();
138 for (i, info) in self.jump_info.iter().enumerate().rev() {
139 let count = self.jump_info_open_environment_count(i);
140 actions.push(JumpRecordAction::PopEnvironments { count });
141
142 if !info.in_finally()
143 && let Some((finally_throw_flag, finally_throw_index)) = info.finally_throw
144 {
145 actions.push(JumpRecordAction::HandleFinally {
146 index: info.jumps.len() as u32,
147 finally_throw_flag,
148 finally_throw_index,
149 });
150 actions.push(JumpRecordAction::Transfer { index: i as u32 });
151 }
152
153 if info.iterator_loop() {
154 actions.push(JumpRecordAction::CloseIterator {
155 r#async: info.for_await_of_loop(),
156 });
157 }
158 }
159
160 actions.reverse();
161 actions
162 }
163}