1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use std::cell::RefCell;
use std::fmt;
use crate::common::score::Result;
use crate::arenas::Alloc;
use crate::hir::visit::Visitor;
use crate::hir::{FromAst, LatentNode, Node};
pub struct Slot<'t, T>(RefCell<SlotState<'t, T>>)
where
T: FromAst<'t> + 't;
#[derive(Copy, Clone)]
enum SlotState<'t, T>
where
T: FromAst<'t> + 't,
{
Fresh(T::LatentInput, T::Context),
Transient,
ReadyOk(&'t T),
ReadyErr,
}
impl<'t, T> Slot<'t, T>
where
T: FromAst<'t>,
T::Context: for<'a> Alloc<'a, 't, T> + Clone,
{
pub fn new(ast: T::LatentInput, context: T::Context) -> Slot<'t, T> {
Slot(RefCell::new(SlotState::Fresh(ast, context)))
}
pub fn poll(&self) -> Result<&'t T> {
match *self.0.borrow() {
SlotState::ReadyOk(x) => return Ok(x),
SlotState::ReadyErr => return Err(()),
SlotState::Transient => panic!("slot recursion"),
_ => (),
}
let (ast, context) = match self.0.replace(SlotState::Transient) {
SlotState::Fresh(ast, context) => (ast, context),
_ => unreachable!(),
};
let node = T::from_ast(ast, context.clone()).map(|x| context.alloc(x) as &T);
self.0.replace(match node {
Ok(x) => SlotState::ReadyOk(x),
Err(()) => SlotState::ReadyErr,
});
node
}
}
impl<'t, T, L> LatentNode<'t, L> for Slot<'t, T>
where
&'t T: Into<&'t L>,
L: ?Sized + 't,
T: FromAst<'t> + Node<'t>,
T::Context: for<'a> Alloc<'a, 't, T> + Clone,
{
fn poll(&self) -> Result<&'t L> {
Slot::poll(self).map(|n| n.into())
}
fn accept(&self, visitor: &mut Visitor<'t>) {
match self.poll() {
Ok(n) => n.accept(visitor),
Err(()) => (),
}
}
fn walk(&self, visitor: &mut Visitor<'t>) {
match self.poll() {
Ok(n) => n.walk(visitor),
Err(()) => (),
}
}
}
impl<'t, T> fmt::Debug for Slot<'t, T>
where
T: FromAst<'t>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.0.borrow() {
SlotState::Fresh(..) => write!(f, "Slot(Fresh)"),
SlotState::Transient => write!(f, "Slot(Transient)"),
SlotState::ReadyOk(..) => write!(f, "Slot(ReadyOk)"),
SlotState::ReadyErr => write!(f, "Slot(ReadyErr)"),
}
}
}