Commit ece6ac74 authored by Jeff Smits's avatar Jeff Smits

WIP: preprocessing CTree type to intermediate one which is easier to interpret

parent 3a88bd70
use types::{Result, Error};
use aterm::ATermFactory;
use std::collections::HashMap;
use std::fmt;
use std::borrow::Borrow;
use std::marker::PhantomData;
use preprocess::SDefT;
#[derive(Debug, Clone)]
pub struct Context<'a, B, F, A>
where F: 'a + ATermFactory<'a, B, ATermRef = A>,
A: Borrow<<F as ATermFactory<'a, B>>::ATerm> + Clone,
B: 'a
{
pub stacktracer: StackTracer,
pub factory: &'a F,
pub primitives: HashMap<String, Primitive>,
pub scopes: Vec<Scope<A>>,
b: PhantomData<B>,
}
impl<'a, B, F, A> Context<'a, B, F, A>
where F: 'a + ATermFactory<'a, B, ATermRef = A>,
A: Borrow<<F as ATermFactory<'a, B>>::ATerm> + Clone,
B: 'a
{
pub fn new(factory: &'a F, global_scope: Scope<A>) -> Context<'a, B, F, A> {
Context {
stacktracer: StackTracer::default(),
factory: factory,
primitives: HashMap::new(),
scopes: vec![global_scope],
b: PhantomData,
}
}
pub fn get_strategy(&self, strat_name: &str) -> Result<SDefT> {
self.scopes
.iter()
.rev()
.flat_map(|scope| scope.strategy.get(strat_name))
.cloned()
.next()
.ok_or(Error::UndefinedStrategy(strat_name.to_owned()))
}
pub fn get_term(&self, strat_name: &str) -> Result<A> {
self.scopes
.iter()
.rev()
.flat_map(|scope| scope.term.get(strat_name))
.cloned()
.next()
.ok_or(Error::UndefinedVariable(strat_name.to_owned()))
}
}
#[derive(Debug, Default, Clone)]
pub struct StackTracer {
stack: Vec<String>,
failure_depth: usize,
}
impl StackTracer {
pub fn push(&mut self, str: String) {
self.stack.push(str);
self.failure_depth = self.stack.len() - 1;
}
pub fn pop_on_failure(&mut self) -> Option<String> {
self.stack.pop()
}
pub fn pop_on_success(&mut self) -> Option<String> {
self.failure_depth = self.stack.len() - 2;
self.stack.pop()
}
}
impl fmt::Display for StackTracer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (n, name) in self.stack.iter().enumerate() {
if n == self.failure_depth {
writeln!(f, "{} <==", name)?;
} else {
writeln!(f, "{}", name)?;
}
}
Ok(())
}
}
#[derive(Debug, Default, Clone)]
pub struct Scope<ATerm> {
pub term: HashMap<String, ATerm>,
pub strategy: HashMap<String, SDefT>,
}
impl<ATerm> Scope<ATerm> {
pub fn from_sdefts<I>(sdefts: I) -> Scope<ATerm>
where I: Iterator<Item = SDefT>
{
Scope {
term: HashMap::default(),
strategy: sdefts.map(|sdeft| (sdeft.c_name(), sdeft)).collect(),
}
}
}
pub type Primitive = ();
\ No newline at end of file
......@@ -7,7 +7,7 @@ use std::convert::TryInto;
use std::borrow::Borrow;
use types::{Error, ctree_validation_error};
use types::Error;
/// ```
/// ModName = {ModNamePart "/"}+
......@@ -50,7 +50,7 @@ impl<'a, A> TryFrom<&'a A> for Module
_ => {}
}
}
Err(ctree_validation_error("Module"))
Err(Error::CTreeParse("Module"))
}
}
......@@ -87,7 +87,7 @@ impl<'a, A> TryFrom<&'a A> for Decl
_ => {}
}
}
Err(ctree_validation_error("Decl"))
Err(Error::CTreeParse("Decl"))
}
}
......@@ -118,7 +118,7 @@ impl<'a, A> TryFrom<&'a A> for ImportModName
_ => {}
}
}
Err(ctree_validation_error("ImportModName"))
Err(Error::CTreeParse("ImportModName"))
}
}
......@@ -149,7 +149,7 @@ impl<'a, A> TryFrom<&'a A> for SDecl
_ => {}
}
}
Err(ctree_validation_error("SDecl"))
Err(Error::CTreeParse("SDecl"))
}
}
......@@ -187,7 +187,7 @@ impl<'a, A> TryFrom<&'a A> for Sort
_ => {}
}
}
Err(ctree_validation_error("Sort"))
Err(Error::CTreeParse("Sort"))
}
}
......@@ -246,7 +246,7 @@ impl<'a, A> TryFrom<&'a A> for OpDecl
_ => {}
}
}
Err(ctree_validation_error("OpDecl"))
Err(Error::CTreeParse("OpDecl"))
}
}
......@@ -269,7 +269,7 @@ impl<'a, A> TryFrom<&'a A> for ConstType
_ => {}
}
}
Err(ctree_validation_error("ConstType"))
Err(Error::CTreeParse("ConstType"))
}
}
......@@ -304,7 +304,7 @@ impl<'a, A> TryFrom<&'a A> for Type
_ => {}
}
}
Err(ctree_validation_error("Type"))
Err(Error::CTreeParse("Type"))
}
}
......@@ -365,7 +365,7 @@ impl<'a, A> TryFrom<&'a A> for Def
_ => {}
}
}
Err(ctree_validation_error("Def"))
Err(Error::CTreeParse("Def"))
}
}
......@@ -389,7 +389,7 @@ impl<'a, A> TryFrom<&'a A> for SVar
_ => {}
}
}
Err(ctree_validation_error("SVar"))
Err(Error::CTreeParse("SVar"))
}
}
......@@ -449,7 +449,7 @@ impl<'a, A> TryFrom<&'a A> for StrategyDef
_ => {}
}
}
Err(ctree_validation_error("StrategyDef"))
Err(Error::CTreeParse("StrategyDef"))
}
}
......@@ -486,7 +486,7 @@ impl<'a, A> TryFrom<&'a A> for Anno
_ => {}
}
}
Err(ctree_validation_error("Anno"))
Err(Error::CTreeParse("Anno"))
}
}
......@@ -511,7 +511,7 @@ impl<'a, A> TryFrom<&'a A> for VarDec
_ => {}
}
}
Err(ctree_validation_error("TypedId"))
Err(Error::CTreeParse("TypedId"))
}
}
......@@ -659,7 +659,7 @@ impl<'a, A> TryFrom<&'a A> for Strategy
_ => {}
}
}
Err(ctree_validation_error("Strategy"))
Err(Error::CTreeParse("Strategy"))
}
}
......@@ -683,7 +683,7 @@ impl<'a, A> TryFrom<&'a A> for Var
_ => {}
}
}
Err(ctree_validation_error("Var"))
Err(Error::CTreeParse("Var"))
}
}
......@@ -729,7 +729,7 @@ impl<'a, A> TryFrom<&'a A> for Term
_ => {}
}
}
Err(ctree_validation_error("Term"))
Err(Error::CTreeParse("Term"))
}
}
......@@ -770,7 +770,7 @@ impl<'a, A> TryFrom<&'a A> for PreTerm
let str = match_string(&r[0])?;
return str.parse()
.map(PreTerm::Int)
.map_err(|_| ctree_validation_error("int"));
.map_err(|_| Error::CTreeParse("int"));
}
}
"Real" => {
......@@ -778,7 +778,7 @@ impl<'a, A> TryFrom<&'a A> for PreTerm
let str = match_string(&r[0])?;
return str.parse()
.map(|f32| PreTerm::Real(BrokenF32(f32)))
.map_err(|_| ctree_validation_error("real"));
.map_err(|_| Error::CTreeParse("real"));
}
}
"Str" => {
......@@ -813,7 +813,7 @@ impl<'a, A> TryFrom<&'a A> for PreTerm
_ => {}
}
}
Err(ctree_validation_error("PreTerm"))
Err(Error::CTreeParse("PreTerm"))
}
}
......@@ -826,7 +826,7 @@ fn match_string<A, R>(r: &R) -> Result<String, Error>
return Ok(string_unescape(str));
}
}
Err(ctree_validation_error("string"))
Err(Error::CTreeParse("string"))
}
fn match_strings<A, R>(r: &R) -> Result<Vec<String>, Error>
......@@ -838,7 +838,7 @@ fn match_strings<A, R>(r: &R) -> Result<Vec<String>, Error>
.map(match_string)
.collect::<Result<Vec<String>, Error>>();
}
Err(ctree_validation_error("list"))
Err(Error::CTreeParse("list"))
}
fn match_list<'a, A, R, T>(r: &'a R) -> Result<Vec<T>, Error>
......@@ -851,7 +851,7 @@ fn match_list<'a, A, R, T>(r: &'a R) -> Result<Vec<T>, Error>
.map(|a| a.borrow().try_into())
.collect::<Result<Vec<T>, Error>>();
}
Err(ctree_validation_error("list"))
Err(Error::CTreeParse("list"))
}
fn match_<'a, A, R, T>(r: &'a R) -> Result<T, Error>
......
This diff is collapsed.
......@@ -20,6 +20,8 @@ use interpreter::interpret_main;
mod types;
mod interpreter;
mod ctree;
mod context;
mod preprocess;
macro_rules! eprintln {
($($tt:tt)*) => {{
......
use types::{Result, Error};
use aterm::ATermFactory;
use ctree;
use std::convert::TryInto;
use std::convert::TryFrom;
use std::result;
use std::borrow::Borrow;
use interpreter::Eval;
use context::{Context, Scope};
pub fn preprocess<'a, B, F, A>(program: ctree::Module) -> Result<Scope<<F as ATermFactory<'a, B>>::ATermRef>> where F: 'a + ATermFactory<'a, B, ATermRef = A>,
A: Borrow<<F as ATermFactory<'a, B>>::ATerm> + Clone,
B: 'a
{
let decls = match program {
ctree::Module::Module(_, decls) => decls,
ctree::Module::Specification(decls) => decls,
};
let defs = decls
.into_iter()
.flat_map(|decl| match decl {
ctree::Decl::Strategies(defs) => defs.into_iter(),
_ => Vec::new().into_iter(),
})
.filter_map(|def| {
match def.try_into() {
Ok(sdeft) => Some(Ok(sdeft)),
Err(Some(e)) => Some(Err(e)),
Err(None) => None,
}
})
.collect::<Result<Vec<SDefT>>>()?;
Ok(Scope::from_sdefts(defs.into_iter()))
}
#[derive(Debug, Clone)]
pub struct SDefT {
name: ctree::Id,
sargs: Vec<ctree::Id>,
targs: Vec<ctree::Id>,
body: Strategy,
}
impl SDefT {
pub fn c_name(&self) -> String {
let name = self.name.replace('_', "__");
let name = name.replace('-', "_");
let name = name.replace('\'', "_p_");
let name = name.replace('"', "_q_");
let name = name.replace('\\', "_b_");
format!("{}_{}_{}", name, self.sargs.len(), self.targs.len())
}
pub fn eval<'a, B, F, A>(&self,
context: &mut Context<'a, B, F, A>,
sargs: Vec<SDefT>,
targs: Vec<A>,
current: A)
-> Result<A>
where F: 'a + ATermFactory<'a, B, ATermRef = A>,
A: Borrow<<F as ATermFactory<'a, B>>::ATerm> + Clone,
B: 'a
{
if sargs.len() != self.sargs.len() || targs.len() != self.targs.len() {
Err(Error::UndefinedStrategy(self.c_name()))
} else {
context
.scopes
.push(Scope {
term: self.targs.iter().cloned().zip(targs).collect(),
strategy: self.sargs.iter().cloned().zip(sargs).collect(),
});
self.body.eval(context, current)
}
}
}
impl TryFrom<ctree::Def> for SDefT {
type Error = Option<Error>;
fn try_from(value: ctree::Def) -> result::Result<Self, Self::Error> {
match value {
ctree::Def::SDefT(name, sargs, targs, body) => {
body.try_into().map(|body| SDefT {
name: name,
sargs: sargs.into_iter().map(|vardec| vardec.0).collect(),
targs: targs.into_iter().map(|vardec| vardec.0).collect(),
body: body,
}).map_err(Some)
}
_ => Err(None),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Strategy {
Let(Vec<ctree::Def>, Box<Strategy>),
CallT(ctree::SVar, Vec<Strategy>, Vec<BuildTerm>),
CallDynamic(BuildTerm, Vec<Strategy>, Vec<BuildTerm>),
Fail,
Id,
Match(ctree::Term),
Build(BuildTerm),
Scope(Vec<ctree::Id>, Box<Strategy>),
Seq(Box<Strategy>, Box<Strategy>),
GuardedLChoice(Box<Strategy>, Box<Strategy>, Box<Strategy>),
PrimT(String, Vec<Strategy>, Vec<BuildTerm>),
Some(Box<Strategy>),
One(Box<Strategy>),
All(Box<Strategy>),
ImportTerm(ctree::ModName),
}
impl TryFrom<ctree::Strategy> for Strategy {
type Error = Error;
fn try_from(value: ctree::Strategy) -> Result<Strategy> {
use ctree::Strategy as I;
use self::Strategy as O;
match value {
I::Let(d,s) => try_into_box(s).map(|s| O::Let(d,s)),
I::CallT(v,s,t) => {
let t = try_into_vec(t)?;
try_into_vec(s).map(|s| O::CallT(v,s,t))
},
I::CallDynamic(t1,s,t2) => {
let t1 = t1.try_into()?;
let t2 = try_into_vec(t2)?;
try_into_vec(s).map(|s| O::CallDynamic(t1,s,t2))
},
I::Fail => Ok(O::Fail),
I::Id => Ok(O::Id),
I::ProceedT(_, _) => Err(Error::CTreeParse("Unknown behaviour: ProceedT")),
I::ProceedNoArgs => Err(Error::CTreeParse("Unknown behaviour: ProceedNoArgs")),
I::Match(t) => Ok(O::Match(t)),
I::Build(t) => t.try_into().map(O::Build),
I::Scope(i,s) => try_into_box(s).map(|s| O::Scope(i,s)),
I::Seq(s1,s2) => {
let s1 = try_into_box(s1)?;
try_into_box(s2).map(|s2| O::Seq(s1,s2))
},
I::GuardedLChoice(s1,s2,s3) => {
let s1 = try_into_box(s1)?;
let s2 = try_into_box(s2)?;
try_into_box(s3).map(|s3| O::GuardedLChoice(s1,s2,s3))
},
I::PrimT(s1,s2,t) => {
let t = try_into_vec(t)?;
try_into_vec(s2).map(|s2| O::PrimT(s1,s2,t))
},
I::Some(s) => try_into_box(s).map(O::Some),
I::One(s) => try_into_box(s).map(O::One),
I::All(s) => try_into_box(s).map(O::All),
I::ImportTerm(mn) => Ok(O::ImportTerm(mn)),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum BuildTerm {
Var(ctree::Id),
Anno(Box<ctree::PreTerm>, Box<ctree::PreTerm>),
}
impl TryFrom<ctree::Term> for BuildTerm {
type Error = Error;
fn try_from(value: ctree::Term) -> Result<BuildTerm> {
use ctree::Term as I;
use self::BuildTerm as O;
match value {
I::Var(id) => Ok(O::Var(id)),
I::Anno(pt1, pt2) => Ok(O::Anno(pt1, pt2)),
I::Wld => Err(Error::CTreeParse("Match pattern in build: _")),
I::As(_, _) => Err(Error::CTreeParse("Match pattern in build: @")),
}
}
}
fn try_into_vec<T1, T2: TryFrom<T1>>(v: Vec<T1>) -> result::Result<Vec<T2>, <T2 as TryFrom<T1>>::Error> {
v.into_iter().map(TryInto::try_into).collect::<result::Result<Vec<_>, _>>()
}
fn try_into_box<T1, T2: TryFrom<T1>>(v: Box<T1>) -> result::Result<Box<T2>, <T2 as TryFrom<T1>>::Error> {
(*v).try_into().map(Box::new)
}
......@@ -15,8 +15,9 @@ pub enum Error {
Io(io::Error),
Fmt(fmt::Error),
ATermParse(aterm::parse::Error),
CTreeParse(String),
CTreeParse(&'static str),
UndefinedStrategy(String),
UndefinedVariable(String),
StrategyFailed,
UnknownBehaviour(&'static str),
}
......@@ -29,6 +30,7 @@ impl<'t> error::Error for Error {
Error::ATermParse(ref err) => err.description(),
Error::CTreeParse(_) => "couldn't parse ctree",
Error::UndefinedStrategy(_) => "couldn't find strategy",
Error::UndefinedVariable(_) => "couldn't find variable",
Error::StrategyFailed => "strategy failed",
Error::UnknownBehaviour(ref s) => "unknown behaviour",
}
......@@ -41,6 +43,7 @@ impl<'t> error::Error for Error {
Error::ATermParse(ref err) => err.cause(),
Error::CTreeParse(_) => None,
Error::UndefinedStrategy(_) => None,
Error::UndefinedVariable(_) => None,
Error::StrategyFailed => None,
Error::UnknownBehaviour(_) => None,
}
......@@ -55,6 +58,7 @@ impl<'t> fmt::Display for Error {
Error::ATermParse(ref err) => err.fmt(f),
Error::CTreeParse(ref s) => write!(f, "CTreeParseError in {}", s),
Error::UndefinedStrategy(ref s) => write!(f, "UndefinedStrategyError: {}", s),
Error::UndefinedVariable(ref s) => write!(f, "UndefinedVariableError: {}", s),
Error::StrategyFailed => write!(f, "Strategy failed"),
Error::UnknownBehaviour(ref s) => write!(f, "Unknown behaviour for {}", s),
}
......@@ -78,7 +82,3 @@ impl<'t> From<aterm::parse::Error> for Error {
Error::ATermParse(err)
}
}
pub fn ctree_validation_error(str: &str) -> Error {
Error::CTreeParse(str.to_owned())
}
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