module Layout where data Token = Token String | TokenVLCurly String !Int | TokenNL !Int deriving(Show) data Context = NoLayout String | Layout String !Int layout :: [Token] -> [Context] -> [Token] layout (TokenNL n:Token "in":rs) (Layout "let" n':ls) = rbrace:Token "in":layout rs ls layout (TokenNL n:rs) (Layout h n':ls) | n == n' = semi:layout rs (Layout h n':ls) | n > n' = layout rs (Layout h n':ls) | n < n' = rbrace:layout (TokenNL n:rs) ls layout (TokenNL _:rs) ls = layout rs ls layout (TokenVLCurly h n:rs) (Layout h' n':ls) | n > n' = lbrace:layout rs (Layout h n:Layout h' n':ls) | otherwise = lbrace : rbrace : layout rs (Layout h' n':ls) layout (TokenVLCurly h n:rs) ls = lbrace:layout rs (Layout h n:ls) layout (t@(Token s):rs) ls | s `elem` fsts layoutBrackets = t:layout rs (NoLayout s:ls) layout (t@(Token s):rs) ls | s `elem` snds layoutBrackets = case ls of Layout _ _:ls -> rbrace:layout (t:rs) ls NoLayout _:ls -> t:layout rs ls [] -> error $ "unexpected " ++ show s layout (t@(Token "in"):rs) ls = case ls of Layout "let" n:ls -> rbrace:t:layout rs ls Layout _ _:ls -> rbrace:layout (t:rs) ls ls -> t:layout rs ls layout (t@(Token ","):rs) (Layout {}:ls) | topNoLayout ls `elem` [Just "(",Just "["] = rbrace:layout (t:rs) ls layout (t@(Token "where"):rs) ls = case ls of Layout l n : rest | l `notElem` ["where","let","of"] -> rbrace : t : layout rs rest -- 'where' closes 'do' _otherwise -> t : layout rs ls layout (t:rs) ls = t:layout rs ls layout [] (Layout _ n:ls) = rbrace:layout [] ls layout [] [] = [] topNoLayout :: [Context] -> Maybe String topNoLayout [] = Nothing topNoLayout (NoLayout s:_) = Just s topNoLayout (_:ls) = topNoLayout ls semi = Token ";" lbrace = Token "{" rbrace = Token "}" fsts = map fst snds = map snd layoutBrackets = [ ("case","of"), ("if","then"), ("(",")"), ("[","]"), ("{","}") ]