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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
module SQLScanner(scan) where
import Data.Char (isDigit, isAlpha, isAlphaNum, toLower)
import Data.List (splitOn)
import Data.Time (CalendarTime (..))
import qualified Data.Map as Map
import SQLToken
scan :: String -> [Token]
scan chs =
case chs of
"" -> []
('*':cs) -> Asterix : scan cs
('(':cs) -> LParen : scan cs
(')':cs) -> RParen : scan cs
(',':cs) -> Comma : scan cs
(';':cs) -> Semi : scan cs
('.':cs) -> Stop : scan cs
('!':'=': cs) -> (BinOp Uneq) : scan cs
('=':cs) -> (BinOp Equal) : scan cs
('{':cs) -> readEmbedExp cs
('<':cs) -> readLessOp cs
('>':cs) -> readGreaterOp cs
('"' :cs) -> readVarString cs
('\'':cs) -> readVarChar cs
(' ':cs) -> scan cs
('\n':cs) -> scan cs
_ -> if (isDigit (head chs) || (head chs) == '-')
then (getNumberOrDate nStr) : scan nRs
else if (isAlpha (head chs))
then (specialOrIdent s) : scan rs
else (Unexpected (head chs)) : scan (tail chs)
where (nStr, nRs) = span isDigitOrNChar chs
(s,rs) = span isAlphaNumUnderScore chs
isDigitOrNChar :: Char -> Bool
isDigitOrNChar c = isDigit c || (c == '-') || (c == '.') || (c == ':')
isAlphaNumUnderScore :: Char -> Bool
isAlphaNumUnderScore c = isAlphaNum c || (c == '_')
specialOrIdent:: String -> Token
specialOrIdent str =
case Map.lookup lstr keywords of
Just tk -> tk
Nothing -> case Map.lookup lstr (Map.union operators constants) of
Just tk -> tk
Nothing -> Ident str
where lstr = map (toLower) str
getNumberOrDate :: String -> Token
getNumberOrDate str = if (':' `elem` str)
then (Constant
(Date
(CalendarTime (read y)
(read m)
(read d)
(read h)
(read mi)
(read s) 0)))
else getNumber str
where dateLs = splitOn [':'] str
(y, dLs1) = getNext dateLs
(m, dLs2) = getNext dLs1
(d, dLs3) = getNext dLs2
(h, dLs4) = getNext dLs3
(mi, dLs5) = getNext dLs4
(s, _) = getNext dLs5
getNext [] = ("0" , [])
getNext (num:ls) = (num, ls)
getNumber :: String -> Token
getNumber str = if ('.' `elem` str) then Constant (NumFloat f)
else Constant (NumInt (read str))
where ((f,_):_) = reads str
readEmbedExp :: String -> [Token]
readEmbedExp str = (EmbedExp embed):(scan rrest)
where (embed,rest) = break (\c -> c == '}') str
rrest = if (null rest) then rest else tail rest
readVarString :: String -> [Token]
readVarString str = (Constant (VarStr var)):(scan rrest)
where (var,rest) = break (\c -> c == '"' ) str
rrest = if (null rest) then rest else (tail rest)
readVarChar :: String -> [Token]
readVarChar str = (Constant var):(scan rrest)
where (svar,rest) = break (\c -> c== '\'') str
var = if (length svar) == 1
then (VarChar (head svar))
else if (length svar) == 0
then (VarChar ' ')
else (VarStr svar)
rrest = if (null rest) then rest else (tail rest)
readLessOp :: String -> [Token]
readLessOp [] = [(BinOp Lth)]
readLessOp (c:cs) = if ( c == '=') then (BinOp Lte) : scan cs
else (BinOp Lth) : scan (c:cs)
readGreaterOp :: String -> [Token]
readGreaterOp [] = [(BinOp Gth)]
readGreaterOp (c:cs) = if (c == '=') then (BinOp Gte) : scan cs
else (BinOp Gth) : scan (c:cs)
keywords :: Map.Map String Token
keywords = Map.fromList [("select", KW_Select),
("from", KW_From),
("where", KW_Where),
("order", KW_Order),
("group", KW_Group),
("by", KW_By),
("having", KW_Having),
("insert", KW_Insert),
("into", KW_Into),
("values", KW_Values),
("update", KW_Update),
("set", KW_Set),
("delete", KW_Delete),
("transaction", KW_Transaction),
("commit", KW_Commit),
("rollback", KW_Rollback),
("begin",KW_Begin),
("inner", KW_Inner),
("cross", KW_Cross),
("join", KW_Join),
("on", KW_On),
("as", KW_As),
("satisfies", KW_Satisfies),
("distinct", KW_Distinct),
("all", KW_All),
("case", KW_Case),
("when", KW_When),
("then", KW_Then),
("else", KW_Else),
("end", KW_End),
("asc", KW_Asc),
("desc", KW_Desc),
("limit", KW_Limit),
("exists", KW_Exists),
("not", KW_Not),
("table", KW_Table)]
constants :: Map.Map String Token
constants = Map.fromList [("true", Constant (Boolean True)),
("false", Constant (Boolean False)),
("null",Constant Null)]
operators :: Map.Map String Token
operators = Map.fromList [("like", BinOp Like),
("between", Between),
( "and", LogOp And ),
( "or", LogOp Or),
( "in", In),
( "is", Is),
("count", Fun Count),
("avg", Fun Avg),
("min", Fun Min),
("max", Fun Max),
("sum", Fun Sum),
("union", SetOp Union),
("intersect", SetOp Intersect),
("except", SetOp Except)]
|