(context, existsOK, nonexistsOK)
| 13236 | // TODO: Optional arguments: \newcommand{\macro}[args][default]{definition} |
| 13237 | |
| 13238 | const newcommand = (context, existsOK, nonexistsOK) => { |
| 13239 | let arg = context.consumeArgs(1)[0]; |
| 13240 | |
| 13241 | if (arg.length !== 1) { |
| 13242 | throw new ParseError("\\newcommand's first argument must be a macro name"); |
| 13243 | } |
| 13244 | |
| 13245 | const name = arg[0].text; |
| 13246 | const exists = context.isDefined(name); |
| 13247 | |
| 13248 | if (exists && !existsOK) { |
| 13249 | throw new ParseError(`\\newcommand{${name}} attempting to redefine ` + `${name}; use \\renewcommand`); |
| 13250 | } |
| 13251 | |
| 13252 | if (!exists && !nonexistsOK) { |
| 13253 | throw new ParseError(`\\renewcommand{${name}} when command ${name} ` + `does not yet exist; use \\newcommand`); |
| 13254 | } |
| 13255 | |
| 13256 | let numArgs = 0; |
| 13257 | arg = context.consumeArgs(1)[0]; |
| 13258 | |
| 13259 | if (arg.length === 1 && arg[0].text === "[") { |
| 13260 | let argText = ''; |
| 13261 | let token = context.expandNextToken(); |
| 13262 | |
| 13263 | while (token.text !== "]" && token.text !== "EOF") { |
| 13264 | // TODO: Should properly expand arg, e.g., ignore {}s |
| 13265 | argText += token.text; |
| 13266 | token = context.expandNextToken(); |
| 13267 | } |
| 13268 | |
| 13269 | if (!argText.match(/^\s*[0-9]+\s*$/)) { |
| 13270 | throw new ParseError(`Invalid number of arguments: ${argText}`); |
| 13271 | } |
| 13272 | |
| 13273 | numArgs = parseInt(argText); |
| 13274 | arg = context.consumeArgs(1)[0]; |
| 13275 | } // Final arg is the expansion of the macro |
| 13276 | |
| 13277 | |
| 13278 | context.macros.set(name, { |
| 13279 | tokens: arg, |
| 13280 | numArgs |
| 13281 | }); |
| 13282 | return ''; |
| 13283 | }; |
| 13284 | |
| 13285 | defineMacro("\\newcommand", context => newcommand(context, false, true)); |
| 13286 | defineMacro("\\renewcommand", context => newcommand(context, true, false)); |
no test coverage detected