1{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
2{-# LANGUAGE BangPatterns, MagicHash, OverloadedStrings, UnboxedTuples #-}
10import qualified Data.Utf8 as Utf8
11import Data.Word (Word8, Word16)
12import Foreign.Ptr (Ptr, plusPtr, minusPtr)
14import qualified Elm.String as ES
15import Parse.Primitives (Parser, Row, Col)
16import qualified Parse.Number as Number
17import qualified Parse.Primitives as P
18import qualified Reporting.Error.Syntax as E
25character :: (Row -> Col -> x) -> (E.Char -> Row -> Col -> x) -> Parser x ES.String
26character toExpectation toError =
27 P.Parser $ \(P.State src pos end indent row col) cok _ cerr eerr ->
28 if pos >= end || P.unsafeIndex pos /= 0x27 {- ' -} then
29 eerr row col toExpectation
32 case chompChar (plusPtr pos 1) end row (col + 1) 0 placeholder of
33 Good newPos newCol numChars mostRecent ->
35 cerr row col (toError (E.CharNotString (fromIntegral (newCol - col))))
38 !newState = P.State src newPos end indent row newCol
39 !char = ES.fromChunks [mostRecent]
44 cerr row newCol (toError E.CharEndless)
46 CharEscape r c escape ->
47 cerr r c (toError (E.CharEscape escape))
51 = Good (Ptr Word8) Col Word16 ES.Chunk
53 | CharEscape Row Col E.Escape
56chompChar :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Word16 -> ES.Chunk -> CharResult
57chompChar pos end row col numChars mostRecent =
63 !word = P.unsafeIndex pos
65 if word == 0x27 {- ' -} then
66 Good (plusPtr pos 1) (col + 1) numChars mostRecent
68 else if word == 0x0A {- \n -} then
71 else if word == 0x22 {- " -} then
72 chompChar (plusPtr pos 1) end row (col + 1) (numChars + 1) doubleQuote
74 else if word == 0x5C {- \ -} then
75 case eatEscape (plusPtr pos 1) end row col of
77 chompChar (plusPtr pos 2) end row (col + 2) (numChars + 1) (ES.Slice pos 2)
79 EscapeUnicode delta code ->
80 chompChar (plusPtr pos delta) end row (col + fromIntegral delta) (numChars + 1) (ES.CodePoint code)
82 EscapeProblem r c badEscape ->
83 CharEscape r c badEscape
90 !width = P.getCharWidth word
91 !newPos = plusPtr pos width
93 chompChar newPos end row (col + 1) (numChars + 1) (ES.Slice pos width)
100string :: (Row -> Col -> x) -> (E.String -> Row -> Col -> x) -> Parser x ES.String
101string toExpectation toError =
102 P.Parser $ \(P.State src pos end indent row col) cok _ cerr eerr ->
103 if isDoubleQuote pos end then
106 !pos1 = plusPtr pos 1
109 if isDoubleQuote pos1 end then
110 let !pos2 = plusPtr pos 2 in
111 if isDoubleQuote pos2 end then
113 !pos3 = plusPtr pos 3
116 multiString pos3 end row col3 pos3 row col mempty
118 Ok pos2 row (col + 2) Utf8.empty
120 singleString pos1 end row (col + 1) pos1 mempty
122 Ok newPos newRow newCol utf8 ->
125 P.State src newPos end indent newRow newCol
133 eerr row col toExpectation
136{-# INLINE isDoubleQuote #-}
137isDoubleQuote :: Ptr Word8 -> Ptr Word8 -> Bool
138isDoubleQuote pos end =
139 pos < end && P.unsafeIndex pos == 0x22 {- " -}
143 = Ok (Ptr Word8) Row Col !ES.String
144 | Err Row Col E.String
147finalize :: Ptr Word8 -> Ptr Word8 -> [ES.Chunk] -> ES.String
148finalize start end revChunks =
149 ES.fromChunks $ reverse $
153 ES.Slice start (minusPtr end start) : revChunks
156addEscape :: ES.Chunk -> Ptr Word8 -> Ptr Word8 -> [ES.Chunk] -> [ES.Chunk]
157addEscape chunk start end revChunks =
161 chunk : ES.Slice start (minusPtr end start) : revChunks
168singleString :: Ptr Word8 -> Ptr Word8 -> Word16 -> Word16 -> Ptr Word8 -> [ES.Chunk] -> StringResult
169singleString pos end row col initialPos revChunks =
171 Err row col E.StringEndless_Single
175 !word = P.unsafeIndex pos
177 if word == 0x22 {- " -} then
178 Ok (plusPtr pos 1) row (col + 1) $
179 finalize initialPos pos revChunks
181 else if word == 0x0A {- \n -} then
182 Err row col E.StringEndless_Single
184 else if word == 0x27 {- ' -} then
185 let !newPos = plusPtr pos 1 in
186 singleString newPos end row (col + 1) newPos $
187 addEscape singleQuote initialPos pos revChunks
189 else if word == 0x5C {- \ -} then
190 case eatEscape (plusPtr pos 1) end row col of
192 singleString (plusPtr pos 2) end row (col + 2) initialPos revChunks
194 EscapeUnicode delta code ->
195 let !newPos = plusPtr pos delta in
196 singleString newPos end row (col + fromIntegral delta) newPos $
197 addEscape (ES.CodePoint code) initialPos pos revChunks
199 EscapeProblem r c x ->
200 Err r c (E.StringEscape x)
203 Err row (col + 1) E.StringEndless_Single
206 let !newPos = plusPtr pos (P.getCharWidth word) in
207 singleString newPos end row (col + 1) initialPos revChunks
214multiString :: Ptr Word8 -> Ptr Word8 -> Word16 -> Word16 -> Ptr Word8 -> Word16 -> Word16 -> [ES.Chunk] -> StringResult
215multiString pos end row col initialPos sr sc revChunks =
217 Err sr sc E.StringEndless_Multi
220 let !word = P.unsafeIndex pos in
221 if word == 0x22 {- " -} && isDoubleQuote (plusPtr pos 1) end && isDoubleQuote (plusPtr pos 2) end then
222 Ok (plusPtr pos 3) row (col + 3) $
223 finalize initialPos pos revChunks
225 else if word == 0x27 {- ' -} then
226 let !pos1 = plusPtr pos 1 in
227 multiString pos1 end row (col + 1) pos1 sr sc $
228 addEscape singleQuote initialPos pos revChunks
230 else if word == 0x0A {- \n -} then
231 let !pos1 = plusPtr pos 1 in
232 multiString pos1 end (row + 1) 1 pos1 sr sc $
233 addEscape newline initialPos pos revChunks
235 else if word == 0x0D {- \r -} then
236 let !pos1 = plusPtr pos 1 in
237 multiString pos1 end row col pos1 sr sc $
238 addEscape carriageReturn initialPos pos revChunks
240 else if word == 0x5C {- \ -} then
241 case eatEscape (plusPtr pos 1) end row col of
243 multiString (plusPtr pos 2) end row (col + 2) initialPos sr sc revChunks
245 EscapeUnicode delta code ->
246 let !newPos = plusPtr pos delta in
247 multiString newPos end row (col + fromIntegral delta) newPos sr sc $
248 addEscape (ES.CodePoint code) initialPos pos revChunks
250 EscapeProblem r c x ->
251 Err r c (E.StringEscape x)
254 Err sr sc E.StringEndless_Multi
257 let !newPos = plusPtr pos (P.getCharWidth word) in
258 multiString newPos end row (col + 1) initialPos sr sc revChunks
267 | EscapeUnicode !Int !Int
269 | EscapeProblem Row Col E.Escape
272eatEscape :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Escape
273eatEscape pos end row col =
278 case P.unsafeIndex pos of
279 0x6E {- n -} -> EscapeNormal
280 0x72 {- r -} -> EscapeNormal
281 0x74 {- t -} -> EscapeNormal
282 0x22 {- " -} -> EscapeNormal
283 0x27 {- ' -} -> EscapeNormal
284 0x5C {- \ -} -> EscapeNormal
285 0x75 {- u -} -> eatUnicode (plusPtr pos 1) end row col
286 _ -> EscapeProblem row col E.EscapeUnknown
289eatUnicode :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Escape
290eatUnicode pos end row col =
291 if pos >= end || P.unsafeIndex pos /= 0x7B {- { -} then
292 EscapeProblem row col (E.BadUnicodeFormat 2)
295 !digitPos = plusPtr pos 1
296 (# newPos, code #) = Number.chompHex digitPos end
297 !numDigits = minusPtr newPos digitPos
299 if newPos >= end || P.unsafeIndex newPos /= 0x7D {- } -} then
300 EscapeProblem row col $ E.BadUnicodeFormat (2 + fromIntegral (minusPtr newPos pos))
302 else if code < 0 || 0x10FFFF < code then
303 EscapeProblem row col $ E.BadUnicodeCode (3 + fromIntegral (minusPtr newPos pos))
305 else if numDigits < 4 || 6 < numDigits then
306 EscapeProblem row col $
308 (3 + fromIntegral (minusPtr newPos pos))
313 EscapeUnicode (numDigits + 4) code
316{-# NOINLINE singleQuote #-}
317singleQuote :: ES.Chunk
322{-# NOINLINE doubleQuote #-}
323doubleQuote :: ES.Chunk
328{-# NOINLINE newline #-}
334{-# NOINLINE carriageReturn #-}
335carriageReturn :: ES.Chunk
340{-# NOINLINE placeholder #-}
341placeholder :: ES.Chunk
343 ES.CodePoint 0xFFFD {-replacement character-}
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