packages feed

alms-0.6.0: src/AST/Patt.hs

module AST.Patt (
  -- * Patterns
  Patt'(..), Patt, PattNote(..), newPatt,
  -- ** Constructors
  paWild, paVar, paCon, paPair, paLit, paAs, paInj, paAnn,
  paBang, paRec, paAnti,
  -- ** Synthetic pattern constructors
  paChar, paStr, paInt, paFloat, paUnit, paCons, paNil,
  ToPatt(..),
) where

import Util
import Meta.DeriveNotable
import AST.Notable
import AST.Anti
import AST.Ident
import AST.Lit
import AST.Type

import Prelude ()
import Data.Generics (Typeable, Data)

type Patt i = N (PattNote i) (Patt' i)

-- | Patterns
data Patt' i
  -- | wildcard
  = PaWild
  -- | variable pattern
  | PaVar (VarId i)
  -- | datacon, possibly with parameter, possibly an exception
  | PaCon (QConId i) (Maybe (Patt i))
  -- | pair pattern
  | PaPair (Patt i) (Patt i)
  -- | literal pattern
  | PaLit Lit
  -- | bind an identifer and a pattern (@as@)
  | PaAs (Patt i) (VarId i)
  -- | open variant
  | PaInj (Uid i) (Maybe (Patt i))
  -- | type annotation on a pattern
  | PaAnn (Patt i) (Type i)
  -- | record pattern
  | PaRec (Uid i) (Patt i) (Patt i)
  -- | imperative/threaded binding
  | PaBang (Patt i)
  -- | antiquote
  | PaAnti Anti
  deriving (Typeable, Data)

data PattNote i
  = PattNote {
      -- | source location
      ploc_  :: !Loc,
      -- | defined variables
      pdv_   :: [VarId i]
    }
  deriving (Typeable, Data)

instance Locatable (PattNote i) where
  getLoc = ploc_

instance Relocatable (PattNote i) where
  setLoc note loc = note { ploc_ = loc }

instance Notable (PattNote i) where
  newNote = PattNote bogus mempty

newPatt :: Tag i => Patt' i -> Patt i
newPatt p0 = flip N p0 $ case p0 of
  PaWild           ->
    newNote {
      pdv_    = mempty
    }
  PaVar x          ->
    newNote {
      pdv_    = [x]
    }
  PaCon _ mx       ->
    newNote {
      pdv_    = maybe mempty dv mx
    }
  PaPair x y       ->
    newNote {
      pdv_    = dv x `mappend` dv y
    }
  PaLit _          ->
    newNote {
      pdv_    = mempty
    }
  PaAs x y         ->
    newNote {
      pdv_    = dv x ++ [y]
    }
  PaInj _ my       ->
    newNote {
      pdv_    = maybe mempty dv my
    }
  PaAnn x _        ->
    newNote {
      pdv_    = dv x
    }
  PaRec _ x y      ->
    newNote {
      pdv_    = dv x `mappend` dv y
    }
  PaBang x         ->
    newNote {
      pdv_    = dv x
    }
  PaAnti a         ->
    newNote {
      pdv_    = antierror "dv" a
    }

instance Dv (N (PattNote i) a) i where
  dv = pdv_ . noteOf

deriveNotable 'newPatt (''Tag, [0]) ''Patt

paChar :: Tag i => Char -> Patt i
paChar = paLit . LtChar

paStr :: Tag i => String -> Patt i
paStr  = paLit . LtStr

paInt :: (Tag i, Integral a) => a -> Patt i
paInt  = paLit . LtInt . toInteger

paFloat :: Tag i => Double -> Patt i
paFloat  = paLit . LtFloat

paUnit :: Tag i => Patt i
paUnit  = paCon idUnitVal Nothing

paCons :: Tag i => Patt i -> Patt i -> Patt i
paCons  = paCon idConsList . Just <$$> paPair

paNil  :: Tag i => Patt i
paNil   = paCon idNilList Nothing

class ToPatt a i | a → i where
  toPatt ∷ a → Patt i

instance ToPatt (Patt i) i where
  toPatt = id

instance Tag i ⇒ ToPatt (VarId i) i where
  toPatt = paVar

instance (Tag i, ToPatt a i, ToPatt b i) ⇒ ToPatt (a, b) i where
  toPatt (a, b) = paPair (toPatt a) (toPatt b)

instance Tag i ⇒ ToPatt String i where
  toPatt = paStr

instance Tag i ⇒ ToPatt Int i where
  toPatt = paInt

instance Tag i ⇒ ToPatt Char i where
  toPatt = paChar

instance Tag i ⇒ ToPatt Double i where
  toPatt = paFloat