use interface::{ATerm as ATermT, ATermFactory as ATermFactoryT, TermPlaceholder};
use bad_idea::BrokenF32;
use print::ATermWrite;
use std::rc::Rc;
use std::marker::PhantomData;
use std::hash::BuildHasher;
use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt;
use string_share::{StringShare, InternedString};
pub mod shared;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Term<'s, B> {
Int(i32),
Long(i64),
Real(BrokenF32),
Application(InternedString<'s>, Box<[Rc<ATerm<'s, B>>]>),
List(Box<[Rc<ATerm<'s, B>>]>),
Placeholder(TermPlaceholder<Rc<ATerm<'s, B>>>),
Blob(B),
}
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 bad_idea::BrokenF32;
use std::borrow::Borrow;
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.borrow())?;
if !children.is_empty() {
write!(writer, "(")?;
children.to_ascii(writer)?;
write!(writer, ")")?;
}
Ok(())
}
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),
}
}
}
pub type T<'s, A: ATermT<'s>> = Term<'s, <A as ATermT<'s>>::Blob>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct ATerm<'s, B> {
pub term: Term<'s, B>,
pub annotations: Box<[Rc<ATerm<'s, B>>]>,
}
impl<'s, B> ATermWrite for ATerm<'s, B>
where
B: ATermWrite,
{
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, B: ATermWrite> fmt::Display for ATerm<'s, B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_ascii(f)
}
}
impl<'s, B> ATerm<'s, B> {
pub fn no_annos(term: Term<'s, B>) -> Self {
ATerm {
term: term,
annotations: Box::new([]),
}
}
pub fn with_annos<A>(term: Term<'s, B>, annos: A) -> Self
where
A: IntoIterator<Item = Rc<ATerm<'s, B>>>,
{
ATerm {
term: term,
annotations: annos.into_iter().collect::<Vec<_>>().into_boxed_slice(),
}
}
}
impl<'s, B> ATermT<'s> for ATerm<'s, B> {
type Rec = Rc<ATerm<'s, B>>;
type Blob = B;
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(BrokenF32(r)) => Some(r),
_ => None,
}
}
fn get_application(&self) -> Option<(InternedString<'s>, &[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(Vec::from(&**r)),
_ => None,
}
}
fn get_placeholder(&self) -> Option<&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 struct ATermFactory<B, H: BuildHasher> {
string_cache: RefCell<StringShare<H>>,
_nothing: PhantomData<B>,
}
impl<'s, B, H: BuildHasher + Default> ATermFactory<B, H> {
pub fn new() -> Self {
ATermFactory {
string_cache: RefCell::new(StringShare::new()),
_nothing: PhantomData,
}
}
}
impl<'s, B, H: BuildHasher + Default> Default for ATermFactory<B, H> {
fn default() -> Self {
Self::new()
}
}
impl<'s, B, H> ATermFactoryT<'s> for ATermFactory<B, H>
where
B: 's + Clone,
H: 's + BuildHasher + Default,
{
type ATerm = ATerm<'s, B>;
type ATermRef = Rc<ATerm<'s, B>>;
fn application<I, S>(&'s self, constructor: S, children: I) -> Self::ATermRef
where
I: IntoIterator<Item = Self::ATermRef>,
S: Into<Cow<'s, str>>,
{
use self::Term::Application;
use utils::extend_lifetime_mut;
let mut string_cache = unsafe { extend_lifetime_mut(&mut self.string_cache.borrow_mut()) };
let cons = string_cache.insert(constructor.into().as_ref());
Rc::new(ATerm::no_annos(Application(
cons,
children.into_iter().collect::<Vec<_>>().into_boxed_slice(),
)))
}
fn with_annos<A>(&'s self, term: Self::ATermRef, annos: A) -> Self::ATermRef
where
A: IntoIterator<Item = Self::ATermRef>,
{
Rc::new(ATerm::with_annos(term.term.clone(), annos))
}
fn int(&'s self, value: i32) -> Self::ATermRef {
Rc::new(ATerm::no_annos(Term::Int(value)))
}
fn string<S>(&'s self, value: S) -> Self::ATermRef
where
S: Into<Cow<'s, str>>,
{
self.application(::utils::string_escape(&value.into()), ::std::iter::empty())
}
fn tuple<I>(&'s self, children: I) -> Self::ATermRef
where
I: IntoIterator<Item = Self::ATermRef>,
{
self.application(String::new(), children)
}
fn real(&'s self, value: f32) -> Self::ATermRef {
Rc::new(ATerm::no_annos(Term::Real(BrokenF32(value))))
}
fn list<I>(&'s self, value: I) -> Self::ATermRef
where
I: IntoIterator<Item = Self::ATermRef>,
{
Rc::new(ATerm::no_annos(Term::List(
value.into_iter().collect::<Vec<_>>().into_boxed_slice(),
)))
}
fn placeholder(&'s self, value: TermPlaceholder<Self::ATermRef>) -> Self::ATermRef {
Rc::new(ATerm::no_annos(Term::Placeholder(value)))
}
fn blob(&'s self, value: <Self::ATerm as ATermT<'s>>::Blob) -> Self::ATermRef {
Rc::new(ATerm::no_annos(Term::Blob(value)))
}
fn long(&'s self, value: i64) -> Self::ATermRef {
Rc::new(ATerm::no_annos(Term::Long(value)))
}
}