module Text.Parser.Indentation.Implementation where

-- Implements common code for "Indentation Senstivie Parising: Landin Revisited"
--
-- Primary functions are:
--  - TODO
-- Primary driver functions are:
--  - TODO

-- TODO:
--   Grace style indentation stream
--   Haskell style indentation stream

--import Control.Monad

------------------------
-- Indentations
------------------------

-- We use indent 1 for the first column.  Not only is this consistent
-- with how Parsec counts columns, but it also allows 'Gt' to refer to
-- the first column by setting the indent to 0.
--data Indentation = Indentation# Int# deriving (Eq, Ord)
type Indentation = Int
data IndentationRel = Eq | Any | Const Indentation | Ge | Gt deriving (Int -> IndentationRel -> ShowS
[IndentationRel] -> ShowS
IndentationRel -> String
(Int -> IndentationRel -> ShowS)
-> (IndentationRel -> String)
-> ([IndentationRel] -> ShowS)
-> Show IndentationRel
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IndentationRel] -> ShowS
$cshowList :: [IndentationRel] -> ShowS
show :: IndentationRel -> String
$cshow :: IndentationRel -> String
showsPrec :: Int -> IndentationRel -> ShowS
$cshowsPrec :: Int -> IndentationRel -> ShowS
Show, IndentationRel -> IndentationRel -> Bool
(IndentationRel -> IndentationRel -> Bool)
-> (IndentationRel -> IndentationRel -> Bool) -> Eq IndentationRel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IndentationRel -> IndentationRel -> Bool
$c/= :: IndentationRel -> IndentationRel -> Bool
== :: IndentationRel -> IndentationRel -> Bool
$c== :: IndentationRel -> IndentationRel -> Bool
Eq)

{-# INLINE infIndentation #-}
infIndentation :: Indentation
infIndentation :: Int
infIndentation = Int
forall a. Bounded a => a
maxBound

{-
instance Num Indentation where

instance Show Indentation where
  show i@(Indentation# i') | i' == maxBound = "Infinity"
                           | otherwise = show (Int# i')
-}

------------------------
-- Indentable Stream
------------------------

-- We store state information about the current indentation in the
-- Stream.  Encoding the indentation state in the Stream is weird, but
-- the other two places where we could put it don't work.  The monad
-- isn't rolledback when backtracking happens (which we need the
-- indentation state to do), and the user state isn't available when
-- we do an 'uncons'.

{-# INLINE mkIndentationState #-}
mkIndentationState :: Indentation -> Indentation -> Bool -> IndentationRel -> IndentationState
mkIndentationState :: Int -> Int -> Bool -> IndentationRel -> IndentationState
mkIndentationState Int
lo Int
hi Bool
mode IndentationRel
rel
  | Int
lo Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
infIndentation = String -> IndentationState
forall a. HasCallStack => String -> a
error String
"mkIndentationState: minimum indentation 'infIndentation' is out of bounds"
  | Int
lo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
hi = String -> IndentationState
forall a. HasCallStack => String -> a
error String
"mkIndentationState: minimum indentation is greater than maximum indent"
  | Bool
otherwise = Int -> Int -> Bool -> IndentationRel -> IndentationState
IndentationState Int
lo Int
hi Bool
mode IndentationRel
rel

-- THEOREM: indent sets are all describable by upper and lower bounds (maxBound is infinity)
-- GLOBAL INVARIANT: minIndentation /= infIndentation
-- GLOBAL INVARIANT: minIndentation <= maxIndentation
-- GLOBAL INVARIENT: lo <= lo' where lo and lo' are minIndentation respectively before and after a monadic action
-- GLOBAL INVARIENT: hi' <= hi where hi and hi' are maxIndentation respectively before and after a monadic action

data IndentationState = IndentationState {
  IndentationState -> Int
minIndentation :: {-# UNPACK #-} !Indentation, -- inclusive, must not equal infIndentation
  IndentationState -> Int
maxIndentation :: {-# UNPACK #-} !Indentation, -- inclusive, infIndentation (i.e., maxBound) means infinity
  IndentationState -> Bool
absMode :: !Bool, -- true if we are in 'absolute' mode
  IndentationState -> IndentationRel
tokenRel :: !IndentationRel
  } deriving (Int -> IndentationState -> ShowS
[IndentationState] -> ShowS
IndentationState -> String
(Int -> IndentationState -> ShowS)
-> (IndentationState -> String)
-> ([IndentationState] -> ShowS)
-> Show IndentationState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IndentationState] -> ShowS
$cshowList :: [IndentationState] -> ShowS
show :: IndentationState -> String
$cshow :: IndentationState -> String
showsPrec :: Int -> IndentationState -> ShowS
$cshowsPrec :: Int -> IndentationState -> ShowS
Show)
  -- Our representation of maxIndentation will get us in trouble if things
  -- overflow.  In future we may want to use a type representing
  -- Integer+Infinity However, this bug triggers *only* when there are
  -- a large number of nested 'Gt' indentations which shouldn't be all
  -- that common and 'local'

{-# INLINE indentationStateAbsMode #-}
indentationStateAbsMode :: IndentationState -> Bool
indentationStateAbsMode :: IndentationState -> Bool
indentationStateAbsMode IndentationState
x = IndentationState -> Bool
absMode IndentationState
x

{-# INLINE updateIndentation #-}
-- PRIVATE: Use assertIndentation instead
updateIndentation :: IndentationState -> Indentation -> (IndentationState -> a) -> (String -> a) -> a
updateIndentation :: IndentationState
-> Int -> (IndentationState -> a) -> (String -> a) -> a
updateIndentation (IndentationState Int
lo Int
hi Bool
mode IndentationRel
rel) Int
i IndentationState -> a
ok String -> a
err = Int
-> Int
-> IndentationRel
-> Int
-> (Int -> Int -> a)
-> (String -> a)
-> a
forall a.
Int
-> Int
-> IndentationRel
-> Int
-> (Int -> Int -> a)
-> (String -> a)
-> a
updateIndentation' Int
lo Int
hi (if Bool
mode then IndentationRel
Eq else IndentationRel
rel) Int
i Int -> Int -> a
ok' String -> a
err' where
  ok' :: Int -> Int -> a
ok' Int
lo' Int
hi' = IndentationState -> a
ok (Int -> Int -> Bool -> IndentationRel -> IndentationState
IndentationState Int
lo' Int
hi' Bool
False IndentationRel
rel)
  err' :: String -> a
err' = String -> a
err

{-# INLINE updateIndentation' #-}
updateIndentation' :: Indentation -> Indentation -> IndentationRel -> Indentation -> (Indentation -> Indentation -> a) -> (String -> a) -> a
updateIndentation' :: Int
-> Int
-> IndentationRel
-> Int
-> (Int -> Int -> a)
-> (String -> a)
-> a
updateIndentation' Int
lo Int
hi IndentationRel
rel Int
i Int -> Int -> a
ok String -> a
err =
  case IndentationRel
rel of
    IndentationRel
Any                          -> Int -> Int -> a
ok Int
lo Int
hi
    Const Int
c | Int
c  Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
i            -> Int -> Int -> a
ok Int
lo Int
hi
            | Bool
otherwise          -> String -> a
err' (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"indentation "String -> ShowS
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
c
    IndentationRel
Eq      | Int
lo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i Bool -> Bool -> Bool
&& Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
hi -> Int -> Int -> a
ok Int
i Int
i
            | Bool
otherwise          -> String -> a
err' (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"an indentation between "String -> ShowS
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
loString -> ShowS
forall a. [a] -> [a] -> [a]
++String
" and "String -> ShowS
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
hi
    IndentationRel
Gt      | Int
lo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<  Int
i            -> Int -> Int -> a
ok Int
lo (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Int
hi)
            | Bool
otherwise          -> String -> a
err' (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"an indentation greater than "String -> ShowS
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
lo
    IndentationRel
Ge      | Int
lo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i            -> Int -> Int -> a
ok Int
lo (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
i Int
hi)
            | Bool
otherwise          -> String -> a
err' (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"an indentation greater than or equal to "String -> ShowS
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
lo
  where err' :: String -> a
err' String
place = String -> a
err (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ String
"Found a token at indentation "String -> ShowS
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
iString -> ShowS
forall a. [a] -> [a] -> [a]
++String
".  Expecting a token at "String -> ShowS
forall a. [a] -> [a] -> [a]
++String
placeString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"."

-- TODO: error when hi is maxIndentation

-- There is no way to query the current indentation because multiple
-- indentations are tried in parallel and later parsing may disqualify
-- one of these indentations.  However, we can assert that the current
-- indentation must have a particular relation, 'r', to a given
-- indentation, 'i'.  The call 'assertIndent r i' does this.  Calling
-- 'assertIndent r i' is equivalent to consuming a pseudo-token that has
-- been annotated with the relation 'r' at indentation 'i'.
--
-- Note that the absolute indentation mode may override 'r'.
{-
assertIndent :: (Monad m, Stream (IndentStream s) m t) => IndentRel -> Indent -> ParsecT (IndentStream s) u m ()
assertIndent r i = do
  IndentStream lo hi mode rel s <- getInput
  let ok s' = setInput (s' { absMode = mode }) -- Update input sets mode to False by default
      --ok lo' hi' = setInput (IndentStream lo' hi' mode rel s)
      err msg = unexpected $ "Indentation assertion '"++show r++" "++show i++"' failed.  "++msg
  updateIndent lo hi mode r i s ok err
  --updateIndent lo hi (if mode then Eq else r) i ok err
-}

{-
{-# INLINE askTokenMode #-}
askTokenMode :: (Monad m) => ParsecT (IndentStream s) u m IndentRel
askTokenMode = liftM tokenRel getInput
-}

------------------------
-- Token Modes
------------------------

-- Token modes determine how the current indentation must relate to
-- the indentation of a token.  Because several languages have special
-- rules for the first token of the production, we split the token
-- mode into two parts.  The first part is the mode for the first
-- token in a grammatical form while the second part is the mode for
-- the other tokens in a grammatical form.
--
-- Because of this split, while token modes generally follow a reader
-- monad pattern, there is one important exception.  Namely the
-- first-token mode may follow a state monad pattern.  (Thus we have
-- the divergent names for the first-token and other-token query
-- operators.)

-- THEOREM: tokenMode == tokenMode'
-- THEOREM: firstTokenMode' == firstTokenMode \/ firstTokenMode' == otherTokenMode

type LocalState a = (IndentationState -> IndentationState) -- pre
                  -> (IndentationState {-old-} -> IndentationState {-new-} -> IndentationState) -- post
                  -> a -> a

{-# INLINE localTokenMode #-}
localTokenMode :: (LocalState a)
               -> (IndentationRel -> IndentationRel)
               -> a -> a
localTokenMode :: LocalState a -> (IndentationRel -> IndentationRel) -> a -> a
localTokenMode LocalState a
localState IndentationRel -> IndentationRel
f_rel = LocalState a
localState IndentationState -> IndentationState
pre IndentationState -> IndentationState -> IndentationState
post where
  pre :: IndentationState -> IndentationState
pre  IndentationState
i1    = IndentationState
i1 { tokenRel :: IndentationRel
tokenRel = IndentationRel -> IndentationRel
f_rel (IndentationState -> IndentationRel
tokenRel IndentationState
i1) }
  post :: IndentationState -> IndentationState -> IndentationState
post IndentationState
i1 IndentationState
i2 = IndentationState
i2 { tokenRel :: IndentationRel
tokenRel =        IndentationState -> IndentationRel
tokenRel IndentationState
i1  }

{-# INLINE absoluteIndentation #-}
absoluteIndentation :: LocalState a -> a -> a
absoluteIndentation :: LocalState a -> a -> a
absoluteIndentation LocalState a
localState = LocalState a
localState IndentationState -> IndentationState
pre IndentationState -> IndentationState -> IndentationState
post where
  pre :: IndentationState -> IndentationState
pre  IndentationState
i1    = IndentationState
i1 { absMode :: Bool
absMode = Bool
True }
  post :: IndentationState -> IndentationState -> IndentationState
post IndentationState
i1 IndentationState
i2 = IndentationState
i2 { absMode :: Bool
absMode = IndentationState -> Bool
absMode IndentationState
i1 Bool -> Bool -> Bool
&& IndentationState -> Bool
absMode IndentationState
i2 }

{-# INLINE ignoreAbsoluteIndentation #-}
ignoreAbsoluteIndentation :: LocalState a -> a -> a
ignoreAbsoluteIndentation :: LocalState a -> a -> a
ignoreAbsoluteIndentation LocalState a
localState = LocalState a
localState IndentationState -> IndentationState
pre IndentationState -> IndentationState -> IndentationState
post where
  pre :: IndentationState -> IndentationState
pre  IndentationState
i1    = IndentationState
i1 { absMode :: Bool
absMode = Bool
False }
  post :: IndentationState -> IndentationState -> IndentationState
post IndentationState
i1 IndentationState
i2 = IndentationState
i2 { absMode :: Bool
absMode = IndentationState -> Bool
absMode IndentationState
i1 }

{-# INLINE localAbsoluteIndentation #-}
localAbsoluteIndentation :: LocalState a -> a -> a
localAbsoluteIndentation :: LocalState a -> a -> a
localAbsoluteIndentation LocalState a
localState = LocalState a
localState IndentationState -> IndentationState
pre IndentationState -> IndentationState -> IndentationState
post where
  pre :: IndentationState -> IndentationState
pre  IndentationState
i1    = IndentationState
i1 { absMode :: Bool
absMode = Bool
True }
  post :: IndentationState -> IndentationState -> IndentationState
post IndentationState
i1 IndentationState
i2 = IndentationState
i2 { absMode :: Bool
absMode = IndentationState -> Bool
absMode IndentationState
i1 }

--{-# INLINE askTokenMode #-}
--askTokenMode :: (Monad m) => ParsecT (IndentationStream s) u m IndentationRel
--askTokenMode = liftM tokenRel getInput
-- TODO: assertNotAbsMod/askAbsMode
-- when (absMode i2) (fail "absoluteIndentation: no tokens consumed") >>

------------------------
-- Local Indentations
------------------------

{-# INLINE localIndentation' #-}
-- PRIVATE: locally violates global invariants but used in a way that does not
localIndentation' :: LocalState a -> (Indentation -> Indentation) -> (Indentation -> Indentation) -> (Indentation -> Indentation -> Indentation) -> a -> a
localIndentation' :: LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
localIndentation' LocalState a
localState Int -> Int
f_lo Int -> Int
f_hi Int -> Int -> Int
f_hi' a
m = LocalState a
localState IndentationState -> IndentationState
pre IndentationState -> IndentationState -> IndentationState
post a
m
  where pre :: IndentationState -> IndentationState
pre (IndentationState Int
lo Int
hi Bool
mode IndentationRel
rel) = Int -> Int -> Bool -> IndentationRel -> IndentationState
IndentationState (Int -> Int
f_lo Int
lo) (Int -> Int
f_hi Int
hi) Bool
mode IndentationRel
rel
        post :: IndentationState -> IndentationState -> IndentationState
post (IndentationState Int
lo Int
hi Bool
_ IndentationRel
_) IndentationState
i2 = IndentationState
i2 { minIndentation :: Int
minIndentation = Int
lo, maxIndentation :: Int
maxIndentation = Int -> Int -> Int
f_hi' Int
hi (IndentationState -> Int
maxIndentation IndentationState
i2) }
--        post (IndentationStream lo hi mode rel s) i2 = IndentationStream lo (f_hi' hi (maxIndentation i2)) mode rel s

-- 'localIndentation r p' specifies that the current indentation for 'p' must have relation 'r'
-- relative to the current indentation of the context in which 'localIndentation r p' is called.
{-# INLINE localIndentation #-}
-- NOTE: it is the responsibility of 'localState' to *not* use it's arguments if we are in absMode
localIndentation :: LocalState a -> IndentationRel -> a -> a
localIndentation :: LocalState a -> IndentationRel -> a -> a
localIndentation LocalState a
_localState IndentationRel
Eq a
m = a
m
localIndentation LocalState a
localState IndentationRel
Any a
m = LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
forall a.
LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
localIndentation' LocalState a
localState (Int -> Int -> Int
forall a b. a -> b -> a
const Int
0) (Int -> Int -> Int
forall a b. a -> b -> a
const Int
infIndentation) (Int -> Int -> Int
forall a b. a -> b -> a
const) a
m
localIndentation LocalState a
localState (Const Int
c) a
m
    | Int
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
infIndentation = String -> a
forall a. HasCallStack => String -> a
error String
"localIndentation: Const indentation 'infIndentation' is out of bounds"
    | Bool
otherwise = LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
forall a.
LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
localIndentation' LocalState a
localState (Int -> Int -> Int
forall a b. a -> b -> a
const Int
c) (Int -> Int -> Int
forall a b. a -> b -> a
const Int
c) (Int -> Int -> Int
forall a b. a -> b -> a
const) a
m
localIndentation LocalState a
localState IndentationRel
Ge a
m = LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
forall a.
LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
localIndentation' LocalState a
localState (Int -> Int
forall a. a -> a
id) (Int -> Int -> Int
forall a b. a -> b -> a
const Int
infIndentation) ((Int -> Int -> Int) -> Int -> Int -> Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Int -> Int
forall a b. a -> b -> a
const) a
m
localIndentation LocalState a
localState IndentationRel
Gt a
m = LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
forall a.
LocalState a
-> (Int -> Int) -> (Int -> Int) -> (Int -> Int -> Int) -> a -> a
localIndentation' LocalState a
localState (Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (Int -> Int -> Int
forall a b. a -> b -> a
const Int
infIndentation) (Int -> Int -> Int
f) ({-TODO: checkOverflow >>-} a
m) where
  f :: Int -> Int -> Int
f Int
hi Int
hi' | Int
hi' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
infIndentation Bool -> Bool -> Bool
|| Int
hi Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
hi' = Int
hi
           | Int
hi' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = Int
hi' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 -- Safe only b/c hi' > 0
           | Bool
otherwise = String -> Int
forall a. HasCallStack => String -> a
error String
"localIndentation: assertion failed: hi' > 0"
{-
  checkOverflow = do
    IndentationStream { minIndentation = lo } <- getState
    when (lo == infIndentation) $ fail "localIndentation: Overflow in indentation lower bound."
-}

----------------
-- SourcePos

{-
mkSourcePosIndentStream s = SourcePosIndentStream s
newtype SourcePosIndentStream s = SourcePosIndentStream s
instance (Stream s m t) => Stream (SourcePosIndentStream s) m (Indent, t) where
  uncons (SourcePosIndentStream s) = do
    col <- liftM sourceColumn $ getPosition
    x <- uncons s
    case x of
      Nothing -> return Nothing
      Just x -> return (Just ((col, x), SourcePosIndentStream s))
-}

----------------
-- Unicode char
-- newtype UnicodeIndentStream

{-
----------------
-- Based on Char
mkCharIndentStream :: s -> CharIndentStream s
mkCharIndentStream s = CharIndentStream 1 s
data CharIndentStream s = CharIndentStream { charIndentStreamColumn :: !Indent,
                                             charIndentStreamStream :: s } deriving (Show)

instance (Stream s m Char) => Stream (CharIndentStream s) m (Indent, Char) where
  uncons (CharIndentStream i s) = do
    x <- uncons s
    case x of
      Nothing -> return Nothing
      Just (c, cs) -> return (Just ((i, c), CharIndentStream (f c) cs)) where
        f '\n' = 1
        f '\t' = i + 8 - ((i-1) `mod` 8)
        f _    = i + 1

charIndentStreamParser :: (Monad m) => ParsecT s u m t -> ParsecT (CharIndentStream s) u m (Indent, t)
charIndentStreamParser p = mkPT $ \state ->
  let go (Ok a state' e) = return (Ok (sourceColumn $ statePos state, a) (state' { stateInput = CharIndentStream (sourceColumn $ statePos state') (stateInput state') }) e)
      go (Error e) = return (Error e)
  in runParsecT p (state { stateInput = charIndentStreamStream (stateInput state) })
         >>= consumed (return . Consumed . go) (return . Empty . go)

----------------
-- TODO: parser based on first non-whitespace char

----------------
-- First token of line indents

----------------
-- Based on Indents

-- Note that if 'p' consumes input but is at the wrong indentation, then
-- 'indentStreamParser p' signals an error but does *not* consume input.
-- This allows Parsec primitives like 'string' to be properly backtracked.
indentStreamParser :: (Monad m) => ParsecT s u m (Indent, t) -> ParsecT (IndentStream s) u m t
indentStreamParser p = mkPT $ \state ->
  let IndentStream lo hi mode rel _ = stateInput state
      go f (Ok (i, a) state' e) = updateIndent lo hi (if mode then Eq else rel) i ok err where
        ok lo' hi' = return $ f $ return (Ok a (state' {stateInput = IndentStream lo' hi' False rel (stateInput state') }) e)
        err msg = return $ Empty $ return $ Error (Message ("Invalid indentation.  "++msg++show ((stateInput state) { tokenStream = ""})) `addErrorMessage` e)
      go f (Error e) = return $ f $ return (Error e)
  in runParsecT p (state { stateInput = tokenStream (stateInput state) }) >>= consumed (go Consumed) (go Empty)

-- lifting operator
-- token, tokens, tokenPrim, tokenPrimEx ???
-- whiteSpace
-- ByteString
-- ByteString.Lazy
-- Text

delimitedLayout :: Stream (IndentStream s) m t =>
  ParsecT (IndentStream s) u m open -> Bool ->
  ParsecT (IndentStream s) u m close -> Bool ->
  ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m a
delimitedLayout open openAny close closeAny body = between open' close' (localIndent (Const 0) body) where
  open'  | openAny = localIndent (Const 0) open
         | otherwise = open
  close' | closeAny = localIndent (Const 0) close
         | otherwise = close

indentedLayout :: Stream (IndentStream s) m t =>
  (Maybe (ParsecT (IndentStream s) u m sep)) ->
  ParsecT (IndentStream s) u m a -> ParsecT (IndentStream s) u m [a]
indentedLayout (Nothing ) clause = localIndent Gt $ many $ absoluteIndent $ clause
indentedLayout (Just sep) clause = liftM concat $ localIndent Gt $ many $ absoluteIndent $ sepBy1 clause sep

{-
layout p = delimitedLayout (symbol "{") False (symbol "}") True (semiSep p)
       <|> indentedLayout (Just semi) p

identifier pred = liftM fromString $ try $ identifier >>= \x -> guard (pred x) >> return x
operator pred = liftM fromString $ try $ operator >>= \x -> guard (pred x) >> return x

reserved name = (if name `elem` middleKeywords then localFirstTokenMode (const Ge) else id) $ reserved name

Numbers, Integers and Naturals are custom

dotSep
dotSep1

-}

{-
test :: String
test = foo where
          foo = "abc \
\def" ++ ""

test2 :: Int
test2 = foo where
          foo = let { x = 1;
 } in x


--- All code indented?
  foo = 3
  bar = 4
-}
-}