{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}

-- |
-- Module      : Jikka.CPlusPlus.Convert.OptimizeRange
-- Description : reduces about @range@ function. / @range@ 関数について簡約します。
-- Copyright   : (c) Kimiyuki Onaka, 2020
-- License     : Apache License 2.0
-- Maintainer  : kimiyuki95@gmail.com
-- Stability   : experimental
-- Portability : portable
module Jikka.CPlusPlus.Convert.OptimizeRange
  ( run,
  )
where

import Jikka.CPlusPlus.Language.Expr
import Jikka.CPlusPlus.Language.Util
import Jikka.Common.Alpha
import Jikka.Common.Error
import Jikka.Common.Name

runExpr :: Monad m => Expr -> m Expr
runExpr :: Expr -> m Expr
runExpr = \case
  Call' Function
At [Call' Function
Range [Expr
_], Expr
i] -> Expr -> m Expr
forall (m :: * -> *) a. Monad m => a -> m a
return Expr
i
  Call' Function
MethodSize [Call' Function
Range [Expr
n]] -> Expr -> m Expr
forall (m :: * -> *) a. Monad m => a -> m a
return Expr
n
  Expr
e -> Expr -> m Expr
forall (m :: * -> *) a. Monad m => a -> m a
return Expr
e

runStatement :: MonadAlpha m => Statement -> m Statement
runStatement :: Statement -> m Statement
runStatement = \case
  ForEach Type
_ VarName
x (Call' Function
Range [Expr
n]) [Statement]
body -> do
    VarName
y <- NameHint -> VarName -> m VarName
forall (m :: * -> *).
MonadAlpha m =>
NameHint -> VarName -> m VarName
renameVarName NameHint
LoopCounterNameHint VarName
x
    let body' :: [Statement]
body' = (Statement -> Statement) -> [Statement] -> [Statement]
forall a b. (a -> b) -> [a] -> [b]
map (VarName -> VarName -> Statement -> Statement
renameVarNameStatement VarName
x VarName
y) [Statement]
body
    Statement -> m Statement
forall (m :: * -> *) a. Monad m => a -> m a
return (Statement -> m Statement) -> Statement -> m Statement
forall a b. (a -> b) -> a -> b
$ VarName -> Expr -> [Statement] -> Statement
repStatement VarName
y Expr
n [Statement]
body' -- TODO: check n is not updated in body
  Statement
stmt -> Statement -> m Statement
forall (m :: * -> *) a. Monad m => a -> m a
return Statement
stmt

runProgram :: MonadAlpha m => Program -> m Program
runProgram :: Program -> m Program
runProgram = (Expr -> m Expr)
-> (Statement -> m [Statement]) -> Program -> m Program
forall (m :: * -> *).
Monad m =>
(Expr -> m Expr)
-> (Statement -> m [Statement]) -> Program -> m Program
mapExprStatementProgramM Expr -> m Expr
forall (m :: * -> *). Monad m => Expr -> m Expr
runExpr (((Statement -> [Statement] -> [Statement]
forall a. a -> [a] -> [a]
: []) (Statement -> [Statement]) -> m Statement -> m [Statement]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (m Statement -> m [Statement])
-> (Statement -> m Statement) -> Statement -> m [Statement]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Statement -> m Statement
forall (m :: * -> *). MonadAlpha m => Statement -> m Statement
runStatement)

-- | `run` replaces superfluous copying.
--
-- == Examples
--
-- Before:
--
-- > int b = range(a).size();
--
-- After:
--
-- > int b = a;
--
-- Before:
--
-- > for (int i : jikka::range(n)) {
-- >     ...
-- > }
--
-- After:
--
-- > for (int i = 0; i < n; ++ i) {
-- >     ...
-- > }
run :: (MonadAlpha m, MonadError Error m) => Program -> m Program
run :: Program -> m Program
run Program
prog = String -> m Program -> m Program
forall (m :: * -> *) a. MonadError Error m => String -> m a -> m a
wrapError' String
"Jikka.CPlusPlus.Convert.OptimizeRange" (m Program -> m Program) -> m Program -> m Program
forall a b. (a -> b) -> a -> b
$ do
  Program -> m Program
forall (m :: * -> *). MonadAlpha m => Program -> m Program
runProgram Program
prog