4ac89c663045282791fe3f2a0518ef92aa36512e
[ghc-hetmet.git] / compiler / parser / LexCore.hs
1 {-# OPTIONS_GHC -w #-}
2 -- The above warning supression flag is a temporary kludge.
3 -- While working on this module you are encouraged to remove it and fix
4 -- any warnings in the module. See
5 --     http://hackage.haskell.org/trac/ghc/wiki/WorkingConventions#Warnings
6 -- for details
7
8 module LexCore where
9
10 import ParserCoreUtils
11 import Char
12 import Numeric
13
14 isNameChar c = isAlpha c || isDigit c || (c == '_') || (c == '\'')
15                || (c == '$') || (c == '-') || (c == '.')
16 isKeywordChar c = isAlpha c || (c == '_') 
17
18 lexer :: (Token -> P a) -> P a 
19 lexer cont []           = cont TKEOF []
20 lexer cont ('\n':cs)    = \line -> lexer cont cs (line+1)
21 lexer cont ('-':'>':cs) = cont TKrarrow cs
22
23 lexer cont (c:cs) 
24       | isSpace c               = lexer cont cs
25       | isLower c || (c == '_') = lexName cont TKname (c:cs)
26       | isUpper c               = lexName cont TKcname (c:cs)
27       | isDigit c || (c == '-') = lexNum cont (c:cs)
28
29 lexer cont ('%':cs)     = lexKeyword cont cs
30 lexer cont ('\'':cs)    = lexChar cont cs
31 lexer cont ('\"':cs)    = lexString [] cont cs 
32 lexer cont ('#':cs)     = cont TKhash cs
33 lexer cont ('(':cs)     = cont TKoparen cs
34 lexer cont (')':cs)     = cont TKcparen cs
35 lexer cont ('{':cs)     = cont TKobrace cs
36 lexer cont ('}':cs)     = cont TKcbrace cs
37 lexer cont ('=':cs)     = cont TKeq cs
38 lexer cont (':':'=':':':cs) = cont TKcoloneqcolon cs
39 lexer cont (':':':':cs) = cont TKcoloncolon cs
40 lexer cont ('*':cs)     = cont TKstar cs
41 lexer cont ('.':cs)     = cont TKdot cs
42 lexer cont ('\\':cs)    = cont TKlambda cs
43 lexer cont ('@':cs)     = cont TKat cs
44 lexer cont ('?':cs)     = cont TKquestion cs
45 lexer cont (';':cs)     = cont TKsemicolon cs
46 -- 20060420 GHC spits out constructors with colon in them nowadays. jds
47 -- 20061103 but it's easier to parse if we split on the colon, and treat them
48 -- as several tokens
49 lexer cont (':':cs)     = cont TKcolon cs
50 -- 20060420 Likewise does it create identifiers starting with dollar. jds
51 lexer cont ('$':cs)     = lexName cont TKname ('$':cs)
52 lexer cont (c:cs)       = failP "invalid character" [c]
53
54
55
56 lexChar cont ('\\':'x':h1:h0:'\'':cs)
57         | isHexEscape [h1,h0] =  cont (TKchar (hexToChar h1 h0)) cs
58 lexChar cont ('\\':cs)   = failP "invalid char character" ('\\':(take 10 cs))
59 lexChar cont ('\'':cs)   = failP "invalid char character" ['\'']
60 lexChar cont ('\"':cs)   = failP "invalid char character" ['\"']
61 lexChar cont (c:'\'':cs) = cont (TKchar c) cs
62
63
64 lexString s cont ('\\':'x':h1:h0:cs) 
65         | isHexEscape [h1,h0] = lexString (s++[hexToChar h1 h0]) cont cs
66 lexString s cont ('\\':cs) = failP "invalid string character" ['\\']
67 lexString s cont ('\'':cs) = failP "invalid string character" ['\'']
68 lexString s cont ('\"':cs) = cont (TKstring s) cs
69 lexString s cont (c:cs) = lexString (s++[c]) cont cs
70
71 isHexEscape = all (\c -> isHexDigit c && (isDigit c || isLower c))
72
73 hexToChar h1 h0 = chr (digitToInt h1 * 16 + digitToInt h0)
74
75
76 lexNum cont cs =
77   case cs of
78      ('-':cs) -> f (-1) cs
79      _        -> f 1 cs
80  where f sgn cs = 
81          case span isDigit cs of
82           (digits,'.':c:rest) 
83                 | isDigit c -> cont (TKrational (fromInteger sgn * r)) rest'
84                 where ((r,rest'):_) = readFloat (digits ++ ('.':c:rest))
85                 -- When reading a floating-point number, which is
86                 -- a bit complicated, use the Haskell 98 library function
87           (digits,rest) -> cont (TKinteger (sgn * (read digits))) rest
88
89 lexName cont cstr cs = cont (cstr name) rest
90    where (name,rest) = span isNameChar cs
91
92 lexKeyword cont cs = 
93    case span isKeywordChar cs of
94       ("module",rest) -> cont TKmodule rest
95       ("data",rest)  -> cont TKdata rest
96       ("newtype",rest) -> cont TKnewtype rest
97       ("forall",rest) -> cont TKforall rest     
98       ("rec",rest) -> cont TKrec rest   
99       ("let",rest) -> cont TKlet rest   
100       ("in",rest) -> cont TKin rest     
101       ("case",rest) -> cont TKcase rest 
102       ("of",rest) -> cont TKof rest     
103       ("cast",rest) -> cont TKcast rest 
104       ("note",rest) -> cont TKnote rest 
105       ("external",rest) -> cont TKexternal rest
106       ("local",rest) -> cont TKlocal rest
107       ("_",rest) -> cont TKwild rest
108       _ -> failP "invalid keyword" ('%':cs) 
109