UNPKG

@unified-latex/unified-latex-util-catcode

Version:

Tools for manipulating unified-latex ASTs

1 lines 23.8 kB
{"version":3,"file":"index.cjs","names":[],"sources":["../libs/find-region.ts","../libs/regions.ts","../libs/reparse-macro-names.ts","../libs/special-regions.ts","../index.ts"],"sourcesContent":["import * as Ast from \"@unified-latex/unified-latex-types\";\nimport { Region } from \"./regions\";\n\n/**\n * Find all contiguous segments in the array that are between start and end blocks.\n * The `start` and `end` are functions that determine when a region starts and ends.\n */\nexport function findRegionInArray(\n tree: Ast.Node[],\n start: (node: Ast.Node) => boolean,\n end: (node: Ast.Node) => boolean\n): Region[] {\n const ret: Region[] = [];\n let currRegion: Region = { start: undefined as any, end: tree.length };\n for (let i = 0; i < tree.length; i++) {\n const node = tree[i];\n if (start(node)) {\n currRegion.start = i;\n }\n if (end(node)) {\n currRegion.end = i + 1;\n ret.push(currRegion);\n currRegion = { start: undefined as any, end: tree.length };\n }\n }\n\n if (currRegion.start != null) {\n // Regions don't necessarily have to encounter an `end` to end.\n ret.push(currRegion);\n }\n return ret;\n}\n","import * as Ast from \"@unified-latex/unified-latex-types\";\n\nexport type Region = { start: number; end: number };\n\n/**\n * Given `regions`, a list of `Region`s (not necessarily ordered, possibly overlapping), return a list of in-order,\n * non-overlapping regions and a corresponding list containing a set of the original `Region`s that the new region\n * is a subset of.\n */\nexport function refineRegions(regions: Region[]): {\n regions: Region[];\n regionsContainedIn: Set<Region>[];\n} {\n const _regions = [...regions];\n _regions.sort((a, b) => a.start - b.start);\n const cutPointsSet = new Set(_regions.flatMap((r) => [r.start, r.end]));\n const cutPoints = Array.from(cutPointsSet);\n cutPoints.sort((a, b) => a - b);\n\n const retRegions: Region[] = [];\n const retRegionsContainedIn: Set<Region>[] = [];\n\n // We will be checking what regions we are completely contained in.\n // Because `_regions` is sorted by start, `seekIndex` will be incremented\n // by end, so that we don't do too much array testing.\n let seekIndex = 0;\n for (let i = 0; i < cutPoints.length - 1; i++) {\n const start = cutPoints[i];\n const end = cutPoints[i + 1];\n const region = { start, end };\n const regionContainedIn: Set<Region> = new Set();\n\n let encounteredEndPastStart = false;\n for (let j = seekIndex; j < _regions.length; j++) {\n const superRegion = _regions[j];\n if (superRegion.end >= region.start) {\n encounteredEndPastStart = true;\n }\n if (!encounteredEndPastStart && superRegion.end < region.start) {\n // In this case, the region (and all regions that came before)\n // end before the region we are testing, so we may safely skip past it\n // from here on out.\n seekIndex = j + 1;\n continue;\n }\n\n if (superRegion.start > end) {\n // Because `_regions` is sorted, we can stop here\n break;\n }\n if (\n superRegion.start <= region.start &&\n superRegion.end >= region.end\n ) {\n encounteredEndPastStart = true;\n regionContainedIn.add(superRegion);\n }\n }\n\n if (regionContainedIn.size > 0) {\n // We only count if we are contained in a subregion\n retRegions.push(region);\n retRegionsContainedIn.push(regionContainedIn);\n }\n }\n\n return { regions: retRegions, regionsContainedIn: retRegionsContainedIn };\n}\n\n/**\n * Split an array up into the disjoint regions specified by `regionRecord`.\n * Returned is a list of tuples, the first item being the key of `regionRecord` if there\n * was a corresponding region, or `null` if there was no corresponding region.\n *\n * This function assumes that the regions in `regionRecord` are disjoint and fully contained\n * within the bounds of `array`.\n */\nexport function splitByRegions<\n T,\n RegionRecord extends Record<string, Region[]>,\n>(array: T[], regionsRecord: RegionRecord) {\n const ret: [keyof RegionRecord | null, T[]][] = [];\n\n const indices = [0, array.length];\n const reverseMap: Record<string, keyof RegionRecord> = {};\n for (const [key, records] of Object.entries(regionsRecord)) {\n indices.push(\n ...records.flatMap((r) => {\n reverseMap[\"\" + [r.start, r.end]] = key;\n return [r.start, r.end];\n })\n );\n }\n indices.sort((a, b) => a - b);\n\n for (let i = 0; i < indices.length - 1; i++) {\n const start = indices[i];\n const end = indices[i + 1];\n if (start === end) {\n continue;\n }\n const regionKey = reverseMap[\"\" + [start, end]];\n\n ret.push([regionKey || null, array.slice(start, end)]);\n }\n\n return ret;\n}\n","import * as Ast from \"@unified-latex/unified-latex-types\";\nimport { match } from \"@unified-latex/unified-latex-util-match\";\nimport { EXIT, visit } from \"@unified-latex/unified-latex-util-visit\";\n\n/**\n * Escape a string so that it can be used to build a regular expression.\n *\n * From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\n */\nfunction escapeRegExp(str: string) {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"); // $& means the whole matched string\n}\n\n/**\n * Build a regular expression that matches everything up to the first non-allowed symbol.\n */\nfunction buildWordRegex(allowedSet: Set<string>): RegExp {\n // /\\p{L}/ matches all letters, including unicode letters. We join this with\n // everything allowed in our set to form a regexp like\n // /(\\p{L}|_|:)*/u\n // The `u` at the end allows unicode characters to be matched.\n const regexpStr = `^(${[\"\\\\p{L}\"]\n .concat(Array.from(allowedSet).map(escapeRegExp))\n .join(\"|\")})*`;\n return new RegExp(regexpStr, \"u\");\n}\n\n/**\n * Checks whether the array has a macro that could be reparsed given the `allowedTokens` but\n * do not do any reparsing. This function can be used in auto-detection schemes to determine if\n * macro names should actually be reparsed.\n */\nexport function hasReparsableMacroNamesInArray(\n tree: Ast.Node[],\n allowedTokens: Set<string>\n): boolean {\n for (let i = 0; i < tree.length; i++) {\n const macro = tree[i];\n const string = tree[i + 1];\n if (match.anyMacro(macro) && match.anyString(string)) {\n // There are two options. Either the macro ends with the special character,\n // e.g. `\\@foo` or the special character starts the next string, e.g. `\\foo@`.\n if (\n allowedTokens.has(\n macro.content.charAt(macro.content.length - 1)\n ) ||\n allowedTokens.has(string.content.charAt(0))\n ) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Checks whether `tree` has a macro that could be reparsed given the `allowedTokens` but\n * do not do any reparsing. This function can be used in auto-detection schemes to determine if\n * macro names should actually be reparsed.\n */\nexport function hasReparsableMacroNames(\n tree: Ast.Ast,\n allowedTokens: string | Set<string>\n): boolean {\n if (typeof allowedTokens === \"string\") {\n allowedTokens = new Set(allowedTokens.split(\"\"));\n }\n // Recast so typescript doesn't complain\n const _allowedTokens = allowedTokens;\n for (const v of _allowedTokens) {\n if (v.length > 1) {\n throw new Error(\n `Only single characters are allowed as \\`allowedTokens\\` when reparsing macro names, not \\`${v}\\`.`\n );\n }\n }\n\n let ret = false;\n visit(\n tree,\n (nodes) => {\n if (hasReparsableMacroNamesInArray(nodes, _allowedTokens)) {\n ret = true;\n return EXIT;\n }\n },\n { includeArrays: true, test: Array.isArray }\n );\n return ret;\n}\n\n/**\n * Reparses all macro names in the array so that they may optionally include characters listed in `allowedTokens`.\n * This is used, for example, when parsing expl3 syntax which allows `_` to be used in a macro name (even though\n * `_` is normally stops the parsing for a macro name).\n */\nexport function reparseMacroNamesInArray(\n tree: Ast.Node[],\n allowedTokens: Set<string>\n) {\n const regex = buildWordRegex(allowedTokens);\n let i = 0;\n while (i < tree.length) {\n const macro = tree[i];\n const string = tree[i + 1];\n if (\n match.anyMacro(macro) &&\n // The _^ macros in math mode should not be extended no-matter what;\n // So we check to make sure that the macro we're dealing with has the default escape token.\n (macro.escapeToken == null || macro.escapeToken === \"\\\\\") &&\n match.anyString(string) &&\n // There are two options. Either the macro ends with the special character,\n // e.g. `\\@foo` or the special character starts the next string, e.g. `\\foo@`.\n (allowedTokens.has(\n macro.content.charAt(macro.content.length - 1)\n ) ||\n allowedTokens.has(string.content.charAt(0)))\n ) {\n // There might be a number somewhere in the string. If so, we should\n // break the string apart at that number\n const match = string.content.match(regex);\n const takeable = match ? match[0] : \"\";\n if (takeable.length > 0) {\n if (takeable.length === string.content.length) {\n // The whole string can be appended to the macro name\n macro.content += string.content;\n tree.splice(i + 1, 1);\n\n // Preserve the source location if available\n if (macro.position && string.position?.end) {\n macro.position.end = string.position.end;\n }\n } else {\n // Only part of the string can be appended to the macro name\n macro.content += takeable;\n string.content = string.content.slice(takeable.length);\n\n // Preserve the source location if available\n if (macro.position?.end) {\n macro.position.end.offset += takeable.length;\n macro.position.end.column += takeable.length;\n }\n if (string.position?.start) {\n string.position.start.offset += takeable.length;\n string.position.start.column += takeable.length;\n }\n }\n } else {\n i++;\n }\n } else {\n ++i;\n }\n }\n}\n\n/**\n * Reparses all macro names so that they may optionally include characters listed in `allowedTokens`.\n * This is used, for example, when parsing expl3 syntax which allows `_` to be used in a macro name (even though\n * `_` is normally stops the parsing for a macro name). Thus, a macro `\\foo_bar:Nn` would be parsed as having\n * the name `foo_bar:Nn` rather than as `foo` followed by the strings `_`, `bar`, `:`, `Nn`.\n */\nexport function reparseMacroNames(\n tree: Ast.Ast,\n allowedTokens: string | Set<string>\n) {\n if (typeof allowedTokens === \"string\") {\n allowedTokens = new Set(allowedTokens.split(\"\"));\n }\n // Recast so typescript doesn't complain\n const _allowedTokens = allowedTokens;\n for (const v of _allowedTokens) {\n if (v.length > 1) {\n throw new Error(\n `Only single characters are allowed as \\`allowedTokens\\` when reparsing macro names, not \\`${v}\\`.`\n );\n }\n }\n\n visit(\n tree,\n (nodes) => {\n reparseMacroNamesInArray(nodes, _allowedTokens);\n },\n { includeArrays: true, test: Array.isArray }\n );\n}\n","import * as Ast from \"@unified-latex/unified-latex-types\";\nimport { match } from \"@unified-latex/unified-latex-util-match\";\nimport { findRegionInArray } from \"./find-region\";\nimport { refineRegions, Region, splitByRegions } from \"./regions\";\nimport { SKIP, visit } from \"@unified-latex/unified-latex-util-visit\";\nimport { reparseMacroNames } from \"./reparse-macro-names\";\n\nconst expl3Find = {\n start: match.createMacroMatcher([\"ExplSyntaxOn\"]),\n end: match.createMacroMatcher([\"ExplSyntaxOff\"]),\n};\nconst atLetterFind = {\n start: match.createMacroMatcher([\"makeatletter\"]),\n end: match.createMacroMatcher([\"makeatother\"]),\n};\n\n/**\n * Find regions between `\\ExplSyntaxOn...\\ExplSyntaxOff` and `\\makeatletter...\\makeatother`.\n * Returns an object containing regions where one or both syntax's apply.\n */\nexport function findExpl3AndAtLetterRegionsInArray(tree: Ast.Node[]): {\n explOnly: Region[];\n atLetterOnly: Region[];\n both: Region[];\n} {\n const expl3 = findRegionInArray(tree, expl3Find.start, expl3Find.end);\n const atLetter = findRegionInArray(\n tree,\n atLetterFind.start,\n atLetterFind.end\n );\n\n const regionMap = new Map([\n ...(expl3.map((x) => [x, \"expl\"]) as [Region, \"expl\"][]),\n ...(atLetter.map((x) => [x, \"atLetter\"]) as [Region, \"atLetter\"][]),\n ]);\n const all = refineRegions([...expl3, ...atLetter]);\n\n const ret = {\n explOnly: [] as Region[],\n atLetterOnly: [] as Region[],\n both: [] as Region[],\n };\n\n for (let i = 0; i < all.regions.length; i++) {\n const region = all.regions[i];\n const containedIn = all.regionsContainedIn[i];\n if (containedIn.size === 2) {\n ret.both.push(region);\n continue;\n }\n for (const v of containedIn.values()) {\n if (regionMap.get(v) === \"expl\") {\n ret.explOnly.push(region);\n }\n if (regionMap.get(v) === \"atLetter\") {\n ret.atLetterOnly.push(region);\n }\n }\n }\n\n // Regions of size 1 only contain the starting/stopping macro, so they should be discarded\n ret.explOnly = ret.explOnly.filter((r) => r.end - r.start > 1);\n ret.atLetterOnly = ret.atLetterOnly.filter((r) => r.end - r.start > 1);\n ret.both = ret.both.filter((r) => r.end - r.start > 1);\n\n return ret;\n}\n\nconst atLetterSet = new Set([\"@\"]);\nconst explSet = new Set([\"_\", \":\"]);\nconst bothSet = new Set([\"_\", \":\", \"@\"]);\n\n/**\n * Find regions between `\\ExplSyntaxOn...\\ExplSyntaxOff` and `\\makeatletter...\\makeatother`\n * and reparse their contents so that the relevant characters (e.g., `@`, `_`, and `:`) become\n * part of the macro names.\n */\nexport function reparseExpl3AndAtLetterRegions(tree: Ast.Ast) {\n visit(\n tree,\n {\n leave: (nodes) => {\n const regions = findExpl3AndAtLetterRegionsInArray(nodes);\n // In all likelihood, we don't need to do any reparsing, so bail early here\n const totalNumRegions =\n regions.both.length +\n regions.atLetterOnly.length +\n regions.explOnly.length;\n if (totalNumRegions === 0) {\n return;\n }\n\n const splits = splitByRegions(nodes, regions);\n const processed: typeof nodes = [];\n for (const [key, slice] of splits) {\n switch (key) {\n case null:\n processed.push(...slice);\n continue;\n case \"atLetterOnly\":\n reparseMacroNames(slice, atLetterSet);\n processed.push(...slice);\n continue;\n case \"explOnly\":\n reparseMacroNames(slice, explSet);\n processed.push(...slice);\n continue;\n case \"both\":\n reparseMacroNames(slice, bothSet);\n processed.push(...slice);\n continue;\n default:\n throw new Error(\n `Unexpected case when splitting ${key}`\n );\n }\n }\n\n nodes.length = 0;\n nodes.push(...processed);\n return SKIP;\n },\n },\n { includeArrays: true, test: Array.isArray }\n );\n}\n","export * from \"./libs/find-region\";\nexport * from \"./libs/special-regions\";\nexport * from \"./libs/reparse-macro-names\";\n\n// NOTE: The docstring comment must be the last item in the index.ts file!\n/**\n * ## What is this?\n *\n * Functions to identify regions of a `unified-latex` Abstract Syntax Tree (AST) that need to be reparsed because of different\n * category codes. For example, regions between `\\makeatletter` and `\\makeatother`.\n *\n * ## When should I use this?\n *\n * If you need to identify regions of the AST that need to be reparsed.\n */\n"],"mappings":"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"}