local lpeg = lpeg local namespace_lookup: {string: string} = { pdf = "http://iso.org/pdf/ssn", pdf2 = "http://iso.org/pdf2/ssn", mathml = "http://www.w3.org/1998/Math/MathML", latex = "https://www.latex-project.org/ns/dflt", ['latex-book'] = "https://www.latex-project.org/ns/book", user = "data:something-custom", } local anonymous_namespace = namespace_lookup.pdf local unmapped_namespaces = { [namespace_lookup.pdf] = true, [namespace_lookup.pdf2] = true, [namespace_lookup.mathml] = true, } local delim = lpeg.P',' * lpeg.P' '^0 local comment = lpeg.P'%' * (1-lpeg.P'\n')^0 * lpeg.P'\n' local word = lpeg.R('az', 'AZ', '09', '--')^1 local line = lpeg.Ct(lpeg.Cg(word, 'name') * delim * lpeg.Cg(word, 'mapped') * delim * lpeg.Cg(word/namespace_lookup, 'ns') * delim * (lpeg.Cg(word, 'class') * delim)^-1) * (lpeg.P'\n' + comment) local document = lpeg.Ct((comment + line)^0) * (lpeg.P(-1) + lpeg.Cp()) local record ParsedEntry name: string mapped: string ns: string class: string end local function parse_ns_file(file_tag: string): {ParsedEntry} local filename = assert(kpse.find_file(string.format('tagpdf-ns-%s.def', file_tag)), 'file not found') local f = assert(io.open(filename, 'r')) local text = f:read'a' assert(f:close()) local result, err_offset = document:match(text) if err_offset then print('!!! ERROR', filename, err_offset) end return result as {ParsedEntry} end local parsed = {} for _, ns in ipairs{'pdf', 'pdf2', 'mathml', 'latex-book'} do parsed[namespace_lookup[ns]] = parse_ns_file(ns) end -- parsed[namespace_lookup.latex] = parse_ns_file('latex', namespace_lookup.latex, namespace_lookup) parsed[namespace_lookup.latex] = parse_ns_file('latex-lab') local role_maps: {string | boolean: {string: string | {string}}} = {} for k, v in pairs(parsed) do if not unmapped_namespaces[k] then local ns_role_map: {string: string | {string}} = {} role_maps[k] = ns_role_map for _, entry in ipairs(v) do local mapped_ns = entry.ns if mapped_ns == anonymous_namespace then ns_role_map[entry.name] = entry.mapped else ns_role_map[entry.name] = {entry.mapped, mapped_ns} end end end end local function add_mapping(source_tag: string, source_ns: string | boolean, target_tag: string, target_ns: string | boolean) local ns_role_map = role_maps[source_ns] if not ns_role_map then ns_role_map = {} role_maps[source_ns] = ns_role_map end if target_ns is string and target_ns ~= anonymous_namespace then ns_role_map[source_tag] = {target_tag, target_ns} else ns_role_map[source_tag] = target_tag end end local default_namespaces = {} for _, ns in ipairs{'mathml', 'latex-book', 'latex', 'pdf', 'pdf2'} do local resolved = namespace_lookup[ns] for _, tag in ipairs(parsed[resolved]) do default_namespaces[tag.name] = resolved end end return { namespace_lookup = namespace_lookup, role_maps = role_maps, add_mapping = add_mapping, default_namespaces = default_namespaces, }