use std::collections::{HashMap};
use std::marker::{Send, Sync};
use std::mem::{discriminant, Discriminant};
use precedence::PrecedenceLevel;
use token::Token;
use types::*;
#[derive(Clone, Debug, Fail)]
pub enum SpecificationError<T: Token + Send + Sync + 'static> {
#[fail(display = "{} token -> rule mapping was already defined", tk)]
TokenToRuleAlreadyDefined{tk: T}
}
#[derive(Clone)]
pub struct ParserSpec<T: Token + Send + Sync + 'static> {
null_map: HashMap<Discriminant<T>, NullInfo<T>>,
left_map: HashMap<Discriminant<T>, LeftInfo<T>>,
}
impl<T: Token + Send + Sync + 'static> ParserSpec<T>
{
pub fn new() -> ParserSpec<T> {
ParserSpec {
null_map: HashMap::new(),
left_map: HashMap::new(),
}
}
pub fn add_null_assoc(&mut self, token: impl Into<T>, bp: PrecedenceLevel, func: NullDenotation<T>) -> Result<(), SpecificationError<T>> {
let token = token.into();
let disc = discriminant(&token);
if !self.null_map.contains_key(&disc) {
self.null_map.insert(disc, (bp, func));
Ok(())
} else {
Err(SpecificationError::TokenToRuleAlreadyDefined{tk: token})
}
}
pub fn add_left_assoc(&mut self, token: impl Into<T>, bp: PrecedenceLevel, func: LeftDenotation<T>) -> Result<(), SpecificationError<T>> {
let token = token.into();
let disc = discriminant(&token);
if !self.left_map.contains_key(&disc) {
self.left_map.insert(disc, (bp, bp, func));
Ok(())
} else {
Err(SpecificationError::TokenToRuleAlreadyDefined{tk: token})
}
}
pub fn add_left_right_assoc(&mut self, token: impl Into<T>, lbp: PrecedenceLevel, rbp: PrecedenceLevel, func: LeftDenotation<T>) -> Result<(), SpecificationError<T>> {
let token = token.into();
let disc = discriminant(&token);
if !self.left_map.contains_key(&disc) {
self.left_map.insert(disc, (lbp, rbp, func));
Ok(())
} else {
Err(SpecificationError::TokenToRuleAlreadyDefined{tk: token})
}
}
pub fn add_null_associations(&mut self, tokens: impl IntoIterator<Item=impl Into<T>>, bp: PrecedenceLevel, func: NullDenotation<T>) -> Result<(), SpecificationError<T>> {
for token in tokens {
self.add_null_assoc(token, bp, func)?;
}
Ok(())
}
pub fn add_left_associations(&mut self, tokens: impl IntoIterator<Item=impl Into<T>>, bp: PrecedenceLevel, func: LeftDenotation<T>) -> Result<(), SpecificationError<T>> {
for token in tokens {
self.add_left_assoc(token, bp, func)?;
}
Ok(())
}
pub fn add_left_right_associations(&mut self, tokens: impl IntoIterator<Item=impl Into<T>>, lbp: PrecedenceLevel, rbp: PrecedenceLevel, func: LeftDenotation<T>) -> Result<(), SpecificationError<T>>{
for token in tokens {
self.add_left_right_assoc(token, lbp, rbp, func)?;
}
Ok(())
}
pub fn maps(self) -> (HashMap<Discriminant<T>, NullInfo<T>>, HashMap<Discriminant<T>, LeftInfo<T>>) {
return (self.null_map, self.left_map)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parserspec_send() {
fn assert_send<T: Send>() {}
assert_send::<ParserSpec<String>>();
}
#[test]
fn test_parserspec_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<ParserSpec<String>>();
}
}