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
// Copyright (c) 2016-2020 Fabian Schuiki

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};

/// A placeholder for an HIR 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,
{
    /// Create a new slot.
    pub fn new(ast: T::LatentInput, context: T::Context) -> Slot<'t, T> {
        Slot(RefCell::new(SlotState::Fresh(ast, context)))
    }

    /// Poll the slot, creating the HIR node from the AST the first time.
    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)"),
        }
    }
}