renderSnippet :: Snippet -> EditState -> (Int, R.YiString)
renderSnippet (Snippet _ body) (EditState (maybeActiveVar, offset) vars) = 
    (either id id epos, string)
    where
    (((), (_var, epos)), string) = runWriter (runStateT (iterM run body) (UserVar (-1), Right 0))
    advance :: MonadState (Var, Either Int Int) m => Int -> m ()
    advance n = modify (fmap (fmap (+ n)))
    run :: SnippetBodyF ((StateT (Var, Either Int Int) (Writer R.YiString)) a)
        -> StateT (Var, Either Int Int) (Writer R.YiString) a
    run (Lit s rest) = do
        tell s
        advance (R.length s)
        rest
    run (Finish rest) = rest
    run (Mirror var rest) = do
        let s = toYiString (vars M.! var)
        tell s

        if Just var == maybeActiveVar
        then do
            (v, curPos) <- get
            case curPos of
                Right pos ->
                    put (v, (Left (pos + offset)))
                _ -> return ()
        else advance (R.length s)

        rest
    run (MakeVar _ f) = do
        (varName, pos) <- get
        let newVar = UserVar (fromVar varName + 1)
        put (newVar, pos)
        f (newVar)
    run (Refer var f) = f (toYiString (vars M.! var))
renderSnippet :: Snippet -> EditState -> (Int, R.YiString)
renderSnippet (Snippet _ body) (EditState (maybeActiveVar, offset) vars) = 
    (either id id epos, string)
    where
    (((), (_var, epos)), string) = runWriter (runStateT (iterM run body) (UserVar (-1), Right 0))
    advance :: MonadState (Var, Either Int Int) m => Int -> m ()
    advance n = modify (fmap (fmap (+ n)))
    run :: SnippetBodyF ((StateT (Var, Either Int Int) (Writer R.YiString)) a)
        -> StateT (Var, Either Int Int) (Writer R.YiString) a
    run (Lit s rest) = do
        tell s
        advance (R.length s)
        rest
    run (Finish rest) = rest
    run (Mirror var rest) = do
        let s = toYiString (vars M.! var)
        tell s

        if Just var == maybeActiveVar
        then do
            (v, curPos) <- get
            case curPos of
                Right pos ->
                    put (v, (Left (pos + offset)))
                _ -> return ()
        else advance (R.length s)

        rest
    run (MakeVar _ f) = do
        (varName, pos) <- get
        let newVar = UserVar (fromVar varName + 1)
        put (newVar, pos)
        f (newVar)
    run (Refer var f) = f (toYiString (vars M.! var))
renderSnippet (Snippet _ body) (EditState (maybeActiveVar, offset) vars) = 
    (either id id epos, string)
    where
    (((), (_var, epos)), string) = runWriter (runStateT (iterM run body) (UserVar (-1), Right 0))
    advance :: MonadState (Var, Either Int Int) m => Int -> m ()
    advance n = modify (fmap (fmap (+ n)))
    run :: SnippetBodyF ((StateT (Var, Either Int Int) (Writer R.YiString)) a)
        -> StateT (Var, Either Int Int) (Writer R.YiString) a
    run (Lit s rest) = do
        tell s
        advance (R.length s)
        rest
    run (Finish rest) = rest
    run (Mirror var rest) = do
        let s = toYiString (vars M.! var)
        tell s

        if Just var == maybeActiveVar
        then do
            (v, curPos) <- get
            case curPos of
                Right pos ->
                    put (v, (Left (pos + offset)))
                _ -> return ()
        else advance (R.length s)

        rest
    run (MakeVar _ f) = do
        (varName, pos) <- get
        let newVar = UserVar (fromVar varName + 1)
        put (newVar, pos)
        f (newVar)
    run (Refer var f) = f (toYiString (vars M.! var))