New calling convention for functions and environments

Fixes issue #255.

Mixing the variable number of arguments a function receives from TeX code
with the fixed arguments which the parser provides can cause some confusion.
After this change, a handler will receive exactly two arguments: one is a
context object from which things provided by the parser can be accessed by
name, which allows for simple extensions in the future.  The other is the
list of TeX arguments, passed as an array.

If we ever switch to EcmaScript 2015, we might want to use its destructuring
features to name the elements of the args array in the function head.  Until
then, destructuring that array manually immediately at the beginning of the
function seems like a useful convention to easily find the meaning of these
arguments.
This commit is contained in:
Martin von Gagern
2015-06-21 10:14:03 +02:00
parent a81c4fe78d
commit 30f7a1c5bf
3 changed files with 116 additions and 68 deletions

View File

@@ -50,14 +50,17 @@ function parseArray(parser, pos, mode, result) {
* - numOptionalArgs: (optional) Just like for a function
* A bare number instead of that object indicates the numArgs value.
*
* The handler function will receive the following arguments:
* The handler function will receive two arguments
* - context: information and references provided by the parser
* - args: an array of arguments passed to \begin{name}
* The context contains the following properties:
* - pos: the current position of the parser.
* - mode: the current parsing mode.
* - envName: the name of the environment, one of the listed names.
* - [args]: the arguments passed to \begin.
* - positions: the positions associated with these arguments.
* The handler is called with `this` referring to the parser.
* It must return a ParseResult.
* - parser: the parser object
* - lexer: the lexer object
* - positions: the positions associated with these arguments from args.
* The handler must return a ParseResult.
*/
function defineEnvironment(names, props, handler) {
@@ -85,8 +88,10 @@ function defineEnvironment(names, props, handler) {
// is part of the source2e.pdf file of LaTeX2e source documentation.
defineEnvironment("array", {
numArgs: 1
}, function(pos, mode, envName, colalign, positions) {
var parser = this;
}, function(context, args) {
var colalign = args[0];
var lexer = context.lexer;
var positions = context.positions;
colalign = colalign.value.map ? colalign.value : [colalign];
var cols = colalign.map(function(node) {
var ca = node.value;
@@ -103,14 +108,14 @@ defineEnvironment("array", {
}
throw new ParseError(
"Unknown column alignment: " + node.value,
parser.lexer, positions[1]);
lexer, positions[1]);
});
var res = {
type: "array",
cols: cols,
hskipBeforeAndAfter: true // \@preamble in lttab.dtx
};
res = parseArray(parser, pos, mode, res);
res = parseArray(context.parser, context.pos, context.mode, res);
return res;
});
@@ -124,7 +129,7 @@ defineEnvironment([
"vmatrix",
"Vmatrix"
], {
}, function(pos, mode, envName) {
}, function(context) {
var delimiters = {
"matrix": null,
"pmatrix": ["(", ")"],
@@ -132,18 +137,18 @@ defineEnvironment([
"Bmatrix": ["\\{", "\\}"],
"vmatrix": ["|", "|"],
"Vmatrix": ["\\Vert", "\\Vert"]
}[envName];
}[context.envName];
var res = {
type: "array",
hskipBeforeAndAfter: false // \hskip -\arraycolsep in amsmath
};
res = parseArray(this, pos, mode, res);
res = parseArray(context.parser, context.pos, context.mode, res);
if (delimiters) {
res.result = new ParseNode("leftright", {
body: [res.result],
left: delimiters[0],
right: delimiters[1]
}, mode);
}, context.mode);
}
return res;
});
@@ -152,7 +157,7 @@ defineEnvironment([
// \def\arraystretch{1.2}%
// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
defineEnvironment("cases", {
}, function(pos, mode, envName) {
}, function(context) {
var res = {
type: "array",
arraystretch: 1.2,
@@ -168,11 +173,11 @@ defineEnvironment("cases", {
postgap: 0
}]
};
res = parseArray(this, pos, mode, res);
res = parseArray(context.parser, context.pos, context.mode, res);
res.result = new ParseNode("leftright", {
body: [res.result],
left: "\\{",
right: "."
}, mode);
}, context.mode);
return res;
});