@@ -1,15 +1,17 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Elm.Kernel
3module Elm.Kernel
4− ( Kernel(..)
4+ ( Opt.KContent(..)
10import qualified Data.ByteString as B
10import qualified Data.ByteString as B
11+import qualified Data.List as List
11import qualified Data.Map as Map
12import qualified Data.Map as Map
12import Data.Monoid ((<>))
13import Data.Monoid ((<>))
14+import qualified Data.Set as Set
13import qualified Data.Text as Text
15import qualified Data.Text as Text
14import Data.Word (Word8)
16import Data.Word (Word8)
@@ -18,6 +20,7 @@ import qualified AST.Optimized as Opt
18import qualified AST.Source as Src
20import qualified AST.Source as Src
19import qualified AST.Module.Name as ModuleName
21import qualified AST.Module.Name as ModuleName
20import qualified Elm.Name as N
22import qualified Elm.Name as N
23+import qualified Elm.Package as Pkg
21import Parse.Primitives (Parser, run)
24import Parse.Primitives (Parser, run)
22import qualified Parse.Primitives.Kernel as K
25import qualified Parse.Primitives.Kernel as K
23import qualified Parse.Primitives.Symbol as Symbol
26import qualified Parse.Primitives.Symbol as Symbol
@@ -30,16 +33,13 @@ import qualified Reporting.Error as E
33−data Kernel =
36+type ImportDict =
34− Kernel
37+ Map.Map N.Name [Pkg.Name]
35− { _imports :: [(N.Name, N.Name)]
36− , _chunks :: [Opt.KChunk]
40−parse :: B.ByteString -> Either E.Error Kernel
40+parse :: ImportDict -> B.ByteString -> Either E.Error Opt.KContent
41−parse sourceCode =
41+parse importDict sourceCode =
42− case run parser sourceCode of
42+ case run (parser importDict) sourceCode of
43 Right kernel ->
43 Right kernel ->
44 Right kernel
44 Right kernel
@@ -47,23 +47,128 @@ parse sourceCode =
47 Left (E.Syntax err)
47 Left (E.Syntax err)
54−parser :: Parser Kernel
50+parser :: ImportDict -> Parser Opt.KContent
55−parser =
51+parser importDict =
56 do Symbol.jsMultiCommentOpen
52 do Symbol.jsMultiCommentOpen
57 Module.freshLine
53 Module.freshLine
58− srcImports <- Module.chompImports []
54+ imports <- Module.chompImports []
59 Symbol.jsMultiCommentClose
55 Symbol.jsMultiCommentClose
60− let imports = Map.unions (map destructImport srcImports)
56+
57+ let (State vtable deps) = processImports importDict imports
61− chunks <- parserHelp imports Map.empty Map.empty []
59+ chunks <- chompChunks vtable Map.empty Map.empty []
62− return $ Kernel (Map.elems imports) chunks
60+
61+ return $ Opt.KContent chunks deps
69+ Map.Map Text.Text Opt.KChunk
73+ State VarTable (Set.Set Opt.Global)
76+processImports :: ImportDict -> [Src.Import] -> State
77+processImports importDict imports =
78+ List.foldl' (addImport importDict) (State Map.empty Set.empty) imports
81+addImport :: ImportDict -> State -> Src.Import -> State
82+addImport importDict state (Src.Import (A.At _ home) maybeAlias exposing) =
83+ if ModuleName.isKernel home then
86+ error ("Cannot use aliases on kernel import of: " ++ show home)
89+ addKernelImport (ModuleName.getKernel home) exposing state
92+ case Map.lookup home importDict of
95+ canonicalHome = ModuleName.Canonical pkg home
96+ prefix = toPrefix home maybeAlias
98+ addNormalImport canonicalHome prefix exposing state
101+ error ("Cannot find kernel import of: " ++ show home)
104+-- INVARIANT: the `home` is the * in `Elm.Kernel.*`
106+addKernelImport :: N.Name -> Src.Exposing -> State -> State
107+addKernelImport home exposing (State vtable deps) =
110+ Map.insert (home <> "_" <> name) (Opt.JsVar home name) table
113+ (List.foldl' addVar vtable (toNames exposing))
114+ (Set.insert (Opt.kernel home) deps)
117+addNormalImport :: ModuleName.Canonical -> N.Name -> Src.Exposing -> State -> State
118+addNormalImport home prefix exposing state =
120+ addVar (State vtable deps) name =
122+ (Map.insert (prefix <> "_" <> name) (Opt.ElmVar home name) vtable)
123+ (Set.insert (Opt.Global home name) deps)
125+ List.foldl' addVar state (toNames exposing)
128+toPrefix :: N.Name -> Maybe N.Name -> N.Name
129+toPrefix home maybeAlias =
135+ if Text.isInfixOf "." home then
136+ error ("kernel imports with dots need an alias: " ++ show home)
140+toNames :: Src.Exposing -> [N.Name]
144+ error "Cannot have `exposing (..)` in kernel code."
146+ Src.Explicit exposedList ->
147+ map toName exposedList
150+toName :: A.Located Src.Exposed -> N.Name
151+toName (A.At _ exposed) =
156+ Src.Upper name Src.Private ->
159+ Src.Upper _ Src.Public ->
160+ error "cannot have Maybe(..) syntax in kernel code header"
163+ error "cannot use binops in kernel code"
65−parserHelp :: Imports -> Enums -> Fields -> [Opt.KChunk] -> Parser [Opt.KChunk]
170+chompChunks :: VarTable -> Enums -> Fields -> [Opt.KChunk] -> Parser [Opt.KChunk]
66−parserHelp imports enums fields chunks =
171+chompChunks vtable enums fields chunks =
67 do (javascript, maybeTag) <- K.chunk
172 do (javascript, maybeTag) <- K.chunk
68 case maybeTag of
173 case maybeTag of
69 Nothing ->
174 Nothing ->
@@ -72,34 +177,34 @@ parserHelp imports enums fields chunks =
72 Just tag ->
177 Just tag ->
73 case tag of
178 case tag of
74 K.Prod ->
179 K.Prod ->
75− parserHelp imports enums fields $
180+ chompChunks vtable enums fields $
76 Opt.Prod : Opt.JS javascript : chunks
181 Opt.Prod : Opt.JS javascript : chunks
78 K.Debug ->
183 K.Debug ->
79− parserHelp imports enums fields $
184+ chompChunks vtable enums fields $
80 Opt.Debug : Opt.JS javascript : chunks
185 Opt.Debug : Opt.JS javascript : chunks
82 K.Import var ->
187 K.Import var ->
83− case Map.lookup var imports of
188+ case Map.lookup var vtable of
84 Nothing ->
189 Nothing ->
85 error ("Bad kernel symbol: " ++ Text.unpack var)
190 error ("Bad kernel symbol: " ++ Text.unpack var)
87− Just (home, name) ->
192+ Just chunk ->
88− parserHelp imports enums fields $
193+ chompChunks vtable enums fields $
89− Opt.Var home name : Opt.JS javascript : chunks
194+ chunk : Opt.JS javascript : chunks
91 K.Enum n var ->
196 K.Enum n var ->
92 let (enum, newEnums) = lookupEnum n var enums in
197 let (enum, newEnums) = lookupEnum n var enums in
93− parserHelp imports newEnums fields $
198+ chompChunks vtable newEnums fields $
94 Opt.Enum enum : Opt.JS javascript : chunks
199 Opt.Enum enum : Opt.JS javascript : chunks
96 K.ElmField name ->
201 K.ElmField name ->
97− parserHelp imports enums fields $
202+ chompChunks vtable enums fields $
98 Opt.ElmField name : Opt.JS javascript : chunks
203 Opt.ElmField name : Opt.JS javascript : chunks
100 K.JsField name ->
205 K.JsField name ->
101 let (field, newFields) = lookupField name fields in
206 let (field, newFields) = lookupField name fields in
102− parserHelp imports enums newFields $
207+ chompChunks vtable enums newFields $
103 Opt.JsField field : Opt.JS javascript : chunks
208 Opt.JsField field : Opt.JS javascript : chunks
@@ -143,55 +248,3 @@ lookupEnum word var allEnums =
143 Nothing ->
248 Nothing ->
144 let n = Map.size enums in
249 let n = Map.size enums in
145 ( n, Map.insert word (Map.insert var n enums) allEnums )
250 ( n, Map.insert word (Map.insert var n enums) allEnums )
153− Map.Map Text.Text (N.Name, N.Name)
156−destructImport :: Src.Import -> Imports
157−destructImport (Src.Import (A.At _ moduleName) maybeAlias exposing) =
165− if ModuleName.isKernel moduleName then
166− ModuleName.getKernel moduleName
167− else if Text.isInfixOf "." moduleName then
168− error ("modules with dots in kernel code need an alias: " ++ show moduleName)
173− ( shortName <> "_" <> name, ( moduleName, name ) )
175− Map.fromList $ map toEntry $
178− error "cannot have open imports in kernel code"
180− Src.Explicit exposed ->
181− map exposedToName exposed
184−exposedToName :: A.Located Src.Exposed -> N.Name
185−exposedToName (A.At _ exposed) =
190− Src.Upper name Src.Private ->
193− Src.Upper _ Src.Public ->
194− error "cannot have Maybe(..) syntax in kernel code header"
197− error "cannot use binops in kernel code"