Commit 79793932 authored by Jeff Smits's avatar Jeff Smits

Revert "Reproducing the strange non-backtracking behaviour of strj/strc"

This reverts commit 6d2973a1.
parent cf9368c6
Specification([Signature([Constructors([ExtOpDecl("Nil",ConstType(Sort("List",[SortVar("a")])))])]),Strategies([SDefT("main_0_0",[],[],Scope(["b_0"],GuardedLChoice(Seq(Build(Anno(Int("1"),Op("Nil",[]))),Seq(Match(Var("b_0")),Fail)),Id,Seq(CallT(SVar("try_1_0"),[Fail],[]),Seq(Build(Var("b_0")),Seq(CallT(SVar("debug_1_0"),[Build(Anno(Str("c is still bound: "),Op("Nil",[])))],[]),Seq(Build(Anno(Int("2"),Op("Nil",[]))),Seq(Match(Var("b_0")),Seq(CallT(SVar("debug_1_0"),[Build(Anno(Str("But we can rebind it once: "),Op("Nil",[])))],[]),Seq(Build(Anno(Int("3"),Op("Nil",[]))),Seq(CallT(SVar("debug_1_0"),[Build(Anno(Str("Second time it matches again, so here is where we fail: "),Op("Nil",[])))],[]),Match(Var("b_0"))))))))))))),ExtSDef("debug_1_0",[VarDec("o_13",FunType([ConstType(Sort("ATerm",[]))],ConstType(Sort("ATerm",[]))))],[]),ExtSDef("try_1_0",[VarDec("w_22",FunType([ConstType(Sort("ATerm",[]))],ConstType(Sort("ATerm",[]))))],[])])])
\ No newline at end of file
module observable_non_backtracking
imports libstratego-lib
strategies
main = !1;?c;fail <+ try(fail;?c);!c;debug(!"c is still bound: ");!2;?c;debug(!"But we can rebind it once: ");!3;debug(!"Second time it matches again, so here is where we fail: ");?c
......@@ -4,7 +4,7 @@ use preprocess::{Def, StrategyDef};
use primitives::{Primitives, eval_prim_ref};
use primitives::ssl::State;
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::fmt;
use std::borrow::Borrow;
use std::cell::RefCell;
......@@ -13,7 +13,7 @@ use std::cell::RefCell;
/// This context is internally mutable in `RefCell` fields. This is just for convenience as we don't
/// want to pass around the mutable fields separately. But the internal mutability is not a hidden
/// thing, there is observable effect, so the name of the context includes `Mut`.
pub struct MutContext<'d, 'f: 'd> {
pub struct MutContext<'d, 'f : 'd> {
pub stack_tracer: RefCell<StackTracer>,
pub scopes: RefCell<Vec<Scope<'d, ATermRef>>>,
pub factory: &'f ATermFactory,
......@@ -21,7 +21,7 @@ pub struct MutContext<'d, 'f: 'd> {
pub ssl_state: RefCell<State>,
}
impl<'d, 'f: 'd> MutContext<'d, 'f> {
impl<'d, 'f : 'd> MutContext<'d, 'f> {
pub fn new(
factory: &'f ATermFactory,
scopes: Vec<Scope<'d, ATermRef>>,
......@@ -59,6 +59,7 @@ impl<'d, 'f: 'd> MutContext<'d, 'f> {
result
}
// Should really return a &SDef, but I can't figure out lifetimes that borrowck will accept :(
pub fn get_strategy(&self, strat_name: &str) -> Result<StrategyDef<'d>> {
self.scopes
.borrow()
......@@ -70,8 +71,12 @@ impl<'d, 'f: 'd> MutContext<'d, 'f> {
.ok_or_else(|| Error::UndefinedStrategy(strat_name.to_owned()))
}
fn get_term_option(&self, term_name: &str) -> Result<Option<ATermRef>> {
Scopes::get_term_option(&self.scopes.borrow(), term_name)
}
pub fn get_term(&self, term_name: &str) -> Result<ATermRef> {
Scopes::get_term_option_ignore_invalidation(&self.scopes.borrow(), term_name).and_then(|o| {
self.get_term_option(term_name).and_then(|o| {
o.ok_or(Error::StrategyFailed)
})
}
......@@ -88,7 +93,7 @@ impl<'d, 'f: 'd> MutContext<'d, 'f> {
let overlay = Scope {
term: HashMap::new(),
strategy: HashMap::new(),
kind: ScopeKind::Overlay,
is_overlay: true,
};
self.push_scope(overlay);
......@@ -121,8 +126,8 @@ impl<'d, 'f: 'd> MutContext<'d, 'f> {
"apply_overlay: Interpreter bug, unexpected end of stack",
);
debug_assert!(
scope.kind == ScopeKind::Overlay,
"apply_overlay: Interpreter bug, unexpected non-overlay scope"
scope.is_overlay,
"apply_overlay: Interpreter bug, unexpected normal scope"
);
self._apply_overlay(scope);
}
......@@ -132,30 +137,17 @@ impl<'d, 'f: 'd> MutContext<'d, 'f> {
"drop_overlay: Interpreter bug, unexpected end of stack",
);
debug_assert!(
popped_scope.kind != ScopeKind::Normal,
popped_scope.is_overlay,
"drop_overlay: Interpreter bug, unexpected normal scope"
);
}
pub fn invalidate_overlay(&self) {
let mut scopes = self.scopes.borrow_mut();
let mut last_scope_ref = scopes.last_mut().expect(
"invalidate_overlay: Interpreter bug, unexpected end of stack",
);
debug_assert!(
last_scope_ref.kind == ScopeKind::Overlay,
"invalidate_overlay: Interpreter bug, unexpected non-overlay scope"
);
last_scope_ref.kind =
ScopeKind::InvalidatedOverlay(last_scope_ref.term.keys().cloned().collect());
}
pub fn pop_scope(&self) {
let scope = self.scopes.borrow_mut().pop().expect(
"pop_scope: Interpreter bug, unexpected end of stack",
);
debug_assert!(
scope.kind == ScopeKind::Normal,
!scope.is_overlay,
"pop_scope: Interpreter bug, unexpected overlay"
);
}
......@@ -201,24 +193,11 @@ impl fmt::Display for StackTracer {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum ScopeKind {
Normal,
Overlay,
InvalidatedOverlay(HashSet<String>),
}
impl Default for ScopeKind {
fn default() -> Self {
ScopeKind::Normal
}
}
#[derive(Debug, Default, Clone)]
pub struct Scope<'a, ATerm> {
pub term: HashMap<String, Option<ATerm>>,
pub strategy: HashMap<String, StrategyDef<'a>>,
kind: ScopeKind,
is_overlay: bool,
}
impl<'a, ATerm> Scope<'a, ATerm> {
......@@ -230,7 +209,7 @@ impl<'a, ATerm> Scope<'a, ATerm> {
Scope {
term: terms.into_iter().map(|(n, a)| (n, Some(a))).collect(),
strategy: defs.into_iter().collect(),
kind: ScopeKind::Normal,
is_overlay: false,
}
}
......@@ -243,25 +222,20 @@ impl<'a, ATerm> Scope<'a, ATerm> {
strategy: defs.into_iter()
.map(|def| (def.name.clone(), StrategyDef::from_def(def)))
.collect(),
kind: ScopeKind::Normal,
is_overlay: false,
}
}
pub fn from_let_defs<I>(no_of_scopes: usize, defs: I) -> Self
where
I: IntoIterator<Item = &'a Def>,
I: IntoIterator<Item=&'a Def>,
{
Scope {
term: HashMap::default(),
strategy: defs.into_iter()
.map(|def| {
(
def.name.clone(),
StrategyDef::from_let_def(def, no_of_scopes),
)
})
.map(|def| (def.name.clone(), StrategyDef::from_let_def(def, no_of_scopes)))
.collect(),
kind: ScopeKind::Normal,
is_overlay: false,
}
}
......@@ -280,7 +254,7 @@ impl<'a, ATerm> Scope<'a, ATerm> {
result
},
strategy: HashMap::default(),
kind: ScopeKind::Normal,
is_overlay: false,
}
}
}
......@@ -289,32 +263,13 @@ impl<'a, ATerm> Scope<'a, ATerm> {
pub mod Scopes {
use super::*;
pub fn get_term_option_ignore_invalidation(
vec: &Vec<Scope<ATermRef>>,
term_name: &str,
) -> Result<Option<ATermRef>> {
vec.iter()
.rev()
.flat_map(|scope| scope.term.get(term_name))
.cloned()
.next()
.ok_or_else(|| Error::UndefinedVariable(term_name.to_owned()))
}
pub fn get_term_option(
vec: &Vec<Scope<ATermRef>>,
term_name: &str,
) -> Result<Option<ATermRef>> {
vec.iter()
.rev()
.flat_map(|scope| {
if let ScopeKind::InvalidatedOverlay(ref set) = scope.kind {
if set.contains(term_name) {
return None;
}
}
scope.term.get(term_name)
})
.flat_map(|scope| scope.term.get(term_name))
.cloned()
.next()
.ok_or_else(|| Error::UndefinedVariable(term_name.to_owned()))
......@@ -336,37 +291,21 @@ pub mod Scopes {
}
None => {
for mut scope in scopes.iter_mut().rev() {
let condition = match scope.kind {
ScopeKind::Normal => scope.term.contains_key(term_name),
ScopeKind::Overlay => true,
ScopeKind::InvalidatedOverlay(ref set) => set.contains(term_name),
};
if condition {
let insert_result = scope.term.insert(
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()),
);
debug_assert!(
match scope.kind {
ScopeKind::Normal => insert_result == Some(None),
ScopeKind::Overlay => insert_result == None,
ScopeKind::InvalidatedOverlay(_) => {
match insert_result {
Some(Some(_)) => true,
_ => false,
}
}
},
"match_term: Interpreter bug, unexpected binding to term_name in scope"
);
if let ScopeKind::InvalidatedOverlay(ref mut set) = scope.kind {
let remove_result = set.remove(term_name);
debug_assert!(
remove_result == true,
"match_term: Interpreter bug, term_name was not in invalidation set"
);
)
{
unreachable!(format!(
"match_term: No scope had {}, but we just \
replaced {} when we added it?!",
term_name,
t
))
} else {
return Ok(());
}
return Ok(());
}
}
}
......
......@@ -127,7 +127,7 @@ pub trait Eval<'d, 'f> {
fn eval(&'d self, context: &MutContext<'d, 'f>, current: ATermRef) -> Result<ATermRef>;
}
impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy {
impl<'d, 'f : 'd> Eval<'d, 'f> for preprocess::Strategy {
fn eval(&'d self, context: &MutContext<'d, 'f>, current: ATermRef) -> Result<ATermRef> {
use preprocess::Strategy::*;
use context;
......@@ -210,10 +210,9 @@ impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy {
s_then.eval(context, current)
}
Err(Error::StrategyFailed) => {
context.invalidate_overlay();
let result = s_else.eval(context, current);
context.apply_overlay();
result
// TODO: pull off the overlay, apply it after the s_else branch, but only where the s_else branch left variables unbound. This is the semantics that strc and strj use.
context.drop_overlay();
s_else.eval(context, current)
}
Err(e) => {
context.drop_overlay();
......@@ -254,7 +253,7 @@ impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy {
}
}
fn eval_match<'d, 'f: 'd>(
fn eval_match<'d, 'f : 'd>(
context: &MutContext<'d, 'f>,
match_term: &preprocess::MatchTerm,
current: &ATermRef,
......@@ -372,7 +371,7 @@ fn eval_match<'d, 'f: 'd>(
}
}
fn eval_some<'d, 'f: 'd>(
fn eval_some<'d, 'f : 'd>(
strat: &'d preprocess::Strategy,
context: &MutContext<'d, 'f>,
current: ATermRef,
......@@ -406,7 +405,7 @@ fn eval_some<'d, 'f: 'd>(
}
}
fn eval_one<'d, 'f: 'd>(
fn eval_one<'d, 'f : 'd>(
strat: &'d preprocess::Strategy,
context: &MutContext<'d, 'f>,
current: ATermRef,
......@@ -440,7 +439,7 @@ fn eval_one<'d, 'f: 'd>(
}
}
fn eval_all<'d, 'f: 'd>(
fn eval_all<'d, 'f : 'd>(
strat: &'d preprocess::Strategy,
context: &MutContext<'d, 'f>,
current: ATermRef,
......@@ -474,7 +473,7 @@ fn eval_all<'d, 'f: 'd>(
}
}
fn one_rec<'d, 'f: 'd>(
fn one_rec<'d, 'f : 'd>(
r: &Box<[ATermRef]>,
strat: &'d preprocess::Strategy,
context: &MutContext<'d, 'f>,
......@@ -499,7 +498,7 @@ fn one_rec<'d, 'f: 'd>(
}
}
fn some_rec<'d, 'f: 'd>(
fn some_rec<'d, 'f : 'd>(
r: &Box<[ATermRef]>,
strat: &'d preprocess::Strategy,
context: &MutContext<'d, 'f>,
......@@ -521,7 +520,7 @@ fn some_rec<'d, 'f: 'd>(
}
}
fn all_rec<'d, 'f: 'd>(
fn all_rec<'d, 'f : 'd>(
r: &Box<[ATermRef]>,
strat: &'d preprocess::Strategy,
context: &MutContext<'d, 'f>,
......@@ -533,7 +532,7 @@ fn all_rec<'d, 'f: 'd>(
.map(Vec::into_boxed_slice)
}
pub fn eval_sdef<'d, 'f: 'd>(
pub fn eval_sdef<'d, 'f : 'd>(
strategy_def: &StrategyDef<'d>,
context: &MutContext<'d, 'f>,
actual_sargs: Vec<StrategyDef<'d>>,
......@@ -541,7 +540,11 @@ pub fn eval_sdef<'d, 'f: 'd>(
current: ATermRef,
) -> Result<ATermRef> {
let name = strategy_def.name();
if !strategy_def.matching_counts(actual_sargs.len(), actual_targs.len()) {
if !strategy_def.matching_counts(
actual_sargs.len(),
actual_targs.len(),
)
{
Err(Error::UndefinedStrategy(name))
} else {
context.stack_tracer.borrow_mut().push(name);
......@@ -567,7 +570,7 @@ pub fn eval_sdef<'d, 'f: 'd>(
}
}
pub fn strategy_def_from_strategy<'d, 'f: 'd>(
pub fn strategy_def_from_strategy<'d, 'f : 'd>(
context: &MutContext<'d, 'f>,
name: &str,
number: usize,
......
......@@ -30,7 +30,10 @@ pub fn preprocess<'a>(program: ctree::Module) -> Result<Vec<Def>> {
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum StrategyDef<'a> {
TopLevel(&'a Def),
Predefined { def: &'a Def, no_of_scopes: usize },
Predefined {
def: &'a Def,
no_of_scopes: usize,
},
Anonymous {
argument_of: String,
argument_no: usize,
......@@ -50,12 +53,12 @@ impl<'a> StrategyDef<'a> {
pub fn matching_counts(&self, c_sargs: usize, c_targs: usize) -> bool {
match *self {
StrategyDef::TopLevel(ref def) => {
def.sargs.len() == c_sargs && def.targs.len() == c_targs
}
StrategyDef::Predefined { def, .. } => {
def.sargs.len() == c_sargs && def.targs.len() == c_targs
}
StrategyDef::TopLevel(ref def) =>
def.sargs.len() == c_sargs && def.targs.len() == c_targs,
StrategyDef::Predefined {
def,
..
} => def.sargs.len() == c_sargs && def.targs.len() == c_targs,
StrategyDef::Anonymous { .. } => c_sargs == 0 && c_targs == 0,
}
}
......@@ -72,7 +75,10 @@ impl<'a> StrategyDef<'a> {
def.sargs.iter().cloned().zip(actual_sargs),
)
}
StrategyDef::Predefined { def, .. } => {
StrategyDef::Predefined {
def,
..
} => {
Scope::new(
def.targs.iter().cloned().zip(actual_targs),
def.sargs.iter().cloned().zip(actual_sargs),
......@@ -123,7 +129,7 @@ impl TryFrom<ctree::Def> for Def {
body.try_into().map(|body| {
Def {
name: name,
sargs: sargs.into_iter().map(|vardec| vardec.0).collect(),
sargs: sargs.into_iter().map( | vardec| vardec.0).collect(),
targs: targs.into_iter().map(|vardec| vardec.0).collect(),
body: body,
}
......@@ -288,11 +294,11 @@ impl TryFrom<ctree::PreTerm> for BuildTerm {
}
impl BuildTerm {
pub fn build<'d, 'f: 'd>(&self, context: &MutContext<'d, 'f>) -> Result<ATermRef> {
pub fn build<'d, 'f : 'd>(&self, context: &MutContext<'d, 'f>) -> Result<ATermRef> {
self.build_with_annos(context, None)
}
fn build_with_annos<'d, 'f: 'd>(
fn build_with_annos<'d, 'f : 'd>(
&self,
context: &MutContext<'d, 'f>,
annos: Option<Vec<ATermRef>>,
......@@ -402,10 +408,7 @@ impl BuildTerm {
}
/// Lifts `build` over a vector
fn build_vec<'d, 'f: 'd>(
context: &MutContext<'d, 'f>,
vec: &[BuildTerm],
) -> Result<Vec<ATermRef>> {
fn build_vec<'d, 'f : 'd>(context: &MutContext<'d, 'f>, vec: &[BuildTerm]) -> Result<Vec<ATermRef>> {
vec.into_iter().map(|t| t.build(context)).collect()
}
......@@ -487,7 +490,7 @@ impl TryFrom<ctree::PreTerm> for MatchTerm {
}
pub fn try_into_vec<T1, T2: TryFrom<T1>, I: IntoIterator<Item = T1>>(
pub fn try_into_vec<T1, T2: TryFrom<T1>, I: IntoIterator<Item=T1>>(
v: I,
) -> result::Result<Vec<T2>, <T2 as TryFrom<T1>>::Err> {
v.into_iter()
......
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