aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs112
1 files changed, 109 insertions, 3 deletions
diff --git a/src/lib.rs b/src/lib.rs
index a138c33..5ea0b63 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,
}
}