l3doc 中 @@ 替换的微妙之处

l3doc 中 @@ 替换的微妙之处

我正在尝试了解类@@中替换的确切语义l3doc。到目前为止,我从文档中收集到的信息如下:

  • %<@@=name>在文档中出现声明之前没有发生替换。
  • 当发生替换时,将按照字符序列(从左到右)的顺序尝试并替换以下模式:

    "@@@@" -> "@@"
    "__@@" -> "__" + name
    "_@@"  -> "__" + name
    "@@"   -> "__" + name
    
  • \cmd替换发生在和的参数中\cs,除非replace=false在这些命令的可选参数中定义了。
  • function替换发生在和环境的第一个参数中列出的所有控制序列名称中macro
  • 替换发生在\begin{macrocode}和之间的所有行中\end{macrocode},除非该字符序列<@@=出现在该行中。

我的问题:

  1. 还有其他地方可以进行替换吗?
  2. 是否有其他选项(全球性或本地性)对替换有影响?
  3. %<@@=name>如果在同一文档中出现多个声明,预期的替换行为是什么?

答案1

替换发生在两种情况下。第一种是 docstrip 步骤,即读取源代码并将源代码.dtx复制到目标.sty/.cls文件;第二种是再次读取代码以排版文档和实现。


在文档删除步骤中l3docstrip.tex使用代码,该代码\moduleOption对原始代码进行了修补docstrip.tex,以包含语法的可能性%<@@=...>。这里docstrip.tex逐行读取输入文件,如果%<@@=...>发现,程序将设置活动模块名称,并对所有后续行使用进行替换\replaceModuleInLine(否则将是一个空定义)。可以使用任意数量的%<@@=...>,代码将更改为新的模块名称。这里替换总是会发生,无论任何设置如何,只要出现%<@@=...>并且\replaceModuleInLine没有被清除。


在排版步骤中,执行替换的命令是\__codedoc_replace_at_at:N。第一个条件是,只有当\g__codedoc_module_name_tl不为空时,即%<@@=name>给出了 a 时,才会进行替换,正如您已经说过的。这是替换宏本身中应用的唯一替换条件,因此它是“最全局”的条件。其他条件则根据上下文应用。

其他出现\__codedoc_replace_at_at:N于:

  • \__codedoc_cmd:nn\cmd,由、\cs和所使用,并且仅当(即选项)为真\tn时才会发生。选项中的默认为 false,因此您需要触发替换。\l__codedoc_cmd_replace_boolreplace\tnreplace\tn[replace=true]

  • \__codedoc_names_get_seq:nN,由 和 两者使用,\__codedoc_function:nnw而和 又由、和环境\__codedoc_macro:nnw使用。替换发生在这些环境的强制参数中,即所描述的变量/函数/宏的列表。在其中任何一个中,如果(即选项) 设置为 false,则会发生替换,因此不会替换。variablefunctionmacro\l__codedoc_names_verb_boolverb\begin{macro}[verb]{\@@_something:n}

  • \__codedoc_xmacro_code:n由环境使用macrocode。在此环境中,替换始终发生(假设%<@@=...>在某处使用),但这里有两种不同的行为。第一种是如果%<@@=....>环境中没有,则替换正常发生。第二种是如果环境中有。在这种情况下,将抓取%<@@=...>到的代码,将其全部替换为当前模块名称,更新模块名称,然后继续扫描代码以查找下一个或环境的末尾。直到最近,如果在单个环境中发现 多个代码,代码就会中断(在单独的环境中仍可能出现任意多个代码)。这个问题已经修复(%<@@=...>@@%<@@=...>
    %<@@=...>macrocode97daab8) 及更新版本l3doc(晚于 2019 年 6 月 27 日)应该具有与 相同的替换行为l3docstrip


l3doc对于2019 年 6 月 27 日之前的版本:

macrocode环境包含时%<@@=...>,它将全局更改 的值\g__codedoc_module_name_tl,并且从那时起将使用新值,因此您可以%<@@=....>在文档中任意使用多个 。例如,此源(假设%<@@=...>之前未使用):

%    \begin{macrocode}
\cs_new:Npn \@@_world:n {}
%<@@=hello>
\cs_new:Npn \@@_world:n {}
%    \end{macrocode}

变成这样的代码:

\cs_new:Npn \@@_world:n {}
\cs_new:Npn \hello_world:n {}

%<@@=...>但是每个环境预计只使用一次macrocode,因此该来源:

%    \begin{macrocode}
\cs_new:Npn \@@_world:n {}
%<@@=hello>
\cs_new:Npn \@@_world:n {}
%<@@=goodbye>
\cs_new:Npn \@@_world:n {}
%    \end{macrocode}

中断 :-)
为:

! Missing { inserted.
<to be read again> 
                   \sb 
l.228 %    \end{macrocode}

?

因为代码用 替换了@@%<@@=goodbye>__hello,不知道这是名称空间的另一次更改,因此造成混乱。\__codedoc_xmacro_code:n和的轻微更改使 的\__codedoc_xmacro_code:w行为与替换 的行为l3cls相同(放在您的序言中):l3docstrip@@

\group_begin:
  \char_set_catcode_letter:N \@
  \char_set_catcode_active:N \<
  \char_set_catcode_active:N \>
  \let\tmpa\__codedoc_xmacro_code:n
  \cs_gset_protected:Npn \__codedoc_xmacro_code:n #1
    {
      \tl_clear:N \l__codedoc_tmpa_tl
      \tl_if_in:nnTF {#1} { < @ @ = }
        { \__codedoc_xmacro_code:w #1 < @ @ = \q_recursion_tail > \q_recursion_stop }
        {
          \tl_set:Nn \l__codedoc_tmpa_tl {#1}
          \__codedoc_detect_internals:N \l__codedoc_tmpa_tl
          \__codedoc_replace_at_at:N \l__codedoc_tmpa_tl
          \tl_use:N \l__codedoc_tmpa_tl
        }
    }
  \cs_gset_protected:Npn \__codedoc_xmacro_code:w #1 < @ @ = #2 >
    {
      \tl_set:Nn \l__codedoc_tmpb_tl {#1}
      \__codedoc_detect_internals:N \l__codedoc_tmpb_tl
      \__codedoc_replace_at_at:N \l__codedoc_tmpb_tl
      \tl_put_right:NV \l__codedoc_tmpa_tl \l__codedoc_tmpb_tl
      \quark_if_recursion_tail_stop_do:nn {#2}
        { \tl_use:N \l__codedoc_tmpa_tl }
      \tl_gset:Nn \g__codedoc_module_name_tl {#2}
      \tl_put_right:Nn \l__codedoc_tmpa_tl { < \text { \verbatim@font @ @ = #2 } > }
      \__codedoc_xmacro_code:w
    }
\group_end:

上述代码使得%<@@=...>在一个macrocode环境中拥有任意多个成为可能。

相关内容