[types] Clean up Pair and Sym types
Reconfigure the top-level object types. - Obj is an enum pointer type - Object is a trait that all Scheme types should implement Define Sym, a symbol type. Define Pair, a pair/cons/list type. Implement Display for all types above. Implement casting methods for the above.
This commit is contained in:
parent
f197f1ba8b
commit
d825d0ec8a
4 changed files with 181 additions and 104 deletions
|
@ -1,13 +1,10 @@
|
|||
pub mod number;
|
||||
pub mod char;
|
||||
|
||||
mod bool;
|
||||
mod object;
|
||||
mod predicates;
|
||||
mod pair;
|
||||
mod sym;
|
||||
|
||||
pub use object::Object;
|
||||
pub use object::ObjectPtr;
|
||||
pub use predicates::*;
|
||||
pub use object::Obj;
|
||||
pub use pair::Pair;
|
||||
pub use sym::Sym;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
//! # Objects
|
||||
//!
|
||||
//! All scheme types are represented by the `Object` enum defined in this
|
||||
//! module. Most references to objects are going to be through an `ObjectPtr`.
|
||||
//! All Scheme types implement the `Object` trait defined in this module. Most
|
||||
//! references to objects are going to be through an `ObjectPtr`.
|
||||
//!
|
||||
//! ## Type Predicates
|
||||
//!
|
||||
|
@ -13,116 +13,133 @@
|
|||
//! available types in Scheme. These predicates are implemented as `is_*`
|
||||
//! methods in a bunch of `Is*` traits defined below.
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use number::Number;
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ObjectPtr {
|
||||
/// Absence of a value. A null pointer.
|
||||
pub enum Obj {
|
||||
Null,
|
||||
/// A pointer to an object.
|
||||
Ptr(Box<Object>),
|
||||
Ptr(Box<Object>)
|
||||
}
|
||||
|
||||
pub trait Object :
|
||||
fmt::Display,
|
||||
|
||||
{ }
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Object {
|
||||
Bool(bool),
|
||||
ByteVector(Vec<u8>),
|
||||
Char(char),
|
||||
Number(Number),
|
||||
Pair(ObjectPtr, ObjectPtr),
|
||||
//Procedure/*( TODO: Something )*/,
|
||||
//Record/*( TODO: Something )*/,
|
||||
String(String),
|
||||
Symbol(String),
|
||||
Vector(Vec<ObjectPtr>),
|
||||
pub trait Object:
|
||||
fmt::Display
|
||||
{
|
||||
fn as_any(&self) -> &Any;
|
||||
fn as_pair(&self) -> Option<&Pair>;
|
||||
fn as_sym(&self) -> Option<&Sym>;
|
||||
}
|
||||
|
||||
impl ObjectPtr {
|
||||
pub fn new(obj: Object) -> ObjectPtr {
|
||||
ObjectPtr::Ptr(Box::new(obj))
|
||||
}
|
||||
|
||||
pub fn new_pair() -> ObjectPtr {
|
||||
ObjectPtr::new(Object::Pair(ObjectPtr::Null, ObjectPtr::Null))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ObjectPtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ObjectPtr::Null => write!(f, "()"),
|
||||
ObjectPtr::Ptr(ref bx) => write!(f, "{}", bx.deref()),
|
||||
impl Obj {
|
||||
pub fn unbox_as<T: 'static + Object>(&self) -> Option<&T> {
|
||||
match self {
|
||||
Obj::Null => None,
|
||||
Obj::Ptr(obj) => obj.as_any().downcast_ref::<T>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Object {
|
||||
impl fmt::Display for Obj {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Object::Bool(ref v) => {
|
||||
let out = if *v { "#t" } else { "#f" };
|
||||
write!(f, "{}", out)
|
||||
},
|
||||
|
||||
Object::ByteVector(ref vec) => {
|
||||
// TODO: Actually write the vector values.
|
||||
write!(f, "#u8(").and_then(|_| write!(f, ")"))
|
||||
},
|
||||
|
||||
Object::Char(ref c) => {
|
||||
// TODO: This is not correct for all cases. See section 6.6 of the spec.
|
||||
write!(f, "#\\{}", c)
|
||||
},
|
||||
|
||||
Object::Number(ref n) => {
|
||||
// TODO: Implement Display for Number
|
||||
write!(f, "{}", n)
|
||||
}
|
||||
|
||||
Object::Pair(ref car, ref cdr) => {
|
||||
write!(f, "(").and_then(|_| Object::fmt_pair(car, cdr, f))
|
||||
.and_then(|_| write!(f, ")"))
|
||||
},
|
||||
|
||||
Object::String(ref st) => {
|
||||
write!(f, "\"{}\"", st)
|
||||
},
|
||||
|
||||
Object::Symbol(ref sym) => {
|
||||
write!(f, "{}", sym)
|
||||
},
|
||||
|
||||
Object::Vector(ref vec) => {
|
||||
// TODO: Actually write the vector values.
|
||||
vec.iter().enumerate().fold(write!(f, "#("), |acc, (i, obj)| {
|
||||
let space = if i == (vec.len() - 1) { " " } else { "" };
|
||||
acc.and(write!(f, "{}{}", obj, space))
|
||||
}).and(write!(f, ")"))
|
||||
}
|
||||
match self {
|
||||
Obj::Null => write!(f, "null"),
|
||||
Obj::Ptr(obj) => write!(f, "{}", obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Object {
|
||||
fn fmt_pair(car: &ObjectPtr, cdr: &ObjectPtr, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", car).and_then(|r| match cdr {
|
||||
&ObjectPtr::Null => Ok(r), // Don't write anything.
|
||||
&ObjectPtr::Ptr(ref ptr) => match ptr.deref() {
|
||||
&Object::Pair(ref next_car, ref next_cdr) => {
|
||||
write!(f, " ").and_then(|_| Object::fmt_pair(next_car, next_cdr, f))
|
||||
},
|
||||
_ => write!(f, " . {}", ptr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
//#[derive(Debug, PartialEq)]
|
||||
//pub enum Object {
|
||||
// ByteVector(Vec<u8>),
|
||||
// Char(char),
|
||||
// Number(Number),
|
||||
// Pair(ObjectPtr, ObjectPtr),
|
||||
// //Procedure/*( TODO: Something )*/,
|
||||
// //Record/*( TODO: Something )*/,
|
||||
// String(String),
|
||||
// Symbol(String),
|
||||
// Vector(Vec<ObjectPtr>),
|
||||
//}
|
||||
//
|
||||
//impl ObjectPtr {
|
||||
// pub fn new(obj: Object) -> ObjectPtr {
|
||||
// ObjectPtr::Ptr(Box::new(obj))
|
||||
// }
|
||||
//
|
||||
// pub fn new_pair() -> ObjectPtr {
|
||||
// ObjectPtr::new(Object::Pair(ObjectPtr::Null, ObjectPtr::Null))
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//impl fmt::Display for ObjectPtr {
|
||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// match *self {
|
||||
// ObjectPtr::Null => write!(f, "()"),
|
||||
// ObjectPtr::Ptr(ref bx) => write!(f, "{}", bx.deref()),
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//impl fmt::Display for Object {
|
||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// match *self {
|
||||
// Object::Bool(ref v) => {
|
||||
// let out = if *v { "#t" } else { "#f" };
|
||||
// write!(f, "{}", out)
|
||||
// },
|
||||
//
|
||||
// Object::ByteVector(ref vec) => {
|
||||
// // TODO: Actually write the vector values.
|
||||
// write!(f, "#u8(").and_then(|_| write!(f, ")"))
|
||||
// },
|
||||
//
|
||||
// Object::Char(ref c) => {
|
||||
// // TODO: This is not correct for all cases. See section 6.6 of the spec.
|
||||
// write!(f, "#\\{}", c)
|
||||
// },
|
||||
//
|
||||
// Object::Number(ref n) => {
|
||||
// // TODO: Implement Display for Number
|
||||
// write!(f, "{}", n)
|
||||
// }
|
||||
//
|
||||
// Object::Pair(ref car, ref cdr) => {
|
||||
// write!(f, "(").and_then(|_| Object::fmt_pair(car, cdr, f))
|
||||
// .and_then(|_| write!(f, ")"))
|
||||
// },
|
||||
//
|
||||
// Object::String(ref st) => {
|
||||
// write!(f, "\"{}\"", st)
|
||||
// },
|
||||
//
|
||||
// Object::Symbol(ref sym) => {
|
||||
// write!(f, "{}", sym)
|
||||
// },
|
||||
//
|
||||
// Object::Vector(ref vec) => {
|
||||
// // TODO: Actually write the vector values.
|
||||
// vec.iter().enumerate().fold(write!(f, "#("), |acc, (i, obj)| {
|
||||
// let space = if i == (vec.len() - 1) { " " } else { "" };
|
||||
// acc.and(write!(f, "{}{}", obj, space))
|
||||
// }).and(write!(f, ")"))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//impl Object {
|
||||
// fn fmt_pair(car: &ObjectPtr, cdr: &ObjectPtr, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// write!(f, "{}", car).and_then(|r| match cdr {
|
||||
// &ObjectPtr::Null => Ok(r), // Don't write anything.
|
||||
// &ObjectPtr::Ptr(ref ptr) => match ptr.deref() {
|
||||
// &Object::Pair(ref next_car, ref next_cdr) => {
|
||||
// write!(f, " ").and_then(|_| Object::fmt_pair(next_car, next_cdr, f))
|
||||
// },
|
||||
// _ => write!(f, " . {}", ptr)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
41
types/src/pair.rs
Normal file
41
types/src/pair.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* types/src/pair.rs
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt;
|
||||
use super::*;
|
||||
use object::Object;
|
||||
|
||||
pub struct Pair {
|
||||
car: Obj,
|
||||
cdr: Obj
|
||||
}
|
||||
|
||||
impl Pair {
|
||||
fn fmt_pair(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let r = write!(f, "{}", self.car);
|
||||
r.and_then(|r| match self.cdr {
|
||||
Obj::Null => Ok(r), // Don't write anything.
|
||||
Obj::Ptr(ref next) => {
|
||||
match next.as_pair() {
|
||||
Some(next_pair) => write!(f, " ").and_then(|_| next_pair.fmt_pair(f)),
|
||||
None => write!(f, " . {}", next)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Object for Pair {
|
||||
fn as_any(&self) -> &Any { self }
|
||||
fn as_pair(&self) -> Option<&Pair> { Some(self) }
|
||||
fn as_sym(&self) -> Option<&Sym> { None }
|
||||
}
|
||||
|
||||
impl fmt::Display for Pair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(").and_then(|_| self.fmt_pair(f))
|
||||
.and_then(|_| write!(f, ")"))
|
||||
}
|
||||
}
|
22
types/src/sym.rs
Normal file
22
types/src/sym.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* types/src/symbol.rs
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt;
|
||||
use object::Object;
|
||||
use super::*;
|
||||
|
||||
pub struct Sym(String);
|
||||
|
||||
impl Object for Sym {
|
||||
fn as_any(&self) -> &Any { self }
|
||||
fn as_pair(&self) -> Option<&Pair> { None }
|
||||
fn as_sym(&self) -> Option<&Sym> { Some(self) }
|
||||
}
|
||||
|
||||
impl fmt::Display for Sym {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue