@ -20,7 +20,10 @@ use crate::{
} ,
} ,
pattern ::{ Pattern , PatternArrayElement , PatternObjectElement } ,
pattern ::{ Pattern , PatternArrayElement , PatternObjectElement } ,
property ::{ MethodDefinition , PropertyDefinition , PropertyName } ,
property ::{ MethodDefinition , PropertyDefinition , PropertyName } ,
statement ::iteration ::{ for_loop ::ForLoopInitializer , IterableLoopInitializer } ,
statement ::{
iteration ::{ for_loop ::ForLoopInitializer , IterableLoopInitializer } ,
Block , DoWhileLoop , ForInLoop , ForLoop , ForOfLoop , LabelledItem , WhileLoop ,
} ,
Declaration , Expression , Statement , StatementList , StatementListItem ,
Declaration , Expression , Statement , StatementList , StatementListItem ,
} ,
} ,
vm ::{ BindingOpcode , CodeBlock , Opcode } ,
vm ::{ BindingOpcode , CodeBlock , Opcode } ,
@ -1553,31 +1556,9 @@ impl<'b> ByteCompiler<'b> {
}
}
#[ inline ]
#[ inline ]
pub fn compile_stmt ( & mut self , node : & Statement , use_expr : bool ) -> JsResult < ( ) > {
pub fn compile_for_loop ( & mut self , for_loop : & ForLoop , label : Option < Sym > ) -> JsResult < ( ) > {
match node {
Statement ::Var ( var ) = > self . compile_var_decl ( var ) ? ,
Statement ::If ( node ) = > {
self . compile_expr ( node . cond ( ) , true ) ? ;
let jelse = self . jump_if_false ( ) ;
self . compile_stmt ( node . body ( ) , false ) ? ;
match node . else_node ( ) {
None = > {
self . patch_jump ( jelse ) ;
}
Some ( else_body ) = > {
let exit = self . jump ( ) ;
self . patch_jump ( jelse ) ;
self . compile_stmt ( else_body , false ) ? ;
self . patch_jump ( exit ) ;
}
}
}
Statement ::ForLoop ( for_loop ) = > {
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env =
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
if let Some ( init ) = for_loop . init ( ) {
if let Some ( init ) = for_loop . init ( ) {
match init {
match init {
@ -1597,7 +1578,7 @@ impl<'b> ByteCompiler<'b> {
let initial_jump = self . jump ( ) ;
let initial_jump = self . jump ( ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info ( for_loop . label ( ) , start_address ) ;
self . push_loop_control_info ( label , start_address ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
if let Some ( final_expr ) = for_loop . final_expr ( ) {
if let Some ( final_expr ) = for_loop . final_expr ( ) {
@ -1621,31 +1602,34 @@ impl<'b> ByteCompiler<'b> {
self . pop_loop_control_info ( ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
let ( num_bindings , compile_environment ) =
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
Ok ( ( ) )
}
}
Statement ::ForInLoop ( for_in_loop ) = > {
#[ inline ]
pub fn compile_for_in_loop (
& mut self ,
for_in_loop : & ForInLoop ,
label : Option < Sym > ,
) -> JsResult < ( ) > {
let init_bound_names = for_in_loop . init ( ) . bound_names ( ) ;
let init_bound_names = for_in_loop . init ( ) . bound_names ( ) ;
if init_bound_names . is_empty ( ) {
if init_bound_names . is_empty ( ) {
self . compile_expr ( for_in_loop . expr ( ) , true ) ? ;
self . compile_expr ( for_in_loop . expr ( ) , true ) ? ;
} else {
} else {
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env =
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
for name in init_bound_names {
for name in init_bound_names {
self . context . create_mutable_binding ( name , false ) ;
self . context . create_mutable_binding ( name , false ) ;
}
}
self . compile_expr ( for_in_loop . expr ( ) , true ) ? ;
self . compile_expr ( for_in_loop . expr ( ) , true ) ? ;
let ( num_bindings , compile_environment ) =
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
let index_compile_environment =
self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
@ -1655,12 +1639,11 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::LoopStart ) ;
self . emit_opcode ( Opcode ::LoopStart ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info_for_of_in_loop ( for_in_loop . label ( ) , start_address ) ;
self . push_loop_control_info_for_of_in_loop ( label , start_address ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env =
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::ForInLoopNext ) ;
let exit = self . emit_opcode_with_operand ( Opcode ::ForInLoopNext ) ;
match for_in_loop . init ( ) {
match for_in_loop . init ( ) {
@ -1716,8 +1699,7 @@ impl<'b> ByteCompiler<'b> {
self . compile_stmt ( for_in_loop . body ( ) , false ) ? ;
self . compile_stmt ( for_in_loop . body ( ) , false ) ? ;
let ( num_bindings , compile_environment ) =
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
@ -1731,25 +1713,29 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::IteratorClose ) ;
self . emit_opcode ( Opcode ::IteratorClose ) ;
self . patch_jump ( early_exit ) ;
self . patch_jump ( early_exit ) ;
Ok ( ( ) )
}
}
Statement ::ForOfLoop ( for_of_loop ) = > {
#[ inline ]
pub fn compile_for_of_loop (
& mut self ,
for_of_loop : & ForOfLoop ,
label : Option < Sym > ,
) -> JsResult < ( ) > {
let init_bound_names = for_of_loop . init ( ) . bound_names ( ) ;
let init_bound_names = for_of_loop . init ( ) . bound_names ( ) ;
if init_bound_names . is_empty ( ) {
if init_bound_names . is_empty ( ) {
self . compile_expr ( for_of_loop . iterable ( ) , true ) ? ;
self . compile_expr ( for_of_loop . iterable ( ) , true ) ? ;
} else {
} else {
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env =
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
for name in init_bound_names {
for name in init_bound_names {
self . context . create_mutable_binding ( name , false ) ;
self . context . create_mutable_binding ( name , false ) ;
}
}
self . compile_expr ( for_of_loop . iterable ( ) , true ) ? ;
self . compile_expr ( for_of_loop . iterable ( ) , true ) ? ;
let ( num_bindings , compile_environment ) =
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
let index_compile_environment =
self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
self . emit_opcode ( Opcode ::PopEnvironment ) ;
@ -1763,12 +1749,11 @@ impl<'b> ByteCompiler<'b> {
self . emit_opcode ( Opcode ::LoopStart ) ;
self . emit_opcode ( Opcode ::LoopStart ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info_for_of_in_loop ( for_of_loop . label ( ) , start_address ) ;
self . push_loop_control_info_for_of_in_loop ( label , start_address ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . context . push_compile_time_environment ( false ) ;
self . context . push_compile_time_environment ( false ) ;
let push_env =
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
let exit = if for_of_loop . r#await ( ) {
let exit = if for_of_loop . r#await ( ) {
self . emit_opcode ( Opcode ::ForAwaitOfLoopIterate ) ;
self . emit_opcode ( Opcode ::ForAwaitOfLoopIterate ) ;
@ -1832,8 +1817,7 @@ impl<'b> ByteCompiler<'b> {
self . compile_stmt ( for_of_loop . body ( ) , false ) ? ;
self . compile_stmt ( for_of_loop . body ( ) , false ) ? ;
let ( num_bindings , compile_environment ) =
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
@ -1845,43 +1829,144 @@ impl<'b> ByteCompiler<'b> {
self . pop_loop_control_info ( ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::IteratorClose ) ;
self . emit_opcode ( Opcode ::IteratorClose ) ;
Ok ( ( ) )
}
}
Statement ::WhileLoop ( while_ ) = > {
#[ inline ]
pub fn compile_while_loop (
& mut self ,
while_loop : & WhileLoop ,
label : Option < Sym > ,
) -> JsResult < ( ) > {
self . emit_opcode ( Opcode ::LoopStart ) ;
self . emit_opcode ( Opcode ::LoopStart ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info ( while_ . label ( ) , start_address ) ;
self . push_loop_control_info ( label , start_address ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . compile_expr ( while_ . condition ( ) , true ) ? ;
self . compile_expr ( while_loop . condition ( ) , true ) ? ;
let exit = self . jump_if_false ( ) ;
let exit = self . jump_if_false ( ) ;
self . compile_stmt ( while_ . body ( ) , false ) ? ;
self . compile_stmt ( while_loop . body ( ) , false ) ? ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . emit ( Opcode ::Jump , & [ start_address ] ) ;
self . patch_jump ( exit ) ;
self . patch_jump ( exit ) ;
self . pop_loop_control_info ( ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
Ok ( ( ) )
}
}
Statement ::DoWhileLoop ( do_while ) = > {
#[ inline ]
pub fn compile_do_while_loop (
& mut self ,
do_while_loop : & DoWhileLoop ,
label : Option < Sym > ,
) -> JsResult < ( ) > {
self . emit_opcode ( Opcode ::LoopStart ) ;
self . emit_opcode ( Opcode ::LoopStart ) ;
let initial_label = self . jump ( ) ;
let initial_label = self . jump ( ) ;
let start_address = self . next_opcode_location ( ) ;
let start_address = self . next_opcode_location ( ) ;
self . push_loop_control_info ( do_while . label ( ) , start_address ) ;
self . push_loop_control_info ( label , start_address ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
self . emit_opcode ( Opcode ::LoopContinue ) ;
let condition_label_address = self . next_opcode_location ( ) ;
let condition_label_address = self . next_opcode_location ( ) ;
self . compile_expr ( do_while . cond ( ) , true ) ? ;
self . compile_expr ( do_while_loop . cond ( ) , true ) ? ;
let exit = self . jump_if_false ( ) ;
let exit = self . jump_if_false ( ) ;
self . patch_jump ( initial_label ) ;
self . patch_jump ( initial_label ) ;
self . compile_stmt ( do_while . body ( ) , false ) ? ;
self . compile_stmt ( do_while_loop . body ( ) , false ) ? ;
self . emit ( Opcode ::Jump , & [ condition_label_address ] ) ;
self . emit ( Opcode ::Jump , & [ condition_label_address ] ) ;
self . patch_jump ( exit ) ;
self . patch_jump ( exit ) ;
self . pop_loop_control_info ( ) ;
self . pop_loop_control_info ( ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
self . emit_opcode ( Opcode ::LoopEnd ) ;
Ok ( ( ) )
}
}
#[ inline ]
pub fn compile_block (
& mut self ,
block : & Block ,
label : Option < Sym > ,
use_expr : bool ,
) -> JsResult < ( ) > {
if let Some ( label ) = label {
let next = self . next_opcode_location ( ) ;
self . push_labelled_block_control_info ( label , next ) ;
}
self . context . push_compile_time_environment ( false ) ;
let push_env = self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . create_decls ( block . statement_list ( ) ) ;
self . compile_statement_list ( block . statement_list ( ) , use_expr ) ? ;
let ( num_bindings , compile_environment ) = self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
if label . is_some ( ) {
self . pop_labelled_block_control_info ( ) ;
}
self . emit_opcode ( Opcode ::PopEnvironment ) ;
Ok ( ( ) )
}
#[ inline ]
pub fn compile_stmt ( & mut self , node : & Statement , use_expr : bool ) -> JsResult < ( ) > {
match node {
Statement ::Var ( var ) = > self . compile_var_decl ( var ) ? ,
Statement ::If ( node ) = > {
self . compile_expr ( node . cond ( ) , true ) ? ;
let jelse = self . jump_if_false ( ) ;
self . compile_stmt ( node . body ( ) , false ) ? ;
match node . else_node ( ) {
None = > {
self . patch_jump ( jelse ) ;
}
Some ( else_body ) = > {
let exit = self . jump ( ) ;
self . patch_jump ( jelse ) ;
self . compile_stmt ( else_body , false ) ? ;
self . patch_jump ( exit ) ;
}
}
}
Statement ::ForLoop ( for_loop ) = > self . compile_for_loop ( for_loop , None ) ? ,
Statement ::ForInLoop ( for_in_loop ) = > self . compile_for_in_loop ( for_in_loop , None ) ? ,
Statement ::ForOfLoop ( for_of_loop ) = > self . compile_for_of_loop ( for_of_loop , None ) ? ,
Statement ::WhileLoop ( while_loop ) = > self . compile_while_loop ( while_loop , None ) ? ,
Statement ::DoWhileLoop ( do_while_loop ) = > {
self . compile_do_while_loop ( do_while_loop , None ) ? ;
}
Statement ::Block ( block ) = > self . compile_block ( block , None , use_expr ) ? ,
Statement ::Labelled ( labelled ) = > match labelled . item ( ) {
LabelledItem ::Statement ( stmt ) = > match stmt {
Statement ::ForLoop ( for_loop ) = > {
self . compile_for_loop ( for_loop , Some ( labelled . label ( ) ) ) ? ;
}
Statement ::ForInLoop ( for_in_loop ) = > {
self . compile_for_in_loop ( for_in_loop , Some ( labelled . label ( ) ) ) ? ;
}
Statement ::ForOfLoop ( for_of_loop ) = > {
self . compile_for_of_loop ( for_of_loop , Some ( labelled . label ( ) ) ) ? ;
}
Statement ::WhileLoop ( while_loop ) = > {
self . compile_while_loop ( while_loop , Some ( labelled . label ( ) ) ) ? ;
}
Statement ::DoWhileLoop ( do_while_loop ) = > {
self . compile_do_while_loop ( do_while_loop , Some ( labelled . label ( ) ) ) ? ;
}
Statement ::Block ( block ) = > {
self . compile_block ( block , Some ( labelled . label ( ) ) , use_expr ) ? ;
}
stmt = > self . compile_stmt ( stmt , use_expr ) ? ,
} ,
LabelledItem ::Function ( f ) = > {
self . function ( f . into ( ) , NodeKind ::Declaration , false ) ? ;
}
} ,
Statement ::Continue ( node ) = > {
Statement ::Continue ( node ) = > {
let next = self . next_opcode_location ( ) ;
let next = self . next_opcode_location ( ) ;
if let Some ( info ) = self
if let Some ( info ) = self
@ -2020,29 +2105,6 @@ impl<'b> ByteCompiler<'b> {
. push ( label ) ;
. push ( label ) ;
}
}
}
}
Statement ::Block ( block ) = > {
if let Some ( label ) = block . label ( ) {
let next = self . next_opcode_location ( ) ;
self . push_labelled_block_control_info ( label , next ) ;
}
self . context . push_compile_time_environment ( false ) ;
let push_env =
self . emit_opcode_with_two_operands ( Opcode ::PushDeclarativeEnvironment ) ;
self . create_decls ( block . statement_list ( ) ) ;
self . compile_statement_list ( block . statement_list ( ) , use_expr ) ? ;
let ( num_bindings , compile_environment ) =
self . context . pop_compile_time_environment ( ) ;
let index_compile_environment = self . push_compile_environment ( compile_environment ) ;
self . patch_jump_with_target ( push_env . 0 , num_bindings as u32 ) ;
self . patch_jump_with_target ( push_env . 1 , index_compile_environment as u32 ) ;
if block . label ( ) . is_some ( ) {
self . pop_labelled_block_control_info ( ) ;
}
self . emit_opcode ( Opcode ::PopEnvironment ) ;
}
Statement ::Throw ( throw ) = > {
Statement ::Throw ( throw ) = > {
self . compile_expr ( throw . expr ( ) , true ) ? ;
self . compile_expr ( throw . expr ( ) , true ) ? ;
self . emit ( Opcode ::Throw , & [ ] ) ;
self . emit ( Opcode ::Throw , & [ ] ) ;