<commit_before>{-# LANGUAGE ExistentialQuantification #-}
module Sodium.Chloride.Clean (clean) where

import Control.Applicative
import Control.Lens hiding (Index, Fold)
import Control.Monad.Reader
import qualified Data.Map as M
import Data.Bool
import Sodium.Chloride.Program.Vector
import Sodium.Chloride.Recmap.Vector

clean :: Program -> Program
clean = recmapProgram' (recmapper' cleanBody)

cleanBody :: Body -> Body
cleanBody body = (bodyVars %~ M.filterWithKey cc) body where
	cc name _ = runReader (unsafeBodyCheckRef body) name

unsafeBodyCheckRef body = checkRef
	[ CheckRef' (body ^. bodyResults)
	, CheckRef' (body ^. bodyBinds)
	]

data CheckRef' = forall a . CheckRef a => CheckRef' a

pairCheckRef' (a, b) = CheckRef' [CheckRef' a, CheckRef' b]

class CheckRef a where
	checkRef :: a -> Reader Name Bool

instance CheckRef CheckRef' where
	checkRef (CheckRef' a) = checkRef a

instance CheckRef a => CheckRef [a] where
	checkRef as = or <$> traversed checkRef as

instance CheckRef Expression where
	checkRef = \case
		Primary _ -> return False
		Access name' _ -> do
			name <- ask
			return (name == name')
		Call _ exprs -> -- Check the operator?
			checkRef exprs
		Fold _ exprs range -> checkRef
			[CheckRef' exprs, CheckRef' range]

instance CheckRef Statement where
	checkRef = \case
		Execute _ exprs -> checkRef exprs
		Assign expr -> checkRef expr
		BodyStatement body -> checkRef body
		ForStatement forCycle -> checkRef forCycle
		MultiIfStatement multiIfBranch -> checkRef multiIfBranch

instance CheckRef Bind where
	checkRef = checkRef . view bindStatement

instance CheckRef ForCycle where
	checkRef forCycle = do
		shadowed <- shadowedBy (forCycle ^.. forArgIndices . traversed . _1)
		let base =
			[ CheckRef' (forCycle ^. forRange)
			, CheckRef' (forCycle ^. forArgExprs)
			]
		let unsh = bool [CheckRef' (forCycle ^. forBody) ] [] shadowed
		checkRef (base ++ unsh)

instance CheckRef MultiIfBranch where
	checkRef multiIfBranch = checkRef
		[ CheckRef' . map pairCheckRef'
			$ (multiIfBranch ^. multiIfLeafs)
		, CheckRef' (multiIfBranch ^. multiIfElse)
		]

instance CheckRef Body where
	checkRef body = do
		shadowed <- shadowedBy (body ^. bodyVars . to M.keys)
		bool (unsafeBodyCheckRef body) (return False) shadowed

shadowedBy :: [Name] -> Reader Name Bool
shadowedBy names = (`elem` names) <$> ask<commit_msg>Refactor the Clean module (no existential quantification)<commit_after>module Sodium.Chloride.Clean (clean) where

import Control.Applicative
import Control.Lens hiding (Index, Fold)
import Control.Monad.Reader
import qualified Data.Map as M
import Data.Bool
import Sodium.Chloride.Program.Vector
import Sodium.Chloride.Recmap.Vector

clean :: Program -> Program
clean = recmapProgram' (recmapper' cleanBody)

cleanBody :: Body -> Body
cleanBody body = (bodyVars %~ M.filterWithKey cc) body where
    cc name _ = runReader (checkRef $ bodyComponents body) name


class CheckRef a where
    checkRef :: a -> Reader Name Bool


-- Helper instances

instance CheckRef a => CheckRef [a] where
    checkRef as = or <$> traversed checkRef as

instance (CheckRef a, CheckRef b) => CheckRef (a, b) where
    checkRef (a, b) = (||) <$> checkRef a <*> checkRef b


-- Actual instances

instance CheckRef Expression where
    checkRef = \case
        Primary _ -> return False
        Access name' _ -> do
            name <- ask
            return (name == name')
        Call _ exprs -> -- Check the operator?
            checkRef exprs
        Fold _ exprs range -> checkRef (exprs, range)

instance CheckRef Statement where
    checkRef = \case
        Execute _ exprs -> checkRef exprs
        Assign expr -> checkRef expr
        BodyStatement body -> checkRef body
        ForStatement forCycle -> checkRef forCycle
        MultiIfStatement multiIfBranch -> checkRef multiIfBranch

instance CheckRef Bind where
    checkRef = checkRef . view bindStatement

instance CheckRef ForCycle where
    checkRef forCycle = do
        shadowed <- shadowedBy (forCycle ^.. forArgIndices . traversed . _1)
        let base = (forCycle ^. forRange, forCycle ^. forArgExprs)
        let unsh = bool [forCycle ^. forBody] [] shadowed
        checkRef (base, unsh)

instance CheckRef MultiIfBranch where
    checkRef multiIfBranch = checkRef 
        (multiIfBranch ^. multiIfLeafs, multiIfBranch ^. multiIfElse)

bodyComponents body = (body ^. bodyResults, body ^. bodyBinds)

instance CheckRef Body where
    checkRef body = do
        shadowed <- shadowedBy (body ^. bodyVars . to M.keys)
        checkRef $ bool [bodyComponents body] [] shadowed

shadowedBy :: [Name] -> Reader Name Bool
shadowedBy names = (`elem` names) <$> ask
{'fraction_non_alphanumeric': 0.08884607150503104, 'fraction_numerical': 0.00042817383857846286, 'mean_word_length': 3.4622731614135627, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5259281', 'n_tokens_mistral': 1486, 'n_tokens_neox': 1431, 'n_words': 477}