Por que \@checkend ocorre após executar \endenvironment?

Por que \@checkend ocorre após executar \endenvironment?

Alguém sabe por que na definição do LaTeX \endo \@checkendcomando ocorre após a execução do código do ambiente final? Parece que, para fins de detecção de erros, seria melhor informar ao usuário que algo está errado o mais rápido possível.

Pergunto isso porque estou desenvolvendo alguns ambientes envae envbacidentalmente digo

\begin{enva}
% some stuff
\end{envb}

lança algum erro de baixo nível dentro de \endenvb. Para evitar isso, tenho que colocar minha própria \@checkendverificação de estilo dentro de \endenvb, o que parece ser parte do que \begindeveria \endfazer por mim.

Como um exemplo simples deste problema, considere o seguinte código:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\def\test{}
\begin{test}
\end{tikzpicture}
\end{document}

Isso dá o erro:

! Undefined control sequence.
\endtikzpicture ...r@layerlist@globally \endscope 
                                                  \let \pgf@baseline =\pgf@s...
l.10 \end{tikzpicture}

o que é menos esclarecedor do que eu desejaria. Quero evitar que erros inúteis semelhantes apareçam em meu próprio código.

Para referência, o que fiz para contornar isso foi escrever o seguinte comando, que coloquei no início do \endcódigo para cada um dos meus ambientes:

% #1 -- the name of the environment being ended
\def\mypkg@checkend#1{
    \def\mypkg@tempa{#1}
    \ifx\mypkg@tempa\@currenvir\else % mismatch
        \mypkg@error{endenv-mismatch}
        \csname end\@currenvir\endcsname % run the \end code for the correct environment
        \def\@currenvir{#1} % Prevent \@checkend from throwing a second redundant error
        \expandafter\mypkg@break % don't run the rest of \endthisenvironment
    \fi
}

Responder1

Uma implementação de um ambiente pode conter outros ambientes:

\newenvironment{foo}{\begin{center}}{\end{center}}

Se \@checkendfosse chamado logo no início do código "final", seria chamado dentro center, aqui. O\@checkend depoisa parte “end” ( \end<environment>) permite que outros ambientes abertos na parte “begin” sejam fechados corretamente.

Responder2

Além deA resposta de Heiko, observe também que pode ser necessário que o código de fim de ambiente funcione por expansão onde houver tabelas envolvidas. Pode-se ver isso sem mover a definição (não expansível), tornando uma \end...macro protegida:

\documentclass{article}
\newenvironment{foo}[1]
  {\begin{tabular}{#1}}{\end{tabular}}
\begin{document}
\fbox{%
  \begin{foo}{ccc}
    \hline
    Test & a & b \\
    \hline
  \end{foo}
}
\protected\edef\endfoo{\unexpanded\expandafter{\endfoo}}
\fbox{%
  \begin{foo}{ccc}
    \hline
    Test & a & b \\
    \hline
  \end{foo}
}
\end{document}

Isto surgiu, por exemplo, emxparsedesenvolvimento.

informação relacionada