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 !foreign = toForeign fp offset start end
130 !newState = State fp end terminal indent row newCol ctx
132 cok foreign newState noError
135foreignUpperHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int, Int #)
136foreignUpperHelp fp offset terminal col =
138 (# newOffset, newCol #) = chompUpper fp offset terminal col
140 if offset == newOffset then
141 (# offset, offset, col #)
143 else if isDot fp newOffset terminal then
144 foreignUpperHelp fp (newOffset + 1) terminal (newCol + 1)
147 (# offset, newOffset, newCol #)
154foreignAlpha :: Parser (Maybe Text, Text)
156 Parser $ \(State fp offset terminal indent row col ctx) cok _ _ eerr ->
157 let (# start, end, newCol #) = foreignAlphaHelp fp offset terminal col in
159 eerr (E.ParseError row newCol (E.Theories ctx [E.LowVar, E.CapVar]))
161 cok (toForeign fp offset start end) (State fp end terminal indent row newCol ctx) noError
164foreignAlphaHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int, Int #)
165foreignAlphaHelp fp offset terminal col =
167 (# lowerOffset, lowerCol #) = chompLower fp offset terminal col
169 if offset < lowerOffset then
170 (# offset, lowerOffset, lowerCol #)
174 (# upperOffset, upperCol #) = chompUpper fp offset terminal col
176 if offset == upperOffset then
177 (# offset, offset, col #)
179 else if isDot fp upperOffset terminal then
180 foreignAlphaHelp fp (upperOffset + 1) terminal (upperCol + 1)
183 (# offset, upperOffset, upperCol #)
190toForeign :: ForeignPtr Word8 -> Int -> Int -> Int -> ( Maybe Text, Text )
191toForeign fp offset start end =
194 if start == offset then
197 Just (Text.decodeUtf8 (B.PS fp offset ((start - 1) - offset)))
200 Text.decodeUtf8 (B.PS fp start (end - start))
202 ( qualifier, variable )
207---- CHAR CHOMPERS ----
215isDot :: ForeignPtr Word8 -> Int -> Int -> Bool
216isDot fp offset terminal =
217 offset < terminal && unsafeIndex fp offset == 0x2e {- . -}
224chompUpper :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
225chompUpper fp offset terminal col =
226 let !width = getUpperWidth fp offset terminal in
230 chompInnerChars fp (offset + width) terminal (col + 1)
233{-# INLINE getUpperWidth #-}
234getUpperWidth :: ForeignPtr Word8 -> Int -> Int -> Int
235getUpperWidth fp offset terminal =
236 if offset < terminal then
237 getUpperWidthHelp fp offset terminal (unsafeIndex fp offset)
242{-# INLINE getUpperWidthHelp #-}
243getUpperWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
244getUpperWidthHelp fp offset terminal word
245 | 0x41 {- A -} <= word && word <= 0x5A {- Z -} = 1
247 | word < 0xe0 = if Char.isUpper (getChar2 fp offset terminal word) then 2 else 0
248 | word < 0xf0 = if Char.isUpper (getChar3 fp offset terminal word) then 3 else 0
249 | word < 0xf8 = if Char.isUpper (getChar4 fp offset terminal word) then 4 else 0
257chompLower :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
258chompLower fp offset terminal col =
259 let !width = getLowerWidth fp offset terminal in
263 chompInnerChars fp (offset + width) terminal (col + 1)
266{-# INLINE getLowerWidth #-}
267getLowerWidth :: ForeignPtr Word8 -> Int -> Int -> Int
268getLowerWidth fp offset terminal =
269 if offset < terminal then
270 getLowerWidthHelp fp offset terminal (unsafeIndex fp offset)
275{-# INLINE getLowerWidthHelp #-}
276getLowerWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
277getLowerWidthHelp fp offset terminal word
278 | 0x61 {- a -} <= word && word <= 0x7A {- z -} = 1
280 | word < 0xe0 = if Char.isLower (getChar2 fp offset terminal word) then 2 else 0
281 | word < 0xf0 = if Char.isLower (getChar3 fp offset terminal word) then 3 else 0
282 | word < 0xf8 = if Char.isLower (getChar4 fp offset terminal word) then 4 else 0
290chompInnerChars :: ForeignPtr Word8 -> Int -> Int -> Int -> (# Int, Int #)
291chompInnerChars fp !offset terminal !col =
292 let !width = getInnerWidth fp offset terminal in
296 chompInnerChars fp (offset + width) terminal (col + 1)
299getInnerWidth :: ForeignPtr Word8 -> Int -> Int -> Int
300getInnerWidth fp offset terminal =
301 if offset < terminal then
302 getInnerWidthHelp fp offset terminal (unsafeIndex fp offset)
307{-# INLINE getInnerWidthHelp #-}
308getInnerWidthHelp :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int
309getInnerWidthHelp fp offset terminal word
310 | 0x61 {- a -} <= word && word <= 0x7A {- z -} = 1
311 | 0x41 {- A -} <= word && word <= 0x5A {- Z -} = 1
312 | 0x30 {- 0 -} <= word && word <= 0x39 {- 9 -} = 1
313 | word == 0x5F {- _ -} = 1
315 | word < 0xe0 = if Char.isAlpha (getChar2 fp offset terminal word) then 2 else 0
316 | word < 0xf0 = if Char.isAlpha (getChar3 fp offset terminal word) then 3 else 0
317 | word < 0xf8 = if Char.isAlpha (getChar4 fp offset terminal word) then 4 else 0
325push :: Word8 -> Int -> Int
327 assert (word .&. 0xc0 == 0x80) (
328 shiftL code 6 .|. fromEnum (word .&. 0x3f)
332getChar2 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
333getChar2 fp offset terminal word =
334 assert (offset + 2 <= terminal) (
336 !word1 = word .&. 0x1f
337 !word2 = unsafeIndex fp (offset + 1)
338 !code = push word2 (fromEnum word1)
340 assert (0x80 <= code) (
346getChar3 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
347getChar3 fp offset terminal word =
348 assert (offset + 3 <= terminal) (
350 !word1 = word .&. 0x0f
351 !word2 = unsafeIndex fp (offset + 1)
352 !word3 = unsafeIndex fp (offset + 2)
353 !code = push word3 (push word2 (fromEnum word1))
355 assert ((0x800 <= code && code < 0xd800) || (0xdfff < code && code < 0xfffe)) (
361getChar4 :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Char
362getChar4 fp offset terminal word =
363 assert (offset + 4 <= terminal) (
365 !word1 = word .&. 0x07
366 !word2 = unsafeIndex fp (offset + 1)
367 !word3 = unsafeIndex fp (offset + 2)
368 !word4 = unsafeIndex fp (offset + 3)
369 !code = push word4 (push word3 (push word2 (fromEnum word1)))
371 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