Parse negative discriminants
diff --git a/syntax/discriminant.rs b/syntax/discriminant.rs
index 2a55468..06a6d1b 100644
--- a/syntax/discriminant.rs
+++ b/syntax/discriminant.rs
@@ -3,7 +3,7 @@
use std::collections::HashSet;
use std::fmt::{self, Display};
use std::str::FromStr;
-use syn::{Error, Expr, Lit, Result};
+use syn::{Error, Expr, Lit, Result, Token, UnOp};
pub struct DiscriminantSet {
values: HashSet<Discriminant>,
@@ -12,6 +12,7 @@
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Discriminant {
+ negative: bool,
magnitude: u32,
}
@@ -31,6 +32,13 @@
pub fn insert_next(&mut self) -> Result<Discriminant> {
let discriminant = match self.previous {
None => Discriminant::zero(),
+ Some(mut discriminant) if discriminant.negative => {
+ discriminant.magnitude -= 1;
+ if discriminant.magnitude == 0 {
+ discriminant.negative = false;
+ }
+ discriminant
+ }
Some(mut discriminant) => {
if discriminant.magnitude == u32::MAX {
let msg = format!("discriminant overflow on value after {}", u32::MAX);
@@ -45,10 +53,20 @@
}
fn expr_to_discriminant(expr: &Expr) -> Result<Discriminant> {
- if let Expr::Lit(expr) = expr {
- if let Lit::Int(lit) = &expr.lit {
- return lit.base10_parse::<Discriminant>();
+ match expr {
+ Expr::Lit(expr) => {
+ if let Lit::Int(lit) = &expr.lit {
+ return lit.base10_parse::<Discriminant>();
+ }
}
+ Expr::Unary(unary) => {
+ if let UnOp::Neg(_) = unary.op {
+ let mut discriminant = expr_to_discriminant(&unary.expr)?;
+ discriminant.negative ^= true;
+ return Ok(discriminant);
+ }
+ }
+ _ => {}
}
Err(Error::new_spanned(
expr,
@@ -68,18 +86,27 @@
impl Discriminant {
fn zero() -> Self {
- Discriminant { magnitude: 0 }
+ Discriminant {
+ negative: false,
+ magnitude: 0,
+ }
}
}
impl Display for Discriminant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.negative {
+ f.write_str("-")?;
+ }
Display::fmt(&self.magnitude, f)
}
}
impl ToTokens for Discriminant {
fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.negative {
+ Token![-](Span::call_site()).to_tokens(tokens);
+ }
Literal::u32_unsuffixed(self.magnitude).to_tokens(tokens);
}
}
@@ -87,9 +114,16 @@
impl FromStr for Discriminant {
type Err = Error;
- fn from_str(s: &str) -> Result<Self> {
+ fn from_str(mut s: &str) -> Result<Self> {
+ let negative = s.starts_with('-');
+ if negative {
+ s = &s[1..];
+ }
match s.parse::<u32>() {
- Ok(magnitude) => Ok(Discriminant { magnitude }),
+ Ok(magnitude) => Ok(Discriminant {
+ negative,
+ magnitude,
+ }),
Err(_) => Err(Error::new(
Span::call_site(),
"discriminant value outside of supported range",