Uma macro para verificar a capacidade de expansão do comando

Uma macro para verificar a capacidade de expansão do comando

Eu gostaria de criarum comando que verifica se uma expressão é totalmente expansível e trava se não(idealmente imprimindo uma mensagem de erro). Eu gostaria de fazer aquilosem um mecanismo TeX específico em mente. Eu acho que está relacionado a esta questãoVerifique se a macro é totalmente expansível, mas a resposta fornecida requer LuaTeX.


Código de teste

Um código de teste ficaria assim:

\documentclass[preview = true, varwidth = true]{standalone}
\usepackage{xparse}
\usepackage{xstring}

\NewDocumentCommand{\checkexpandability}{m}{
    % CODE HERE
}

\newcommand{\expandable}[1]{#1}
\newcommand{\notexpandable}[1]{%
    \edef\myvariable{\expandable{#1}}%
    \myvariable%
}

\begin{document}
\checkexpandability{\expandable{test}} % Should be OK
\checkexpandability{\notexpandable{test}} % Should CRASH
\checkexpandability{\IfBeginWith{string}{str}{true}{false}} % Should CRASH
\end{document}

Caso seja muito complicado

Se não for possível, posso modificar a assinatura do comando para incluir um parâmetro para o qual o comando deve se expandir:

\begin{document}
\checkexpandability{\expandable{test}}{test} % Should be OK
\checkexpandability{\notexpandable{test}}{test} % Should CRASH
\checkexpandability{\IfBeginWith{string}{str}{true}{false}}{true} % Should CRASH
\end{document}

Comente sobre expansibilidade

Como a definição de totalmente expansível não é tão clara quanto se poderia imaginar (veja o comentário abaixo), o contexto desta questão é que estou apenas tentando criar algo que me ajude a depurar algum código. Posso restringir a questão a este comportamento específico: se a macro funcionaria nas macros de contexto como o \colorcomando:

\documentclass[preview = true, varwidth = true]{standalone}
\usepackage{xcolor}

\newcommand{\expandable}[1]{#1}
\newcommand{\notexpandable}[1]{%
    \edef\myvariable{\expandable{#1}}%
    \myvariable%
}
    
\begin{document}
\color{\expandable{blue}} % OK
\color{\notexpandable{red}} % CRASHES
X
\end{document}

Basicamente, o \colorcomando faz o tipo de trabalho que procuro, só que gostaria de chamá-lo \checkexpandability, ser um pouco mais genérico e imprimir uma bela mensagem de erro.

Responder1

Acho que o mal-entendido básico é

Basicamente, o \colorcomando faz o tipo de trabalho que procuro,

O \colorcomando não faz verificações do tipo solicitado, simplesmente espera que após a expansão o argumento seja um nome de cor definido. Se a expansão falhar, você receberá um erro de baixo nível ou se ela se expandir para uma cor indefinida, você receberá uma mensagem de erro específica, mas nenhuma parte do processamento é genérica ou se aplica a um comando diferente dos comandos que esperam cores.

A única versão que pode ser implementada é a versão com uma expansão esperada, pois simplesmente pergunta se os dois argumentos são iguais após a expansão. A camada de programação L3 tem diversas variantes disso ou você pode usar o ifthenpacote e

\ifthenelse{\equal{\expandable{test}}{test}}{yes}{no}

que retornará sim se os argumentos se expandirem para a mesma coisa, não se não o fizerem, ou fornecerá um erro de baixo nível se o argumento não for seguro em um contexto de expansão (que é o que normalmente significa "não é expansível")

Responder2

Para depurar seu código, eu usaria apenas \typeout.

\documentclass[preview = true, varwidth = true]{standalone}
\usepackage{xcolor}

\newcommand{\expandable}[1]{#1}
\newcommand{\notexpandable}[1]{%
    \edef\myvariable{\expandable{#1}}%
    \myvariable%
}
    
\begin{document}
\typeout{\expandable{blue}} % OK, print "blue"
\typeout{\notexpandable{red}} % CRASHES
X
\end{document}

A questão é que \typeoutexpandirá totalmente seu argumento e, em seguida, imprimirá qualquer resultado totalmente expandido no terminal --- para que você possa apenas dar uma olhada no terminal.

Para o primeiro caso ele imprime blue, então está tudo bem. No segundo caso, ele trava.


Claro, existem dois problemas com a abordagem acima.

  • Ainda que\expandable{blue} étotalmente expansível (seja lá o que isso signifique),pode não ser o caso que \colorgaranta a expansão total do seu argumento antes de interpretar o resultado como uma cor. (acho que porLei de Hyrumseria praticamente para evitar a quebra de "pacotes existentes".)

    Então, se você quiser ter mais certeza, é melhor expandi-lo antecipadamente usando, por exemplo\ExpandArgs.

  • As informações sobre o código da categoria, bem como qualquer caractere especial oculto no código (por exemplo, espaço versus tabulação), são perdidas.

    Na prática isso não importaria muito, mas às vezes importa. (por exemplo, quando você tenta depurar algum pacote que tenta capturar o corpo do ambiente literalmente)

    Se for esse o caso, considere experimentarMeu pacote. (o código está uma bagunça agora, mas funciona bem, e existem pacotes com código-fonte pior por aí)

informação relacionada