Commit dd224f4a by Jeff Smits

Moved to ATerm lists, and everything got easier :)

parent 139d0c06
......@@ -85,7 +85,7 @@ pub fn interpret_main(
program,
libraries,
"main_0_0",
to_cons_nil_list(factory, iter::once(factory.string("main_0_0".to_owned()))),
factory.list(iter::once(factory.string("main_0_0".to_owned()))),
)
}
......@@ -278,7 +278,7 @@ fn eval_match<'a>(
Anno(ref cons, ref annos) => {
eval_match(context, &*cons, current)?;
let current_annos = b(current).as_inner().annotations.into_iter().cloned();
let current_annos = &to_cons_nil_list(context.factory, current_annos);
let current_annos = &context.factory.list(current_annos);
eval_match(context, &*annos, current_annos)
}
As(ref v, ref term) => {
......@@ -307,6 +307,29 @@ fn eval_match<'a>(
.and_then(|s2| if *s == s2 { Some(()) } else { None })
.ok_or(Error::StrategyFailed)
}
Op(ref cons, ref children) if cons == "Cons" && children.len() == 2 => {
current.get_list().ok_or(Error::StrategyFailed).and_then(
|v| {
if v.is_empty() {
Err(Error::StrategyFailed)
} else {
eval_match(context, &children[0], &v[0])?;
let tail = if v.len() > 1 {
context.factory.list(v[1..].iter().cloned())
} else {
context.factory.list(iter::empty())
};
eval_match(context, &children[1], &tail)
}
},
)
}
Op(ref cons, ref children) if cons == "Nil" && children.is_empty() => {
current
.get_list()
.and_then(|v| if v.is_empty() { Some(()) } else { None })
.ok_or(Error::StrategyFailed)
}
Op(ref cons, ref children) => {
current
.get_application()
......@@ -333,22 +356,15 @@ fn eval_match<'a>(
let current_cons = &context.factory.string(current_cons.to_owned());
eval_match(context, cons, current_cons)?;
let current_children =
&to_cons_nil_list(context.factory, current_children.into_iter().cloned());
eval_match(context, children, current_children)?;
context.factory.list(current_children.into_iter().cloned());
eval_match(context, children, &current_children)?;
}
Term::List(ref list) => {
eval_match(
context,
cons,
&context.factory.application(
String::from("Nil"),
iter::empty(),
),
)?;
eval_match(context, cons, &context.factory.list(iter::empty()))?;
eval_match(
context,
children,
&to_cons_nil_list(context.factory, Vec::from(list.clone())),
&context.factory.list(list.clone().to_vec()),
)?;
}
Term::Blob(_) |
......@@ -360,14 +376,7 @@ fn eval_match<'a>(
}
Term::Int(_) | Term::Long(_) | Term::Real(_) => {
eval_match(context, cons, current)?;
eval_match(
context,
children,
&context.factory.application(
String::from("Nil"),
iter::empty(),
),
)?;
eval_match(context, children, &context.factory.list(iter::empty()))?;
}
}
Ok(())
......@@ -535,35 +544,3 @@ fn all_rec<'a>(
.collect::<Result<Vec<_>>>()
.map(Vec::into_boxed_slice)
}
pub fn to_cons_nil_list<I>(f: &ATermFactory, value: I) -> ATermRef
where
I: IntoIterator<Item = ATermRef>,
<I as iter::IntoIterator>::IntoIter: iter::DoubleEndedIterator,
{
value.into_iter().rev().fold(
f.application(
"Nil".to_owned(),
iter::empty(),
),
|list, term| {
f.application("Cons".to_owned(), iter::once(term).chain(iter::once(list)))
},
)
}
pub fn from_cons_nil_list(list: ATermRef) -> Result<Vec<ATermRef>> {
let mut result = Vec::new();
let mut list_term = &b(&list).as_inner().term;
while let Term::Application(ref c, ref r) = *list_term {
match (c.as_ref(), r.len()) {
("Nil", 0) => return Ok(result),
("Cons", 2) => {
result.push(r[0].clone());
list_term = &b(&r[1]).as_inner().term;
}
_ => return Err(Error::UnknownBehaviour("TypeError: expected List")),
}
}
Err(Error::UnknownBehaviour("TypeError: expected List"))
}
......@@ -3,7 +3,6 @@ use ctree;
use error::{Result, Error};
use factory::{ATermFactory, ATermRef};
use interpreter::Eval;
use interpreter::to_cons_nil_list;
use aterm::BrokenF32;
use aterm::{ATerm as A, ATermFactory as ATF};
......@@ -210,9 +209,7 @@ impl TryFrom<ctree::Def> for StrategyDef {
}
ctree::Def::ExtSDef(_, _, _) => Err(Error::CTreeParse("Unknown behaviour: ExtSDef")),
ctree::Def::ExtSDefInl(_, _, _, _) => {
Err(Error::CTreeParse(
"Unknown behaviour: ExtSDefInl",
))
Err(Error::CTreeParse("Unknown behaviour: ExtSDefInl"))
}
ctree::Def::AnnoDef(_, sdeft) => {
// libstratego-lib already has some of these, so this warning will be shown by
......@@ -414,37 +411,33 @@ impl BuildTerm {
))
}
Op(ref s, ref t) => {
use interpreter::b;
use aterm::Term::Application;
use std::iter;
let t = Self::build_vec(context, t)?;
if s == "Cons" && t.len() == 2 {
match b(&t[1]).as_inner().term {
Application(ref c, ref r)
if c == "Nil" && r.is_empty() || c == "Cons" && r.len() == 2 => {}
_ => {
return Err(Error::StrategyFailed);
}
}
t[1].get_list().ok_or(Error::StrategyFailed).map(|v| {
context.factory.list(iter::once(t[0].clone()).chain(
v.iter().cloned(),
))
})
} else if s == "Nil" && t.is_empty() {
Ok(context.factory.list(iter::empty()))
} else {
Ok(context.factory.with_annos(
context.factory.t_application(
s.clone(),
t.into_iter(),
),
annos.unwrap_or_default(),
))
}
Ok(context.factory.with_annos(
context.factory.t_application(
s.clone(),
t.into_iter(),
),
annos.unwrap_or_default(),
))
}
Explode(ref cons, ref children) => {
use interpreter::from_cons_nil_list;
let cons = cons.build(context)?;
let children = children.build(context)?;
let children = from_cons_nil_list(children).map_err(|_| {
Error::UnknownBehaviour(
"Non-list in build of explode pattern (#) second argument",
)
})?;
let children = children.get_list().ok_or(Error::UnknownBehaviour(
"Non-list in build of explode pattern (#) second argument",
))?;
if let Some(s) = cons.get_string() {
let string = context.factory.application(s.clone(), ::std::iter::empty());
......@@ -462,7 +455,7 @@ impl BuildTerm {
} else if cons.get_application().is_some() {
Err(Error::StrategyFailed)
} else if cons.get_list().is_some() {
Ok(to_cons_nil_list(context.factory, children.iter().cloned()))
Ok(context.factory.list(children.iter().cloned()))
} else if cons.get_blob().is_some() {
Err(Error::UnknownBehaviour(
"Blob in build of explode pattern (#) first argument",
......@@ -479,13 +472,11 @@ impl BuildTerm {
// 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) => {
use interpreter::from_cons_nil_list;
// TODO: Optimisation idea; try specialising the case where annos is a list literal
let annos: ATermRef = (**annos).build(context)?;
if let Ok(annos_vec) = from_cons_nil_list(annos.clone()) {
term.build_with_annos(context, Some(annos_vec))
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]))
term.build_with_annos(context, Some(vec![annos.clone()]))
}
}
}
......
use context::MutContext;
use error::{Error, Result};
use factory::{Blob, HashTable, ATermRef};
use interpreter::to_cons_nil_list;
use preprocess::StrategyDef;
use aterm::{ATermFactory as ATF, ATerm as A};
......@@ -221,7 +220,7 @@ pub fn hashtable_keys<'a>(
let table: &RefCell<HashTable> = table.borrow();
let result = to_cons_nil_list(context.factory, table.borrow().keys().cloned());
let result = context.factory.list(table.borrow().keys().cloned());
Ok(result)
}
......
use context::MutContext;
use error::{Error, Result};
use factory::{IndexedSet, ATermRef};
use interpreter::to_cons_nil_list;
use preprocess::StrategyDef;
use aterm::{ATermFactory as ATF, ATerm as A};
......@@ -180,6 +179,6 @@ pub fn indexedSet_elements<'a>(
let set: &RefCell<IndexedSet> = set.borrow();
let keys: Vec<_> = set.borrow().keys().cloned().collect();
let result = to_cons_nil_list(context.factory, keys.into_iter());
let result = context.factory.list(keys.into_iter());
Ok(result)
}
use context::MutContext;
use error::{Error, Result};
use factory::ATermRef;
use interpreter::from_cons_nil_list;
use preprocess::StrategyDef;
use aterm::ATermFactory as ATF;
use aterm::ATerm;
pub fn get_list_length<'a>(
context: &MutContext<'a>,
......@@ -18,8 +18,7 @@ pub fn get_list_length<'a>(
argument count",
));
}
// Not cheap :(
let list = from_cons_nil_list(targs[0].clone())?;
let list = targs[0].get_list().ok_or(Error::StrategyFailed)?;
Ok(context.factory.int(list.len() as i32))
}
......@@ -36,11 +35,10 @@ pub fn list_loop<'a>(
));
}
// Allocates more, but gives a type error earlier
let list = from_cons_nil_list(targs[0].clone())?;
let list = targs[0].get_list().ok_or(Error::StrategyFailed)?;
for t in list {
let _ = sargs[0].eval(context, Vec::new(), Vec::new(), t)?;
let _ = sargs[0].eval(context, Vec::new(), Vec::new(), t.clone())?;
}
Ok(current)
......@@ -59,13 +57,17 @@ pub fn list_fold<'a>(
));
}
// Allocates more, but gives a type error earlier
let list = from_cons_nil_list(targs[0].clone())?;
let list = targs[0].get_list().ok_or(Error::StrategyFailed)?;
let mut current = targs[0].clone();
for t in list {
current = sargs[0].eval(context, Vec::new(), vec![t.clone()], t)?;
current = sargs[0].eval(
context,
Vec::new(),
vec![t.clone()],
t.clone(),
)?;
}
Ok(current)
......
use context::MutContext;
use error::Result;
use factory::ATermRef;
use interpreter::to_cons_nil_list;
use preprocess::StrategyDef;
use aterm::ATermFactory as ATF;
......@@ -12,10 +11,11 @@ pub fn stacktrace_get_all_frame_names<'a>(
targs: Vec<ATermRef>,
current: ATermRef,
) -> Result<ATermRef> {
Ok(to_cons_nil_list(
context.factory,
context.stack_tracer.borrow().stack().map(|s| {
context.factory.string(s.clone())
}),
Ok(context.factory.list(
context.stack_tracer.borrow().stack().map(
|s| {
context.factory.string(s.clone())
},
),
))
}
use context::MutContext;
use error::{Error, Result};
use factory::ATermRef;
use interpreter::{from_cons_nil_list, to_cons_nil_list};
use preprocess::StrategyDef;
use aterm::{ATermFactory as ATF, ATerm as A};
......@@ -45,10 +44,9 @@ pub fn explode_string<'a>(
));
}
let s = targs[0].get_string().ok_or(Error::StrategyFailed)?;
Ok(to_cons_nil_list(
context.factory,
s.bytes().map(|b| context.factory.int(b as i32)),
))
Ok(context.factory.list(s.bytes().map(
|b| context.factory.int(b as i32),
)))
}
pub fn is_string<'a>(
......@@ -94,7 +92,7 @@ pub fn implode_string<'a>(
"Primitive implode_string called with wrong argument count",
));
}
let vec = from_cons_nil_list(targs[0].clone())?;
let vec = targs[0].get_list().ok_or(Error::StrategyFailed)?;
let bytes = vec.into_iter()
.map(|a| {
a.get_int().map(|i| i as u8).ok_or(Error::StrategyFailed)
......@@ -135,7 +133,7 @@ pub fn concat_strings<'a>(
"Primitive concat_strings called with wrong argument count",
));
}
let vec = from_cons_nil_list(targs[0].clone())?;
let vec = targs[0].get_list().ok_or(Error::StrategyFailed)?;
let strings = vec.into_iter()
.map(|a| a.get_string().ok_or(Error::StrategyFailed))
.collect::<Result<Vec<_>>>()?;
......
use context::MutContext;
use error::{Error, Result};
use factory::ATermRef;
use interpreter::{from_cons_nil_list, to_cons_nil_list};
use preprocess::StrategyDef;
use aterm::{ATermFactory as ATF, ATerm as A};
......@@ -378,7 +377,7 @@ pub fn access<'a>(
}
let path = targs[0].get_string().ok_or(Error::StrategyFailed)?;
let permissions = from_cons_nil_list(targs[1].clone())?;
let permissions = targs[1].get_list().ok_or(Error::StrategyFailed)?;
let path = context.ssl_state.borrow().sys.cwd_join(&path);
let permissions: u8 = permissions
.into_iter()
......@@ -430,7 +429,7 @@ pub fn readdir<'a>(
})
})
.collect::<Result<Vec<_>>>()?;
Ok(to_cons_nil_list(context.factory, dir_listing))
Ok(context.factory.list(dir_listing))
}
pub fn modification_time<'a>(
......@@ -947,7 +946,7 @@ pub fn printnl<'a>(
));
}
let out = targs[0].to_ascii_string()?;
let list = from_cons_nil_list(targs[1].clone())?;
let list = targs[1].get_list().ok_or(Error::StrategyFailed)?;
let mut stdout = io::stdout();
let mut stderr = io::stderr();
let mut writer = if out == "stdout" {
......
use context::MutContext;
use error::{Error, Result};
use factory::ATermRef;
use interpreter::{from_cons_nil_list, to_cons_nil_list};
use preprocess::StrategyDef;
use aterm::{Term, ATermFactory as ATF, ATerm as A};
......@@ -14,6 +13,7 @@ pub fn get_constructor<'a>(
current: ATermRef,
) -> Result<ATermRef> {
use super::super::super::interpreter::b;
use std::iter;
if targs.len() < 1 {
return Err(Error::UnknownBehaviour(
"Primitive get_constructor called with wrong argument \
......@@ -23,9 +23,9 @@ pub fn get_constructor<'a>(
match b(&targs[0]).as_inner().term {
Term::Int(_) |
Term::Long(_) |
Term::List(_) |
Term::Placeholder(_) |
Term::Real(_) => Ok(targs[0].clone()),
Term::List(_) => Ok(context.factory.list(iter::empty())),
Term::Application(ref v, _) => Ok(context.factory.string(v.clone())),
Term::Blob(ref b) => {
let mut str_repr = String::from("BLOB_");
......@@ -67,9 +67,10 @@ pub fn mkterm<'a>(
Ok(string)
} else {
let s = truncate_at_illegal_chars(s);
from_cons_nil_list(targs[1].clone()).map(|l| {
context.factory.application(s, l.into_iter())
})
targs[1]
.get_list()
.map(|l| context.factory.application(s, l.into_iter().cloned()))
.ok_or(Error::StrategyFailed)
}
})
.or_else(|_| {
......@@ -101,16 +102,14 @@ pub fn get_arguments<'a>(
targs: Vec<ATermRef>,
current: ATermRef,
) -> Result<ATermRef> {
use std::iter;
if targs.len() < 1 {
return Err(Error::UnknownBehaviour(
"Primitive get_arguments called with wrong argument \
count",
));
}
let empty_list = context.factory.application(
String::from("Nil"),
::std::iter::empty(),
);
let empty_list = context.factory.list(iter::empty());
// filter out strings first as we'll match on application later
targs[0]
.get_string()
......@@ -121,7 +120,7 @@ pub fn get_arguments<'a>(
.or_else(|| targs[0].get_list().map(|_| targs[0].clone()))
.or_else(|| {
targs[0].get_application().map(|(_, r)| {
to_cons_nil_list(context.factory, r.into_iter().cloned())
context.factory.list(r.into_iter().cloned())
})
})
.ok_or(Error::StrategyFailed)
......@@ -151,12 +150,12 @@ pub fn get_appl_arguments_map<'a>(
argument count",
));
}
let list = from_cons_nil_list(targs[0].clone())?;
let list = targs[0].get_list().ok_or(Error::StrategyFailed)?;
let mut result = Vec::with_capacity(list.len());
for (n, term) in list.into_iter().enumerate() {
result[n] = sargs[0].eval(context, Vec::new(), Vec::new(), term.clone())?;
}
Ok(to_cons_nil_list(context.factory, result))
Ok(context.factory.list(result))
}
pub fn address<'a>(
......
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