aboutsummaryrefslogtreecommitdiff
path: root/Data/ConfigManager/Parser.hs
blob: b49f586193da5be02eca22f57eede3a1fe88209d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{-# LANGUAGE OverloadedStrings #-}

module Data.ConfigManager.Parser
  ( parseConfig
  ) where

import Data.Text (Text)
import qualified Data.Text as T
import Data.Char (isSpace, isAlphaNum)

import Text.ParserCombinators.Parsec

import Data.ConfigManager.Types

parseConfig :: Text -> Either Text [Expr]
parseConfig input =
  case parse exprsParser "" (T.unpack (T.concat [input, "\n"])) of
    Right exprs -> Right exprs
    Left parserError -> Left . T.pack . show $ parserError

exprsParser :: Parser [Expr]
exprsParser = skip *> many (exprParser <* restOfLine <* skip) <* eof

exprParser :: Parser Expr
exprParser =
  (try bindingParser)
    <|> (try $ importParser "import" (Import Required))
    <|> (try $ importParser "importMaybe" (Import Optional))

bindingParser :: Parser Expr
bindingParser = do
  name <- nameParser
  _ <- spaces
  _ <- char '='
  _ <- spaces
  value <- valueParser
  return $ Binding name value

importParser :: String -> (FilePath -> Expr) -> Parser Expr
importParser name exprFromPath = do
  _ <- string name
  _ <- spaces
  _ <- char '"'
  path <- many (noneOf "\"")
  _ <- char '"'
  return $ exprFromPath path

nameParser :: Parser Name
nameParser = do
  first <- letter
  rest <- many (satisfy (\c -> isAlphaNum c || c == '-' || c == '_'))
  return . T.pack $ first : rest

valueParser :: Parser Value
valueParser = T.strip . T.pack <$> many (noneOf "\n#")

skip :: Parser ()
skip =
  (satisfy isSpace *> skip)
  <|> (comment *> skip)
  <|> (return ())

comment :: Parser ()
comment = do
  _ <- char '#' *> (many $ noneOf "\n") >> return ()
  return ()

restOfLine :: Parser ()
restOfLine = do
  _ <- many (char ' ')
  _ <- optional comment
  _ <- newline
  return ()