diff --git a/HSCParser.hs b/HSCParser.hs index d855cf10e57d1cd691b563491ebc2fd38b7b046f..478faf0679665dde5c2bfac1618a2e169b185181 100644 --- a/HSCParser.hs +++ b/HSCParser.hs @@ -100,6 +100,9 @@ anyChar_ = do any2Chars_ :: Parser () any2Chars_ = anyChar_ >> anyChar_ +any3Chars_ :: Parser () +any3Chars_ = anyChar_ >> anyChar_ >> anyChar_ + many :: Parser a -> Parser [a] many p = many1 p `mplus` return [] @@ -161,12 +164,57 @@ text = do _ -> do return () `fakeOutput` unescapeHashes symb text - '\"':_ -> do anyChar_; hsString '\"'; text - '\'':_ -> do anyChar_; hsString '\''; text - '{':'-':_ -> do any2Chars_; linePragma `mplus` - columnPragma `mplus` - hsComment; text - _:_ -> do anyChar_; text + '\"':_ -> do anyChar_; hsString '\"'; text + -- See Note [Single Quotes] + '\'':'\\':_ -> do any2Chars_; hsString '\''; text -- Case 1 + '\'':d:'\'':_ -> do any3Chars_; text -- Case 2 + '\'':d:_ | isSpace d -> do -- Case 3 + any2Chars_ + manySatisfy_ (\c' -> isSpace c') + manySatisfy_ (\c' -> isAlphaNum c' || c' == '_' || c' == '\'') + text + '\'':_ -> do -- Case 4 + anyChar_ + manySatisfy_ (\c' -> isAlphaNum c' || c' == '_' || c' == '\'') + text + '{':'-':_ -> do + any2Chars_ + linePragma `mplus` columnPragma `mplus` hsComment + text + _:_ -> do anyChar_; text + +-- Note [Single Quotes] +-- +-- hsc2hs performs some tricks to figure out if we are looking at character +-- literal or a promoted data constructor. In order, the cases considered are: +-- +-- 1. quote-backslash: An escape sequence character literal. Since these +-- escape sequences have several different possible lengths, hsc2hs will +-- consume everything after this until another single quote is encountered. +-- 2. quote-any-quote: A character literal. Consumes the triplet. +-- 3. quote-space: Here, the order of the patterns becomes important. This +-- case and the case below handle promoted data constructors. This one +-- is to handle data constructor that end in a quote. They have special +-- syntax for promotion that requires adding a leading space. After an +-- arbitrary number of initial space characters, consume +-- all alphanumeric characters and quotes, considering them part of the +-- identifier. +-- 4. quote: If nothing else matched, we assume we are dealing with a normal +-- promoted data constructor. Consume all alphanumeric characters and +-- quotes, considering them part of the identifier. +-- +-- Here are some lines of code for which at one of the described cases +-- would be matched at some point: +-- +-- data Foo = Foo' | Bar +-- +-- main :: IO () +-- main = do +-- 1> putChar 'x' +-- 2> putChar '\NUL' +-- 3> let y = Proxy :: Proxy ' Foo' +-- 4> let x = Proxy :: Proxy 'Bar +-- pure () hsString :: Char -> Parser () hsString quote = do diff --git a/changelog.md b/changelog.md index 07812af836b060f7352cd731440ce118784c8102..33e88774c741ce58e748ce2fd72fbef8dc229b99 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,9 @@ - Support for non-x86 platforms should be significantly more robust due to improvements in `hsc2hs`'s assembly parser + - Add support for haskell files that use a leading single quote for promoted + data constructors. + ## 0.68.4 - Add support to read command line arguments supplied via response files