{-|
Module      : Data.Dson.Parsec
Copyright   : (c) Ezequiel Alvarez 2014
License     : MIT
Maintainer  : welcometothechango@gmail.com
Stability   : provisional
Portability : portable

Provides the main DSON parser.
-}

module Data.Dson.Parsec (
    Dson(..),
    dsonTop
    ) where

import Data.Dson.Octal
import Data.Dson.Lexer

import Control.Applicative
import Text.Parsec (sepBy, try, oneOf, spaces, parseTest)
import Text.Parsec.String (Parser)

data Dson = DSDict [(String, Dson)] | DSArray [Dson] | DSString String | DSNumber Double | Yes | No | Empty
    deriving (Show, Eq)

dsonString :: Parser Dson
dsonString = DSString <$> stringLiteral

dsonInt :: Parser Dson
dsonInt = DSNumber <$> octal <* spaces

dsonBool :: Parser Dson
dsonBool =     (symbol "yes"   *> pure Yes)
           <|> (symbol "no"    *> pure No)
           <|> (symbol "empty" *> pure Empty)

dsonValue :: Parser Dson
dsonValue = try dsonArray <|> try dsonDict <|> try dsonBool <|> try dsonInt <|> dsonString

dsonArray = DSArray <$> (symbol "so" *> dsonValue `sepBy` arraySep <* symbol "many")
    where arraySep = try (symbol "also") <|> symbol "and"

dsonDict :: Parser Dson
dsonDict = DSDict <$> (symbol "such" *> (kvPairs `sepBy` dictSep) <* symbol "wow")
    where kvPairs = (,) <$> stringLiteral <*> (symbol "is" *> dsonValue)
          dictSep = oneOf ".,!?" <* spaces

-- | This parser scans for either a DSON dict or array.
dsonTop :: Parser Dson
dsonTop = try dsonDict <|> dsonArray