Beginnings of a type system.

This commit is contained in:
James Harton 2018-08-23 15:15:33 +12:00
parent 37f3070326
commit c2d775169f
10 changed files with 487 additions and 112 deletions

View file

@ -4,3 +4,5 @@ version = "0.1.0"
authors = ["James Harton <james@automat.nz>"] authors = ["James Harton <james@automat.nz>"]
[dependencies] [dependencies]
im = "11.0.1"
wrc = "0.3.0"

184
src/context.rs Normal file
View file

@ -0,0 +1,184 @@
use static_strings::StaticStringId;
use static_strings::StaticStrings;
use std::collections::HashMap;
use traits::Trait;
use traits::TraitId;
use types::Type;
use types::TypeId;
#[derive(Debug)]
pub struct Context {
pub strings: StaticStrings,
types: HashMap<TypeId, Type>,
traits: HashMap<TraitId, Trait>,
}
impl Context {
pub fn new() -> Self {
Context {
strings: StaticStrings::new(),
types: HashMap::new(),
traits: HashMap::new(),
}
}
pub fn new_native_integer_type(&mut self, name: &str) -> TypeId {
let id = self.next_type_id();
let name = self.strings.set(name);
self.types
.insert(id.clone(), Type::integer(id.clone(), name));
id
}
pub fn new_native_float_type(&mut self, name: &str) -> TypeId {
let id = self.next_type_id();
let name = self.strings.set(name);
self.types.insert(id.clone(), Type::float(id.clone(), name));
id
}
pub fn new_native_buffer_type(&mut self, name: &str) -> TypeId {
let id = self.next_type_id();
let name = self.strings.set(name);
self.types
.insert(id.clone(), Type::buffer(id.clone(), name));
id
}
pub fn new_type(&mut self, name: &str, fields: Vec<(&str, TypeId)>) -> TypeId {
let id = self.next_type_id();
let name = self.strings.set(name);
let fields = fields
.into_iter()
.map(|(n, i)| (self.strings.set(n), i))
.collect();
self.types
.insert(id.clone(), Type::compound(id.clone(), name, fields));
id
}
pub fn new_trait(&mut self, name: &str) -> TraitId {
let id = self.next_trait_id();
let name = self.strings.set(name);
self.traits.insert(id.clone(), Trait::new(id.clone(), name));
id
}
pub fn get_type(&self, id: TypeId) -> Option<&Type> {
self.types.get(&id)
}
pub fn get_trait(&self, id: TraitId) -> Option<&Trait> {
self.traits.get(&id)
}
fn next_type_id(&self) -> TypeId {
TypeId::new(self.types.len() as u32)
}
fn next_trait_id(&self) -> TraitId {
TraitId::new(self.traits.len() as u32)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_new() {
Context::new();
}
#[test]
fn test_new_native_integer_type() {
let mut context = Context::new();
let typeid = context.new_native_integer_type("Marty McFly");
assert_eq!(typeid.clone(), TypeId::new(0));
let ty = context.get_type(typeid).unwrap();
assert_eq!(ty.name(), context.strings.try("Marty McFly").unwrap());
assert_eq!(ty.is_integer(), true);
assert_eq!(ty.is_float(), false);
assert_eq!(ty.is_buffer(), false);
assert_eq!(ty.is_compound(), false);
}
#[test]
fn test_new_native_float_type() {
let mut context = Context::new();
let typeid = context.new_native_float_type("Marty McFly");
assert_eq!(typeid.clone(), TypeId::new(0));
let ty = context.get_type(typeid).unwrap();
assert_eq!(ty.name(), context.strings.try("Marty McFly").unwrap());
assert_eq!(ty.is_integer(), false);
assert_eq!(ty.is_float(), true);
assert_eq!(ty.is_buffer(), false);
assert_eq!(ty.is_compound(), false);
}
#[test]
fn test_new_native_buffer_type() {
let mut context = Context::new();
let typeid = context.new_native_buffer_type("Marty McFly");
assert_eq!(typeid.clone(), TypeId::new(0));
let ty = context.get_type(typeid).unwrap();
assert_eq!(ty.name(), context.strings.try("Marty McFly").unwrap());
assert_eq!(ty.is_integer(), false);
assert_eq!(ty.is_float(), false);
assert_eq!(ty.is_buffer(), true);
assert_eq!(ty.is_compound(), false);
}
#[test]
fn test_new_type() {
let mut context = Context::new();
let int = context.new_native_integer_type("int");
let flt = context.new_native_float_type("flt");
let id = context.new_type("compound", vec![("a", int.clone()), ("b", flt.clone())]);
let ty = context.get_type(id).unwrap();
assert_eq!(ty.name(), context.strings.try("compound").unwrap());
assert_eq!(ty.is_integer(), false);
assert_eq!(ty.is_float(), false);
assert_eq!(ty.is_buffer(), false);
assert_eq!(ty.is_compound(), true);
let fields = ty.fields().unwrap();
assert_eq!(fields[0], (context.strings.try("a").unwrap(), int));
assert_eq!(fields[1], (context.strings.try("b").unwrap(), flt));
}
#[test]
fn test_new_trait() {
let mut context = Context::new();
let id = context.new_trait("Marty");
let tr = context.get_trait(id.clone()).unwrap();
assert_eq!(tr.id(), id);
assert_eq!(tr.name(), context.strings.try("Marty").unwrap());
}
// #[test]
// fn test_debug() {
// let mut context = Context::new();
// let int = context.new_native_integer_type("INTEGER");
// let flt = context.new_native_float_type("FLOAT");
// let buf = context.new_native_buffer_type("BUFFER");
// context.new_type(
// "TUPLE",
// vec![("INTEGER", int), ("FLOAT", flt), ("BUFFER", buf)],
// );
// context.new_trait("Integer");
// assert_eq!("WAT", format!("{:?}", context));
// }
}

View file

@ -1,4 +0,0 @@
mod storage;
mod tag;
mod value;
pub use self::value::Value;

View file

@ -1,4 +0,0 @@
pub union Storage {
pub integer: i64,
pub float: f64,
}

View file

@ -1,5 +0,0 @@
#[derive(Debug)]
pub enum Tag {
Integer,
Float,
}

View file

@ -1,90 +0,0 @@
use std::convert::From;
use std::fmt;
use super::storage::Storage;
use super::tag::Tag;
pub struct Value {
tag: Tag,
storage: Storage,
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
match self {
&Value {
tag: Tag::Integer,
storage: Storage { integer: value },
} => write!(f, "Value::Integer<{:?}>", value),
&Value {
tag: Tag::Float,
storage: Storage { float: value },
} => write!(f, "Value::Float<{:?}>", value),
}
}
}
}
impl From<i32> for Value {
fn from(i: i32) -> Self {
Value {
tag: Tag::Integer,
storage: Storage { integer: i as i64 },
}
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Value {
tag: Tag::Integer,
storage: Storage { integer: i },
}
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Value {
tag: Tag::Float,
storage: Storage { float: f },
}
}
}
impl From<f32> for Value {
fn from(f: f32) -> Self {
Value {
tag: Tag::Float,
storage: Storage { float: f as f64 },
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn convert_from_i32() {
let i: i32 = 73;
let value = Value::from(i);
assert_eq!(format!("{:?}", value), "Value::Integer<73>");
}
#[test]
fn convert_from_i64() {
let i: i64 = 73;
let value = Value::from(i);
assert_eq!(format!("{:?}", value), "Value::Integer<73>");
}
#[test]
fn convert_from_f64() {
let i: f64 = 1.23;
let value = Value::from(i);
assert_eq!(format!("{:?}", value), "Value::Float<1.23>");
}
}

View file

@ -1,9 +1,4 @@
mod inner; mod context;
mod static_strings;
#[cfg(test)] mod traits;
mod tests { mod types;
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

72
src/static_strings.rs Normal file
View file

@ -0,0 +1,72 @@
use std::collections::HashMap;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StaticStringId(u32);
impl StaticStringId {
pub fn new(id: u32) -> Self {
StaticStringId(id)
}
}
#[derive(Debug)]
pub struct StaticStrings {
forward: HashMap<String, StaticStringId>,
backward: HashMap<StaticStringId, String>,
}
impl StaticStrings {
pub fn new() -> Self {
StaticStrings {
forward: HashMap::new(),
backward: HashMap::new(),
}
}
pub fn set(&mut self, value: &str) -> StaticStringId {
if self.forward.contains_key(value) {
return self.forward.get(value).unwrap().clone();
}
let id = self.next_string_id();
self.forward.insert(value.to_string(), id.clone());
self.backward.insert(id.clone(), value.to_string());
id
}
pub fn get(&self, id: StaticStringId) -> Option<&String> {
self.backward.get(&id)
}
pub fn try(&self, value: &str) -> Option<StaticStringId> {
match self.forward.get(value) {
Some(id) => Some(id.clone()),
None => None,
}
}
fn next_string_id(&self) -> StaticStringId {
StaticStringId::new(self.forward.len() as u32)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_set_returns_duplicate_ids() {
let mut strings = StaticStrings::new();
let id0 = strings.set("Marty McFly");
let id1 = strings.set("Doc Brown");
let id2 = strings.set("Marty McFly");
assert_ne!(id0, id1);
assert_eq!(id0, id2);
}
#[test]
fn test_get() {
let mut strings = StaticStrings::new();
let id0 = strings.set("Marty McFly");
assert_eq!(strings.get(id0).unwrap(), "Marty McFly");
}
}

46
src/traits.rs Normal file
View file

@ -0,0 +1,46 @@
use static_strings::StaticStringId;
#[derive(Debug)]
pub struct Trait {
name: StaticStringId,
id: TraitId,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TraitId(u32);
impl TraitId {
pub fn new(id: u32) -> TraitId {
TraitId(id)
}
}
impl Trait {
pub fn new(id: TraitId, name: StaticStringId) -> Self {
Trait { name: name, id: id }
}
pub fn id(&self) -> TraitId {
self.id.clone()
}
pub fn name(&self) -> StaticStringId {
self.name.clone()
}
}
#[cfg(test)]
mod test {
use super::*;
use static_strings::StaticStrings;
#[test]
fn test_new() {
let mut ss = StaticStrings::new();
let s0 = ss.set("Marty McFly");
let id = TraitId::new(13);
let t = Trait::new(id.clone(), s0.clone());
assert_eq!(t.id(), id);
assert_eq!(t.name(), s0);
}
}

179
src/types.rs Normal file
View file

@ -0,0 +1,179 @@
use static_strings::StaticStringId;
#[derive(Debug)]
enum Inner {
Integer,
Float,
Buffer,
Compound(Vec<(StaticStringId, TypeId)>),
}
#[derive(Debug)]
pub struct Type {
name: StaticStringId,
id: TypeId,
inner: Inner,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TypeId(u32);
impl TypeId {
pub fn new(id: u32) -> TypeId {
TypeId(id)
}
}
impl Type {
pub fn integer(id: TypeId, name: StaticStringId) -> Self {
Type {
name: name,
id: id,
inner: Inner::Integer,
}
}
pub fn float(id: TypeId, name: StaticStringId) -> Self {
Type {
name: name,
id: id,
inner: Inner::Float,
}
}
pub fn buffer(id: TypeId, name: StaticStringId) -> Self {
Type {
name: name,
id: id,
inner: Inner::Buffer,
}
}
pub fn compound(
id: TypeId,
name: StaticStringId,
fields: Vec<(StaticStringId, TypeId)>,
) -> Self {
Type {
name: name,
id: id,
inner: Inner::Compound(fields),
}
}
pub fn id(&self) -> TypeId {
self.id.clone()
}
pub fn name(&self) -> StaticStringId {
self.name.clone()
}
pub fn is_integer(&self) -> bool {
match self.inner {
Inner::Integer => true,
_ => false,
}
}
pub fn is_float(&self) -> bool {
match self.inner {
Inner::Float => true,
_ => false,
}
}
pub fn is_buffer(&self) -> bool {
match self.inner {
Inner::Buffer => true,
_ => false,
}
}
pub fn is_compound(&self) -> bool {
match self.inner {
Inner::Compound(_) => true,
_ => false,
}
}
pub fn fields(&self) -> Option<Vec<(StaticStringId, TypeId)>> {
match self.inner {
Inner::Compound(ref fields) => Some(fields.clone()),
_ => None,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use static_strings::StaticStrings;
#[test]
fn test_integer() {
let mut ss = StaticStrings::new();
let s0 = ss.set("Marty McFly");
let id = TypeId::new(13);
let t = Type::integer(id.clone(), s0.clone());
assert_eq!(t.id(), id);
assert_eq!(t.name(), s0);
assert_eq!(t.is_integer(), true);
assert_eq!(t.is_float(), false);
assert_eq!(t.is_buffer(), false);
assert_eq!(t.is_compound(), false);
}
#[test]
fn test_float() {
let mut ss = StaticStrings::new();
let s0 = ss.set("Marty McFly");
let id = TypeId::new(14);
let t = Type::float(id.clone(), s0.clone());
assert_eq!(t.id(), id);
assert_eq!(t.name(), s0);
assert_eq!(t.is_integer(), false);
assert_eq!(t.is_float(), true);
assert_eq!(t.is_buffer(), false);
assert_eq!(t.is_compound(), false);
}
#[test]
fn test_buffer() {
let mut ss = StaticStrings::new();
let s0 = ss.set("Marty McFly");
let id = TypeId::new(15);
let t = Type::buffer(id.clone(), s0.clone());
assert_eq!(t.id(), id);
assert_eq!(t.name(), s0);
assert_eq!(t.is_integer(), false);
assert_eq!(t.is_float(), false);
assert_eq!(t.is_buffer(), true);
assert_eq!(t.is_compound(), false);
}
#[test]
fn test_compound() {
let mut ss = StaticStrings::new();
let s0 = ss.set("Marty McFly");
let s1 = ss.set("Doc Brown");
let s2 = ss.set("Biff Tannen");
let id0 = TypeId::new(0);
let id1 = TypeId::new(1);
let id2 = TypeId::new(2);
let t = Type::compound(
id0.clone(),
s0.clone(),
vec![(s1.clone(), id1.clone()), (s2.clone(), id2.clone())],
);
assert_eq!(t.id(), id0);
assert_eq!(t.name(), s0);
assert_eq!(t.is_integer(), false);
assert_eq!(t.is_float(), false);
assert_eq!(t.is_buffer(), false);
assert_eq!(t.is_compound(), true);
let fields = t.fields().unwrap();
assert_eq!(fields[0], (s1, id1));
assert_eq!(fields[1], (s2, id2));
}
}