123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- module Gidl.Parse where
- import Data.Functor.Identity
- import Data.Monoid
- import Control.Monad
- import Text.Parsec.Prim
- import Text.Parsec.Char
- import Text.Parsec.Token
- import Text.Parsec.Combinator
- import Text.Parsec.Language
- import Text.Parsec.Error
- import Gidl.Types
- type Parser u a = ParsecT String u Identity a
- lexer :: GenTokenParser String u Identity
- lexer = makeTokenParser haskellDef
- tWhiteSpace :: Parser u ()
- tWhiteSpace = whiteSpace lexer
- tInteger :: Parser u Integer
- tInteger = (integer lexer) <?> "integer"
- tNatural :: Parser u Integer
- tNatural = do
- i <- tInteger
- case i < 0 of
- True -> fail "expected positive integer"
- False -> return i
- tFloat :: Parser u Double
- tFloat = (float lexer) <?> "floating point number"
- tString :: Parser u String
- tString = (stringLiteral lexer) <?> "string"
- tSymbol :: Parser u String
- tSymbol = (many1 $ noneOf "()\" \t\n\r") <?> "symbol"
- tIdentifier :: String -> Parser u ()
- tIdentifier i = do
- s <- tSymbol
- case s == i of
- True -> return ()
- False -> fail ("expected identifier " ++ i)
- tList :: Parser u a -> Parser u a
- tList c = do
- tWhiteSpace
- void $ char '('
- tWhiteSpace
- r <- c
- tWhiteSpace
- void $ char ')'
- return r
- <?> "list"
- tPair :: Parser u a
- -> Parser u b
- -> Parser u (a, b)
- tPair a b = tList $ do
- ra <- a
- tWhiteSpace
- rb <- b
- return (ra, rb)
- tTypeName :: Parser TypeEnv TypeName
- tTypeName = do
- s <- tSymbol
- te <- getState
- case lookupTypeName s te of
- Just _ -> return s
- Nothing -> fail ("expected a known type name, got " ++ s)
- tStructRow :: Parser TypeEnv (Identifier, TypeName)
- tStructRow = tPair tSymbol tTypeName
- <?> "struct row"
- tStructBody :: Parser TypeEnv [(Identifier, TypeName)]
- tStructBody = tList (many1 (tWhiteSpace >> tStructRow))
- <?> "struct body"
- tStructDecl :: Parser TypeEnv (TypeName, Type)
- tStructDecl = tList $ do
- tIdentifier "def-struct"
- tWhiteSpace
- n <- tSymbol
- b <- tStructBody
- return (n, StructType (Struct b))
- defineType :: (TypeName, Type) -> Parser TypeEnv ()
- defineType (tn, t) = do
- te <- getState
- case lookupTypeName tn te of
- Just _ -> fail ("type named '" ++ tn ++ "' already exists")
- Nothing -> setState (insertType tn t te)
- tNewtypeDecl :: Parser TypeEnv (TypeName, Type)
- tNewtypeDecl = tList $ do
- tIdentifier "def-newtype"
- tWhiteSpace
- n <- tSymbol
- tWhiteSpace
- c <- tTypeName
- return (n, NewtypeType (Newtype c))
- tEnumDecl :: Parser TypeEnv (TypeName, Type)
- tEnumDecl = tList $ do
- tIdentifier "def-enum"
- tWhiteSpace
- n <- tSymbol
- -- XXX specify bit width, optionally
- vs <- tList $ many1 $ tPair tSymbol tNatural
- -- XXX check that symbols are unique, numbers are unique, numbers are
- -- ascending
- -- XXX make it possible to implicitly assign numbers
- return (n, EnumType (EnumT Bits32 vs))
- tDecls :: Parser TypeEnv TypeEnv
- tDecls = do
- _ <- many ((choice [try tStructDecl, try tNewtypeDecl, try tEnumDecl]) >>= defineType)
- getState
- parseDecls :: String -> Either ParseError TypeEnv
- parseDecls s = runP tDecls mempty "" s
|