diff options
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 112 |
1 files changed, 109 insertions, 3 deletions
@@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::path::{Path, PathBuf}; @@ -86,11 +86,56 @@ pub enum Type { Bool, String, Tuple(Vec<Type>), + Union(HashSet<Type>), Function(Vec<Type>, Box<Type>), Blob(Rc<Blob>), Instance(Rc<Blob>), } +impl Hash for Type { + fn hash<H: Hasher>(&self, h: &mut H) { + match self { + Type::Void => 0, + Type::Unknown => 1, + Type::Int => 2, + Type::Float => 3, + Type::Bool => 4, + Type::String => 5, + Type::Tuple(ts) => { + for t in ts.iter() { + t.hash(h); + } + 6 + } + Type::Union(ts) => { + for t in ts { + t.hash(h); + } + 7 + } + Type::Function(args, ret) => { + ret.hash(h); + for t in args.iter() { + t.hash(h); + } + 8 + } + Type::Blob(b) => { + for (_, t) in b.fields.values() { + t.hash(h); + } + 10 + } + Type::Instance(b) => { + for (_, t) in b.fields.values() { + t.hash(h); + } + 11 + } + }.hash(h); + } +} + impl PartialEq for Type { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -104,6 +149,9 @@ impl PartialEq for Type { (Type::Tuple(a), Type::Tuple(b)) => { a.iter().zip(b.iter()).all(|(a, b)| a == b) } + (Type::Union(a), b) | (b, Type::Union(a)) => { + a.iter().any(|x| x == b) + } (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => a_args == b_args && a_ret == b_ret, _ => false, @@ -111,6 +159,8 @@ impl PartialEq for Type { } } +impl Eq for Type {} + impl From<&Value> for Type { fn from(value: &Value) -> Type { match value { @@ -119,6 +169,9 @@ impl From<&Value> for Type { Value::Tuple(v) => { Type::Tuple(v.iter().map(|x| Type::from(x)).collect()) } + Value::Union(v) => { + Type::Union(v.iter().map(|x| Type::from(x)).collect()) + } Value::Int(_) => Type::Int, Value::Float(_) => Type::Float, Value::Bool(_) => Type::Bool, @@ -147,6 +200,9 @@ impl From<&Type> for Value { Type::Tuple(fields) => { Value::Tuple(Rc::new(fields.iter().map(Value::from).collect())) } + Type::Union(v) => { + Value::Union(v.iter().map(Value::from).collect()) + } Type::Unknown => Value::Unknown, Type::Int => Value::Int(1), Type::Float => Value::Float(1.0), @@ -172,6 +228,7 @@ pub enum Value { Blob(Rc<Blob>), Instance(Rc<Blob>, Rc<RefCell<Vec<Value>>>), Tuple(Rc<Vec<Value>>), + Union(HashSet<Value>), Float(f64), Int(i64), Bool(bool), @@ -200,6 +257,7 @@ impl Debug for Value { Value::Unknown => write!(fmt, "(unknown)"), Value::Nil => write!(fmt, "(nil)"), Value::Tuple(v) => write!(fmt, "({:?})", v), + Value::Union(v) => write!(fmt, "(U {:?})", v), } } } @@ -214,6 +272,9 @@ impl PartialEq<Value> for Value { (Value::Tuple(a), Value::Tuple(b)) => { a.len() == b.len() && a.iter().zip(b.iter()).all(|(a, b)| a == b) } + (Value::Union(a), b) | (b, Value::Union(a)) => { + a.iter().any(|x| x == b) + } (Value::Nil, Value::Nil) => true, _ => false, } @@ -566,6 +627,7 @@ pub enum Op { mod op { use super::{Type, Value}; use std::rc::Rc; + use std::collections::HashSet; fn tuple_bin_op(a: &Rc<Vec<Value>>, b: &Rc<Vec<Value>>, f: fn (&Value, &Value) -> Value) -> Value { Value::Tuple(Rc::new(a.iter().zip(b.iter()).map(|(a, b)| f(a, b)).collect())) @@ -575,11 +637,34 @@ mod op { Value::Tuple(Rc::new(a.iter().map(f).collect())) } + fn union_un_op(a: &HashSet<Value>, f: fn (&Value) -> Value) -> Value { + a.iter().find_map(|x| { + let x = f(x); + if x.is_nil() { + None + } else { + Some(x) + } + }).unwrap_or(Value::Nil) + } + + fn union_bin_op(a: &HashSet<Value>, b: &Value, f: fn (&Value, &Value) -> Value) -> Value { + a.iter().find_map(|x| { + let x = f(x, b); + if x.is_nil() { + None + } else { + Some(x) + } + }).unwrap_or(Value::Nil) + } + pub fn neg(value: &Value) -> Value { match value { Value::Float(a) => Value::Float(-*a), Value::Int(a) => Value::Int(-*a), Value::Tuple(a) => tuple_un_op(a, neg), + Value::Union(v) => union_un_op(&v, neg), Value::Unknown => Value::Unknown, _ => Value::Nil, } @@ -589,6 +674,7 @@ mod op { match value { Value::Bool(a) => Value::Bool(!*a), Value::Tuple(a) => tuple_un_op(a, not), + Value::Union(v) => union_un_op(&v, not), Value::Unknown => Value::from(Type::Bool), _ => Value::Nil, } @@ -603,6 +689,7 @@ mod op { (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, add), (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => add(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, add), _ => Value::Nil, } } @@ -618,6 +705,7 @@ mod op { (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, mul), (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => mul(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, mul), _ => Value::Nil, } } @@ -629,6 +717,7 @@ mod op { (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, div), (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => div(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, div), _ => Value::Nil, } } @@ -639,9 +728,17 @@ mod op { (Value::Int(a), Value::Int(b)) => Value::Bool(a == b), (Value::String(a), Value::String(b)) => Value::Bool(a == b), (Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b), - (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, eq), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => { + a.iter().zip(b.iter()).find_map( + |(a, b)| match eq(a, b) { + Value::Bool(true) => None, + a => Some(a), + }).unwrap_or(Value::Bool(true)) + } (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => eq(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, eq), + (Value::Nil, Value::Nil) => Value::Bool(true), _ => Value::Nil, } } @@ -652,9 +749,16 @@ mod op { (Value::Int(a), Value::Int(b)) => Value::Bool(a < b), (Value::String(a), Value::String(b)) => Value::Bool(a < b), (Value::Bool(a), Value::Bool(b)) => Value::Bool(a < b), - (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, less), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => { + a.iter().zip(b.iter()).find_map( + |(a, b)| match less(a, b) { + Value::Bool(true) => None, + a => Some(a), + }).unwrap_or(Value::Bool(true)) + } (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => less(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, less), _ => Value::Nil, } } @@ -669,6 +773,7 @@ mod op { (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, and), (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => and(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, and), _ => Value::Nil, } } @@ -679,6 +784,7 @@ mod op { (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, or), (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => or(a, a), (Value::Unknown, Value::Unknown) => Value::Unknown, + (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, or), _ => Value::Nil, } } |
