{-# LANGUAGE CPP #-}

{-# OPTIONS_GHC -Wunused-imports #-}

{-| This module contains the building blocks used to construct the lexer.
-}
module Mikan.Syntax.Parser.LexActions
    ( -- * Main function
      lexToken
      -- * Lex actions
      -- ** General actions
    , token
    , withInterval, withInterval', withInterval_
    , withLayout
    , andThen, skip
    , begin, end, beginWith, endWith
    , begin_, end_
    , lexError
      -- ** Specialized actions
    , keyword, symbol, qualifiedToken, literal, literal', integer
      -- * Lex predicates
    , followedBy, eof, inState
    ) where

import Control.Monad.State (modify)

import Data.Bifunctor
import Data.Char
#if !MIN_VERSION_base(4,20,0)
import Data.Foldable (foldl')
#endif

import Data.Text (Text)
import Data.Text qualified as T

import Mikan.Syntax.Common (pattern Ranged)
import Mikan.Syntax.Parser.Lexer
import Mikan.Syntax.Parser.Alex
import Mikan.Syntax.Parser.Monad
import Mikan.Syntax.Parser.Tokens
import Mikan.Syntax.Position
import Mikan.Syntax.Literal

import Mikan.Utils.List

import Mikan.Utils.Impossible

{--------------------------------------------------------------------------
    Scan functions
 --------------------------------------------------------------------------}

-- | Called at the end of a file. Returns 'TokEOF'.
returnEOF :: AlexInput -> Parser Token
returnEOF :: AlexInput -> Parser Token
returnEOF AlexInput{ SrcFile
lexSrcFile :: SrcFile
lexSrcFile :: AlexInput -> SrcFile
lexSrcFile, PositionWithoutFile
lexPos :: PositionWithoutFile
lexPos :: AlexInput -> PositionWithoutFile
lexPos } = do
  -- Andreas, 2018-12-30, issue #3480
  -- The following setLastPos leads to parse error reporting
  -- far away from the interesting position, in particular
  -- if there is a long comment before the EOF.
  -- (Such a long comment is frequent in interactive programming, as
  -- commenting out until the end of the file is a common habit.)
  -- -- setLastPos lexPos
  -- Without it, we get much more useful error locations.
  Text -> Parser ()
setPrevToken Text
"<EOF>"
  Token -> Parser Token
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ Interval -> Token
TokEOF (Interval -> Token) -> Interval -> Token
forall a b. (a -> b) -> a -> b
$ SrcFile -> PositionWithoutFile -> PositionWithoutFile -> Interval
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
posToInterval SrcFile
lexSrcFile PositionWithoutFile
lexPos PositionWithoutFile
lexPos

-- | Set the current input and lex a new token (calls 'lexToken').
skipTo :: AlexInput -> Parser Token
skipTo :: AlexInput -> Parser Token
skipTo AlexInput
inp = do
  AlexInput -> Parser ()
setLexInput AlexInput
inp
  Parser Token
lexToken

{-| Scan the input to find the next token. Calls
'Agda.Syntax.Parser.Lexer.alexScanUser'. This is the main lexing function
where all the work happens. The function 'Agda.Syntax.Parser.Lexer.lexer',
used by the parser is the continuation version of this function.
-}
lexToken :: Parser Token
lexToken :: Parser Token
lexToken =
    do  inp <- Parser AlexInput
getLexInput
        lss <- getLexState
        flags <- getParseFlags
        case alexScanUser (lss, flags) inp (headWithDefault __IMPOSSIBLE__ lss) of
            AlexReturn (LexAction Token)
AlexEOF                     -> AlexInput -> Parser Token
returnEOF AlexInput
inp
            AlexSkip AlexInput
inp' LexState
len           -> AlexInput -> Parser Token
skipTo AlexInput
inp'
            AlexToken AlexInput
inp' LexState
len LexAction Token
action   -> Token -> Token
postToken (Token -> Token) -> Parser Token -> Parser Token
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> LexAction Token
-> AlexInput -> AlexInput -> LexState -> Parser Token
forall r.
LexAction r -> AlexInput -> AlexInput -> LexState -> Parser r
runLexAction LexAction Token
action AlexInput
inp AlexInput
inp' LexState
len
            AlexError AlexInput
i                 -> [Char] -> Parser Token
forall a. [Char] -> Parser a
parseError ([Char] -> Parser Token) -> [Char] -> Parser Token
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
              [ [Char]
"Lexical error"
              , case Text -> Maybe (Char, Text)
T.uncons (Text -> Maybe (Char, Text)) -> Text -> Maybe (Char, Text)
forall a b. (a -> b) -> a -> b
$ AlexInput -> Text
lexInput AlexInput
i of
                  Just (Char
'\t', Text
_)                -> [Char]
" (you may want to replace tabs with spaces)"
                  Just (Char
c, Text
_) | Bool -> Bool
not (Char -> Bool
isPrint Char
c) -> [Char]
" (unprintable character)"
                  Maybe (Char, Text)
_ -> [Char]
""
              , [Char]
":"
              ]

isSub :: Char -> Bool
isSub :: Char -> Bool
isSub Char
c = Char
'\x2080' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x2089'

readSubscript :: [Char] -> Integer
readSubscript :: [Char] -> Integer
readSubscript = [Char] -> Integer
forall a. Read a => [Char] -> a
read ([Char] -> Integer) -> ([Char] -> [Char]) -> [Char] -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map (\Char
c -> LexState -> Char
forall a. Enum a => LexState -> a
toEnum (Char -> LexState
forall a. Enum a => a -> LexState
fromEnum Char
c LexState -> LexState -> LexState
forall a. Num a => a -> a -> a
- LexState
0x2080 LexState -> LexState -> LexState
forall a. Num a => a -> a -> a
+ Char -> LexState
forall a. Enum a => a -> LexState
fromEnum Char
'0'))

postToken :: Token -> Token
postToken :: Token -> Token
postToken (TokId (Interval
r, Text
"\x03bb")) = Symbol -> Interval -> Token
TokSymbol Symbol
SymLambda Interval
r
postToken (TokId (Interval
r, Text
"\x2026")) = Symbol -> Interval -> Token
TokSymbol Symbol
SymEllipsis Interval
r
postToken (TokId (Interval
r, Text
"\x2192")) = Symbol -> Interval -> Token
TokSymbol Symbol
SymArrow Interval
r
postToken (TokId (Interval
r, Text
"\x2983")) = Symbol -> Interval -> Token
TokSymbol (Bool -> Symbol
SymDoubleOpenBrace Bool
True) Interval
r
postToken (TokId (Interval
r, Text
"\x2984")) = Symbol -> Interval -> Token
TokSymbol (Bool -> Symbol
SymDoubleCloseBrace Bool
True) Interval
r
postToken (TokId (Interval
r, Text
"\x2987")) = Symbol -> Interval -> Token
TokSymbol (Bool -> Symbol
SymOpenIdiomBracket Bool
True) Interval
r
postToken (TokId (Interval
r, Text
"\x2988")) = Symbol -> Interval -> Token
TokSymbol (Bool -> Symbol
SymCloseIdiomBracket Bool
True) Interval
r
postToken (TokId (Interval
r, Text
"\x2987\x2988")) = Symbol -> Interval -> Token
TokSymbol Symbol
SymEmptyIdiomBracket Interval
r
postToken (TokId (Interval
r, Text
"\x2200")) = Keyword -> Interval -> Token
TokKeyword Keyword
KwForall Interval
r
postToken Token
t = Token
t

{--------------------------------------------------------------------------
    Lex actions
 --------------------------------------------------------------------------}

-- | The most general way of parsing a token.
token :: (Text -> Parser tok) -> LexAction tok
token :: forall tok. (Text -> Parser tok) -> LexAction tok
token Text -> Parser tok
action = (AlexInput -> AlexInput -> LexState -> Parser tok) -> LexAction tok
forall r.
(AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r
LexAction ((AlexInput -> AlexInput -> LexState -> Parser tok)
 -> LexAction tok)
-> (AlexInput -> AlexInput -> LexState -> Parser tok)
-> LexAction tok
forall a b. (a -> b) -> a -> b
$ \ AlexInput
inp AlexInput
inp' LexState
len ->
    do  AlexInput -> Parser ()
setLexInput AlexInput
inp'
        let t :: Text
t = LexState -> Text -> Text
T.take LexState
len (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ AlexInput -> Text
lexInput AlexInput
inp
        Text -> Parser ()
setPrevToken Text
t
        PositionWithoutFile -> Parser ()
setLastPos (PositionWithoutFile -> Parser ())
-> PositionWithoutFile -> Parser ()
forall a b. (a -> b) -> a -> b
$ AlexInput -> PositionWithoutFile
lexPos AlexInput
inp
        Text -> Parser tok
action Text
t

-- | Parse a token from an 'Interval' and the lexed string.
withInterval :: ((Interval, Text) -> tok) -> LexAction tok
withInterval :: forall tok. ((Interval, Text) -> tok) -> LexAction tok
withInterval (Interval, Text) -> tok
f = (Text -> Parser tok) -> LexAction tok
forall tok. (Text -> Parser tok) -> LexAction tok
token ((Text -> Parser tok) -> LexAction tok)
-> (Text -> Parser tok) -> LexAction tok
forall a b. (a -> b) -> a -> b
$ \Text
s -> do
                   r <- Parser Interval
getParseInterval
                   return $ f (r,s)

-- | Like 'withInterval', but applies a function to the string.
withInterval' :: (Text -> a) -> ((Interval, a) -> tok) -> LexAction tok
withInterval' :: forall a tok.
(Text -> a) -> ((Interval, a) -> tok) -> LexAction tok
withInterval' Text -> a
f (Interval, a) -> tok
t = ((Interval, Text) -> tok) -> LexAction tok
forall tok. ((Interval, Text) -> tok) -> LexAction tok
withInterval ((Interval, a) -> tok
t ((Interval, a) -> tok)
-> ((Interval, Text) -> (Interval, a)) -> (Interval, Text) -> tok
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> a) -> (Interval, Text) -> (Interval, a)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Text -> a
f)

-- | Return a token without looking at the lexed string.
withInterval_ :: (Interval -> r) -> LexAction r
withInterval_ :: forall r. (Interval -> r) -> LexAction r
withInterval_ Interval -> r
f = ((Interval, Text) -> r) -> LexAction r
forall tok. ((Interval, Text) -> tok) -> LexAction tok
withInterval (Interval -> r
f (Interval -> r)
-> ((Interval, Text) -> Interval) -> (Interval, Text) -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Interval, Text) -> Interval
forall a b. (a, b) -> a
fst)

-- | Enter the layout state for the given keyword.
enterLayout :: Keyword -> Parser ()
enterLayout :: Keyword -> Parser ()
enterLayout Keyword
kw = do
  LexState -> Parser ()
pushLexState LexState
layout
  (ParseState -> ParseState) -> Parser ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify \ParseState
st -> ParseState
st { parseLayKw = kw }

-- | Executed for layout keywords. Enters the 'Agda.Syntax.Parser.Lexer.layout'
--   state and performs the given action.
withLayout :: Keyword -> LexAction r -> LexAction r
withLayout :: forall r. Keyword -> LexAction r -> LexAction r
withLayout Keyword
kw LexAction r
a = Keyword -> Parser ()
enterLayout Keyword
kw Parser () -> LexAction r -> LexAction r
forall r. Parser () -> LexAction r -> LexAction r
`andThen` LexAction r
a

infixr 1 `andThen`

-- | Prepend some parser manipulation to an action.
andThen :: Parser () -> LexAction r -> LexAction r
andThen :: forall r. Parser () -> LexAction r -> LexAction r
andThen Parser ()
cmd LexAction r
a = (AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r
forall r.
(AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r
LexAction ((AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r)
-> (AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r
forall a b. (a -> b) -> a -> b
$ \ AlexInput
inp AlexInput
inp' LexState
n -> do
  Parser ()
cmd
  LexAction r -> AlexInput -> AlexInput -> LexState -> Parser r
forall r.
LexAction r -> AlexInput -> AlexInput -> LexState -> Parser r
runLexAction LexAction r
a AlexInput
inp AlexInput
inp' LexState
n

-- | Visit the current lexeme again.
revisit :: LexAction Token
revisit :: LexAction Token
revisit = (AlexInput -> AlexInput -> LexState -> Parser Token)
-> LexAction Token
forall r.
(AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r
LexAction ((AlexInput -> AlexInput -> LexState -> Parser Token)
 -> LexAction Token)
-> (AlexInput -> AlexInput -> LexState -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ AlexInput
_ AlexInput
_ LexState
_ -> Parser Token
lexToken

-- | Throw away the current lexeme.
skip :: LexAction Token
skip :: LexAction Token
skip = (AlexInput -> AlexInput -> LexState -> Parser Token)
-> LexAction Token
forall r.
(AlexInput -> AlexInput -> LexState -> Parser r) -> LexAction r
LexAction ((AlexInput -> AlexInput -> LexState -> Parser Token)
 -> LexAction Token)
-> (AlexInput -> AlexInput -> LexState -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ AlexInput
_ AlexInput
inp' LexState
_ -> AlexInput -> Parser Token
skipTo AlexInput
inp'

-- | Enter a new state without consuming any input.
begin :: LexState -> LexAction Token
begin :: LexState -> LexAction Token
begin LexState
code = LexState -> LexAction Token -> LexAction Token
forall a. LexState -> LexAction a -> LexAction a
beginWith LexState
code LexAction Token
revisit

-- | Exit the current state without consuming any input.
end :: LexAction Token
end :: LexAction Token
end = LexAction Token -> LexAction Token
forall a. LexAction a -> LexAction a
endWith LexAction Token
revisit

-- | Enter a new state throwing away the current lexeme.
begin_ :: LexState -> LexAction Token
begin_ :: LexState -> LexAction Token
begin_ LexState
code = LexState -> LexAction Token -> LexAction Token
forall a. LexState -> LexAction a -> LexAction a
beginWith LexState
code LexAction Token
skip

-- | Exit the current state throwing away the current lexeme.
end_ :: LexAction Token
end_ :: LexAction Token
end_ = LexAction Token -> LexAction Token
forall a. LexAction a -> LexAction a
endWith LexAction Token
skip

-- | Enter a new state and perform the given action.
beginWith :: LexState -> LexAction a -> LexAction a
beginWith :: forall a. LexState -> LexAction a -> LexAction a
beginWith LexState
code LexAction a
a = LexState -> Parser ()
pushLexState LexState
code Parser () -> LexAction a -> LexAction a
forall r. Parser () -> LexAction r -> LexAction r
`andThen` LexAction a
a

-- | Exit the current state and perform the given action.
endWith :: LexAction a -> LexAction a
endWith :: forall a. LexAction a -> LexAction a
endWith LexAction a
a = Parser ()
popLexState Parser () -> LexAction a -> LexAction a
forall r. Parser () -> LexAction r -> LexAction r
`andThen` LexAction a
a


-- | Parse a 'Keyword' token, triggers layout for 'layoutKeywords'.
keyword :: Keyword -> LexAction Token
keyword :: Keyword -> LexAction Token
keyword Keyword
k =
    case Keyword
k of

        -- Unconditional layout keyword.
        Keyword
_ | Keyword
k Keyword -> [Keyword] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Keyword]
layoutKeywords ->
            Keyword -> LexAction Token -> LexAction Token
forall r. Keyword -> LexAction r -> LexAction r
withLayout Keyword
k LexAction Token
cont

        -- Andreas, 2021-05-06, issue #5356:
        -- @constructor@ is not a layout keyword after all, replaced by @data _ where@.
        -- -- @constructor@ is not a layout keyword in @record ... where@ blocks,
        -- -- only in @interleaved mutual@ blocks.
        -- KwConstructor -> do
        --     cxt <- getContext
        --     if inMutualAndNotInWhereBlock cxt
        --       then withLayout k cont
        --       else cont

        Keyword
_ -> LexAction Token
cont
    where
    cont :: LexAction Token
cont = (Interval -> Token) -> LexAction Token
forall r. (Interval -> r) -> LexAction r
withInterval_ (Keyword -> Interval -> Token
TokKeyword Keyword
k)

    -- Andreas, 2021-05-06, issue #5356:
    -- @constructor@ is not a layout keyword after all, replaced by @data _ where@.
    -- -- Most recent block decides ...
    -- inMutualAndNotInWhereBlock = \case
    --   Layout KwMutual _ _ : _ -> True
    --   Layout KwWhere  _ _ : _ -> False
    --   _ : bs                  -> inMutualAndNotInWhereBlock bs
    --   []                      -> True  -- For better errors on stray @constructor@ decls.


-- | Parse a 'Symbol' token.
symbol :: Symbol -> LexAction Token
symbol :: Symbol -> LexAction Token
symbol Symbol
s = (Interval -> Token) -> LexAction Token
forall r. (Interval -> r) -> LexAction r
withInterval_ (Symbol -> Interval -> Token
TokSymbol Symbol
s)


-- | Parse a number.
number :: Text -> Integer
number :: Text -> Integer
number Text
str
  | Just Text
num <- Text -> Text -> Maybe Text
T.stripPrefix Text
"0x" Text
str = Integer -> Text -> Integer
parseNumber Integer
16 Text
num
  | Just Text
num <- Text -> Text -> Maybe Text
T.stripPrefix Text
"0b" Text
str = Integer -> Text -> Integer
parseNumber Integer
2 Text
num
  | Bool
otherwise = Integer -> Text -> Integer
parseNumber Integer
10 Text
str
    where
      parseNumber :: Integer -> Text -> Integer
      parseNumber :: Integer -> Text -> Integer
parseNumber Integer
radix = (Integer -> Char -> Integer) -> Integer -> Text -> Integer
forall a. (a -> Char -> a) -> a -> Text -> a
T.foldl' (Integer -> Integer -> Char -> Integer
addDigit Integer
radix) Integer
0

        -- We rely on Agda.Syntax.Parser.Lexer to enforce that the digits are
        -- in the correct range (so e.g. the digit 'E' cannot appear in a
        -- binary number).
      addDigit :: Integer -> Integer -> Char -> Integer
      addDigit :: Integer -> Integer -> Char -> Integer
addDigit Integer
radix Integer
n Char
'_' = Integer
n
      addDigit Integer
radix Integer
n Char
c   = Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
radix Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ LexState -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> LexState
digitToInt Char
c)

integer :: Text -> Integer
integer :: Text -> Integer
integer Text
t =
  case Text -> Maybe (Char, Text)
T.uncons Text
t of
    Just (Char
'-', Text
t) -> - (Text -> Integer
number Text
t)
    Maybe (Char, Text)
_             -> Text -> Integer
number Text
t

-- | Parse a literal.
literal' :: (Text -> a) -> (a -> Literal) -> LexAction Token
literal' :: forall a. (Text -> a) -> (a -> Literal) -> LexAction Token
literal' Text -> a
read a -> Literal
lit = (Text -> a) -> ((Interval, a) -> Token) -> LexAction Token
forall a tok.
(Text -> a) -> ((Interval, a) -> tok) -> LexAction tok
withInterval' Text -> a
read (((Interval, a) -> Token) -> LexAction Token)
-> ((Interval, a) -> Token) -> LexAction Token
forall a b. (a -> b) -> a -> b
$ \ (Interval
r, a
a) ->
  RLiteral -> Token
TokLiteral (RLiteral -> Token) -> RLiteral -> Token
forall a b. (a -> b) -> a -> b
$ Range -> Literal -> RLiteral
forall a. Range -> a -> Ranged a
Ranged (Interval -> Range
forall a. HasRange a => a -> Range
getRange Interval
r) (Literal -> RLiteral) -> Literal -> RLiteral
forall a b. (a -> b) -> a -> b
$ a -> Literal
lit a
a

literal :: Read a => (a -> Literal) -> LexAction Token
literal :: forall a. Read a => (a -> Literal) -> LexAction Token
literal = (Text -> a) -> (a -> Literal) -> LexAction Token
forall a. (Text -> a) -> (a -> Literal) -> LexAction Token
literal' ([Char] -> a
forall a. Read a => [Char] -> a
read ([Char] -> a) -> (Text -> [Char]) -> Text -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack)

-- | Parse a potentially-qualified token. This action is responsible for
-- lexing both identifiers (which do not always have a qualifier, in
-- which case a 'TokId' is returned) *and* "qualified keywords", like
-- qualified @do@.
--
-- This action may thus modify the layout state of the parser, since
-- qualified @do@ is a layout "keyword".
--
-- Examples: @Foo.Bar.f@, @Foo.do@.
qualifiedToken :: LexAction Token
qualifiedToken :: LexAction Token
qualifiedToken = (Either (Interval, Text) [(Interval, Text)] -> Parser Token)
-> LexAction Token
forall a.
(Either (Interval, Text) [(Interval, Text)] -> Parser a)
-> LexAction a
qualified ((Either (Interval, Text) [(Interval, Text)] -> Parser Token)
 -> LexAction Token)
-> (Either (Interval, Text) [(Interval, Text)] -> Parser Token)
-> LexAction Token
forall a b. (a -> b) -> a -> b
$ ((Interval, Text) -> Parser Token)
-> ([(Interval, Text)] -> Parser Token)
-> Either (Interval, Text) [(Interval, Text)]
-> Parser Token
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Token -> Parser Token
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Parser Token)
-> ((Interval, Text) -> Token) -> (Interval, Text) -> Parser Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Interval, Text) -> Token
TokId) [(Interval, Text)] -> Parser Token
qid where
  qid :: [(Interval, Text)] -> Parser Token
  qid :: [(Interval, Text)] -> Parser Token
qid [(Interval, Text)]
parts = case [(Interval, Text)] -> Maybe ([(Interval, Text)], (Interval, Text))
forall a. [a] -> Maybe ([a], a)
initLast [(Interval, Text)]
parts of
    -- For qualified 'do', we have to pretend to be a layout keyword
    Just ([(Interval, Text)]
initp, (Interval
i, Text
"do")) ->
      QualifiableToken -> [(Interval, Text)] -> Interval -> Token
TokQual QualifiableToken
QualDo [(Interval, Text)]
initp Interval
i Token -> Parser () -> Parser Token
forall a b. a -> Parser b -> Parser a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Keyword -> Parser ()
enterLayout Keyword
KwDo

    Just ([(Interval, Text)]
initp, (Interval
i, Text
"(|)"))          -> Token -> Parser Token
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ QualifiableToken -> [(Interval, Text)] -> Interval -> Token
TokQual QualifiableToken
QualEmptyIdiom [(Interval, Text)]
initp Interval
i
    Just ([(Interval, Text)]
initp, (Interval
i, Text
"\x2987\x2988")) -> Token -> Parser Token
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ QualifiableToken -> [(Interval, Text)] -> Interval -> Token
TokQual QualifiableToken
QualEmptyIdiom [(Interval, Text)]
initp Interval
i

    Just ([(Interval, Text)]
initp, (Interval
i, Text
"(|"))           -> Token -> Parser Token
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ QualifiableToken -> [(Interval, Text)] -> Interval -> Token
TokQual (Bool -> QualifiableToken
QualOpenIdiom Bool
False) [(Interval, Text)]
initp Interval
i
    Just ([(Interval, Text)]
initp, (Interval
i, Text
"\x2987"))       -> Token -> Parser Token
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ QualifiableToken -> [(Interval, Text)] -> Interval -> Token
TokQual (Bool -> QualifiableToken
QualOpenIdiom Bool
True) [(Interval, Text)]
initp Interval
i

    Maybe ([(Interval, Text)], (Interval, Text))
_                                 -> Token -> Parser Token
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token -> Parser Token) -> Token -> Parser Token
forall a b. (a -> b) -> a -> b
$ [(Interval, Text)] -> Token
TokQId [(Interval, Text)]
parts

-- | Parse a possibly qualified name.
qualified :: (Either (Interval, Text) [(Interval, Text)] -> Parser a) -> LexAction a
qualified :: forall a.
(Either (Interval, Text) [(Interval, Text)] -> Parser a)
-> LexAction a
qualified Either (Interval, Text) [(Interval, Text)] -> Parser a
tok =
    (Text -> Parser a) -> LexAction a
forall tok. (Text -> Parser tok) -> LexAction tok
token ((Text -> Parser a) -> LexAction a)
-> (Text -> Parser a) -> LexAction a
forall a b. (a -> b) -> a -> b
$ \Text
s ->
    do  i <- Parser Interval
getParseInterval
        case mkName i $ T.splitOn "." s of
            []  -> [Char] -> Parser a
forall a. [Char] -> Parser a
lexError [Char]
"lex error on .."
            [(Interval, Text)
x] -> Either (Interval, Text) [(Interval, Text)] -> Parser a
tok (Either (Interval, Text) [(Interval, Text)] -> Parser a)
-> Either (Interval, Text) [(Interval, Text)] -> Parser a
forall a b. (a -> b) -> a -> b
$ (Interval, Text) -> Either (Interval, Text) [(Interval, Text)]
forall a b. a -> Either a b
Left  (Interval, Text)
x
            [(Interval, Text)]
xs  -> Either (Interval, Text) [(Interval, Text)] -> Parser a
tok (Either (Interval, Text) [(Interval, Text)] -> Parser a)
-> Either (Interval, Text) [(Interval, Text)] -> Parser a
forall a b. (a -> b) -> a -> b
$ [(Interval, Text)] -> Either (Interval, Text) [(Interval, Text)]
forall a b. b -> Either a b
Right [(Interval, Text)]
xs
    where
        -- Compute the ranges for the substrings (separated by '.') of
        -- a name. Dots are included: the intervals generated for
        -- "A.B.x" correspond to "A.", "B." and "x".
        mkName :: Interval -> [Text] -> [(Interval, Text)]
        mkName :: Interval -> [Text] -> [(Interval, Text)]
mkName Interval
_ []     = []
        mkName Interval
i [Text
x]    = [(Interval
i, Text
x)]
        mkName (Interval SrcFile
f PositionWithoutFile
p0 PositionWithoutFile
p1) (Text
x:[Text]
xs) = (Interval
i0, Text
x) (Interval, Text) -> [(Interval, Text)] -> [(Interval, Text)]
forall a. a -> [a] -> [a]
: Interval -> [Text] -> [(Interval, Text)]
mkName Interval
i1 [Text]
xs
            where
                p' :: PositionWithoutFile
p' = PositionWithoutFile -> Char -> PositionWithoutFile
forall a. Position' a -> Char -> Position' a
movePos (PositionWithoutFile -> Text -> PositionWithoutFile
forall a. Position' a -> Text -> Position' a
movePosByString PositionWithoutFile
p0 Text
x) Char
'.'
                i0 :: Interval
i0 = SrcFile -> PositionWithoutFile -> PositionWithoutFile -> Interval
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
Interval SrcFile
f PositionWithoutFile
p0 PositionWithoutFile
p'
                i1 :: Interval
i1 = SrcFile -> PositionWithoutFile -> PositionWithoutFile -> Interval
forall a.
a -> PositionWithoutFile -> PositionWithoutFile -> Interval' a
Interval SrcFile
f PositionWithoutFile
p' PositionWithoutFile
p1


{--------------------------------------------------------------------------
    Predicates
 --------------------------------------------------------------------------}

-- | True when the given character is the next character of the input string.
followedBy :: Char -> LexPredicate
followedBy :: Char -> LexPredicate
followedBy Char
c' ([LexState], ParseFlags)
_ AlexInput
_ LexState
_ AlexInput
inp =
    case Text -> Maybe (Char, Text)
T.uncons (AlexInput -> Text
lexInput AlexInput
inp) of
        Maybe (Char, Text)
Nothing  -> Bool
False
        Just (Char
c, Text
_) -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c'

-- | True if we are at the end of the file.
eof :: LexPredicate
eof :: LexPredicate
eof ([LexState], ParseFlags)
_ AlexInput
_ LexState
_ AlexInput
inp = Text -> Bool
T.null (Text -> Bool) -> Text -> Bool
forall a b. (a -> b) -> a -> b
$ AlexInput -> Text
lexInput AlexInput
inp

-- | True if the given state appears somewhere on the state stack
inState :: LexState -> LexPredicate
inState :: LexState -> LexPredicate
inState LexState
s ([LexState]
ls, ParseFlags
_) AlexInput
_ LexState
_ AlexInput
_ = LexState
s LexState -> [LexState] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [LexState]
ls