module Common.Error (formatParseError, formatError, formatFancyError, getExpected, getUnexpected) where
import Data.Text (Text)
import Data.Void (Void)
import Text.Megaparsec
( PosState(..)
, reachOffset
, unPos
, sourceLine
, sourceColumn
)
import Text.Megaparsec.Error
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.Set as Set
import Data.List (intercalate, sort)
formatError :: String -> String -> String
formatError :: [Char] -> [Char] -> [Char]
formatError [Char]
tag [Char]
msg = [Char]
"\x1b[31m[" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
tag [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"]\x1b[0m " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
msg
getExpected :: ParseError Text Void -> String
getExpected :: ParseError Text Void -> [Char]
getExpected (TrivialError Int
_ Maybe (ErrorItem (Token Text))
_ Set (ErrorItem (Token Text))
expectedSet) =
[ErrorItem Char] -> [Char]
cleanExpected ([ErrorItem Char] -> [ErrorItem Char]
forall a. Ord a => [a] -> [a]
sort ([ErrorItem Char] -> [ErrorItem Char])
-> [ErrorItem Char] -> [ErrorItem Char]
forall a b. (a -> b) -> a -> b
$ Set (ErrorItem Char) -> [ErrorItem Char]
forall a. Set a -> [a]
Set.toList Set (ErrorItem Char)
Set (ErrorItem (Token Text))
expectedSet)
getExpected (FancyError Int
_ Set (ErrorFancy Void)
_) = [Char]
"custom error"
getUnexpected :: ParseError Text Void -> String
getUnexpected :: ParseError Text Void -> [Char]
getUnexpected (TrivialError Int
_ (Just ErrorItem (Token Text)
unex) Set (ErrorItem (Token Text))
_) = ErrorItem Char -> [Char]
parseErrorItem ErrorItem Char
ErrorItem (Token Text)
unex
getUnexpected (TrivialError Int
_ Maybe (ErrorItem (Token Text))
Nothing Set (ErrorItem (Token Text))
_) = [Char]
"end of input"
getUnexpected (FancyError Int
_ Set (ErrorFancy Void)
_) = [Char]
"custom error"
formatFancyError :: Set.Set (ErrorFancy Void) -> String
formatFancyError :: Set (ErrorFancy Void) -> [Char]
formatFancyError Set (ErrorFancy Void)
errs = [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"; " ((ErrorFancy Void -> [Char]) -> [ErrorFancy Void] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ErrorFancy Void -> [Char]
forall {e}. ErrorFancy e -> [Char]
showFancy (Set (ErrorFancy Void) -> [ErrorFancy Void]
forall a. Set a -> [a]
Set.toList Set (ErrorFancy Void)
errs))
where
showFancy :: ErrorFancy e -> [Char]
showFancy (ErrorFail [Char]
msg) = [Char]
msg
showFancy (ErrorIndentation Ordering
_ Pos
ref Pos
actual) =
[Char]
"incorrect indentation (got " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show (Pos -> Int
unPos Pos
actual) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
[Char]
", should be " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show (Pos -> Int
unPos Pos
ref) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
")"
showFancy (ErrorCustom e
_) = [Char]
"custom error"
getErrorDesc :: ParseError Text Void -> String
getErrorDesc :: ParseError Text Void -> [Char]
getErrorDesc err :: ParseError Text Void
err@(TrivialError Int
_ Maybe (ErrorItem (Token Text))
_ Set (ErrorItem (Token Text))
_) =
[Char]
", expected " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ParseError Text Void -> [Char]
getExpected ParseError Text Void
err [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
[Char]
" but got " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ParseError Text Void -> [Char]
getUnexpected ParseError Text Void
err
getErrorDesc (FancyError Int
_ Set (ErrorFancy Void)
fancyErrs) =
[Char]
": " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Set (ErrorFancy Void) -> [Char]
formatFancyError Set (ErrorFancy Void)
fancyErrs
formatParseError :: ParseErrorBundle Text Void -> String
formatParseError :: ParseErrorBundle Text Void -> [Char]
formatParseError ParseErrorBundle Text Void
bundle =
let (ParseError Text Void
err :| [ParseError Text Void]
_) = ParseErrorBundle Text Void -> NonEmpty (ParseError Text Void)
forall s e. ParseErrorBundle s e -> NonEmpty (ParseError s e)
bundleErrors ParseErrorBundle Text Void
bundle
(Int
line, Int
col) = PosState Text -> Int -> (Int, Int)
getLineCol (ParseErrorBundle Text Void -> PosState Text
forall s e. ParseErrorBundle s e -> PosState s
bundlePosState ParseErrorBundle Text Void
bundle) (ParseError Text Void -> Int
forall s e. ParseError s e -> Int
errorOffset ParseError Text Void
err)
details :: [Char]
details = [Char]
"line " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
line [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
", column " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
col [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
ParseError Text Void -> [Char]
getErrorDesc ParseError Text Void
err
in [Char] -> [Char] -> [Char]
formatError [Char]
"Parse Error" [Char]
details
getLineCol :: PosState Text -> Int -> (Int, Int)
getLineCol :: PosState Text -> Int -> (Int, Int)
getLineCol PosState Text
state Int
offset =
let (Maybe [Char]
_, PosState Text
newState) = Int -> PosState Text -> (Maybe [Char], PosState Text)
forall s.
TraversableStream s =>
Int -> PosState s -> (Maybe [Char], PosState s)
reachOffset Int
offset PosState Text
state
pos :: SourcePos
pos = PosState Text -> SourcePos
forall s. PosState s -> SourcePos
pstateSourcePos PosState Text
newState
in (Pos -> Int
unPos (SourcePos -> Pos
sourceLine SourcePos
pos), Pos -> Int
unPos (SourcePos -> Pos
sourceColumn SourcePos
pos))
cleanExpected :: [ErrorItem Char] -> String
cleanExpected :: [ErrorItem Char] -> [Char]
cleanExpected [] = [Char]
"unknown"
cleanExpected [ErrorItem Char]
items =
let labels :: [[Char]]
labels = [NonEmpty Char -> [Char]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty Char
l | Label NonEmpty Char
l <- [ErrorItem Char]
items]
tokens :: [[Char]]
tokens = [[Char] -> [Char]
forall a. Show a => a -> [Char]
show (NonEmpty Char -> [Char]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty Char
t) | Tokens NonEmpty Char
t <- [ErrorItem Char]
items]
in if [[Char]] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Char]]
labels
then [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
", " (Int -> [[Char]] -> [[Char]]
forall a. Int -> [a] -> [a]
take Int
3 [[Char]]
tokens)
else [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" or " [[Char]]
labels
parseErrorItem :: ErrorItem Char -> String
parseErrorItem :: ErrorItem Char -> [Char]
parseErrorItem (Tokens NonEmpty Char
t) = [Char] -> [Char]
forall a. Show a => a -> [Char]
show (NonEmpty Char -> [Char]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty Char
t)
parseErrorItem (Label NonEmpty Char
l) = NonEmpty Char -> [Char]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty Char
l
parseErrorItem (ErrorItem Char
EndOfInput) = [Char]
"end of input"