gigaparsec-0.2.4.0: src/Text/Gigaparsec/Internal/Errors/DefuncError.hs
{-# LANGUAGE Safe #-}
{-# LANGUAGE GADTs, NamedFieldPuns, BinaryLiterals, NumericUnderscores, DataKinds, BangPatterns #-}
{-# OPTIONS_HADDOCK hide #-}
{-# OPTIONS_GHC -Wno-missing-import-lists #-}
module Text.Gigaparsec.Internal.Errors.DefuncError (
DefuncError(presentationOffset),
specialisedError, expectedError, unexpectedError, emptyError,
merge, withHints, withReason, withReasonAndOffset, label,
amend, entrench, dislodge, markAsLexical,
isVanilla, isExpectedEmpty, isLexical
) where
import Data.Word (Word32)
import Data.Bits ((.&.), (.|.), testBit, clearBit, setBit, complement, bit)
import Data.Set (Set)
import Data.Set qualified as Set (null)
import Text.Gigaparsec.Internal.Errors.CaretControl (CaretWidth, Span, isFlexible)
import Text.Gigaparsec.Internal.Errors.DefuncTypes (
DefuncError(..), DefuncError_(..), ErrKindSingleton(..),
ErrorOp(..), BaseError(..),
DefuncHints(..)
)
import Text.Gigaparsec.Internal.Errors.ErrorItem (ExpectItem)
{-# INLINABLE isVanilla #-}
isVanilla :: DefuncError -> Bool
isVanilla DefuncError{flags} = testBit flags vanillaBit
{-# INLINABLE isExpectedEmpty #-}
isExpectedEmpty :: DefuncError -> Bool
isExpectedEmpty DefuncError{flags} = testBit flags expectedEmptyBit
{-# INLINABLE entrenchedBy #-}
entrenchedBy :: DefuncError -> Word32
entrenchedBy DefuncError{flags} = flags .&. entrenchedMask
{-# INLINABLE entrenched #-}
entrenched :: DefuncError -> Bool
entrenched err = entrenchedBy err > 0
{-# INLINABLE isFlexibleCaret #-}
isFlexibleCaret :: DefuncError -> Bool
isFlexibleCaret DefuncError{flags} = testBit flags flexibleCaretBit
{-# INLINABLE isLexical #-}
isLexical :: DefuncError -> Bool
isLexical DefuncError{flags} = testBit flags lexicalBit
-- Base Errors
specialisedError :: Word -> Word -> Word -> [String] -> CaretWidth -> DefuncError
specialisedError !pOff !line !col !msgs caret =
DefuncError IsSpecialised flags pOff pOff (Base line col (ClassicSpecialised msgs caret))
where flags :: Word32
!flags
| isFlexible caret = setBit (bit expectedEmptyBit) flexibleCaretBit
| otherwise = bit expectedEmptyBit
emptyError :: Word -> Word -> Word -> Span -> DefuncError
emptyError !pOff !line !col !unexWidth =
DefuncError IsVanilla flags pOff pOff (Base line col (Empty unexWidth))
where flags :: Word32
!flags = setBit (bit vanillaBit) expectedEmptyBit
expectedError :: Word -> Word -> Word -> Set ExpectItem -> Span -> DefuncError
expectedError !pOff !line !col !exs !unexWidth =
DefuncError IsVanilla flags pOff pOff (Base line col (Expected exs unexWidth))
where flags :: Word32
!flags
| Set.null exs = setBit (bit vanillaBit) expectedEmptyBit
| otherwise = bit vanillaBit
unexpectedError :: Word -> Word -> Word -> Set ExpectItem -> String -> CaretWidth -> DefuncError
unexpectedError !pOff !line !col !exs !unex caretWidth =
DefuncError IsVanilla flags pOff pOff (Base line col (Unexpected exs unex caretWidth))
where flags :: Word32
!flags
| Set.null exs = setBit (bit vanillaBit) expectedEmptyBit
| otherwise = bit vanillaBit
-- Operations
merge :: DefuncError -> DefuncError -> DefuncError
merge err1@(DefuncError k1 flags1 pOff1 uOff1 errTy1)
err2@(DefuncError k2 flags2 pOff2 uOff2 errTy2) =
case compare uOff1 uOff2 of
GT -> err1
LT -> err2
EQ -> case compare pOff1 pOff2 of
GT -> err1
LT -> err2
EQ -> case k1 of
IsSpecialised -> case k2 of
IsSpecialised ->
DefuncError IsSpecialised (combineFlags flags1 flags2) pOff1 uOff1 (Op (Merged errTy1 errTy2))
IsVanilla | isFlexibleCaret err1 ->
DefuncError IsSpecialised flags1 pOff1 uOff1 (Op (AdjustCaret errTy1 errTy2))
_ -> err1
IsVanilla -> case k2 of
IsVanilla ->
DefuncError IsVanilla (combineFlags flags1 flags2) pOff1 uOff1 (Op (Merged errTy1 errTy2))
IsSpecialised | isFlexibleCaret err2 ->
DefuncError IsSpecialised flags1 pOff1 uOff1 (Op (AdjustCaret errTy2 errTy1))
_ -> err2
where combineFlags f1 f2 =
(f1 .&. f2 .&. complement entrenchedMask) .|. max (f1 .&. entrenchedMask) (f2 .&. entrenchedMask)
withHints :: DefuncHints -> DefuncError -> DefuncError
withHints Blank err = err
withHints hints (DefuncError IsVanilla flags pOff uOff errTy) =
DefuncError IsVanilla (clearBit flags expectedEmptyBit) pOff uOff (Op (WithHints errTy hints))
withHints _ err = err
withReasonAndOffset :: String -> Word -> DefuncError -> DefuncError
withReasonAndOffset !reason !off (DefuncError IsVanilla flags pOff uOff errTy) | pOff == off =
DefuncError IsVanilla flags pOff uOff (Op (WithReason errTy reason))
withReasonAndOffset _ _ err = err
withReason :: String -> DefuncError -> DefuncError
withReason !reason err = withReasonAndOffset reason (presentationOffset err) err
label :: Word -> Set String -> DefuncError -> DefuncError
label !off !labels (DefuncError IsVanilla flags pOff uOff errTy) | pOff == off =
DefuncError IsVanilla flags' pOff uOff (Op (WithLabel errTy labels))
where !flags'
| Set.null labels = setBit flags expectedEmptyBit
| otherwise = clearBit flags expectedEmptyBit
label _ _ err = err
amend :: Bool -> Word -> Word -> Word -> DefuncError -> DefuncError
amend !partial !pOff !line !col err@(DefuncError k flags _ uOff errTy)
| entrenched err = err
| otherwise = DefuncError k flags pOff uOff' (Op (Amended line col errTy))
where
!uOff' = if partial then uOff else pOff
entrench :: DefuncError -> DefuncError
entrench (DefuncError k flags pOff uOff errTy) = DefuncError k (flags + 1) pOff uOff errTy
dislodge :: Word32 -> DefuncError -> DefuncError
dislodge by err@(DefuncError k flags pOff uOff errTy)
| eBy == 0 = err
| eBy > by = DefuncError k (flags - by) pOff uOff errTy
| otherwise = DefuncError k (flags .&. complement entrenchedMask) pOff uOff errTy
where !eBy = entrenchedBy err
markAsLexical :: Word -> DefuncError -> DefuncError
markAsLexical !off (DefuncError IsVanilla flags pOff uOff errTy) | off < pOff =
DefuncError IsVanilla (setBit flags lexicalBit) pOff uOff errTy
markAsLexical _ err = err
-- FLAG MASKS
{-# INLINE vanillaBit #-}
{-# INLINE expectedEmptyBit #-}
{-# INLINE lexicalBit #-}
{-# INLINE flexibleCaretBit #-}
{-# INLINE entrenchedMask #-}
vanillaBit, expectedEmptyBit, lexicalBit, flexibleCaretBit :: Int
vanillaBit = 31
expectedEmptyBit = 30
lexicalBit = 29
flexibleCaretBit = 28
entrenchedMask :: Word32
entrenchedMask = 0b00001111_11111111_11111111_11111111