1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE BangPatterns, UnboxedTuples, OverloadedStrings #-}
3module Parse.Primitives.Variable
16import Control.Exception (assert)
17import Data.Bits ((.&.), (.|.), shiftL)
18import qualified Data.ByteString.Internal as B
19import qualified Data.Char as Char
20import qualified Data.Set as Set
21import Data.Text (Text)
22import qualified Data.Text.Encoding as Text
23import Foreign.ForeignPtr (ForeignPtr)
24import GHC.Word (Word8)
26import Parse.Primitives.Internals (Parser(..), State(..), expect, noError, unsafeIndex)
27import qualified Reporting.Error.Syntax as E
36 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
37 let (# newOffset, newCol #) = chompUpper fp offset terminal col in
38 if offset == newOffset then
39 eerr (expect row col ctx E.CapVar)
41 let !variable = Text.decodeUtf8 (B.PS fp offset (newOffset - offset)) in
42 cok variable (State fp newOffset terminal indent row newCol ctx) noError
51 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
52 let (# newOffset, newCol #) = chompLower fp offset terminal col in
53 if offset == newOffset then
54 eerr (expect row col ctx E.LowVar)
56 let !variable = Text.decodeUtf8 (B.PS fp offset (newOffset - offset)) in
57 if Set.member variable reservedWords then
58 eerr (expect row col ctx E.LowVar)
60 cok variable (State fp newOffset terminal indent row newCol ctx) noError
63{-# NOINLINE reservedWords #-}
64reservedWords :: Set.Set Text
67 [ "if", "then", "else"
72 , "import", "exposing"
82moduleName :: Parser Text
84 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
85 let (# newOffset, newCol #) = chompUpper fp offset terminal col in
86 case moduleNameHelp fp newOffset terminal newCol of
88 eerr (expect row badCol ctx E.CapVar)
92 !name = Text.decodeUtf8 (B.PS fp offset (end - offset))
93 !newState = State fp end terminal indent row endCol ctx
95 cok name newState noError
98data ModuleName = Bad Int | Good Int Int
101moduleNameHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> ModuleName
102moduleNameHelp fp offset terminal col =
103 if isDot fp offset terminal then
105 !offset1 = offset + 1
106 (# newOffset, newCol #) = chompUpper fp offset1 terminal (col + 1)
108 if offset1 == newOffset then
111 moduleNameHelp fp newOffset terminal newCol
121foreignUpper :: Parser (Maybe Text, Text)
123 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
124 let (# start, end, newCol #) = foreignUpperHelp fp offset terminal col in
126 eerr (expect row newCol ctx E.CapVar)
129 !newState = State fp end terminal indent row newCol ctx
130 !variable = Text.decodeUtf8 (B.PS fp start (end - start))
132 if start == offset then
135 let !home = Text.decodeUtf8 (B.PS fp offset ((start - 1) - offset)) in
136 (Just home, variable)
138 cok foreign newState noError
141foreignUpperHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int, Int #)
142foreignUpperHelp fp offset terminal col =
144 (# newOffset, newCol #) = chompUpper fp offset terminal col
146 if offset == newOffset then
147 (# offset, offset, col #)
149 else if isDot fp newOffset terminal then
150 foreignUpperHelp fp (newOffset + 1) terminal (newCol + 1)
153 (# offset, newOffset, newCol #)
160foreignAlpha :: Parser (Maybe Text, Text)
162 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
163 let (# start, end, newCol #) = foreignAlphaHelp fp offset terminal col in
165 eerr (E.ParseError row newCol (E.Theories ctx [E.LowVar, E.CapVar]))
168 !newState = State fp end terminal indent row newCol ctx
169 !variable = Text.decodeUtf8 (B.PS fp start (end - start))
171 if start == offset then
172 if Set.member variable reservedWords then
175 cok (Nothing, variable) newState noError
177 let !home = Text.decodeUtf8 (B.PS fp offset ((start - 1) - offset)) in
178 cok (Just home, variable) newState noError
181foreignAlphaHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int, Int #)
182foreignAlphaHelp fp offset terminal col =
184 (# lowerOffset, lowerCol #) = chompLower fp offset terminal col
186 if offset < lowerOffset then
187 (# offset, lowerOffset, lowerCol #)
191 (# upperOffset, upperCol #) = chompUpper fp offset terminal col
193 if offset == upperOffset then
194 (# offset, offset, col #)
196 else if isDot fp upperOffset terminal then
197 foreignAlphaHelp fp (upperOffset + 1) terminal (upperCol + 1)
200 (# offset, upperOffset, upperCol #)
204---- CHAR CHOMPERS ----
212isDot :: ForeignPtr Word8 -> Int -> Int -> Bool
213isDot fp offset terminal =
214 offset < terminal && unsafeIndex fp offset == 0x2e {- . -}
221chompUpper :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
222chompUpper fp offset terminal col =
223 let !width = getUpperWidth fp offset terminal in
227 chompInnerChars fp (offset + width) terminal (col + 1)
230{-# INLINE getUpperWidth #-}
231getUpperWidth :: ForeignPtr Word8 -> Int -> Int -> Int
232getUpperWidth fp offset terminal =
233 if offset < terminal then
234 getUpperWidthHelp fp offset terminal (unsafeIndex fp offset)
239{-# INLINE getUpperWidthHelp #-}
240getUpperWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
241getUpperWidthHelp fp offset terminal word
242 | 0x41 {- A -} <= word && word <= 0x5A {- Z -} = 1
244 | word < 0xe0 = if Char.isUpper (getChar2 fp offset terminal word) then 2 else 0
245 | word < 0xf0 = if Char.isUpper (getChar3 fp offset terminal word) then 3 else 0
246 | word < 0xf8 = if Char.isUpper (getChar4 fp offset terminal word) then 4 else 0
254chompLower :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
255chompLower fp offset terminal col =
256 let !width = getLowerWidth fp offset terminal in
260 chompInnerChars fp (offset + width) terminal (col + 1)
263{-# INLINE getLowerWidth #-}
264getLowerWidth :: ForeignPtr Word8 -> Int -> Int -> Int
265getLowerWidth fp offset terminal =
266 if offset < terminal then
267 getLowerWidthHelp fp offset terminal (unsafeIndex fp offset)
272{-# INLINE getLowerWidthHelp #-}
273getLowerWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
274getLowerWidthHelp fp offset terminal word
275 | 0x61 {- a -} <= word && word <= 0x7A {- z -} = 1
277 | word < 0xe0 = if Char.isLower (getChar2 fp offset terminal word) then 2 else 0
278 | word < 0xf0 = if Char.isLower (getChar3 fp offset terminal word) then 3 else 0
279 | word < 0xf8 = if Char.isLower (getChar4 fp offset terminal word) then 4 else 0
287chompInnerChars :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
288chompInnerChars fp !offset terminal !col =
289 let !width = getInnerWidth fp offset terminal in
293 chompInnerChars fp (offset + width) terminal (col + 1)
296getInnerWidth :: ForeignPtr Word8 -> Int -> Int -> Int
297getInnerWidth fp offset terminal =
298 if offset < terminal then
299 getInnerWidthHelp fp offset terminal (unsafeIndex fp offset)
304{-# INLINE getInnerWidthHelp #-}
305getInnerWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
306getInnerWidthHelp fp offset terminal word
307 | 0x61 {- a -} <= word && word <= 0x7A {- z -} = 1
308 | 0x41 {- A -} <= word && word <= 0x5A {- Z -} = 1
309 | 0x30 {- 0 -} <= word && word <= 0x39 {- 9 -} = 1
310 | word == 0x5F {- _ -} = 1
312 | word < 0xe0 = if Char.isAlpha (getChar2 fp offset terminal word) then 2 else 0
313 | word < 0xf0 = if Char.isAlpha (getChar3 fp offset terminal word) then 3 else 0
314 | word < 0xf8 = if Char.isAlpha (getChar4 fp offset terminal word) then 4 else 0
322push :: Word8 -> Int -> Int
324 assert (word .&. 0xc0 == 0x80) (
325 shiftL code 6 .|. fromEnum (word .&. 0x3f)
329getChar2 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
330getChar2 fp offset terminal word =
331 assert (offset + 2 <= terminal) (
333 !word1 = word .&. 0x1f
334 !word2 = unsafeIndex fp (offset + 1)
335 !code = push word2 (fromEnum word1)
337 assert (0x80 <= code) (
343getChar3 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
344getChar3 fp offset terminal word =
345 assert (offset + 3 <= terminal) (
347 !word1 = word .&. 0x0f
348 !word2 = unsafeIndex fp (offset + 1)
349 !word3 = unsafeIndex fp (offset + 2)
350 !code = push word3 (push word2 (fromEnum word1))
352 assert ((0x800 <= code && code < 0xd800) || (0xdfff < code && code < 0xfffe)) (
358getChar4 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
359getChar4 fp offset terminal word =
360 assert (offset + 4 <= terminal) (
362 !word1 = word .&. 0x07
363 !word2 = unsafeIndex fp (offset + 1)
364 !word3 = unsafeIndex fp (offset + 2)
365 !word4 = unsafeIndex fp (offset + 3)
366 !code = push word4 (push word3 (push word2 (fromEnum word1)))
368 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