rain_lang/value/
mod.rs

1/*!
2The `rain` intermediate representation directed acyclic graph
3*/
4use std::ops::{Deref, DerefMut};
5use std::borrow::Cow;
6use std::convert::{TryInto, TryFrom, Infallible};
7use std::cmp::Ordering;
8use smallvec::SmallVec;
9use std::fmt::{self, Debug, Display, Formatter};
10use std::hash::{Hash, Hasher};
11use either::Either;
12
13use crate::graph::{
14    node::{Node, WeakNode, NodeData, View, Backlink},
15    region::{WeakRegion, Parameter},
16    cons::CacheEntry
17};
18
19pub mod primitive;
20use primitive::{
21    Unit,
22    logical::{self, LogicalOp, Bool}
23};
24
25pub mod expr;
26use expr::Sexpr;
27
28
29pub mod lambda;
30use lambda::Lambda;
31
32pub mod error;
33use error::{IncomparableRegions, ValueError};
34
35pub mod judgement;
36use judgement::JEq;
37
38pub mod eval;
39
40pub mod cons;
41use cons::VALUE_CACHE;
42
43/// The size of a small list of dependents
44const SMALL_DEPENDENTS: usize = 2;
45
46/// A `rain` value
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub enum ValueEnum {
49    /// An S-expression
50    Sexpr(Sexpr),
51    /// Boolean values
52    Bool(bool),
53    /// Logical operations
54    LogicalOp(LogicalOp),
55    /// A lambda function
56    Lambda(Lambda),
57    /// The boolean type
58    BoolTy(Bool),
59    /// The unit type
60    UnitTy(Unit),
61    /// A parameter to a region
62    Parameter(Parameter)
63}
64
65/// An iterator over the dependencies of a rain value
66#[derive(Debug, Clone)]
67pub enum Dependencies<'a> {
68    /// A slice of dependencies
69    Slice(std::slice::Iter<'a, ValId>)
70}
71
72impl<'a> Iterator for Dependencies<'a> {
73    type Item = &'a ValId;
74    fn next(&mut self) -> Option<&'a ValId> {
75        match self {
76            Dependencies::Slice(s) => s.next()
77        }
78    }
79}
80
81impl ValueEnum {
82    /// Check whether this value enum variant can potentially be applied
83    pub fn applicable(&self) -> bool {
84        use ValueEnum::*;
85        match self {
86            Sexpr(_) | LogicalOp(_) | Parameter(_) | Lambda(_) => true,
87            _ => false
88        }
89    }
90    /// Print a value with a name
91    pub fn name_print(&self, fmt: &mut fmt::Formatter, name: Option<&str>)
92    -> Result<(), fmt::Error> {
93        use ValueEnum::*;
94        match (self, name) {
95            (Parameter(parameter), Some(name)) => write!(fmt, "({} : {})", name, parameter.ty),
96            (value, _) => write!(fmt, "{}", value)
97        }
98    }
99    /// Get the base region of this ValueEnum
100    pub fn base_region(&self) -> Cow<WeakRegion> {
101        match self {
102            ValueEnum::Parameter(p) => Cow::Borrowed(p.region()),
103            ValueEnum::Lambda(l) => Cow::Owned(l.region().downgrade()),
104            _ => Cow::Owned(WeakRegion::default())
105        }
106    }
107}
108
109/// A trait implemented by representations of `rain` values
110pub trait ValueDesc: TryInto<ValId> {
111    /// The error type for trying to convert this type into a `ValId`
112    type Err:
113        From<<Self as TryInto<ValId>>::Error>
114        + Into<ValueError>;
115    /// Try to make this type into a node
116    #[inline] fn to_node<E>(self) -> Result<ValId, E>
117    where <Self as TryInto<ValId>>::Error: Into<E> {
118        let v: Result<ValId, _> = self.try_into();
119        v.map_err(|err| err.into())
120    }
121}
122
123/// A trait implemented by `rain` values
124pub trait Value: ValueDesc + TryInto<ValueEnum> + JEq<ValueEnum> + JEq<Self> + JEq<ValId> {
125    /// Try to make this type into a value
126    #[inline] fn to_value<E>(self) -> Result<ValueEnum, E>
127    where <Self as TryInto<ValueEnum>>::Error: Into<E> {
128        let v: Result<ValueEnum, _> = self.try_into();
129        v.map_err(|err| err.into())
130    }
131}
132
133impl ValueDesc for ValueEnum {
134    type Err = ValueError;
135    fn to_node<E>(self) -> Result<ValId, E>
136    where <Self as TryInto<ValId>>::Error: Into<E> {
137        match self {
138            ValueEnum::Sexpr(s) => s.to_node(),
139            v => Node::try_new(ValueData::from(v)).map_err(|err| err.into())
140        }
141    }
142}
143
144impl Value for ValueEnum {}
145
146macro_rules! primitive_value {
147    ($p_ty:ty, $e_ty:expr) => {
148        impl From<$p_ty> for ValueEnum {
149            fn from(p: $p_ty) -> ValueEnum { $e_ty(p) }
150        }
151        impl From<$p_ty> for ValueData {
152            fn from(p: $p_ty) -> ValueData { ValueData::new($e_ty(p)) }
153        }
154        impl From<$p_ty> for ValId {
155            fn from(p: $p_ty) -> ValId {
156                Node::try_new(ValueData::new($e_ty(p))).expect("Impossible")
157            }
158        }
159        impl ValueDesc for $p_ty { type Err = Infallible; }
160        impl Value for $p_ty {}
161    }
162}
163
164primitive_value!(bool, ValueEnum::Bool);
165primitive_value!(Bool, ValueEnum::BoolTy);
166primitive_value!(Unit, ValueEnum::UnitTy);
167primitive_value!(LogicalOp, ValueEnum::LogicalOp);
168primitive_value!(logical::Binary, |b| ValueEnum::LogicalOp(LogicalOp::Binary(b)));
169primitive_value!(logical::Unary, |u| ValueEnum::LogicalOp(LogicalOp::Unary(u)));
170
171impl Display for ValueEnum {
172    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
173        match self {
174            ValueEnum::Sexpr(x) => write!(fmt, "{}", x),
175            ValueEnum::Bool(x) => write!(fmt, "#{}", x),
176            ValueEnum::LogicalOp(x) => write!(fmt, "{}", x),
177            ValueEnum::BoolTy(b) => write!(fmt, "{}", b),
178            ValueEnum::Lambda(_l) => write!(fmt, "#lambda #TODO"), //TODO
179            ValueEnum::UnitTy(u) => write!(fmt, "{}", u),
180            ValueEnum::Parameter(p) => write!(fmt, "#param({})", p.ty)
181        }
182    }
183}
184
185/// The data associated with a rain value
186#[derive(Debug, Clone)]
187pub struct ValueData {
188    /// The value itself
189    pub value: ValueEnum,
190    /// The name associated with this value, if any
191    pub name: Option<String>,
192    /// The region this value is defined in
193    pub region: WeakRegion,
194    /// The values dependent on this value
195    dependents: SmallVec<[WeakId; SMALL_DEPENDENTS]>,
196    /*
197    /// A self-link
198    pub this: WeakId
199    */
200}
201
202impl<R> View<R> where R: DerefMut<Target=ValueData> {
203    /// Add a dependent to the given value
204    #[inline]
205    pub fn add_dependent(&mut self, dependent: WeakId) {
206        self.0.deref_mut().dependents.push(dependent)
207    }
208    /// Try to set the name of a given value
209    pub fn set_name(&mut self, name: String) -> Result<(), String> {
210        if self.name.is_none() {
211            self.0.name = Some(name);
212            Ok(())
213        } else {
214            Err(name)
215        }
216    }
217}
218
219impl Deref for ValueData {
220    type Target = ValueEnum;
221    #[inline(always)] fn deref(&self) -> &ValueEnum { &self.value }
222}
223
224impl ValueData {
225    /*
226    /// Check if this value data points to the same value as another
227    pub fn ptr_eq<O: HasThis<ValueData>>(&self, other: &O) -> bool {
228        self.this.ptr_eq(&other.this())
229    }
230    /// Check if this value data points to the same allocation as another
231    /// Returns false if either value data are not currently in an allocation.
232    pub fn alloc_eq<O: HasThis<ValueData>>(&self, other: &O) -> bool {
233        self.this.alloc_eq(&other.this())
234    }
235    */
236    /// Create ValueData from a ValueEnum having a given region
237    pub fn with_region(value: ValueEnum, region: WeakRegion) -> ValueData {
238        ValueData {
239            value,
240            region,
241            name: None,
242            dependents: SmallVec::new()
243        }
244    }
245    /// Create ValueData from a ValueEnum with no region
246    pub fn new(value: ValueEnum) -> ValueData {
247        Self::with_region(value, WeakRegion::default())
248    }
249    /// Add a dependent to a value
250    #[inline]
251    pub fn add_dependent(&mut self, dependent: WeakNode<Self>) { self.dependents.push(dependent) }
252    /// Iterate over the direct dependencies for the given node
253    pub fn dependencies(&self) -> Dependencies {
254        match &self.value {
255            ValueEnum::Sexpr(s) => Dependencies::Slice(s.dependencies()),
256            ValueEnum::Lambda(l) => Dependencies::Slice(l.dependencies()),
257            _ => Dependencies::Slice([].iter())
258        }
259    }
260    /// Get the direct dependents of a given node
261    pub fn dependents(&self) -> &[WeakId] { self.dependents.deref() }
262}
263
264impl Display for ValueData {
265    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
266        self.value.name_print(fmt, self.name.as_ref().map(|s| s.as_str()))
267    }
268}
269
270impl From<ValueEnum> for ValueData {
271    fn from(value: ValueEnum) -> ValueData { ValueData::new(value) }
272}
273
274impl PartialEq for ValueData {
275    fn eq(&self, other: &ValueData) -> bool {
276        /*self.alloc_eq(other) ||*/ self.value == other.value
277    }
278}
279
280impl Hash for ValueData {
281    fn hash<H: Hasher>(&self, hasher: &mut H) {
282        self.value.hash(hasher)
283    }
284}
285
286/// A value ID: a node pointing to value data
287pub type ValId = Node<ValueData>;
288
289/// A weak value ID: a weak node optionally pointing to value data
290pub type WeakId = WeakNode<ValueData>;
291
292impl NodeData for ValueData {
293    type Error = ValueError;
294    type CacheAcceptor = CacheEntry<'static, ValueData>;
295    #[inline] fn backlink(&mut self, backlink: Backlink<ValueData>) -> Result<(), ValueError> {
296        //let this = backlink.downgrade();
297        //self.this = this
298
299        let mut region = WeakRegion::default();
300        std::mem::swap(&mut self.region, &mut region);
301
302        let max_region = |acc: &mut WeakRegion, region: &WeakRegion| {
303            let ord = (*acc).partial_cmp(region);
304            match ord {
305                None => return Err(
306                    ValueError::IncomparableRegions(
307                        IncomparableRegions(
308                            SmallVec::from([region.clone(), region.clone()])
309                        )
310                    )
311                ),
312                Some(Ordering::Greater) => *acc = region.clone(),
313                _ => {}
314            }
315            Ok(())
316        };
317        max_region(&mut region, &self.value.base_region())?;
318
319        for dependency in self.dependencies() {
320            let mut dependency = dependency.data_mut();
321            dependency.add_dependent(backlink.downgrade());
322            max_region(&mut region, &dependency.region)?;
323        }
324        self.region = region;
325        Ok(())
326    }
327    #[inline] fn dedup(&mut self) -> Either<ValId, CacheEntry<'static, ValueData>> {
328        VALUE_CACHE.deref().cached_entry(self)
329    }
330}
331
332impl ValId {
333    /// Register a value dependent on this value
334    #[inline] pub fn add_dependent(&self, dependent: WeakId) {
335        self.data_mut().add_dependent(dependent)
336    }
337}
338
339impl TryFrom<ValueEnum> for ValId {
340    type Error = ValueError;
341    fn try_from(value: ValueEnum) -> Result<ValId, ValueError> {
342        Node::try_new(ValueData::try_from(value)?)
343    }
344}