context.rs 11.2 KB
Newer Older
1
use error::{Result, Error};
2 3
use factory::{ATermFactory, ATermRef};
use preprocess::ir_v2::{Def, StrategyDef, StrategyRef, TermRef};
4
use primitives::{Primitives, eval_prim_ref};
5
use primitives::ssl::State;
6

7 8
use fnv::FnvHashMap;

9 10
use aterm::string_share::InternedString;

11
use std::fmt;
12
use std::cell::RefCell;
13

Jeff Smits's avatar
Jeff Smits committed
14
/// This context is internally mutable in `RefCell` fields. This is just for convenience as we don't
15
/// want to pass around the mutable fields separately. But the internal mutability is not a hidden
16
/// thing, there is observable effect, so the name of the context includes `Mut`.
Jeff Smits's avatar
Jeff Smits committed
17
pub struct MutContext<'d, 'f: 'd> {
18
    pub stack_tracer: RefCell<StackTracer<'f>>,
19 20 21
    pub term: RefCell<Vec<Option<ATermRef<'f>>>>,
    pub overlays: RefCell<Vec<(usize, FnvHashMap<usize, ATermRef<'f>>)>>,
    pub strategy: RefCell<Vec<StrategyDef<'d, 'f>>>,
22 23
    pub strategy_clos_offsets: RefCell<Vec<usize>>,
    pub term_clos_offsets: RefCell<Vec<usize>>,
24
    pub factory: &'f ATermFactory,
Jeff Smits's avatar
Jeff Smits committed
25
    pub primitives: Vec<&'static Primitives>,
Jeff Smits's avatar
Jeff Smits committed
26
    pub ssl_state: RefCell<State<'f>>,
27 28
}

Jeff Smits's avatar
Jeff Smits committed
29
impl<'d, 'f: 'd> MutContext<'d, 'f> {
30
    pub fn new(
31
        factory: &'f ATermFactory,
32
        strat_scope: StrategyScope<'d, 'f>,
33
        primitives: Vec<&'static Primitives>,
34
    ) -> MutContext<'d, 'f> {
35 36
        MutContext {
            stack_tracer: RefCell::new(StackTracer::default()),
37 38
            factory,
            primitives,
Jeff Smits's avatar
Jeff Smits committed
39
            term: RefCell::new(Vec::new()),
40
            overlays: RefCell::new(Vec::new()),
41
            strategy: RefCell::new(strat_scope),
42 43
            strategy_clos_offsets: RefCell::new(Vec::new()),
            term_clos_offsets: RefCell::new(Vec::new()),
44
            ssl_state: RefCell::new(State::new()),
45 46 47
        }
    }

48 49
    pub fn call_primitive(
        &self,
50
        prim_name: InternedString<'f>,
51 52
        sargs: &[StrategyDef<'d, 'f>],
        targs: &[ATermRef<'f>],
Jeff Smits's avatar
Jeff Smits committed
53 54
        current: ATermRef<'f>,
    ) -> Result<ATermRef<'f>> {
Jeff Smits's avatar
Jeff Smits committed
55 56
        let prim_ref = self.primitives
            .iter()
57
            .flat_map(|prims| prims.get(&*prim_name))
58
            .cloned() // ATermRef is fairly cheap to clone
Jeff Smits's avatar
Jeff Smits committed
59
            .next()
60
            .ok_or_else(|| Error::UndefinedPrimitive(String::from(prim_name)))?;
61
        self.stack_tracer.borrow_mut().push(prim_name);
62
        let result = eval_prim_ref(&prim_ref, self, sargs, targs, current);
63
        if result.is_ok() {
64
            self.stack_tracer.borrow_mut().pop_on_success();
65
        } else {
66
            self.stack_tracer.borrow_mut().pop_on_failure();
67 68
        }
        result
Jeff Smits's avatar
Jeff Smits committed
69 70
    }

71 72 73 74 75 76 77 78
    pub fn make_clos_offsets(&self) -> (Vec<usize>, Vec<usize>) {
        let mut term_clos_offsets = self.term_clos_offsets.borrow().clone();
        let mut strategy_clos_offsets = self.strategy_clos_offsets.borrow().clone();
        term_clos_offsets.push(self.term.borrow().len());
        strategy_clos_offsets.push(self.strategy.borrow().len());
        (term_clos_offsets, strategy_clos_offsets)
    }

79
    pub fn make_let_clos_offsets(&self, let_scope_size: usize) -> (Vec<usize>, Vec<usize>) {
80 81 82
        let mut term_clos_offsets = self.term_clos_offsets.borrow().clone();
        let mut strategy_clos_offsets = self.strategy_clos_offsets.borrow().clone();
        term_clos_offsets.push(self.term.borrow().len());
83
        // note the extra local scope, because `let`s allow recursive definitions
84
        strategy_clos_offsets.push(self.strategy.borrow().len() + let_scope_size);
85 86 87
        (term_clos_offsets, strategy_clos_offsets)
    }

88
    pub fn get_strategy(&self, strat_ref: StrategyRef) -> Result<StrategyDef<'d, 'f>> {
89 90 91 92 93 94 95 96
        let offset = if strat_ref.scope_offset > 0 {
            self.strategy_clos_offsets.borrow()[self.strategy_clos_offsets.borrow().len() -
                                                    strat_ref.scope_offset] -
                strat_ref.ref_offset
        } else {
            self.strategy.borrow().len() - strat_ref.ref_offset
        };
        Ok(self.strategy.borrow()[offset].clone())
97 98
    }

99
    pub fn get_term(&self, term_ref: TermRef) -> Result<ATermRef<'f>> {
100 101 102 103 104 105
        let offset = if term_ref.scope_offset > 0 {
            self.term_clos_offsets.borrow()[self.term_clos_offsets.borrow().len() -
                                                term_ref.scope_offset] -
                term_ref.ref_offset
        } else {
            self.term.borrow().len() - term_ref.ref_offset
106 107
        };
        for &(n, ref map) in self.overlays.borrow().iter().rev() {
108
            if n <= offset {
109 110 111 112 113 114 115 116 117
                break;
            }
            if let Some(binding) = map.get(&offset) {
                return Ok(binding.clone());
            }
        }
        self.term.borrow()[offset].clone().ok_or(
            Error::StrategyFailed,
        )
Jeff Smits's avatar
Jeff Smits committed
118 119
    }

120
    pub fn match_term(&self, term_ref: TermRef, current: &ATermRef<'f>) -> Result<()> {
121 122 123 124 125 126
        let offset = if term_ref.scope_offset > 0 {
            self.term_clos_offsets.borrow()[self.term_clos_offsets.borrow().len() -
                                                term_ref.scope_offset] -
                term_ref.ref_offset
        } else {
            self.term.borrow().len() - term_ref.ref_offset
127 128
        };
        self.match_term_offset(offset, current)
Jeff Smits's avatar
Jeff Smits committed
129 130
    }

131 132 133 134
    fn match_term_offset(&self, offset: usize, current: &ATermRef<'f>) -> Result<()> {
        let mut overlay_active = false;

        for &(n, ref map) in self.overlays.borrow().iter().rev() {
135
            if n <= offset {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
                break;
            }
            overlay_active = true;
            if let Some(binding) = map.get(&offset) {
                return if binding == current {
                    Ok(())
                } else {
                    Err(Error::StrategyFailed)
                };
            }
        }
        if let Some(ref binding) = self.term.borrow()[offset] {
            return if binding == current {
                Ok(())
            } else {
                Err(Error::StrategyFailed)
            };
153
        }
154 155 156 157 158 159 160 161 162 163
        if overlay_active {
            self.overlays.borrow_mut().last_mut().unwrap().1.insert(
                offset,
                current
                    .clone(),
            );
            Ok(())
        } else {
            self.term.borrow_mut()[offset] = Some(current.clone());
            Ok(())
164
        }
165 166 167 168 169 170 171 172 173 174 175 176
    }

    pub fn in_scope<F>(
        &self,
        (term_scope, strat_scope): ScopePair<'d, 'f>,
        body: F,
    ) -> Result<ATermRef<'f>>
    where
        F: FnOnce() -> Result<ATermRef<'f>>,
    {
        let term_len = self.term.borrow().len();
        let strat_len = self.strategy.borrow().len();
177 178 179

        self.term.borrow_mut().extend_from_slice(&term_scope);
        self.strategy.borrow_mut().extend_from_slice(&strat_scope);
180 181 182 183 184 185

        let result = body();

        self.term.borrow_mut().truncate(term_len);
        self.strategy.borrow_mut().truncate(strat_len);

186 187 188
        result
    }

189 190 191
    pub fn in_term_scope<F>(&self, term_scope: TermScope<'f>, body: F) -> Result<ATermRef<'f>>
    where
        F: FnOnce() -> Result<ATermRef<'f>>,
Jeff Smits's avatar
Jeff Smits committed
192
    {
193
        let term_len = self.term.borrow().len();
194 195

        self.term.borrow_mut().extend_from_slice(&term_scope);
196

Jeff Smits's avatar
Jeff Smits committed
197
        let result = body();
198 199 200

        self.term.borrow_mut().truncate(term_len);

Jeff Smits's avatar
Jeff Smits committed
201 202 203
        result
    }

204 205 206 207 208 209 210
    pub fn in_strategy_scope<F>(
        &self,
        strat_scope: StrategyScope<'d, 'f>,
        body: F,
    ) -> Result<ATermRef<'f>>
    where
        F: FnOnce() -> Result<ATermRef<'f>>,
Jeff Smits's avatar
Jeff Smits committed
211
    {
212
        let strat_len = self.strategy.borrow().len();
213 214

        self.strategy.borrow_mut().extend_from_slice(&strat_scope);
215

Jeff Smits's avatar
Jeff Smits committed
216
        let result = body();
217 218 219

        self.strategy.borrow_mut().truncate(strat_len);

Jeff Smits's avatar
Jeff Smits committed
220 221 222
        result
    }

223
    pub fn push_overlay(&self) {
224 225 226 227
        self.overlays.borrow_mut().push((
            self.term.borrow().len(),
            FnvHashMap::default(),
        ));
228 229
    }

230
    fn apply_overlay_internal(&self, map: FnvHashMap<usize, ATermRef<'f>>) {
231
        for (name, value) in map {
232 233 234 235 236
            let result = self.match_term_offset(name, &value);
            debug_assert!(
                result.is_ok(),
                "_apply_overlay: Interpreter bug, overlay could not bind to names underneath"
            );
237
        }
238 239 240
    }

    pub fn apply_overlay(&self) {
241
        let (offset, map) = self.overlays.borrow_mut().pop().expect(
242 243
            "apply_overlay: Interpreter bug, unexpected end of stack",
        );
244
        debug_assert_eq!(
245 246
            self.term.borrow().len(),
            offset,
247
            "apply_overlay: Interpreter bug, unexpected normal scope"
248
        );
249
        self.apply_overlay_internal(map);
250 251 252
    }

    pub fn drop_overlay(&self) {
253
        let (offset, _map) = self.overlays.borrow_mut().pop().expect(
254 255
            "drop_overlay: Interpreter bug, unexpected end of stack",
        );
256
        debug_assert_eq!(
257 258
            self.term.borrow().len(),
            offset,
259 260
            "drop_overlay: Interpreter bug, unexpected normal scope"
        );
Jeff Smits's avatar
Jeff Smits committed
261 262
    }

263
    pub fn clear_overlay(&self) {
264 265
        let mut overlays = self.overlays.borrow_mut();
        let &mut (ref offset, ref mut map) = overlays.last_mut().expect(
266 267
            "clear_overlay: Interpreter bug, unexpected end of stack",
        );
268
        debug_assert_eq!(
269 270
            self.term.borrow().len(),
            *offset,
Jeff Smits's avatar
Jeff Smits committed
271
            "clear_overlay: Interpreter bug, unexpected normal scope"
272
        );
273
        map.clear();
274 275 276 277
    }
}

#[derive(Debug, Default, Clone)]
278
pub struct StackTracer<'a> {
279
    stack: Vec<InternedString<'a>>,
280
    current_depth: usize,
281 282
}

283
impl<'a> StackTracer<'a> {
284
    pub fn push(&mut self, str: InternedString<'a>) {
285
        self.stack.truncate(self.current_depth);
286
        self.stack.push(str);
287
        self.current_depth += 1;
288 289
    }

290 291
    pub fn pop_on_failure(&mut self) {
        self.current_depth -= 1;
292 293
    }

294 295 296
    pub fn pop_on_success(&mut self) {
        let _ = self.stack.pop();
        self.current_depth = self.stack.len();
297
    }
Jeff Smits's avatar
Jeff Smits committed
298

299
    pub fn stack(&self) -> ::std::slice::Iter<InternedString<'a>> {
Jeff Smits's avatar
Jeff Smits committed
300 301
        self.stack.iter()
    }
302 303
}

304
impl<'a> fmt::Display for StackTracer<'a> {
305 306
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (n, name) in self.stack.iter().enumerate() {
Jeff Smits's avatar
Jeff Smits committed
307
            if n + 1 == self.current_depth {
308 309 310 311 312 313 314 315 316
                writeln!(f, "{} <==", name)?;
            } else {
                writeln!(f, "{}", name)?;
            }
        }
        Ok(())
    }
}

317 318
pub type TermScope<'f> = Vec<Option<ATermRef<'f>>>;
pub type StrategyScope<'d, 'f> = Vec<StrategyDef<'d, 'f>>;
Jeff Smits's avatar
Jeff Smits committed
319
pub type ScopePair<'d, 'f> = (TermScope<'f>, StrategyScope<'d, 'f>);
320

Jeff Smits's avatar
Jeff Smits committed
321 322 323
#[allow(non_snake_case)]
pub mod Scope {
    use super::*;
Jeff Smits's avatar
Jeff Smits committed
324

325 326
    pub fn from_defs<'d, 'f: 'd>(defs: &'d Vec<Def<'f>>) -> StrategyScope<'d, 'f> {
        let strat_scope_offset = defs.len();
Jeff Smits's avatar
Jeff Smits committed
327
        defs.into_iter()
328
            .map(|def| StrategyDef::from_def(def, strat_scope_offset))
Jeff Smits's avatar
Jeff Smits committed
329
            .collect()
330 331
    }

332
    pub fn from_let_defs<'d, 'f: 'd, I>(
333 334
        term_scope_offset: Vec<usize>,
        strat_scope_offset: Vec<usize>,
335 336
        defs: I,
    ) -> StrategyScope<'d, 'f>
337
    where
Jeff Smits's avatar
Jeff Smits committed
338
        I: IntoIterator<Item = &'d Def<'f>>,
339
    {
Jeff Smits's avatar
Jeff Smits committed
340 341
        defs.into_iter()
            .map(|def| {
342 343 344 345 346
                StrategyDef::from_let_def(
                    def,
                    term_scope_offset.clone(),
                    strat_scope_offset.clone(),
                )
Jeff Smits's avatar
Jeff Smits committed
347 348
            })
            .collect()
349
    }
350
}