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 -> TokenLength -> Parser Token)
-> LexAction Token
forall r.
(PreviousInput -> PreviousInput -> TokenLength -> Parser r)
-> LexAction r
LexAction ((PreviousInput -> PreviousInput -> TokenLength -> Parser Token)
-> LexAction Token)
-> (PreviousInput -> PreviousInput -> TokenLength -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ PreviousInput
inp PreviousInput
_ TokenLength
_ -> 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 -> TokenLength -> Parser Token)
-> LexAction Token
forall r.
(PreviousInput -> PreviousInput -> TokenLength -> Parser r)
-> LexAction r
LexAction ((PreviousInput -> PreviousInput -> TokenLength -> Parser Token)
-> LexAction Token)
-> (PreviousInput -> PreviousInput -> TokenLength -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ PreviousInput
inp PreviousInput
_ TokenLength
_ -> 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
TokenLength -> Parser ()
pushLexState TokenLength
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 -> TokenLength -> Parser Token)
-> LexAction Token
forall r.
(PreviousInput -> PreviousInput -> TokenLength -> Parser r)
-> LexAction r
LexAction ((PreviousInput -> PreviousInput -> TokenLength -> Parser Token)
-> LexAction Token)
-> (PreviousInput -> PreviousInput -> TokenLength -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ PreviousInput
inp PreviousInput
_ TokenLength
_ -> 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 :: Int32
offset = PositionWithoutFile -> Int32
forall a. Position' a -> Int32
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
Int32
prevOffs <- LayoutContext -> Int32
confirmedLayoutColumn (LayoutContext -> Int32) -> Parser LayoutContext -> Parser Int32
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser LayoutContext
forall (m :: * -> *). MonadState ParseState m => m LayoutContext
getContext
if Int32
prevOffs Int32 -> Int32 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int32
offset
then TokenLength -> Parser ()
pushLexState TokenLength
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 Int32 -> LayoutContext -> LayoutContext
confirmTentativeBlocks (Maybe Int32 -> LayoutContext -> LayoutContext)
-> Maybe Int32 -> LayoutContext -> LayoutContext
forall a b. (a -> b) -> a -> b
$ Int32 -> Maybe Int32
forall a. a -> Maybe a
Just Int32
offset
LayoutBlock -> Parser ()
pushBlock (LayoutBlock -> Parser ()) -> LayoutBlock -> Parser ()
forall a b. (a -> b) -> a -> b
$ Keyword -> LayoutStatus -> Int32 -> LayoutBlock
Layout Keyword
kw LayoutStatus
status Int32
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 -> Int32
confirmedLayoutColumn = \case
Layout Keyword
_ LayoutStatus
Confirmed Int32
c : LayoutContext
_ -> Int32
c
Layout Keyword
_ LayoutStatus
Tentative Int32
_ : LayoutContext
cxt -> LayoutContext -> Int32
confirmedLayoutColumn LayoutContext
cxt
[] -> Int32
0
getOffside :: Position' a -> Parser Ordering
getOffside :: 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
_ Int32
n : LayoutContext
_ -> Int32 -> Int32 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Position' a -> Int32
forall a. Position' a -> Int32
posCol Position' a
loc) Int32
n
LayoutContext
_ -> Ordering
GT
confirmLayout :: Parser ()
confirmLayout :: Parser ()
confirmLayout = Parser [TokenLength]
getLexState Parser [TokenLength] -> ([TokenLength] -> Parser ()) -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ case
TokenLength
s : [TokenLength]
_ | TokenLength
s TokenLength -> TokenLength -> Bool
forall a. Eq a => a -> a -> Bool
== TokenLength
layout -> Parser ()
confirmedLayoutComing
[TokenLength]
_ -> 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 Int32 -> LayoutContext -> LayoutContext
confirmTentativeBlocks Maybe Int32
forall a. Maybe a
Nothing
confirmTentativeBlocks :: Maybe Column -> LayoutContext -> LayoutContext
confirmTentativeBlocks :: Maybe Int32 -> LayoutContext -> LayoutContext
confirmTentativeBlocks Maybe Int32
mcol = \case
Layout Keyword
kw LayoutStatus
Tentative Int32
col : LayoutContext
cxt | Bool -> (Int32 -> Bool) -> Maybe Int32 -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Int32
col Int32 -> Int32 -> Bool
forall a. Ord a => a -> a -> Bool
<) Maybe Int32
mcol
-> Keyword -> LayoutStatus -> Int32 -> LayoutBlock
Layout Keyword
kw LayoutStatus
Confirmed Int32
col LayoutBlock -> LayoutContext -> LayoutContext
forall a. a -> [a] -> [a]
: Maybe Int32 -> LayoutContext -> LayoutContext
confirmTentativeBlocks (Int32 -> Maybe Int32
forall a. a -> Maybe a
Just Int32
col) LayoutContext
cxt
LayoutContext
cxt -> LayoutContext
cxt