Substitute "command" for "macro"
This commit is contained in:
parent
da17e8978a
commit
5b16b58dc4
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue