diff --git a/Cargo.lock b/Cargo.lock index 9830c435e4..68093bddb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,38 @@ version = "0.1.3" dependencies = [ "gc 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gc_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "gc" version = "0.3.2" @@ -27,11 +56,46 @@ name = "itoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libc" +version = "0.2.43" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ryu" version = "0.2.6" @@ -39,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -49,7 +113,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -79,20 +143,62 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "time" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-xid" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gc 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "630b15fafc2270fc89de904da9ebb8b950642a5ed7bd99ec3f95558b0831ea9a" "checksum gc_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2501c15cbaf28a0c2214617aa85351982a933161d7937fe6cd71c855364e0ea6" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" +"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" +"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" -"checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9" +"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" "checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" +"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 536d763bae..a2d85fdccf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ exclude = [".vscode/*", "Dockerfile", "Makefile", ".editorConfig"] gc = "0.3.2" gc_derive = "*" serde_json = "1.0" +rand = "0.5.5" +time = "0.1" [lib] name = "boa" diff --git a/src/lib/js/array.rs b/src/lib/js/array.rs new file mode 100644 index 0000000000..02882b1ff2 --- /dev/null +++ b/src/lib/js/array.rs @@ -0,0 +1,17 @@ +use js::function::Function; +use js::value::{to_value, ResultValue, Value}; + +/// Create a new array +pub fn make_array(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { + this.set_field_slice("length", to_value(0i32)); + Ok(Value::undefined()) +} +/// Create a new `Array` object +pub fn _create() -> Value { + let array = Function::make(make_array, &[]); + array +} +/// Initialise the global object with the `Array` object +pub fn init(global: Value) { + global.set_field_slice("Array", _create()); +} diff --git a/src/lib/js/boolean.rs b/src/lib/js/boolean.rs new file mode 100644 index 0000000000..dc0ff01c51 --- /dev/null +++ b/src/lib/js/boolean.rs @@ -0,0 +1,17 @@ +use gc::Gc; +use js::value::{to_value, ResultValue, Value, ValueData}; + +/// Create a new boolean +pub fn make_boolean(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { + Ok(Gc::new(ValueData::Undefined)) +} +/// Create a new `Boolean` object +pub fn _create(global: Value) -> Value { + let boolean = to_value(make_boolean); + boolean +} +/// Initialise the global object with the `Error` object +pub fn init(global: Value) { + let global_ptr = global.borrow(); + global_ptr.set_field_slice("Boolean", _create(global)); +} diff --git a/src/lib/js/console.rs b/src/lib/js/console.rs new file mode 100644 index 0000000000..fe9361425b --- /dev/null +++ b/src/lib/js/console.rs @@ -0,0 +1,34 @@ +use js::function::Function; +use js::value::{from_value, ResultValue, Value}; +use std::iter::FromIterator; +use time::{now, strftime}; +/// Print a javascript value to the standard output stream +pub fn log(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + let args: Vec = FromIterator::from_iter( + args.iter() + .map(|x| from_value::(x.clone()).unwrap()), + ); + println!("{}: {}", strftime("%X", &now()).unwrap(), args.join(" ")); + Ok(Value::undefined()) +} +/// Print a javascript value to the standard error stream +pub fn error(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + let args: Vec = FromIterator::from_iter( + args.iter() + .map(|x| from_value::(x.clone()).unwrap()), + ); + eprintln!("{}: {}", strftime("%X", &now()).unwrap(), args.join(" ")); + Ok(Value::undefined()) +} +/// Create a new `console` object +pub fn _create(global: Value) -> Value { + let console = Value::new_obj(Some(global)); + console.set_field_slice("log", Function::make(log, &["object"])); + console.set_field_slice("error", Function::make(error, &["error"])); + console.set_field_slice("exception", Function::make(error, &["error"])); + console +} +/// Initialise the global object with the `console` object +pub fn init(global: Value) { + global.set_field_slice("console", _create(global.clone())); +} diff --git a/src/lib/js/error.rs b/src/lib/js/error.rs new file mode 100644 index 0000000000..13836ce39b --- /dev/null +++ b/src/lib/js/error.rs @@ -0,0 +1,31 @@ +use js::function::Function; +use js::object::PROTOTYPE; +use js::value::{to_value, ResultValue, Value}; + +/// Create a new error +pub fn make_error(args: Vec, _: Value, _: Value, this: Value) -> ResultValue { + if args.len() >= 1 { + this.set_field_slice("message", to_value(args.get(0).unwrap().to_string())); + } + Ok(Value::undefined()) +} +/// Get the string representation of the error +pub fn to_string(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { + let name = this.get_field_slice("name"); + let message = this.get_field_slice("message"); + Ok(to_value(format!("{}: {}", name, message).to_string())) +} +/// Create a new `Error` object +pub fn _create(global: Value) -> Value { + let prototype = Value::new_obj(Some(global)); + prototype.set_field_slice("message", to_value("")); + prototype.set_field_slice("name", to_value("Error")); + prototype.set_field_slice("toString", Function::make(to_string, &[])); + let error = Function::make(make_error, &["message"]); + error.set_field_slice(PROTOTYPE, prototype); + error +} +/// Initialise the global object with the `Error` object +pub fn init(global: Value) { + global.set_field_slice("Error", _create(global.clone())); +} diff --git a/src/lib/js/function.rs b/src/lib/js/function.rs index 20af23e40e..52662cb55b 100644 --- a/src/lib/js/function.rs +++ b/src/lib/js/function.rs @@ -1,5 +1,8 @@ -use js::object::ObjectData; -use js::value::{ResultValue, Value}; +use gc::{Gc, GcCell}; +use js::object::{ObjectData, Property}; +use js::value::{to_value, ResultValue, Value, ValueData}; +use std::collections::HashMap; +use std::iter::FromIterator; pub type FunctionData = fn(Vec, Value, Value, Value) -> ResultValue; /// A Javascript function @@ -16,3 +19,42 @@ pub struct Function { /// The argument names of the function pub args: Vec, } + +impl Function { + /// Make a new function + pub fn new(repr: FunctionData, args: Vec) -> Function { + let mut obj = HashMap::new(); + obj.insert( + "arguments".to_string(), + Property::from_value(to_value(args.len() as i32)), + ); + Function { + object: obj, + repr: repr, + args: args, + } + } + /// Create a function from function data and arguments + pub fn make(repr: FunctionData, args: &[&'static str]) -> Value { + Value { + ptr: Gc::new(ValueData::Function(GcCell::new(Function::new( + repr, + FromIterator::from_iter(args.iter().map(|arg| arg.to_string())), + )))), + } + } + /// Call with some args + pub fn call(&self, args: Vec, global: Value, scope: Value, this: Value) -> ResultValue { + (self.repr)(args, global, scope, this) + } +} + +/// Create a new `Function` object +pub fn _create() -> Value { + let function: ObjectData = HashMap::new(); + to_value(function) +} +/// Initialise the global object with the `Function` object +pub fn init(global: Value) { + global.set_field_slice("Function", _create()); +} diff --git a/src/lib/js/json.rs b/src/lib/js/json.rs index 6968ee93a1..98cfc679cf 100644 --- a/src/lib/js/json.rs +++ b/src/lib/js/json.rs @@ -2,20 +2,21 @@ /// https://tc39.github.io/ecma262/#sec-json-object use gc::GcCell; use js::value::{to_value, ResultValue, Value, ValueData}; +use serde_json; /// Parse a JSON string into a Javascript object /// https://tc39.github.io/ecma262/#sec-json.parse pub fn parse(args: Vec) -> ResultValue { - match serde_json::from_str(args.get(0).borrow().to_str().as_slice()) { - Ok(json) => Ok(GcCell::new(ValueData::from_json(json))), - Err(err) => Err(GcCell::new(Value::String(err.to_str()))), + match serde_json::from_str(&args.get(0).unwrap().clone().to_string()) { + Ok(json) => Ok(to_value(json)), + Err(err) => Err(to_value(err.to_string())), } } /// Process a Javascript object into a JSON string pub fn stringify(args: Vec) -> ResultValue { let obj = args.get(0); - let json = serde_json::to_string_pretty(obj.borrow()).unwrap(); - Ok(GcCell::new(Value::String(json.to_pretty_str()))) + let json = serde_json::to_string_pretty(obj.clone()).unwrap(); + Ok(to_value(json.to_pretty_str())) } /// Create a new `JSON` object diff --git a/src/lib/js/math.rs b/src/lib/js/math.rs new file mode 100644 index 0000000000..ea5d2fc6bf --- /dev/null +++ b/src/lib/js/math.rs @@ -0,0 +1,195 @@ +use js::function::Function; +use js::value::{from_value, to_value, ResultValue, Value}; +use rand::random; +use std::f64; + +/// Get the absolute value of a number +pub fn abs(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().abs() + } else { + f64::NAN + })) +} +/// Get the arccos of a number +pub fn acos(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().acos() + } else { + f64::NAN + })) +} +/// Get the arcsine of a number +pub fn asin(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().asin() + } else { + f64::NAN + })) +} +/// Get the arctangent of a number +pub fn atan(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().atan() + } else { + f64::NAN + })) +} +/// Get the arctangent of a numbers +pub fn atan2(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)) + .unwrap() + .atan2(args.get(1).to_num()) + } else { + f64::NAN + })) +} +/// Get the cubic root of a number +pub fn cbrt(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().cbrt() + } else { + f64::NAN + })) +} +/// Get lowest integer above a number +pub fn ceil(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().ceil() + } else { + f64::NAN + })) +} +/// Get the cosine of a number +pub fn cos(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().cos() + } else { + f64::NAN + })) +} +/// Get the power to raise the natural logarithm to get the number +pub fn exp(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().exp() + } else { + f64::NAN + })) +} +/// Get the highest integer below a number +pub fn floor(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().floor() + } else { + f64::NAN + })) +} +/// Get the natural logarithm of a number +pub fn log(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().log(f64::consts::E) + } else { + f64::NAN + })) +} +/// Get the maximum of several numbers +pub fn max(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + let mut max = f64::NEG_INFINITY; + for arg in args.iter() { + let num = arg.to_num(); + max = max.max(num); + } + Ok(to_value(max)) +} +/// Get the minimum of several numbers +pub fn min(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + let mut max = f64::INFINITY; + for arg in args.iter() { + let num = arg.to_num(); + max = max.min(num); + } + Ok(to_value(max)) +} +/// Raise a number to a power +pub fn pow(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 2 { + let num: f64 = from_value(*args.get(0)).unwrap(); + let power: f64 = from_value(*args.get(1)).unwrap(); + num.powf(power) + } else { + f64::NAN + })) +} +/// Generate a random floating-point number between 0 and 1 +pub fn _random(_: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(random::())) +} +/// Round a number to the nearest integer +pub fn round(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().round() + } else { + f64::NAN + })) +} +/// Get the sine of a number +pub fn sin(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().sin() + } else { + f64::NAN + })) +} +/// Get the square root of a number +pub fn sqrt(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().sqrt() + } else { + f64::NAN + })) +} +/// Get the tangent of a number +pub fn tan(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { + Ok(to_value(if args.len() >= 1 { + from_value::(*args.get(0)).unwrap().tan() + } else { + f64::NAN + })) +} +/// Create a new `Math` object +pub fn _create(global: Value) -> Value { + let math = Value::new_obj(Some(global)); + math.set_field_slice("E", to_value(f64::consts::E)); + math.set_field_slice("LN2", to_value(f64::consts::LN_2)); + math.set_field_slice("LN10", to_value(f64::consts::LN_10)); + math.set_field_slice("LOG2E", to_value(f64::consts::LOG2_E)); + math.set_field_slice("LOG10E", to_value(f64::consts::LOG10_E)); + math.set_field_slice("SQRT1_2", to_value(0.5f64.sqrt())); + math.set_field_slice("SQRT2", to_value(f64::consts::SQRT2)); + math.set_field_slice("PI", to_value(f64::consts::PI)); + math.set_field_slice("abs", Function::make(abs, ["num1", "num2"])); + math.set_field_slice("acos", Function::make(acos, ["num1", "num2"])); + math.set_field_slice("asin", Function::make(asin, ["num1", "num2"])); + math.set_field_slice("atan", Function::make(atan, ["num1", "num2"])); + math.set_field_slice("atan2", Function::make(atan2, ["num1", "num2"])); + math.set_field_slice("cbrt", Function::make(cbrt, ["num1", "num2"])); + math.set_field_slice("ceil", Function::make(ceil, ["num1", "num2"])); + math.set_field_slice("cos", Function::make(cos, ["num1", "num2"])); + math.set_field_slice("exp", Function::make(exp, ["num1", "num2"])); + math.set_field_slice("floor", Function::make(floor, ["num"])); + math.set_field_slice("log", Function::make(log, ["num1", "num2"])); + math.set_field_slice("max", Function::make(max, ["num1", "num2"])); + math.set_field_slice("min", Function::make(min, ["num1", "num2"])); + math.set_field_slice("pow", Function::make(pow, ["num1", "num2"])); + math.set_field_slice("random", Function::make(_random, [])); + math.set_field_slice("round", Function::make(round, ["num"])); + math.set_field_slice("sin", Function::make(sin, ["num"])); + math.set_field_slice("sqrt", Function::make(sqrt, ["num"])); + math.set_field_slice("tan", Function::make(tan, ["num"])); + math +} +/// Initialise the `Math` object on the global object +pub fn init(global: Value) { + global.set_field_slice("Math", _create(global)); +} diff --git a/src/lib/js/mod.rs b/src/lib/js/mod.rs index c8b51b4183..4dd2a8347d 100644 --- a/src/lib/js/mod.rs +++ b/src/lib/js/mod.rs @@ -1,7 +1,13 @@ +/// The global `Array` object +pub mod array; +/// The global `console` object +pub mod console; +/// The global `Error` object +pub mod error; /// The global `Function` object and function value representations pub mod function; -// /// The global `JSON` object -// pub mod json; +/// The global `JSON` object +pub mod json; /// The global `Object` object pub mod object; /// Javascript values, utility methods and conversion between Javascript values and Rust values diff --git a/src/lib/js/string.rs b/src/lib/js/string.rs new file mode 100644 index 0000000000..f52b77d050 --- /dev/null +++ b/src/lib/js/string.rs @@ -0,0 +1,34 @@ +use js::function::Function; +use js::object::{Property, PROTOTYPE}; +use js::value::{from_value, to_value, ResultValue, Value}; + +/// Create new string +pub fn make_string(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { + this.set_field_slice("length", to_value(0i32)); + Ok(Value::undefined()) +} +/// Get a string's length +pub fn get_string_length(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { + let this_str: String = from_value(this).unwrap(); + Ok(to_value::(this_str.len() as i32)) +} +/// Create a new `String` object +pub fn _create(global: Value) -> Value { + let string = Function::make(make_string, ["string"]); + let proto = Value::new_obj(Some(global)); + let prop = Property { + configurable: false, + enumerable: false, + writable: false, + value: Value::undefined(), + get: Function::make(get_string_length, []), + set: Value::undefined(), + }; + proto.set_prop_slice("length", prop); + string.set_field_slice(PROTOTYPE, proto); + string +} +/// Initialise the `String` object on the global object +pub fn init(global: Value) { + global.set_field_slice("String", _create(global)); +} diff --git a/src/lib/lib.rs b/src/lib/lib.rs index ed12daa6f2..e00417dc90 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,5 +1,8 @@ extern crate gc; +extern crate rand; extern crate serde_json; +extern crate time; + #[macro_use] extern crate gc_derive; diff --git a/tests/value_test.rs b/tests/value_test.rs index b6b5f6de65..971166daa8 100644 --- a/tests/value_test.rs +++ b/tests/value_test.rs @@ -15,6 +15,13 @@ fn check_string_to_value() { assert_eq!(v.is_null(), false); } +#[test] +fn check_undefined() { + let u = Value::undefined(); + assert_eq!(u.get_type(), "undefined"); + assert_eq!(u.to_string(), "undefined"); +} + #[test] fn check_get_set_field() { let obj = Value::new_obj(None);