@@ -17,7 +17,7 @@ import Data.List (intersperse)
1717import BNFC.CF
1818import BNFC.Backend.Common.StrUtils (escapeChars )
1919import BNFC.Backend.Haskell.Utils
20- import BNFC.Options (HappyMode (.. ), TokenText (.. ))
20+ import BNFC.Options (HappyMode (.. ), TokenText (.. ), ErrorType ( .. ) )
2121import BNFC.PrettyPrint
2222import BNFC.Utils
2323
@@ -42,17 +42,18 @@ cf2Happy
4242 -> HappyMode -- ^ Happy mode.
4343 -> TokenText -- ^ Use @ByteString@ or @Text@?
4444 -> Bool -- ^ AST is a functor?
45+ -> ErrorType -- ^ The error type in the parser result type.
4546 -> CF -- ^ Grammar.
4647 -> String -- ^ Generated code.
47- cf2Happy name absName lexName mode tokenText functor cf = unlines
48+ cf2Happy name absName lexName mode tokenText functor errorType cf = unlines
4849 [ header name absName lexName tokenText eps
4950 , render $ declarations mode functor eps
5051 , render $ tokens cf functor
5152 , delimiter
5253 , specialRules absName functor tokenText cf
5354 , render $ prRules absName functor (rulesForHappy absName functor cf)
5455 , " "
55- , footer absName tokenText functor eps cf
56+ , footer absName tokenText functor eps errorType cf
5657 ]
5758 where
5859 eps = toList $ allEntryPoints cf
@@ -66,7 +67,14 @@ header modName absName lexName tokenText eps = unlines $ concat
6667 , " {-# LANGUAGE PatternSynonyms #-}"
6768 , " "
6869 , " module " ++ modName
69- , " ( happyError"
70+ , " ( Err"
71+ , " , Failure(..)"
72+ , " , InvalidTokenFailure(..)"
73+ , " , UnexpectedTokenFailure(..)"
74+ , " , UnexpectedEofFailure(..)"
75+ -- TODO: maybe we should stop exporting happyError, since there is no reason
76+ -- to use it outside and its type can vary?
77+ , " , happyError"
7078 , " , myLexer"
7179 ]
7280 , map ((" , " ++ ) . render . parserName) eps
@@ -91,6 +99,8 @@ header modName absName lexName tokenText eps = unlines $ concat
9199-- -- no lexer declaration
92100-- %monad { Err } { (>>=) } { return }
93101-- %tokentype {Token}
102+ -- %errorhandlertype explist
103+ -- %error { happyError }
94104--
95105-- >>> declarations Standard True [Cat "A", Cat "B", ListCat (Cat "B")]
96106-- %name pA_internal A
@@ -99,14 +109,18 @@ header modName absName lexName tokenText eps = unlines $ concat
99109-- -- no lexer declaration
100110-- %monad { Err } { (>>=) } { return }
101111-- %tokentype {Token}
112+ -- %errorhandlertype explist
113+ -- %error { happyError }
102114declarations :: HappyMode -> Bool -> [Cat ] -> Doc
103115declarations mode functor ns = vcat
104116 [ vcat $ map generateP ns
105117 , case mode of
106118 Standard -> " -- no lexer declaration"
107- GLR -> " %lexer { myLexer } { Err _ }" ,
108- " %monad { Err } { (>>=) } { return }" ,
109- " %tokentype" <+> braces (text tokenName)
119+ GLR -> " %lexer { myLexer } { Err _ }"
120+ , " %monad { Err } { (>>=) } { return }"
121+ , " %tokentype" <+> braces (text tokenName)
122+ , " %errorhandlertype explist"
123+ , " %error { happyError }"
110124 ]
111125 where
112126 generateP n = " %name" <+> parserName n <> (if functor then " _internal" else " " ) <+> text (identCat n)
@@ -255,24 +269,88 @@ prRules absM functor = vsep . map prOne
255269
256270-- Finally, some haskell code.
257271
258- footer :: ModuleName -> TokenText -> Bool -> [Cat ] -> CF -> String
259- footer absName tokenText functor eps _cf = unlines $ concat
272+ footer :: ModuleName -> TokenText -> Bool -> [Cat ] -> ErrorType -> CF -> String
273+ footer absName tokenText functor eps errorType _cf = unlines $ concat
260274 [ [ " {"
261275 , " "
262- , " type Err = Either String"
276+ , " -- | The parser failure type."
277+ , " --"
278+ , " -- It can contain fields of more specific failure record types, so that they"
279+ , " -- could easily be extended with new fields."
280+ , " data Failure"
281+ , " = FailureInvalidToken !InvalidTokenFailure"
282+ , " | FailureUnexpectedToken !UnexpectedTokenFailure"
283+ , " | FailureUnexpectedEof !UnexpectedEofFailure"
284+ , " deriving (Show, Eq)"
263285 , " "
264- , " happyError :: [" ++ tokenName ++ " ] -> Err a"
265- , " happyError ts = Left $"
266- , " \" syntax error at \" ++ tokenPos ts ++ "
267- , " case ts of"
268- , " [] -> []"
269- , " [Err _] -> \" due to lexer error\" "
270- , unwords
271- [ " t:_ -> \" before `\" ++"
272- , " (prToken t)"
273- -- , tokenTextUnpack tokenText "(prToken t)"
274- , " ++ \" '\" "
275- ]
286+ , " -- | The lexer error type."
287+ , " newtype InvalidTokenFailure = InvalidTokenFailure"
288+ , " { itfPosn :: Posn -- ^ The position of the beginning of an invalid token."
289+ , " } deriving (Show, Eq)"
290+ , " "
291+ , " -- | The parser error: no production is found to match a token."
292+ , " data UnexpectedTokenFailure = UnexpectedTokenFailure"
293+ , " { utfPosn :: !Posn -- ^ The position of the beginning of the unexpected token."
294+ , " , utfTokenText :: !(" ++ tokenTextType tokenText ++ " )"
295+ , " , utfExpectedTokens :: [String] -- ^ Names of possible tokens at this position according to the grammar."
296+ , " } deriving (Show, Eq)"
297+ , " "
298+ , " -- | The parser error: the end of file is encountered but a token is expected."
299+ , " newtype UnexpectedEofFailure = UnexpectedEofFailure"
300+ , " { ueofExpectedTokens :: [String] -- ^ Names of possible tokens at this position according to the grammar."
301+ , " } deriving (Show, Eq)"
302+ , " "
303+ ]
304+ , case errorType of
305+ ErrorTypeStructured ->
306+ [ " type Err = Either Failure"
307+ , " "
308+ , " happyError :: ([" ++ tokenName ++ " ], [String]) -> Err a"
309+ , " happyError = Left . uncurry mkFailure"
310+ ]
311+ ErrorTypeString ->
312+ [ " type Err = Either String"
313+ , " "
314+ , " happyError :: ([" ++ tokenName ++ " ], [String]) -> Err a"
315+ , " happyError = Left . failureToString . uncurry mkFailure"
316+ , " "
317+ , " failureToString :: Failure -> String"
318+ , " failureToString f ="
319+ , " \" syntax error at \" ++ pos ++ "
320+ , " case f of"
321+ , " FailureUnexpectedEof _ -> []"
322+ , " FailureInvalidToken _ -> \" due to lexer error\" "
323+ , unwords
324+ [ " FailureUnexpectedToken ut -> \" before `\" ++"
325+ , tokenTextUnpack tokenText " (utfTokenText ut)"
326+ , " ++ \" '\" "
327+ ]
328+ , " where"
329+ , " pos = case f of"
330+ , " FailureInvalidToken it -> printPosn (itfPosn it)"
331+ , " FailureUnexpectedToken ut -> printPosn (utfPosn ut)"
332+ , " FailureUnexpectedEof _ -> \" end of file\" "
333+ ]
334+ , [ " "
335+ , " mkFailure :: [" ++ tokenName ++ " ] -> [String] -> Failure"
336+ , " mkFailure ts expectedTokens = case ts of"
337+ , " [] ->"
338+ , " FailureUnexpectedEof"
339+ , " UnexpectedEofFailure"
340+ , " { ueofExpectedTokens = expectedTokens"
341+ , " }"
342+ , " [Err pos] ->"
343+ , " FailureInvalidToken"
344+ , " InvalidTokenFailure"
345+ , " { itfPosn = pos"
346+ , " }"
347+ , " t : _ ->"
348+ , " FailureUnexpectedToken"
349+ , " UnexpectedTokenFailure"
350+ , " { utfPosn = tokenPosn t"
351+ , " , utfTokenText = tokenText t"
352+ , " , utfExpectedTokens = expectedTokens"
353+ , " }"
276354 , " "
277355 , " myLexer :: " ++ tokenTextType tokenText ++ " -> [" ++ tokenName ++ " ]"
278356 , " myLexer = tokens"
0 commit comments