use std::fmt;
use wast::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::{AsAtoms, Atom, Integer, Sign};
pub fn symbolic<S: AsRef<str>>(s: S) -> Index {
Index::Symbolic(SymbolicIndex::new(s.as_ref().to_owned()))
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Index {
Numeric(NumericIndex),
Symbolic(SymbolicIndex),
}
impl fmt::Display for Index {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Numeric(i) => write!(f, "{}", i.src()),
Self::Symbolic(i) => write!(f, "{}", i.to_string()),
}
}
}
impl Parse<'_> for Index {
fn parse(parser: Parser<'_>) -> Result<Self> {
match parser.parse::<NumericIndex>() {
Ok(ni) => Ok(Self::Numeric(ni)),
Err(_) => match parser.parse::<SymbolicIndex>() {
Ok(si) => Ok(Self::Symbolic(si)),
Err(err) => Err(err),
},
}
}
}
impl AsAtoms for Index {
fn as_atoms(&self) -> Vec<Atom> {
match self {
Self::Numeric(i) => i.as_atoms(),
Self::Symbolic(i) => i.as_atoms(),
}
}
}
impl Peek for Index {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.id().is_some() || cursor.integer().is_some()
}
fn display() -> &'static str {
"an index"
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Indexes {
idxs: Vec<Index>,
}
impl Indexes {
pub fn new(idxs: Vec<Index>) -> Self {
Self { idxs }
}
}
impl IntoIterator for Indexes {
type Item = Index;
type IntoIter = std::vec::IntoIter<Index>;
fn into_iter(self) -> Self::IntoIter {
self.idxs.into_iter()
}
}
impl AsAtoms for Indexes {
fn as_atoms(&self) -> Vec<Atom> {
self.idxs.iter().map(|i| Atom::new(i.to_string())).collect()
}
}
impl Parse<'_> for Indexes {
fn parse(parser: Parser<'_>) -> Result<Self> {
let mut idxs = Vec::new();
while parser.peek::<Index>() {
idxs.push(parser.parse()?);
}
Ok(Self { idxs })
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NumericIndex {
i: Integer,
span: Option<wast::Span>,
}
impl NumericIndex {
pub fn new(i: Integer) -> Self {
Self { i, span: None }
}
pub fn span(&self) -> Option<wast::Span> {
self.span
}
pub fn sign(&self) -> Option<Sign> {
self.i.sign()
}
pub fn src(&self) -> &str {
self.i.src()
}
pub fn val(&self) -> (Option<&String>, Option<u32>) {
self.i.val()
}
}
impl AsAtoms for NumericIndex {
fn as_atoms(&self) -> Vec<Atom> {
vec![Atom::new(self.i.to_string())]
}
}
impl Parse<'_> for NumericIndex {
fn parse(parser: Parser<'_>) -> Result<Self> {
let span = Some(parser.cur_span());
let i = parser.parse::<Integer>()?;
Ok(Self { i, span })
}
}
impl Peek for NumericIndex {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.integer().is_some()
}
fn display() -> &'static str {
"a numeric index"
}
}
#[derive(Debug, Clone)]
pub struct SymbolicIndex {
name: String,
span: Option<wast::Span>,
}
impl SymbolicIndex {
pub fn new(name: String) -> Self {
Self { name, span: None }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn span(&self) -> Option<wast::Span> {
self.span
}
}
impl std::hash::Hash for SymbolicIndex {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for SymbolicIndex {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for SymbolicIndex {}
impl fmt::Display for SymbolicIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "${}", self.name)
}
}
impl AsAtoms for SymbolicIndex {
fn as_atoms(&self) -> Vec<Atom> {
vec![Atom::new(self.to_string())]
}
}
impl Parse<'_> for SymbolicIndex {
fn parse(parser: Parser<'_>) -> Result<Self> {
let id = parser.parse::<wast::Id>()?;
let name = id.name().to_owned();
let span = Some(id.span());
Ok(Self { name, span })
}
}
impl Peek for SymbolicIndex {
fn peek(cursor: Cursor<'_>) -> bool {
cursor.id().is_some()
}
fn display() -> &'static str {
"a symbolic index"
}
}