-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLex.hs
More file actions
47 lines (34 loc) · 2.44 KB
/
Copy pathLex.hs
File metadata and controls
47 lines (34 loc) · 2.44 KB
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
module Lex where
import Prelude hiding (seq)
import RegEx
import Control.Monad.Error
import Data.Char
type Regex = RegEx Char
mapFst :: (a->t) -> [(a,b)] -> [(t,b)]
mapFst f ps = map (\(x,y) ->(f x, y)) ps
lexer :: [(Regex,String -> t)] -> String -> Either String [t]
lexer rules s = lexAt 0 0 rules s where
lexAt line char rules s = do
(t,s',line',char') <- tokenize line char rules s
case s' of
[] -> return [t]
str -> do
rest <- lexAt line' char' rules str
return $ t:rest
tok :: [(Regex,String->t)] -> String -> Either String (t,String,Int,Int)
tok = tokenize 0 0
tokenize :: Int -> Int -> [(Regex,String->t)] -> String -> Either String (t,String,Int,Int)
tokenize line char rules string = go line char rules string [] where
go line char [] _ _ = Left "Error: Empty rule list."
go line char rules [] s = let rules' = filter ((\(a,b) -> empty a)) rules in
case rules' of
[] -> Left $ "Line: " ++ show line ++ " Char: " ++ show char ++ "\nError: Empty string unexpected"
(r:rs) -> Right (snd r $ reverse s,[],line,char)
go line char rules (c:cs) s = let char' = if c == '\n' then 0 else (char + 1)
line' = line + if c == '\n' then 1 else 0
step = mapFst (derivative c) rules in
case filter (\(a,b) -> notNull a) step of
(r:rs) -> go line' char' step cs (c:s)
[] -> case filter (\(a,b) -> empty a) rules of
[] -> Left $ "Line: " ++ show line ++ " Char: " ++ show char ++ "\nError: No matching regular expressions."
(r:rs) -> Right $ (snd r $ reverse s,(c:cs),line,char)