{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Frenetic.Pattern ( Matchable (..) , Wildcard (..) , Prefix (..) , wMatch ) where import Data.List hiding (intersect) import Data.Bits import Data.Word import Data.Maybe import Numeric (showHex) {-| A class for types that compose similar to wildcards. All instances must satisfy the following: * @match@ defines a partial order; @top@ is the top element of this order and @intersect@ is a meet. * Meets are exact: if @match x y@ and @match x z@, then @match x (fromJust (intersect y z))@, if such a meet exists. Minimal complete definition: top and intersect. -} class (Eq a) => Matchable a where top :: a intersect :: a -> a -> Maybe a match :: a -> a -> Bool overlap :: a -> a -> Bool disjoint :: a -> a -> Bool match x y = intersect x y == Just x overlap x y = isJust $ intersect x y disjoint x y = isNothing $ intersect x y data Wildcard a = Exact a | Wildcard deriving (Ord, Eq) data Prefix a = Prefix a Int deriving (Ord, Eq) instance Show a => Show (Wildcard a) where show Wildcard = "*" show (Exact a) = show a instance Functor Wildcard where fmap f (Exact a) = Exact (f a) fmap _ Wildcard = Wildcard instance (Bits a, Show a) => Show (Prefix a) where show (Prefix val significantBits) = if bitSize val == significantBits then show val else "Prefix " ++ show val ++ " " ++ show significantBits instance Bits a => Matchable (Prefix a) where top = Prefix 0 0 intersect (Prefix v1 sig1) (Prefix v2 sig2) = let sig = min sig1 sig2 -- shorter prefix width = bitSize v1 -- value ignored mask = complement (bit (width - sig) - 1) in -- mask out lower bits if v1 .&. mask == v2 .&. mask then if sig1 > sig2 then Just (Prefix v1 sig1) else Just (Prefix v2 sig2) else Nothing instance Eq a => Matchable (Wildcard a) where top = Wildcard intersect (Exact a) (Exact b) = if a == b then Just (Exact a) else Nothing intersect (Exact a) Wildcard = Just (Exact a) intersect Wildcard (Exact b) = Just (Exact b) intersect Wildcard Wildcard = Just Wildcard wMatch :: Eq a => a -> Wildcard a -> Bool wMatch b w = Exact b `match` w