packages feed

glsl-0.0.0.1: src/Language/GLSL/StructuralEquality.hs

-- | Structural equality, ignoring the variable names.
module Language.GLSL.StructuralEquality where

import           Language.GLSL.ConstExpr (ConstExprs, isConstExpr)
import           Language.GLSL.Types


eqStmtAnnots :: ConstExprs -> [(StmtAnnot a, StmtAnnot a)] -> Bool
eqStmtAnnots ce = all (uncurry (eqStmtAnnot ce))

eqStmtAnnot :: ConstExprs -> StmtAnnot a -> StmtAnnot a -> Bool
eqStmtAnnot ce (SA _ a) (SA _ b) = eqStmt ce a b


eqStmt :: ConstExprs -> Stmt a -> Stmt a -> Bool
eqStmt ce (AssignStmt _ ea) (AssignStmt _ eb) =
  -- We consider constant expressions to be equal, since we can just pass that
  -- constant into the function as an argument. Most of the time, it's small
  -- things like 1.0 or (-1.0) (possibly in a t-var, hence the ConstExprs set).
  isConstExpr ce ea && isConstExpr ce eb ||
  eqExpr ea eb
eqStmt _ (DeclStmt da) (DeclStmt db) =
  eqLocalDecl da db
eqStmt _ (EmitStmt ea) (EmitStmt eb) =
  eqEmit ea eb
eqStmt ce (IfStmt _ ta ea) (IfStmt _ tb eb) =
  eqStmtAnnots ce (zip ta tb) &&
  eqStmtAnnots ce (zip ea eb)
eqStmt _ _ _ = False


eqExpr :: Expr -> Expr -> Bool
eqExpr (AtomExpr ea) (AtomExpr eb) =
  eqExprAtom ea eb
eqExpr (UnaryExpr ua ea) (UnaryExpr ub eb) =
  ua == ub && eqExprAtom ea eb
eqExpr (FunCallExpr fa aa) (FunCallExpr fb ab) =
  fa == fb && all (uncurry eqExprAtom) (zip aa ab)
eqExpr (TextureExpr ta xa ya) (TextureExpr tb xb yb) =
  all (uncurry eqExprAtom) [(ta, tb), (xa, xb), (ya, yb)]
eqExpr (BinaryExpr la oa ra) (BinaryExpr lb ob rb) =
  oa == ob && eqExprAtom la lb && eqExprAtom ra rb
eqExpr _ _ =
  False


eqExprAtom :: ExprAtom -> ExprAtom -> Bool
eqExprAtom (LitIntExpr _ _) (LitIntExpr _ _)             = True
eqExprAtom (LitIntExpr _ _) (LitFloatExpr _ _)           = True
eqExprAtom (LitFloatExpr _ _) (LitFloatExpr _ _)         = True
eqExprAtom (LitFloatExpr _ _) (LitIntExpr _ _)           = True
eqExprAtom (IdentifierExpr a) (IdentifierExpr b)         = eqNameExpr a b
eqExprAtom (SwizzleExpr _ a) (SwizzleExpr _ b)           = a == b
eqExprAtom (VecIndexExpr _ ia) (VecIndexExpr _ ib)       = ia == ib
eqExprAtom (MatIndexExpr _ ia ja) (MatIndexExpr _ ib jb) = ia == ib && ja == jb
eqExprAtom _ _                                           = False

-- | All variable names are equal.
--
--   We used to ignore temporary names only, considering all other names as
--   globals and a fixed part of the code. This check is quite expensive and it
--   turns out that most of the time the global variables *are* the same. If
--   they are not, we'll need to pass them as arguments to our new function, but
--   this is rare enough so it won't increase the average function parameter
--   list length too much.
eqNameExpr :: NameExpr -> NameExpr -> Bool
eqNameExpr (UniformExpr na ma) (UniformExpr nb mb) = na == nb && ma == mb
-- eqName (Name NsT _) (Name NsT _)   = True
-- eqName (Name nsa na) (Name nsb nb) = nsa == nsb && na == nb
eqNameExpr _ _                                     = True

eqLocalDecl :: LocalDecl -> LocalDecl -> Bool
eqLocalDecl (LDecl tya _ ea) (LDecl tyb _ eb) =
  eqType tya tyb && eqMaybe eqExpr ea eb


eqType :: Type -> Type -> Bool
eqType = (==)


eqEmit :: Emit -> Emit -> Bool
eqEmit (EmitPosition a) (EmitPosition b) = eqExpr a b
eqEmit EmitFragDepth EmitFragDepth       = True
eqEmit _ _                               = False


eqMaybe :: (a -> a -> Bool) -> Maybe a -> Maybe a -> Bool
eqMaybe f (Just a) (Just b) = f a b
eqMaybe _ Nothing Nothing   = True
eqMaybe _ _ _               = False