1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE BangPatterns, UnboxedTuples #-}
3module Parse.Primitives.Number
10import Prelude hiding (length)
11import qualified Data.ByteString.Char8 as Char8
12import qualified Data.ByteString.Internal as B
13import Foreign.ForeignPtr (ForeignPtr)
14import GHC.Word (Word8)
16import qualified AST.Literal as L
17import Parse.Primitives.Internals (Parser(..), State(..), noError)
18import qualified Parse.Primitives.Internals as I
19import qualified Parse.Primitives.Variable as Var
20import qualified Reporting.Error.Syntax as E
27isDirtyEnd :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Bool
28isDirtyEnd fp offset terminal word =
29 Var.getInnerWidthHelp fp offset terminal word > 0
32{-# INLINE isDecimalDigit #-}
33isDecimalDigit :: Word8 -> Bool
35 word <= 0x39 {- 9 -} && word >= 0x30 {- 0 -}
42number :: Parser L.Literal
44 Parser $ \(State fp offset terminal indent row col ctx) cok cerr _ eerr ->
45 if offset >= terminal then
49 let !word = I.unsafeIndex fp offset in
50 if not (isDecimalDigit word) then
56 if word == 0x30 {- 0 -} then
57 chompZero fp (offset + 1) terminal
59 chompInt fp (offset + 1) terminal (fromIntegral (word - 0x30 {- 0 -}))
62 Err newOffset problem ->
63 cerr (E.ParseError row (col + (newOffset - offset)) problem)
68 !newState = State fp newOffset terminal indent row (col + (newOffset - offset)) ctx
70 cok integer newState noError
74 !length = newOffset - offset
75 !float = L.FloatNum $ read $ Char8.unpack $ B.PS fp offset length
76 !newState = State fp newOffset terminal indent row (col + length) ctx
78 cok float newState noError
86 = Err { _offset :: Int, _problem :: E.Problem }
87 | OkInt { _offset :: Int, _value :: Int }
88 | OkFloat { _offset :: Int }
95chompInt :: ForeignPtr Word8 -> Int -> Int -> Int -> Outcome
96chompInt fp !offset terminal !n =
97 if offset >= terminal then
104 !word = I.unsafeIndex fp offset
106 if isDecimalDigit word then
107 chompInt fp (offset + 1) terminal (10 * n + fromIntegral (word - 0x30 {- 0 -}))
109 else if word == 0x2E {- . -} then
110 chompFraction fp (offset + 1) terminal
112 else if word == 0x65 {- e -} || word == 0x45 {- E -} then
113 chompExponent fp (offset + 1) terminal
115 else if isDirtyEnd fp offset terminal word then
116 Err offset E.BadNumberEnd
126chompFraction :: ForeignPtr Word8 -> Int -> Int -> Outcome
127chompFraction fp offset terminal =
128 if offset >= terminal then
129 Err offset E.BadNumberDot
131 else if isDecimalDigit (I.unsafeIndex fp offset) then
132 chompFractionHelp fp (offset + 1) terminal
135 Err offset E.BadNumberDot
138chompFractionHelp :: ForeignPtr Word8 -> Int -> Int -> Outcome
139chompFractionHelp fp offset terminal =
140 if offset >= terminal then
144 let !word = I.unsafeIndex fp offset in
145 if isDecimalDigit word then
146 chompFractionHelp fp (offset + 1) terminal
148 else if word == 0x65 {- e -} || word == 0x45 {- E -} then
149 chompExponent fp (offset + 1) terminal
151 else if isDirtyEnd fp offset terminal word then
152 Err offset E.BadNumberEnd
162chompExponent :: ForeignPtr Word8 -> Int -> Int -> Outcome
163chompExponent fp offset terminal =
164 if offset >= terminal then
165 Err offset E.BadNumberExp
168 let !word = I.unsafeIndex fp offset in
169 if isDecimalDigit word then
170 chompExponentHelp fp (offset + 1) terminal
172 else if word == 0x2B {- + -} || word == 0x2D {- - -} then
174 let !offset1 = offset + 1 in
175 if offset1 < terminal && isDecimalDigit (I.unsafeIndex fp offset1) then
176 chompExponentHelp fp (offset + 2) terminal
178 Err offset E.BadNumberExp
181 Err offset E.BadNumberExp
184chompExponentHelp :: ForeignPtr Word8 -> Int -> Int -> Outcome
185chompExponentHelp fp offset terminal =
186 if offset >= terminal then
189 else if isDecimalDigit (I.unsafeIndex fp offset) then
190 chompExponentHelp fp (offset + 1) terminal
200chompZero :: ForeignPtr Word8 -> Int -> Int -> Outcome
201chompZero fp offset terminal =
202 if offset >= terminal then
206 let !word = I.unsafeIndex fp offset in
207 if word == 0x78 {- x -} then
208 chompHexInt fp (offset + 1) terminal
210 else if word == 0x2E {- . -} then
211 chompFraction fp (offset + 1) terminal
213 else if isDecimalDigit word then
214 Err offset E.BadNumberZero
216 else if isDirtyEnd fp offset terminal word then
217 Err offset E.BadNumberEnd
223chompHexInt :: ForeignPtr Word8 -> Int -> Int -> Outcome
224chompHexInt fp offset terminal =
225 let (# newOffset, answer #) = chompHex fp offset terminal in
227 Err newOffset E.BadNumberHex
229 OkInt newOffset answer
236-- Return -1 if it has NO digits
237-- Return -2 if it has BAD digits
239{-# INLINE chompHex #-}
240chompHex :: ForeignPtr Word8 -> Int -> Int -> (# Int, Int #)
241chompHex fp offset terminal =
242 chompHexHelp fp offset terminal (-1) 0
245chompHexHelp :: ForeignPtr Word8 -> Int -> Int -> Int -> Int -> (# Int, Int #)
246chompHexHelp fp offset terminal answer accumulator =
247 if offset >= terminal then
252 stepHex fp offset terminal (I.unsafeIndex fp offset) accumulator
254 if newAnswer < 0 then
255 (# offset, if newAnswer == -1 then answer else -2 #)
257 chompHexHelp fp (offset + 1) terminal newAnswer newAnswer
260{-# INLINE stepHex #-}
261stepHex :: ForeignPtr Word8 -> Int -> Int -> Word8 -> Int -> Int
262stepHex fp offset terminal word acc
263 | 0x30 {- 0 -} <= word && word <= 0x39 {- 9 -} = 16 * acc + fromIntegral (word - 0x30 {- 0 -})
264 | 0x61 {- a -} <= word && word <= 0x66 {- f -} = 16 * acc + 10 + fromIntegral (word - 0x61 {- a -})
265 | 0x41 {- A -} <= word && word <= 0x46 {- F -} = 16 * acc + 10 + fromIntegral (word - 0x41 {- A -})
266 | isDirtyEnd fp offset terminal word = -2
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