diff options
author | Vladislav Zavialov <vlad.z.4096@gmail.com> | 2020-07-01 22:56:15 +0300 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-07-27 07:06:56 -0400 |
commit | aee45d9ea8c6cf4ebad4d5c732748923c7865cbe (patch) | |
tree | 3cb1952015aeacdc886ba142f23c97f9b29acae7 /compiler | |
parent | 52685cf7c077c51e3719e3c4dd5ca8257a99c4ea (diff) | |
download | haskell-aee45d9ea8c6cf4ebad4d5c732748923c7865cbe.tar.gz |
Improve NegativeLiterals (#18022, GHC Proposal #344)
Before this patch, NegativeLiterals used to parse x-1 as x (-1).
This may not be what the user expects, and now it is fixed:
x-1 is parsed as (-) x 1.
We achieve this by the following requirement:
* When lexing a negative literal,
it must not be preceded by a 'closing token'.
This also applies to unboxed literals, e.g. -1#.
See GHC Proposal #229 for the definition of a closing token.
A nice consequence of this change is that -XNegativeLiterals becomes a
subset of -XLexicalNegation. In other words, enabling both of those
extensions has the same effect as enabling -XLexicalNegation alone.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/GHC/Parser/Lexer.x | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/compiler/GHC/Parser/Lexer.x b/compiler/GHC/Parser/Lexer.x index 7265e1dffb..7395c53b80 100644 --- a/compiler/GHC/Parser/Lexer.x +++ b/compiler/GHC/Parser/Lexer.x @@ -199,7 +199,6 @@ $docsym = [\| \^ \* \$] -- normal signed numerical literals can only be explicitly negative, -- not explicitly positive (contrast @exponent) @negative = \- -@signed = @negative ? -- ----------------------------------------------------------------------------- @@ -531,12 +530,12 @@ $tab { warnTab } ifExtension BinaryLiteralsBit } { tok_primint positive 2 3 binary } 0[oO] @numspc @octal \# / { ifExtension MagicHashBit } { tok_primint positive 2 3 octal } 0[xX] @numspc @hexadecimal \# / { ifExtension MagicHashBit } { tok_primint positive 2 3 hexadecimal } - @negative @decimal \# / { ifExtension MagicHashBit } { tok_primint negative 1 2 decimal } - @negative 0[bB] @numspc @binary \# / { ifExtension MagicHashBit `alexAndPred` + @negative @decimal \# / { negHashLitPred } { tok_primint negative 1 2 decimal } + @negative 0[bB] @numspc @binary \# / { negHashLitPred `alexAndPred` ifExtension BinaryLiteralsBit } { tok_primint negative 3 4 binary } - @negative 0[oO] @numspc @octal \# / { ifExtension MagicHashBit } { tok_primint negative 3 4 octal } + @negative 0[oO] @numspc @octal \# / { negHashLitPred } { tok_primint negative 3 4 octal } @negative 0[xX] @numspc @hexadecimal \# - / { ifExtension MagicHashBit } { tok_primint negative 3 4 hexadecimal } + / { negHashLitPred } { tok_primint negative 3 4 hexadecimal } @decimal \# \# / { ifExtension MagicHashBit } { tok_primword 0 2 decimal } 0[bB] @numspc @binary \# \# / { ifExtension MagicHashBit `alexAndPred` @@ -546,8 +545,11 @@ $tab { warnTab } -- Unboxed floats and doubles (:: Float#, :: Double#) -- prim_{float,double} work with signed literals - @signed @floating_point \# / { ifExtension MagicHashBit } { tok_frac 1 tok_primfloat } - @signed @floating_point \# \# / { ifExtension MagicHashBit } { tok_frac 2 tok_primdouble } + @floating_point \# / { ifExtension MagicHashBit } { tok_frac 1 tok_primfloat } + @floating_point \# \# / { ifExtension MagicHashBit } { tok_frac 2 tok_primdouble } + + @negative @floating_point \# / { negHashLitPred } { tok_frac 1 tok_primfloat } + @negative @floating_point \# \# / { negHashLitPred } { tok_frac 2 tok_primdouble } } -- Strings and chars are lexed by hand-written code. The reason is @@ -1192,8 +1194,8 @@ atEOL _ _ _ (AI _ buf) = atEnd buf || currentChar buf == '\n' -- Check if we should parse a negative literal (e.g. -123) as a single token. negLitPred :: AlexAccPred ExtsBitmap negLitPred = - negative_literals `alexOrPred` - (lexical_negation `alexAndPred` prefix_minus) + prefix_minus `alexAndPred` + (negative_literals `alexOrPred` lexical_negation) where negative_literals = ifExtension NegativeLiteralsBit @@ -1202,14 +1204,33 @@ negLitPred = alexNotPred (ifExtension NoLexicalNegationBit) prefix_minus = - -- The condition for a prefix occurrence of an operator is: - -- - -- not precededByClosingToken && followedByOpeningToken - -- - -- but we don't check followedByOpeningToken here as it holds - -- simply because we immediately lex a literal after the minus. + -- Note [prefix_minus in negLitPred and negHashLitPred] + alexNotPred precededByClosingToken + +-- Check if we should parse an unboxed negative literal (e.g. -123#) as a single token. +negHashLitPred :: AlexAccPred ExtsBitmap +negHashLitPred = prefix_minus `alexAndPred` magic_hash + where + magic_hash = ifExtension MagicHashBit + prefix_minus = + -- Note [prefix_minus in negLitPred and negHashLitPred] alexNotPred precededByClosingToken +{- Note [prefix_minus in negLitPred and negHashLitPred] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We want to parse -1 as a single token, but x-1 as three tokens. +So in negLitPred (and negHashLitPred) we require that we have a prefix +occurrence of the minus sign. See Note [Whitespace-sensitive operator parsing] +for a detailed definition of a prefix occurrence. + +The condition for a prefix occurrence of an operator is: + + not precededByClosingToken && followedByOpeningToken + +but we don't check followedByOpeningToken when parsing a negative literal. +It holds simply because we immediately lex a literal after the minus. +-} + ifExtension :: ExtBits -> AlexAccPred ExtsBitmap ifExtension extBits bits _ _ _ = extBits `xtest` bits |