Allow macro definitions in settings (#493)

* Introduce MacroExpander

The job of the MacroExpander is turning a stream of possibly expandable
tokens, as obtained from the Lexer, into a stream of non-expandable tokens
(in KaTeX, even though they may well be expandable in TeX) which can be
processed by the Parser.  The challenge here is that we don't have
mode-specific lexer implementations any more, so we need to do everything on
the token level, including reassembly of sizes and colors.

* Make macros available in development server

Now one can specify macro definitions like \foo=bar as part of the query
string and use these macros in the formula being typeset.

* Add tests for macro expansions

* Handle end of input in special groups

This avoids an infinite loop if input ends prematurely.

* Simplify parseSpecialGroup

The parseSpecialGroup methos now returns a single token spanning the whole
special group, and leaves matching that string against a suitable regular
expression to whoever is calling the method.  Suggested by @cbreeden.

* Incorporate review suggestions

Add improvements suggested by Kevin Barabash during review.

* Input range sanity checks

Ensure that both tokens of a token range come from the same lexer,
and that the range has a non-negative length.

* Improved wording of two comments
This commit is contained in:
Martin von Gagern
2016-07-08 21:24:31 +02:00
committed by Kevin Barabash
parent b49eee4de7
commit 8c55aed39a
11 changed files with 509 additions and 296 deletions

View File

@@ -2,26 +2,50 @@
* This is the ParseError class, which is the main error thrown by KaTeX
* functions when something has gone wrong. This is used to distinguish internal
* errors from errors in the expression that the user provided.
*
* If possible, a caller should provide a Token or ParseNode with information
* about where in the source string the problem occurred.
*
* @param {string} message The error message
* @param {(Token|ParseNode)=} token An object providing position information
*/
function ParseError(message, lexer, position) {
function ParseError(message, token) {
var error = "KaTeX parse error: " + message;
var start;
var end;
if (lexer !== undefined && position !== undefined) {
if (token && token.lexer && token.start <= token.end) {
// If we have the input and a position, make the error a bit fancier
// Prepend some information
error += " at position " + position + ": ";
// Get the input
var input = lexer._input;
// Insert a combining underscore at the correct position
input = input.slice(0, position) + "\u0332" +
input.slice(position);
var input = token.lexer.input;
// Prepend some information
start = token.start;
end = token.end;
if (start === input.length) {
error += " at end of input: ";
} else {
error += " at position " + (start + 1) + ": ";
}
// Underline token in question using combining underscores
var underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
// Extract some context from the input and add it to the error
var begin = Math.max(0, position - 15);
var end = position + 15;
error += input.slice(begin, end);
var left;
if (start > 15) {
left = "…" + input.slice(start - 15, start);
} else {
left = input.slice(0, start);
}
var right;
if (end + 15 < input.length) {
right = input.slice(end, end + 15) + "…";
} else {
right = input.slice(end);
}
error += left + underlined + right;
}
// Some hackery to make ParseError a prototype of Error
@@ -30,7 +54,7 @@ function ParseError(message, lexer, position) {
self.name = "ParseError";
self.__proto__ = ParseError.prototype;
self.position = position;
self.position = start;
return self;
}