packages feed

peg-matching-0.1.0.0: src/Quote/Base.hs

{-|
Module      : Quote.Base
Description : Base file for QuasiQuoter.
Copyright   : (c) Guilherme Drummond, Rodrigo Ribeiro, 2025
License     : BSD-3-Clause
Maintainer  : rodrigo.ribeiro@ufop.edu.br
Stability   : experimental
Portability : POSIX

This module provides basic functions for QuasiQuoters.
-}
module Quote.Base 
    ( topLevel
    , parseIO
    , location'
    , setPosition
    ) where

import Parser.Base (Parser, sc)
import Text.Megaparsec
    ( parse
    , MonadParsec(eof, updateParserState)
    , SourcePos(..)
    , mkPos
    , PosState (pstateSourcePos)
    , State (statePosState), errorBundlePretty
    )
import Language.Haskell.TH
    (Q, location, Loc(loc_start, loc_filename))
import Control.Exception (throwIO)

{-|
Parses a parser from the beginning of input and requires that the parser
consumes all remaining whitespace and reaches end of file.
-}
topLevel :: Parser a -> Parser a
topLevel p = sc *> p <* eof

{-|
Parse a string using the provided parser and raise an IO exception on parse
failure.
-}
parseIO :: Parser a -> String -> IO a
parseIO p str =
    case parse p "" str of
        Left err -> throwIO (userError (errorBundlePretty err))
        Right a  -> return a

{-|
Return the current Template Haskell source position as a Megaparsec
position, t'Text.Megaparsec.SourcePos'.
-}
location' :: Q SourcePos
location' = aux <$> location
    where
        aux :: Loc -> SourcePos
        aux loc =
            let (line, col) = loc_start loc
            in SourcePos 
            {   sourceName = loc_filename loc
            ,   sourceLine = mkPos line
            ,   sourceColumn = mkPos col 
            }

{-|
Set the parser state position to the given t'Text.Megaparsec.SourcePos'.
-}
setPosition :: SourcePos -> Parser ()
setPosition pos = updateParserState $ \state ->
    let pst = statePosState state
        pst' = pst { pstateSourcePos = pos }
    in state { statePosState = pst' }