module Lvm.Core.Parsing.Layout (layout) where
import Lvm.Core.Parsing.Token
layout :: [Token] -> [Token]
layout = doubleSemi . lay [] . addLayout
data Layout = CtxLay Int
| CtxLet Int
| CtxBrace
| Indent Int
deriving (Eq,Show)
type LayoutToken = Either (Pos, Layout) Token
getPos :: LayoutToken -> Pos
getPos = either fst fst
addLayout :: [Token] -> [LayoutToken]
addLayout ts =
case ts of
(pos,LexMODULE):_ -> addLay pos rest
(pos,LexLBRACE):_ -> addLay pos rest
(pos,_):_ -> Left (pos, CtxLay (snd pos)) : addLay pos rest
[] -> []
where
rest = map Right ts
addLay :: Pos -> [LayoutToken] -> [LayoutToken]
addLay _ [] = []
addLay (l, _) (t:ts) =
case t of
Left (pos@(ln, col), _)
| ln > l -> Left (pos, Indent col) : rest
| otherwise -> rest
where
rest = t : addLay pos ts
Right (pos@(ln, col), lexeme)
| ln > l -> Left (pos,Indent col) : t : rest
| otherwise -> t : rest
where
rest = case lexeme of
LexLET -> newlay CtxLet
LexLETSTRICT -> newlay CtxLet
LexWHERE -> newlay CtxLay
LexOF -> newlay CtxLay
LexDO -> newlay CtxLay
_ -> addLay pos ts
newlay ctx =
case ts of
[] -> []
u@(Right (pos',LexLBRACE)):us ->
u : addLay pos' us
u:us ->
let pos' = getPos u
in Left (pos', ctx (snd pos')) : u : addLay pos' us
lay :: [Layout] -> [LayoutToken] -> [Token]
lay ctx tokens =
case tokens of
[] -> []
Left (pos, c):ts ->
case (ctx, c, ts) of
(CtxLet _:cs, Indent _, Right t@(post,LexIN):rest) ->
(post,LexRBRACE) : t : lay cs rest
(CtxLet n:cs, Indent i, _)
| i == n -> (pos,LexSEMI) : lay ctx ts
| i < n -> (pos,LexRBRACE) : lay cs tokens
| otherwise -> lay ctx ts
(CtxLay n:cs, Indent i, _)
| i == n -> (pos,LexSEMI) : lay ctx ts
| i < n -> (pos,LexRBRACE) : lay cs tokens
| otherwise -> lay ctx ts
(CtxBrace:_, Indent _, _) -> lay ctx ts
(_,Indent _, _) -> lay ctx ts
_ -> (pos,LexLBRACE) : lay (c:ctx) ts
Right t@(pos, lexeme):ts ->
case (ctx, lexeme) of
(CtxLet _:cs, LexIN) -> (pos,LexRBRACE) : t : lay cs ts
(CtxLay _:cs, LexIN) -> (pos,LexRBRACE) : lay cs tokens
(CtxBrace:cs, LexRBRACE) -> t : lay cs ts
(_, LexLBRACE) -> t : lay (CtxBrace:ctx) ts
_ -> t : lay ctx ts
doubleSemi :: [Token] -> [Token]
doubleSemi (t@(_, LexSEMI):(_, LexSEMI):rest) = doubleSemi (t:rest)
doubleSemi (t:ts) = t:doubleSemi ts
doubleSemi [] = []