[project @ 2002-04-24 11:17:53 by simonpj]
[ghc-base.git] / Text / Read / Lex.lhs
1 % ----------------------------------------------------------------
2 % $Id: Lex.lhs
3 %
4 % (c) The University of Glasgow, 1994-2000
5 %
6
7 \begin{code}
8 {-# OPTIONS -fno-implicit-prelude #-}
9
10 module Text.Read.Lex
11   -- lexing types
12   ( LexP             -- :: *; = ReadP Lexeme
13   , Lexeme(..)       -- :: *; Show, Eq
14   
15   -- lexer
16   , lex              -- :: LexP
17   , lexLitChar       -- :: LexP
18   
19   -- numbers
20   , Number           -- :: *; Show, Eq
21   
22   , numberToInt      -- :: Number -> Maybe Int
23   , numberToInteger  -- :: Number -> Maybe Integer
24   , numberToRational -- :: Number -> Maybe Integer
25   , numberToFloat    -- :: Number -> Maybe Float
26   , numberToDouble   -- :: Number -> Maybe Double
27
28   , readIntP         -- :: Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadP a
29   , readOctP         -- :: Num a => ReadP a 
30   , readDecP         -- :: Num a => ReadP a
31   , readHexP         -- :: Num a => ReadP a
32   )
33  where
34
35 import Text.ParserCombinators.ReadP
36
37 import GHC.Base
38 import GHC.Num( Num(..), Integer )
39 import GHC.Show( Show(.. ), showChar, showString,
40                  isSpace, isAlpha, isAlphaNum,
41                  isOctDigit, isHexDigit, toUpper )
42 import GHC.Real( Ratio, Integral, Rational, (%), fromIntegral, fromRational, 
43                  toInteger, (^), (^^) )
44 import GHC.Float( Float, Double )
45 import GHC.List
46 import GHC.Show( ShowS, shows )
47 import GHC.Enum( minBound, maxBound )
48 import Data.Maybe
49 import Data.Either
50 import Control.Monad
51 \end{code}
52
53 %*********************************************************
54 %*                                                      *
55 \subsection{Lexing types}
56 %*                                                      *
57 %*********************************************************
58
59 \begin{code}
60 type LexP = ReadP Lexeme
61
62 data Lexeme
63   = Char   Char
64   | String String
65   | Single Char
66   | Symbol String
67   | Ident  String
68   | Number Number
69  deriving (Eq)
70
71 instance Show Lexeme where
72   showsPrec n (Char c)   = showsPrec n c
73   showsPrec n (String s) = showsPrec n s
74   showsPrec _ (Single c) = showChar c
75   showsPrec _ (Ident s)  = showString s
76   showsPrec _ (Symbol s) = showString s
77   showsPrec n (Number x) = showsPrec n x
78 \end{code}
79
80
81 %*********************************************************
82 %*                                                      *
83 \subsection{Lexing}
84 %*                                                      *
85 %*********************************************************
86
87 \begin{code}
88 lex :: LexP
89 lex =
90   do skipSpaces
91      (lexLitChar
92        +++ lexString
93          +++ lexSingle
94            +++ lexSymbol
95              +++ lexIdf
96                +++ lexNumber)
97 \end{code}
98
99 \begin{code}
100 ------------------------------------------------------------------------
101 -- symbols
102
103 lexSymbol :: LexP
104 lexSymbol =
105   do s <- munch1 isSymbolChar
106      return (Symbol s)
107  where
108   isSymbolChar c = c `elem` "!@#$%&*+./<=>?\\^|:-~"
109
110 ------------------------------------------------------------------------
111 -- identifiers
112
113 lexIdf :: LexP
114 lexIdf =
115   do c <- satisfy isAlpha
116      s <- munch isIdfChar
117      return (Ident (c:s))
118  where
119   isIdfChar c = isAlphaNum c || c `elem` "_'"
120 \end{code}
121
122
123 %*********************************************************
124 %*                                                      *
125 \subsection{Lexing characters and strings}
126 %*                                                      *
127 %*********************************************************
128
129 \begin{code}
130 ------------------------------------------------------------------------
131 -- char literal
132
133 lexLitChar :: LexP
134 lexLitChar =
135   do char '\''
136      (c,esc) <- lexChar
137      guard (esc || c /= '\'')
138      char '\''
139      return (Char c)
140
141 lexChar :: ReadP (Char, Bool)  -- "escaped or not"?
142 lexChar =
143   do c <- get
144      if c == '\\'
145        then do c <- lexEsc; return (c, True)
146        else do return (c, False)
147  where 
148   lexEsc =
149     lexEscChar
150       +++ lexNumeric
151         +++ lexCntrlChar
152           +++ lexAscii
153   
154   lexEscChar =
155     do c <- get
156        case c of
157          'a'  -> return '\a'
158          'b'  -> return '\b'
159          'f'  -> return '\f'
160          'n'  -> return '\n'
161          'r'  -> return '\r'
162          't'  -> return '\t'
163          'v'  -> return '\v'
164          '\\' -> return '\\'
165          '\"' -> return '\"'
166          '\'' -> return '\''
167          _    -> pfail
168   
169   lexNumeric =
170     do base <- lexBase
171        n    <- lexInteger base
172        guard (n <= toInteger (ord maxBound))
173        return (chr (fromInteger n))
174    where
175     lexBase =
176       do s <- look
177          case s of
178            'o':_ -> do get; return 8
179            'x':_ -> do get; return 16
180            _     -> do return 10
181   
182   lexCntrlChar =
183     do char '^'
184        c <- get
185        case c of
186          '@'  -> return '\^@'
187          'A'  -> return '\^A'
188          'B'  -> return '\^B'
189          'C'  -> return '\^C'
190          'D'  -> return '\^D'
191          'E'  -> return '\^E'
192          'F'  -> return '\^F'
193          'G'  -> return '\^G'
194          'H'  -> return '\^H'
195          'I'  -> return '\^I'
196          'J'  -> return '\^J'
197          'K'  -> return '\^K'
198          'L'  -> return '\^L'
199          'M'  -> return '\^M'
200          'N'  -> return '\^N'
201          'O'  -> return '\^O'
202          'P'  -> return '\^P'
203          'Q'  -> return '\^Q'
204          'R'  -> return '\^R'
205          'S'  -> return '\^S'
206          'T'  -> return '\^T'
207          'U'  -> return '\^U'
208          'V'  -> return '\^V'
209          'W'  -> return '\^W'
210          'X'  -> return '\^X'
211          'Y'  -> return '\^Y'
212          'Z'  -> return '\^Z'
213          '['  -> return '\^['
214          '\\' -> return '\^\'
215          ']'  -> return '\^]'
216          '^'  -> return '\^^'
217          '_'  -> return '\^_'
218          _    -> pfail
219
220   lexAscii =
221     do choice
222          [ string "NUL" >> return '\NUL'
223          , string "SOH" >> return '\SOH'
224          , string "STX" >> return '\STX'
225          , string "ETX" >> return '\ETX'
226          , string "EOT" >> return '\EOT'
227          , string "ENQ" >> return '\ENQ'
228          , string "ACK" >> return '\ACK'
229          , string "BEL" >> return '\BEL'
230          , string "BS"  >> return '\BS'
231          , string "HT"  >> return '\HT'
232          , string "LF"  >> return '\LF'
233          , string "VT"  >> return '\VT'
234          , string "FF"  >> return '\FF'
235          , string "CR"  >> return '\CR'
236          , string "SO"  >> return '\SO'
237          , string "SI"  >> return '\SI'
238          , string "DLE" >> return '\DLE'
239          , string "DC1" >> return '\DC1'
240          , string "DC2" >> return '\DC2'
241          , string "DC3" >> return '\DC3'
242          , string "DC4" >> return '\DC4'
243          , string "NAK" >> return '\NAK'
244          , string "SYN" >> return '\SYN'
245          , string "ETB" >> return '\ETB'
246          , string "CAN" >> return '\CAN'
247          , string "EM"  >> return '\EM'
248          , string "SUB" >> return '\SUB'
249          , string "ESC" >> return '\ESC'
250          , string "FS"  >> return '\FS'
251          , string "GS"  >> return '\GS'
252          , string "RS"  >> return '\RS'
253          , string "US"  >> return '\US'
254          , string "SP"  >> return '\SP'
255          , string "DEL" >> return '\DEL'
256          ]
257
258 ------------------------------------------------------------------------
259 -- string literal
260
261 lexString :: LexP
262 lexString =
263   do char '"'
264      body id
265  where
266   body f =
267     do (c,esc) <- lexStrItem
268        if c /= '"' || esc
269          then body (f.(c:))
270          else return (String (f ""))
271
272   lexStrItem =
273     (lexEmpty >> lexStrItem)
274       +++ lexChar
275   
276   lexEmpty =
277     do char '\\'
278        c <- get
279        case c of
280          '&'           -> do return ()
281          _ | isSpace c -> do skipSpaces; char '\\'; return ()
282          _             -> do pfail
283
284 ------------------------------------------------------------------------
285 -- single character lexemes
286
287 lexSingle :: LexP
288 lexSingle =
289   do c <- satisfy isSingleChar
290      return (Single c)
291  where
292   isSingleChar c = c `elem` ",;()[]{=}_`"
293 \end{code}
294
295
296 %*********************************************************
297 %*                                                      *
298 \subsection{Lexing numbers}
299 %*                                                      *
300 %*********************************************************
301
302 \begin{code}
303 data Number
304   = MkNumber
305     { value    :: Either Integer Rational
306     , base     :: Base
307     , digits   :: Digits
308     , fraction :: Maybe Digits
309     , exponent :: Maybe Integer
310     }
311  deriving (Eq)
312
313 type Base   = Int
314 type Digits = [Int]
315
316 instance Show Number where
317   showsPrec _ x =
318       showsBase (base x)
319     . foldr (.) id (map showDigit (digits x))
320     . showsFrac (fraction x)
321     . showsExp (exponent x)
322    where
323     showsBase 8  = showString "0o"
324     showsBase 10 = id
325     showsBase 16 = showString "0x"
326    
327     showsFrac Nothing   = id
328     showsFrac (Just ys) =
329         showChar '.'
330       . foldr (.) id (map showDigit ys) 
331     
332     showsExp Nothing    = id
333     showsExp (Just exp) =
334         showChar 'e'
335       . shows exp
336
337 showDigit :: Int -> ShowS
338 showDigit n | n <= 9    = shows n
339             | otherwise = showChar (chr (n + ord 'A' - 10))
340
341 lexNumber :: LexP
342 lexNumber =
343   do base <- lexBase
344      lexNumberBase base
345  where
346   lexBase =
347     do s <- look
348        case s of
349          '0':'o':_ -> do get; get; return 8
350          '0':'O':_ -> do get; get; return 8
351          '0':'x':_ -> do get; get; return 16
352          '0':'X':_ -> do get; get; return 16
353          _         -> do return 10
354        
355 lexNumberBase :: Base -> LexP
356 lexNumberBase base =
357   do xs    <- lexDigits base
358      mFrac <- lexFrac base
359      mExp  <- lexExp base
360      return (Number (MkNumber (value xs mFrac mExp) base xs mFrac mExp))
361  where
362   value xs mFrac mExp = valueFracExp (val (fromIntegral base) 0 xs) mFrac mExp
363   
364   valueFracExp a Nothing   mExp = Left (valueExp a mExp)
365   valueFracExp a (Just fs) mExp =
366     Right (valueExp (fromInteger a + frac (fromIntegral base) 0 1 fs) mExp)
367
368   valueExp a Nothing    = a
369   valueExp a (Just exp) = a * (fromIntegral base ^ exp)
370
371 lexFrac :: Base -> ReadP (Maybe Digits)
372 lexFrac base =
373   do s <- look
374      case s of
375        '.' : _ ->
376          do get
377             frac <- lexDigits base
378             return (Just frac)
379        
380        _ ->
381          do return Nothing
382
383 lexExp :: Base -> ReadP (Maybe Integer)
384 lexExp base =
385   do s <- look
386      case s of
387        e : _ | e `elem` "eE" && base == 10 ->
388          do get
389             (signedExp +++ exp)
390         where
391          signedExp =
392            do c <- char '-' +++ char '+'
393               n <- lexInteger 10
394               return (Just (if c == '-' then -n else n))
395          
396          exp =
397            do n <- lexInteger 10
398               return (Just n)
399
400        _ ->
401          do return Nothing
402
403 lexDigits :: Int -> ReadP Digits
404 lexDigits base =
405   do s  <- look
406      xs <- scan s id
407      guard (not (null xs))
408      return xs
409  where
410   scan (c:cs) f = case valDig base c of
411                     Just n  -> do get; scan cs (f.(n:))
412                     Nothing -> do return (f [])
413   scan []     f = do return (f [])
414
415 lexInteger :: Base -> ReadP Integer
416 lexInteger base =
417   do xs <- lexDigits base
418      return (val (fromIntegral base) 0 xs)
419
420 val :: Num a => a -> a -> Digits -> a
421 val base y []     = y
422 val base y (x:xs) = y' `seq` val base y' xs
423  where
424   y' = y * base + fromIntegral x
425
426 frac :: Integral a => a -> a -> a -> Digits -> Ratio a
427 frac base a b []     = a % b
428 frac base a b (x:xs) = a' `seq` b' `seq` frac base a' b' xs
429  where
430   a' = a * base + fromIntegral x
431   b' = b * base
432
433 valDig :: Num a => a -> Char -> Maybe Int
434 valDig 8 c
435   | '0' <= c && c <= '7' = Just (ord c - ord '0')
436   | otherwise            = Nothing
437
438 valDig 10 c
439   | '0' <= c && c <= '9' = Just (ord c - ord '0')
440   | otherwise            = Nothing
441
442 valDig 16 c
443   | '0' <= c && c <= '9' = Just (ord c - ord '0')
444   | 'a' <= c && c <= 'f' = Just (ord c - ord 'a' + 10)
445   | 'A' <= c && c <= 'F' = Just (ord c - ord 'A' + 10)
446   | otherwise            = Nothing
447
448 ------------------------------------------------------------------------
449 -- conversion
450
451 numberToInt :: Number -> Maybe Int
452 numberToInt x =
453   case numberToInteger x of
454     Just n | minBound' <= n && n <= maxBound' -> Just (fromInteger n)
455     _                                         -> Nothing
456  where
457   minBound' = toInteger (minBound :: Int)
458   maxBound' = toInteger (maxBound :: Int)
459
460 numberToInteger :: Number -> Maybe Integer
461 numberToInteger x =
462   case value x of
463     Left n -> Just n
464     _      -> Nothing
465
466 numberToRational :: Number -> Maybe Rational
467 numberToRational x =
468   case value x of
469     Left n  -> Just (fromInteger n)
470     Right r -> Just r
471
472 numberToFloat :: Number -> Maybe Float
473 numberToFloat x =
474   case value x of
475     Left n  -> Just (fromInteger n)
476     Right r -> Just (fromRational r)
477
478 numberToDouble :: Number -> Maybe Double
479 numberToDouble x =
480   case value x of
481     Left n  -> Just (fromInteger n)
482     Right r -> Just (fromRational r)
483
484 ------------------------------------------------------------------------
485 -- other numeric lexing functions
486
487 readIntP :: Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadP a
488 readIntP base isDigit valDigit =
489   do s <- munch1 isDigit
490      return (val base 0 (map valDigit s))
491
492 readIntP' :: Num a => a -> ReadP a
493 readIntP' base = readIntP base isDigit valDigit
494  where
495   isDigit  c = maybe False (const True) (valDig base c)
496   valDigit c = maybe 0     id           (valDig base c)
497
498 readOctP, readDecP, readHexP :: Num a => ReadP a
499 readOctP = readIntP' 8
500 readDecP = readIntP' 10
501 readHexP = readIntP' 16
502 \end{code}