From bd54a3889f6e08ce743367bc94ca22b0fc266f73 Mon Sep 17 00:00:00 2001 From: Jarred Holman Date: Sat, 15 Aug 2020 03:48:33 +0930 Subject: [PATCH] Add missing ops to exec module * Node::ConditionalOp * Node::Continue --- boa/src/exec/block/mod.rs | 6 ++- boa/src/exec/break_node/mod.rs | 14 ++++- boa/src/exec/conditional/mod.rs | 16 +++++- boa/src/exec/iteration/mod.rs | 28 ++++++++-- boa/src/exec/iteration/tests.rs | 92 +++++++++++++++++++++++++++++++++ boa/src/exec/mod.rs | 5 +- boa/src/exec/statement_list.rs | 6 ++- boa/src/exec/switch/mod.rs | 7 ++- boa/src/exec/tests.rs | 6 +++ 9 files changed, 169 insertions(+), 11 deletions(-) diff --git a/boa/src/exec/block/mod.rs b/boa/src/exec/block/mod.rs index ddf4bd3f17d..4835022ed2b 100644 --- a/boa/src/exec/block/mod.rs +++ b/boa/src/exec/block/mod.rs @@ -33,7 +33,11 @@ impl Executable for Block { // Early break. break; } - _ => { + InterpreterState::Continue(_label) => { + // TODO, continue to a label + break; + } + InterpreterState::Executing => { // Continue execution } } diff --git a/boa/src/exec/break_node/mod.rs b/boa/src/exec/break_node/mod.rs index 923aa927c13..76acb67db9b 100644 --- a/boa/src/exec/break_node/mod.rs +++ b/boa/src/exec/break_node/mod.rs @@ -1,5 +1,9 @@ use super::{Executable, Interpreter, InterpreterState}; -use crate::{builtins::value::Value, syntax::ast::node::Break, Result}; +use crate::{ + builtins::value::Value, + syntax::ast::node::{Break, Continue}, + Result, +}; #[cfg(test)] mod tests; @@ -11,3 +15,11 @@ impl Executable for Break { Ok(Value::undefined()) } } + +impl Executable for Continue { + fn run(&self, interpreter: &mut Interpreter) -> Result { + interpreter.set_current_state(InterpreterState::Continue(self.label().map(String::from))); + + Ok(Value::undefined()) + } +} diff --git a/boa/src/exec/conditional/mod.rs b/boa/src/exec/conditional/mod.rs index 92524612059..17409d66ad1 100644 --- a/boa/src/exec/conditional/mod.rs +++ b/boa/src/exec/conditional/mod.rs @@ -1,5 +1,9 @@ use super::{Executable, Interpreter}; -use crate::{builtins::Value, syntax::ast::node::If, Result}; +use crate::{ + builtins::Value, + syntax::ast::node::{ConditionalOp, If}, + Result, +}; use std::borrow::Borrow; impl Executable for If { @@ -13,3 +17,13 @@ impl Executable for If { }) } } + +impl Executable for ConditionalOp { + fn run(&self, interpreter: &mut Interpreter) -> Result { + Ok(if self.cond().run(interpreter)?.borrow().to_boolean() { + self.if_true().run(interpreter)? + } else { + self.if_false().run(interpreter)? + }) + } +} diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index b65ca5e886b..5bd86ebfb84 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -43,10 +43,15 @@ impl Executable for ForLoop { interpreter.set_current_state(InterpreterState::Executing); break; } + InterpreterState::Continue(_label) => { + // TODO continue to label. + interpreter.set_current_state(InterpreterState::Executing); + // after breaking out of the block, continue execution of the loop + } InterpreterState::Return => { return Ok(result); } - _ => { + InterpreterState::Executing => { // Continue execution. } } @@ -76,10 +81,15 @@ impl Executable for WhileLoop { interpreter.set_current_state(InterpreterState::Executing); break; } + InterpreterState::Continue(_label) => { + // TODO continue to label. + interpreter.set_current_state(InterpreterState::Executing); + // after breaking out of the block, continue execution of the loop + } InterpreterState::Return => { return Ok(result); } - _ => { + InterpreterState::Executing => { // Continue execution. } } @@ -99,10 +109,15 @@ impl Executable for DoWhileLoop { interpreter.set_current_state(InterpreterState::Executing); return Ok(result); } + InterpreterState::Continue(_label) => { + // TODO continue to label; + interpreter.set_current_state(InterpreterState::Executing); + // after breaking out of the block, continue execution of the loop + } InterpreterState::Return => { return Ok(result); } - _ => { + InterpreterState::Executing => { // Continue execution. } } @@ -117,10 +132,15 @@ impl Executable for DoWhileLoop { interpreter.set_current_state(InterpreterState::Executing); break; } + InterpreterState::Continue(_label) => { + // TODO continue to label. + interpreter.set_current_state(InterpreterState::Executing); + // after breaking out of the block, continue execution of the loop + } InterpreterState::Return => { return Ok(result); } - _ => { + InterpreterState::Executing => { // Continue execution. } } diff --git a/boa/src/exec/iteration/tests.rs b/boa/src/exec/iteration/tests.rs index 458546364ed..864665b3af4 100644 --- a/boa/src/exec/iteration/tests.rs +++ b/boa/src/exec/iteration/tests.rs @@ -99,3 +99,95 @@ fn do_loop_early_break() { assert_eq!(&exec(scenario), "3"); } + +#[test] +fn break_out_of_inner_loop() { + let scenario = r#" + var a = 0, b = 0; + for (let i = 0; i < 2; i++) { + a++; + for (let j = 0; j < 10; j++) { + b++; + if (j == 3) + break; + } + a++; + } + [a, b] + "#; + assert_eq!(&exec(scenario), "[ 4, 8 ]"); +} + +#[test] +fn continue_inner_loop() { + let scenario = r#" + var a = 0, b = 0; + for (let i = 0; i < 2; i++) { + a++; + for (let j = 0; j < 10; j++) { + if (j < 3) + continue; + b++; + } + a++; + } + [a, b] + "#; + assert_eq!(&exec(scenario), "[ 4, 14 ]"); +} + +#[test] +fn for_loop_continue_out_of_switch() { + let scenario = r#" + var a = 0, b = 0, c = 0; + for (let i = 0; i < 3; i++) { + a++; + switch (i) { + case 0: + continue; + c++; + case 1: + continue; + case 5: + c++; + } + b++; + } + [a, b, c] + "#; + assert_eq!(&exec(scenario), "[ 3, 1, 0 ]"); +} + +#[test] +fn while_loop_continue() { + let scenario = r#" + var i = 0, a = 0, b = 0; + while (i < 3) { + i++; + if (i < 2) { + a++; + continue; + } + b++; + } + [a, b] + "#; + assert_eq!(&exec(scenario), "[ 1, 2 ]"); +} + +#[test] +fn do_while_loop_continue() { + let scenario = r#" + var i = 0, a = 0, b = 0; + do { + i++; + if (i < 2) { + a++; + continue; + } + b++; + } while (i < 3) + [a, b] + "#; + assert_eq!(&exec(scenario), "[ 1, 2 ]"); +} diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 2c05da1a474..6400543d1f0 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -50,6 +50,7 @@ pub(crate) enum InterpreterState { Executing, Return, Break(Option), + Continue(Option), } /// A Javascript intepreter @@ -380,6 +381,7 @@ impl Executable for Node { Node::DoWhileLoop(ref do_while) => do_while.run(interpreter), Node::ForLoop(ref for_loop) => for_loop.run(interpreter), Node::If(ref if_smt) => if_smt.run(interpreter), + Node::ConditionalOp(ref op) => op.run(interpreter), Node::Switch(ref switch) => switch.run(interpreter), Node::Object(ref obj) => obj.run(interpreter), Node::ArrayDecl(ref arr) => arr.run(interpreter), @@ -404,8 +406,7 @@ impl Executable for Node { } Node::Try(ref try_node) => try_node.run(interpreter), Node::Break(ref break_node) => break_node.run(interpreter), - Node::ConditionalOp(_) => unimplemented!("ConditionalOp"), - Node::Continue(_) => unimplemented!("Continue"), + Node::Continue(ref continue_node) => continue_node.run(interpreter), } } } diff --git a/boa/src/exec/statement_list.rs b/boa/src/exec/statement_list.rs index bb358cb8869..df42d6e71fd 100644 --- a/boa/src/exec/statement_list.rs +++ b/boa/src/exec/statement_list.rs @@ -25,7 +25,11 @@ impl Executable for StatementList { // Early break. break; } - _ => { + InterpreterState::Continue(_label) => { + // TODO, continue to a label. + break; + } + InterpreterState::Executing => { // Continue execution } } diff --git a/boa/src/exec/switch/mod.rs b/boa/src/exec/switch/mod.rs index 8eb5dd1c852..b0158ed1d47 100644 --- a/boa/src/exec/switch/mod.rs +++ b/boa/src/exec/switch/mod.rs @@ -28,11 +28,16 @@ impl Executable for Switch { return Ok(result); } InterpreterState::Break(_label) => { + // TODO, break to a label. // Break statement encountered so therefore end switch statement. interpreter.set_current_state(InterpreterState::Executing); break; } - _ => { + InterpreterState::Continue(_label) => { + // TODO, continue to a label. + break; + } + InterpreterState::Executing => { // Continuing execution / falling through to next case statement(s). fall_through = true; } diff --git a/boa/src/exec/tests.rs b/boa/src/exec/tests.rs index 7130cab8124..0f2abd1610f 100644 --- a/boa/src/exec/tests.rs +++ b/boa/src/exec/tests.rs @@ -1233,3 +1233,9 @@ fn test_undefined_type() { let scenario = "typeof undefined"; assert_eq!(&exec(scenario), "\"undefined\""); } + +#[test] +fn test_conditional_op() { + let scenario = "1 === 2 ? 'a' : 'b'"; + assert_eq!(&exec(scenario), "\"b\""); +}