Substitute "command" for "macro"

This commit is contained in:
naskya 2023-03-26 08:06:49 +09:00
parent da17e8978a
commit 5b16b58dc4
No known key found for this signature in database
GPG Key ID: 164DFF24E2D40139
1 changed files with 55 additions and 55 deletions

View File

@ -1,10 +1,10 @@
type KaTeXCommand = { type KaTeXMacro = {
args: number; args: number;
rule: (string | number)[]; rule: (string | number)[];
}; };
function parseSingleKaTeXCommand(src: string): [string, KaTeXCommand] { function parseSingleKaTeXMacro(src: string): [string, KaTeXMacro] {
const invalid: [string, KaTeXCommand] = ["", { args: 0, rule: [] }]; const invalid: [string, KaTeXMacro] = ["", { args: 0, rule: [] }];
const skipSpaces = (pos: number): number => { const skipSpaces = (pos: number): number => {
while (src[pos] === " ") while (src[pos] === " ")
@ -12,10 +12,10 @@ function parseSingleKaTeXCommand(src: string): [string, KaTeXCommand] {
return pos; return pos;
}; };
if (!src.startsWith("\\newcommand") || src.slice(-1) !== "}") if (!src.startsWith("\\newmacro") || src.slice(-1) !== "}")
return invalid; return invalid;
// current index we are checking (= "\\newcommand".length) // current index we are checking (= "\\newmacro".length)
let currentPos: number = 11; let currentPos: number = 11;
currentPos = skipSpaces(currentPos); currentPos = skipSpaces(currentPos);
@ -46,18 +46,18 @@ function parseSingleKaTeXCommand(src: string): [string, KaTeXCommand] {
currentPos = skipSpaces(closeNameBracketPos + 1); currentPos = skipSpaces(closeNameBracketPos + 1);
let command: KaTeXCommand = { args: 0, rule: [] }; let macro: KaTeXMacro = { args: 0, rule: [] };
// parse [number of arguments] (optional) // parse [number of arguments] (optional)
if (src[currentPos] === "[") { if (src[currentPos] === "[") {
const closeArgsBracketPos: number = src.indexOf("]", currentPos); const closeArgsBracketPos: number = src.indexOf("]", currentPos);
command.args = Number(src.slice(currentPos + 1, closeArgsBracketPos).trim()); macro.args = Number(src.slice(currentPos + 1, closeArgsBracketPos).trim());
currentPos = closeArgsBracketPos + 1; currentPos = closeArgsBracketPos + 1;
if (Number.isNaN(command.args) || command.args < 0) if (Number.isNaN(macro.args) || macro.args < 0)
return invalid; return invalid;
} else if (src[currentPos] === "{") { } else if (src[currentPos] === "{") {
command.args = 0; macro.args = 0;
} else { } else {
return invalid; return invalid;
} }
@ -90,43 +90,43 @@ function parseSingleKaTeXCommand(src: string): [string, KaTeXCommand] {
} }
} }
if (numbersignPos === -1) { if (numbersignPos === -1) {
command.rule.push(src.slice(currentPos, -1)); macro.rule.push(src.slice(currentPos, -1));
break; break;
} }
const argIndexEndPos = src.slice(numbersignPos + 1).search(/[^\d]/) + numbersignPos; const argIndexEndPos = src.slice(numbersignPos + 1).search(/[^\d]/) + numbersignPos;
const argIndex: number = Number(src.slice(numbersignPos + 1, argIndexEndPos + 1)); const argIndex: number = Number(src.slice(numbersignPos + 1, argIndexEndPos + 1));
if (Number.isNaN(argIndex) || argIndex < 1 || command.args < argIndex) if (Number.isNaN(argIndex) || argIndex < 1 || macro.args < argIndex)
return invalid; return invalid;
if (currentPos !== numbersignPos) if (currentPos !== numbersignPos)
command.rule.push(src.slice(currentPos, numbersignPos)); macro.rule.push(src.slice(currentPos, numbersignPos));
command.rule.push(argIndex); macro.rule.push(argIndex);
currentPos = argIndexEndPos + 1; currentPos = argIndexEndPos + 1;
} }
if (command.args === 0) if (macro.args === 0)
return [name, command]; return [name, macro];
else else
return [name + bracket[0], command]; return [name + bracket[0], macro];
} }
export function parseKaTeXCommands(src: string): string { export function parseKaTeXMacros(src: string): string {
let result: { [name: string]: KaTeXCommand } = {}; let result: { [name: string]: KaTeXMacro } = {};
for (const s of src.split("\n")) { for (const s of src.split("\n")) {
const [name, command]: [string, KaTeXCommand] = parseSingleKaTeXCommand(s.trim()); const [name, macro]: [string, KaTeXMacro] = parseSingleKaTeXMacro(s.trim());
if (name !== "") if (name !== "")
result[name] = command; result[name] = macro;
} }
return JSON.stringify(result); return JSON.stringify(result);
} }
export function expandKaTeXCommand(src: string, commandsAsJsonString: string): string { export function expandKaTeXMacro(src: string, macrosAsJsonString: string): string {
const commands = JSON.parse(commandsAsJsonString); const macros = JSON.parse(macrosAsJsonString);
const bracketKinds = 3; const bracketKinds = 3;
const openBracketId: { [bracket: string]: number } = {"(": 0, "{": 1, "[": 2}; const openBracketId: { [bracket: string]: number } = {"(": 0, "{": 1, "[": 2};
@ -175,9 +175,9 @@ export function expandKaTeXCommand(src: string, commandsAsJsonString: string): s
return result; return result;
})(); })();
function expandSingleKaTeXCommand(expandedArgs: string[], commandName: string): string { function expandSingleKaTeXMacro(expandedArgs: string[], macroName: string): string {
let result = ""; let result = "";
for (const block of commands[commandName].rule) { for (const block of macros[macroName].rule) {
if (typeof block === "string") if (typeof block === "string")
result += block; result += block;
else else
@ -190,7 +190,7 @@ export function expandKaTeXCommand(src: string, commandsAsJsonString: string): s
const maxNumberOfExpansions = 200; // to prevent infinite expansion loop const maxNumberOfExpansions = 200; // to prevent infinite expansion loop
// only expand src.slice(beginPos, endPos) // only expand src.slice(beginPos, endPos)
function expandKaTeXCommandImpl(beginPos: number, endPos: number): string { function expandKaTeXMacroImpl(beginPos: number, endPos: number): string {
if (endPos <= beginPos) if (endPos <= beginPos)
return ""; return "";
@ -201,35 +201,35 @@ export function expandKaTeXCommand(src: string, commandsAsJsonString: string): s
return fallback; return fallback;
++numberOfExpansions; ++numberOfExpansions;
// search for a custom command // search for a custom macro
let checkedPos = beginPos - 1; let checkedPos = beginPos - 1;
let commandName = ""; let macroName = "";
let commandBackslashPos = 0; let macroBackslashPos = 0;
// for commands w/o args: unused // for macros w/o args: unused
// w/ args: the first open bracket ("(", "{", or "[") after cmd name // w/ args: the first open bracket ("(", "{", or "[") after cmd name
let commandArgBeginPos = 0; let macroArgBeginPos = 0;
// for commands w/o args: the end of cmd name // for macros w/o args: the end of cmd name
// w/ args: the closing bracket of the last arg // w/ args: the closing bracket of the last arg
let commandArgEndPos = 0; let macroArgEndPos = 0;
while (checkedPos < endPos) { while (checkedPos < endPos) {
checkedPos = src.indexOf("\\", checkedPos + 1); checkedPos = src.indexOf("\\", checkedPos + 1);
// there is no command to expand // there is no macro to expand
if (checkedPos === -1) if (checkedPos === -1)
return raw; return raw;
// is it a custom command? // is it a custom macro?
let nonAlphaPos = src.slice(checkedPos + 1).search(/[^A-Za-z]/) + checkedPos + 1; let nonAlphaPos = src.slice(checkedPos + 1).search(/[^A-Za-z]/) + checkedPos + 1;
let commandNameCandidate = src.slice(checkedPos + 1, nonAlphaPos); let macroNameCandidate = src.slice(checkedPos + 1, nonAlphaPos);
if (commands.hasOwnProperty(commandNameCandidate)) { if (macros.hasOwnProperty(macroNameCandidate)) {
// this is a custom command without args // this is a custom macro without args
commandBackslashPos = checkedPos; macroBackslashPos = checkedPos;
commandArgEndPos = nonAlphaPos - 1; macroArgEndPos = nonAlphaPos - 1;
commandName = commandNameCandidate; macroName = macroNameCandidate;
break; break;
} }
@ -243,38 +243,38 @@ export function expandKaTeXCommand(src: string, commandsAsJsonString: string): s
if (nextOpenBracketPos === endPos) if (nextOpenBracketPos === endPos)
return fallback; // there is no open bracket return fallback; // there is no open bracket
commandNameCandidate += src[nextOpenBracketPos]; macroNameCandidate += src[nextOpenBracketPos];
if (commands.hasOwnProperty(commandNameCandidate)) { if (macros.hasOwnProperty(macroNameCandidate)) {
commandBackslashPos = checkedPos; macroBackslashPos = checkedPos;
commandArgBeginPos = nextOpenBracketPos; macroArgBeginPos = nextOpenBracketPos;
commandArgEndPos = nextOpenBracketPos; // to search the first arg from here macroArgEndPos = nextOpenBracketPos; // to search the first arg from here
commandName = commandNameCandidate; macroName = macroNameCandidate;
break; break;
} }
} }
const numArgs: number = commands[commandName].args; const numArgs: number = macros[macroName].args;
const openBracket: string = commandName.slice(-1); const openBracket: string = macroName.slice(-1);
let expandedArgs = new Array<string>(numArgs); let expandedArgs = new Array<string>(numArgs);
for (let i = 0; i < numArgs; ++i) { for (let i = 0; i < numArgs; ++i) {
// find the first open bracket after what we've searched // find the first open bracket after what we've searched
const nextOpenBracketPos = src.indexOf(openBracket, commandArgEndPos); const nextOpenBracketPos = src.indexOf(openBracket, macroArgEndPos);
if (nextOpenBracketPos === -1) if (nextOpenBracketPos === -1)
return fallback; // not enough arguments are provided return fallback; // not enough arguments are provided
if (!bracketMapping[nextOpenBracketPos]) if (!bracketMapping[nextOpenBracketPos])
return fallback; // found open bracket doesn't correspond to any close bracket return fallback; // found open bracket doesn't correspond to any close bracket
commandArgEndPos = bracketMapping[nextOpenBracketPos]; macroArgEndPos = bracketMapping[nextOpenBracketPos];
expandedArgs[i] = expandKaTeXCommandImpl(nextOpenBracketPos + 1, commandArgEndPos); expandedArgs[i] = expandKaTeXMacroImpl(nextOpenBracketPos + 1, macroArgEndPos);
} }
return src.slice(beginPos, commandBackslashPos) return src.slice(beginPos, macroBackslashPos)
+ expandSingleKaTeXCommand(expandedArgs, commandName) + expandSingleKaTeXMacro(expandedArgs, macroName)
+ expandKaTeXCommandImpl(commandArgEndPos + 1, endPos); + expandKaTeXMacroImpl(macroArgEndPos + 1, endPos);
} }
return expandKaTeXCommandImpl(0, src.length); return expandKaTeXMacroImpl(0, src.length);
} }