packages feed

Jikka-5.0.11.1: src/Jikka/CPlusPlus/Language/VariableAnalysis.hs

{-# LANGUAGE LambdaCase #-}

module Jikka.CPlusPlus.Language.VariableAnalysis where

import qualified Data.Set as S
import Jikka.CPlusPlus.Language.Expr

data ReadWriteList = ReadWriteList
  { readList :: S.Set VarName,
    writeList :: S.Set VarName
  }
  deriving (Eq, Ord, Show, Read)

instance Semigroup ReadWriteList where
  ReadWriteList rs ws <> ReadWriteList rs' ws' = ReadWriteList (rs <> rs') (ws <> ws')

instance Monoid ReadWriteList where
  mempty = ReadWriteList S.empty S.empty

readVariable :: VarName -> ReadWriteList
readVariable x = ReadWriteList (S.singleton x) S.empty

writeVariable :: VarName -> ReadWriteList
writeVariable x = ReadWriteList S.empty (S.singleton x)

analyzeExpr :: Expr -> ReadWriteList
analyzeExpr = \case
  Var x -> readVariable x
  Lit _ -> mempty
  UnOp _ e -> analyzeExpr e
  BinOp _ e1 e2 -> analyzeExpr e1 <> analyzeExpr e2
  Cond e1 e2 e3 -> analyzeExpr e1 <> analyzeExpr e2 <> analyzeExpr e3
  Lam args _ body ->
    let ReadWriteList rs ws = analyzeStatements body
        args' = S.fromList (map snd args)
     in ReadWriteList (rs `S.difference` args') (ws `S.difference` args')
  Call _ args -> mconcat (map analyzeExpr args)
  CallExpr f args -> mconcat (map analyzeExpr (f : args))

analyzeLeftExpr :: LeftExpr -> ReadWriteList
analyzeLeftExpr = \case
  LeftVar x -> writeVariable x
  LeftAt e1 e2 -> analyzeLeftExpr e1 <> analyzeExpr e2
  LeftGet _ e -> analyzeLeftExpr e

analyzeAssignExpr :: AssignExpr -> ReadWriteList
analyzeAssignExpr = \case
  AssignExpr _ e1 e2 -> analyzeLeftExpr e1 <> analyzeExpr e2
  AssignIncr e -> analyzeLeftExpr e
  AssignDecr e -> analyzeLeftExpr e

analyzeStatement :: Statement -> ReadWriteList
analyzeStatement = \case
  ExprStatement e -> analyzeExpr e
  Block body -> analyzeStatements body
  If e body1 body2 -> analyzeExpr e <> analyzeStatements body1 <> maybe mempty analyzeStatements body2
  For _ x init pred incr body -> writeVariable x <> analyzeExpr init <> analyzeExpr pred <> analyzeAssignExpr incr <> analyzeStatements body
  ForEach _ x e body -> writeVariable x <> analyzeExpr e <> analyzeStatements body
  While e body -> analyzeExpr e <> analyzeStatements body
  Declare _ x init ->
    writeVariable x <> case init of
      DeclareDefault -> mempty
      DeclareCopy e -> analyzeExpr e
      DeclareInitialize es -> mconcat (map analyzeExpr es)
  DeclareDestructure xs e -> mconcat (map writeVariable xs) <> analyzeExpr e
  Assign e -> analyzeAssignExpr e
  Assert e -> analyzeExpr e
  Return e -> analyzeExpr e

analyzeStatements :: [Statement] -> ReadWriteList
analyzeStatements = mconcat . map analyzeStatement