Skip to content

Instantly share code, notes, and snippets.

@fero23
Created March 11, 2016 03:15
Show Gist options
  • Save fero23/62b869dab4798c684969 to your computer and use it in GitHub Desktop.
Save fero23/62b869dab4798c684969 to your computer and use it in GitHub Desktop.
Sneak peek of a new Javascript builder library in Rust
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