> module Epic.Scopecheck where
Check that an expression has all its names in scope. This is the only checking we do (for now).
> import Control.Monad.State
> import Epic.Language
> import Epic.Parser
> checkAll :: Monad m => [Decl] -> m (Context, [Decl])
> checkAll xs = do let ctxt = mkContext xs
>                  ds <- ca (mkContext xs) xs
>                  return (ctxt,ds)
>    where ca ctxt [] = return []
>          ca ctxt ((Decl nm rt fn):xs) = 
>              do fn' <- scopecheck ctxt fn
>                 xs' <- ca ctxt xs
>                 return $ (Decl nm rt fn'):xs'
>          ca ctxt (x:xs) =
>              do xs' <- ca ctxt xs
>                 return (x:xs')
>          mkContext [] = []
>          mkContext ((Decl nm rt (Bind args _ _)):xs) =
>              (nm,(map snd args, rt)):(mkContext xs)
>          mkContext ((Extern nm rt args):xs) =
>              (nm,(args, rt)):(mkContext xs)
>          mkContext (_:xs) = mkContext xs
> scopecheck :: Monad m => Context -> Func -> m Func
> scopecheck ctxt (Bind args locs exp) = do
>        (exp', locs') <- runStateT (tc (v_ise args 0) exp) (length args)
>        return $ Bind args locs' exp'
>  where
>    tc env (R n) = case lookup n env of
>                      Nothing -> case lookup n ctxt of
>                         Nothing -> return $ Const (MkInt 1234567890)
> -- lift $ fail $ 
>    --                                  "Unknown name " ++ showuser n
>                         (Just _) -> return $ R n
>                      (Just i) -> return $ V i
>    tc env (Let n ty v sc) = do
>                v' <- tc env v
>                sc' <- tc ((n,length env):env) sc
>                maxlen <- get
>                put (if (length env + 1)>maxlen 
>                        then (length env + 1) 
>                        else maxlen)
>                return $ Let n ty v' sc'
>    tc env (Case v alts) = do
>                v' <- tc env v
>                alts' <- tcalts env alts
>                return $ Case v' alts'
>    tc env (If a t e) = do
>                a' <- tc env a
>                t' <- tc env t
>                e' <- tc env e
>                return $ If a' t' e'
>    tc env (App f as) = do
>                f' <- tc env f
>                as' <- mapM (tc env) as
>                return $ App f' as'
>    tc env (LazyApp f as) = do
>                f' <- tc env f
>                as' <- mapM (tc env) as
>                return $ LazyApp f' as'
>    tc env (Con t as) = do
>                as' <- mapM (tc env) as
>                return $ Con t as'
>    tc env (Proj e i) = do
>                e' <- tc env e
>                return $ Proj e' i
>    tc env (Op op l r) = do
>                l' <- tc env l
>                r' <- tc env r
>                return $ Op op l' r'
>    tc env (ForeignCall ty fn args) = do
>                argexps' <- mapM (tc env) (map fst args)
>                return $ ForeignCall ty fn (zip argexps' (map snd args))
>    tc env x = return x
>    tcalts env [] = return []
>    tcalts env ((Alt tag args expr):alts) = do
>                let env' = (v_ise args (length env))++env
>                expr' <- tc env' expr
>                maxlen <- get
>                put (if (length env')>maxlen 
>                        then (length env')
>                        else maxlen)
>                alts' <- tcalts env alts
>                return $ (Alt tag args expr'):alts'
>    tcalts env ((DefaultCase expr):alts) = do
>                expr' <- tc env expr
>                alts' <- tcalts env alts
>                return $ (DefaultCase expr'):alts'
Turn the argument list into a mapping from names to argument position
>    v_ise [] _ = []
>    v_ise ((n,ty):args) i = (n,i):(v_ise args (i+1))