Commit 5b283330 authored by Jeff Smits's avatar Jeff Smits

Turns out transactions weren't needed after all

parent bcf7e925
......@@ -8,7 +8,6 @@ use std::collections::HashMap;
use std::fmt;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::cell::Cell;
// TODO: do AOS to SOA transform for scopes, (to the level of individual variables? Maybe ).
/// This context is internally mutable in `RefCell` fields. This is just for convenience as we don't
......@@ -20,7 +19,6 @@ pub struct MutContext<'a> {
pub factory: &'a ATermFactory,
pub primitives: Vec<&'static Primitives>,
pub ssl_state: RefCell<State>,
overlay_counter: Cell<u32>,
}
impl<'a> MutContext<'a> {
......@@ -34,7 +32,6 @@ impl<'a> MutContext<'a> {
primitives: primitives,
scopes: RefCell::new(scopes),
ssl_state: RefCell::new(State::new()),
overlay_counter: Cell::new(0),
}
}
......@@ -92,19 +89,16 @@ impl<'a> MutContext<'a> {
}
pub fn push_overlay(&self) {
let overlay_no = self.overlay_counter.get();
self.overlay_counter.set(overlay_no+1);
let overlay = Scope {
term: HashMap::new(),
strategy: HashMap::new(),
overlay: Some(overlay_no),
is_overlay: true,
};
self.push_scope(overlay);
}
fn _apply_overlay(&self, scope: Scope<ATermRef>) {
debug_assert!(scope.is_overlay(), "_apply_overlay: Interpreter bug, trying to apply non-overlay");
debug_assert!(scope.strategy.is_empty(), "_apply_overlay: Interpreter bug, overlay is leaking a strategy definition");
for (name, value) in scope.term {
if let Some(value) = value {
......@@ -119,51 +113,19 @@ impl<'a> MutContext<'a> {
}
pub fn apply_overlay(&self) {
let scope_option = self.scopes.borrow_mut().pop();
if let Some(scope) = scope_option {
if scope.is_overlay() {
self._apply_overlay(scope);
} else {
unreachable!("apply_overlay: Interpreter bug, unexpected normal scope")
}
} else {
unreachable!("apply_overlay: Interpreter bug, unexpected end of stack")
}
let scope = self.scopes.borrow_mut().pop().expect("apply_overlay: Interpreter bug, unexpected end of stack");
debug_assert!(scope.is_overlay, "apply_overlay: Interpreter bug, unexpected normal scope");
self._apply_overlay(scope);
}
pub fn drop_overlay(&self) {
let mut scopes = self.scopes.borrow_mut();
if let Some(popped_scope) = scopes.pop() {
// All scopes with a higher number than this overlay, which are lower in the stack, are
// from calls made after this overlay. Since those depend on this overlay to survive,
// and this one is being dropped, we neutralise those higher number overlays.
if let Some(popped_scope_no) = popped_scope.overlay {
for mut scope in scopes.iter_mut() {
if let Some(scope_no) = scope.overlay {
if scope_no > popped_scope_no {
scope.overlay = Some(u32::max_value());
scope.term.clear();
}
}
}
} else {
unreachable!("drop_overlay: Interpreter bug, unexpected normal scope");
}
} else {
unreachable!("drop_overlay: Interpreter bug, unexpected end of stack")
}
let popped_scope = self.scopes.borrow_mut().pop().expect("drop_overlay: Interpreter bug, unexpected end of stack");
debug_assert!(popped_scope.is_overlay, "drop_overlay: Interpreter bug, unexpected normal scope");
}
pub fn pop_scope(&self) {
let scope_option = self.scopes.borrow_mut().pop();
if let Some(scope) = scope_option {
if scope.is_overlay() {
self._apply_overlay(scope);
self.pop_scope();
}
} else {
unreachable!("pop_scope: Interpreter bug, unexpected end of stack")
}
let scope = self.scopes.borrow_mut().pop().expect("pop_scope: Interpreter bug, unexpected end of stack");
debug_assert!(!scope.is_overlay, "pop_scope: Interpreter bug, unexpected overlay");
}
}
......@@ -211,7 +173,7 @@ impl fmt::Display for StackTracer {
pub struct Scope<ATerm> {
pub term: HashMap<String, Option<ATerm>>,
pub strategy: HashMap<String, StrategyDef>,
overlay: Option<u32>,
is_overlay: bool,
}
impl<ATerm> Scope<ATerm> {
......@@ -222,7 +184,7 @@ impl<ATerm> Scope<ATerm> {
Scope {
term: terms.into_iter().map(|(n, a)| (n, Some(a))).collect(),
strategy: defs.into_iter().collect(),
overlay: None,
is_overlay: false,
}
}
......@@ -234,7 +196,7 @@ impl<ATerm> Scope<ATerm> {
strategy: defs.into_iter()
.map(|sdeft| (sdeft.name(), sdeft))
.collect(),
overlay: None,
is_overlay: false,
}
}
......@@ -246,7 +208,7 @@ impl<ATerm> Scope<ATerm> {
strategy: defs.into_iter()
.map(|sdeft| (sdeft.name(), sdeft.set_scope_on_let_sdef(no_of_scopes)))
.collect(),
overlay: None,
is_overlay: false,
}
}
......@@ -264,13 +226,9 @@ impl<ATerm> Scope<ATerm> {
result
},
strategy: HashMap::default(),
overlay: None,
is_overlay: false,
}
}
pub fn is_overlay(&self) -> bool {
self.overlay.is_some()
}
}
#[allow(non_snake_case)]
......@@ -298,9 +256,8 @@ pub mod Scopes {
}
None => {
for mut scope in scopes.iter_mut().rev() {
if scope.is_overlay() || scope.term.contains_key(term_name) {
if let Some(Some(t)) =
scope
if scope.is_overlay || scope.term.contains_key(term_name) {
if let Some(Some(t)) = scope
.term
.insert(term_name.to_owned(), Some(current.clone())) {
unreachable!(format!("match_term: No scope had {}, but we just \
......
......@@ -156,7 +156,8 @@ impl<'a> Eval<'a> for preprocess::Strategy {
.into_iter()
.map(|build_term| build_term.build(context))
.collect::<Result<_>>()?;
sdeft.eval(context, sargs, targs, current)
let result = sdeft.eval(context, sargs, targs, current);
result
}
CallDynamic(ref term_name, ref sargs, ref targs) => {
let strategy_name = context.get_term(term_name)?;
......
......@@ -30,6 +30,7 @@ pub fn preprocess(program: ctree::Module) -> Result<Scope<ATermRef>> {
Ok(Scope::from_defs(defs))
}
// TODO: Make fields public so the eval code can be moved to the interpreter module
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum StrategyDef {
Predefined {
......@@ -48,7 +49,7 @@ pub enum StrategyDef {
}
impl StrategyDef {
// TODO: this big piece of code shouldn't be so complicated right? Rethink the design of closures and backtracking, then fix this mess
// TODO: refactor StrategyDef to remove code duplication below.
pub fn eval<'a>(&self,
context: &MutContext<'a>,
actual_sargs: Vec<StrategyDef>,
......@@ -70,36 +71,17 @@ impl StrategyDef {
// closure was made.
// This works because closure cannot be returned, so the number of scopes always
// reflects the environment in which the closure was made.
// Only problem complicating matters is that an overlay may be temporarily
// popped off here, but it's supposed to catch variable bindings. Therefore
// after popping things off, we always add another overlay.
context.stack_tracer.borrow_mut().push(name.clone());
let popped_scopes = context.scopes.borrow_mut().split_off(no_of_scopes);
context.push_overlay();
context.push_scope(Scope::new(targs.iter().cloned().zip(actual_targs),
sargs.iter().cloned().zip(actual_sargs)));
let result = body.eval(context, current);
context.pop_scope();
let empty_overlay = context.scopes.borrow().last().expect("Where did my overlay go?").term.is_empty();
if result.is_ok() && empty_overlay {
context.apply_overlay();
} else if result.is_err() {
context.drop_overlay();
}
context
.scopes
.borrow_mut()
.extend_from_slice(&popped_scopes);
if result.is_ok() {
// we're leaving an extra scope on the stack, so now we need to fix up the
// no_of_scopes numbers of everything else :(
if !empty_overlay {
for mut scope in context.scopes.borrow_mut().iter_mut().skip(no_of_scopes) {
for (_, mut sdef) in scope.strategy.iter_mut() {
sdef.inc_no_of_scopes();
}
}
}
context.stack_tracer.borrow_mut().pop_on_success();
} else {
context.stack_tracer.borrow_mut().pop_on_failure();
......@@ -130,28 +112,12 @@ impl StrategyDef {
} else {
context.stack_tracer.borrow_mut().push(name);
let popped_scopes = context.scopes.borrow_mut().split_off(no_of_scopes);
context.push_overlay();
let result = body.eval(context, current);
let empty_overlay = context.scopes.borrow().last().expect("Where did my overlay go?").term.is_empty();
if result.is_ok() && empty_overlay {
context.apply_overlay();
} else if result.is_err() {
context.drop_overlay();
}
context
.scopes
.borrow_mut()
.extend_from_slice(&popped_scopes);
if result.is_ok() {
// we're leaving an extra scope on the stack, so now we need to fix up the
// no_of_scopes numbers of everything else :(
if !empty_overlay {
for mut scope in context.scopes.borrow_mut().iter_mut().skip(no_of_scopes) {
for (_, mut sdef) in scope.strategy.iter_mut() {
sdef.inc_no_of_scopes();
}
}
}
context.stack_tracer.borrow_mut().pop_on_success();
} else {
context.stack_tracer.borrow_mut().pop_on_failure();
......@@ -212,18 +178,6 @@ impl StrategyDef {
} => format!("{}.{}", argument_of, argument_no),
}
}
fn inc_no_of_scopes(&mut self) {
match *self {
StrategyDef::Predefined { no_of_scopes: None, .. } => {},
StrategyDef::Predefined { no_of_scopes: Some(ref mut n), .. } => {
*n += 1;
},
StrategyDef::Anonymous { ref mut no_of_scopes, .. } => {
*no_of_scopes += 1;
}
}
}
}
impl TryFrom<ctree::Def> for StrategyDef {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment