1module Language.Haskell.Lexer.Layout (layoutPre,PosToken) where
2
3import Language.Haskell.Lexer.Tokens
4import Language.Haskell.Lexer.Position
5
6type PosToken = (Token,(Pos,String))
7
8-- | This is an implementation of Haskell layout, as specified in
9-- section 9.3 of the revised Haskell 98 report.
10-- This preprocessor inserts the extra \<n\> and {n} tokens.
11layoutPre :: [PosToken] -> [PosToken]
12layoutPre = indent . open
13
14open :: [PosToken] -> [PosToken]
15open = open1
16
17{-+
18If the first lexeme of a module is not { or module, then it is preceded
19by {n} where n is the indentation of the lexeme.
20-}
21open1 :: [PosToken] -> [PosToken]
22open1 (t1@(Reservedid,(_,"module")):ts) = t1:open2 ts
23open1 (t1@(Special,(_,"{")):ts)         = t1:open2 ts
24open1 ts@((_,(p,_)):_)                  = (Open (column p),(p,"")):open2 ts
25open1 []                                = []
26
27{-+
28If a let, where, do, or of keyword is not followed by the lexeme {,
29the token {n} is inserted after the keyword, where n is the indentation of
30the next lexeme if there is one, or 0 if the end of file has been reached.
31-}
32open2 :: [PosToken] -> [PosToken]
33open2 (t1:ts1) | isLtoken t1 =
34    case ts1 of
35      t2@(_,(p,_)):ts2 ->
36        if notLBrace t2
37        then t1:(Open (column p),(p,"")):open2 ts1
38        else t1:t2:open2 ts2
39      [] -> t1:(Open 0,(fst (snd t1),"")):[]
40  where
41    isLtoken (Reservedid,(_,s)) = s `elem` ["let","where","do","of"]
42    isLtoken _ = False
43
44    notLBrace (Special,(_,"{")) = False
45    notLBrace _ = True
46open2 (t:ts) = t:open2 ts
47open2 [] = []
48
49{-+
50(This is from the original Haskell 98 report.)
51The first token on each line (not including tokens already annotated) is
52preceeded by &lt;n&gt;, where n is the indentation of the token.
53-}
54indent :: [PosToken] -> [PosToken]
55indent (t1@(Open _,(p,_)):ts) = t1:indent2 (line p) ts
56indent (t1@(_,(p,_)):ts)    = (Indent (column p),(p,"")):t1:indent2 (line p) ts
57indent [] = []
58
59indent2 :: Int -> [PosToken] -> [PosToken]
60indent2 r (t1@(_,(p,_)):ts) | line p==r = t1:indent2 r ts
61indent2 _ ts = indent ts
62