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 = forall r.
(PreviousInput -> PreviousInput -> LexState -> Parser r)
-> LexAction r
LexAction 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 = forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval (PreviousInput -> SrcFile
lexSrcFile PreviousInput
inp) PositionWithoutFile
p PositionWithoutFile
p
forall a. Position' a -> Parser Ordering
getOffside PositionWithoutFile
p forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Ordering
LT -> do Parser ()
popBlock
forall (m :: * -> *) a. Monad m => a -> m a
return (Symbol -> Interval' SrcFile -> Token
TokSymbol Symbol
SymCloseVirtualBrace Interval' SrcFile
i)
Ordering
EQ -> do Parser ()
popLexState
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 = forall r.
(PreviousInput -> PreviousInput -> LexState -> Parser r)
-> LexAction r
LexAction 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 = forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval (PreviousInput -> SrcFile
lexSrcFile PreviousInput
inp) PositionWithoutFile
p PositionWithoutFile
p
Parser ()
popLexState
LexState -> Parser ()
pushLexState LexState
bol
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 = forall r.
(PreviousInput -> PreviousInput -> LexState -> Parser r)
-> LexAction r
LexAction 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 = forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval (PreviousInput -> SrcFile
lexSrcFile PreviousInput
inp) PositionWithoutFile
p PositionWithoutFile
p
offset :: Column
offset = forall a. Position' a -> Column
posCol PositionWithoutFile
p
LayoutStatus
status <- Parser LayoutStatus
popPendingLayout
Keyword
kw <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ParseState -> Keyword
parseLayKw
Column
prevOffs <- LayoutContext -> Column
confirmedLayoutColumn forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). MonadState ParseState m => m LayoutContext
getContext
if Column
prevOffs forall a. Ord a => a -> a -> Bool
>= Column
offset
then LexState -> Parser ()
pushLexState LexState
empty_layout
else do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LayoutStatus
status forall a. Eq a => a -> a -> Bool
== LayoutStatus
Confirmed) forall a b. (a -> b) -> a -> b
$
(LayoutContext -> LayoutContext) -> Parser ()
modifyContext forall a b. (a -> b) -> a -> b
$ Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just Column
offset
LayoutBlock -> Parser ()
pushBlock forall a b. (a -> b) -> a -> b
$ Keyword -> LayoutStatus -> Column -> LayoutBlock
Layout Keyword
kw LayoutStatus
status Column
offset
forall (m :: * -> *) a. Monad m => a -> m a
return 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 <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ParseState -> LayoutStatus
parseLayStatus
Parser ()
resetLayoutStatus
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 =
forall (m :: * -> *). MonadState ParseState m => m LayoutContext
getContext forall (m :: * -> *) a b. Functor m => m a -> (a -> b) -> m b
<&> \case
Layout Keyword
_ LayoutStatus
_ Column
n : LayoutContext
_ -> forall a. Ord a => a -> a -> Ordering
compare (forall a. Position' a -> Column
posCol Position' a
loc) Column
n
LayoutContext
_ -> Ordering
GT
confirmLayout :: Parser ()
confirmLayout :: Parser ()
confirmLayout = Parser [LexState]
getLexState forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ case
LexState
s : [LexState]
_ | LexState
s forall a. Eq a => a -> a -> Bool
== LexState
layout -> Parser ()
confirmedLayoutComing
[LexState]
_ -> Parser ()
confirmLayoutAtNewLine
where
confirmedLayoutComing :: Parser ()
confirmedLayoutComing :: Parser ()
confirmedLayoutComing = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify 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 forall a b. (a -> b) -> a -> b
$ Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks 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 | forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Column
col forall a. Ord a => a -> a -> Bool
<) Maybe Column
mcol
-> Keyword -> LayoutStatus -> Column -> LayoutBlock
Layout Keyword
kw LayoutStatus
Confirmed Column
col forall a. a -> [a] -> [a]
: Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks (forall a. a -> Maybe a
Just Column
col) LayoutContext
cxt
LayoutContext
cxt -> LayoutContext
cxt