1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE BangPatterns, EmptyDataDecls, OverloadedStrings, UnboxedTuples #-}
12import Control.Monad (liftM, liftM2)
13import Data.Binary (Binary, get, put, getWord8, putWord8)
14import qualified Data.ByteString.Internal as B
15import qualified Data.List as List
16import qualified Data.Map as Map
17import qualified Data.Name as Name
18import Data.Word (Word8, Word16)
19import Foreign.Ptr (Ptr, plusPtr, minusPtr)
20import Foreign.ForeignPtr (ForeignPtr)
21import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
23import qualified AST.Source as Src
24import qualified Elm.ModuleName as ModuleName
25import qualified Elm.Package as Pkg
26import qualified Parse.Module as Module
27import qualified Parse.Space as Space
28import qualified Parse.Variable as Var
29import Parse.Primitives hiding (fromByteString)
30import qualified Parse.Primitives as P
31import qualified Reporting.Annotation as A
40 | ElmVar ModuleName.Canonical Name.Name
41 | JsVar Name.Name Name.Name
53countFields :: [Chunk] -> Map.Map Name.Name Int
55 foldr addField Map.empty chunks
58addField :: Chunk -> Map.Map Name.Name Int -> Map.Map Name.Name Int
59addField chunk fields =
64 ElmField f -> Map.insertWith (+) f 1 fields
76 Content [Src.Import] [Chunk]
80 Map.Map ModuleName.Raw Pkg.Name
83fromByteString :: Pkg.Name -> Foreigns -> B.ByteString -> Maybe Content
84fromByteString pkg foreigns bytes =
85 case P.fromByteString (parser pkg foreigns) toError bytes of
93parser :: Pkg.Name -> Foreigns -> Parser () Content
95 do word2 0x2F 0x2A {-/*-} toError
96 Space.chomp ignoreError
97 Space.checkFreshLine toError
98 imports <- specialize ignoreError (Module.chompImports [])
99 word2 0x2A 0x2F {-*/-} toError
100 chunks <- parseChunks (toVarTable pkg foreigns imports) Map.empty Map.empty
101 return (Content imports chunks)
104toError :: Row -> Col -> ()
109ignoreError :: a -> Row -> Col -> ()
118parseChunks :: VarTable -> Enums -> Fields -> Parser () [Chunk]
119parseChunks vtable enums fields =
120 P.Parser $ \(P.State src pos end indent row col) cok _ cerr _ ->
122 (# chunks, newPos, newRow, newCol #) =
123 chompChunks vtable enums fields src pos end row col pos []
125 if newPos == end then
126 cok chunks (P.State src newPos end indent newRow newCol)
131chompChunks :: VarTable -> Enums -> Fields -> ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> Word16 -> Word16 -> Ptr Word8 -> [Chunk] -> (# [Chunk], Ptr Word8, Word16, Word16 #)
132chompChunks vs es fs src pos end row col lastPos revChunks =
134 let !js = toByteString src lastPos end in
135 (# reverse (JS js : revChunks), pos, row, col #)
138 let !word = unsafeIndex pos in
139 if word == 0x5F {-_-} then
141 !pos1 = plusPtr pos 1
142 !pos3 = plusPtr pos 3
144 if pos3 <= end && unsafeIndex pos1 == 0x5F {-_-} then
145 let !js = toByteString src lastPos pos in
146 chompTag vs es fs src pos3 end row (col + 3) (JS js : revChunks)
148 chompChunks vs es fs src pos1 end row (col + 1) lastPos revChunks
150 else if word == 0x0A {-\n-} then
151 chompChunks vs es fs src (plusPtr pos 1) end (row + 1) 1 lastPos revChunks
155 !newPos = plusPtr pos (getCharWidth word)
157 chompChunks vs es fs src newPos end row (col + 1) lastPos revChunks
160toByteString :: ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> B.ByteString
161toByteString src pos end =
163 !off = minusPtr pos (unsafeForeignPtrToPtr src)
164 !len = minusPtr end pos
170-- relies on external checks in chompChunks
171chompTag :: VarTable -> Enums -> Fields -> ForeignPtr Word8 -> Ptr Word8 -> Ptr Word8 -> Word16 -> Word16 -> [Chunk] -> (# [Chunk], Ptr Word8, Word16, Word16 #)
172chompTag vs es fs src pos end row col revChunks =
174 (# newPos, newCol #) = Var.chompInnerChars pos end col
175 !tagPos = plusPtr pos (-1)
176 !word = unsafeIndex tagPos
178 if word == 0x24 {-$-} then
180 !name = Name.fromPtr pos newPos
182 chompChunks vs es fs src newPos end row newCol newPos $
183 ElmField name : revChunks
186 !name = Name.fromPtr tagPos newPos
188 if 0x30 {-0-} <= word && word <= 0x39 {-9-} then
191 lookupEnum (word - 0x30) name es
193 chompChunks vs newEnums fs src newPos end row newCol newPos $
194 JsEnum enum : revChunks
196 else if 0x61 {-a-} <= word && word <= 0x7A {-z-} then
201 chompChunks vs es newFields src newPos end row newCol newPos $
202 JsField field : revChunks
204 else if name == "DEBUG" then
205 chompChunks vs es fs src newPos end row newCol newPos (Debug : revChunks)
207 else if name == "PROD" then
208 chompChunks vs es fs src newPos end row newCol newPos (Prod : revChunks)
211 case Map.lookup name vs of
213 chompChunks vs es fs src newPos end row newCol newPos (chunk : revChunks)
216 (# revChunks, pos, row, col #)
224 Map.Map Name.Name Int
227lookupField :: Name.Name -> Fields -> (Int, Fields)
228lookupField name fields =
229 case Map.lookup name fields of
234 let n = Map.size fields in
235 ( n, Map.insert name n fields )
243 Map.Map Word8 (Map.Map Name.Name Int)
246lookupEnum :: Word8 -> Name.Name -> Enums -> (Int, Enums)
247lookupEnum word var allEnums =
250 Map.findWithDefault Map.empty word allEnums
252 case Map.lookup var enums of
257 let n = Map.size enums in
258 ( n, Map.insert word (Map.insert var n enums) allEnums )
266 Map.Map Name.Name Chunk
269toVarTable :: Pkg.Name -> Foreigns -> [Src.Import] -> VarTable
270toVarTable pkg foreigns imports =
271 List.foldl' (addImport pkg foreigns) Map.empty imports
274addImport :: Pkg.Name -> Foreigns -> VarTable -> Src.Import -> VarTable
275addImport pkg foreigns vtable (Src.Import (A.At _ importName) maybeAlias exposing) =
276 if Name.isKernel importName then
279 error ("cannot use `as` with kernel import of: " ++ Name.toChars importName)
283 home = Name.getKernel importName
285 Map.insert (Name.sepBy 0x5F {-_-} home name) (JsVar home name) table
287 List.foldl' add vtable (toNames exposing)
291 home = ModuleName.Canonical (Map.findWithDefault pkg importName foreigns) importName
292 prefix = toPrefix importName maybeAlias
294 Map.insert (Name.sepBy 0x5F {-_-} prefix name) (ElmVar home name) table
296 List.foldl' add vtable (toNames exposing)
299toPrefix :: Name.Name -> Maybe Name.Name -> Name.Name
300toPrefix home maybeAlias =
306 if Name.hasDot home then
307 error ("kernel imports with dots need an alias: " ++ show (Name.toChars home))
312toNames :: Src.Exposing -> [Name.Name]
316 error "cannot have `exposing (..)` in kernel code."
318 Src.Explicit exposedList ->
319 map toName exposedList
322toName :: A.Located Src.Exposed -> Name.Name
323toName (A.At _ exposed) =
328 Src.Upper name Src.Private ->
331 Src.Upper _ Src.Public ->
332 error "cannot have Maybe(..) syntax in kernel code header"
335 error "cannot use binops in kernel code"
342instance Binary Chunk where
345 JS a -> putWord8 0 >> put a
346 ElmVar a b -> putWord8 1 >> put a >> put b
347 JsVar a b -> putWord8 2 >> put a >> put b
348 ElmField a -> putWord8 3 >> put a
349 JsField a -> putWord8 4 >> put a
350 JsEnum a -> putWord8 5 >> put a
358 1 -> liftM2 ElmVar get get
359 2 -> liftM2 JsVar get get
360 3 -> liftM ElmField get
361 4 -> liftM JsField get
362 5 -> liftM JsEnum get
365 _ -> error "problem deserializing Elm.Kernel.Chunk"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list