-- | The Ranker allows sorting valid changes, before presenting them to the user
module Seminal.Ranker (sortChanges) where
import Seminal.Change (Change(..))
import Data.List (sortOn)
import Data.Ix (Ix(range))
import Seminal.Compiler.API
import Data.Ord (Down(Down))

-- | Takes the list of successful changes from the searcher.
-- It sorts changes based on their type and index
-- (The deeper <=> the left-most = the better)
sortChanges :: [Change a] -> [Change a]
sortChanges :: forall a. [Change a] -> [Change a]
sortChanges [Change a]
list = (Int, Change a) -> Change a
forall a b. (a, b) -> b
snd ((Int, Change a) -> Change a) -> [(Int, Change a)] -> [Change a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((Int, Change a) -> Down (ChangeType, RealSrcSpan, Int))
-> [(Int, Change a)] -> [(Int, Change a)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Int, Change a) -> Down (ChangeType, RealSrcSpan, Int)
forall {c} {node}.
(c, Change node) -> Down (ChangeType, RealSrcSpan, c)
cmp ([Change a] -> [(Int, Change a)]
forall a. [Change a] -> [(Int, Change a)]
indexed [Change a]
list)
    where
        -- The comparison sorts from best (left-most) to worse (right-most)
        -- (Reverted using `Down`)
        cmp :: (c, Change node) -> Down (ChangeType, RealSrcSpan, c)
cmp (c
index, Change node
change) = (ChangeType, RealSrcSpan, c) -> Down (ChangeType, RealSrcSpan, c)
forall a. a -> Down a
Down (
            -- | The change type is the most important to sort on
            Change node -> ChangeType
forall node. Change node -> ChangeType
category Change node
change,
            SrcSpan -> RealSrcSpan
realSrcSpan (SrcSpan -> RealSrcSpan) -> SrcSpan -> RealSrcSpan
forall a b. (a -> b) -> a -> b
$ Change node -> SrcSpan
forall node. Change node -> SrcSpan
location Change node
change,
            -- | Then we order by 'when' the change was found
            -- If we found it later, it was deeper in the AST => it's better
            c
index
            )
        indexed :: [Change a] -> [(Int, Change a)]
        indexed :: forall a. [Change a] -> [(Int, Change a)]
indexed [Change a]
l = [Int] -> [Change a] -> [(Int, Change a)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((Int, Int) -> [Int]
forall a. Ix a => (a, a) -> [a]
range (Int
0, [Change a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Change a]
l)) [Change a]
l