on master help sign in
Add check that all ports appear in the "main" module

It is unclear what it means if ports are used in sub-modules, so to be cautious, we want to rule it out in the first release. As people use the API it’ll become clear how sub-module ports are necessary and what problems they might cause.

commitb00a8cb9b548fe11b226f2535070218d8d977459 authorEvan Czaplicki <info@elm-lang.org> dateMon 20 Jan 2014, 15:10 (13 years ago) parent066a164
5 files changed+49−15
compiler/Build/File.hs+27−6 compiler/Build/Source.hs+1 compiler/SourceSyntax/Declaration.hs+6 compiler/SourceSyntax/Module.hs+14−9 compiler/Transform/Canonicalize.hs+1
compiler/Build/File.hs+27−6
@@ -10,6 +10,7 @@ import System.FilePath
1010import System.IO
1111
1212import qualified Data.Binary as Binary
13+import qualified Data.List as List
1314import qualified Data.Maybe as Maybe
1415import qualified Data.Map as Map
1516import qualified Data.ByteString.Lazy as L
@@ -34,17 +35,37 @@ type Build a = BuildT IO a
3435-- Interfaces, remembering if something was recompiled
3536type BInterfaces = Map.Map String (Bool, M.ModuleInterface)
3637
37−evalBuild :: Flag.Flags -> M.Interfaces -> Build () -> IO (Maybe String)
38−evalBuild flags interfaces b = do
39− (_, s) <- evalRWST b flags (fmap notUpdated interfaces)
40− return . getLast $ s
38+evalBuild :: Flag.Flags -> M.Interfaces -> Build ()
39+ -> IO (Map.Map String M.ModuleInterface, Maybe String)
40+evalBuild flags interfaces build =
41+ do (ifaces, moduleNames) <- execRWST build flags (fmap notUpdated interfaces)
42+ return (fmap snd ifaces, getLast moduleNames)
4143 where
42− notUpdated i = (False, i)
44+ notUpdated iface = (False, iface)
4345
4446-- | Builds a list of files, returning the moduleName of the last one.
4547-- Returns \"\" if the list is empty
4648build :: Flag.Flags -> M.Interfaces -> [FilePath] -> IO String
47−build flags is = fmap (Maybe.fromMaybe "") . evalBuild flags is . buildAll
49+build flags interfaces files =
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
54+ where
55+ checkPorts topName (name,iface)
56+ | null ports = return ()
57+ | otherwise = Print.failure msg
58+ where
59+ ports = M.iPorts iface
60+ msg = concat
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
65+ , case topName of
66+ Nothing -> ""
67+ Just tname -> "\n All ports must appear in module " ++ tname
68+ ]
4869
4970buildAll :: [FilePath] -> Build ()
5071buildAll fs = mapM_ (uncurry build1) (zip [1..] fs)
compiler/Build/Source.hs+1
@@ -51,6 +51,7 @@ build noPrelude interfaces source =
5151 , datatypes = [ (name,vars,ctors) | Datatype name vars ctors <- decls ]
5252 , fixities = [ (assoc,level,op) | Fixity assoc level op <- decls ]
5353 , aliases = [ (name,tvs,tipe) | TypeAlias name tvs tipe <- decls ]
54+ , ports = [ portName port | Port port <- decls ]
5455 }
5556
5657 types <- TI.infer interfaces metaModule
compiler/SourceSyntax/Declaration.hs+6
@@ -28,6 +28,12 @@ data Port
2828 | In String T.Type
2929 deriving (Show)
3030
31+portName :: Port -> String
32+portName port =
33+ case port of
34+ Out name _ _ -> name
35+ In name _ -> name
36+
3137type ParseDeclaration = Declaration' ParsePort Expr.ParseDef
3238type Declaration = Declaration' Port Expr.Def
3339
compiler/SourceSyntax/Module.hs+14−9
@@ -47,20 +47,23 @@ data MetadataModule =
4747 , fixities :: [(Assoc, Int, String)]
4848 , aliases :: [Alias]
4949 , datatypes :: [ADT]
50+ , ports :: [String]
5051 } deriving Show
5152
5253type Interfaces = Map.Map String ModuleInterface
5354type ADT = (String, [String], [(String,[Type])])
5455type Alias = (String, [String], Type)
5556
56−data ModuleInterface = ModuleInterface {
57− iVersion :: Version.Version,
58− iTypes :: Map.Map String Type,
59− iImports :: [(String, ImportMethod)],
60− iAdts :: [ADT],
61− iAliases :: [Alias],
62− iFixities :: [(Assoc, Int, String)]
63−} deriving Show
57+data ModuleInterface =
58+ ModuleInterface
59+ { iVersion :: Version.Version
60+ , iTypes :: Map.Map String Type
61+ , iImports :: [(String, ImportMethod)]
62+ , iAdts :: [ADT]
63+ , iAliases :: [Alias]
64+ , iFixities :: [(Assoc, Int, String)]
65+ , iPorts :: [String]
66+ } deriving Show
6467
6568metaToInterface :: MetadataModule -> ModuleInterface
6669metaToInterface metaModule =
@@ -71,10 +74,11 @@ metaToInterface metaModule =
7174 , iAdts = datatypes metaModule
7275 , iAliases = aliases metaModule
7376 , iFixities = fixities metaModule
77+ , iPorts = ports metaModule
7478 }
7579
7680instance Binary ModuleInterface where
77− get = ModuleInterface <$> get <*> get <*> get <*> get <*> get <*> get
81+ get = ModuleInterface <$> get <*> get <*> get <*> get <*> get <*> get <*> get
7882 put modul = do
7983 put (iVersion modul)
8084 put (iTypes modul)
@@ -82,3 +86,4 @@ instance Binary ModuleInterface where
8286 put (iAdts modul)
8387 put (iAliases modul)
8488 put (iFixities modul)
89+ put (iPorts modul)
compiler/Transform/Canonicalize.hs+1
@@ -25,6 +25,7 @@ interface moduleName iface =
2525 , iAdts = map (both prefix renameCtors) (iAdts iface)
2626 , iAliases = map (both prefix renameType') (iAliases iface)
2727 , iFixities = iFixities iface -- cannot have canonicalized operators while parsing
28+ , iPorts = iPorts iface
2829 }
2930 where
3031 both f g (a,b,c) = (f a, b, g c)