module Lib.ProcessDecl

import Prelude
import Data.IORef
import Data.String

import Lib.Common
import Lib.Elab
import Lib.Parser
import Lib.Syntax
import Data.SortedMap
import Lib.TopContext
import Lib.Eval
import Lib.Prettier
import Lib.Types
import Lib.Util
import Lib.Erasure

dumpEnv : Context -> M String
dumpEnv ctx =
  unlines ∘ reverse <$> go (names ctx) 0 (reverse $ zip ctx.env ctx.types) Nil
  where
    isVar : Int -> Val -> Bool
    isVar k (VVar _ k' Lin) = k == k'
    isVar _ _ = False

    go : List String -> Int -> List (Val × String × Val) -> List String -> M (List String)
    go _ _ Nil acc = pure acc
    go names k ((v, n, ty) :: xs) acc = if isVar k v
      -- TODO - use Doc and add <+/> as appropriate to printing
      then do
        ty' <- quote ctx.lvl ty
        go names (1 + k) xs ("  \{n} : \{render 90 $ pprint names ty'}":: acc)
      else do
        v' <- quote ctx.lvl v
        ty' <- quote ctx.lvl ty
        go names (1 + k) xs ("  \{n} = \{render 90 $ pprint names v'} : \{render 90 $ pprint names ty'}":: acc)


logMetas : List MetaEntry -> M Unit
logMetas Nil = pure MkUnit
logMetas (OutOfScope :: rest) = logMetas rest
logMetas (Solved fc k soln :: rest) = logMetas rest
logMetas (Unsolved fc k ctx ty User cons :: rest) = do
      ty' <- quote ctx.lvl ty
      let names = map fst ctx.types
      env <- dumpEnv ctx
      let msg = "\{env}\n  -----------\n  \{render 90 $ pprint names ty'}"
      info fc "User Hole\n\{msg}"
      logMetas rest
logMetas (Unsolved fc k ctx ty kind cons :: rest) = do
      ty' <- forceMeta ty
      tm <- quote ctx.lvl ty'
      -- FIXME in Combinatory.newt, the val doesn't match environment?
      let msg = "Unsolved meta \{show k} \{show kind} type \{render 90 $ pprint (names ctx) tm} \{show $ length' cons} constraints"
      msgs <- for cons $ \case
        (MkMc fc env sp val) => do
            pure "  * (m\{show k} (\{unwords $ map show $ sp <>> Nil}) =?= \{show val}"
      sols <- case kind of
        AutoSolve => do
          x <- quote ctx.lvl ty
          ty <- eval ctx.env x
          debug $ \ _ => "AUTO ---> \{show ty}"
          -- we want the context here too.
          top <- getTop
          let (VRef _ tyname _) = ty | _ => pure Nil
          let cands = fromMaybe Nil $ lookupMap' tyname top.hints
          matches <- findMatches ctx ty cands
          pure $ ("  \{show $ length' matches} Solutions: \{show matches}" :: Nil)

        _ => pure Nil
      info fc $ unlines ((msg :: Nil) ++ msgs ++ sols)
      logMetas rest


-- Used for Class and Record
getSigs : List Decl -> List (FC × String × Raw)
getSigs Nil = Nil
getSigs ((TypeSig _ Nil _) :: xs) = getSigs xs
getSigs ((TypeSig fc (nm :: nms) ty) :: xs) = (fc, nm, ty) :: getSigs xs
getSigs (_ :: xs) = getSigs xs

teleToPi : Telescope -> Raw -> Raw
teleToPi Nil end = end
teleToPi ((info, ty) :: tele) end = RPi (getFC info) info ty (teleToPi tele end)

impTele : Telescope -> Telescope
impTele tele = map foo tele
  where
    foo : BindInfo × Raw → BindInfo × Raw
    foo (BI fc nm _ _ , ty) = (BI fc nm Implicit Zero, ty)


checkAlreadyDef : FC → Name → M Unit
checkAlreadyDef fc nm = do
  top <- getTop
  case lookupRaw nm top of
    Nothing => pure MkUnit
    Just entry => error fc "\{show nm} is already defined at \{show entry.fc}"


processDecl : List String -> Decl -> M Unit

processTypeSig : List String → FC → List Name → Raw → M Unit
processTypeSig ns fc names tm = do
  log 1 $ \ _ => "-----"

  top <- getTop
  let mc = top.metaCtx
  -- let mstart = length' mc.metas
  traverse (checkAlreadyDef fc) names
  ty <- check (mkCtx fc) tm (VU fc)
  -- this is not needed
  -- ty <- zonk top 0 Nil ty
  log 1 $ \ _ => "TypeSig \{unwords names} : \{render 90 $ pprint Nil ty}"
  ignore $ for names $ \nm => setDef (QN ns nm) fc ty Axiom Nil


processPrimType : List Name → FC → Name → Maybe Raw → M Unit
processPrimType ns fc nm ty = do
  top <- getTop
  ty' <- check (mkCtx fc) (maybe (RU fc) id ty) (VU fc)
  let arity = cast $ piArity ty'
  setDef (QN ns nm) fc ty' (PrimTCon arity) Nil


processPrimFn : List String → FC → String → List String → Raw → String → M Unit
processPrimFn ns fc nm used ty src = do
  top <- getTop
  ty <- check (mkCtx fc) ty (VU fc)
  ty' <- nf Nil ty
  log 1 $ \ _ => "pfunc \{nm} : \{render 90 $ pprint Nil ty'} = \{show src}"
  -- TODO wire through fc for not in scope error
  used' <- for used $ \ name => case lookupRaw name top of
    Nothing => error fc "\{name} not in scope"
    Just entry => pure entry.name
  let arity = piArity ty'
  setDef (QN ns nm) fc ty' (PrimFn src arity used') Nil

-- I'm trying to get ++ and + inlined as javascript +
complexity : Tm → Int
complexity (Ref _ _) = 1
complexity (Lam _ _ _ _ sc) = 1 + complexity sc
complexity (App _ t u) = complexity t + complexity u
complexity (Bnd _ _) = 1
-- These turn into a projection
complexity (Case _ sc (CaseCons _ _ t :: Nil)) = 1 + complexity sc + complexity t
complexity _ = 100

processDef : List String → FC → String → List (Raw × Raw) → M Unit
processDef ns fc nm clauses = do
  log 1 $ \ _ => "-----"
  log 1 $ \ _ => "Def \{show nm}"
  top <- getTop
  let mc = top.metaCtx
  let (Just entry) = lookupRaw nm top
    | Nothing => throwError $ E fc "No declaration for \{nm}"
  let (MkEntry fc name ty Axiom _) = entry
    | _ => throwError $ E fc "\{nm} already defined at \{show entry.fc}"

  log 1 $ \ _ => "check \{nm} at \{render 90 $ pprint Nil ty}"
  vty <- eval Nil ty

  debug $ \ _ => "\{nm} vty is \{show vty}"

  clauses' <- traverse makeClause clauses
  tm <- buildTree (mkCtx fc) (MkProb clauses' vty)

  solveAutos
  -- TODO - make nf that expands all metas and drop zonk
  -- Idris2 doesn't expand metas for performance - a lot of these are dropped during erasure.
  -- Day1.newt is a test case
  -- This inlines metas and functions flagged Inline.
  tm' <- zonk top 0 Nil tm
  debug $ \ _ => "NF\n\{render 80 $ pprint Nil tm'}"
  debug $ \ _ => "Add def \{nm} \{render 90 $ pprint Nil tm'} : \{render 90 $ pprint Nil ty}"
  updateDef (QN ns nm) fc ty (Fn tm')
  -- putStrLn "complexity \{show (QN ns nm)} \{show $ complexity tm'}"
  -- putStrLn $ show tm'
  -- TODO we need some protection against inlining a function calling itself.
  -- 14 gets us to 6.21s, higher than 11 breaks Zoo4eg.newt with a unification error (probably need to inline at the end instead)
  -- But we need better heuristics, maybe fuel and deciding while inlining.
  -- bind is explicit here because the complexity has a 100 in it.
  if complexity tm' < 11 || show (QN ns nm) == "Prelude.Prelude.Monad Prelude.IO,bind"
    then setFlag (QN ns nm) fc Inline
    else pure MkUnit

processCheck : List String → FC → Raw → Raw → M Unit
processCheck ns fc tm ty = do
  log 1 $ \ _ => "----- DCheck"
  top <- getTop

  info fc "check \{show tm} at \{show ty}"
  ty' <- check (mkCtx fc) ty (VU fc)
  putStrLn "  got type \{render 90 $ pprint Nil ty'}"
  vty <- eval Nil ty'
  res <- check (mkCtx fc) tm vty
  putStrLn "  got \{render 90 $ pprint Nil res}"
  norm <- nf Nil res
  putStrLn "  NF \{render 90 $ pprint Nil norm}"


processClass : List String → FC → String → Telescope → List Decl → M Unit
processClass ns classFC nm tele decls = do
  -- REVIEW maybe we can leverage Record for this
  -- a couple of catches, we don't want the dotted accessors and
  -- the self argument should be an auto-implicit
  log 1 $ \ _ => "-----"
  log 1 $ \ _ => "Class \{nm}"
  let fields = getSigs decls
  -- We'll need names for the telescope
  let dcName = "Mk\{nm}"
  let tcType = teleToPi tele (RU classFC)
  let tail = foldl mkApp (RVar classFC nm) tele
  let dcType = teleToPi (impTele tele) $ foldr mkPi tail fields

  log 1 $ \ _ => "tcon type \{render 90 $ pretty tcType}"
  log 1 $ \ _ => "dcon type \{render 90 $ pretty dcType}"
  let decl = Data classFC nm tcType (TypeSig classFC (dcName :: Nil) dcType :: Nil)
  log 1 $ \ _ => "Decl:"
  log 1 $ \ _ => render 90 $ pretty decl
  processDecl ns decl
  ignore $ for fields $ \case
    (fc,name,ty) => do
      let funType = teleToPi (impTele tele) $ RPi fc (BI fc "_" Auto Many) tail ty
      let autoPat = foldl mkAutoApp (RVar classFC dcName) fields
      let lhs = makeLHS (RVar fc name) tele
      let lhs = RApp classFC lhs autoPat Auto
      let decl = FunDef fc name ((lhs, (RVar fc name)) :: Nil)

      log 1 $ \ _ => "\{name} : \{render 90 $ pretty funType}"
      log 1 $ \ _ => "\{render 90 $ pretty decl}"
      processDecl ns $ TypeSig fc (name :: Nil) funType
      setFlag (QN ns name) fc Inline
      processDecl ns decl
  where
    makeLHS : Raw → Telescope → Raw
    makeLHS acc ((BI fc' nm icit quant,  _) :: tele) = RApp fc' (makeLHS acc tele) (RVar fc' nm) Implicit
    makeLHS acc Nil = acc

    -- TODO probably should just do the fold ourselves then.
    mkAutoApp : Raw → FC × String × Raw → Raw
    mkAutoApp acc (fc, nm, ty) = RApp fc acc (RVar fc nm) Explicit

    mkPi : FC × String × Raw → Raw → Raw
    mkPi (fc, nm, ty) acc = RPi fc (BI fc nm Explicit Many) ty acc

    mkApp : Raw → BindInfo × Raw → Raw
    mkApp acc (BI fc nm icit _, _) = RApp fc acc (RVar fc nm) icit

processInstance : List String → FC → Raw → Maybe (List Decl) → M Unit
processInstance ns instfc ty decls = do
  log 1 $ \ _ => "-----"
  log 1 $ \ _ => "Instance \{render 90 $ pretty ty}"
  top <- getTop
  let tyFC = getFC ty

  vty <- check (mkCtx instfc) ty (VU instfc)
  -- Here `tele` holds arguments to the instance
  let (codomain, tele) = splitTele vty
  -- env represents the environment of those arguments
  let env = tenv (length tele)
  debug $ \ _ => "codomain \{render 90 $ pprint Nil codomain}"
  debug $ \ _ => "tele is \{show tele}"

  -- ok so we need a name, a hack for now.
  -- Maybe we need to ask the user (e.g. `instance someName : Monad Foo where`)
  -- or use "Monad\{show $ length' defs}"
  let instname = render 90 $ pprint Nil codomain
  let sigDecl = TypeSig instfc (instname :: Nil) ty
  -- This needs to be declared before processing the defs, but the defs need to be
  -- declared before this - side effect is that a duplicate def is noted at the first
  -- member
  case lookupRaw instname top of
    Just _ => pure MkUnit -- TODO check that the types match
    Nothing => do
      -- only add once
      processDecl ns sigDecl
      setFlag (QN ns instname) instfc Hint
      addHint (QN ns instname)

  let (Just decls) = collectDecl <$> decls
    | _ => do
      debug $ \ _ => "Forward declaration \{show sigDecl}"

  let (Ref _ tconName, args) = funArgs codomain
    | (tm, _) => error tyFC "\{render 90 $ pprint Nil codomain} doesn't appear to be a TCon application"
  let (Just (MkEntry _ name type (TCon _ cons) _)) = lookup tconName top
    | _ => error tyFC "\{show tconName} is not a type constructor"
  let (con :: Nil) = cons
    | _ => error tyFC "\{show tconName} has multiple constructors \{show cons}"
  let (Just (MkEntry _ _ dcty (DCon _ _ _) _)) = lookup con top
    | _ => error tyFC "can't find constructor \{show con}"
  vdcty@(VPi _ nm icit rig a b) <- eval Nil dcty
    | x => error (getFC x) "dcty not Pi"
  debug $ \ _ => "dcty \{render 90 $ pprint Nil dcty}"
  let (_,args) = funArgs codomain

  debug $ \ _ => "traverse \{show $ map showTm args}"
  -- This is a little painful because we're reverse engineering the
  -- individual types back out from the composite type
  args' <- traverse (eval env) args
  debug $ \ _ => "args' is \{show args'}"
  appty <- apply vdcty args'
  conTele <- getFields appty env Nil
  -- declare individual functions, collect their defs
  defs <- for conTele $ \case
     (MkBinder fc nm Explicit rig ty) => do
       let ty' = foldr (\ x acc => case the Binder x of (MkBinder fc nm' icit rig ty') => Pi fc nm' icit rig ty' acc) ty tele
       let nm' = "\{instname},\{nm}"
       -- we're working with a Tm, so we define directly instead of processDecl
       let (Just (FunDef fc name xs)) = find (\x => case the Decl x of
        (FunDef y name xs) => name == nm
        _ => False) decls
          | _ => error instfc "no definition for \{nm}"

       -- REVIEW if we want to Hint this
       setDef (QN ns nm') fc ty' Axiom Nil
       let decl = (FunDef fc nm' xs)
       log 1 $ \ _ => "***"
       log 1 $ \ _ => "«\{nm'}» : \{render 90 $ pprint Nil ty'}"
       log 1 $ \ _ => render 80 $ pretty decl
       pure $ Just decl
     _ => pure Nothing

  for (mapMaybe id defs) $ \decl => do
    -- debug because already printed above, but nice to have it near processing
    debug $ \ _ => render 80 $ pretty decl
    processDecl ns decl
  let (QN _ con') = con
  let decl = FunDef instfc instname ((RVar instfc instname, mkRHS instname conTele (RVar instfc con')) :: Nil)
  log 1 $ \ _ => "SIGDECL"
  log 1 $ \ _ => "\{render 90 $ pretty sigDecl}"
  log 1 $ \ _ => render 80 $ pretty decl
  processDecl ns decl
  where
    -- try to extract types of individual fields from the typeclass dcon
    -- We're assuming they don't depend on each other.
    getFields : Val -> Env -> List Binder -> M (List Binder)
    getFields tm@(VPi fc nm Explicit rig ty sc) env bnds = do
      bnd <- MkBinder fc nm Explicit rig <$> quote (length' env) ty
      appsc <- sc $$ VVar fc (length' env) Lin
      getFields appsc env (bnd :: bnds)
    getFields tm@(VPi fc nm _ rig ty sc) env bnds = do
      appsc <- sc $$ VVar fc (length' env) Lin
      getFields appsc env bnds
    getFields tm xs bnds = pure $ reverse bnds

    tenv : Nat -> Env
    tenv Z = Nil
    tenv (S k) = (VVar emptyFC (cast k) Lin :: tenv k)

    mkRHS : String -> List Binder -> Raw -> Raw
    mkRHS instName (MkBinder fc nm Explicit rig ty :: bs) tm = mkRHS instName bs (RApp fc tm (RVar fc "\{instName},\{nm}") Explicit)
    mkRHS instName (b :: bs) tm = mkRHS instName bs tm
    mkRHS instName Nil tm = tm

    apply : Val -> List Val -> M Val
    apply x Nil = pure x
    apply (VPi fc nm icit rig a b) (x :: xs) = do
      bx <- b $$ x
      apply bx xs
    apply x (y :: xs) = error instfc "expected pi type \{show x}"

-- desugars to Data and processes it
processShortData : List String → FC → Raw → List Raw → M Unit
processShortData ns fc lhs sigs = do
  (nm,args) <- getArgs lhs Nil
  let ty = foldr mkPi (RU fc) args
  cons <- traverse (mkDecl args Nil) sigs
  let dataDecl = Data fc nm ty cons
  log 1 $ \ _ => "SHORTDATA"
  log 1 $ \ _ => "\{render 90 $ pretty dataDecl}"
  processDecl ns dataDecl
  where
    mkPi : FC × Name → Raw → Raw
    mkPi (fc,n) a = RPi fc (BI fc n Explicit Zero) (RU fc) a

    getArgs : Raw -> List (FC × String) -> M (String × List (FC × String))
    getArgs (RVar fc1 nm) acc = pure (nm, acc)
    getArgs (RApp _ t (RVar fc' nm) _) acc = getArgs t ((fc', nm) :: acc)
    getArgs tm _ = error (getFC tm) "Expected contructor application, got: \{show tm}"

    mkDecl : List (FC × Name) -> List Raw -> Raw -> M Decl
    mkDecl args acc (RVar fc' name) = do
      let base = foldr (\ ty acc => RPi (getFC ty) (BI (getFC ty) "_" Explicit Many) ty acc) lhs acc
      let ty = foldr mkPi base args
      pure $ TypeSig fc' (name :: Nil) ty
      where
        mkPi : FC × String → Raw → Raw
        mkPi (fc,nm) acc = RPi fc (BI fc nm Implicit Zero) (RU fc) acc

    mkDecl args acc (RApp fc' t u icit) = mkDecl args (u :: acc) t
    mkDecl args acc tm = error (getFC tm) "Expected contructor application, got: \{show tm}"

-- Identify Nat-like, enum-like, etc
populateConInfo : List TopEntry → List TopEntry
populateConInfo entries =
  let (Nothing) = traverse checkEnum entries
    | Just entries => entries in
  let (a :: b :: Nil) = entries | _ => entries in
  let (Just succ) = find isSucc entries | _ => entries in
  let (Just zero) = find isZero entries | _ => entries in
  setInfo zero ZeroCon :: setInfo succ SuccCon :: Nil
  where
    setInfo : TopEntry → ConInfo → TopEntry
    setInfo (MkEntry fc nm dty (DCon _ arity hn) flags) info = MkEntry fc nm dty (DCon info arity hn) flags
    setInfo x _ = x

    checkEnum : TopEntry → Maybe TopEntry
    checkEnum (MkEntry fc nm dty (DCon _ 0 hn) flags) = Just $ MkEntry fc nm dty (DCon EnumCon 0 hn) flags
    checkEnum _ = Nothing

    isZero : TopEntry → Bool
    isZero (MkEntry fc nm dty (DCon _ 0 hn) flags) = True
    isZero _ = False

    -- TODO - handle indexes, etc
    isSucc : TopEntry → Bool
    isSucc (MkEntry fc nm dty@(Pi _ _ _ _ (Ref _ a) (Ref _ b)) (DCon _ 1 hn) _) = a == b
    isSucc _ = False

processData : List String → FC → String → Raw → List Decl → M Unit
processData ns fc nm ty cons = do
  log 1 $ \ _ => "-----"
  log 1 $ \ _ => "Data \{nm}"
  top <- getTop
  let mc = top.metaCtx
  tyty <- check (mkCtx fc) ty (VU fc)
  case lookupRaw nm top of
    Just (MkEntry _ name type Axiom _) => do
      tyty' <- eval Nil tyty
      type' <- eval Nil type
      unifyCatch fc (mkCtx fc) tyty' type'
    Just _ => error fc "\{show nm} already declared"
    Nothing => setDef (QN ns nm) fc tyty Axiom Nil
  entries <- join <$> (for cons $ \x => case x of
      (TypeSig fc names tm) => do
          traverse (checkAlreadyDef fc) names
          debug $ \ _ => "check dcon \{show names} \{show tm}"
          dty <- check (mkCtx fc) tm (VU fc)
          debug $ \ _ => "dty \{show names} is \{render 90 $ pprint Nil dty}"

          -- We only check that codomain used the right type constructor
          -- We know it's in U because it's part of a checked Pi type
          let (codomain, tele) = splitTele dty
          -- for printing
          let tnames = reverse $ map binderName tele
          let (Ref _ hn, args) = funArgs codomain
            | (tm, _) => error (getFC tm) "expected \{nm} got \{render 90 $ pprint tnames tm}"
          when (hn /= QN ns nm) $ \ _ =>
            error (getFC codomain) "Constructor codomain is \{render 90 $ pprint tnames codomain} rather than \{nm}"
          pure $ map (\ nm' => (MkEntry fc (QN ns nm') dty (DCon NormalCon (getArity dty) hn) Nil)) names
      decl => throwError $ E (getFC decl) "expected constructor declaration")
  -- type level autos like _++_
  solveAutos
  let entries = populateConInfo entries
  for entries $ \case (MkEntry name fc dty def flags) => setDef fc name dty def flags
  let cnames = map (\x => x.name) entries

  log 1 $ \ _ => "setDef \{nm}  TCon \{show cnames}"
  let arity = cast $ piArity tyty
  updateDef (QN ns nm) fc tyty (TCon arity cnames)
  where
    binderName : Binder → Name
    binderName (MkBinder _ nm _ _ _) = nm

    checkDeclType : Tm -> M Unit
    checkDeclType (UU _) = pure MkUnit
    checkDeclType (Pi _ str icit rig t u) = checkDeclType u
    checkDeclType _ = error fc "data type doesn't return U"


processRecord : List String → FC → String → Telescope → Maybe Name → List Decl → M Unit
processRecord ns recordFC nm tele cname decls = do
  log 1 $ \ _ => "-----"
  log 1 $ \ _ => "Record"
  let fields = getSigs decls
  let dcName = fromMaybe "Mk\{show nm}" cname
  let tcType = teleToPi tele (RU recordFC)
  -- REVIEW - I probably want to stick the telescope in front of the fields
  let tail = foldl (\ acc bi => case the (BindInfo × Raw) bi of (BI fc nm icit _, _) => RApp fc acc (RVar fc nm) icit) (RVar recordFC nm) tele
  let dcType = teleToPi (impTele tele) $
    foldr (\ x acc => case the (FC × String × Raw) x of (fc, nm, ty) =>  RPi fc (BI fc nm Explicit Many) ty acc  ) tail fields

  log 1 $ \ _ => "tcon type \{render 90 $ pretty tcType}"
  log 1 $ \ _ => "dcon type \{render 90 $ pretty dcType}"
  let decl = Data recordFC nm tcType (TypeSig recordFC (dcName :: Nil) dcType :: Nil)
  log 1 $ \ _ => "Decl:"
  log 1 $ \ _ => render 90 $ pretty decl
  processDecl ns decl
  ignore $ for fields $ \case
    (fc,name,ty) => do
      -- TODO dependency isn't handled yet
      -- we'll need to replace stuff like `len` with `len self`.
      let funType = teleToPi (impTele tele) $ RPi fc (BI fc "_" Explicit Many) tail ty
      let autoPat = foldl (\acc x => case the (FC × String × Raw) x of (fc,nm,ty) => RApp fc acc (RVar fc nm) Explicit) (RVar recordFC dcName) fields

      -- `.fieldName`
      let pname = "." ++ name
      let lhs = foldl (\acc x => case the (BindInfo × Raw) x of (BI fc' nm icit quant, _) => RApp fc' acc (RVar fc' nm) Implicit) (RVar fc pname) tele
      let lhs = RApp recordFC lhs autoPat Explicit
      let pdecl = FunDef fc pname ((lhs, (RVar fc name)) :: Nil)
      log 1 $ \ _ => "\{pname} : \{render 90 $ pretty funType}"
      log 1 $ \ _ => "\{render 90 $ pretty pdecl}"
      processDecl ns $ TypeSig fc (pname :: Nil) funType
      processDecl ns pdecl
      setFlag (QN ns pname) fc Inline

-- currently mixfix registration is handled in the parser
-- since we now run a decl at a time we could do it here.
processDecl ns (PMixFix _ _ _ _)  = pure MkUnit
processDecl ns (TypeSig fc names tm) = processTypeSig ns fc names tm
processDecl ns (PType fc nm ty) = processPrimType ns fc nm ty
processDecl ns (PFunc fc nm used ty src) = processPrimFn ns fc nm used ty src
processDecl ns (FunDef fc nm clauses) = processDef ns fc nm clauses
processDecl ns (DCheck fc tm ty) = processCheck ns fc tm ty
processDecl ns (Class classFC nm tele decls) = processClass ns classFC nm tele decls
processDecl ns (Instance instfc ty decls) = processInstance ns instfc ty decls
processDecl ns (ShortData fc lhs sigs) = processShortData ns fc lhs sigs
processDecl ns (Data fc nm ty cons) = processData ns fc nm ty cons
processDecl ns (Record recordFC nm tele cname decls) = processRecord ns recordFC nm tele cname decls
