use core::fmt;
use std::{collections::HashMap, fmt::Write};
use super::parse::{ParseErrorKind, ParseState, TokenKind};
use crate::{
parse_error,
token_wildcard,
Context,
Parse,
ParseResult,
Print,
PrintResult,
PrintState,
};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct MnemonicSegment(String);
impl From<&str> for MnemonicSegment {
fn from(segment: &str) -> Self { Self(segment.to_string()) }
}
impl MnemonicSegment {
pub fn new(segment: &str) -> Self { Self(segment.to_string()) }
pub fn as_str(&self) -> &str { &self.0 }
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Mnemonic {
primary: MnemonicSegment,
secondary: MnemonicSegment,
}
impl Mnemonic {
pub fn new(primary: &str, secondary: &str) -> Self {
Self {
primary: MnemonicSegment::new(primary),
secondary: MnemonicSegment::new(secondary),
}
}
pub fn primary(&self) -> &MnemonicSegment { &self.primary }
pub fn secondary(&self) -> &MnemonicSegment { &self.secondary }
}
impl fmt::Display for Mnemonic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.primary.as_str(), self.secondary.as_str())
}
}
macro_rules! map {
($($key:expr => $value:expr),* $(,)?) => {
{
let mut map = HashMap::new();
$(
map.insert($key, $value);
)*
map
}
};
}
impl Parse for Mnemonic {
type Item = Mnemonic;
fn parse(_: &mut Context, state: &mut ParseState) -> ParseResult<Self::Item> {
let shortcuts = map! {
"func" => ("func", "func"),
};
let token = state.stream.consume()?;
match token.kind {
TokenKind::Tokenized(s) => {
let s = if s.starts_with('"') && s.ends_with('"') {
&s[1..s.len() - 1]
} else {
s.as_str()
};
let (primary, secondary) = match s.split_once('.') {
Some((primary, secondary)) => (primary, secondary),
None => {
if let Some(shortcut) = shortcuts.get(s) {
*shortcut
} else {
("builtin", s)
}
}
};
Ok(Mnemonic::new(primary, secondary))
}
_ => parse_error!(
token.span,
ParseErrorKind::InvalidToken(vec![token_wildcard!("...")].into(), token.kind)
)
.into(),
}
}
}
impl Print for Mnemonic {
fn print(&self, _: &Context, state: &mut PrintState) -> PrintResult<()> {
if self.primary.as_str() == "builtin" {
write!(state.buffer, "{}", self.secondary.as_str())?;
} else {
write!(
state.buffer,
"{}.{}",
self.primary.as_str(),
self.secondary.as_str()
)?;
}
Ok(())
}
}