mathml/pdfmml-showlists.lua

147 lines
5.6 KiB
Lua
Raw Normal View History

require'pdfmml-emulate-node'
local properties = node.get_properties_table()
2021-05-28 18:25:25 +02:00
local l = lpeg or require'lpeg'
local hex_digit = l.R('09', 'af')
local function hex_to_int(s) return tonumber(s, 16) end
local tex_char = l.Cg('^^' * (hex_digit * hex_digit / hex_to_int
+ l.R'\0\x3F' / function(s) return s:byte() + 0x40 end
+ l.R'\x40\x7F' / function(s) return s:byte() - 0x40 end)
+ l.P(1) / string.byte)
2021-05-31 13:25:08 +02:00
local scaled = l.P'-'^-1 * l.R'09'^1 * '.' * l.R'09'^1 / function(s) return (tonumber(s * 0x10000) + .5) // 1 end
2021-05-28 18:25:25 +02:00
local delimiter_code = '"' * (l.R('09', 'AF')^1 / function(s)
local code = tonumber(s, 16)
return {id = 'delim',
small_fam = (code >> 20) & 0xF,
2021-05-29 12:39:24 +02:00
small_char = (code >> 12) & 0xFF,
large_fam = (code >> 8) & 0xF,
2021-05-28 18:25:25 +02:00
large_char = code & 0xFF,
}
end)
local math_char = l.Ct('\\fam' * l.Cg(l.R'09'^1 / tonumber, 'fam') * ' ' * l.Cg(tex_char, 'char') * l.Cg(l.Cc'math_char', 'id'))
local simple_noad = l.Ct(
'\\math' * l.Cg(
'ord' * l.Cc(0)
+ 'open' * l.Cc(6)
2021-05-29 12:39:24 +02:00
+ 'op\\limits' * l.Cc(2)
+ 'op\\nolimits' * l.Cc(3)
2021-05-28 18:25:25 +02:00
+ 'op' * l.Cc(1)
+ 'bin' * l.Cc(4)
+ 'rel' * l.Cc(5)
+ 'close' * l.Cc(7)
+ 'punct' * l.Cc(8)
+ 'inner' * l.Cc(9)
2021-05-29 12:39:24 +02:00
+ 'under' * l.Cc(10)
+ 'over' * l.Cc(11)
+ 'vcenter' * l.Cc(12)
2021-05-28 18:25:25 +02:00
, 'subtype') * l.Cg(l.Cc'noad', 'id')
2021-05-29 12:39:24 +02:00
+ '\\radical' * l.Cg(delimiter_code, 'left') * l.Cg(l.Cc(0), 'subtype') * l.Cg(l.Cc'radical', 'id')
+ '\\accent' * l.Cg(math_char, 'accent') * l.Cg(l.Cc(0), 'subtype') * l.Cg(l.Cc'accent', 'id')
2021-05-28 18:25:25 +02:00
+ l.Cg('\\left' * l.Cc(1)
+ '\\middle' * l.Cc(2)
2021-05-30 20:37:03 +02:00
+ '\\right' * l.Cc(3), 'subtype') * l.Cg(delimiter_code, 'delim')
* l.Cg(l.Cc(0), 'options') * l.Cg(l.Cc(0), 'height')
* l.Cg(l.Cc(0), 'depth') * l.Cg(l.Cc(0), 'height')
* l.Cg(l.Cc(-1), 'class') * l.Cg(l.Cc'fence', 'id')
2021-05-29 13:34:38 +02:00
+ '\\' * l.Cg(
'display' * l.Cc(0)
+ 'text' * l.Cc(2)
+ 'scriptscript' * l.Cc(6)
+ 'script' * l.Cc(4), 'subtype') * l.Cg('style', 'id')
2021-05-31 13:25:08 +02:00
+ '\\mkern' * l.Cg(scaled, 'kern') * 'mu' * l.Cg(l.Cc(99), 'subtype') * l.Cg(l.Cc'kern', 'id')
+ '\\kern' * l.Cg(' ' * l.Cc(1) + l.Cc(0), 'subtype') * l.Cg(scaled, 'kern') * (' (for ' * (l.R'az' + l.S'/\\') * ')')^-1 * l.Cg(l.Cc'kern', 'id')
2021-05-28 18:25:25 +02:00
) * -1
2021-05-29 12:39:24 +02:00
local fraction_noad = l.Ct('\\fraction, thickness '
* l.Cg('= default' * l.Cc(0x40000000) + scaled, 'width')
* l.Cg(', left-delimiter ' * delimiter_code, 'left')^-1 * l.Cg(', right-delimiter ' * delimiter_code, 'right')^-1
* l.Cg(l.Cc'fraction', 'id'))
2021-05-28 18:25:25 +02:00
* -1
2021-05-29 13:34:38 +02:00
local mathchoice_noad = l.Ct('\\mathchoice' * l.Cg(l.Cc'choice', 'id') * -1)
local mark_whatsit = '\\write-{LUAMML_MARK:' * (l.R'09'/tonumber) * ':'
2021-05-28 18:25:25 +02:00
local parse_list
local function parse_kernel(lines, i, prefix)
local line = lines[i]
if not line or line:sub(1, #prefix) ~= prefix then return nil, i end
local result = math_char:match(lines[i], #prefix + 1)
if result then return result, i+1 end
result, i = parse_list(lines, i, prefix)
return {list = result, id = 'sub_mlist'}, i
end
function parse_list(lines, i, prefix, marks)
2021-05-28 18:25:25 +02:00
i = i or 1
prefix = prefix or ''
2021-05-29 12:39:24 +02:00
local head, last
local mark_environment = {}
local current_mark, current_count, current_offset
2021-05-28 18:25:25 +02:00
while true do
local skip
2021-05-28 18:25:25 +02:00
local line = lines[i]
if not line or line:sub(1, #prefix) ~= prefix then break end
local simple = simple_noad:match(line, #prefix+1)
if simple then
simple.nucleus, i = parse_kernel(lines, i + 1, prefix .. '.')
simple.sup, i = parse_kernel(lines, i, prefix .. '^')
simple.sub, i = parse_kernel(lines, i, prefix .. '_')
2021-05-29 12:39:24 +02:00
if last then
simple.prev, last.next = last, simple
end
last = simple
2021-05-28 18:25:25 +02:00
else
local fraction = fraction_noad:match(line, #prefix+1)
if fraction then
fraction.num, i = parse_kernel(lines, i + 1, prefix .. '\\')
fraction.denom, i = parse_kernel(lines, i, prefix .. '/')
2021-05-29 12:39:24 +02:00
if last then
fraction.prev, last.next = last, fraction
end
last = fraction
2021-05-28 18:25:25 +02:00
else
2021-05-29 13:34:38 +02:00
local mathchoice = mathchoice_noad:match(line, #prefix+1)
if mathchoice then
mathchoice.display, i = parse_list(lines, i + 1, prefix .. 'D')
mathchoice.text, i = parse_list(lines, i, prefix .. 'T')
mathchoice.script, i = parse_list(lines, i, prefix .. 'S')
mathchoice.scriptscript, i = parse_list(lines, i, prefix .. 's')
if last then
mathchoice.prev, last.next = last, mathchoice
end
last = mathchoice
else
skip = true
local mark = mark_whatsit:match(line)
if mark then
local mark_table = assert(load('return {' .. assert(marks[mark], 'Undefined mark encountered') .. '}', nil, 't', mark_environment))()
current_mark, current_count, current_offset = mark_table, mark_table.count or 1, mark_table.offset or 1
i = i + 1
else
print(line, prefix, i)
print('unknown noad ' .. line:sub(#prefix+1))
i = i + 1
end
2021-05-29 13:34:38 +02:00
end
2021-05-28 18:25:25 +02:00
end
end
2021-05-29 12:39:24 +02:00
if not head then head = last end
if not skip and current_mark then
current_count = current_count - 1
current_offset = current_offset - 1
if current_offset == 0 then
properties[current_mark.nucleus and last.nucleus or last] = {mathml_core = current_mark.core}
else
properties[last] = {mathml_core = false}
end
if current_count == 0 then current_mark = nil end
end
2021-05-28 18:25:25 +02:00
end
2021-05-29 12:39:24 +02:00
return head, i
2021-05-28 18:25:25 +02:00
end
2021-05-29 12:39:24 +02:00
return parse_list