{ {-| 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 Toml.Lexer (Context(..), Token(..)) import Toml.Located (Located(Located, locThing)) import Toml.Parser.Types (Expr(..), Key, Val(..), SectionKind(..)) import Toml.Parser.Utils (Parser, runParser, lexerP, errorP, push, pop, thenP, pureP, asString) import Toml.Position (startPos) } %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 $$) } %monad { Parser r } { thenP } { pureP } %lexer { lexerP } { Located _ TokEOF } %error { errorP } %name parseRawToml_ toml %% toml :: { [Expr] } : sepBy1(expression, NEWLINE) { concat $1 } expression :: { [Expr] } : { [] } | keyval { [KeyValExpr (fst $1) (snd $1)] } | '[' key ']' { [TableExpr $2 ] } | '[[' key ']]' { [ArrayTableExpr $2 ] } keyval :: { (Key, Val) } : key rhs '=' pop val { ($1,$5) } 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)] } : lhs '{' sepBy(keyval, ',') pop '}' { $3 } array :: { [Val] } : rhs '[' newlines pop ']' { [] } | rhs '[' newlines arrayvalues pop ']' { reverse $4 } | rhs '[' newlines arrayvalues ',' newlines pop ']' { reverse $4 } 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{ pure $1 } | sepBy1_(p,q) q p{ NonEmpty.cons $3 $1 } rhs :: { () } : {% push ValueContext } lhs :: { () } : {% push TableContext } pop :: { () } : {% pop } { -- | Parse a list of tokens either returning the first unexpected -- token or a list of the TOML statements in the file to be -- processed by "Toml.Semantics". parseRawToml :: String -> Either (Located String) [Expr] parseRawToml = runParser parseRawToml_ TopContext . Located startPos }