Browse Source

fixes #10 (#112)

pull/125/head
Jason Williams 5 years ago committed by GitHub
parent
commit
27178e1645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      src/lib/exec.rs
  2. 16
      src/lib/js/boolean.rs
  3. 38
      src/lib/js/string.rs
  4. 8
      src/lib/js/value.rs
  5. 6
      tests/js/test.js

15
src/lib/exec.rs

@ -15,7 +15,10 @@ use crate::{
}, },
}; };
use gc::{Gc, GcCell}; use gc::{Gc, GcCell};
use std::{borrow::Borrow, ops::Deref}; use std::{
borrow::Borrow,
ops::{Deref, DerefMut},
};
/// An execution engine /// An execution engine
pub trait Executor { pub trait Executor {
@ -470,7 +473,17 @@ impl Default for InterpreterBuilder {
impl Interpreter { impl Interpreter {
/// https://tc39.es/ecma262/#sec-call /// https://tc39.es/ecma262/#sec-call
fn call(&mut self, f: &Value, v: &Value, arguments_list: Vec<Value>) -> ResultValue { fn call(&mut self, f: &Value, v: &Value, arguments_list: Vec<Value>) -> ResultValue {
// All functions should be objects, and eventually will be.
// During this transition call will support both native functions and function objects
match (*f).deref() { match (*f).deref() {
ValueData::Object(ref obj) => {
let func: Value = obj.borrow_mut().deref_mut().get_internal_slot("call");
if !func.is_undefined() {
return self.call(&func, v, arguments_list);
}
// TODO: error object should be here
Err(Gc::new(ValueData::Undefined))
}
ValueData::Function(ref inner_func) => match *inner_func.deref().borrow() { ValueData::Function(ref inner_func) => match *inner_func.deref().borrow() {
Function::NativeFunc(ref ntv) => { Function::NativeFunc(ref ntv) => {
let func = ntv.data; let func = ntv.data;

16
src/lib/js/boolean.rs

@ -100,6 +100,22 @@ mod tests {
assert_eq!(boolean_constructor.is_function(), true); assert_eq!(boolean_constructor.is_function(), true);
} }
#[test]
/// Test the correct type is returned from call and construct
fn construct_and_call() {
let mut engine = Executor::new();
let init = r#"
const one = new Boolean(1);
const zero = Boolean(0);
"#;
forward(&mut engine, init);
let one = forward_val(&mut engine, "one").unwrap();
let zero = forward_val(&mut engine, "zero").unwrap();
assert_eq!(one.is_object(), true);
assert_eq!(zero.is_boolean(), true);
}
#[test] #[test]
fn constructor_gives_true_instance() { fn constructor_gives_true_instance() {
let mut engine = Executor::new(); let mut engine = Executor::new();

38
src/lib/js/string.rs

@ -7,12 +7,13 @@ use crate::{
value::{from_value, to_value, ResultValue, Value, ValueData}, value::{from_value, to_value, ResultValue, Value, ValueData},
}, },
}; };
use gc::Gc;
use std::{ use std::{
cmp::{max, min}, cmp::{max, min},
f64::NAN, f64::NAN,
}; };
/// Create new string /// Create new string [[Construct]]
/// <https://searchfox.org/mozilla-central/source/js/src/vm/StringObject.h#19> /// <https://searchfox.org/mozilla-central/source/js/src/vm/StringObject.h#19>
// This gets called when a new String() is created, it's called by exec:346 // This gets called when a new String() is created, it's called by exec:346
pub fn make_string(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub fn make_string(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
@ -33,6 +34,21 @@ pub fn make_string(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultV
Ok(this.clone()) Ok(this.clone())
} }
/// Call new string [[Call]]
/// https://tc39.es/ecma262/#sec-string-constructor-string-value
pub fn call_string(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
let arg = match args.get(0) {
Some(v) => v.clone(),
None => Gc::new(ValueData::Undefined),
};
if arg.is_undefined() {
return Ok(to_value(""));
}
Ok(to_value(arg.to_string()))
}
/// Get a string's length /// Get a string's length
pub fn get_string_length(this: &Value, _: &[Value], ctx: &mut Interpreter) -> ResultValue { pub fn get_string_length(this: &Value, _: &[Value], ctx: &mut Interpreter) -> ResultValue {
let this_str = ctx.value_to_rust_string(this); let this_str = ctx.value_to_rust_string(this);
@ -654,7 +670,7 @@ pub fn create_constructor(global: &Value) -> Value {
string_constructor.set_internal_method("construct", make_string); string_constructor.set_internal_method("construct", make_string);
// Todo: add call internal method (should be easy) // Todo: add call internal method (should be easy)
// Currently call points to the constructor function, this is wrong // Currently call points to the constructor function, this is wrong
string_constructor.set_internal_method("call", make_string); string_constructor.set_internal_method("call", call_string);
// Create prototype // Create prototype
let proto = ValueData::new_obj(Some(global)); let proto = ValueData::new_obj(Some(global));
@ -697,7 +713,7 @@ pub fn init(global: &Value) {
mod tests { mod tests {
use super::*; use super::*;
use crate::exec::Executor; use crate::exec::Executor;
use crate::forward; use crate::{forward, forward_val};
#[test] #[test]
fn check_string_constructor_is_function() { fn check_string_constructor_is_function() {
@ -747,6 +763,22 @@ mod tests {
//assert_eq!(b, String::from("Hello, world! Have a nice day.")); //assert_eq!(b, String::from("Hello, world! Have a nice day."));
} }
#[test]
/// Test the correct type is returned from call and construct
fn construct_and_call() {
let mut engine = Executor::new();
let init = r#"
const hello = new String('Hello');
const world = String('world');
"#;
forward(&mut engine, init);
let hello = forward_val(&mut engine, "hello").unwrap();
let world = forward_val(&mut engine, "world").unwrap();
assert_eq!(hello.is_object(), true);
assert_eq!(world.is_string(), true);
}
#[test] #[test]
fn repeat() { fn repeat() {
let mut engine = Executor::new(); let mut engine = Executor::new();

8
src/lib/js/value.rs

@ -139,6 +139,14 @@ impl ValueData {
} }
} }
/// Returns true if the value is a boolean
pub fn is_boolean(&self) -> bool {
match *self {
ValueData::Boolean(_) => true,
_ => false,
}
}
/// Returns true if the value is true /// Returns true if the value is true
/// [toBoolean](https://tc39.github.io/ecma262/#sec-toboolean) /// [toBoolean](https://tc39.github.io/ecma262/#sec-toboolean)
pub fn is_true(&self) -> bool { pub fn is_true(&self) -> bool {

6
tests/js/test.js

@ -1,4 +1,2 @@
function jason(a, b) { let a = Boolean(0);
return arguments[0]; typeof a;
}
const val = jason(100, 6);

Loading…
Cancel
Save