summaryrefslogtreecommitdiff
path: root/compiler/parser/LexCore.hs
blob: 99ec88ea6ee5b26a0f7db28a4a9af8093dfe49cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{-# OPTIONS -w #-}
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and fix
-- any warnings in the module. See
--     http://hackage.haskell.org/trac/ghc/wiki/CodingStyle#Warnings
-- for details

module LexCore where

import ParserCoreUtils
import Char
import Numeric

isNameChar c = isAlpha c || isDigit c || (c == '_') || (c == '\'')
	       || (c == '$') || (c == '-') || (c == '.')
isKeywordChar c = isAlpha c || (c == '_') 

lexer :: (Token -> P a) -> P a 
lexer cont [] 		= cont TKEOF []
lexer cont ('\n':cs) 	= \line -> lexer cont cs (line+1)
lexer cont ('-':'>':cs) = cont TKrarrow cs

lexer cont (c:cs) 
      | isSpace c		= lexer cont cs
      | isLower c || (c == '_') = lexName cont TKname (c:cs)
      | isUpper c 		= lexName cont TKcname (c:cs)
      | isDigit c || (c == '-') = lexNum cont (c:cs)

lexer cont ('%':cs)  	= lexKeyword cont cs
lexer cont ('\'':cs) 	= lexChar cont cs
lexer cont ('\"':cs) 	= lexString [] cont cs 
lexer cont ('#':cs) 	= cont TKhash cs
lexer cont ('(':cs) 	= cont TKoparen cs
lexer cont (')':cs) 	= cont TKcparen cs
lexer cont ('{':cs) 	= cont TKobrace cs
lexer cont ('}':cs) 	= cont TKcbrace cs
lexer cont ('=':cs)     = cont TKeq cs
lexer cont (':':'=':':':cs) = cont TKcoloneqcolon cs
lexer cont (':':':':cs) = cont TKcoloncolon cs
lexer cont ('*':cs) 	= cont TKstar cs
lexer cont ('.':cs) 	= cont TKdot cs
lexer cont ('\\':cs)    = cont TKlambda cs
lexer cont ('@':cs) 	= cont TKat cs
lexer cont ('?':cs) 	= cont TKquestion cs
lexer cont (';':cs) 	= cont TKsemicolon cs
-- 20060420 GHC spits out constructors with colon in them nowadays. jds
-- 20061103 but it's easier to parse if we split on the colon, and treat them
-- as several tokens
lexer cont (':':cs)     = cont TKcolon cs
-- 20060420 Likewise does it create identifiers starting with dollar. jds
lexer cont ('$':cs)     = lexName cont TKname ('$':cs)
lexer cont (c:cs) 	= failP "invalid character" [c]



lexChar cont ('\\':'x':h1:h0:'\'':cs)
	| isHexEscape [h1,h0] =  cont (TKchar (hexToChar h1 h0)) cs
lexChar cont ('\\':cs) 	 = failP "invalid char character" ('\\':(take 10 cs))
lexChar cont ('\'':cs) 	 = failP "invalid char character" ['\'']
lexChar cont ('\"':cs) 	 = failP "invalid char character" ['\"']
lexChar cont (c:'\'':cs) = cont (TKchar c) cs


lexString s cont ('\\':'x':h1:h0:cs) 
	| isHexEscape [h1,h0] = lexString (s++[hexToChar h1 h0]) cont cs
lexString s cont ('\\':cs) = failP "invalid string character" ['\\']
lexString s cont ('\'':cs) = failP "invalid string character" ['\'']
lexString s cont ('\"':cs) = cont (TKstring s) cs
lexString s cont (c:cs) = lexString (s++[c]) cont cs

isHexEscape = all (\c -> isHexDigit c && (isDigit c || isLower c))

hexToChar h1 h0 = chr (digitToInt h1 * 16 + digitToInt h0)


lexNum cont cs =
  case cs of
     ('-':cs) -> f (-1) cs
     _ 	      -> f 1 cs
 where f sgn cs = 
         case span isDigit cs of
          (digits,'.':c:rest) 
		| isDigit c -> cont (TKrational (fromInteger sgn * r)) rest'
	        where ((r,rest'):_) = readFloat (digits ++ ('.':c:rest))
		-- When reading a floating-point number, which is
		-- a bit complicated, use the Haskell 98 library function
          (digits,rest) -> cont (TKinteger (sgn * (read digits))) rest

lexName cont cstr cs = cont (cstr name) rest
   where (name,rest) = span isNameChar cs

lexKeyword cont cs = 
   case span isKeywordChar cs of
      ("module",rest) -> cont TKmodule rest
      ("data",rest)  -> cont TKdata rest
      ("newtype",rest) -> cont TKnewtype rest
      ("forall",rest) -> cont TKforall rest	
      ("rec",rest) -> cont TKrec rest	
      ("let",rest) -> cont TKlet rest	
      ("in",rest) -> cont TKin rest	
      ("case",rest) -> cont TKcase rest	
      ("of",rest) -> cont TKof rest	
      ("cast",rest) -> cont TKcast rest	
      ("note",rest) -> cont TKnote rest	
      ("external",rest) -> cont TKexternal rest
      ("local",rest) -> cont TKlocal rest
      ("_",rest) -> cont TKwild rest
      _ -> failP "invalid keyword" ('%':cs)