@@ -10,6 +10,7 @@ import System.FilePath
10import System.IO
10import System.IO
12import qualified Data.Binary as Binary
12import qualified Data.Binary as Binary
13+import qualified Data.List as List
13import qualified Data.Maybe as Maybe
14import qualified Data.Maybe as Maybe
14import qualified Data.Map as Map
15import qualified Data.Map as Map
15import qualified Data.ByteString.Lazy as L
16import qualified Data.ByteString.Lazy as L
@@ -34,17 +35,37 @@ type Build a = BuildT IO a
34-- Interfaces, remembering if something was recompiled
35-- Interfaces, remembering if something was recompiled
35type BInterfaces = Map.Map String (Bool, M.ModuleInterface)
36type BInterfaces = Map.Map String (Bool, M.ModuleInterface)
37−evalBuild :: Flag.Flags -> M.Interfaces -> Build () -> IO (Maybe String)
38+evalBuild :: Flag.Flags -> M.Interfaces -> Build ()
39+ -> IO (Map.Map String M.ModuleInterface, Maybe String)
38−evalBuild flags interfaces b = do
40+evalBuild flags interfaces build =
39− (_, s) <- evalRWST b flags (fmap notUpdated interfaces)
41+ do (ifaces, moduleNames) <- execRWST build flags (fmap notUpdated interfaces)
40− return . getLast $ s
42+ return (fmap snd ifaces, getLast moduleNames)
42− notUpdated i = (False, i)
44+ notUpdated iface = (False, iface)
44-- | Builds a list of files, returning the moduleName of the last one.
46-- | Builds a list of files, returning the moduleName of the last one.
45-- Returns \"\" if the list is empty
47-- Returns \"\" if the list is empty
46build :: Flag.Flags -> M.Interfaces -> [FilePath] -> IO String
48build :: Flag.Flags -> M.Interfaces -> [FilePath] -> IO String
49+build flags interfaces files =
47−build flags is = fmap (Maybe.fromMaybe "") . evalBuild flags is . buildAll
50+ do (ifaces, topName) <- evalBuild flags interfaces (buildAll files)
51+ let removeTopName = Maybe.maybe id Map.delete topName
52+ mapM_ (checkPorts topName) (Map.toList $ removeTopName ifaces)
53+ return $ Maybe.fromMaybe "" topName
55+ checkPorts topName (name,iface)
56+ | null ports = return ()
57+ | otherwise = Print.failure msg
59+ ports = M.iPorts iface
61+ [ "Port Error: ports may only appear in the main module, but\n"
62+ , " sub-module ", name, " declares the following port"
63+ , if length ports == 1 then "" else "s", ": "
64+ , List.intercalate ", " ports
67+ Just tname -> "\n All ports must appear in module " ++ tname
49buildAll :: [FilePath] -> Build ()
70buildAll :: [FilePath] -> Build ()
50buildAll fs = mapM_ (uncurry build1) (zip [1..] fs)
71buildAll fs = mapM_ (uncurry build1) (zip [1..] fs)