Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing ops to exec module #635

Merged
merged 1 commit into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion boa/src/exec/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ impl Executable for Block {
// Early break.
break;
}
_ => {
InterpreterState::Continue(_label) => {
// TODO, continue to a label
break;
}
InterpreterState::Executing => {
// Continue execution
}
}
Expand Down
14 changes: 13 additions & 1 deletion boa/src/exec/break_node/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -11,3 +15,11 @@ impl Executable for Break {
Ok(Value::undefined())
}
}

impl Executable for Continue {
fn run(&self, interpreter: &mut Interpreter) -> Result<Value> {
interpreter.set_current_state(InterpreterState::Continue(self.label().map(String::from)));

Ok(Value::undefined())
}
}
16 changes: 15 additions & 1 deletion boa/src/exec/conditional/mod.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -13,3 +17,13 @@ impl Executable for If {
})
}
}

impl Executable for ConditionalOp {
fn run(&self, interpreter: &mut Interpreter) -> Result<Value> {
Ok(if self.cond().run(interpreter)?.borrow().to_boolean() {
self.if_true().run(interpreter)?
} else {
self.if_false().run(interpreter)?
})
}
}
28 changes: 24 additions & 4 deletions boa/src/exec/iteration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
}
Expand Down Expand Up @@ -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.
}
}
Expand All @@ -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.
}
}
Expand All @@ -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.
}
}
Expand Down
92 changes: 92 additions & 0 deletions boa/src/exec/iteration/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]");
}
5 changes: 3 additions & 2 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub(crate) enum InterpreterState {
Executing,
Return,
Break(Option<String>),
Continue(Option<String>),
}

/// A Javascript intepreter
Expand Down Expand Up @@ -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),
Expand All @@ -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),
}
}
}
6 changes: 5 additions & 1 deletion boa/src/exec/statement_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ impl Executable for StatementList {
// Early break.
break;
}
_ => {
InterpreterState::Continue(_label) => {
// TODO, continue to a label.
break;
}
InterpreterState::Executing => {
// Continue execution
}
}
Expand Down
7 changes: 6 additions & 1 deletion boa/src/exec/switch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
6 changes: 6 additions & 0 deletions boa/src/exec/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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\"");
}