packages feed

hic-0.0.0.1: src/Language/Cimple/Analysis/Refined/SemanticEquality.hs

{-# LANGUAGE DataKinds  #-}
{-# LANGUAGE GADTs      #-}
{-# LANGUAGE StrictData #-}

module Language.Cimple.Analysis.Refined.SemanticEquality
    ( semEqStep
    , semEqResult
    ) where

import           Data.Bifunctor                         (first)
import qualified Data.List                              as List
import           Data.Word                              (Word32)
import qualified Language.Cimple                        as C
import           Language.Cimple.Analysis.Refined.State (ProductState (..))
import           Language.Cimple.Analysis.Refined.Types

-- | Checks if a 'StepResult' matches an original node (by applying a selector to 'ProductState').
-- Assumes both nodes are in canonical form (sorted collections).
semEqStep :: Eq tid => AnyRigidNodeF tid ProductState -> (ProductState -> Word32) -> AnyRigidNodeF tid Word32 -> Bool
semEqStep (AnyRigidNodeF n1) selector (AnyRigidNodeF n2) =
    case (n1, n2) of
        (RObject s1 q1, RObject s2 q2) -> q1 == q2 && semEqStepObj s1 selector s2
        (RReference r1 n1' o1 q1, RReference r2 n2' o2 q2) ->
            n1' == n2' && o1 == o2 && q1 == q2 && semEqStepRef r1 selector r2
        (RFunction a1 r1, RFunction a2 r2) ->
            length a1 == length a2 &&
            all (\(ps, expected) -> selector ps == expected) (zip a1 a2) &&
            semEqStepRet r1 selector r2
        (RTerminal t1, RTerminal t2) -> semEqTerminal t1 selector t2
        _ -> False

semEqTerminal :: TerminalNode ProductState -> (ProductState -> Word32) -> TerminalNode Word32 -> Bool
semEqTerminal SBottom _ SBottom = True
semEqTerminal SAny        _ SAny        = True
semEqTerminal SConflict   _ SConflict   = True
semEqTerminal (STerminal ps) selector (STerminal expected) = selector ps == expected
semEqTerminal _ _ _ = False

semEqStepObj :: Eq tid => ObjectStructure tid ProductState -> (ProductState -> Word32) -> ObjectStructure tid Word32 -> Bool
semEqStepObj s1 selector s2 = case (s1, s2) of
    (VBuiltin b1, VBuiltin b2) -> b1 == b2
    (VSingleton b1 v1, VSingleton b2 v2) -> b1 == b2 && v1 == v2
    (VNominal n1 p1, VNominal n2 p2) ->
        C.lexemeText n1 == C.lexemeText n2 && length p1 == length p2 && all (\(ps, expected) -> selector ps == expected) (zip p1 p2)
    (VEnum n1, VEnum n2) -> C.lexemeText n1 == C.lexemeText n2
    (VVar t1 i1, VVar t2 i2) -> t1 == t2 && i1 == i2
    (VExistential ts1 b1, VExistential ts2 b2) -> ts1 == ts2 && selector b1 == b2
    (VVariant m1, VVariant m2) ->
        fmap selector m1 == m2
    (VProperty a1 pk1, VProperty a2 pk2) -> pk1 == pk2 && selector a1 == a2
    (VSizeExpr m1, VSizeExpr m2) ->
        List.sortOn fst (map (first selector) m1) == List.sortOn fst m2
    _ -> False

semEqStepRef :: Eq tid => RefStructure tid ProductState -> (ProductState -> Word32) -> RefStructure tid Word32 -> Bool
semEqStepRef r1 selector r2 = case (r1, r2) of
    (Arr e1 d1, Arr e2 d2) ->
        selector e1 == e2 && length d1 == length d2 && all (\(ps, expected) -> selector ps == expected) (zip d1 d2)
    (Ptr p1, Ptr p2) -> semEqStepPtr p1 selector p2
    _ -> False

semEqStepPtr :: Eq tid => PtrTarget tid ProductState -> (ProductState -> Word32) -> PtrTarget tid Word32 -> Bool
semEqStepPtr p1 selector p2 = case (p1, p2) of
    (TargetObject o1, TargetObject o2) -> selector o1 == o2
    (TargetFunction a1 r1, TargetFunction a2 r2) ->
        length a1 == length a2 && all (\(ps, expected) -> selector ps == expected) (zip a1 a2) && semEqStepRet r1 selector r2
    (TargetOpaque t1, TargetOpaque t2) -> t1 == t2
    _ -> False

semEqStepRet :: ReturnType ProductState -> (ProductState -> Word32) -> ReturnType Word32 -> Bool
semEqStepRet r1 selector r2 = case (r1, r2) of
    (RetVal v1, RetVal v2) -> selector v1 == v2
    (RetVoid, RetVoid)     -> True
    _                      -> False

-- | Checks if two 'StepResult's are semantically equal (canonicalizing order/duplicates).
semEqResult :: Eq tid => AnyRigidNodeF tid ProductState -> AnyRigidNodeF tid ProductState -> Bool
semEqResult = (==) -- Results are guaranteed canonical by 'step'