toml-parser-1.0.0.0: src/Toml/Parser.y
{
{-|
Module : Toml.Parser
Description : Raw TOML expression parser
Copyright : (c) Eric Mertens, 2023
License : ISC
Maintainer : emertens@gmail.com
This module parses TOML tokens into a list of raw,
uninterpreted sections and assignments.
-}
module Toml.Parser (
-- * types
Expr(..),
SectionKind(..),
Val(..),
Key,
-- * parser
parseRawToml,
) where
import Data.List.NonEmpty (NonEmpty)
import Data.List.NonEmpty qualified as NonEmpty
import Data.Time (Day, TimeOfDay, LocalTime, ZonedTime)
import Toml.Located (Located(Located, locPosition, locThing))
import Toml.Position (posLine)
import Toml.Parser.Types
import Toml.Lexer (Token(..))
}
%tokentype { Located Token }
%token
'true' { Located _ TokTrue }
'false' { Located _ TokFalse }
',' { Located _ TokComma }
'=' { Located _ TokEquals }
NEWLINE { Located _ TokNewline }
'.' { Located _ TokPeriod }
'[' { Located _ TokSquareO }
']' { Located _ TokSquareC }
'[[' { Located _ Tok2SquareO }
']]' { Located _ Tok2SquareC }
'{' { Located _ TokCurlyO }
'}' { Located _ TokCurlyC }
BAREKEY { Located _ (TokBareKey _ ) }
STRING { Located _ (TokString _ ) }
MLSTRING { Located _ (TokMlString $$) }
INTEGER { Located _ (TokInteger $$) }
FLOAT { Located _ (TokFloat $$) }
OFFSETDATETIME { Located _ (TokOffsetDateTime $$) }
LOCALDATETIME { Located _ (TokLocalDateTime $$) }
LOCALDATE { Located _ (TokLocalDate $$) }
LOCALTIME { Located _ (TokLocalTime $$) }
EOF { Located _ TokEOF }
%monad { Either (Located Token) }
%error { errorP }
%name parseRawToml toml
%%
toml :: { [Expr] }
: sepBy1(expression, NEWLINE) EOF { concat $1 }
expression :: { [Expr] }
: { [] }
| keyval { [KeyValExpr (fst $1) (snd $1)] }
| '[' key ']' { [TableExpr $2 ] }
| '[[' key ']]' { [ArrayTableExpr $2 ] }
keyval :: { (Key, Val) }
: key '=' val { ($1,$3) }
key :: { Key }
: sepBy1(simplekey, '.') { $1 }
simplekey :: { Located String }
: BAREKEY { fmap asString $1 }
| STRING { fmap asString $1 }
val :: { Val }
: INTEGER { ValInteger $1 }
| FLOAT { ValFloat $1 }
| 'true' { ValBool True }
| 'false' { ValBool False }
| STRING { ValString (asString (locThing $1)) }
| MLSTRING { ValString $1 }
| LOCALDATE { ValDay $1 }
| LOCALTIME { ValTimeOfDay $1 }
| OFFSETDATETIME { ValZonedTime $1 }
| LOCALDATETIME { ValLocalTime $1 }
| array { ValArray $1 }
| inlinetable { ValTable $1 }
inlinetable :: { [(Key, Val)] }
: '{' sepBy(keyval, ',') '}' { $2 }
array :: { [Val] }
: '[' newlines ']' { [] }
| '[' newlines arrayvalues ']' { reverse $3 }
| '[' newlines arrayvalues ',' newlines ']' { reverse $3 }
arrayvalues :: { [Val] }
: val newlines { [$1] }
| arrayvalues ',' newlines val newlines { $4 : $1 }
newlines :: {}
: {}
| newlines NEWLINE {}
sepBy(p,q) :: { [p] }
: { [] }
| sepBy1(p,q) { NonEmpty.toList $1 }
sepBy1(p,q) :: { NonEmpty p }
: sepBy1_(p,q) { NonEmpty.reverse $1 }
sepBy1_(p,q) :: { NonEmpty p }
: p { NonEmpty.singleton $1 }
| sepBy1_(p,q) q p { NonEmpty.cons $3 $1 }
{
errorP :: [Located Token] -> Either (Located Token) a
errorP (t:_) = Left t
errorP [] = error "Parser.errorP: unterminated token stream"
asString :: Token -> String
asString (TokString x) = x
asString (TokBareKey x) = x
asString _ = error "simpleKeyLexeme: panic"
}