1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE BangPatterns, UnboxedTuples, OverloadedStrings #-}
3module Parse.Primitives.Variable
17import Control.Exception (assert)
18import Data.Bits ((.&.), (.|.), shiftL)
19import qualified Data.Char as Char
20import qualified Data.Set as Set
21import Data.Text (Text)
22import Foreign.ForeignPtr (ForeignPtr)
23import GHC.Word (Word8)
25import qualified AST.Source as Src
26import qualified Elm.Name as N
27import Parse.Primitives.Internals (Parser(..), State(..), expect, noError, unsafeIndex)
28import qualified Reporting.Error.Syntax as E
37 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
38 let (# newOffset, newCol #) = chompUpper fp offset terminal col in
39 if offset == newOffset then
40 eerr (expect row col ctx E.CapVar)
42 let !name = N.fromForeignPtr fp offset (newOffset - offset) in
43 cok name (State fp newOffset terminal indent row newCol ctx) noError
52 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
53 let (# newOffset, newCol #) = chompLower fp offset terminal col in
54 if offset == newOffset then
55 eerr (expect row col ctx E.LowVar)
57 let !name = N.fromForeignPtr fp offset (newOffset - offset) in
58 if Set.member name reservedWords then
59 eerr (expect row col ctx E.LowVar)
61 cok name (State fp newOffset terminal indent row newCol ctx) noError
64{-# NOINLINE reservedWords #-}
65reservedWords :: Set.Set Text
68 [ "if", "then", "else"
73 , "import", "exposing"
83moduleName :: Parser Text
85 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
86 let (# newOffset, newCol #) = chompUpper fp offset terminal col in
87 case moduleNameHelp fp newOffset terminal newCol of
89 eerr (expect row badCol ctx E.CapVar)
93 !name = N.fromForeignPtr fp offset (end - offset)
94 !newState = State fp end terminal indent row endCol ctx
96 cok name newState noError
99data ModuleName = Bad Int | Good Int Int
102moduleNameHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> ModuleName
103moduleNameHelp fp offset terminal col =
104 if isDot fp offset terminal then
106 !offset1 = offset + 1
107 (# newOffset, newCol #) = chompUpper fp offset1 terminal (col + 1)
109 if offset1 == newOffset then
112 moduleNameHelp fp newOffset terminal newCol
124 | Qualified N.Name N.Name
127foreignUpper :: Parser Upper
129 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
130 let (# start, end, newCol #) = foreignUpperHelp fp offset terminal col in
132 eerr (expect row newCol ctx E.CapVar)
135 !newState = State fp end terminal indent row newCol ctx
136 !name = N.fromForeignPtr fp start (end - start)
138 if start == offset then
141 let !home = N.fromForeignPtr fp offset ((start - 1) - offset) in
144 cok foreign newState noError
147foreignUpperHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int, Int #)
148foreignUpperHelp fp offset terminal col =
150 (# newOffset, newCol #) = chompUpper fp offset terminal col
152 if offset == newOffset then
153 (# offset, offset, col #)
155 else if isDot fp newOffset terminal then
156 foreignUpperHelp fp (newOffset + 1) terminal (newCol + 1)
159 (# offset, newOffset, newCol #)
166foreignAlpha :: Parser Src.Expr_
168 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
169 let (# start, end, newCol, varType #) = foreignAlphaHelp fp offset terminal col in
171 eerr (E.ParseError row newCol (E.Theories ctx [E.LowVar, E.CapVar]))
174 !newState = State fp end terminal indent row newCol ctx
175 !name = N.fromForeignPtr fp start (end - start)
177 if start == offset then
178 if Set.member name reservedWords then
181 cok (Src.Var varType name) newState noError
183 let !home = N.fromForeignPtr fp offset ((start - 1) - offset) in
184 cok (Src.VarQual varType home name) newState noError
187foreignAlphaHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int, Int, Src.VarType #)
188foreignAlphaHelp fp offset terminal col =
190 (# lowerOffset, lowerCol #) = chompLower fp offset terminal col
192 if offset < lowerOffset then
193 (# offset, lowerOffset, lowerCol, Src.Value #)
197 (# upperOffset, upperCol #) = chompUpper fp offset terminal col
199 if offset == upperOffset then
200 (# offset, offset, col, Src.Ctor #)
202 else if isDot fp upperOffset terminal then
203 foreignAlphaHelp fp (upperOffset + 1) terminal (upperCol + 1)
206 (# offset, upperOffset, upperCol, Src.Ctor #)
210---- CHAR CHOMPERS ----
218isDot :: ForeignPtr Word8 -> Int -> Int -> Bool
219isDot fp offset terminal =
220 offset < terminal && unsafeIndex fp offset == 0x2e {- . -}
227chompUpper :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
228chompUpper fp offset terminal col =
229 let !width = getUpperWidth fp offset terminal in
233 chompInnerChars fp (offset + width) terminal (col + 1)
236{-# INLINE getUpperWidth #-}
237getUpperWidth :: ForeignPtr Word8 -> Int -> Int -> Int
238getUpperWidth fp offset terminal =
239 if offset < terminal then
240 getUpperWidthHelp fp offset terminal (unsafeIndex fp offset)
245{-# INLINE getUpperWidthHelp #-}
246getUpperWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
247getUpperWidthHelp fp offset terminal word
248 | 0x41 {- A -} <= word && word <= 0x5A {- Z -} = 1
250 | word < 0xe0 = if Char.isUpper (getChar2 fp offset terminal word) then 2 else 0
251 | word < 0xf0 = if Char.isUpper (getChar3 fp offset terminal word) then 3 else 0
252 | word < 0xf8 = if Char.isUpper (getChar4 fp offset terminal word) then 4 else 0
260chompLower :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
261chompLower fp offset terminal col =
262 let !width = getLowerWidth fp offset terminal in
266 chompInnerChars fp (offset + width) terminal (col + 1)
269{-# INLINE getLowerWidth #-}
270getLowerWidth :: ForeignPtr Word8 -> Int -> Int -> Int
271getLowerWidth fp offset terminal =
272 if offset < terminal then
273 getLowerWidthHelp fp offset terminal (unsafeIndex fp offset)
278{-# INLINE getLowerWidthHelp #-}
279getLowerWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
280getLowerWidthHelp fp offset terminal word
281 | 0x61 {- a -} <= word && word <= 0x7A {- z -} = 1
283 | word < 0xe0 = if Char.isLower (getChar2 fp offset terminal word) then 2 else 0
284 | word < 0xf0 = if Char.isLower (getChar3 fp offset terminal word) then 3 else 0
285 | word < 0xf8 = if Char.isLower (getChar4 fp offset terminal word) then 4 else 0
293chompInnerChars :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
294chompInnerChars fp !offset terminal !col =
295 let !width = getInnerWidth fp offset terminal in
299 chompInnerChars fp (offset + width) terminal (col + 1)
302getInnerWidth :: ForeignPtr Word8 -> Int -> Int -> Int
303getInnerWidth fp offset terminal =
304 if offset < terminal then
305 getInnerWidthHelp fp offset terminal (unsafeIndex fp offset)
310{-# INLINE getInnerWidthHelp #-}
311getInnerWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
312getInnerWidthHelp fp offset terminal word
313 | 0x61 {- a -} <= word && word <= 0x7A {- z -} = 1
314 | 0x41 {- A -} <= word && word <= 0x5A {- Z -} = 1
315 | 0x30 {- 0 -} <= word && word <= 0x39 {- 9 -} = 1
316 | word == 0x5F {- _ -} = 1
318 | word < 0xe0 = if Char.isAlpha (getChar2 fp offset terminal word) then 2 else 0
319 | word < 0xf0 = if Char.isAlpha (getChar3 fp offset terminal word) then 3 else 0
320 | word < 0xf8 = if Char.isAlpha (getChar4 fp offset terminal word) then 4 else 0
328push :: Word8 -> Int -> Int
330 assert (word .&. 0xc0 == 0x80) (
331 shiftL code 6 .|. fromEnum (word .&. 0x3f)
335getChar2 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
336getChar2 fp offset terminal word =
337 assert (offset + 2 <= terminal) (
339 !word1 = word .&. 0x1f
340 !word2 = unsafeIndex fp (offset + 1)
341 !code = push word2 (fromEnum word1)
343 assert (0x80 <= code) (
349getChar3 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
350getChar3 fp offset terminal word =
351 assert (offset + 3 <= terminal) (
353 !word1 = word .&. 0x0f
354 !word2 = unsafeIndex fp (offset + 1)
355 !word3 = unsafeIndex fp (offset + 2)
356 !code = push word3 (push word2 (fromEnum word1))
358 assert ((0x800 <= code && code < 0xd800) || (0xdfff < code && code < 0xfffe)) (
364getChar4 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
365getChar4 fp offset terminal word =
366 assert (offset + 4 <= terminal) (
368 !word1 = word .&. 0x07
369 !word2 = unsafeIndex fp (offset + 1)
370 !word3 = unsafeIndex fp (offset + 2)
371 !word4 = unsafeIndex fp (offset + 3)
372 !code = push word4 (push word3 (push word2 (fromEnum word1)))
374 assert (0x10000 <= code && code < 0x110000) (
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