#![allow(clippy::let_and_return)]
#![warn(missing_docs)]
mod conversion;
mod ptr_cmp;
pub mod symbol;
#[doc(hidden)]
mod test_readme {
#![doc = include_str ! ("../README.md")]
}
use std::fmt;
use std::mem;
use std::sync::Arc;
#[doc(inline)]
pub use self::symbol::Symbol;
#[cfg(feature = "unstable_parse")]
pub use self::ptr_cmp::ExprRefCmp;
#[cfg(feature = "unstable_parse")]
pub mod parse {
pub use crate::symbol::parse::*;
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Expr {
inner: Arc<ExprKind>,
}
const _: () = assert!(mem::size_of::<Expr>() == mem::size_of::<usize>());
const _: () = assert!(mem::size_of::<Expr>() == mem::size_of::<*const ()>());
const _: () = assert!(mem::align_of::<Expr>() == mem::align_of::<usize>());
const _: () = assert!(mem::align_of::<Expr>() == mem::align_of::<*const ()>());
impl Expr {
pub fn new(kind: ExprKind) -> Expr {
Expr {
inner: Arc::new(kind),
}
}
#[allow(clippy::wrong_self_convention)]
pub fn to_kind(self) -> ExprKind {
match Arc::try_unwrap(self.inner) {
Ok(kind) => kind,
Err(self_) => (*self_).clone(),
}
}
pub fn kind(&self) -> &ExprKind {
&*self.inner
}
pub fn kind_mut(&mut self) -> &mut ExprKind {
Arc::make_mut(&mut self.inner)
}
pub fn ref_count(&self) -> usize {
Arc::strong_count(&self.inner)
}
pub fn normal<H: Into<Expr>>(head: H, contents: Vec<Expr>) -> Expr {
let head = head.into();
Expr {
inner: Arc::new(ExprKind::Normal(Normal { head, contents })),
}
}
pub fn symbol<S: Into<Symbol>>(s: S) -> Expr {
let s = s.into();
Expr {
inner: Arc::new(ExprKind::Symbol(s)),
}
}
pub fn number(num: Number) -> Expr {
Expr {
inner: Arc::new(ExprKind::from(num)),
}
}
pub fn string<S: Into<String>>(s: S) -> Expr {
Expr {
inner: Arc::new(ExprKind::String(s.into())),
}
}
pub fn real(real: f64) -> Expr {
Expr::number(Number::real(real))
}
pub fn tag(&self) -> Option<Symbol> {
match *self.inner {
ExprKind::Integer(_) | ExprKind::Real(_) | ExprKind::String(_) => None,
ExprKind::Normal(ref normal) => normal.head.tag(),
ExprKind::Symbol(ref sym) => Some(sym.clone()),
}
}
pub fn normal_head(&self) -> Option<Expr> {
match *self.inner {
ExprKind::Normal(ref normal) => Some(normal.head.clone()),
ExprKind::Symbol(_)
| ExprKind::Integer(_)
| ExprKind::Real(_)
| ExprKind::String(_) => None,
}
}
pub fn normal_part(&self, index_0: usize) -> Option<&Expr> {
match self.kind() {
ExprKind::Normal(ref normal) => normal.contents.get(index_0),
ExprKind::Symbol(_)
| ExprKind::Integer(_)
| ExprKind::Real(_)
| ExprKind::String(_) => None,
}
}
pub fn has_normal_head(&self, sym: &Symbol) -> bool {
match *self.kind() {
ExprKind::Normal(ref normal) => normal.has_head(sym),
_ => false,
}
}
pub fn null() -> Expr {
Expr::symbol(unsafe { Symbol::unchecked_new("System`Null") })
}
pub fn rule<LHS: Into<Expr>>(lhs: LHS, rhs: Expr) -> Expr {
let lhs = lhs.into();
Expr::normal(Symbol::new("System`Rule"), vec![lhs, rhs])
}
pub fn rule_delayed<LHS: Into<Expr>>(lhs: LHS, rhs: Expr) -> Expr {
let lhs = lhs.into();
Expr::normal(Symbol::new("System`RuleDelayed"), vec![lhs, rhs])
}
pub fn list(elements: Vec<Expr>) -> Expr {
Expr::normal(Symbol::new("System`List"), elements)
}
}
#[allow(missing_docs)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ExprKind<E = Expr> {
Integer(i64),
Real(F64),
String(String),
Symbol(Symbol),
Normal(Normal<E>),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Normal<E = Expr> {
head: E,
contents: Vec<E>,
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
pub enum Number {
Integer(i64),
Real(F64),
}
pub type F64 = ordered_float::NotNan<f64>;
pub type F32 = ordered_float::NotNan<f32>;
impl Normal {
pub fn new<E: Into<Expr>>(head: E, contents: Vec<Expr>) -> Self {
Normal {
head: head.into(),
contents,
}
}
pub fn head(&self) -> &Expr {
&self.head
}
pub fn elements(&self) -> &[Expr] {
&self.contents
}
pub fn into_elements(self) -> Vec<Expr> {
self.contents
}
pub fn has_head(&self, sym: &Symbol) -> bool {
self.head == *sym
}
}
impl Number {
pub fn real(r: f64) -> Self {
let r = match ordered_float::NotNan::new(r) {
Ok(r) => r,
Err(_) => panic!("Number::real: got NaN"),
};
Number::Real(r)
}
}
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Expr { inner } = self;
write!(f, "{:?}", inner)
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.inner)
}
}
impl fmt::Display for ExprKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ExprKind::Normal(ref normal) => fmt::Display::fmt(normal, f),
ExprKind::Integer(ref int) => fmt::Display::fmt(int, f),
ExprKind::Real(ref real) => fmt::Display::fmt(real, f),
ExprKind::String(ref string) => {
write!(f, "{:?}", string)
},
ExprKind::Symbol(ref symbol) => fmt::Display::fmt(symbol, f),
}
}
}
impl fmt::Debug for ExprKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl fmt::Display for Normal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}[", self.head)?;
for (idx, elem) in self.contents.iter().enumerate() {
write!(f, "{}", elem)?;
if idx != self.contents.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Number::Integer(ref int) => write!(f, "{}", int),
Number::Real(ref real) => {
let real: f64 = **real;
write!(f, "{:?}", real)
},
}
}
}
impl PartialEq<Symbol> for Expr {
fn eq(&self, other: &Symbol) -> bool {
match self.kind() {
ExprKind::Symbol(self_sym) => self_sym == other,
_ => false,
}
}
}