检查宏是否完全可扩展

检查宏是否完全可扩展

问题

有没有办法检查宏是否完全可扩展(或者更确切地说“在仅扩展上下文中是安全的”[1])?

考虑以下代码:

\def\a{Just a string}
\def\b{\a}
\def\c{\def\unsafe}
\def\d{\c}

我如何检查哪些宏 (ad) 在仅扩展上下文中是安全的?通过查看它们,我知道 a 和 b 是安全的,而 c 和 d 不是,但如果我想知道我自己没有编写的宏的相同情况,这可能会非常有用。


背景

我正在研究一种方法来检测某些输入是否是 PGF 中的有效数字。为此,我开发了这种方法它利用将输入传递到\pgfmathfloatparsenumber
我遇到的问题是,所述宏似乎以某种方式设法扩展输入,直到出现错误(如果输入在仅扩展的上下文中实际上不安全)。我尝试使用和类似方法protectednoexpand但不知何故 PGF 设法绕过了这些。

因此,这个想法是在实际将输入传递给 PGF 之前检查输入是否安全。问题是:我不知道该怎么做...

答案1

我是否听到有人说这是不可能的?

以下定义了\ifexpandable检查标记是否可扩展的内容(实际上您也可以给它一个标记列表,它会检查所有标记是否都可扩展)。我不知道这是否有任何副作用。需要 LuaTeX。

\documentclass{article}

\def\ifexpandablelua{%
  \directlua{
    local t = token.scan_toks()
    local b = true
    for n,v in ipairs(t) do
        local is_assign =
            string.find(v.cmdname, "assign") \string~= nil or
            string.find(v.cmdname, "def") \string~= nil or
            string.find(v.cmdname, "let") \string~= nil or
            string.find(v.cmdname, "box") \string~= nil
        local is_call = string.find(v.cmdname, "call") \string~= nil
        print(v.cmdname, is_assign, is_call)
        b = b and (not is_assign) and (is_call and v.expandable or true)
    end
    if b then
        tex.sprint("\string\\iftrue")
    else
        tex.sprint("\string\\iffalse")
    end
  }%
}

\def\ifexpandable#1{%
  \expandafter\ifexpandablelua\expandafter{\romannumeral-`0#1}%
}

\begin{document}

\def\a{Just a string}
\def\b{\a}
\def\c{\def\unsafe}
\def\d{\c}

\edef\isexpandable{%
  \ifexpandable\section
    expandable
  \else
    not expandable
  \fi
}
\isexpandable

\end{document}

相关内容