never executed always true always false
    1 {-# LANGUAGE OverloadedStrings #-}
    2 
    3 -- |
    4 -- Module      : Aihc.Parser
    5 -- Description : Haskell parser for the AIHC compiler
    6 -- License     : Unlicense
    7 --
    8 -- This module provides parsing functions for Haskell source code.
    9 -- The main entry point is 'parseModule' for parsing complete Haskell modules.
   10 -- Additional functions are provided for parsing individual expressions,
   11 -- patterns, and types.
   12 module Aihc.Parser
   13   ( -- * Parsing modules
   14     parseModule,
   15 
   16     -- * Configuration
   17     ParserConfig (..),
   18     defaultConfig,
   19 
   20     -- * Parse results
   21     ParseResult (..),
   22     ParseErrorBundle,
   23     errorBundlePretty,
   24 
   25     -- * Parsing expressions, patterns, and types
   26     parseExpr,
   27     parseType,
   28     parsePattern,
   29   )
   30 where
   31 
   32 import Aihc.Parser.Internal.Expr (exprParser, patternParser, typeParser)
   33 import Aihc.Parser.Internal.Module (moduleParser)
   34 import Aihc.Parser.Lex
   35   ( lexModuleTokensWithExtensions,
   36     lexTokensWithExtensions,
   37     readModuleHeaderExtensions,
   38   )
   39 import Aihc.Parser.Pretty ()
   40 import Aihc.Parser.Syntax (Expr, Extension (..), ExtensionSetting (..), Module, Pattern, Type)
   41 import Aihc.Parser.Types
   42 import Data.List qualified as List
   43 import Data.Text (Text)
   44 import Text.Megaparsec (runParser)
   45 import Text.Megaparsec qualified as MP
   46 
   47 -- $setup
   48 -- >>> :set -XOverloadedStrings
   49 -- >>> import Aihc.Parser
   50 -- >>> import Aihc.Parser.Syntax (moduleName)
   51 -- >>> import Aihc.Parser.Shorthand (Shorthand(..))
   52 
   53 -- | Default parser configuration.
   54 --
   55 -- * 'parserSourceName' is set to @\"\<input\>\"@
   56 -- * 'parserExtensions' is empty (no extensions enabled by default)
   57 --
   58 -- >>> parserSourceName defaultConfig
   59 -- "<input>"
   60 --
   61 -- >>> parserExtensions defaultConfig
   62 -- []
   63 defaultConfig :: ParserConfig
   64 defaultConfig =
   65   ParserConfig
   66     { parserSourceName = "<input>",
   67       parserExtensions = []
   68     }
   69 
   70 -- | Parse a Haskell expression.
   71 --
   72 -- >>> shorthand $ parseExpr defaultConfig "1 + 2"
   73 -- ParseOk (EInfix (EInt 1) "+" (EInt 2))
   74 --
   75 -- >>> shorthand $ parseExpr defaultConfig "\\x -> x + 1"
   76 -- ParseOk (ELambdaPats [PVar "x"] (EInfix (EVar "x") "+" (EInt 1)))
   77 --
   78 -- Parse errors are returned as 'ParseErr':
   79 --
   80 -- >>> case parseExpr defaultConfig "1 +" of { ParseErr _ -> "error"; ParseOk _ -> "ok" }
   81 -- "error"
   82 parseExpr :: ParserConfig -> Text -> ParseResult Expr
   83 parseExpr cfg input =
   84   let toks = lexTokensWithExtensions (parserExtensions cfg) input
   85    in case runParser (exprParser <* MP.eof) (parserSourceName cfg) (TokStream toks) of
   86         Left bundle -> ParseErr bundle
   87         Right expr -> ParseOk expr
   88 
   89 -- | Parse a Haskell pattern.
   90 --
   91 -- >>> shorthand $ parsePattern defaultConfig "(x, y)"
   92 -- ParseOk (PTuple [PVar "x", PVar "y"])
   93 --
   94 -- >>> shorthand $ parsePattern defaultConfig "Just x"
   95 -- ParseOk (PCon "Just" [PVar "x"])
   96 parsePattern :: ParserConfig -> Text -> ParseResult Pattern
   97 parsePattern cfg input =
   98   let toks = lexTokensWithExtensions (parserExtensions cfg) input
   99    in case runParser (patternParser <* MP.eof) (parserSourceName cfg) (TokStream toks) of
  100         Left bundle -> ParseErr bundle
  101         Right pat -> ParseOk pat
  102 
  103 -- | Parse a Haskell type.
  104 --
  105 -- >>> shorthand $ parseType defaultConfig "Int -> Bool"
  106 -- ParseOk (TFun (TCon "Int") (TCon "Bool"))
  107 --
  108 -- >>> shorthand $ parseType defaultConfig "Maybe a"
  109 -- ParseOk (TApp (TCon "Maybe") (TVar "a"))
  110 parseType :: ParserConfig -> Text -> ParseResult Type
  111 parseType cfg input =
  112   let toks = lexTokensWithExtensions (parserExtensions cfg) input
  113    in case runParser (typeParser <* MP.eof) (parserSourceName cfg) (TokStream toks) of
  114         Left bundle -> ParseErr bundle
  115         Right ty -> ParseOk ty
  116 
  117 -- | Parse a complete Haskell module.
  118 --
  119 -- >>> shorthand $ parseModule defaultConfig "module Main where\nmain = putStrLn \"Hello\""
  120 -- ParseOk (Module {name = "Main", decls = [DeclValue (FunctionBind "main" [Match {rhs = UnguardedRhs (EApp (EVar "putStrLn") (EString "Hello"))}])]})
  121 --
  122 -- Modules without a header are also supported:
  123 --
  124 -- >>> case parseModule defaultConfig "x = 1" of { ParseOk m -> moduleName m; ParseErr _ -> Just "error" }
  125 -- Nothing
  126 parseModule :: ParserConfig -> Text -> ParseResult Module
  127 parseModule cfg input =
  128   let toks = lexModuleTokensWithExtensions effectiveExtensions input
  129    in case runParser (moduleParser <* MP.eof) (parserSourceName cfg) (TokStream toks) of
  130         Left bundle -> ParseErr bundle
  131         Right modu -> ParseOk modu
  132   where
  133     effectiveExtensions =
  134       applyExtensionSettings
  135         (parserExtensions cfg)
  136         (readModuleHeaderExtensions input)
  137 
  138 applyExtensionSettings :: [Extension] -> [ExtensionSetting] -> [Extension]
  139 applyExtensionSettings = List.foldl' applySetting
  140   where
  141     applySetting exts setting =
  142       case setting of
  143         EnableExtension ext
  144           | ext `elem` exts -> exts
  145           | otherwise -> exts <> [ext]
  146         DisableExtension ext -> filter (/= ext) exts
  147 
  148 -- | Pretty-print a parse error bundle.
  149 errorBundlePretty :: ParseErrorBundle -> String
  150 errorBundlePretty = MP.errorBundlePretty