module Parse.Parser (parseProgram, preParse) where import Ast import Control.Applicative ((<$>), (<*>)) import Control.Monad import Data.Char (isSymbol, isDigit) import Data.List (foldl',intercalate) import Text.Parsec hiding (newline,spaces) import Parse.Library import Parse.Expr import Parse.Types import Parse.Modules import Parse.Foreign statement = choice (typeAlias:defs) <|> def "datatype or variable definition" where defs = map ((:[]) <$>) [ foreignDef, datatype, typeAnnotation ] freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do freshLine statement "another datatype or variable definition" defs1 = do d <- statement "at least one datatype or variable definition" concat <$> (d:) <$> many freshDef program = do optional freshLine (names,exports) <- option (["Main"],[]) (moduleDef `followedBy` freshLine) is <- (do try (lookAhead $ reserved "import") imports `followedBy` freshLine) <|> return [] statements <- defs1 optional freshLine ; optional spaces ; eof return $ Module names exports is statements parseProgram = setupParser program preParse :: String -> Either String (String, [String]) preParse = setupParser $ do optional skip (,) <$> option "Main" moduleName <*> option [] imprts where skip = try (manyTill anyChar (try (string "/**"))) imprts = fmap (map fst) imports `followedBy` freshLine getName = intercalate "." . fst moduleName = do optional freshLine getName <$> moduleDef `followedBy` freshLine setupParser p source = case iParse p "" source of Right result -> Right result Left err -> Left $ "Parse error at " ++ show err