{-# OPTIONS -Wall -fno-warn-name-shadowing #-}

-- The grm grammar generator
-- Copyright 2011-2012, Brett Letner

module Grm.Layout (layout) where

import Grm.Lex
import Grm.Prims

layout :: [Token Point] -> [Token Point]
layout ts = loop [] ts
  where
  loop [] [] = []

  loop (_:cs) [] = stopSyms eofLoc ++ loop cs []

  loop cs (x:y:xs) | isStopSym x && isStopWord y = x : y : loop cs xs

  loop (_:cs) (x:xs) | isStopWord x =
    stopSyms (startLoc x) ++ [x] ++ loop (filter ((>=) $ col x) cs) xs

  loop (c:cs) xs0@(x:_) | col x < c = stopSyms (startLoc x) ++ loop cs xs0

  loop (c:cs) (x:xs) | col x == c && (isWord ["where"] x) = stopSyms (startLoc x) ++ cont cs x xs

  loop cs0@(c:_) (x:xs) | col x == c = termSym (startLoc x) : cont cs0 x xs

  loop cs0 (x:xs) = cont cs0 x xs

  cont cs0 x0 [] | isStartWord x0 = x0 : startSym (stopLoc x0) : loop (col x0 : cs0) []

  cont cs0 x0 (x:xs) | isStartWord x0 && not (isStartSym x) =
    x0 : startSym (startLoc x) : cont (col x : cs0) x xs

  cont cs0 x xs0 = x : loop cs0 xs0

  eofLoc = stopLoc $ last ts

isStartWord :: Token Point -> Bool
isStartWord = isWord [ "where", "do", "of", "imports", "exports", "branch" ] -- , "let"

isStopWord :: Token Point -> Bool
isStopWord = isWord [ "until" ]

isStartSym :: Token Point -> Bool
isStartSym = isWord ["{"]

isStopSym :: Token Point -> Bool
isStopSym = isWord ["}"]

isWord :: [String] -> Token Point -> Bool
isWord ss (TSymbol _ s) = s `elem` ss
isWord _ _ = False

col :: Token Point -> Int
col = locColumn . startLoc

mkSym :: String -> Loc -> Token Point
mkSym s l = TSymbol (Point l l) s

startSym :: Loc -> Token Point
startSym = mkSym "{"

stopSyms :: Loc -> [Token Point]
stopSyms loc = [ termSym loc, mkSym "}" loc ]

termSym :: Loc -> Token Point
termSym = mkSym ";"