on master help sign in
New syntax and semantics for imports

The new syntax has the following variations import List import List exposing (map, filter) import List exposing (..) import List as L import List as L exposing (..) In all cases we are able to refer to members of the List module qualified. In cases 1, 2, and 3, we can say List.foldl or List.isEmpty. In cases 4 and 5, we give an alias for the module so we can say L.foldl or L.isEmpty. When the “exposing” keyword is used, it brings in certain values that do not need to be qualified. You can explicitly list all exposed values, but it’s also possible to do a wildcard and just expose everything.

commit2234b88396395ec8633b20a4af5261517059d8c4 authorEvan Czaplicki <info@elm-lang.org> dateSat 7 Feb 2015, 17:30 (12 years ago) parent1cf108f
7 files changed+99−117
src/AST/Module.hs+39−30 src/AST/Variable.hs+10 src/Elm/Compiler/Module.hs+1−1 src/Parse/Helpers.hs+1−1 src/Parse/Module.hs+19−14 src/Transform/AddDefaultImports.hs+12−62 src/Transform/Canonicalize/Setup.hs+17−9
src/AST/Module.hs+39−30
@@ -1,4 +1,14 @@
1−module AST.Module where
1+module AST.Module
2+ ( Interfaces
3+ , Types, Aliases, ADTs
4+ , AdtInfo, CanonicalAdt
5+ , SourceModule, ValidModule, CanonicalModule
6+ , Module(..), CanonicalBody(..)
7+ , HeaderAndImports(..)
8+ , Name, nameToString, nameIsNative
9+ , Interface(..), toInterface
10+ , ImportMethod(..)
11+ ) where
212
313import Data.Binary
414import qualified Data.List as List
@@ -65,10 +75,14 @@ data HeaderAndImports = HeaderAndImports
6575 , _imports :: [(Name, ImportMethod)]
6676 }
6777
78+
6879type Name = [String] -- must be non-empty
6980
81+
7082nameToString :: Name -> String
71−nameToString = List.intercalate "."
83+nameToString =
84+ List.intercalate "."
85+
7286
7387nameIsNative :: Name -> Bool
7488nameIsNative name =
@@ -121,27 +135,19 @@ instance Binary Interface where
121135
122136-- IMPORT METHOD
123137
124−data ImportMethod
125− = As !String
126− | Open !(Var.Listing Var.Value)
127−
128−open :: ImportMethod
129−open = Open (Var.openListing)
138+data ImportMethod = ImportMethod
139+ { alias :: Maybe String
140+ , exposedVars :: !(Var.Listing Var.Value)
141+ }
130142
131−importing :: [Var.Value] -> ImportMethod
132−importing xs = Open (Var.Listing xs False)
133143
134144instance Binary ImportMethod where
135− put method =
136− case method of
137− As alias -> putWord8 0 >> put alias
138− Open listing -> putWord8 1 >> put listing
145+ put (ImportMethod alias exposedVars) =
146+ do put alias
147+ put exposedVars
139148
140− get = do tag <- getWord8
141− case tag of
142− 0 -> As <$> get
143− 1 -> Open <$> get
144− _ -> error "Error reading valid ImportMethod type from serialized string"
149+ get =
150+ ImportMethod <$> get <*> get
145151
146152
147153-- PRETTY PRINTING
@@ -150,19 +156,22 @@ instance (Pretty exs, Pretty body) => Pretty (Module exs body) where
150156 pretty (Module names _ exs ims body) =
151157 P.vcat [modul, P.text "", prettyImports, P.text "", pretty body]
152158 where
153− modul = P.text "module" <+> name <+> pretty exs <+> P.text "where"
154− name = P.text (List.intercalate "." names)
159+ modul =
160+ P.text "module" <+> name <+> pretty exs <+> P.text "where"
161+
162+ name =
163+ P.text (nameToString names)
155164
156165 prettyImports =
157− P.vcat $ map prettyMethod ims
166+ P.vcat $ map prettyMethod ims
158167
159168
160169prettyMethod :: (Name, ImportMethod) -> Doc
161−prettyMethod import' =
162− case import' of
163− ([name], As alias)
164− | name == alias -> P.empty
165−
166− (_, As alias) -> P.text "as" <+> P.text alias
167−
168− (_, Open listing) -> pretty listing
170+prettyMethod (name, ImportMethod maybeAlias exposedVars) =
171+ let prettyAlias =
172+ case maybeAlias of
173+ Nothing -> P.empty
174+ Just alias ->
175+ P.text "as" <+> P.text alias
176+ in
177+ prettyAlias <+> pretty exposedVars
src/AST/Variable.hs+10
@@ -126,6 +126,16 @@ openListing =
126126 Listing [] True
127127
128128
129+closedListing :: Listing a
130+closedListing =
131+ Listing [] False
132+
133+
134+listing :: [a] -> Listing a
135+listing xs =
136+ Listing xs False
137+
138+
129139-- | A value that can be imported or exported
130140data Value
131141 = Value !String
src/Elm/Compiler/Module.hs+1−1
@@ -34,7 +34,7 @@ newtype Name = Name [String]
3434
3535defaultImports :: [Name]
3636defaultImports =
37− map Name (Map.keys Defaults.defaultImports)
37+ map (Name . fst) Defaults.defaultImports
3838
3939
4040-- POKING AROUND INTERFACES
src/Parse/Helpers.hs+1−1
@@ -29,7 +29,7 @@ reserveds =
2929 , "let", "in"
3030 , "type"
3131 , "module", "where"
32− , "import", "as", "hiding", "open"
32+ , "import", "as", "hiding", "exposing"
3333 , "export", "foreign"
3434 , "deriving", "port"
3535 ]
src/Parse/Module.hs+19−14
@@ -1,7 +1,6 @@
11module Parse.Module (header, headerAndImports, getModuleName) where
22
33import Control.Applicative ((<$>), (<*>))
4−import Data.List (intercalate)
54import Text.Parsec hiding (newline, spaces)
65
76import Parse.Helpers
@@ -18,7 +17,7 @@ getModuleName source =
1817 getModuleName =
1918 do optional freshLine
2019 (names, _) <- header
21− return (intercalate "." names)
20+ return (Module.nameToString names)
2221
2322
2423headerAndImports :: IParser Module.HeaderAndImports
@@ -52,19 +51,25 @@ import' =
5251 do try (reserved "import")
5352 whitespace
5453 names <- dotSep1 capVar
55− (,) names <$> option (Module.As (intercalate "." names)) method
54+ (,) names <$> method (Module.nameToString names)
5655 where
57− method :: IParser Module.ImportMethod
58− method = as' <|> importing'
59−
60− as' :: IParser Module.ImportMethod
61− as' = do
62− try (whitespace >> reserved "as")
63− whitespace
64− Module.As <$> capVar <?> "alias for module"
65−
66− importing' :: IParser Module.ImportMethod
67− importing' = Module.Open <$> listing value
56+ method :: String -> IParser Module.ImportMethod
57+ method defaultAlias =
58+ Module.ImportMethod
59+ <$> option (Just defaultAlias) (Just <$> as')
60+ <*> option Var.closedListing exposing
61+
62+ as' :: IParser String
63+ as' =
64+ do try (whitespace >> reserved "as")
65+ whitespace
66+ capVar <?> "alias for module"
67+
68+ exposing :: IParser (Var.Listing Var.Value)
69+ exposing =
70+ do try (whitespace >> reserved "exposing")
71+ whitespace
72+ listing value
6873
6974
7075listing :: IParser a -> IParser (Var.Listing a)
src/Transform/AddDefaultImports.hs+12−62
@@ -1,47 +1,28 @@
1−{-# LANGUAGE FlexibleContexts #-}
21module Transform.AddDefaultImports (add, defaultImports) where
32
4−import Prelude hiding (maybe)
5−import qualified Data.Map as Map
6−
73import qualified AST.Module as Module
84import qualified AST.Variable as Var
95
106
11−type ImportDict =
12− Map.Map Module.Name ([String], Var.Listing Var.Value)
13−
14−
157-- DESCRIPTION OF DEFAULT IMPORTS
168
179(==>) :: a -> b -> (a,b)
1810(==>) = (,)
1911
2012
21−defaultImports :: ImportDict
13+defaultImports :: [(Module.Name, Module.ImportMethod)]
2214defaultImports =
23− Map.fromList
24− [ ["Basics"] ==> ([], Var.openListing)
25− , ["List"] ==> ([], Var.Listing [Var.Value "::"] False)
26− , ["Maybe"] ==> ([], Var.Listing [maybe] False)
27− , ["Result"] ==> ([], Var.Listing [result] False)
28− , ["Signal"] ==> ([], Var.Listing [signal] False)
15+ [ ["Basics"] ==> Module.ImportMethod Nothing Var.openListing
16+ , ["List"] ==> exposing [Var.Value "::"]
17+ , ["Maybe"] ==> exposing [Var.Union "Maybe" Var.openListing]
18+ , ["Result"] ==> exposing [Var.Union "Result" Var.openListing]
19+ , ["Signal"] ==> exposing [Var.Union "Signal" Var.closedListing]
2920 ]
3021
3122
32−maybe :: Var.Value
33−maybe =
34− Var.Union "Maybe" Var.openListing
35−
36−
37−result :: Var.Value
38−result =
39− Var.Union "Result" Var.openListing
40−
41−
42−signal :: Var.Value
43−signal =
44− Var.Union "Signal" (Var.Listing [] False)
23+exposing :: [Var.Value] -> Module.ImportMethod
24+exposing vars =
25+ Module.ImportMethod Nothing (Var.listing vars)
4526
4627
4728-- ADDING DEFAULT IMPORTS TO A MODULE
@@ -51,37 +32,6 @@ add needsDefaults (Module.Module moduleName path exports imports decls) =
5132 Module.Module moduleName path exports ammendedImports decls
5233 where
5334 ammendedImports =
54− importDictToList $
55− foldr addImport (if needsDefaults then defaultImports else Map.empty) imports
56−
57−
58−importDictToList :: ImportDict -> [(Module.Name, Module.ImportMethod)]
59−importDictToList dict =
60− concatMap toImports (Map.toList dict)
61− where
62− toImports (name, (qualifiers, listing@(Var.Listing explicits open))) =
63− map (\qualifier -> (name, Module.As qualifier)) qualifiers
64− ++
65− if open || not (null explicits)
66− then [(name, Module.Open listing)]
67− else []
68−
69−
70−addImport :: (Module.Name, Module.ImportMethod) -> ImportDict -> ImportDict
71−addImport (name, method) importDict =
72− Map.alter mergeMethods name importDict
73− where
74− mergeMethods :: Maybe ([String], Var.Listing Var.Value)
75− -> Maybe ([String], Var.Listing Var.Value)
76− mergeMethods entry =
77− let (qualifiers, listing) =
78− case entry of
79− Nothing -> ([], Var.Listing [] False)
80− Just v -> v
81− in
82− case method of
83− Module.As qualifier ->
84− Just (qualifier : qualifiers, listing)
85−
86− Module.Open newListing ->
87− Just (qualifiers, newListing)
35+ if needsDefaults
36+ then defaultImports ++ imports
37+ else imports
src/Transform/Canonicalize/Setup.hs+17−9
@@ -73,20 +73,26 @@ addImports moduleName interfaces environ (name, method)
7373 return environ
7474
7575 | otherwise =
76− case method of
77− Module.As name' ->
78− return (updateEnviron (name' ++ "."))
76+ let (Module.ImportMethod maybeAlias listing) = method
7977
80− Module.Open (Var.Listing vs open)
81− | open -> return (updateEnviron "")
82− | otherwise -> foldM (addValue name interface) environ vs
78+ (Var.Listing exposedVars open) = listing
79+
80+ qualifier =
81+ maybe (Module.nameToString name) id maybeAlias
82+
83+ env =
84+ updateEnviron (qualifier ++ ".") environ
85+ in
86+ if open
87+ then return (updateEnviron "" env)
88+ else foldM (addValue name interface) env exposedVars
8389 where
8490 interface =
8591 Interface.filterExports ((Map.!) interfaces name)
8692
87− updateEnviron prefix =
93+ updateEnviron prefix env =
8894 let dict' = dict . map (first (prefix++)) in
89− merge environ $
95+ merge env $
9096 Env { _home = moduleName
9197 , _values = dict' $ map pair (Map.keys (iTypes interface)) ++ ctors
9298 , _adts = dict' $ map pair (Map.keys (iAdts interface))
@@ -106,7 +112,9 @@ addImports moduleName interfaces environ (name, method)
106112 (x, (canonical x, tvars, tipe))
107113
108114 ctors =
109− concatMap (map (pair . fst) . snd . snd) (Map.toList (iAdts interface))
115+ concatMap
116+ (map (pair . fst) . snd . snd)
117+ (Map.toList (iAdts interface))
110118
111119
112120addValue