Created
March 11, 2016 03:15
-
-
Save fero23/62b869dab4798c684969 to your computer and use it in GitHub Desktop.
Sneak peek of a new Javascript builder library in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::rc::Rc; | |
use std::fmt::Debug; | |
use std::ops::{Add, Sub}; | |
#[derive(Debug, Clone)] | |
pub enum JsValue<T: ToString> { | |
StaticValue(T), | |
ResultValue(Box<JsOps>), | |
} | |
#[derive(Debug, Clone)] | |
pub enum JsType { | |
JsString(JsValue<String>), | |
JsNumber(JsValue<f64>), | |
JsBoolean(JsValue<bool>), | |
JsFunction(Vec<JsOps>), | |
JsObject(Rc<JsObjectType>), | |
JsArray(Vec<JsType>), | |
JsUndefined, | |
} | |
impl JsType { | |
pub fn to_string(&self) -> String { | |
match *self { | |
JsType::JsString(JsValue::StaticValue(ref str)) => format!("\"{}\"", str), | |
JsType::JsNumber(JsValue::StaticValue(ref num)) => num.to_string(), | |
_ => "".to_string(), | |
} | |
} | |
fn get_type_name(&self) -> String { | |
match *self { | |
JsType::JsString(_) => "string".to_string(), | |
JsType::JsNumber(_) => "number".to_string(), | |
JsType::JsBoolean(_) => "boolean".to_string(), | |
JsType::JsFunction(_) => "function".to_string(), | |
JsType::JsObject(_) => "object".to_string(), | |
JsType::JsArray(_) => "array".to_string(), | |
JsType::JsUndefined => "undefined".to_string(), | |
} | |
} | |
} | |
impl Add for JsType { | |
type Output = JsOps; | |
fn add(self, rhs: JsType) -> JsOps { | |
JsOps::Add { | |
lhs: self, | |
rhs: rhs, | |
} | |
} | |
} | |
impl<'a> Add for &'a JsType { | |
type Output = JsOps; | |
fn add(self, rhs: &JsType) -> JsOps { | |
self.clone() + rhs.clone() | |
} | |
} | |
impl Sub for JsType { | |
type Output = JsOps; | |
fn sub(self, rhs: JsType) -> JsOps { | |
if let (&JsType::JsNumber(_), &JsType::JsNumber(_)) = (&self, &rhs) { | |
return JsOps::Sub { | |
lhs: self, | |
rhs: rhs, | |
}; | |
} | |
panic!(format!("Cannot use operator '-' on types {} and {}", | |
self.get_type_name(), | |
rhs.get_type_name())); | |
} | |
} | |
impl<'a> Sub for &'a JsType { | |
type Output = JsOps; | |
fn sub(self, rhs: &JsType) -> JsOps { | |
self.clone() - rhs.clone() | |
} | |
} | |
#[derive(Debug, Clone)] | |
pub enum JsOps { | |
Add { | |
lhs: JsType, | |
rhs: JsType, | |
}, | |
Div { | |
lhs: JsType, | |
rhs: JsType, | |
}, | |
Mul { | |
lhs: JsType, | |
rhs: JsType, | |
}, | |
Sub { | |
lhs: JsType, | |
rhs: JsType, | |
}, | |
Neg(JsType), | |
Invoke { | |
target: JsType, | |
count: u8, | |
params: Vec<JsType>, | |
}, | |
Assign { | |
ident: String, | |
rhs: JsType, | |
}, | |
} | |
impl JsOps { | |
fn get_repr(&self) -> String { | |
match *self { | |
JsOps::Add {ref lhs, ref rhs} => format!("{} + {}", lhs.to_string(), rhs.to_string()), | |
JsOps::Sub {ref lhs, ref rhs} => format!("{} - {}", lhs.to_string(), rhs.to_string()), | |
_ => "".to_string(), | |
} | |
} | |
} | |
struct JsProps { | |
map: HashMap<String, JsType>, | |
} | |
pub trait JsObjectType: Debug { | |
fn get_props<'a>(&self) -> &'a mut HashMap<String, JsType>; | |
fn get_prop(&mut self, name: String) -> Option<JsType> { | |
let map = self.get_props(); | |
if map.contains_key(&name) { | |
Some(map[&name].clone()) | |
} else { | |
None | |
} | |
} | |
fn set_prop(&mut self, name: String, value: JsType) { | |
if let Some(_value) = self.get_props().get_mut(&name) { | |
*_value = value; | |
} else { | |
self.get_props().insert(name, value); | |
} | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn add_strings() { | |
let lhs = JsType::JsString(JsValue::StaticValue("hello ".to_string())); | |
let rhs = JsType::JsString(JsValue::StaticValue("world".to_string())); | |
assert_eq!((&lhs + &rhs).get_repr(), "\"hello \" + \"world\""); | |
assert_eq!((lhs + rhs).get_repr(), "\"hello \" + \"world\""); | |
} | |
#[test] | |
fn sub_numbers() { | |
let lhs = JsType::JsNumber(JsValue::StaticValue(1.0)); | |
let rhs = JsType::JsNumber(JsValue::StaticValue(2.0)); | |
assert_eq!((&lhs - &rhs).get_repr(), "1 - 2"); | |
assert_eq!((lhs - rhs).get_repr(), "1 - 2"); | |
} | |
#[test] | |
#[should_panic] | |
fn sub_strings() { | |
let lhs = JsType::JsString(JsValue::StaticValue("hello ".to_string())); | |
let rhs = JsType::JsString(JsValue::StaticValue("world".to_string())); | |
let _ = lhs - rhs; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment