It is only possible to dissect math lists when using LuaTeX. For instance, you can use the mlist_to_hlist
callback. The code below emulates \showlists
for math lists, to some limited extent: for instance \radical
is not taken care of.
Note that I am very much a LuaTeX newbie, so the code is probably very far from optimal, and doesn't follow standard best practices.
\begingroup
\catcode`~=12
\catcode`#=12
\escapechar=-1
\edef\\{\string\\}
\directlua
{%
local my = {}
my.node = {}
function my.node.tostring(t, newline)
if t == nil then
return ''
end
if my[node.type(t.id)] ~= nil then
return my[node.type(t.id)].tostring(t, newline)
else
local result = newline .. node.type(t.id)
for _, v in ipairs(node.fields(t.id)) do
if v == 'id' or t[v] == nil then else
local value = t[v]
if type(value) == "userdata" then
value = node.type(value.id)
end
result = result .. ', ' .. v .. ': ' .. value
end
end
return result
end
end
%
my.noad = {}
my.noad.subtypes = {'op', nil, nil, 'bin', 'rel', 'open',
'close', 'punct', 'inner', [0] = 'ord'}
function my.noad.subtype(subtype)
if my.noad.subtypes[subtype] == nil then
return '\\\\math?'
else
return '\\\\math' .. my.noad.subtypes[subtype]
end
end
function my.noad.tostring(t, newline)
local result = newline .. my.noad.subtype(t.subtype)
if t.attr ~= nil then
result = result .. t.attr
end
result = result
.. my.node.tostring(t.nucleus, newline .. '.')
.. my.node.tostring(t.sup, newline .. '^')
.. my.node.tostring(t.sub, newline .. '_')
return result
end
%
my.math_char = {}
function my.math_char.tostring(t, newline)
return newline .. '\\\\fam' .. t.fam .. ' ' .. string.char(t.char)
end
%
my.fence = {}
function my.fence.tostring(t, newline)
fencename = ({'\\\\left', '\\\\middle', '\\\\right'})[t.subtype]
return newline .. fencename .. my.node.tostring(t.delim, ' ')
end
%
my.delim = {}
function my.delim.tostring(t, newline)
return
newline
.. 'small: \\\\fam'
.. t.small_fam
.. ' '
.. (t.small_char == 0 and '^'..'^@' or string.char(t.small_char))
.. ', large: \\\\fam'
.. t.large_fam
.. ' '
.. (t.large_char == 0 and '^'..'^@' or string.char(t.large_char))
end
%
% subtype and attr ignored for sub_mlist?
my.sub_mlist = {}
function my.sub_mlist.tostring(mlist, newline)
return my.mlist.tostring(mlist.head, newline)
end
%
my.mlist = {}
function my.mlist.tostring(h, newline)
local result = ''
for t in node.traverse(h) do
result = result .. my.node.tostring(t, newline)
end
return result
end
%
callback.register
(
"mlist_to_hlist",
function (h, d, p)
local tab = {}
texio.write_nl('\\n')
my.mlist.tostring(h, '\\n'):gsub('([^\\n]+)', texio.write_nl)
texio.write_nl('\\n')
return node.mlist_to_hlist(h, d, p)
end
)
}
\endgroup
abc $ \mathord{\mathord{a}^b}^b \sum + = (),\left(2\middle|3\right)\sqrt{a}$ f
\bye