Skip to content

Commit

Permalink
chore: use more early return
Browse files Browse the repository at this point in the history
  • Loading branch information
theseanl committed Jan 22, 2024
1 parent bd1f972 commit ebcf3aa
Showing 1 changed file with 54 additions and 55 deletions.
109 changes: 54 additions & 55 deletions packages/unified-latex-util-macros/libs/newcommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,82 +215,81 @@ export function createMacroExpander(

return (macro: Ast.Macro) => {
const retTree = structuredClone(cachedSubstitutionTree);
const args = macro.args;

const stack: number[] = [];
let lastSelfReference: number | null = null;

// Recursively expand macro arguments. If a self-reference is found, it returns
// the corresponding hash number, which is used to special-case `O{#2} O{#1}`.
// Recursively expand macro arguments. If a self-reference is found, sets a
// lastSelfReference variable, which is used to special-case `O{#2} O{#1}`.
function expandArgs(retTree: Ast.Node[]): void {
replaceNode(retTree, (node) => {
if (node.type !== "hash_number") {
return;
}

const hashNum = node.number;
const arg = args?.[hashNum - 1];
const arg = macro.args?.[hashNum - 1];

// Check if this argument is -NoValue-
if (!arg || match.blankArgument(arg)) {
// Check if there exists a default argument for this hash number
const defaultArg = defaultArgs[hashNum - 1];
if (!defaultArg) {
return s(`#${hashNum}`);
}
// If `arg` is provided, return it
if (arg && !match.blankArgument(arg)) {
return arg.content;
}

// Detect self-references
if (stack.includes(hashNum)) {
lastSelfReference = hashNum;
return s(`#${hashNum}`);
}
// Check if there exists a default argument for this hash number
const defaultArg = defaultArgs[hashNum - 1];
if (!defaultArg) {
return s(`#${hashNum}`);
}

// `defaultArg` is a string expression. The same `defaultArg` may be parsed
// differently depending on the context of `macro`, so we cannot cache
// the parse result of `defaultArg`. Currently we just call `parse` without
// taking account of parsing contexts, so actually the result can be cached,
// but this is not the correct thing to do. FIXME: we should probably pass
// some options that is provided to whatever function that called this to
// the below parse call. Note that `parse` is done in several passes, and we
// may be able to cache result of a first few passes that aren't context-dependent.
const subst = parse(defaultArg).content;
const nextHashNums = getMacroSubstitutionHashNumbers(subst);
// Detect self-references
if (stack.includes(hashNum)) {
lastSelfReference = hashNum;
return s(`#${hashNum}`);
}

if (nextHashNums.size === 0) {
return subst;
}
// `defaultArg` is a string expression. The same `defaultArg` may be parsed
// differently depending on the context of `macro`, so we cannot cache
// the parse result of `defaultArg`. Currently we just call `parse` without
// taking account of parsing contexts, so actually the result can be cached,
// but this is not the correct thing to do. FIXME: we should probably pass
// some options that is provided to whatever function that called this to
// the below parse call. Note that `parse` is done in several passes, and we
// may be able to cache result of a first few passes that aren't context-dependent.
const subst = parse(defaultArg).content;
const nextHashNums = getMacroSubstitutionHashNumbers(subst);

stack.push(hashNum);
try {
expandArgs(subst);
if (nextHashNums.size === 0) {
return subst;
}

if (lastSelfReference !== hashNum) {
return subst;
}
stack.push(hashNum);
try {
expandArgs(subst);

// At this point, we have encountered #n while expanding #n.
// Check if we got exactly #n by expanding #n,
// in which case we should return the -NoValue-.
if (`#${hashNum}` === printRaw(subst)) {
// We are good, clear the last self-reference variable
lastSelfReference = null;
return emptyArg();
}
if (lastSelfReference !== hashNum) {
return subst;
}

console.warn(
`Detected unrecoverable self-reference while expanding macro: ${printRaw(
macro
)}`
);
// Return a placeholder string, so that we know that
// this code path is not taken in unit tests.
return s("-Circular-");
} finally {
stack.pop();
// At this point, we have encountered #n while expanding #n.
// Check if we got exactly #n by expanding #n,
// in which case we should return the -NoValue-.
if (`#${hashNum}` === printRaw(subst)) {
// We are good, clear the last self-reference variable
lastSelfReference = null;
return emptyArg();
}
}

return arg.content;
console.warn(
`Detected unrecoverable self-reference while expanding macro: ${printRaw(
macro
)}`
);
// Return a placeholder string, so that we know that
// this code path is not taken in unit tests.
return s("-Circular-");
} finally {
stack.pop();
}
});
}

Expand Down

0 comments on commit ebcf3aa

Please sign in to comment.