Commit 4845c86c by Jeff Smits

Moved build_aterm back to interpreter.rs. Added Cached BuildTerm variant, using it is still TODO

parent 8689c23e
......@@ -151,7 +151,7 @@ impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy<'f> {
.collect::<Result<_>>()?;
let targs = targs
.into_iter()
.map(|build_term| build_term.build(context))
.map(|term| build_term::build(term, context))
.collect::<Result<_>>()?;
eval_sdef(&sdeft, context, sargs, targs, current)
}
......@@ -174,7 +174,7 @@ impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy<'f> {
.collect::<Result<_>>()?;
let targs = targs
.into_iter()
.map(|build_term| build_term.build(context))
.map(|term| build_term::build(term, context))
.collect::<Result<_>>()?;
eval_sdef(&sdeft, context, sargs, targs, current)
}
......@@ -193,7 +193,7 @@ impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy<'f> {
}
}
}
Build(ref term) => term.build(context),
Build(ref term) => build_term::build(term, context),
Scope(ref fresh_names, ref body) => {
context.push_scope(context::Scope::from_fresh_variables(
fresh_names.iter().cloned(),
......@@ -247,7 +247,7 @@ impl<'d, 'f: 'd> Eval<'d, 'f> for preprocess::Strategy<'f> {
.collect::<Result<Vec<_>>>()?;
let targs = targs
.into_iter()
.map(|build_term| build_term.build(context))
.map(|term| build_term::build(term, context))
.collect::<Result<Vec<_>>>()?;
context.call_primitive(name, &sargs, &targs, current)
}
......@@ -407,6 +407,143 @@ fn eval_match<'d, 'f: 'd>(
}
}
mod build_term {
use preprocess::BuildTerm;
use context::MutContext;
use error::{Error, Result};
use factory::ATermRef;
use aterm::BrokenF32;
use aterm::{ATerm as A, ATermFactory as ATF};
pub fn build<'d, 'f: 'd>(term: &BuildTerm<'f>, context: &MutContext<'d, 'f>) -> Result<ATermRef<'f>> {
build_with_annos(term, context, None)
}
fn build_with_annos<'d, 'f: 'd>(
term: &BuildTerm<'f>,
context: &MutContext<'d, 'f>,
annos: Option<Vec<ATermRef<'f>>>,
) -> Result<ATermRef<'f>> {
use preprocess::BuildTerm::*;
use preprocess::C;
match *term {
Var(s) => {
if let Some(annos) = annos {
let term = context.get_term(s)?;
Ok(context.factory.with_annos(term, annos))
} else {
context.get_term(s)
}
}
Int(i) => {
Ok(context.factory.with_annos(
context.factory.int(i),
annos.unwrap_or_default(),
))
}
Real(BrokenF32(f)) => {
Ok(context.factory.with_annos(
context.factory.real(f),
annos.unwrap_or_default(),
))
}
Str(s) => {
Ok(context.factory.with_annos(
context.factory.string(s),
annos.unwrap_or_default(),
))
}
Op(s, ref t) => {
let t = build_vec(context, t)?;
if s == "Cons" && t.len() == 2 {
if let ::factory::Term::List(ref tail) = t[1].term {
Ok(context.factory.cons(t[0].clone(), tail.clone()))
} else {
Err(Error::StrategyFailed)
}
} else if s == "Nil" && t.is_empty() {
Ok(context.factory.nil())
} else {
Ok(context.factory.with_annos(
context.factory.application(
s,
t.into_iter(),
),
annos.unwrap_or_default(),
))
}
}
Explode(ref cons, ref children) => {
let cons = build(cons, context)?;
let children = build(children, context)?;
let children = children.get_list().ok_or(Error::UnknownBehaviour(
"Non-list in build of explode pattern (#) second argument",
))?;
use factory::Term::*;
use ctree::string_unescape;
match cons.term {
Application(_, _) => return Err(Error::StrategyFailed),
Placeholder(_, _) => {
return Err(Error::UnknownBehaviour(
"ATerm placeholder in build of explode pattern (#) first argument",
))
}
Blob(_) => {
return Err(Error::UnknownBehaviour(
"Blob in build of explode pattern (#) first argument",
))
}
List(_) => return Ok(context.factory.list(children.iter().cloned())),
String(s) => {
let result = if s.starts_with('"') {
Ok(context.factory.string(string_unescape(s)))
} else {
let application =
context.factory.application(s, children.iter().cloned());
Ok(context.factory.with_annos(
application,
annos.unwrap_or_default(),
))
};
return result;
}
Int(_) | Long(_) | Real(_) => {}
}
Ok(cons)
}
// NOTE: `str '!((1{2}){3})'` gives `1{2}`, so the innermost `annos` list in a build is
// used! Therefore we just shadow the input `annos` with the annotations in this `Anno`
Anno(ref term, ref annos) => {
let annos: ATermRef<'f> = build(&**annos, context)?;
if let Some(annos_vec) = annos.get_list() {
build_with_annos(term, context, Some(annos_vec.to_vec()))
} else {
build_with_annos(term, context, Some(vec![annos.clone()]))
}
}
Cached(C(ref cache), ref term) => {
if let Option::Some(ref cached_term) = *cache.borrow() {
Ok(cached_term.clone())
} else {
let result = build_with_annos(term, context, annos)?;
*cache.borrow_mut() = Some(result.clone());
Ok(result)
}
}
}
}
/// Lifts `build` over a vector
fn build_vec<'d, 'f: 'd>(context: &MutContext<'d, 'f>, vec: &[BuildTerm<'f>]) -> Result<Vec<ATermRef<'f>>> {
vec.into_iter().map(|t| build(t, context)).collect()
}
}
fn eval_<'d, 'f: 'd, F1, F2>(
strat: &'d preprocess::Strategy<'f>,
context: &MutContext<'d, 'f>,
......
use context::{MutContext, Scope};
use context::Scope;
use ctree;
use error::{Result, Error};
use factory::ATermRef;
use aterm::BrokenF32;
use aterm::{ATerm as A, ATermFactory as ATF};
use try_from::{TryInto, TryFrom};
......@@ -12,6 +11,7 @@ use fnv::FnvHashMap;
use std::result;
use std::rc::Rc;
use std::cell::RefCell;
pub fn preprocess(program: ctree::Module) -> Result<Vec<Def>> {
let decls = match program {
......@@ -331,6 +331,14 @@ pub enum BuildTerm<'a> {
Str(&'a str),
Op(&'a str, Vec<BuildTerm<'a>>),
Explode(Box<BuildTerm<'a>>, Box<BuildTerm<'a>>),
Cached(C<'a>, Box<BuildTerm<'a>>),
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct C<'a>(pub RefCell<Option<ATermRef<'a>>>);
impl<'a> ::std::hash::Hash for C<'a> {
fn hash<H: ::std::hash::Hasher>(&self, _state: &mut H) {}
}
impl<'a> TryFrom<ctree::Term<'a>> for BuildTerm<'a> {
......@@ -391,124 +399,6 @@ impl<'a> TryFrom<ctree::PreTerm<'a>> for BuildTerm<'a> {
}
}
impl<'d, 'f: 'd> BuildTerm<'f> {
pub fn build(&self, context: &MutContext<'d, 'f>) -> Result<ATermRef<'f>> {
self.build_with_annos(context, None)
}
fn build_with_annos(
&self,
context: &MutContext<'d, 'f>,
annos: Option<Vec<ATermRef<'f>>>,
) -> Result<ATermRef<'f>> {
use self::BuildTerm::*;
match *self {
Var(s) => {
if let Some(annos) = annos {
let term = context.get_term(s)?;
Ok(context.factory.with_annos(term, annos))
} else {
context.get_term(s)
}
}
Int(i) => {
Ok(context.factory.with_annos(
context.factory.int(i),
annos.unwrap_or_default(),
))
}
Real(BrokenF32(f)) => {
Ok(context.factory.with_annos(
context.factory.real(f),
annos.unwrap_or_default(),
))
}
Str(s) => {
Ok(context.factory.with_annos(
context.factory.string(s),
annos.unwrap_or_default(),
))
}
Op(s, ref t) => {
let t = Self::build_vec(context, t)?;
if s == "Cons" && t.len() == 2 {
if let ::factory::Term::List(ref tail) = t[1].term {
Ok(context.factory.cons(t[0].clone(), tail.clone()))
} else {
Err(Error::StrategyFailed)
}
} else if s == "Nil" && t.is_empty() {
Ok(context.factory.nil())
} else {
Ok(context.factory.with_annos(
context.factory.application(
s,
t.into_iter(),
),
annos.unwrap_or_default(),
))
}
}
Explode(ref cons, ref children) => {
let cons = cons.build(context)?;
let children = children.build(context)?;
let children = children.get_list().ok_or(Error::UnknownBehaviour(
"Non-list in build of explode pattern (#) second argument",
))?;
use factory::Term::*;
use ctree::string_unescape;
match cons.term {
Application(_, _) => return Err(Error::StrategyFailed),
Placeholder(_, _) => {
return Err(Error::UnknownBehaviour(
"ATerm placeholder in build of explode pattern (#) first argument",
))
}
Blob(_) => {
return Err(Error::UnknownBehaviour(
"Blob in build of explode pattern (#) first argument",
))
}
List(_) => return Ok(context.factory.list(children.iter().cloned())),
String(s) => {
let result = if s.starts_with('"') {
Ok(context.factory.string(string_unescape(s)))
} else {
let application =
context.factory.application(s, children.iter().cloned());
Ok(context.factory.with_annos(
application,
annos.unwrap_or_default(),
))
};
return result;
}
Int(_) | Long(_) | Real(_) => {}
}
Ok(cons)
}
// NOTE: `str '!((1{2}){3})'` gives `1{2}`, so the innermost `annos` list in a build is
// used! Therefore we just shadow the input `annos` with the annotations in this `Anno`
Anno(ref term, ref annos) => {
let annos: ATermRef<'f> = (**annos).build(context)?;
if let Some(annos_vec) = annos.get_list() {
term.build_with_annos(context, Some(annos_vec.to_vec()))
} else {
term.build_with_annos(context, Some(vec![annos.clone()]))
}
}
}
}
/// Lifts `build` over a vector
fn build_vec(context: &MutContext<'d, 'f>, vec: &[BuildTerm<'f>]) -> Result<Vec<ATermRef<'f>>> {
vec.into_iter().map(|t| t.build(context)).collect()
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum MatchTerm<'a> {
Var(&'a str),
......
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