module Helium.Parser.LayoutRule(layout) where
import Helium.Parser.LexerToken(Token, Lexeme(..), lexemeLength)
import Text.ParserCombinators.Parsec.Pos
layout :: [Token] -> [Token]
layout [] = []
layout input@((pos, lexeme):_) = optimise $
case lexeme of
LexKeyword "module" ->
lay dummyToken [] input
LexSpecial '{' ->
lay dummyToken [] input
_ ->
(pos, LexInsertedOpenBrace) :
lay dummyToken [CtxLay (sourceColumn pos) False] input
where
zeroPos = setSourceColumn (setSourceLine pos 0) 0
dummyToken = (zeroPos, LexVar "")
optimise :: [Token] -> [Token]
optimise (token1@(_, LexInsertedOpenBrace) : (_, LexInsertedSemicolon) : ts) =
optimise (token1 : ts)
optimise (t:ts) =
t : optimise ts
optimise [] = []
data Context
= CtxLay Int Bool
| CtxBrace
deriving (Eq,Show)
lay :: Token -> [Context] -> [Token] -> [Token]
lay _
cc@(CtxBrace:cs)
input@(t@(_, lexeme):ts)
| lexeme == LexSpecial '}' =
t : lay t cs ts
| otherwise =
t : addContext t cc input
lay prevToken
(CtxLay _ True:cs)
(t@(_, LexKeyword "in"):ts)
= (behind prevToken, LexInsertedCloseBrace) : t : lay t cs ts
lay prevToken@(prevPos, _)
cc@(CtxLay ctxCol _:cs)
input@(t@(pos, _):_)
| sourceLine pos > sourceLine prevPos =
if sourceColumn pos > ctxCol then
t : addContext t cc input
else if sourceColumn pos == ctxCol then
(behind prevToken, LexInsertedSemicolon) : t : addContext t cc input
else
(behind prevToken, LexInsertedCloseBrace) : lay prevToken cs input
| otherwise =
t : addContext t cc input
lay _ _ [] = []
lay _ [] input@(t@(_, _):_) =
t : addContext t [] input
behind :: Token -> SourcePos
behind (pos, lexeme) = incSourceColumn pos (lexemeLength lexeme)
addContext :: Token -> [Context] -> [Token] -> [Token]
addContext prevToken cs ((_, LexSpecial '{'):ts) =
lay prevToken (CtxBrace : cs) ts
addContext prevToken cs
((_, LexKeyword keyword):t2@(pos2, lexeme2):ts)
| keyword `elem` ["do", "where", "of","let"] =
if lexeme2 == LexSpecial '{' then
lay prevToken cs (t2:ts)
else
(pos2, LexInsertedOpenBrace) :
lay prevToken
(CtxLay (sourceColumn pos2) (keyword == "let") : cs)
(t2:ts)
| otherwise =
lay prevToken cs (t2:ts)
addContext prevToken cs (_:ts) =
lay prevToken cs ts
addContext _ _ [] = []