elm/compiler/Parse/Parse.hs

78 lines
2.8 KiB
Haskell
Raw Normal View History

2013-07-16 19:38:20 +00:00
module Parse.Parse (program, dependencies) where
2012-04-19 06:32:10 +00:00
import Control.Applicative ((<$>), (<*>))
import Control.Monad
import Data.Char (isSymbol, isDigit)
import Data.List (foldl',intercalate)
2013-08-29 09:53:20 +00:00
import qualified Data.Map as Map
import Text.Parsec hiding (newline,spaces)
import qualified Text.PrettyPrint as P
2013-07-16 19:38:20 +00:00
import qualified SourceSyntax.Module as S
import SourceSyntax.Declaration (Declaration(Fixity))
import Parse.Helpers
import Parse.Binop (OpTable)
import Parse.Expression
import Parse.Declaration (infixDecl)
import Parse.Type
import Parse.Module
import qualified Parse.Declaration as Decl
freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do
freshLine
Decl.declaration <?> "another datatype or variable definition"
2012-04-19 06:32:10 +00:00
decls = do d <- Decl.declaration <?> "at least one datatype or variable definition"
(d:) <$> many freshDef
2013-08-29 09:53:20 +00:00
program :: OpTable -> String -> Either [P.Doc] (S.Module t v)
program table = setupParserWithTable table $ do
optional freshLine
(names,exports) <- option (["Main"],[]) (moduleDef `followedBy` freshLine)
is <- (do try (lookAhead $ reserved "import")
imports `followedBy` freshLine) <|> return []
declarations <- decls
optional freshLine ; optional spaces ; eof
2013-07-16 19:38:20 +00:00
return $ S.Module names exports is declarations
2012-04-19 06:32:10 +00:00
2013-07-16 19:38:20 +00:00
dependencies :: String -> Either [P.Doc] (String, [String])
dependencies =
let getName = intercalate "." . fst in
setupParser $ do
optional freshLine
(,) <$> option "Main" (getName <$> moduleDef `followedBy` freshLine)
<*> option [] (map fst <$> imports `followedBy` freshLine)
2013-08-29 09:53:20 +00:00
setupParserWithTable :: OpTable -> IParser a -> String -> Either [P.Doc] a
setupParserWithTable table p source =
do localTable <- setupParser parseFixities source
case Map.intersection table localTable of
overlap | not (Map.null overlap) -> Left [ msg overlap ]
| otherwise ->
flip setupParser source $ do
putState (Map.union table localTable)
p
where
msg overlap =
P.vcat [ P.text "Parse error:"
, P.text $ "Overlapping definitions for infix operators: " ++
intercalate " " (Map.keys overlap)
]
parseFixities = infixes []
where
eatLine = anyThen (const False <$> simpleNewline <|> const True <$> eof)
2013-08-29 09:53:20 +00:00
infixes ops = do
next <- Left <$> infixDecl <|> Right <$> eatLine
2013-08-29 09:53:20 +00:00
case next of
Left (Fixity assoc lvl op) -> infixes ((op,(lvl,assoc)) : ops)
Right True -> return $ Map.fromList ops
Right False -> infixes ops
2013-08-29 09:53:20 +00:00
setupParser :: IParser a -> String -> Either [P.Doc] a
setupParser p source =
case iParse p source of
Right result -> Right result
2013-07-22 12:40:00 +00:00
Left err -> Left [ P.text $ "Parse error at " ++ show err ]