mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-09 13:08:40 +00:00
fix: remove local macros upon parse error (#3114)
Close all groups after parse, in particular in case of parse error, completing `Namespace`'s simulation of local definitions. Fixes #3122 Co-authored-by: ylemkimon <y@ylem.kim>
This commit is contained in:
@@ -74,6 +74,14 @@ export default class MacroExpander implements MacroContextInterface {
|
||||
this.macros.endGroup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends all currently nested groups (if any), restoring values before the
|
||||
* groups began. Useful in case of an error in the middle of parsing.
|
||||
*/
|
||||
endGroups() {
|
||||
this.macros.endGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topmost token on the stack, without expanding it.
|
||||
* Similar in behavior to TeX's `\futurelet`.
|
||||
|
@@ -57,6 +57,16 @@ export default class Namespace<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends all currently nested groups (if any), restoring values before the
|
||||
* groups began. Useful in case of an error in the middle of parsing.
|
||||
*/
|
||||
endGroups() {
|
||||
while (this.undefStack.length > 0) {
|
||||
this.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether `name` has a definition. Equivalent to
|
||||
* `get(name) != null`.
|
||||
|
@@ -130,6 +130,7 @@ export default class Parser {
|
||||
this.gullet.macros.set("\\color", "\\textcolor");
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to parse the input
|
||||
const parse = this.parseExpression(false);
|
||||
|
||||
@@ -140,7 +141,13 @@ export default class Parser {
|
||||
if (!this.settings.globalGroup) {
|
||||
this.gullet.endGroup();
|
||||
}
|
||||
|
||||
return parse;
|
||||
|
||||
// Close any leftover groups in case of a parse error.
|
||||
} finally {
|
||||
this.gullet.endGroups();
|
||||
}
|
||||
}
|
||||
|
||||
static endOfExpression: string[] = ["}", "\\endgroup", "\\end", "\\right", "&"];
|
||||
|
@@ -3440,6 +3440,12 @@ describe("A macro expander", function() {
|
||||
expect(macros["\\foo"]).toBeFalsy();
|
||||
});
|
||||
|
||||
it("\\def doesn't change settings.macros on error", () => {
|
||||
const macros = {};
|
||||
expect`\def\foo{c^}\foo`.not.toParse(new Settings({macros}));
|
||||
expect(macros["\\foo"]).toBeFalsy();
|
||||
});
|
||||
|
||||
it("\\def changes settings.macros with globalGroup", () => {
|
||||
const macros = {};
|
||||
expect`\gdef\foo{1}`.toParse(new Settings({macros, globalGroup: true}));
|
||||
|
Reference in New Issue
Block a user