abcnotation-0.5: src/Music/Abc/Parser.hs
-------------------------------------------------------------------------------------
-- |
-- Copyright : (c) Hans Hoglund 2012
--
-- License : BSD-style
--
-- Maintainer : hans@hanshoglund.se
-- Stability : experimental
-- Portability : portable
--
-------------------------------------------------------------------------------------
module Music.Abc.Parser (
parse
) where
import Data.Monoid
import Data.Either
import Control.Monad
import Control.Applicative hiding ((<|>), optional, many)
import Text.Parsec hiding (parse)
import Text.Parsec.Token
import Text.Parsec.String
import Music.Abc
-- TODO information field verification (header/body)
-- ## Limitations:
--
-- * Limited support for *volatile* features
-- * Limited support for text strings (§8.2)
-- * No mnemonics
-- * No entities
-- * Unicode escapes are supported
-- * No support for macros (§9)
-- * No support for outdated syntax (§10)
-- * Stylesheet directives are ignored (§11)
-- * Typeset text is ignored (§2.2.3)
-- * Strict interpretation assumed (§12)
-- |
-- Parse a module description, returning an error if unsuccessful.
--
parse :: String -> Either ParseError AbcFile
parse = runParser abcFile () ""
-------------------------------------------------------------------------------------
-- Parsers
-------------------------------------------------------------------------------------
abcFile :: Parser AbcFile
abcFile = do
-- optional byteOrderMark
string "%abc"
optional $ string "-" >> version
optional $ fileHeader
fileBody
return undefined
fileHeader :: Parser FileHeader
fileHeader = fmap (uncurry FileHeader . partitionEithers) $ many1 $ mzero
<|> fmap Left informationField
<|> fmap Right styleSheetDirective
fileBody :: Parser [Element]
fileBody = (flip sepBy) emptyLine $ mzero
<|> fmap Tune abcTune
<|> fmap FreeText freeText
<|> fmap TypesetText typeSetText
informationField :: Parser Information
informationField = do
letter
char ':'
-- TODO anything not \n
char '\n'
return undefined
-- Not parsed, see Limitations
styleSheetDirective :: Parser Directive
styleSheetDirective = mzero
byteOrderMark :: Parser ()
byteOrderMark = do
char '\xFFFE' <|> char '\xFEFF'
return ()
version :: Parser Double
version = undefined
abcTune :: Parser AbcTune
abcTune = undefined
freeText :: Parser String
freeText = undefined
-- Not parsed, see Limitations
typeSetText :: Parser String
typeSetText = mzero
-------------------------------------------------------------------------------------
-- Lexer
-------------------------------------------------------------------------------------
lexer :: TokenParser ()
lexer = makeTokenParser $ LanguageDef {
commentStart = "[r:",
commentEnd = "]",
commentLine = "%",
nestedComments = False,
identStart = (letter <|> char '_'),
identLetter = (alphaNum <|> char '_'),
opStart = mzero,
opLetter = mzero,
reservedNames = reservedNames,
reservedOpNames = mzero,
caseSensitive = True
}
where
reservedNames = []
-- Convenient synonyms, not exported
llex = lexeme lexer
lnat = natural lexer
lstr = stringLiteral lexer
lname = identifier lexer
lres = reserved lexer
lspace = whiteSpace lexer
emptyLine = newLine >> newLine
newLine = string "\r\n" <|> string "\n"
single x = [x]
notSupported x = error $ "Not supported yet: " ++ x