1 {-# OPTIONS -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
4 -- Module : Text.Read.Lex
5 -- Copyright : (c) The University of Glasgow 2002
6 -- License : BSD-style (see the file libraries/base/LICENSE)
8 -- Maintainer : libraries@haskell.org
9 -- Stability : provisional
10 -- Portability : portable
12 -- The cut-down Haskell lexer, used by Text.Read
14 -----------------------------------------------------------------------------
18 ( LexP -- :: *; = ReadP Lexeme
19 , Lexeme(..) -- :: *; Show, Eq
23 , lexLitChar -- :: LexP
26 , Number -- :: *; Show, Eq
28 , numberToInt -- :: Number -> Maybe Int
29 , numberToInteger -- :: Number -> Maybe Integer
30 , numberToRational -- :: Number -> Maybe Integer
31 , numberToFloat -- :: Number -> Maybe Float
32 , numberToDouble -- :: Number -> Maybe Double
34 , readIntP -- :: Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadP a
35 , readOctP -- :: Num a => ReadP a
36 , readDecP -- :: Num a => ReadP a
37 , readHexP -- :: Num a => ReadP a
41 import Text.ParserCombinators.ReadP
44 import GHC.Num( Num(..), Integer )
45 import GHC.Show( Show(.. ), showChar, showString,
46 isSpace, isAlpha, isAlphaNum,
47 isOctDigit, isHexDigit, toUpper )
48 import GHC.Real( Ratio, Integral, Rational, (%), fromIntegral, fromRational,
49 toInteger, (^), (^^) )
50 import GHC.Float( Float, Double )
52 import GHC.Show( ShowS, shows )
53 import GHC.Enum( minBound, maxBound )
58 -- -----------------------------------------------------------------------------
61 type LexP = ReadP Lexeme
72 instance Show Lexeme where
73 showsPrec n (Char c) = showsPrec n c
74 showsPrec n (String s) = showsPrec n s
75 showsPrec _ (Single c) = showChar c
76 showsPrec _ (Ident s) = showString s
77 showsPrec _ (Symbol s) = showString s
78 showsPrec n (Number x) = showsPrec n x
80 -- -----------------------------------------------------------------------------
93 -- ----------------------------------------------------------------------
98 do s <- munch1 isSymbolChar
101 isSymbolChar c = c `elem` "!@#$%&*+./<=>?\\^|:-~"
103 -- ----------------------------------------------------------------------
108 do c <- satisfy isAlpha
112 isIdfChar c = isAlphaNum c || c `elem` "_'"
114 -- ---------------------------------------------------------------------------
115 -- Lexing character literals
121 guard (esc || c /= '\'')
125 lexChar :: ReadP (Char, Bool) -- "escaped or not"?
129 then do c <- lexEsc; return (c, True)
130 else do return (c, False)
156 guard (n <= toInteger (ord maxBound))
157 return (chr (fromInteger n))
162 'o':_ -> do get; return 8
163 'x':_ -> do get; return 16
206 [ string "NUL" >> return '\NUL'
207 , string "SOH" >> return '\SOH'
208 , string "STX" >> return '\STX'
209 , string "ETX" >> return '\ETX'
210 , string "EOT" >> return '\EOT'
211 , string "ENQ" >> return '\ENQ'
212 , string "ACK" >> return '\ACK'
213 , string "BEL" >> return '\BEL'
214 , string "BS" >> return '\BS'
215 , string "HT" >> return '\HT'
216 , string "LF" >> return '\LF'
217 , string "VT" >> return '\VT'
218 , string "FF" >> return '\FF'
219 , string "CR" >> return '\CR'
220 , string "SO" >> return '\SO'
221 , string "SI" >> return '\SI'
222 , string "DLE" >> return '\DLE'
223 , string "DC1" >> return '\DC1'
224 , string "DC2" >> return '\DC2'
225 , string "DC3" >> return '\DC3'
226 , string "DC4" >> return '\DC4'
227 , string "NAK" >> return '\NAK'
228 , string "SYN" >> return '\SYN'
229 , string "ETB" >> return '\ETB'
230 , string "CAN" >> return '\CAN'
231 , string "EM" >> return '\EM'
232 , string "SUB" >> return '\SUB'
233 , string "ESC" >> return '\ESC'
234 , string "FS" >> return '\FS'
235 , string "GS" >> return '\GS'
236 , string "RS" >> return '\RS'
237 , string "US" >> return '\US'
238 , string "SP" >> return '\SP'
239 , string "DEL" >> return '\DEL'
243 -- ---------------------------------------------------------------------------
252 do (c,esc) <- lexStrItem
255 else return (String (f ""))
258 (lexEmpty >> lexStrItem)
266 _ | isSpace c -> do skipSpaces; char '\\'; return ()
269 -- ---------------------------------------------------------------------------
270 -- single character lexemes
274 do c <- satisfy isSingleChar
277 isSingleChar c = c `elem` ",;()[]{=}_`"
279 -- ---------------------------------------------------------------------------
284 { value :: Either Integer Rational
287 , fraction :: Maybe Digits
288 , exponent :: Maybe Integer
295 instance Show Number where
298 . foldr (.) id (map showDigit (digits x))
299 . showsFrac (fraction x)
300 . showsExp (exponent x)
302 showsBase 8 = showString "0o"
304 showsBase 16 = showString "0x"
306 showsFrac Nothing = id
307 showsFrac (Just ys) =
309 . foldr (.) id (map showDigit ys)
311 showsExp Nothing = id
312 showsExp (Just exp) =
316 showDigit :: Int -> ShowS
317 showDigit n | n <= 9 = shows n
318 | otherwise = showChar (chr (n + ord 'A' - 10))
328 '0':'o':_ -> do get; get; return 8
329 '0':'O':_ -> do get; get; return 8
330 '0':'x':_ -> do get; get; return 16
331 '0':'X':_ -> do get; get; return 16
334 lexNumberBase :: Base -> LexP
336 do xs <- lexDigits base
337 mFrac <- lexFrac base
339 return (Number (MkNumber (value xs mFrac mExp) base xs mFrac mExp))
341 value xs mFrac mExp = valueFracExp (val (fromIntegral base) 0 xs) mFrac mExp
343 valueFracExp a Nothing mExp
344 | validIntExp mExp = Left (valueExpInt a mExp)
345 | otherwise = Right (valueExp (fromIntegral a) mExp)
346 valueFracExp a (Just fs) mExp =
347 Right (valueExp (fromInteger a + frac (fromIntegral base) 0 1 fs) mExp)
349 -- only positive exponents allowed
350 validIntExp Nothing = True
351 validIntExp (Just e) = e >= 0
353 valueExpInt a Nothing = a
354 valueExpInt a (Just exp) = a * ((fromIntegral base) ^ exp)
356 valueExp a Nothing = a
357 valueExp a (Just exp) = a * ((fromIntegral base) ^^ exp)
359 lexFrac :: Base -> ReadP (Maybe Digits)
365 frac <- lexDigits base
371 lexExp :: Base -> ReadP (Maybe Integer)
375 e : _ | e `elem` "eE" && base == 10 ->
380 do c <- char '-' +++ char '+'
382 return (Just (if c == '-' then -n else n))
385 do n <- lexInteger 10
391 lexDigits :: Int -> ReadP Digits
395 guard (not (null xs))
398 scan (c:cs) f = case valDig base c of
399 Just n -> do get; scan cs (f.(n:))
400 Nothing -> do return (f [])
401 scan [] f = do return (f [])
403 lexInteger :: Base -> ReadP Integer
405 do xs <- lexDigits base
406 return (val (fromIntegral base) 0 xs)
408 val :: Num a => a -> a -> Digits -> a
410 val base y (x:xs) = y' `seq` val base y' xs
412 y' = y * base + fromIntegral x
414 frac :: Integral a => a -> a -> a -> Digits -> Ratio a
415 frac base a b [] = a % b
416 frac base a b (x:xs) = a' `seq` b' `seq` frac base a' b' xs
418 a' = a * base + fromIntegral x
421 valDig :: Num a => a -> Char -> Maybe Int
423 | '0' <= c && c <= '7' = Just (ord c - ord '0')
424 | otherwise = Nothing
427 | '0' <= c && c <= '9' = Just (ord c - ord '0')
428 | otherwise = Nothing
431 | '0' <= c && c <= '9' = Just (ord c - ord '0')
432 | 'a' <= c && c <= 'f' = Just (ord c - ord 'a' + 10)
433 | 'A' <= c && c <= 'F' = Just (ord c - ord 'A' + 10)
434 | otherwise = Nothing
436 -- ----------------------------------------------------------------------
439 numberToInt :: Number -> Maybe Int
441 case numberToInteger x of
442 Just n | minBound' <= n && n <= maxBound' -> Just (fromInteger n)
445 minBound' = toInteger (minBound :: Int)
446 maxBound' = toInteger (maxBound :: Int)
448 numberToInteger :: Number -> Maybe Integer
454 numberToRational :: Number -> Maybe Rational
457 Left n -> Just (fromInteger n)
460 numberToFloat :: Number -> Maybe Float
463 Left n -> Just (fromInteger n)
464 Right r -> Just (fromRational r)
466 numberToDouble :: Number -> Maybe Double
469 Left n -> Just (fromInteger n)
470 Right r -> Just (fromRational r)
472 -- ----------------------------------------------------------------------
473 -- other numeric lexing functions
475 readIntP :: Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadP a
476 readIntP base isDigit valDigit =
477 do s <- munch1 isDigit
478 return (val base 0 (map valDigit s))
480 readIntP' :: Num a => a -> ReadP a
481 readIntP' base = readIntP base isDigit valDigit
483 isDigit c = maybe False (const True) (valDig base c)
484 valDigit c = maybe 0 id (valDig base c)
486 readOctP, readDecP, readHexP :: Num a => ReadP a
487 readOctP = readIntP' 8
488 readDecP = readIntP' 10
489 readHexP = readIntP' 16