diff --git a/emulated_nodes.lua b/emulated_nodes.lua new file mode 100644 index 0000000..c7f6135 --- /dev/null +++ b/emulated_nodes.lua @@ -0,0 +1,36 @@ +local properties = {} +local subtypes = { + noad = {[0] = 'ord', 'opdisplaylimits', 'oplimits', 'opnolimits', 'bin', 'rel', 'open', 'close', 'punct', 'inner', 'under', 'over', 'vcenter'}, + fence = {[0] = 'unset', 'left', 'middle', 'right', 'no'}, + radical = {[0] = 'radical', 'uradical', 'uroot', 'uunderdelimiter', 'uoverdelimiter', 'udelimiterunder', 'udelimiterover'}, +} +local function traverse_iter(context, head) + if head == nil then + head = context + else + head = head.next + end + if head then + return head, head.id, head.subtype + else + return nil + end +end +node = { + get_properties_table = function() + return properties + end, + id = function(name) + return name + end, + is_node = function(node) + return type(node) == 'table' and node.id and true or false + end, + subtypes = function(id) + return subtypes[id] + end, + traverse = function(head) + return traverse_iter, head, nil + end, +} +tex.nulldelimiterspace = tex.nulldelimiterspace or 78643 -- 1.2pt diff --git a/parse_showlists.lua b/parse_showlists.lua index 7d15f81..fc8cb41 100644 --- a/parse_showlists.lua +++ b/parse_showlists.lua @@ -11,8 +11,8 @@ local delimiter_code = '"' * (l.R('09', 'AF')^1 / function(s) local code = tonumber(s, 16) return {id = 'delim', small_fam = (code >> 20) & 0xF, - small_char = (code >> 16) & 0xFF, - large_fam = (code >> 4) & 0xF, + small_char = (code >> 12) & 0xFF, + large_fam = (code >> 8) & 0xF, large_char = code & 0xFF, } end) @@ -22,6 +22,8 @@ local math_char = l.Ct('\\fam' * l.Cg(l.R'09'^1 / tonumber, 'fam') * ' ' * l.Cg( local simple_noad = l.Ct( '\\math' * l.Cg( 'ord' * l.Cc(0) + + 'op\\limits' * l.Cc(2) + + 'op\\nolimits' * l.Cc(3) + 'op' * l.Cc(1) + 'bin' * l.Cc(4) + 'rel' * l.Cc(5) @@ -29,16 +31,21 @@ local simple_noad = l.Ct( + 'close' * l.Cc(7) + 'punct' * l.Cc(8) + 'inner' * l.Cc(9) + + 'under' * l.Cc(10) + + 'over' * l.Cc(11) + + 'vcenter' * l.Cc(12) , 'subtype') * l.Cg(l.Cc'noad', 'id') - + '\\radical' * l.Cg(delimiter_code, 'left') * l.Cg(l.Cc'radical', 'id') - + '\\accent' * l.Cg(math_char, 'accent') * l.Cg(l.Cc'accent', 'id') + + '\\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') + l.Cg('\\left' * l.Cc(1) + '\\middle' * l.Cc(2) - + '\\right' * l.Cc(3), 'subtype') * l.Cg(delimiter_code, 'delim') * l.Cg(l.Cc'fence', 'id') + + '\\right' * l.Cc(3), 'subtype') * l.Cg(delimiter_code, 'delim') * l.Cg(l.Cc(0), 'class') * l.Cg(l.Cc'fence', 'id') ) * -1 -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) +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')) * -1 local parse_list @@ -53,7 +60,7 @@ end function parse_list(lines, i, prefix) i = i or 1 prefix = prefix or '' - local list = {} + local head, last while true do local line = lines[i] if not line or line:sub(1, #prefix) ~= prefix then break end @@ -62,23 +69,26 @@ function parse_list(lines, i, prefix) 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 .. '_') - list[#list + 1] = simple + if last then + simple.prev, last.next = last, simple + end + last = simple 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 .. '/') - list[#list + 1] = fraction + if last then + fraction.prev, last.next = last, fraction + end + last = fraction else print('unknown noad ' .. line:sub(#prefix+1)) i = i + 1 end end + if not head then head = last end end - return list, i + return head, i end -local lines = {} -for l in io.lines() do - lines[#lines + 1] = l ~= '' and l or nil -end -print(require'inspect'((parse_list(lines)))) +return parse_list diff --git a/showlists_test.lua b/showlists_test.lua new file mode 100644 index 0000000..78680a9 --- /dev/null +++ b/showlists_test.lua @@ -0,0 +1,79 @@ +local parse_showlists = require'parse_showlists' +local l = lpeg or require'lpeg' + +local lines = l.Ct((l.C((1-l.P'\n')^0) * '\n')^0 * l.C(l.P(1)^1)^-1):match( +[[\mathinner +.\left"28300 +.\mathord +..\fraction, thickness 0.0, left-delimiter "28300, right-delimiter "29301 +..\\mathord +..\.\fam0 1 +../\mathord +../.\fam0 1 +.\mathord +..\fam1 x +._\mathord +._.\fam0 1 +._\mathord +._.\fam1 = +._\mathord +._.\fam0 2 +.\mathbin +..\fam0 + +.\accent\fam0 _ +..\fam1 z +._\fam0 0 +.\middle"26A30C +.\mathrel +..\fam0 = +.\mathop\limits +..\fam3 P +.\mathop\nolimits +..\fam3 P +.\mathop +..\fam3 P +.^\mathord +.^.\fam0 1 +.^\mathord +.^.\fam0 0 +.^\mathord +.^.\fam0 0 +.^\mathord +.^.\fam0 0 +._\mathord +._.\fam1 i +._\mathrel +._.\fam0 = +._\mathord +._.\fam0 1 +.\mathord +..\fraction, thickness = default +..\\mathbin +..\.\fam2 ^^@ +..\\mathord +..\.\fam1 p +..\\mathbin +..\.\fam2 ^^F +..\\radical"270370 +..\.\mathord +..\..\fam1 p +..\.\mathbin +..\..\fam2 ^^@ +..\.\mathord +..\..\fam0 4 +..\.\mathord +..\..\fam1 q +../\mathord +../.\fam0 2 +.\right"0 +]]) + +local parsed = parse_showlists(lines) +require'emulated_nodes' +local convert = require'luamml-convert' +local mappings = require'luamml-legacy-mappings' +convert.register_family(1, mappings.oml) +convert.register_family(2, mappings.oms) +convert.register_family(3, mappings.omx) +local to_xml = require'luamml-xmlwriter' +print(to_xml(convert.make_root(convert.process(parsed), 2)))