use std::{fmt::Display, ops::Deref};
use combine::Parser;
use rustc_hash::FxHashMap;
use crate::{
attribute::{AttrId, AttrParserFn},
context::Context,
identifier::Identifier,
input_err,
location::{Located, Location},
op::{OpId, OpObj},
parsable::{IntoParseResult, Parsable, ParseResult, ParserFn, StateStream},
printable::{self, Printable},
r#type::{TypeId, TypeParserFn},
};
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct DialectName(Identifier);
impl DialectName {
pub fn new(name: &str) -> DialectName {
DialectName(name.try_into().expect("Invalid Identifier for DialectName"))
}
}
impl From<&str> for DialectName {
fn from(value: &str) -> Self {
DialectName::new(value)
}
}
impl Printable for DialectName {
fn fmt(
&self,
_ctx: &Context,
_state: &printable::State,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl Display for DialectName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Parsable for DialectName {
type Arg = ();
type Parsed = DialectName;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed>
where
Self: Sized,
{
let loc = state_stream.loc();
let id = Identifier::parser(());
let mut parser = id.then(move |dialect_name| {
let loc = loc.clone();
combine::parser(move |state_stream: &mut StateStream<'a>| {
let dialect_name = DialectName::new(&dialect_name);
if state_stream.state.ctx.dialects.contains_key(&dialect_name) {
Ok(dialect_name).into_parse_result()
} else {
input_err!(loc.clone(), "Unregistered dialect {}", *dialect_name)?
}
})
});
parser.parse_stream(state_stream).into()
}
}
impl Deref for DialectName {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct Dialect {
pub name: DialectName,
pub(crate) ops: FxHashMap<OpId, ParserFn<Vec<(Identifier, Location)>, OpObj>>,
pub(crate) types: FxHashMap<TypeId, TypeParserFn>,
pub(crate) attributes: FxHashMap<AttrId, AttrParserFn>,
}
impl Printable for Dialect {
fn fmt(
&self,
ctx: &Context,
_state: &printable::State,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
write!(f, "{}", self.name.disp(ctx))
}
}
impl Dialect {
pub fn new(name: DialectName) -> Dialect {
Dialect {
name,
ops: FxHashMap::default(),
types: FxHashMap::default(),
attributes: FxHashMap::default(),
}
}
pub fn register(self, ctx: &mut Context) {
ctx.dialects.entry(self.name.clone()).or_insert(self);
}
pub(crate) fn add_op(
&mut self,
op: OpId,
op_parser: ParserFn<Vec<(Identifier, Location)>, OpObj>,
) {
assert!(op.dialect == self.name);
self.ops.insert(op, op_parser);
}
pub(crate) fn add_type(&mut self, ty: TypeId, ty_parser: TypeParserFn) {
assert!(ty.dialect == self.name);
self.types.insert(ty, ty_parser);
}
pub(crate) fn add_attr(&mut self, attr: AttrId, attr_parser: AttrParserFn) {
assert!(attr.dialect == self.name);
self.attributes.insert(attr, attr_parser);
}
pub fn get_name(&self) -> &DialectName {
&self.name
}
}
#[cfg(test)]
mod test {
use expect_test::expect;
use crate::{
builtin,
context::Context,
location,
parsable::{self, state_stream_from_iterator, Parsable},
printable::Printable,
};
use super::DialectName;
#[test]
fn parse_dialect_name() {
let mut ctx = Context::new();
builtin::register(&mut ctx);
let state_stream = state_stream_from_iterator(
"non_existant".chars(),
parsable::State::new(&mut ctx, location::Source::InMemory),
);
let res = DialectName::parser(()).parse(state_stream);
let err_msg = format!("{}", res.err().unwrap());
let expected_err_msg = expect![[r#"
Parse error at line: 1, column: 1
Unregistered dialect non_existant
"#]];
expected_err_msg.assert_eq(&err_msg);
let state_stream = state_stream_from_iterator(
"builtin".chars(),
parsable::State::new(&mut ctx, location::Source::InMemory),
);
let parsed = DialectName::parser(()).parse(state_stream).unwrap().0;
assert_eq!(parsed.disp(&ctx).to_string(), "builtin");
}
}