Browse Source

added values and json

pull/5/head
Jason Williams 6 years ago
parent
commit
6371600e39
  1. 30
      Cargo.lock
  2. 1
      Cargo.toml
  3. 36
      src/lib/exec.rs
  4. 110
      src/lib/js/function.rs
  5. 34
      src/lib/js/json.rs
  6. 6
      src/lib/js/mod.rs
  7. 39
      src/lib/js/object.rs
  8. 279
      src/lib/js/value.rs

30
Cargo.lock generated

@ -4,6 +4,7 @@ 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)",
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -21,11 +22,36 @@ dependencies = [
"synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.3"
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 = "ryu"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_json"
version = "1.0.32"
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)",
]
[[package]]
name = "syn"
version = "0.11.11"
@ -61,7 +87,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"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 quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"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_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"

1
Cargo.toml

@ -12,6 +12,7 @@ exclude = [".vscode/*", "Dockerfile", "Makefile", ".editorConfig"]
[dependencies]
gc = "0.3.2"
gc_derive = "*"
serde_json = "1.0"
[lib]
name = "boa"

36
src/lib/exec.rs

@ -1,17 +1,43 @@
use js::object::{INSTANCE_PROTOTYPE, PROTOTYPE, ObjectData};
use gc::GcCell;
use js::object::ObjectData;
use js::value::{ResultValue, Value, ValueData};
use js::{function, json, object};
use std::cell::RefCell;
use syntax::ast::expr::Expr;
/// An execution engine
pub trait Executor {
/// Make a new execution engine
fn new() -> Self;
/// Set a global variable called `name` with the value `val`
// fn set_global(&mut self, name: String, val: Value) -> Value;
fn set_global(&mut self, name: String, val: Value) -> Value;
/// Resolve the global variable `name`
// fn get_global(&self, name: String) -> Value;
fn get_global(&self, name: String) -> Value;
/// Create a new scope and return it
// fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
fn make_scope(&mut self) -> GcCell<RefCell<ObjectData>>;
/// Destroy the current scope
fn destroy_scope(&mut self) -> ();
/// Run an expression
// fn run(&mut self, expr: &Expr) -> ResultValue;
fn run(&mut self, expr: &Expr) -> ResultValue;
}
/// A Javascript intepreter
pub struct Interpreter {
/// An object representing the global object
global: Value,
/// The variable scopes
scopes: Vec<GcCell<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
fn new() -> Interpreter {
let global = ValueData::new_obj(None);
object::init(global);
function::init(global);
json::init(global);
Interpreter {
global: global,
scopes: Vec::new(),
}
}
}

110
src/lib/js/function.rs

@ -0,0 +1,110 @@
use exec::Interpreter;
use gc::GcCell;
use js::object::{ObjectData, Property};
use js::value::{to_value, ResultValue, Value, ValueData};
use std::collections::HashMap;
use syntax::ast::expr::Expr;
/// A Javascript function
/// A member of the Object type that may be invoked as a subroutine
/// https://tc39.github.io/ecma262/#sec-terms-and-definitions-function
pub enum Function {
/// A native javascript function
NativeFunc(NativeFunction),
/// A regular javascript function
RegularFunc(RegularFunction),
}
impl Function {
/// Call a function with some arguments
pub fn call(
&self,
exe: &mut Interpreter,
this: Value,
callee: Value,
args: Vec<Value>,
) -> ResultValue {
match *self {
Function::NativeFunc(ref ntv) => {
let func = ntv.data;
func(this, callee, args)
}
Function::RegularFunc(ref data) => {
let scope = exe.make_scope();
scope
.borrow()
.borrow_mut()
.insert("this".to_string(), Property::new(this));
for i in 0..data.args.len() {
let name = data.args.get(i);
let expr = args.get(i);
scope
.borrow()
.borrow_mut()
.insert(name.to_string(), Property::new(*expr));
}
let result = exe.run(&data.expr);
exe.destroy_scope();
result
}
}
}
}
/// Represents a regular javascript function in memory
/// A member of the Object type that may be invoked as a subroutine
pub struct RegularFunction {
/// The fields associated with the function
pub object: ObjectData,
/// This function's expression
pub expr: Expr,
/// The argument names of the function
pub args: Vec<String>,
}
impl RegularFunction {
/// Make a new regular function
pub fn new(expr: Expr, args: Vec<String>) -> RegularFunction {
let mut obj = HashMap::new();
obj.insert(
"arguments".to_string(),
Property::new(GcCell::new(ValueData::Integer(args.len() as i32))),
);
RegularFunction {
object: obj,
expr: expr,
args: args,
}
}
}
pub type NativeFunctionData = fn(Value, Value, Vec<Value>) -> ResultValue;
/// Represents a native javascript function in memory
pub struct NativeFunction {
/// The fields associated with the function
pub object: ObjectData,
/// The callable function data
pub data: NativeFunctionData,
}
impl NativeFunction {
/// Make a new native function with the given function data
pub fn new(data: NativeFunctionData) -> NativeFunction {
let obj = HashMap::new();
NativeFunction {
object: obj,
data: data,
}
}
}
/// 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) {
let global_ptr = global.borrow();
global_ptr.set_field_slice("Function", _create(global));
}

34
src/lib/js/json.rs

@ -0,0 +1,34 @@
/// The JSON Object
/// https://tc39.github.io/ecma262/#sec-json-object
use gc::GcCell;
use js::value::{to_value, ResultValue, Value, ValueData};
/// Parse a JSON string into a Javascript object
/// https://tc39.github.io/ecma262/#sec-json.parse
pub fn parse(args: Vec<Value>) -> 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()))),
}
}
/// Process a Javascript object into a JSON string
pub fn stringify(args: Vec<Value>) -> 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())))
}
/// Create a new `JSON` object
pub fn _create(global: Value) -> Value {
let object = ValueData::new_obj(Some(global));
let object_ptr = object.borrow();
object_ptr.set_field_slice("stringify", to_value(stringify));
object_ptr.set_field_slice("parse", to_value(parse));
object
}
/// Initialise the global object with the `JSON` object
pub fn init(global: Value) {
let global_ptr = global.borrow();
global_ptr.set_field_slice("JSON", _create(global));
}

6
src/lib/js/mod.rs

@ -1,5 +1,9 @@
extern crate gc;
extern crate serde_json;
/// The global `Function` object and function value representations
pub mod function;
/// 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

39
src/lib/js/object.rs

@ -1,5 +1,5 @@
use gc::Gc;
use js::value::Value;
use gc::GcCell;
use js::value::{to_value, ResultValue, Value, ValueData};
use std::collections::HashMap;
pub static PROTOTYPE: &'static str = "prototype";
pub static INSTANCE_PROTOTYPE: &'static str = "__proto__";
@ -7,6 +7,10 @@ pub static INSTANCE_PROTOTYPE: &'static str = "__proto__";
pub type ObjectData = HashMap<String, Property>;
/// A Javascript Property
/// [Attributes of a Data Property](https://tc39.github.io/ecma262/#sec-property-attributes)
/// [Attributes of an Accessor Property](https://tc39.github.io/ecma262/#table-3)
/// A data property associates a key value with an ECMAScript language value and a set of Boolean attributes.
/// An accessor property associates a key value with one or two accessor functions, and a set of Boolean attributes.
pub struct Property {
/// If the type of this can be changed and this can be deleted
pub configurable: bool,
@ -24,14 +28,41 @@ pub struct Property {
impl Property {
/// Make a new property with the given value
/// [Default Attributes](https://tc39.github.io/ecma262/#table-4)
pub fn new(value: Value) -> Property {
Property {
configurable: false,
enumerable: false,
writable: false,
value: value,
// get: Gc::new(VUndefined),
// set: Gc::new(VUndefined),
get: GcCell::new(Value::Undefined),
set: GcCell::new(Value::Undefined),
}
}
}
/// Create a new object
pub fn make_object() -> ResultValue {
Ok(GcCell::new(ValueData::Undefined))
}
/// Create a new `Object` object
pub fn _create(global: Value) -> Value {
let object = to_value(make_object);
let object_ptr = object.borrow();
let prototype = ValueData::new_obj(Some(global));
// prototype.borrow().set_field_slice("hasOwnProperty", to_value(has_own_prop));
// prototype.borrow().set_field_slice("toString", to_value(to_string));
object_ptr.set_field_slice("length", to_value(1i32));
// object_ptr.set_field_slice(PROTOTYPE, prototype);
// object_ptr.set_field_slice("setPrototypeOf", to_value(set_proto_of));
// object_ptr.set_field_slice("getPrototypeOf", to_value(get_proto_of));
// object_ptr.set_field_slice("defineProperty", to_value(define_prop));
object
}
/// Initialise the `Object` object on the global object
pub fn init(global: Value) {
let global_ptr = global.borrow();
global_ptr.set_field_slice("Object", _create(global));
}

279
src/lib/js/value.rs

@ -1,13 +1,16 @@
use gc::Gc;
use gc::GcCell;
use js::function::Function;
use js::object::{ObjectData, Property, INSTANCE_PROTOTYPE, PROTOTYPE};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::iter::FromIterator;
use std::str::FromStr;
/// The result of a Javascript expression is represented like this so it can succeed (`Ok`) or fail (`Err`)
pub type ResultValue = Result<Value, Value>;
/// A Garbage-collected Javascript value as represented in the interpreter
pub type Value = Gc<ValueData>;
pub type Value = GcCell<ValueData>;
/// A Javascript value
pub enum ValueData {
@ -42,7 +45,7 @@ impl ValueData {
.get_field_slice(PROTOTYPE);
obj.insert(INSTANCE_PROTOTYPE.into_String(), Property::new(obj_proto));
}
Gc::new(ValueData::Object(RefCell::new(obj)))
GcCell::new(ValueData::Object(RefCell::new(obj)))
}
/// Returns true if the value is an object
pub fn is_object(&self) -> bool {
@ -128,8 +131,8 @@ impl ValueData {
ValueData::Function(ref func) => {
let func = func.borrow().clone();
match func {
NativeFunc(f) => f.object.clone(),
RegularFunc(f) => f.object.clone(),
Function::NativeFunc(f) => f.object.clone(),
Function::RegularFunc(f) => f.object.clone(),
}
}
_ => return None,
@ -146,7 +149,7 @@ impl ValueData {
pub fn get_field(&self, field: String) -> Value {
match self.get_prop(field) {
Some(prop) => prop.value,
None => Gc::new(ValueData::Undefined),
None => GcCell::new(ValueData::Undefined),
}
}
/// Resolve the property in the object and get its value, or undefined if this is not an object or the field doesn't exist
@ -161,8 +164,12 @@ impl ValueData {
}
ValueData::Function(ref func) => {
match *func.borrow_mut().deref_mut() {
NativeFunc(ref mut f) => f.object.insert(field.clone(), Property::new(val)),
RegularFunc(ref mut f) => f.object.insert(field.clone(), Property::new(val)),
Function::NativeFunc(ref mut f) => {
f.object.insert(field.clone(), Property::new(val))
}
Function::RegularFunc(ref mut f) => {
f.object.insert(field.clone(), Property::new(val))
}
};
}
_ => (),
@ -181,8 +188,8 @@ impl ValueData {
}
ValueData::Function(ref func) => {
match *func.borrow_mut().deref_mut() {
NativeFunc(ref mut f) => f.object.insert(field.clone(), prop),
RegularFunc(ref mut f) => f.object.insert(field.clone(), prop),
Function::NativeFunc(ref mut f) => f.object.insert(field.clone(), prop),
Function::RegularFunc(ref mut f) => f.object.insert(field.clone(), prop),
};
}
_ => (),
@ -194,12 +201,12 @@ impl ValueData {
self.set_prop(field.into_String(), prop)
}
/// Convert from a JSON value to a JS value
pub fn from_json(json: Json) -> ValueData {
pub fn from_json(json: serde_json::Value) -> ValueData {
match json {
Number(v) => ValueData::Number(v),
String(v) => ValueData::String(v),
Boolean(v) => ValueData::Boolean(v),
List(vs) => {
serde_json::Value::Number(v) => ValueData::Number(v),
serde_json::Value::String(v) => ValueData::String(v),
serde_json::Value::Boolean(v) => ValueData::Boolean(v),
serde_json::Value::List(vs) => {
let mut i = 0;
let mut data: ObjectData = FromIterator::from_iter(vs.iter().map(|json| {
i += 1;
@ -214,7 +221,7 @@ impl ValueData {
);
ValueData::Object(RefCell::new(data))
}
Object(obj) => {
serde_json::Value::Object(obj) => {
let data: ObjectData = FromIterator::from_iter(
obj.iter()
.map(|(key, json)| (key.clone(), Property::new(to_value(json.clone())))),
@ -224,8 +231,29 @@ impl ValueData {
Null => ValueData::Null,
}
}
pub fn to_json(&self) -> serde_json::Value {
match *self {
ValueData::Null | ValueData::Undefined => serde_json::Value::Null,
ValueData::Boolean(b) => serde_json::Value::Boolean(b),
ValueData::Object(ref obj) => {
let mut nobj = HashMap::new();
for (k, v) in obj.borrow().iter() {
if k.as_slice() != INSTANCE_PROTOTYPE.as_slice() {
nobj.insert(k.clone(), v.value.borrow().to_json());
}
}
serde_json::Value::Object(Box::new(nobj))
}
ValueData::String(ref str) => serde_json::Value::String(str.clone()),
ValueData::Number(num) => serde_json::Value::Number(num),
ValueData::Integer(val) => serde_json::Value::Number(val as f64),
ValueData::Function(_) => serde_json::Value::Null,
}
}
}
impl fmt::Show for ValueData {
impl fmt::Display for ValueData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ValueData::Null => write!(f, "null"),
@ -259,8 +287,10 @@ impl fmt::Show for ValueData {
}
ValueData::Integer(v) => write!(f, "{}", v),
ValueData::Function(ref v) => match v.borrow().clone() {
NativeFunc(_) => write!(f, "{}", "function() { [native code] }"),
RegularFunc(rf) => write!(f, "function({}){}", rf.args.connect(", "), rf.expr),
Function::NativeFunc(_) => write!(f, "{}", "function() { [native code] }"),
Function::RegularFunc(rf) => {
write!(f, "function({}){}", rf.args.connect(", "), rf.expr)
}
},
}
}
@ -289,148 +319,128 @@ impl PartialEq for ValueData {
}
}
}
impl ToJson for ValueData {
fn to_json(&self) -> Json {
match *self {
ValueData::Null | ValueData::Undefined => Null,
ValueData::Boolean(b) => Boolean(b),
ValueData::Object(ref obj) => {
let mut nobj = HashMap::new();
for (k, v) in obj.borrow().iter() {
if k.as_slice() != INSTANCE_PROTOTYPE.as_slice() {
nobj.insert(k.clone(), v.value.borrow().to_json());
}
}
Object(box nobj)
}
ValueData::String(ref str) => String(str.clone()),
ValueData::Number(num) => Number(num),
ValueData::Integer(val) => Number(val as f64),
ValueData::Function(_) => Null,
}
}
}
impl Add<ValueData, ValueData> for ValueData {
fn add(&self, other: &ValueData) -> ValueData {
return match (self.clone(), other.clone()) {
(ValueData::String(s), other) | (other, ValueData::String(s)) => {
ValueData::String(s.clone().append(other.to_str().as_slice()))
}
(_, _) => ValueData::Number(self.to_num() + other.to_num()),
};
}
}
impl Sub<ValueData, ValueData> for ValueData {
fn sub(&self, other: &ValueData) -> ValueData {
ValueData::Number(self.to_num() - other.to_num())
}
}
impl Mul<ValueData, ValueData> for ValueData {
fn mul(&self, other: &ValueData) -> ValueData {
ValueData::Number(self.to_num() * other.to_num())
}
}
impl Div<ValueData, ValueData> for ValueData {
fn div(&self, other: &ValueData) -> ValueData {
ValueData::Number(self.to_num() / other.to_num())
}
}
impl Rem<ValueData, ValueData> for ValueData {
fn rem(&self, other: &ValueData) -> ValueData {
ValueData::Number(self.to_num() % other.to_num())
}
}
impl BitAnd<ValueData, ValueData> for ValueData {
fn bitand(&self, other: &ValueData) -> ValueData {
ValueData::Integer(self.to_int() & other.to_int())
}
}
impl BitOr<ValueData, ValueData> for ValueData {
fn bitor(&self, other: &ValueData) -> ValueData {
ValueData::Integer(self.to_int() | other.to_int())
}
}
impl BitXor<ValueData, ValueData> for ValueData {
fn bitxor(&self, other: &ValueData) -> ValueData {
ValueData::Integer(self.to_int() ^ other.to_int())
}
}
impl Shl<ValueData, ValueData> for ValueData {
fn shl(&self, other: &ValueData) -> ValueData {
ValueData::Integer(self.to_int() << other.to_int())
}
}
impl Shr<ValueData, ValueData> for ValueData {
fn shr(&self, other: &ValueData) -> ValueData {
ValueData::Integer(self.to_int() >> other.to_int())
}
}
impl Not<ValueData> for ValueData {
fn not(&self) -> ValueData {
ValueData::Boolean(!self.is_true())
}
}
// impl Add<ValueData, ValueData> for ValueData {
// fn add(&self, other: &ValueData) -> ValueData {
// return match (self.clone(), other.clone()) {
// (ValueData::String(s), other) | (other, ValueData::String(s)) => {
// ValueData::String(s.clone().append(other.to_str().as_slice()))
// }
// (_, _) => ValueData::Number(self.to_num() + other.to_num()),
// };
// }
// }
// impl Sub<ValueData, ValueData> for ValueData {
// fn sub(&self, other: &ValueData) -> ValueData {
// ValueData::Number(self.to_num() - other.to_num())
// }
// }
// impl Mul<ValueData, ValueData> for ValueData {
// fn mul(&self, other: &ValueData) -> ValueData {
// ValueData::Number(self.to_num() * other.to_num())
// }
// }
// impl Div<ValueData, ValueData> for ValueData {
// fn div(&self, other: &ValueData) -> ValueData {
// ValueData::Number(self.to_num() / other.to_num())
// }
// }
// impl Rem<ValueData, ValueData> for ValueData {
// fn rem(&self, other: &ValueData) -> ValueData {
// ValueData::Number(self.to_num() % other.to_num())
// }
// }
// impl BitAnd<ValueData, ValueData> for ValueData {
// fn bitand(&self, other: &ValueData) -> ValueData {
// ValueData::Integer(self.to_int() & other.to_int())
// }
// }
// impl BitOr<ValueData, ValueData> for ValueData {
// fn bitor(&self, other: &ValueData) -> ValueData {
// ValueData::Integer(self.to_int() | other.to_int())
// }
// }
// impl BitXor<ValueData, ValueData> for ValueData {
// fn bitxor(&self, other: &ValueData) -> ValueData {
// ValueData::Integer(self.to_int() ^ other.to_int())
// }
// }
// impl Shl<ValueData, ValueData> for ValueData {
// fn shl(&self, other: &ValueData) -> ValueData {
// ValueData::Integer(self.to_int() << other.to_int())
// }
// }
// impl Shr<ValueData, ValueData> for ValueData {
// fn shr(&self, other: &ValueData) -> ValueData {
// ValueData::Integer(self.to_int() >> other.to_int())
// }
// }
// impl Not<ValueData> for ValueData {
// fn not(&self) -> ValueData {
// ValueData::Boolean(!self.is_true())
// }
// }
/// Conversion to Javascript values from Rust values
pub trait ToValue {
/// Convert this value to a Rust value
fn to_value(&self) -> Value;
}
/// Conversion to Rust values from Javascript values
pub trait FromValue {
pub trait FromValue<T: std::marker::Sized> {
/// Convert this value to a Javascript value
fn from_value(value: Value) -> Result<Self, &'static str>;
fn from_value(value: Value) -> Result<T, &'static str>;
}
impl ToValue for String {
fn to_value(&self) -> Value {
Gc::new(ValueData::String(self.clone()))
GcCell::new(ValueData::String(self.clone()))
}
}
impl FromValue for String {
impl<T> FromValue<T> for String {
fn from_value(v: Value) -> Result<String, &'static str> {
Ok(v.borrow().to_str())
}
}
impl<'s> ToValue for &'s str {
fn to_value(&self) -> Value {
Gc::new(ValueData::String(String::from_str(*self)))
GcCell::new(ValueData::String(String::from_str(*self)))
}
}
impl ToValue for char {
fn to_value(&self) -> Value {
Gc::new(ValueData::String(String::from_char(1, *self)))
GcCell::new(ValueData::String(String::from_char(1, *self)))
}
}
impl FromValue for char {
impl<T> FromValue<T> for char {
fn from_value(v: Value) -> Result<char, &'static str> {
Ok(v.borrow().to_str().as_slice().char_at(0))
}
}
impl ToValue for f64 {
fn to_value(&self) -> Value {
Gc::new(ValueData::Number(self.clone()))
GcCell::new(ValueData::Number(self.clone()))
}
}
impl FromValue for f64 {
impl<T> FromValue<T> for f64 {
fn from_value(v: Value) -> Result<f64, &'static str> {
Ok(v.borrow().to_num())
}
}
impl ToValue for i32 {
fn to_value(&self) -> Value {
Gc::new(ValueData::Integer(self.clone()))
GcCell::new(ValueData::Integer(self.clone()))
}
}
impl FromValue for i32 {
impl<T> FromValue<T> for i32 {
fn from_value(v: Value) -> Result<i32, &'static str> {
Ok(v.borrow().to_int())
}
}
impl ToValue for bool {
fn to_value(&self) -> Value {
Gc::new(ValueData::Boolean(self.clone()))
GcCell::new(ValueData::Boolean(self.clone()))
}
}
impl FromValue for bool {
impl<T> FromValue<T> for bool {
fn from_value(v: Value) -> Result<bool, &'static str> {
Ok(v.borrow().is_true())
}
@ -457,28 +467,28 @@ impl<T: ToValue> ToValue for Vec<T> {
to_value(arr)
}
}
impl<T: FromValue> FromValue for Vec<T> {
impl<T: FromValue<T>, R> FromValue<R> for Vec<T> {
fn from_value(v: Value) -> Result<Vec<T>, &'static str> {
let len = v.borrow().get_field_slice("length").borrow().to_int();
let mut vec = Vec::with_capacity(len as uint);
for i in range(0, len) {
let mut vec = Vec::with_capacity(len);
for i in 0..len {
vec.push(try!(from_value(v.borrow().get_field(i.to_str()))))
}
Ok(vec)
}
}
impl ToValue for NativeFunctionData {
impl ToValue for Function {
fn to_value(&self) -> Value {
Gc::new(ValueData::Function(RefCell::new(NativeFunc(
NativeFunction::new(*self),
GcCell::new(ValueData::Function(RefCell::new(Function::NativeFunc(
Function::NativeFunction::new(*self),
))))
}
}
impl FromValue for NativeFunctionData {
fn from_value(v: Value) -> Result<NativeFunctionData, &'static str> {
impl<T> FromValue<T> for Function {
fn from_value(v: Value) -> Result<Function, &'static str> {
match *v.borrow() {
ValueData::Function(ref func) => match *func.borrow() {
NativeFunc(ref data) => Ok(data.data),
Function::NativeFunc(ref data) => Ok(data.data),
_ => Err("Value is not a native function"),
},
_ => Err("Value is not a function"),
@ -487,43 +497,34 @@ impl FromValue for NativeFunctionData {
}
impl ToValue for ObjectData {
fn to_value(&self) -> Value {
Gc::new(ValueData::Object(RefCell::new(self.clone())))
GcCell::new(ValueData::Object(RefCell::new(self.clone())))
}
}
impl FromValue for ObjectData {
impl<T> FromValue<T> for ObjectData {
fn from_value(v: Value) -> Result<ObjectData, &'static str> {
match *v.borrow() {
ValueData::Object(ref obj) => Ok(obj.clone().borrow().deref().clone()),
ValueData::Function(ref func) => Ok(match *func.borrow().deref() {
NativeFunc(ref data) => data.object.clone(),
RegularFunc(ref data) => data.object.clone(),
Function::NativeFunc(ref data) => data.object.clone(),
Function::RegularFunc(ref data) => data.object.clone(),
}),
_ => Err("Value is not a valid object"),
}
}
}
impl ToValue for Json {
fn to_value(&self) -> Value {
Gc::new(ValueData::from_json(self.clone()))
}
}
impl FromValue for Json {
fn from_value(v: Value) -> Result<Json, &'static str> {
Ok(v.borrow().to_json())
}
}
impl ToValue for () {
fn to_value(&self) -> Value {
Gc::new(ValueData::Null)
GcCell::new(ValueData::Null)
}
}
impl FromValue for () {
impl<T> FromValue<T> for () {
fn from_value(_: Value) -> Result<(), &'static str> {
Ok(())
}
}
/// A utility function that just calls FromValue::from_value
pub fn from_value<A: FromValue>(v: Value) -> Result<A, &'static str> {
pub fn from_value<A: FromValue<T>>(v: Value) -> Result<A, &'static str> {
FromValue::from_value(v)
}

Loading…
Cancel
Save