Commit d6bd79e1 authored by Jeff Smits's avatar Jeff Smits

Still WIP, with these changes strings and constructors should be shared

parent 7581e405
......@@ -121,6 +121,7 @@ fn gen_primitives() {
"indexedSet_destroy",
"indexedSet_put",
"indexedSet_getIndex",
"indexedSet_getElem",
"indexedSet_elements",
"indexedSet_remove",
"indexedSet_reset",
......@@ -306,7 +307,7 @@ fn gen_strc_tests() {
for entry in read_dir("tests/strc_tests").unwrap() {
let path = entry.unwrap().path();
if path.is_file() && Some("ctree".as_ref()) == path.extension() {
// TODO: sanitise file_stem so it's likely to be a valid test name?
// Should we sanitise file_stem so it's likely to be a valid test name?
let test_name = path.file_stem().unwrap().to_str().unwrap().replace(
'-',
"_",
......
......@@ -16,14 +16,14 @@ use std::cell::RefCell;
pub struct MutContext<'d, 'f : 'd> {
pub stack_tracer: RefCell<StackTracer>,
pub scopes: RefCell<Vec<Scope<'d, ATermRef<'f>>>>,
pub factory: &'f ATermFactory<'f>,
pub factory: &'f ATermFactory,
pub primitives: Vec<&'static Primitives>,
pub ssl_state: RefCell<State<'f>>,
}
impl<'d, 'f : 'd> MutContext<'d, 'f> {
pub fn new(
factory: &'f ATermFactory<'f>,
factory: &'f ATermFactory,
scopes: Vec<Scope<'d, ATermRef<'f>>>,
primitives: Vec<&'static Primitives>,
) -> MutContext<'d, 'f> {
......
use aterm as a;
use aterm::BrokenF32;
use try_from::{TryFrom, TryInto};
......@@ -8,6 +7,7 @@ use std::fmt;
use error::Error;
use factory::ATermRef;
use factory::Term as FTerm;
/// ```sdf3
/// ModName = {ModNamePart "/"}+
......@@ -54,7 +54,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Module
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Module" => {
if r.len() == 2 {
......@@ -117,7 +117,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Decl
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Imports" => {
if r.len() == 1 {
......@@ -162,7 +162,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for ImportModName
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Import" => {
if r.len() == 1 {
......@@ -215,7 +215,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for SDecl
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Sorts" => {
if r.len() == 1 {
......@@ -267,7 +267,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Sort
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"SortVar" => {
if r.len() == 1 {
......@@ -329,7 +329,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for OpDecl
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"OpDecl" => {
if r.len() == 2 {
......@@ -387,7 +387,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for ConstType
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
if let "ConstType" = c.borrow() {
if r.len() == 1 {
return match_(&r[0]).map(ConstType);
......@@ -429,7 +429,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Type
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"ConstType" => {
if r.len() == 1 {
......@@ -513,7 +513,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Def
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"SDefT" => {
if r.len() == 4 {
......@@ -574,7 +574,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for SVar
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
if let "SVar" = c.borrow() {
let r = r;
if r.len() == 1 {
......@@ -643,7 +643,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for StrategyDef
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"SDefT" => {
if r.len() == 4 {
......@@ -721,7 +721,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Anno
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Extend" => {
if r.is_empty() {
......@@ -760,7 +760,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for VarDec
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
if let "VarDec" = c.borrow() {
if r.len() == 2 {
let str = match_string(&r[0])?;
......@@ -876,7 +876,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Strategy
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Let" => {
if r.len() == 2 {
......@@ -1011,7 +1011,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Var
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
if let "Var" = c.borrow() {
let r = r;
if r.len() == 1 {
......@@ -1048,7 +1048,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for Term
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Var" => {
let r = r;
......@@ -1121,7 +1121,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for PreTerm
type Err = Error;
fn try_from(value: &'a ATermRef<'s>) -> Result<Self, Self::Err> {
if let a::rc::Term::Application(c, ref r) = value.term {
if let FTerm::Application(c, ref r) = value.term {
match c {
"Var" => {
let r = r;
......@@ -1187,7 +1187,7 @@ impl<'s, 'a> TryFrom<&'a ATermRef<'s>> for PreTerm
}
fn match_string<'s>(r: &ATermRef<'s>) -> Result<String, Error> {
if let a::rc::Term::Application(ref str, ref r) = r.term {
if let FTerm::Application(ref str, ref r) = r.term {
if r.is_empty() {
return Ok(string_unescape(str));
}
......@@ -1196,21 +1196,21 @@ fn match_string<'s>(r: &ATermRef<'s>) -> Result<String, Error> {
}
fn match_strings<'s>(r: &ATermRef<'s>) -> Result<Vec<String>, Error> {
if let a::rc::Term::List(ref r) = r.term {
return r.into_iter()
.map(match_string)
if let FTerm::List(ref r) = r.term {
return r.iter()
.map(|a| match_string(&a))
.collect::<Result<Vec<String>, Error>>();
}
Err(Error::CTreeParse("list"))
}
fn match_list<'a, 's, T>(r: &'a ATermRef<'s>) -> Result<Vec<T>, Error>
fn match_list<'s, T>(r: &ATermRef<'s>) -> Result<Vec<T>, Error>
where
T: TryFrom<&'a ATermRef<'s>, Err = Error>,
T: for<'a> TryFrom<&'a ATermRef<'s>, Err = Error>,
{
if let a::rc::Term::List(ref r) = r.term {
if let FTerm::List(ref r) = r.term {
return r.iter()
.map(|a| a.try_into())
.map(|a| (&a).try_into())
.collect::<Result<Vec<T>, Error>>();
}
Err(Error::CTreeParse("list"))
......
use aterm;
use aterm::print::ATermWrite;
use aterm::string_share::StringShare;
use linked_hash_map::LinkedHashMap;
......@@ -12,7 +14,8 @@ use std::hash::Hash;
use std::hash::Hasher;
use std::fmt;
use std::rc::Rc;
use std::borrow::Borrow;
use std::borrow::{Cow, Borrow};
use std::iter::FromIterator;
pub type HashTable<'s> = LinkedHashMap<ATermRef<'s>, ATermRef<'s>, ::fnv::FnvBuildHasher>;
#[derive(Debug, Eq, Clone, Default)]
......@@ -129,16 +132,292 @@ impl<'s> TryInto<Rc<RefCell<IndexedSet<'s>>>> for Blob<'s> {
}
}
pub trait StrTerm<'s>: aterm::ATerm<'s> {
fn get_string(&self) -> Option<&'s str>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum TermList<'s> {
Cons(ATermRef<'s>, Rc<TermList<'s>>),
Nil,
}
impl<'s> TermList<'s> {
pub fn iter(&self) -> TermListIterator<'s> {
self.clone().into_iter()
}
}
impl<'s> IntoIterator for TermList<'s> {
type Item = ATermRef<'s>;
type IntoIter = TermListIterator<'s>;
fn into_iter(self) -> Self::IntoIter {
TermListIterator {
listterm: Rc::new(self),
}
}
}
impl<'s> ATermWrite for TermList<'s> {
fn to_ascii<W: fmt::Write>(&self, writer: &mut W) -> fmt::Result {
self.iter().collect::<Vec<_>>().to_ascii(writer)
}
}
// TODO: Support annotations on sublists (not support by the aterm format)
#[derive(Debug, Clone)]
pub struct TermListIterator<'s> {
listterm: Rc<TermList<'s>>,
}
impl<'s> Iterator for TermListIterator<'s> {
type Item = ATermRef<'s>;
fn next(&mut self) -> Option<Self::Item> {
use self::TermList::*;
pub type ATermFactory<'s> = aterm::rc::ATermFactory<Blob<'s>, FnvBuildHasher>;
pub type ATerm<'s> = aterm::rc::ATerm<'s, Blob<'s>>;
pub type ATermRef<'s> = Rc<aterm::rc::ATerm<'s, Blob<'s>>>;
let (h, t) = if let Cons(ref h, ref t) = *self.listterm {
(h.clone(), t.clone())
} else {
return None
};
self.listterm = t;
Some(h)
}
}
impl<'s> FromIterator<ATermRef<'s>> for TermList<'s> {
fn from_iter<T: IntoIterator<Item=ATermRef<'s>>>(iter: T) -> Self {
iter.into_iter().fold(TermList::Nil, |list, item| TermList::Cons(item, Rc::new(list)))
}
}
#[derive(Debug, Eq, Clone, Hash)]
pub enum Term<'s, B> {
Int(i32),
Long(i64),
Real(aterm::BrokenF32),
Application(&'s str, Box<[ATermRef<'s>]>),
String(&'s str),
List(Rc<TermList<'s>>),
Placeholder(aterm::TermPlaceholder<ATermRef<'s>>),
Blob(B),
}
// Note that this implementation uses pointer equality on strings, assuming all strings went
// through the factory and were collapsed when equal!
impl<'s, B: PartialEq> PartialEq for Term<'s, B> {
fn eq(&self, other: &Self) -> bool {
use self::Term::*;
use std::ptr;
match (self, other) {
(&Int(l), &Int(r)) => l == r,
(&Long(l), &Long(r)) => l == r,
(&Real(l), &Real(r)) => l == r,
(&Application(lc, ref lch), &Application(rc, ref rch)) => {
ptr::eq(lc, rc) && lch == rch
}
(&List(ref l), &List(ref r)) => l == r,
(&Placeholder(ref l), &Placeholder(ref r)) => l == r,
(&Blob(ref l), &Blob(ref r)) => l == r,
_ => false,
}
}
}
impl<'s, B> ATermWrite for Term<'s, B>
where
B: ATermWrite,
{
fn to_ascii<W: fmt::Write>(&self, writer: &mut W) -> fmt::Result {
use self::Term::*;
use aterm::BrokenF32;
match *self {
Int(i) => write!(writer, "{}", i),
Long(l) => write!(writer, "{}", l),
Real(BrokenF32(r)) => write!(writer, "{}", r),
Application(cons, ref children) => {
writer.write_str(cons)?;
if !children.is_empty() {
write!(writer, "(")?;
children.to_ascii(writer)?;
write!(writer, ")")?;
}
Ok(())
}
String(string) => {
write!(writer, "{:?}", string)
}
List(ref l) => {
write!(writer, "[")?;
l.to_ascii(writer)?;
write!(writer, "]")
}
Placeholder(ref tp) => tp.to_ascii(writer),
Blob(ref b) => b.to_ascii(writer),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Attachment {
}
/// The annotated term. This only combines the term with the annotations.
#[derive(Debug, Eq, Clone)]
pub struct ATerm<'s> {
/// The actual term.
pub term: Term<'s, Blob<'s>>,
/// The annotations on the term. The spec says this is an ATerm list of pairs of ATerms. We
/// extend this to a general list of aterms so we can support more systems (e.g. Stratego/XT).
pub annotations: Box<[ATermRef<'s>]>,
/// Mutable attachments are invisible when an aterm is printed
pub attachments: RefCell<Vec<Attachment>>,
}
impl<'s> PartialEq<ATerm<'s>> for ATerm<'s> {
fn eq(&self, other: &ATerm<'s>) -> bool {
self.term == other.term && self.annotations == other.annotations
}
}
impl<'s> Hash for ATerm<'s> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.term.hash(state);
self.annotations.hash(state);
}
}
impl<'s> ATermWrite for ATerm<'s>
{
fn to_ascii<W: fmt::Write>(&self, writer: &mut W) -> fmt::Result {
let annotations = &self.annotations;
self.term.to_ascii(writer)?;
if !annotations.is_empty() {
write!(writer, "{{")?;
annotations.to_ascii(writer)?;
write!(writer, "}}")?;
}
Ok(())
}
}
impl<'s> fmt::Display for ATerm<'s> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_ascii(f)
}
}
impl<'s> ATerm<'s> {
pub fn no_annos(term: Term<'s, Blob<'s>>) -> Self {
ATerm {
term: term,
annotations: Box::new([]),
attachments: RefCell::new(Vec::new())
}
}
pub fn with_annos<A>(term: Term<'s, Blob<'s>>, annos: A) -> Self
where
A: IntoIterator<Item = ATermRef<'s>>,
{
ATerm {
term: term,
annotations: annos.into_iter().collect::<Vec<_>>().into_boxed_slice(),
attachments: RefCell::new(Vec::new()),
}
}
pub fn with_annos_attachments<A, I>(term: Term<'s, Blob<'s>>, annos: A, attachments: I) -> Self
where
A: IntoIterator<Item = ATermRef<'s>>,
I: IntoIterator<Item=Attachment>,
{
ATerm {
term: term,
annotations: annos.into_iter().collect::<Vec<_>>().into_boxed_slice(),
attachments: RefCell::new(attachments.into_iter().collect()),
}
}
pub fn get_string(&self) -> Option<&'s str> {
use self::Term::*;
match self.term {
String(s) => Some(s),
_ => None,
}
}
pub fn get_attachments(&self) -> Vec<Attachment> {
RefCell::borrow(&self.attachments).clone()
}
pub fn set_attachments<I>(&self, attachments: I)
where
I: IntoIterator<Item=Attachment>,
{
*self.attachments.borrow_mut() = attachments.into_iter().collect();
}
}
impl<'s> aterm::ATerm<'s> for ATerm<'s> {
type Rec = ATermRef<'s>;
type Blob = Blob<'s>;
fn get_int(&self) -> Option<i32> {
match self.term {
Term::Int(i) => Some(i),
_ => None,
}
}
fn get_long(&self) -> Option<i64> {
match self.term {
Term::Long(l) => Some(l),
_ => None,
}
}
fn get_real(&self) -> Option<f32> {
match self.term {
Term::Real(aterm::BrokenF32(r)) => Some(r),
_ => None,
}
}
fn get_application(&self) -> Option<(&'s str, &[Self::Rec])> {
match self.term {
Term::Application(c, ref r) => Some((c, r)),
_ => None,
}
}
fn get_list(&self) -> Option<Vec<Self::Rec>> {
match self.term {
Term::List(ref r) => Some(r.iter().collect()),
_ => None,
}
}
fn get_placeholder(&self) -> Option<&aterm::TermPlaceholder<Self::Rec>> {
match self.term {
Term::Placeholder(ref tp) => Some(tp),
_ => None,
}
}
fn get_blob(&self) -> Option<&Self::Blob> {
match self.term {
Term::Blob(ref b) => Some(b),
_ => None,
}
}
fn get_annotations(&self) -> &[Self::Rec] {
&*self.annotations
}
}
pub type ATermRef<'s> = Rc<ATerm<'s>>;
impl<'s> aterm::print::ATermWrite for Blob<'s> {
fn to_ascii<W: fmt::Write>(&self, writer: &mut W) -> fmt::Result {
......@@ -149,12 +428,123 @@ impl<'s> aterm::print::ATermWrite for Blob<'s> {
}
}
impl<'s> StrTerm<'s> for ATerm<'s> {
fn get_string(&self) -> Option<&'s str> {
use aterm::rc::Term::*;
match self.term {
Application(s, ref c) if c.is_empty() && s.starts_with('"') && s.ends_with('"') => Some(s),
_ => None,
pub struct ATermFactory {
string_cache: RefCell<StringShare<FnvBuildHasher>>,
}
impl ATermFactory {
pub fn new() -> Self {
ATermFactory {
string_cache: RefCell::new(StringShare::new()),
}
}
}
impl<'s> ATermFactory {
pub fn cons(&'s self, head: ATermRef<'s>, tail: Rc<TermList<'s>>) -> ATermRef<'s> {
Rc::new(ATerm::no_annos(Term::List(Rc::new(TermList::Cons(head, tail)))))
}
pub fn nil(&'s self) -> ATermRef<'s> {
Rc::new(ATerm::no_annos(Term::List(Rc::new(TermList::Nil))))
}
pub fn list_term(&'s self, list: Rc<TermList<'s>>) -> ATermRef<'s> {
Rc::new(ATerm::no_annos(Term::List(list)))
}
pub fn with_annos_attachments<I, A>(&'s self, aterm: ATermRef<'s>, annos: A, attachments: I) -> ATermRef<'s>
where
A: IntoIterator<Item=ATermRef<'s>>,
I: IntoIterator<Item=Attachment>,
{
Rc::new(ATerm::with_annos_attachments(aterm.term.clone(), annos, attachments))
}
}
impl Default for ATermFactory {
fn default() -> Self {
Self::new()
}
}