module Agda.Syntax.Parser.Layout
( withLayout
, offsideRule
, newLayoutBlock
, emptyLayout
, confirmLayout
) where
import Control.Monad ( when )
import Control.Monad.State ( gets, modify )
import Agda.Syntax.Parser.Lexer
import Agda.Syntax.Parser.Alex
import Agda.Syntax.Parser.Monad
import Agda.Syntax.Parser.Tokens
import Agda.Syntax.Parser.LexActions
import Agda.Syntax.Position
import Agda.Utils.Functor ((<&>))
import Agda.Utils.Impossible
offsideRule :: LexAction Token
offsideRule :: LexAction Token
offsideRule = (PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token
forall r.
(PreviousInput -> PreviousInput -> LexState -> Parser r)
-> LexAction r
LexAction ((PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token)
-> (PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ PreviousInput
inp PreviousInput
_ LexState
_ -> do
let p :: PositionWithoutFile
p = PreviousInput -> PositionWithoutFile
lexPos PreviousInput
inp
i :: Interval' SrcFile
i = SrcFile
-> PositionWithoutFile -> PositionWithoutFile -> Interval' SrcFile
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval (PreviousInput -> SrcFile
lexSrcFile PreviousInput
inp) PositionWithoutFile
p PositionWithoutFile
p
PositionWithoutFile -> Parser Ordering
forall a. Position' a -> Parser Ordering
getOffside PositionWithoutFile
p Parser Ordering -> (Ordering -> Parser Token) -> Parser Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Ordering
LT -> do Parser ()
popBlock
Token -> Parser Token
forall (m :: * -> *) a. Monad m => a -> m a
return (Symbol -> Interval' SrcFile -> Token
TokSymbol Symbol
SymCloseVirtualBrace Interval' SrcFile
i)
Ordering
EQ -> do Parser ()
popLexState
Token -> Parser Token
forall (m :: * -> *) a. Monad m => a -> m a
return (Symbol -> Interval' SrcFile -> Token
TokSymbol Symbol
SymVirtualSemi Interval' SrcFile
i)
Ordering
GT -> do Parser ()
popLexState
Parser Token
lexToken
emptyLayout :: LexAction Token
emptyLayout :: LexAction Token
emptyLayout = (PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token
forall r.
(PreviousInput -> PreviousInput -> LexState -> Parser r)
-> LexAction r
LexAction ((PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token)
-> (PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ PreviousInput
inp PreviousInput
_ LexState
_ -> do
let p :: PositionWithoutFile
p = PreviousInput -> PositionWithoutFile
lexPos PreviousInput
inp
i :: Interval' SrcFile
i = SrcFile
-> PositionWithoutFile -> PositionWithoutFile -> Interval' SrcFile
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval (PreviousInput -> SrcFile
lexSrcFile PreviousInput
inp) PositionWithoutFile
p PositionWithoutFile
p
Parser ()
popLexState
LexState -> Parser ()
pushLexState LexState
bol
Token -> Parser Token
forall (m :: * -> *) a. Monad m => a -> m a
return (Symbol -> Interval' SrcFile -> Token
TokSymbol Symbol
SymCloseVirtualBrace Interval' SrcFile
i)
newLayoutBlock :: LexAction Token
newLayoutBlock :: LexAction Token
newLayoutBlock = (PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token
forall r.
(PreviousInput -> PreviousInput -> LexState -> Parser r)
-> LexAction r
LexAction ((PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token)
-> (PreviousInput -> PreviousInput -> LexState -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ PreviousInput
inp PreviousInput
_ LexState
_ -> do
let p :: PositionWithoutFile
p = PreviousInput -> PositionWithoutFile
lexPos PreviousInput
inp
i :: Interval' SrcFile
i = SrcFile
-> PositionWithoutFile -> PositionWithoutFile -> Interval' SrcFile
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval (PreviousInput -> SrcFile
lexSrcFile PreviousInput
inp) PositionWithoutFile
p PositionWithoutFile
p
offset :: Column
offset = PositionWithoutFile -> Column
forall a. Position' a -> Column
posCol PositionWithoutFile
p
LayoutStatus
status <- Parser LayoutStatus
popPendingLayout
Keyword
kw <- (ParseState -> Keyword) -> Parser Keyword
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ParseState -> Keyword
parseLayKw
Column
prevOffs <- LayoutContext -> Column
confirmedLayoutColumn (LayoutContext -> Column) -> Parser LayoutContext -> Parser Column
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser LayoutContext
forall (m :: * -> *). MonadState ParseState m => m LayoutContext
getContext
if Column
prevOffs Column -> Column -> Bool
forall a. Ord a => a -> a -> Bool
>= Column
offset
then LexState -> Parser ()
pushLexState LexState
empty_layout
else do
Bool -> Parser () -> Parser ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LayoutStatus
status LayoutStatus -> LayoutStatus -> Bool
forall a. Eq a => a -> a -> Bool
== LayoutStatus
Confirmed) (Parser () -> Parser ()) -> Parser () -> Parser ()
forall a b. (a -> b) -> a -> b
$
(LayoutContext -> LayoutContext) -> Parser ()
modifyContext ((LayoutContext -> LayoutContext) -> Parser ())
-> (LayoutContext -> LayoutContext) -> Parser ()
forall a b. (a -> b) -> a -> b
$ Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks (Maybe Column -> LayoutContext -> LayoutContext)
-> Maybe Column -> LayoutContext -> LayoutContext
forall a b. (a -> b) -> a -> b
$ Column -> Maybe Column
forall a. a -> Maybe a
Just Column
offset
LayoutBlock -> Parser ()
pushBlock (LayoutBlock -> Parser ()) -> LayoutBlock -> Parser ()
forall a b. (a -> b) -> a -> b
$ Keyword -> LayoutStatus -> Column -> LayoutBlock
Layout Keyword
kw LayoutStatus
status Column
offset
Token -> Parser Token
forall (m :: * -> *) a. Monad m => a -> m a
return (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ Symbol -> Interval' SrcFile -> Token
TokSymbol Symbol
SymOpenVirtualBrace Interval' SrcFile
i
where
popPendingLayout :: Parser LayoutStatus
popPendingLayout :: Parser LayoutStatus
popPendingLayout = do
LayoutStatus
status <- (ParseState -> LayoutStatus) -> Parser LayoutStatus
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ParseState -> LayoutStatus
parseLayStatus
Parser ()
resetLayoutStatus
LayoutStatus -> Parser LayoutStatus
forall (m :: * -> *) a. Monad m => a -> m a
return LayoutStatus
status
confirmedLayoutColumn :: LayoutContext -> Column
confirmedLayoutColumn :: LayoutContext -> Column
confirmedLayoutColumn = \case
Layout Keyword
_ LayoutStatus
Confirmed Column
c : LayoutContext
_ -> Column
c
Layout Keyword
_ LayoutStatus
Tentative Column
_ : LayoutContext
cxt -> LayoutContext -> Column
confirmedLayoutColumn LayoutContext
cxt
[] -> Column
0
getOffside :: Position' a -> Parser Ordering
getOffside :: forall a. Position' a -> Parser Ordering
getOffside Position' a
loc =
Parser LayoutContext
forall (m :: * -> *). MonadState ParseState m => m LayoutContext
getContext Parser LayoutContext
-> (LayoutContext -> Ordering) -> Parser Ordering
forall (m :: * -> *) a b. Functor m => m a -> (a -> b) -> m b
<&> \case
Layout Keyword
_ LayoutStatus
_ Column
n : LayoutContext
_ -> Column -> Column -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Position' a -> Column
forall a. Position' a -> Column
posCol Position' a
loc) Column
n
LayoutContext
_ -> Ordering
GT
confirmLayout :: Parser ()
confirmLayout :: Parser ()
confirmLayout = Parser [LexState]
getLexState Parser [LexState] -> ([LexState] -> Parser ()) -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ case
LexState
s : [LexState]
_ | LexState
s LexState -> LexState -> Bool
forall a. Eq a => a -> a -> Bool
== LexState
layout -> Parser ()
confirmedLayoutComing
[LexState]
_ -> Parser ()
confirmLayoutAtNewLine
where
confirmedLayoutComing :: Parser ()
confirmedLayoutComing :: Parser ()
confirmedLayoutComing = (ParseState -> ParseState) -> Parser ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((ParseState -> ParseState) -> Parser ())
-> (ParseState -> ParseState) -> Parser ()
forall a b. (a -> b) -> a -> b
$ \ ParseState
s -> ParseState
s { parseLayStatus :: LayoutStatus
parseLayStatus = LayoutStatus
Confirmed }
confirmLayoutAtNewLine :: Parser ()
confirmLayoutAtNewLine :: Parser ()
confirmLayoutAtNewLine = (LayoutContext -> LayoutContext) -> Parser ()
modifyContext ((LayoutContext -> LayoutContext) -> Parser ())
-> (LayoutContext -> LayoutContext) -> Parser ()
forall a b. (a -> b) -> a -> b
$ Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks Maybe Column
forall a. Maybe a
Nothing
confirmTentativeBlocks :: Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks :: Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks Maybe Column
mcol = \case
Layout Keyword
kw LayoutStatus
Tentative Column
col : LayoutContext
cxt | Bool -> (Column -> Bool) -> Maybe Column -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Column
col Column -> Column -> Bool
forall a. Ord a => a -> a -> Bool
<) Maybe Column
mcol
-> Keyword -> LayoutStatus -> Column -> LayoutBlock
Layout Keyword
kw LayoutStatus
Confirmed Column
col LayoutBlock -> LayoutContext -> LayoutContext
forall a. a -> [a] -> [a]
: Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks (Column -> Maybe Column
forall a. a -> Maybe a
Just Column
col) LayoutContext
cxt
LayoutContext
cxt -> LayoutContext
cxt