# Is there a way to dissect math lists?

In the course of trying to answer this question, I now realize that I need to be able to construct a math list and then check if it consists of a single character atom.

What I would like to be able to do is to deconstruct the math list similar to "Dissecting paragraphs with \lastbox" in TeX by Topic.

As described in this answer, one can use \showlists to write a representation of the partial lists to the log file. That doesn't seem to help me unless I want to parse the log file. (I don't.)

-

I am pretty sure you can do something that extends the TeX by Topic with \lastbox and box unrolling after the paragraph has completed, but (besides being very tedious) that will not give you access to the actual math list, only to its converted format as a nested tree of \hbox and \vbox-es.

TeX82 does not offer access to the math list other than via \showlists (and for once I think a luatex answer would not really help).

-
I'm not sure how to deal with the \mathon/\mathoff itemsssssss that appear in the boxes. For example, \hbox{$x$} gives \mathon, \teni x, and \mathoff in plain TeX. I guess I haven't played with box unrolling much to know if there's anything that can be done to see that this is just a \teni x, for example. If I could do that, I think that'd be sufficient. – TH. Oct 8 '10 at 10:35
To follow up on that, \hbox{$x$\setbox0\lastbox\showbox0} tells me that \box0 is void. This makes sense since \mathoff is not a box. I might just be out of luck here. – TH. Oct 8 '10 at 10:47
@TH Yes, I fear you are right. Parsing the log file it is, then – Taco Hoekwater Oct 8 '10 at 12:00
@TH: In Chapter 21 of the TeXbook it says that \lastbox is always void in math mode. – Hendrik Vogt Oct 8 '10 at 13:33
@TH: The following might be worth pointing out: It is not only that \mathoff is not a box, it is not even a TeX command. – Hendrik Vogt Oct 8 '10 at 14:55

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.subtypes = {'op', nil, nil, 'bin', 'rel', 'open',
'close', 'punct', 'inner', [0] = 'ord'}
if my.noad.subtypes[subtype] == nil then
return '\\\\math?'
else
return '\\\\math' .. my.noad.subtypes[subtype]
end
end
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)
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

-