module Agda.Interaction.Library.Parse
( parseLibFile
, splitCommas
, trimLineComment
, runP
) where
import Control.Monad
import Control.Monad.Except
import Control.Monad.Writer
import Data.Char
import qualified Data.List as List
import System.FilePath
import Agda.Interaction.Library.Base
import Agda.Syntax.Position
import Agda.Utils.Applicative
import Agda.Utils.FileName
import Agda.Utils.IO ( catchIO )
import qualified Agda.Utils.IO.UTF8 as UTF8
import Agda.Utils.Lens
import Agda.Utils.List ( duplicates )
import Agda.Utils.List1 ( List1, toList )
import qualified Agda.Utils.List1 as List1
import qualified Agda.Utils.Maybe.Strict as Strict
import Agda.Utils.Singleton
import Agda.Utils.String ( ltrim )
type P = ExceptT LibParseError (Writer [LibWarning'])
runP :: P a -> (Either LibParseError a, [LibWarning'])
runP :: forall a. P a -> (Either LibParseError a, [LibWarning'])
runP = Writer [LibWarning'] (Either LibParseError a)
-> (Either LibParseError a, [LibWarning'])
forall w a. Writer w a -> (a, w)
runWriter (Writer [LibWarning'] (Either LibParseError a)
-> (Either LibParseError a, [LibWarning']))
-> (P a -> Writer [LibWarning'] (Either LibParseError a))
-> P a
-> (Either LibParseError a, [LibWarning'])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. P a -> Writer [LibWarning'] (Either LibParseError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT
warningP :: LibWarning' -> P ()
warningP :: LibWarning' -> ExceptT LibParseError (Writer [LibWarning']) ()
warningP = [LibWarning'] -> ExceptT LibParseError (Writer [LibWarning']) ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([LibWarning'] -> ExceptT LibParseError (Writer [LibWarning']) ())
-> (LibWarning' -> [LibWarning'])
-> LibWarning'
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LibWarning' -> [LibWarning']
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
type GenericFile = [GenericEntry]
data GenericEntry = GenericEntry
{ :: String
, GenericEntry -> [String]
_geContent :: [String]
}
data Field = forall a. Field
{ Field -> String
fName :: String
, Field -> Bool
fOptional :: Bool
, ()
fParse :: Range -> [String] -> P a
, ()
fSet :: LensSet AgdaLibFile a
}
optionalField ::
String -> (Range -> [String] -> P a) -> Lens' AgdaLibFile a -> Field
optionalField :: forall a.
String
-> (Range -> [String] -> P a) -> Lens' AgdaLibFile a -> Field
optionalField String
str Range -> [String] -> P a
p Lens' AgdaLibFile a
l = String
-> Bool
-> (Range -> [String] -> P a)
-> LensSet AgdaLibFile a
-> Field
forall a.
String
-> Bool
-> (Range -> [String] -> P a)
-> LensSet AgdaLibFile a
-> Field
Field String
str Bool
True Range -> [String] -> P a
p (Lens' AgdaLibFile a -> LensSet AgdaLibFile a
forall o i. Lens' o i -> LensSet o i
set (a -> f a) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile a
l)
agdaLibFields :: [Field]
agdaLibFields :: [Field]
agdaLibFields =
[ String
-> (Range -> [String] -> P String)
-> Lens' AgdaLibFile String
-> Field
forall a.
String
-> (Range -> [String] -> P a) -> Lens' AgdaLibFile a -> Field
optionalField String
"name" (\Range
_ -> [String] -> P String
parseName) (String -> f String) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile String
libName
, String
-> (Range -> [String] -> P [String])
-> Lens' AgdaLibFile [String]
-> Field
forall a.
String
-> (Range -> [String] -> P a) -> Lens' AgdaLibFile a -> Field
optionalField String
"include" (\Range
_ -> [String] -> P [String]
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([String] -> P [String])
-> ([String] -> [String]) -> [String] -> P [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
parsePaths) ([String] -> f [String]) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile [String]
libIncludes
, String
-> (Range -> [String] -> P [String])
-> Lens' AgdaLibFile [String]
-> Field
forall a.
String
-> (Range -> [String] -> P a) -> Lens' AgdaLibFile a -> Field
optionalField String
"depend" (\Range
_ -> [String] -> P [String]
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([String] -> P [String])
-> ([String] -> [String]) -> [String] -> P [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
splitCommas) ([String] -> f [String]) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile [String]
libDepends
, String
-> (Range -> [String] -> P OptionsPragma)
-> Lens' AgdaLibFile OptionsPragma
-> Field
forall a.
String
-> (Range -> [String] -> P a) -> Lens' AgdaLibFile a -> Field
optionalField String
"flags" (\Range
r -> OptionsPragma -> P OptionsPragma
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (OptionsPragma -> P OptionsPragma)
-> ([String] -> OptionsPragma) -> [String] -> P OptionsPragma
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> OptionsPragma) -> [String] -> OptionsPragma
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Range -> String -> OptionsPragma
parseFlags Range
r)) (OptionsPragma -> f OptionsPragma) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile OptionsPragma
libPragmas
]
where
parseName :: [String] -> P LibName
parseName :: [String] -> P String
parseName [String
s] | [String
name] <- String -> [String]
words String
s = String -> P String
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
name
parseName [String]
ls = LibParseError -> P String
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError -> P String) -> LibParseError -> P String
forall a b. (a -> b) -> a -> b
$ String -> LibParseError
BadLibraryName (String -> LibParseError) -> String -> LibParseError
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String]
ls
parsePaths :: String -> [FilePath]
parsePaths :: String -> [String]
parsePaths = (String -> String) -> String -> [String]
go String -> String
forall a. a -> a
id where
fixup :: ([a] -> t a) -> f (t a)
fixup [a] -> t a
acc = let fp :: t a
fp = [a] -> t a
acc [] in Bool -> Bool
not (t a -> Bool
forall a. t a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null t a
fp) Bool -> t a -> f (t a)
forall (f :: * -> *) a. Alternative f => Bool -> a -> f a
?$> t a
fp
go :: (String -> String) -> String -> [String]
go String -> String
acc [] = (String -> String) -> [String]
forall {f :: * -> *} {t :: * -> *} {a} {a}.
(Alternative f, Foldable t) =>
([a] -> t a) -> f (t a)
fixup String -> String
acc
go String -> String
acc (Char
'\\' : Char
' ' :String
cs) = (String -> String) -> String -> [String]
go (String -> String
acc (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
' 'Char -> String -> String
forall a. a -> [a] -> [a]
:)) String
cs
go String -> String
acc (Char
'\\' : Char
'\\' :String
cs) = (String -> String) -> String -> [String]
go (String -> String
acc (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:)) String
cs
go String -> String
acc ( Char
' ' :String
cs) = (String -> String) -> [String]
forall {f :: * -> *} {t :: * -> *} {a} {a}.
(Alternative f, Foldable t) =>
([a] -> t a) -> f (t a)
fixup String -> String
acc [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> String -> [String]
go String -> String
forall a. a -> a
id String
cs
go String -> String
acc (Char
c :String
cs) = (String -> String) -> String -> [String]
go (String -> String
acc (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:)) String
cs
parseFlags :: Range -> String -> OptionsPragma
parseFlags :: Range -> String -> OptionsPragma
parseFlags Range
r String
s = OptionsPragma
{ pragmaStrings :: [String]
pragmaStrings = String -> [String]
words String
s
, pragmaRange :: Range
pragmaRange = Range
r
}
parseLibFile :: FilePath -> IO (P AgdaLibFile)
parseLibFile :: String -> IO (P AgdaLibFile)
parseLibFile String
file = do
AbsolutePath
abs <- String -> IO AbsolutePath
absolute String
file
((AgdaLibFile -> AgdaLibFile) -> P AgdaLibFile -> P AgdaLibFile
forall a b.
(a -> b)
-> ExceptT LibParseError (Writer [LibWarning']) a
-> ExceptT LibParseError (Writer [LibWarning']) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap AgdaLibFile -> AgdaLibFile
setPath (P AgdaLibFile -> P AgdaLibFile)
-> (String -> P AgdaLibFile) -> String -> P AgdaLibFile
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AbsolutePath -> String -> P AgdaLibFile
parseLib AbsolutePath
abs (String -> P AgdaLibFile) -> IO String -> IO (P AgdaLibFile)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO String
UTF8.readFile String
file) IO (P AgdaLibFile)
-> (IOException -> IO (P AgdaLibFile)) -> IO (P AgdaLibFile)
forall a. IO a -> (IOException -> IO a) -> IO a
forall (m :: * -> *) a.
CatchIO m =>
m a -> (IOException -> m a) -> m a
`catchIO` \IOException
e ->
P AgdaLibFile -> IO (P AgdaLibFile)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (P AgdaLibFile -> IO (P AgdaLibFile))
-> P AgdaLibFile -> IO (P AgdaLibFile)
forall a b. (a -> b) -> a -> b
$ LibParseError -> P AgdaLibFile
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError -> P AgdaLibFile) -> LibParseError -> P AgdaLibFile
forall a b. (a -> b) -> a -> b
$ String -> IOException -> LibParseError
ReadFailure String
file IOException
e
where
setPath :: AgdaLibFile -> AgdaLibFile
setPath AgdaLibFile
lib = String -> AgdaLibFile -> AgdaLibFile
unrelativise (String -> String
takeDirectory String
file) (Lens' AgdaLibFile String -> String -> AgdaLibFile -> AgdaLibFile
forall o i. Lens' o i -> LensSet o i
set (String -> f String) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile String
libFile String
file AgdaLibFile
lib)
unrelativise :: String -> AgdaLibFile -> AgdaLibFile
unrelativise String
dir = Lens' AgdaLibFile [String] -> LensMap AgdaLibFile [String]
forall o i. Lens' o i -> LensMap o i
over ([String] -> f [String]) -> AgdaLibFile -> f AgdaLibFile
Lens' AgdaLibFile [String]
libIncludes ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
dir String -> String -> String
</>))
parseLib
:: AbsolutePath
-> String -> P AgdaLibFile
parseLib :: AbsolutePath -> String -> P AgdaLibFile
parseLib AbsolutePath
file String
s = AbsolutePath -> GenericFile -> P AgdaLibFile
fromGeneric AbsolutePath
file (GenericFile -> P AgdaLibFile)
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
-> P AgdaLibFile
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> ExceptT LibParseError (Writer [LibWarning']) GenericFile
parseGeneric String
s
fromGeneric
:: AbsolutePath
-> GenericFile -> P AgdaLibFile
fromGeneric :: AbsolutePath -> GenericFile -> P AgdaLibFile
fromGeneric AbsolutePath
file = AbsolutePath -> [Field] -> GenericFile -> P AgdaLibFile
fromGeneric' AbsolutePath
file [Field]
agdaLibFields
fromGeneric'
:: AbsolutePath
-> [Field] -> GenericFile -> P AgdaLibFile
fromGeneric' :: AbsolutePath -> [Field] -> GenericFile -> P AgdaLibFile
fromGeneric' AbsolutePath
file [Field]
fields GenericFile
fs = do
[Field]
-> [String] -> ExceptT LibParseError (Writer [LibWarning']) ()
checkFields [Field]
fields ((GenericEntry -> String) -> GenericFile -> [String]
forall a b. (a -> b) -> [a] -> [b]
map GenericEntry -> String
geHeader GenericFile
fs)
(AgdaLibFile -> GenericEntry -> P AgdaLibFile)
-> AgdaLibFile -> GenericFile -> P AgdaLibFile
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM AgdaLibFile -> GenericEntry -> P AgdaLibFile
upd AgdaLibFile
emptyLibFile GenericFile
fs
where
r :: Range
r = Maybe RangeFile -> Seq (Interval' ()) -> Range
forall a. a -> Seq (Interval' ()) -> Range' a
Range
(RangeFile -> Maybe RangeFile
forall a. a -> Maybe a
Strict.Just (RangeFile -> Maybe RangeFile) -> RangeFile -> Maybe RangeFile
forall a b. (a -> b) -> a -> b
$ AbsolutePath -> Maybe TopLevelModuleName -> RangeFile
mkRangeFile AbsolutePath
file Maybe TopLevelModuleName
forall a. Maybe a
Nothing)
(Interval' () -> Seq (Interval' ())
forall el coll. Singleton el coll => el -> coll
singleton (() -> PositionWithoutFile -> PositionWithoutFile -> Interval' ()
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval () PositionWithoutFile
p PositionWithoutFile
p))
where
p :: PositionWithoutFile
p = Pn { srcFile :: ()
srcFile = ()
, posPos :: Int32
posPos = Int32
1
, posLine :: Int32
posLine = Int32
1
, posCol :: Int32
posCol = Int32
1
}
upd :: AgdaLibFile -> GenericEntry -> P AgdaLibFile
upd :: AgdaLibFile -> GenericEntry -> P AgdaLibFile
upd AgdaLibFile
l (GenericEntry String
h [String]
cs) = do
Maybe Field
mf <- String -> [Field] -> P (Maybe Field)
findField String
h [Field]
fields
case Maybe Field
mf of
Just Field{Bool
String
LensSet AgdaLibFile a
Range -> [String] -> P a
fName :: Field -> String
fOptional :: Field -> Bool
fParse :: ()
fSet :: ()
fName :: String
fOptional :: Bool
fParse :: Range -> [String] -> P a
fSet :: LensSet AgdaLibFile a
..} -> do
a
x <- Range -> [String] -> P a
fParse Range
r [String]
cs
AgdaLibFile -> P AgdaLibFile
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (m :: * -> *) a. Monad m => a -> m a
return (AgdaLibFile -> P AgdaLibFile) -> AgdaLibFile -> P AgdaLibFile
forall a b. (a -> b) -> a -> b
$ LensSet AgdaLibFile a
fSet a
x AgdaLibFile
l
Maybe Field
Nothing -> AgdaLibFile -> P AgdaLibFile
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (m :: * -> *) a. Monad m => a -> m a
return AgdaLibFile
l
checkFields :: [Field] -> [String] -> P ()
checkFields :: [Field]
-> [String] -> ExceptT LibParseError (Writer [LibWarning']) ()
checkFields [Field]
fields [String]
fs = do
() <- [String]
-> (List1 String
-> ExceptT LibParseError (Writer [LibWarning']) ())
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall m a. Null m => [a] -> (List1 a -> m) -> m
List1.unlessNull [String]
missing ((List1 String -> ExceptT LibParseError (Writer [LibWarning']) ())
-> ExceptT LibParseError (Writer [LibWarning']) ())
-> (List1 String
-> ExceptT LibParseError (Writer [LibWarning']) ())
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall a b. (a -> b) -> a -> b
$ LibParseError -> ExceptT LibParseError (Writer [LibWarning']) ()
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError -> ExceptT LibParseError (Writer [LibWarning']) ())
-> (List1 String -> LibParseError)
-> List1 String
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. List1 String -> LibParseError
MissingFields
[String]
-> (List1 String
-> ExceptT LibParseError (Writer [LibWarning']) ())
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall m a. Null m => [a] -> (List1 a -> m) -> m
List1.unlessNull ([String] -> [String]
forall a. Ord a => [a] -> [a]
duplicates [String]
fs) ((List1 String -> ExceptT LibParseError (Writer [LibWarning']) ())
-> ExceptT LibParseError (Writer [LibWarning']) ())
-> (List1 String
-> ExceptT LibParseError (Writer [LibWarning']) ())
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall a b. (a -> b) -> a -> b
$ LibParseError -> ExceptT LibParseError (Writer [LibWarning']) ()
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError -> ExceptT LibParseError (Writer [LibWarning']) ())
-> (List1 String -> LibParseError)
-> List1 String
-> ExceptT LibParseError (Writer [LibWarning']) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. List1 String -> LibParseError
DuplicateFields
where
mandatory :: [String]
mandatory :: [String]
mandatory = [ Field -> String
fName Field
f | Field
f <- [Field]
fields, Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Field -> Bool
fOptional Field
f ]
missing :: [String]
missing :: [String]
missing = [String]
mandatory [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
List.\\ [String]
fs
findField :: String -> [Field] -> P (Maybe Field)
findField :: String -> [Field] -> P (Maybe Field)
findField String
s [Field]
fs = P (Maybe Field)
-> (Field -> P (Maybe Field)) -> Maybe Field -> P (Maybe Field)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe P (Maybe Field)
err (Maybe Field -> P (Maybe Field)
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Field -> P (Maybe Field))
-> (Field -> Maybe Field) -> Field -> P (Maybe Field)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field -> Maybe Field
forall a. a -> Maybe a
Just) (Maybe Field -> P (Maybe Field)) -> Maybe Field -> P (Maybe Field)
forall a b. (a -> b) -> a -> b
$ (Field -> Bool) -> [Field] -> Maybe Field
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
List.find ((String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
==) (String -> Bool) -> (Field -> String) -> Field -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field -> String
fName) [Field]
fs
where err :: P (Maybe Field)
err = LibWarning' -> ExceptT LibParseError (Writer [LibWarning']) ()
warningP (String -> LibWarning'
UnknownField String
s) ExceptT LibParseError (Writer [LibWarning']) ()
-> P (Maybe Field) -> P (Maybe Field)
forall a b.
ExceptT LibParseError (Writer [LibWarning']) a
-> ExceptT LibParseError (Writer [LibWarning']) b
-> ExceptT LibParseError (Writer [LibWarning']) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe Field -> P (Maybe Field)
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Field
forall a. Maybe a
Nothing
parseGeneric :: String -> P GenericFile
parseGeneric :: String -> ExceptT LibParseError (Writer [LibWarning']) GenericFile
parseGeneric String
s =
[GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
groupLines ([GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile)
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [[GenericLine]] -> [GenericLine]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[GenericLine]] -> [GenericLine])
-> ExceptT LibParseError (Writer [LibWarning']) [[GenericLine]]
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (LineNumber
-> String
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine])
-> [LineNumber]
-> [String]
-> ExceptT LibParseError (Writer [LibWarning']) [[GenericLine]]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM LineNumber
-> String
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
parseLine [LineNumber
1..] ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
stripComments ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ String -> [String]
lines String
s)
data GenericLine
= LineNumber String
| Content LineNumber String
deriving (LineNumber -> GenericLine -> String -> String
[GenericLine] -> String -> String
GenericLine -> String
(LineNumber -> GenericLine -> String -> String)
-> (GenericLine -> String)
-> ([GenericLine] -> String -> String)
-> Show GenericLine
forall a.
(LineNumber -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: LineNumber -> GenericLine -> String -> String
showsPrec :: LineNumber -> GenericLine -> String -> String
$cshow :: GenericLine -> String
show :: GenericLine -> String
$cshowList :: [GenericLine] -> String -> String
showList :: [GenericLine] -> String -> String
Show)
parseLine :: LineNumber -> String -> P [GenericLine]
parseLine :: LineNumber
-> String
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
parseLine LineNumber
_ String
"" = [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
parseLine LineNumber
l s :: String
s@(Char
c:String
_)
| Char -> Bool
isSpace Char
c = [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [LineNumber -> String -> GenericLine
Content LineNumber
l (String -> GenericLine) -> String -> GenericLine
forall a b. (a -> b) -> a -> b
$ String -> String
ltrim String
s]
| Bool
otherwise =
case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
':') String
s of
(String
h, Char
':' : String
r) ->
case String -> [String]
words String
h of
[String
h] -> [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine])
-> [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a b. (a -> b) -> a -> b
$ LineNumber -> String -> GenericLine
Header LineNumber
l String
h GenericLine -> [GenericLine] -> [GenericLine]
forall a. a -> [a] -> [a]
: [LineNumber -> String -> GenericLine
Content LineNumber
l String
r' | let r' :: String
r' = String -> String
ltrim String
r, Bool -> Bool
not (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
r')]
[] -> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine])
-> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a b. (a -> b) -> a -> b
$ LineNumber -> LibParseError
MissingFieldName LineNumber
l
[String]
hs -> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine])
-> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a b. (a -> b) -> a -> b
$ LineNumber -> String -> LibParseError
BadFieldName LineNumber
l String
h
(String, String)
_ -> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine])
-> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) [GenericLine]
forall a b. (a -> b) -> a -> b
$ LineNumber -> String -> LibParseError
MissingColonForField LineNumber
l (String -> String
ltrim String
s)
groupLines :: [GenericLine] -> P GenericFile
groupLines :: [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
groupLines [] = GenericFile
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
forall a. a -> ExceptT LibParseError (Writer [LibWarning']) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
groupLines (Content LineNumber
l String
c : [GenericLine]
_) = LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
forall a.
LibParseError -> ExceptT LibParseError (Writer [LibWarning']) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile)
-> LibParseError
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
forall a b. (a -> b) -> a -> b
$ LineNumber -> LibParseError
ContentWithoutField LineNumber
l
groupLines (Header LineNumber
_ String
h : [GenericLine]
ls) = (String -> [String] -> GenericEntry
GenericEntry String
h [ String
c | Content LineNumber
_ String
c <- [GenericLine]
cs ] GenericEntry -> GenericFile -> GenericFile
forall a. a -> [a] -> [a]
:) (GenericFile -> GenericFile)
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [GenericLine]
-> ExceptT LibParseError (Writer [LibWarning']) GenericFile
groupLines [GenericLine]
ls1
where
([GenericLine]
cs, [GenericLine]
ls1) = (GenericLine -> Bool)
-> [GenericLine] -> ([GenericLine], [GenericLine])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span GenericLine -> Bool
isContent [GenericLine]
ls
isContent :: GenericLine -> Bool
isContent Content{} = Bool
True
isContent Header{} = Bool
False
trimLineComment :: String -> String
= String -> String
stripComments (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
ltrim
splitCommas :: String -> [String]
splitCommas :: String -> [String]
splitCommas = String -> [String]
words (String -> [String]) -> (String -> String) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map (\Char
c -> if Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
',' then Char
' ' else Char
c)
stripComments :: String -> String
String
"" = String
""
stripComments (Char
'-':Char
'-':Char
c:String
_) | Char -> Bool
isSpace Char
c = String
""
stripComments (Char
c : String
s) = Char -> String -> String
cons Char
c (String -> String
stripComments String
s)
where
cons :: Char -> String -> String
cons Char
c String
"" | Char -> Bool
isSpace Char
c = String
""
cons Char
c String
s = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
s