@@ -36,20 +36,35 @@ pub enum LitError {
3636 InvalidSuffix ( Symbol ) ,
3737 InvalidIntSuffix ( Symbol ) ,
3838 InvalidFloatSuffix ( Symbol ) ,
39+ InvalidNegation ( token:: LitKind ) ,
3940 NonDecimalFloat ( u32 ) , // u32 is the base
4041 IntTooLarge ( u32 ) , // u32 is the base
4142}
4243
4344impl LitKind {
4445 /// Converts literal token into a semantic literal.
4546 pub fn from_token_lit ( lit : token:: Lit ) -> Result < LitKind , LitError > {
47+ Self :: from_token_lit_maybe_negated ( lit, false )
48+ }
49+
50+ /// Converts literal token into a semantic literal.
51+ /// May optionally include a sign, and will error if a literal
52+ /// other than integer or float literals is negated.
53+ pub fn from_token_lit_maybe_negated (
54+ lit : token:: Lit ,
55+ negated : bool ,
56+ ) -> Result < LitKind , LitError > {
4657 let token:: Lit { kind, symbol, suffix } = lit;
4758 if let Some ( suffix) = suffix
4859 && !kind. may_have_suffix ( )
4960 {
5061 return Err ( LitError :: InvalidSuffix ( suffix) ) ;
5162 }
5263
64+ if negated && !matches ! ( kind, token:: Integer | token:: Float ) {
65+ return Err ( LitError :: InvalidNegation ( kind) ) ;
66+ }
67+
5368 // For byte/char/string literals, chars and escapes have already been
5469 // checked in the lexer (in `cook_lexer_literal`). So we can assume all
5570 // chars and escapes are valid here.
@@ -71,8 +86,8 @@ impl LitKind {
7186
7287 // There are some valid suffixes for integer and float literals,
7388 // so all the handling is done internally.
74- token:: Integer => return integer_lit ( symbol, suffix) ,
75- token:: Float => return float_lit ( symbol, suffix) ,
89+ token:: Integer => return integer_lit ( symbol, suffix, negated ) ,
90+ token:: Float => return float_lit ( symbol, suffix, negated ) ,
7691
7792 token:: Str => {
7893 // If there are no characters requiring special treatment we can
@@ -189,14 +204,21 @@ impl fmt::Display for LitKind {
189204 let symbol = str:: from_utf8 ( bytes) . unwrap ( ) ;
190205 write ! ( f, "cr{delim}\" {symbol}\" {delim}" , delim = "#" . repeat( n as usize ) , ) ?;
191206 }
192- LitKind :: Int ( n, ty) => {
193- write ! ( f, "{n}" ) ?;
194- match ty {
195- ast:: LitIntType :: Unsigned ( ty) => write ! ( f, "{}" , ty. name( ) ) ?,
196- ast:: LitIntType :: Signed ( ty) => write ! ( f, "{}" , ty. name( ) ) ?,
197- ast:: LitIntType :: Unsuffixed => { }
207+ LitKind :: Int ( n, ty) => match ty {
208+ ast:: LitIntType :: Unsigned ( ty) => write ! ( f, "{n}{}" , ty. name( ) ) ?,
209+ ast:: LitIntType :: Signed ( ty, negated) => {
210+ if negated {
211+ write ! ( f, "-" ) ?;
212+ }
213+ write ! ( f, "{n}{}" , ty. name( ) ) ?
198214 }
199- }
215+ ast:: LitIntType :: Unsuffixed ( negated) => {
216+ if negated {
217+ write ! ( f, "-" ) ?;
218+ }
219+ write ! ( f, "{n}" ) ?;
220+ }
221+ } ,
200222 LitKind :: Float ( symbol, ty) => {
201223 write ! ( f, "{symbol}" ) ?;
202224 match ty {
@@ -269,11 +291,13 @@ fn filtered_float_lit(
269291 symbol : Symbol ,
270292 suffix : Option < Symbol > ,
271293 base : u32 ,
294+ negated : bool ,
272295) -> Result < LitKind , LitError > {
273- debug ! ( "filtered_float_lit: {:?}, {:?}, {:?}" , symbol , suffix , base ) ;
296+ debug ! ( ?symbol , ?suffix , ?base , ?negated ) ;
274297 if base != 10 {
275298 return Err ( LitError :: NonDecimalFloat ( base) ) ;
276299 }
300+ let symbol = if negated { Symbol :: intern ( & format ! ( "-{}" , symbol. as_str( ) ) ) } else { symbol } ;
277301 Ok ( match suffix {
278302 Some ( suffix) => LitKind :: Float (
279303 symbol,
@@ -289,12 +313,12 @@ fn filtered_float_lit(
289313 } )
290314}
291315
292- fn float_lit ( symbol : Symbol , suffix : Option < Symbol > ) -> Result < LitKind , LitError > {
316+ fn float_lit ( symbol : Symbol , suffix : Option < Symbol > , negated : bool ) -> Result < LitKind , LitError > {
293317 debug ! ( "float_lit: {:?}, {:?}" , symbol, suffix) ;
294- filtered_float_lit ( strip_underscores ( symbol) , suffix, 10 )
318+ filtered_float_lit ( strip_underscores ( symbol) , suffix, 10 , negated )
295319}
296320
297- fn integer_lit ( symbol : Symbol , suffix : Option < Symbol > ) -> Result < LitKind , LitError > {
321+ fn integer_lit ( symbol : Symbol , suffix : Option < Symbol > , negated : bool ) -> Result < LitKind , LitError > {
298322 debug ! ( "integer_lit: {:?}, {:?}" , symbol, suffix) ;
299323 let symbol = strip_underscores ( symbol) ;
300324 let s = symbol. as_str ( ) ;
@@ -308,12 +332,12 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
308332
309333 let ty = match suffix {
310334 Some ( suf) => match suf {
311- sym:: isize => ast:: LitIntType :: Signed ( ast:: IntTy :: Isize ) ,
312- sym:: i8 => ast:: LitIntType :: Signed ( ast:: IntTy :: I8 ) ,
313- sym:: i16 => ast:: LitIntType :: Signed ( ast:: IntTy :: I16 ) ,
314- sym:: i32 => ast:: LitIntType :: Signed ( ast:: IntTy :: I32 ) ,
315- sym:: i64 => ast:: LitIntType :: Signed ( ast:: IntTy :: I64 ) ,
316- sym:: i128 => ast:: LitIntType :: Signed ( ast:: IntTy :: I128 ) ,
335+ sym:: isize => ast:: LitIntType :: Signed ( ast:: IntTy :: Isize , negated ) ,
336+ sym:: i8 => ast:: LitIntType :: Signed ( ast:: IntTy :: I8 , negated ) ,
337+ sym:: i16 => ast:: LitIntType :: Signed ( ast:: IntTy :: I16 , negated ) ,
338+ sym:: i32 => ast:: LitIntType :: Signed ( ast:: IntTy :: I32 , negated ) ,
339+ sym:: i64 => ast:: LitIntType :: Signed ( ast:: IntTy :: I64 , negated ) ,
340+ sym:: i128 => ast:: LitIntType :: Signed ( ast:: IntTy :: I128 , negated ) ,
317341 sym:: usize => ast:: LitIntType :: Unsigned ( ast:: UintTy :: Usize ) ,
318342 sym:: u8 => ast:: LitIntType :: Unsigned ( ast:: UintTy :: U8 ) ,
319343 sym:: u16 => ast:: LitIntType :: Unsigned ( ast:: UintTy :: U16 ) ,
@@ -322,11 +346,18 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
322346 sym:: u128 => ast:: LitIntType :: Unsigned ( ast:: UintTy :: U128 ) ,
323347 // `1f64` and `2f32` etc. are valid float literals, and
324348 // `fxxx` looks more like an invalid float literal than invalid integer literal.
325- _ if suf. as_str ( ) . starts_with ( 'f' ) => return filtered_float_lit ( symbol, suffix, base) ,
349+ _ if suf. as_str ( ) . starts_with ( 'f' ) => {
350+ return filtered_float_lit ( symbol, suffix, base, negated) ;
351+ }
326352 _ => return Err ( LitError :: InvalidIntSuffix ( suf) ) ,
327353 } ,
328- _ => ast:: LitIntType :: Unsuffixed ,
354+ _ => ast:: LitIntType :: Unsuffixed ( negated ) ,
329355 } ;
356+ if let ast:: LitIntType :: Unsigned ( _) = ty
357+ && negated
358+ {
359+ return Err ( LitError :: InvalidNegation ( token:: Integer ) ) ;
360+ }
330361
331362 let s = & s[ if base != 10 { 2 } else { 0 } ..] ;
332363 u128:: from_str_radix ( s, base)
0 commit comments