Browse Source

support early returns, fixes #101

pull/102/head
Jason Williams 5 years ago
parent
commit
910d20f6a5
  1. 4
      Cargo.toml
  2. 30
      benches/fib.rs
  3. 19
      src/lib/exec.rs
  4. 14
      tests/js/test.js

4
Cargo.toml

@ -36,6 +36,10 @@ path = "src/lib/lib.rs"
name = "string" name = "string"
harness = false harness = false
[[bench]]
name = "fib"
harness = false
[[bin]] [[bin]]
name = "boa" name = "boa"
path = "src/bin/bin.rs" path = "src/bin/bin.rs"

30
benches/fib.rs

@ -0,0 +1,30 @@
#[macro_use]
extern crate criterion;
use boa::exec;
use boa::syntax::lexer::Lexer;
use boa::syntax::parser::Parser;
use criterion::black_box;
use criterion::Criterion;
static SRC: &str = r#"
let num = 12;
function fib(n) {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
}
let res = fib(num);
res;
"#;
fn fibonacci(c: &mut Criterion) {
c.bench_function("fibonacci (Execution)", move |b| {
b.iter(|| exec(black_box(SRC)))
});
}
criterion_group!(benches, fibonacci);
criterion_main!(benches);

19
src/lib/exec.rs

@ -30,6 +30,7 @@ pub trait Executor {
pub struct Interpreter { pub struct Interpreter {
/// An object representing the global object /// An object representing the global object
environment: LexicalEnvironment, environment: LexicalEnvironment,
is_return: bool,
} }
/// Builder for the [`Interpreter`] /// Builder for the [`Interpreter`]
@ -62,7 +63,13 @@ impl Executor for Interpreter {
let mut obj = to_value(None::<()>); let mut obj = to_value(None::<()>);
for e in es.iter() { for e in es.iter() {
let val = self.run(e)?; let val = self.run(e)?;
if e == es.last().unwrap() { // early return
if self.is_return {
obj = val;
self.is_return = false;
break;
}
if e == es.last().expect("unable to get last value") {
obj = val; obj = val;
} }
} }
@ -312,10 +319,15 @@ impl Executor for Interpreter {
_ => Ok(Gc::new(ValueData::Undefined)), _ => Ok(Gc::new(ValueData::Undefined)),
} }
} }
ExprDef::Return(ref ret) => match *ret { ExprDef::Return(ref ret) => {
let result = match *ret {
Some(ref v) => self.run(v), Some(ref v) => self.run(v),
None => Ok(Gc::new(ValueData::Undefined)), None => Ok(Gc::new(ValueData::Undefined)),
}, };
// Set flag for return
self.is_return = true;
result
}
ExprDef::Throw(ref ex) => Err(self.run(ex)?), ExprDef::Throw(ref ex) => Err(self.run(ex)?),
ExprDef::Assign(ref ref_e, ref val_e) => { ExprDef::Assign(ref ref_e, ref val_e) => {
let val = self.run(val_e)?; let val = self.run(val_e)?;
@ -410,6 +422,7 @@ impl InterpreterBuilder {
pub fn build(self) -> Interpreter { pub fn build(self) -> Interpreter {
Interpreter { Interpreter {
environment: LexicalEnvironment::new(self.global.clone()), environment: LexicalEnvironment::new(self.global.clone()),
is_return: false,
} }
} }
} }

14
tests/js/test.js

@ -1,2 +1,12 @@
let a = "hello"; let num = 12;
print(a);
function fib(n) {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
}
let res = fib(num);
res;
// (2 - 1 = 1) + (2 - 2 = rt 1)

Loading…
Cancel
Save