collectVars :: SnippetBody a -> Vars
collectVars body =
    snd (runState (iterM run body) mempty)
    where
    run :: SnippetBodyF (State Vars a) -> State Vars a
    run (Lit _ rest) = rest
    run (Finish rest) = rest
    run (MakeVar s f) = do
        vars <- get
        let newVar = if M.null vars
                        then (UserVar 0)
                        else UserVar (maximum (map fromVar (M.keys vars)) + 1)
            newVars = M.insert newVar (DefaultValue s) vars
        put newVars
        f newVar
    run (Mirror _ rest) = rest
    run (Refer var f) = do
        vars <- get
        f (toYiString (vars M.! var))
collectVars :: SnippetBody a -> Vars
collectVars body =
    snd (runState (iterM run body) mempty)
    where
    run :: SnippetBodyF (State Vars a) -> State Vars a
    run (Lit _ rest) = rest
    run (Finish rest) = rest
    run (MakeVar s f) = do
        vars <- get
        let newVar = if M.null vars
                        then (UserVar 0)
                        else UserVar (maximum (map fromVar (M.keys vars)) + 1)
            newVars = M.insert newVar (DefaultValue s) vars
        put newVars
        f newVar
    run (Mirror _ rest) = rest
    run (Refer var f) = do
        vars <- get
        f (toYiString (vars M.! var))
collectVars body =
    snd (runState (iterM run body) mempty)
    where
    run :: SnippetBodyF (State Vars a) -> State Vars a
    run (Lit _ rest) = rest
    run (Finish rest) = rest
    run (MakeVar s f) = do
        vars <- get
        let newVar = if M.null vars
                        then (UserVar 0)
                        else UserVar (maximum (map fromVar (M.keys vars)) + 1)
            newVars = M.insert newVar (DefaultValue s) vars
        put newVars
        f newVar
    run (Mirror _ rest) = rest
    run (Refer var f) = do
        vars <- get
        f (toYiString (vars M.! var))