Browse Source

Add missing ops to exec module (#635)

* Node::ConditionalOp
* Node::Continue
pull/662/head
Jarred Holman 4 years ago committed by GitHub
parent
commit
c7531afd10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      boa/src/exec/block/mod.rs
  2. 14
      boa/src/exec/break_node/mod.rs
  3. 16
      boa/src/exec/conditional/mod.rs
  4. 28
      boa/src/exec/iteration/mod.rs
  5. 92
      boa/src/exec/iteration/tests.rs
  6. 5
      boa/src/exec/mod.rs
  7. 6
      boa/src/exec/statement_list.rs
  8. 7
      boa/src/exec/switch/mod.rs
  9. 6
      boa/src/exec/tests.rs

6
boa/src/exec/block/mod.rs

@ -33,7 +33,11 @@ impl Executable for Block {
// Early break. // Early break.
break; break;
} }
_ => { InterpreterState::Continue(_label) => {
// TODO, continue to a label
break;
}
InterpreterState::Executing => {
// Continue execution // Continue execution
} }
} }

14
boa/src/exec/break_node/mod.rs

@ -1,5 +1,9 @@
use super::{Executable, Interpreter, InterpreterState}; 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)] #[cfg(test)]
mod tests; mod tests;
@ -11,3 +15,11 @@ impl Executable for Break {
Ok(Value::undefined()) 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
boa/src/exec/conditional/mod.rs

@ -1,5 +1,9 @@
use super::{Executable, Interpreter}; 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; use std::borrow::Borrow;
impl Executable for If { impl Executable for If {
@ -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
boa/src/exec/iteration/mod.rs

@ -43,10 +43,15 @@ impl Executable for ForLoop {
interpreter.set_current_state(InterpreterState::Executing); interpreter.set_current_state(InterpreterState::Executing);
break; 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 => { InterpreterState::Return => {
return Ok(result); return Ok(result);
} }
_ => { InterpreterState::Executing => {
// Continue execution. // Continue execution.
} }
} }
@ -76,10 +81,15 @@ impl Executable for WhileLoop {
interpreter.set_current_state(InterpreterState::Executing); interpreter.set_current_state(InterpreterState::Executing);
break; 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 => { InterpreterState::Return => {
return Ok(result); return Ok(result);
} }
_ => { InterpreterState::Executing => {
// Continue execution. // Continue execution.
} }
} }
@ -99,10 +109,15 @@ impl Executable for DoWhileLoop {
interpreter.set_current_state(InterpreterState::Executing); interpreter.set_current_state(InterpreterState::Executing);
return Ok(result); 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 => { InterpreterState::Return => {
return Ok(result); return Ok(result);
} }
_ => { InterpreterState::Executing => {
// Continue execution. // Continue execution.
} }
} }
@ -117,10 +132,15 @@ impl Executable for DoWhileLoop {
interpreter.set_current_state(InterpreterState::Executing); interpreter.set_current_state(InterpreterState::Executing);
break; 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 => { InterpreterState::Return => {
return Ok(result); return Ok(result);
} }
_ => { InterpreterState::Executing => {
// Continue execution. // Continue execution.
} }
} }

92
boa/src/exec/iteration/tests.rs

@ -99,3 +99,95 @@ fn do_loop_early_break() {
assert_eq!(&exec(scenario), "3"); 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
boa/src/exec/mod.rs

@ -50,6 +50,7 @@ pub(crate) enum InterpreterState {
Executing, Executing,
Return, Return,
Break(Option<String>), Break(Option<String>),
Continue(Option<String>),
} }
/// A Javascript intepreter /// A Javascript intepreter
@ -380,6 +381,7 @@ impl Executable for Node {
Node::DoWhileLoop(ref do_while) => do_while.run(interpreter), Node::DoWhileLoop(ref do_while) => do_while.run(interpreter),
Node::ForLoop(ref for_loop) => for_loop.run(interpreter), Node::ForLoop(ref for_loop) => for_loop.run(interpreter),
Node::If(ref if_smt) => if_smt.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::Switch(ref switch) => switch.run(interpreter),
Node::Object(ref obj) => obj.run(interpreter), Node::Object(ref obj) => obj.run(interpreter),
Node::ArrayDecl(ref arr) => arr.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::Try(ref try_node) => try_node.run(interpreter),
Node::Break(ref break_node) => break_node.run(interpreter), Node::Break(ref break_node) => break_node.run(interpreter),
Node::ConditionalOp(_) => unimplemented!("ConditionalOp"), Node::Continue(ref continue_node) => continue_node.run(interpreter),
Node::Continue(_) => unimplemented!("Continue"),
} }
} }
} }

6
boa/src/exec/statement_list.rs

@ -25,7 +25,11 @@ impl Executable for StatementList {
// Early break. // Early break.
break; break;
} }
_ => { InterpreterState::Continue(_label) => {
// TODO, continue to a label.
break;
}
InterpreterState::Executing => {
// Continue execution // Continue execution
} }
} }

7
boa/src/exec/switch/mod.rs

@ -28,11 +28,16 @@ impl Executable for Switch {
return Ok(result); return Ok(result);
} }
InterpreterState::Break(_label) => { InterpreterState::Break(_label) => {
// TODO, break to a label.
// Break statement encountered so therefore end switch statement. // Break statement encountered so therefore end switch statement.
interpreter.set_current_state(InterpreterState::Executing); interpreter.set_current_state(InterpreterState::Executing);
break; break;
} }
_ => { InterpreterState::Continue(_label) => {
// TODO, continue to a label.
break;
}
InterpreterState::Executing => {
// Continuing execution / falling through to next case statement(s). // Continuing execution / falling through to next case statement(s).
fall_through = true; fall_through = true;
} }

6
boa/src/exec/tests.rs

@ -1233,3 +1233,9 @@ fn test_undefined_type() {
let scenario = "typeof undefined"; let scenario = "typeof undefined";
assert_eq!(&exec(scenario), "\"undefined\""); assert_eq!(&exec(scenario), "\"undefined\"");
} }
#[test]
fn test_conditional_op() {
let scenario = "1 === 2 ? 'a' : 'b'";
assert_eq!(&exec(scenario), "\"b\"");
}

Loading…
Cancel
Save