use std::collections::HashMap;
use std::num::Wrapping;
use std::ops::{
AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, ShlAssign,
ShrAssign, SubAssign,
};
use crate::literal::{self, CChar};
use crate::token::{Kind as TokenKind, Token};
use crate::ToCexprResult;
use nom::branch::alt;
use nom::combinator::{complete, map, map_opt};
use nom::multi::{fold_many0, many0, separated_list0};
use nom::sequence::{delimited, pair, preceded};
use nom::*;
#[derive(Debug)]
pub struct IdentifierParser<'ident> {
identifiers: &'ident HashMap<Vec<u8>, EvalResult>,
}
#[derive(Copy, Clone)]
struct PRef<'a>(&'a IdentifierParser<'a>);
pub type CResult<'a, R> = IResult<&'a [Token], R, crate::Error<&'a [Token]>>;
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum EvalResult {
Int(Wrapping<i64>),
Float(f64),
Char(CChar),
Str(Vec<u8>),
Invalid,
}
macro_rules! result_opt (
(fn $n:ident: $e:ident -> $t:ty) => (
#[allow(dead_code)]
#[allow(clippy::wrong_self_convention)]
fn $n(self) -> Option<$t> {
if let EvalResult::$e(v) = self {
Some(v)
} else {
None
}
}
);
);
impl EvalResult {
result_opt!(fn as_int: Int -> Wrapping<i64>);
result_opt!(fn as_float: Float -> f64);
result_opt!(fn as_char: Char -> CChar);
result_opt!(fn as_str: Str -> Vec<u8>);
#[allow(clippy::wrong_self_convention)]
fn as_numeric(self) -> Option<EvalResult> {
match self {
EvalResult::Int(_) | EvalResult::Float(_) => Some(self),
_ => None,
}
}
}
impl From<Vec<u8>> for EvalResult {
fn from(s: Vec<u8>) -> EvalResult {
EvalResult::Str(s)
}
}
macro_rules! exact_token (
($k:ident, $c:expr) => ({
move |input: &[Token]| {
if input.is_empty() {
let res: CResult<'_, &[u8]> = Err(crate::nom::Err::Incomplete(Needed::new($c.len())));
res
} else {
if input[0].kind==TokenKind::$k && &input[0].raw[..]==$c {
Ok((&input[1..], &input[0].raw[..]))
} else {
Err(crate::nom::Err::Error((input, crate::ErrorKind::ExactToken(TokenKind::$k,$c)).into()))
}
}
}
});
);
fn identifier_token(input: &[Token]) -> CResult<'_, &[u8]> {
if input.is_empty() {
let res: CResult<'_, &[u8]> = Err(nom::Err::Incomplete(Needed::new(1)));
res
} else {
if input[0].kind == TokenKind::Identifier {
Ok((&input[1..], &input[0].raw[..]))
} else {
Err(crate::nom::Err::Error((input, crate::ErrorKind::TypedToken(TokenKind::Identifier)).into()))
}
}
}
fn p(c: &'static str) -> impl Fn(&[Token]) -> CResult<'_, &[u8]> {
exact_token!(Punctuation, c.as_bytes())
}
fn one_of_punctuation(c: &'static [&'static str]) -> impl Fn(&[Token]) -> CResult<'_, &[u8]> {
move |input| {
if input.is_empty() {
let min = c
.iter()
.map(|opt| opt.len())
.min()
.expect("at least one option");
Err(crate::nom::Err::Incomplete(Needed::new(min)))
} else if input[0].kind == TokenKind::Punctuation
&& c.iter().any(|opt| opt.as_bytes() == &input[0].raw[..])
{
Ok((&input[1..], &input[0].raw[..]))
} else {
Err(crate::nom::Err::Error(
(
input,
crate::ErrorKind::ExactTokens(TokenKind::Punctuation, c),
)
.into(),
))
}
}
}
impl<'a> AddAssign<&'a EvalResult> for EvalResult {
fn add_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a + b),
(&Float(a), &Int(b)) => Float(a + (b.0 as f64)),
(&Int(a), &Float(b)) => Float(a.0 as f64 + b),
(&Float(a), &Float(b)) => Float(a + b),
_ => Invalid,
};
}
}
impl<'a> BitAndAssign<&'a EvalResult> for EvalResult {
fn bitand_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a & b),
_ => Invalid,
};
}
}
impl<'a> BitOrAssign<&'a EvalResult> for EvalResult {
fn bitor_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a | b),
_ => Invalid,
};
}
}
impl<'a> BitXorAssign<&'a EvalResult> for EvalResult {
fn bitxor_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a ^ b),
_ => Invalid,
};
}
}
impl<'a> DivAssign<&'a EvalResult> for EvalResult {
fn div_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a / b),
(&Float(a), &Int(b)) => Float(a / (b.0 as f64)),
(&Int(a), &Float(b)) => Float(a.0 as f64 / b),
(&Float(a), &Float(b)) => Float(a / b),
_ => Invalid,
};
}
}
impl<'a> MulAssign<&'a EvalResult> for EvalResult {
fn mul_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a * b),
(&Float(a), &Int(b)) => Float(a * (b.0 as f64)),
(&Int(a), &Float(b)) => Float(a.0 as f64 * b),
(&Float(a), &Float(b)) => Float(a * b),
_ => Invalid,
};
}
}
impl<'a> RemAssign<&'a EvalResult> for EvalResult {
fn rem_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a % b),
(&Float(a), &Int(b)) => Float(a % (b.0 as f64)),
(&Int(a), &Float(b)) => Float(a.0 as f64 % b),
(&Float(a), &Float(b)) => Float(a % b),
_ => Invalid,
};
}
}
impl<'a> ShlAssign<&'a EvalResult> for EvalResult {
fn shl_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a << (b.0 as usize)),
_ => Invalid,
};
}
}
impl<'a> ShrAssign<&'a EvalResult> for EvalResult {
fn shr_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a >> (b.0 as usize)),
_ => Invalid,
};
}
}
impl<'a> SubAssign<&'a EvalResult> for EvalResult {
fn sub_assign(&mut self, rhs: &'a EvalResult) {
use self::EvalResult::*;
*self = match (&*self, rhs) {
(&Int(a), &Int(b)) => Int(a - b),
(&Float(a), &Int(b)) => Float(a - (b.0 as f64)),
(&Int(a), &Float(b)) => Float(a.0 as f64 - b),
(&Float(a), &Float(b)) => Float(a - b),
_ => Invalid,
};
}
}
fn unary_op(input: (&[u8], EvalResult)) -> Option<EvalResult> {
use self::EvalResult::*;
assert_eq!(input.0.len(), 1);
match (input.0[0], input.1) {
(b'+', i) => Some(i),
(b'-', Int(i)) => Some(Int(Wrapping(i.0.wrapping_neg()))), (b'-', Float(i)) => Some(Float(-i)),
(b'-', _) => unreachable!("non-numeric unary op"),
(b'~', Int(i)) => Some(Int(!i)),
(b'~', Float(_)) => None,
(b'~', _) => unreachable!("non-numeric unary op"),
_ => unreachable!("invalid unary op"),
}
}
fn numeric<I: Clone, E: nom::error::ParseError<I>, F>(
f: F,
) -> impl FnMut(I) -> nom::IResult<I, EvalResult, E>
where
F: FnMut(I) -> nom::IResult<I, EvalResult, E>,
{
nom::combinator::map_opt(f, EvalResult::as_numeric)
}
impl<'a> PRef<'a> {
fn unary(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
alt((
delimited(p("("), |i| self.numeric_expr(i), p(")")),
numeric(|i| self.literal(i)),
numeric(|i| self.identifier(i)),
map_opt(
pair(one_of_punctuation(&["+", "-", "~"][..]), |i| self.unary(i)),
unary_op,
),
))(input)
}
fn mul_div_rem(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
let (input, acc) = self.unary(input)?;
fold_many0(
pair(complete(one_of_punctuation(&["*", "/", "%"][..])), |i| {
self.unary(i)
}),
move || acc.clone(),
|mut acc, (op, val): (&[u8], EvalResult)| {
match op[0] as char {
'*' => acc *= &val,
'/' => acc /= &val,
'%' => acc %= &val,
_ => unreachable!(),
};
acc
},
)(input)
}
fn add_sub(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
let (input, acc) = self.mul_div_rem(input)?;
fold_many0(
pair(complete(one_of_punctuation(&["+", "-"][..])), |i| {
self.mul_div_rem(i)
}),
move || acc.clone(),
|mut acc, (op, val): (&[u8], EvalResult)| {
match op[0] as char {
'+' => acc += &val,
'-' => acc -= &val,
_ => unreachable!(),
};
acc
},
)(input)
}
fn shl_shr(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
let (input, acc) = self.add_sub(input)?;
numeric(fold_many0(
pair(complete(one_of_punctuation(&["<<", ">>"][..])), |i| {
self.add_sub(i)
}),
move || acc.clone(),
|mut acc, (op, val): (&[u8], EvalResult)| {
match op {
b"<<" => acc <<= &val,
b">>" => acc >>= &val,
_ => unreachable!(),
};
acc
},
))(input)
}
fn and(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
let (input, acc) = self.shl_shr(input)?;
numeric(fold_many0(
preceded(complete(p("&")), |i| self.shl_shr(i)),
move || acc.clone(),
|mut acc, val: EvalResult| {
acc &= &val;
acc
},
))(input)
}
fn xor(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
let (input, acc) = self.and(input)?;
numeric(fold_many0(
preceded(complete(p("^")), |i| self.and(i)),
move || acc.clone(),
|mut acc, val: EvalResult| {
acc ^= &val;
acc
},
))(input)
}
fn or(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
let (input, acc) = self.xor(input)?;
numeric(fold_many0(
preceded(complete(p("|")), |i| self.xor(i)),
move || acc.clone(),
|mut acc, val: EvalResult| {
acc |= &val;
acc
},
))(input)
}
#[inline(always)]
fn numeric_expr(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
self.or(input)
}
}
impl<'a> PRef<'a> {
fn identifier(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
match input.split_first() {
None => Err(Err::Incomplete(Needed::new(1))),
Some((
&Token {
kind: TokenKind::Identifier,
ref raw,
},
rest,
)) => {
if let Some(r) = self.identifiers.get(&raw[..]) {
Ok((rest, r.clone()))
} else {
Err(Err::Error(
(input, crate::ErrorKind::UnknownIdentifier).into(),
))
}
}
Some(_) => Err(Err::Error(
(input, crate::ErrorKind::TypedToken(TokenKind::Identifier)).into(),
)),
}
}
fn literal(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
match input.split_first() {
None => Err(Err::Incomplete(Needed::new(1))),
Some((
&Token {
kind: TokenKind::Literal,
ref raw,
},
rest,
)) => match literal::parse(raw) {
Ok((_, result)) => Ok((rest, result)),
_ => Err(Err::Error((input, crate::ErrorKind::InvalidLiteral).into())),
},
Some(_) => Err(Err::Error(
(input, crate::ErrorKind::TypedToken(TokenKind::Literal)).into(),
)),
}
}
fn string(self, input: &'_ [Token]) -> CResult<'_, Vec<u8>> {
alt((
map_opt(|i| self.literal(i), EvalResult::as_str),
map_opt(|i| self.identifier(i), EvalResult::as_str),
))(input)
.to_cexpr_result()
}
fn concat_str(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
map(
pair(|i| self.string(i), many0(complete(|i| self.string(i)))),
|(first, v)| {
Vec::into_iter(v)
.fold(first, |mut s, elem| {
Vec::extend_from_slice(&mut s, Vec::<u8>::as_slice(&elem));
s
})
.into()
},
)(input)
.to_cexpr_result()
}
fn expr(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
alt((
|i| self.numeric_expr(i),
delimited(p("("), |i| self.expr(i), p(")")),
|i| self.concat_str(i),
|i| self.literal(i),
|i| self.identifier(i),
))(input)
.to_cexpr_result()
}
fn macro_definition(self, input: &'_ [Token]) -> CResult<'_, (&'_ [u8], EvalResult)> {
pair(identifier_token, |i| self.expr(i))(input)
}
}
impl<'a> ::std::ops::Deref for PRef<'a> {
type Target = IdentifierParser<'a>;
fn deref(&self) -> &IdentifierParser<'a> {
self.0
}
}
impl<'ident> IdentifierParser<'ident> {
fn as_ref(&self) -> PRef<'_> {
PRef(self)
}
pub fn new(identifiers: &HashMap<Vec<u8>, EvalResult>) -> IdentifierParser<'_> {
IdentifierParser { identifiers }
}
pub fn expr<'a>(&self, input: &'a [Token]) -> CResult<'a, EvalResult> {
self.as_ref().expr(input)
}
pub fn macro_definition<'a>(&self, input: &'a [Token]) -> CResult<'a, (&'a [u8], EvalResult)> {
crate::assert_full_parse(self.as_ref().macro_definition(input))
}
}
pub fn expr(input: &[Token]) -> CResult<'_, EvalResult> {
IdentifierParser::new(&HashMap::new()).expr(input)
}
pub fn macro_definition(input: &[Token]) -> CResult<'_, (&'_ [u8], EvalResult)> {
IdentifierParser::new(&HashMap::new()).macro_definition(input)
}
pub fn fn_macro_declaration(input: &[Token]) -> CResult<'_, (&[u8], Vec<&[u8]>)> {
pair(
identifier_token,
delimited(
p("("),
separated_list0(p(","), identifier_token),
p(")"),
),
)(input)
}