@@ -47,11 +47,14 @@ import Control.Monad
47import Control.Monad.Error (throwError, catchError)
47import Control.Monad.Error (throwError, catchError)
48import Control.Monad.State.Strict
48import Control.Monad.State.Strict
50import Data.Maybe
51import Data.Maybe
51import qualified Data.List.Split as Spl
52import qualified Data.List.Split as Spl
52import Data.List
53import Data.List
53import Data.Monoid
54import Data.Monoid
54import Data.Char
55import Data.Char
57+import qualified Data.Map as M
55import qualified Data.HashSet as HS
58import qualified Data.HashSet as HS
56import qualified Data.Text as T
59import qualified Data.Text as T
57import qualified Data.ByteString.UTF8 as UTF8
60import qualified Data.ByteString.UTF8 as UTF8
@@ -91,13 +94,15 @@ moduleHeader = try (do reserved "module"
91{- | Parses an import statement
94{- | Parses an import statement
92 Import ::= 'import' Identifier_t ';'?;
95 Import ::= 'import' Identifier_t ';'?;
94−import_ :: IdrisParser String
97+import_ :: IdrisParser (String, Maybe String, FC)
98+import_ = do fc <- getFC
95−import_ = do reserved "import"
99+ reserved "import"
96 id <- identifier
100 id <- identifier
101+ newName <- optional (reserved "as" *> identifier)
97 option ';' (lchar ';')
102 option ';' (lchar ';')
98− return (toPath id)
103+ return (toPath id, toPath <$> newName, fc)
99 <?> "import statement"
104 <?> "import statement"
100− where toPath f = foldl1' (</>) (Spl.splitOn "." f)
105+ where toPath = foldl1' (</>) . Spl.splitOn "."
102{- | Parses program source
107{- | Parses program source
103 Prog ::= Decl* EOF;
108 Prog ::= Decl* EOF;
@@ -934,7 +939,7 @@ parseTactic :: IState -> String -> Result PTactic
934parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
939parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
936-- | Parse module header and imports
941-- | Parse module header and imports
937−parseImports :: FilePath -> String -> Idris ([String], [String], Maybe Delta)
942+parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
938parseImports fname input
943parseImports fname input
939 = do i <- getIState
944 = do i <- getIState
940 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
945 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
@@ -942,7 +947,7 @@ parseImports fname input
942 Success (x, i) -> do -- Discard state updates (there should be
947 Success (x, i) -> do -- Discard state updates (there should be
943 -- none anyway)
948 -- none anyway)
945− where imports :: IdrisParser (([String], [String], Maybe Delta), IState)
950+ where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
946 imports = do whiteSpace
951 imports = do whiteSpace
947 mname <- moduleHeader
952 mname <- moduleHeader
948 ps <- many import_
953 ps <- many import_
@@ -1053,13 +1058,24 @@ loadSource h lidr f
1053 let def_total = default_total i
1058 let def_total = default_total i
1054 file_in <- runIO $ readFile f
1059 file_in <- runIO $ readFile f
1055 file <- if lidr then tclift $ unlit f file_in else return file_in
1060 file <- if lidr then tclift $ unlit f file_in else return file_in
1056− (mname, modules, pos) <- parseImports f file
1061+ (mname, imports, pos) <- parseImports f file
1063+ -- process and check module aliases
1064+ let modAliases = M.fromList
1065+ [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1066+ prep = map T.pack . reverse . Spl.splitOn "/"
1067+ aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1068+ histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1069+ case map head . filter ((/= 1) . length) $ histogram of
1070+ [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1071+ (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1057 i <- getIState
1073 i <- getIState
1058− putIState (i { default_access = Hidden })
1074+ putIState (i { default_access = Hidden, module_aliases = modAliases })
1059 clearIBC -- start a new .ibc file
1075 clearIBC -- start a new .ibc file
1060− mapM_ (addIBC . IBCImport) modules
1076+ mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1061− ds' <- parseProg (defaultSyntax {syn_namespace = reverse mname })
1077+ let syntax = defaultSyntax{ syn_namespace = reverse mname }
1062− f file pos
1078+ ds' <- parseProg syntax f file pos
1063 unless (null ds') $ do
1079 unless (null ds') $ do
1064 let ds = namespaces mname ds'
1080 let ds = namespaces mname ds'
1065 logLvl 3 (show $ showDecls True ds)
1081 logLvl 3 (show $ showDecls True ds)