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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::collections::{ HashMap, VecDeque };
use little::*;
use value::Value;
pub struct Staging<'c, V: LittleValue> {
next_constant: Constant,
unique_constants: HashMap<Fingerprint, Constant>,
pub locals: VecDeque<Basket<'c, Binding>>,
template: Template<V>,
}
impl<'c, V: LittleValue> Staging<'c, V> {
pub fn new<'r>() -> Staging<'r, V> {
let mut st = Staging {
next_constant: Constant(0),
unique_constants: HashMap::new(),
locals: VecDeque::new(),
template: Template::empty(),
};
st.locals.push_front(Basket::new(Binding(0), |Binding(p)| Binding(p + 1)));
st
}
pub fn include_const(&mut self, const_value: V) -> Mem {
let mut next = self.next_constant;
let constant = match const_value.identify_value() {
Some(fingerprint) => {
let mut added = false;
let identifier = *self.unique_constants.entry(fingerprint).or_insert_with(|| {
let identifier = next;
next = match next {
Constant(v) => Constant(v + 1),
};
added = true;
identifier
});
if added {
self.template.push_constant(identifier, const_value);
}
identifier
},
None => {
let identifier = next;
next = match next {
Constant(v) => Constant(v + 1),
};
self.template.push_constant(identifier, const_value);
identifier
},
};
self.next_constant = next;
Mem::Const(constant)
}
pub fn use_name(&mut self, name: &'c str) -> Option<Mem> {
for basket in &self.locals {
if let Some(ref binding) = basket.get(name) {
return Some(Mem::Binding(binding.clone()));
}
}
None
}
pub fn instr(&mut self, instruction: Instruction) {
trace!("instr {:?}", &instruction);
self.template.push_instruction(instruction);
}
}
impl<'a> Into<Template<Value>> for Staging<'a, Value> {
fn into(self) -> Template<Value> {
self.template
}
}
pub struct Basket<'c, T> {
pub map: HashMap<&'c str, T>,
next: Box<Fn(T) -> T>,
current: T,
}
impl<'c, T> Basket<'c, T> where T: Eq + Clone {
pub fn new<'r, N: Fn(T) -> T + 'static>(initial: T, next: N) -> Basket<'r, T> {
Basket {
map: HashMap::new(),
next: Box::new(next),
current: initial,
}
}
pub fn assign_space(&mut self, name: &'c str) -> T {
let len = self.map.len();
let current = self.current.clone();
let result = self.map.entry(&name).or_insert(current.clone()).clone();
if self.map.len() > len {
self.current = (self.next)(current);
}
result
}
pub fn get(&self, name: &str) -> Option<T> {
self.map.get(name).cloned()
}
}