包装 xdef 以检查冲突

包装 xdef 以检查冲突

我如何才能xdef根据包选项编写透明包装器,报告错误,覆盖或遵守先前的定义,而不会牺牲所有灵活性?我不知道如何传递所有这些#

编辑:例如我能做什么以及我想做什么:

%% This is not valid. xdef have different syntax.
%% \ifpackage@force\xdef\package@define\xdef\fi
\ifpackage@obey\xdef\package@define\providecommand\fi
\ifpackage@err\xdef\package@define\newcommand\fi

因此我可以拥有providecommand和的通用接口newcommand。我想添加签入xdef

答案1

类似这样的

\begin{filecontents}{cxdef.sty}
\ProvidesPackage{cxdef}[2013/05/30]

\DeclareOption{over}{\let\myxdef\xdef}
\DeclareOption{error}{\let\myxdef\errorxdef}
\DeclareOption{preserve}{\let\myxdef\preservexdef}


\def\errorxdef#1{%
\ifx#1\@undefined
  \expandafter\xdef
\else
  \PackageError{cxdef}{\string#1 already defined}{think of a new name}%
  \expandafter\skip@xdef
\fi
#1}


\def\preservexdef#1{%
\ifx#1\@undefined
  \expandafter\xdef
\else
  \expandafter\skip@xdef
\fi
#1}

\def\skip@xdef#1#{\@gobble}

\ExecuteOptions{over}

\ProcessOptions\relax

\end{filecontents}

\documentclass{article}

\usepackage[error]{cxdef}

\myxdef\mbox#1#2\zz{this is bad}

\myxdef\zzzz#1#2\zz{this is good}

\typeout{\meaning\zzzz}


\stop

产生

! Package cxdef Error: \mbox already defined.

See the cxdef package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.39 \myxdef\mbox
                 #1#2\zz{this is bad}
? 
macro:#1#2\zz ->this is good
 )

\xdef\errorxdef\preservexdef都可用,或者您可以根据包选项使用\myxdef其中\let之一。

正如 egreg 在对该问题的评论中指出的那样,最好使用\protected@xdef而不是\xdef后者出现在包代码中的任何地方,但我\xdef现在将保留,因为这是原始问题。

答案2

这个答案试图回答这个问题,是否\xdef可以用宏来代替以捕获要定义的命令。

的语法\xdef比较复杂,相关方面:

  1. \xdef是无法扩展的。
  2. 该定义可以以\long、作为前缀\outer,并且 e-TeX 会添加\protected
  3. \afterassignment可能会在定义之后立即插入一个标记。

Vanilla TeX 已经无法解决问题 1。如果使用 定义新宏,至少 e-TeX 可以提供近似值\protected

以下示例针对 e-TeX 的各种格式尝试了问题 2(etexpdflatex):

\catcode`\@=11 % same as \makeatletter
\def\msg#{\immediate\write16}% short for printing something on the console

\let\xdef@original\xdef

\def\xdef@test@{}
\long\def\xdef@test@L{}
\protected\def\xdef@test@P{}
\protected\long\def\xdef@test@PL{}

\outer\def\xdef@test@O{}
\long\outer\def\xdef@test@LO{}
\protected\outer\def\xdef@test@PO{}
\protected\long\outer\def\xdef@test@PLO{}

\protected\def\xdef{%
  \def\xdef@test{}%
  \edef\xdef@prefix{%
    \ifx     \xdef@test\xdef@test@
    \else\ifx\xdef@test\xdef@test@L
      \noexpand\long
    \else\ifx\xdef@test\xdef@test@P
      \noexpand\protected
    \else\ifx\xdef@test\xdef@test@PL
      \noexpand\protected
      \noexpand\long
    \else
      \xdef@test@outer
    \fi\fi\fi\fi
  }%
  \xdef@check
}

\def\xdef@test@outer{%
  \expandafter\ifx     \csname xdef@test\expandafter\endcsname
                       \csname xdef@test@O\endcsname
    \noexpand\outer
  \else\expandafter\ifx\csname xdef@test\expandafter\endcsname
                       \csname xdef@test@LO\endcsname
    \noexpand\long
    \noexpand\outer
  \else\expandafter\ifx\csname xdef@test\expandafter\endcsname
                       \csname xdef@test@PO\endcsname
    \noexpand\protected
    \noexpand\outer
  \else\expandafter\ifx\csname xdef@test\expandafter\endcsname
                       \csname xdef@test@PLO\endcsname
    \noexpand\protected
    \noexpand\long
    \noexpand\outer
  \fi\fi\fi\fi
}

\edef\xdef@test@undefined{\meaning\xdef@undefined}
\edef\xdef@test@relax{\meaning\relax}
\def\xdef@check#1{%
  \edef\xdef@test{\meaning#1}%
  \ifx\xdef@test\xdef@test@undefined
    \chardef\xdef@ok=1 %
  \else\ifx\xdef@test\xdef@test@relax
    \chardef\xdef@ok=1 %
  \else
    \chardef\xdef@ok=0 %
  \fi\fi
  \ifcase\xdef@ok
    \errmessage{\string#1 is already defined}%
    \expandafter\def\expandafter\xdef@dummy   
  \or
    \expandafter\xdef@prefix
    \expandafter\xdef@original\expandafter#1%
  \fi
}

% testing
\xdef\aaa{}
\long\xdef\bbb{}
\protected\xdef\ccc{}
\protected\long\xdef\ddd{}
\outer\xdef\eee{}
\long\outer\xdef\fff{}
\protected\outer\xdef\ggg{}
\protected\long\outer\xdef\hhh{}
\xdef\iii{}

% end of job (LaTeX or plain TeX)
\csname @@end\endcsname\end

前缀只能被另一个定义捕获,因此新定义\xdef以 的定义开头\xdef@test。然后根据一系列其他宏测试新定义,以找到活动的前缀。前缀\outer由于其性质而使测试复杂化。\outer宏的使用存在限制。找到的前缀存储在 中\xdef@prefix

然后测试新的命令标记,看它是否未定义或具有 的含义\relax(LaTeX 对 中“未定义”的解释\@ifundefined)。这通过 进行检查。如果新命令已定义,而代之以定义\meaning伪命令,则会抛出错误。\xdef@dummy

然而这种重新\xdef定义不是原始版本的有效替代品\xdef。它无法解决第 3 个问题,即\afterassignment功能:

  • 前缀和最终定义之间的可扩展内容不会造成影响。因此,我们可以测试命令是否已定义。但抛出错误消息(或打印警告)是不可扩展的,TeX 会抱怨:

    ! You can't use a prefix with `\errmessage'.
    

    因此,我们至少需要一个测试定义来捕获前缀。

  • 如果\afterassignment正在使用,则令牌会在第一个测试定义之后立即插入,非常早:

    • 插入的标记可能需要使用尚未定义的新定义。
    • 定义业务尚未完成。令牌可能想要清理一些东西并弄乱事情。

因此我很确定,TeX 或 e-TeX 无法模拟全部通过宏来\xdef捕获要定义的命令,以打印警告或抛出错误(如果命令已经定义)。

相关内容