{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-} {-# LANGUAGE OverloadedStrings #-} module Parse.Declaration ( declaration ) where import Data.Text (Text) import qualified Data.Text.Encoding as Text import qualified AST.Expression.Source as Src import qualified AST.Pattern as Pattern import qualified AST.Type as Type import qualified Parse.Expression as Expr import qualified Parse.Pattern as Pattern import Parse.Primitives import qualified Parse.Primitives.Keyword as Keyword import qualified Parse.Primitives.Symbol as Symbol import qualified Parse.Primitives.Variable as Var import qualified Parse.Primitives.Whitespace as W import qualified Parse.Type as Type import qualified Reporting.Annotation as A import qualified Reporting.Error.Syntax as E import qualified Reporting.Region as R -- DECLARATION declaration :: SParser Src.Decl declaration = hint E.Decl $ do start <- getPosition oneOf [ doc_ start , type_ start , port_ start , def_ start ] -- DOC COMMENTS {-# INLINE doc_ #-} doc_ :: R.Position -> SParser Src.Decl doc_ start = do doc <- W.docComment end <- getPosition pos <- W.whitespace return ( A.at start end (Src.Docs (Text.decodeUtf8 doc)), end, pos ) -- DEFINITION and ANNOTATION {-# INLINE def_ #-} def_ :: R.Position -> SParser Src.Decl def_ start = do name <- Var.lower nameEnd <- getPosition let locatedName = A.at start nameEnd name spaces oneOf [ do Symbol.hasType inContext start (E.Annotation name) $ do spaces (tipe, end, space) <- Type.expression return ( A.at start end (Src.Annotation locatedName tipe), end, space ) , inContext start (E.Definition name) $ definitionHelp start locatedName [] ] definitionHelp :: R.Position -> A.Located Text -> [Pattern.Raw] -> SParser Src.Decl definitionHelp start name revArgs = oneOf [ do arg <- hint E.Arg Pattern.term spaces definitionHelp start name (arg : revArgs) , do Symbol.equals spaces (body, end, space) <- Expr.expression let def = A.at start end (Src.Definition name (reverse revArgs) body) return ( def, end, space ) ] -- TYPE ALIAS and UNION TYPES {-# INLINE type_ #-} type_ :: R.Position -> SParser Src.Decl type_ start = do Keyword.type_ spaces oneOf [ do Keyword.alias_ inContext start E.TypeAlias $ do spaces (name, args) <- nameArgsEquals (tipe, end, pos) <- Type.expression return ( A.at start end (Src.Alias name args tipe), end, pos ) , inContext start E.TypeUnion $ do (name, args) <- nameArgsEquals (firstCtor, firstEnd, firstSpace) <- Type.unionConstructor (ctors, end, pos) <- chompConstructors [firstCtor] firstEnd firstSpace return ( A.at start end (Src.Union name args ctors), end, pos ) ] nameArgsEquals :: Parser (A.Located Text, [A.Located Text]) nameArgsEquals = do name <- addLocation Var.upper spaces nameArgsEqualsHelp name [] nameArgsEqualsHelp :: A.Located Text -> [A.Located Text] -> Parser (A.Located Text, [A.Located Text]) nameArgsEqualsHelp name args = oneOf [ do arg <- addLocation Var.lower spaces nameArgsEqualsHelp name (arg:args) , do Symbol.equals spaces return ( name, reverse args ) ] chompConstructors :: [(A.Located Text, [Type.Raw])] -> R.Position -> SPos -> SParser [(A.Located Text, [Type.Raw])] chompConstructors ctors end pos = oneOf [ do checkSpace pos Symbol.pipe spaces (ctor, newEnd, newSpace) <- Type.unionConstructor chompConstructors (ctor:ctors) newEnd newSpace , return ( reverse ctors, end, pos ) ] -- PORT {-# INLINE port_ #-} port_ :: R.Position -> SParser Src.Decl port_ start = do Keyword.port_ inContext start E.Port $ do spaces name <- addLocation Var.lower spaces Symbol.hasType spaces (tipe, end, pos) <- Type.expression return ( A.at start end (Src.Port name tipe), end, pos )