|
|
- module Frontend.Lexer.Wrapper where
-
- import Control.Applicative as App (Applicative (..))
-
- import Data.Word (Word8)
-
- import Data.Int (Int64)
- import qualified Data.Char
- import qualified Data.ByteString.Lazy as ByteString
- import qualified Data.ByteString.Internal as ByteString (w2c)
- import Frontend.Lexer.Tokens (Token)
- import qualified Data.Text as T
- import Frontend.Parser.Posn
-
- type Byte = Word8
- type AlexInput = ( Posn, -- current position,
- Char, -- previous char
- ByteString.ByteString, -- current input string
- Int64) -- bytes consumed so far
-
- ignorePendingBytes :: AlexInput -> AlexInput
- ignorePendingBytes i = i -- no pending bytes when lexing bytestrings
-
- alexInputPrevChar :: AlexInput -> Char
- alexInputPrevChar (_,c,_,_) = c
-
- alexGetByte :: AlexInput -> Maybe (Byte,AlexInput)
- alexGetByte (p,_,cs,n) =
- case ByteString.uncons cs of
- Nothing -> Nothing
- Just (b, cs') ->
- let c = ByteString.w2c b
- p' = alexMove p c
- n' = n+1
- in p' `seq` cs' `seq` n' `seq` Just (b, (p', c, cs',n'))
-
- -- -----------------------------------------------------------------------------
- -- Token positions
-
- -- `Posn' records the location of a token in the input text. It has three
- -- fields: the address (number of chacaters preceding the token), line number
- -- and column of a token within the file. `start_pos' gives the position of the
- -- start of the file and `eof_pos' a standard encoding for the end of file.
- -- `move_pos' calculates the new position after traversing a given character,
- -- assuming the usual eight character tab stops.
-
-
- alexStartPos :: Posn
- alexStartPos = Posn 1 1
-
- alexMove :: Posn -> Char -> Posn
- alexMove (Posn l c) '\t' = Posn l (c+8-((c-1) `mod` 8))
- alexMove (Posn l _) '\n' = Posn (l+1) 1
- alexMove (Posn l c) _ = Posn l (c+1)
-
- data AlexState = AlexState {
- alex_pos :: !Posn, -- position at current input location
-
- alex_bpos:: !Int64, -- bytes consumed so far
- alex_inp :: ByteString.ByteString, -- the current input
- alex_chr :: !Char, -- the character before the input
-
- alex_scd :: !Int -- the current startcode
-
- , alex_ust :: AlexUserState -- AlexUserState will be defined in the user program
- , alex_fname :: String
- }
-
- runAlex :: String -> ByteString.ByteString -> Alex a -> Either ParseError a
- runAlex fname input__ (Alex f) =
- case f initState of
- Left msg -> Left msg
- Right ( _, a ) -> Right a
- where
- initState = AlexState
- { alex_bpos = 0
- , alex_pos = alexStartPos
- , alex_inp = input__
- , alex_chr = '\n'
-
- , alex_ust = alexInitUserState
-
- , alex_scd = 0
- , alex_fname = fname
- }
-
- newtype Alex a = Alex { unAlex :: AlexState -> Either ParseError (AlexState, a) }
-
- instance Functor Alex where
- fmap f a = Alex $ \s -> case unAlex a s of
- Left msg -> Left msg
- Right (s', a') -> Right (s', f a')
-
- instance Applicative Alex where
- pure a = Alex $ \s -> Right (s, a)
- fa <*> a = Alex $ \s -> case unAlex fa s of
- Left msg -> Left msg
- Right (s', f) -> case unAlex a s' of
- Left msg -> Left msg
- Right (s'', b) -> Right (s'', f b)
-
- instance Monad Alex where
- m >>= k = Alex $ \s -> case unAlex m s of
- Left msg -> Left msg
- Right (s',a) -> unAlex (k a) s'
- return = App.pure
-
- alexGetInput :: Alex AlexInput
- alexGetInput =
- Alex $ \s@AlexState{alex_pos=pos,alex_bpos=bpos,alex_chr=c,alex_inp=inp__} ->
- Right (s, (pos,c,inp__,bpos))
-
-
- alexSetInput :: AlexInput -> Alex ()
- alexSetInput (pos,c,inp__,bpos)
- = Alex $ \s -> Right ( s { alex_pos = pos
- , alex_bpos = bpos
- , alex_chr = c
- , alex_inp = inp__
- }
- , ())
-
- alexError :: String -> Alex a
- alexError message = Alex $ \s -> Left (ParseError message (alex_fname s) Nothing (alex_pos s) (alex_pos s))
-
- alexErrorPosn :: Posn -> Posn -> String -> Alex a
- alexErrorPosn start end message = Alex $ \s -> Left (ParseError message (alex_fname s) Nothing start end)
-
- alexThrow :: (String -> ParseError) -> Alex a
- alexThrow err = Alex $ \s -> Left (err (alex_fname s))
-
- alexGetStartCode :: Alex Int
- alexGetStartCode = Alex $ \s@AlexState{alex_scd=sc} -> Right (s, sc)
-
- alexSetStartCode :: Int -> Alex ()
- alexSetStartCode sc = Alex $ \s -> Right (s{alex_scd=sc}, ())
-
- -- -----------------------------------------------------------------------------
- -- Useful token actions
-
- type AlexAction result = AlexInput -> Int64 -> Alex result
-
- -- perform an action for this token, and set the start code to a new value
- andBegin :: AlexAction result -> Int -> AlexAction result
- (action `andBegin` code) input__ len = do
- alexSetStartCode code
- action input__ len
-
- token :: (AlexInput -> Int64 -> token) -> AlexAction token
- token t input__ len = return (t input__ len)
-
- data LayoutState
- = LetLayout { layoutCol :: Int }
- | Layout { layoutCol :: Int }
- | ExplicitLayout
- deriving (Show)
-
- data AlexUserState =
- AlexUserState { layoutColumns :: ![LayoutState]
- , startCodes :: ![Int]
- , leastColumn :: !Int
-
- , pendingLayoutKw :: Maybe (Int -> LayoutState)
- , pendingTokens :: ![Token]
- , pendingLambdaCase :: !Bool
-
- , stringBuffer :: !T.Text
- , stringStartPosn :: Maybe Posn
- }
-
- alexInitUserState :: AlexUserState
- alexInitUserState = AlexUserState [] [] 0 Nothing [] False T.empty Nothing
-
- data ParseError
- = ParseError { parseErrorMessage :: String
- , parseErrorFilename :: String
- , parseErrorInlineDesc :: Maybe String
- , parseErrorBegin :: Posn
- , parseErrorEnd :: Posn
- }
- deriving (Eq, Show)
|