content: {-# LANGUAGE CPP #-}
  
  {-| Utils for various parsers (beyond token level).
  
  We can sometimes work around there being free-form and fixed-form versions of
  the @LexAction@ monad by requesting the underlying instances instances. We place
  such utilities that match that form here.
  
  -}
  module Language.Fortran.Parser.ParserUtils where
  
  import Language.Fortran.AST
  import Language.Fortran.AST.Literal.Real
  import Language.Fortran.AST.Literal.Complex
  import Language.Fortran.Util.Position
  
  #if !MIN_VERSION_base(4,13,0)
  -- Control.Monad.Fail import is redundant since GHC 8.8.1
  import Control.Monad.Fail ( MonadFail )
  #endif
  
  {- $complex-lit-parsing
  
  Parsing complex literal parts unambiguously is a pain, so instead, we parse any
  expression, then case on it to determine if it's valid for a complex literal
  part -- and if so, push it into a 'ComplexPart' constructor. This may cause
  unexpected behaviour if more bracketing/tuple rules are added!
  -}
  
  -- | Try to validate an expression as a COMPLEX literal part.
  --
  -- $complex-lit-parsing
  exprToComplexLitPart :: MonadFail m => Expression a -> m (ComplexPart a)
  exprToComplexLitPart e =
      case e' of
        ExpValue a ss val ->
          case val of
            ValReal    r mkp ->
              let r' = r { realLitSignificand = sign <> realLitSignificand r }
               in return $ ComplexPartReal a ss r' mkp
            ValInteger i mkp -> return $ ComplexPartInt a ss (sign<>i) mkp
            ValVariable var  -> return $ ComplexPartNamed a ss var
            _                -> fail $ "Invalid COMPLEX literal @ " <> show ss
        _ -> fail $ "Invalid COMPLEX literal @ " <> show (getSpan e')
    where
      (sign, e') = case e of ExpUnary _ _ Minus e'' -> ("-", e'')
                             ExpUnary _ _ Plus  e'' -> ("", e'')
                             _                      -> ("", e)
  
  -- | Helper for forming COMPLEX literals.
  complexLit
      :: MonadFail m => SrcSpan -> Expression A0 -> Expression A0
      -> m (Expression A0)
  complexLit ss e1 e2 = do
      compReal <- exprToComplexLitPart e1
      compImag <- exprToComplexLitPart e2
      return $ ExpValue () ss $ ValComplex $ ComplexLit () ss compReal compImag
  