toml-parser-1.3.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 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
}