commit
5722b45633
|
@ -120,21 +120,77 @@ Parser.prototype.parseInput = function(pos, mode) {
|
|||
/**
|
||||
* Handles a body of an expression.
|
||||
*/
|
||||
Parser.prototype.handleExpressionBody = function(pos, mode) {
|
||||
Parser.prototype.handleExpressionBody = function(pos, mode, breakOnInfix) {
|
||||
var body = [];
|
||||
var atom;
|
||||
// Keep adding atoms to the body until we can't parse any more atoms (either
|
||||
// we reached the end, a }, or a \right)
|
||||
while ((atom = this.parseAtom(pos, mode))) {
|
||||
body.push(atom.result);
|
||||
pos = atom.position;
|
||||
if (breakOnInfix && atom.result.type === "infix") {
|
||||
break;
|
||||
} else {
|
||||
body.push(atom.result);
|
||||
pos = atom.position;
|
||||
}
|
||||
}
|
||||
return {
|
||||
body: body,
|
||||
body: this.handleInfixNodes(body, mode),
|
||||
position: pos
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Rewrites infix operators such as \over with corresponding commands such
|
||||
* as \frac.
|
||||
*
|
||||
* There can only be one infix operator per group. If there's more than one
|
||||
* then the expression is ambiguous. This can be resolved by adding {}.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
Parser.prototype.handleInfixNodes = function (body, mode) {
|
||||
var overIndex = -1;
|
||||
var func;
|
||||
var funcName;
|
||||
|
||||
for (var i = 0; i < body.length; i++) {
|
||||
var node = body[i];
|
||||
if (node.type === "infix") {
|
||||
if (overIndex !== -1) {
|
||||
throw new ParseError("only one infix operator per group",
|
||||
this.lexer, -1);
|
||||
}
|
||||
overIndex = i;
|
||||
funcName = node.value.replaceWith;
|
||||
func = functions.funcs[funcName];
|
||||
}
|
||||
}
|
||||
|
||||
if (overIndex !== -1) {
|
||||
var numerNode, denomNode;
|
||||
|
||||
var numerBody = body.slice(0, overIndex);
|
||||
var denomBody = body.slice(overIndex + 1);
|
||||
|
||||
if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
|
||||
numerNode = numerBody[0];
|
||||
} else {
|
||||
numerNode = new ParseNode("ordgroup", numerBody, mode);
|
||||
}
|
||||
|
||||
if (denomBody.length === 1 && denomBody[0].type === "ordgroup") {
|
||||
denomNode = denomBody[0];
|
||||
} else {
|
||||
denomNode = new ParseNode("ordgroup", denomBody, mode);
|
||||
}
|
||||
|
||||
var value = func.handler(funcName, numerNode, denomNode);
|
||||
return [new ParseNode(value.type, value, mode)];
|
||||
} else {
|
||||
return body;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses an "expression", which is a list of atoms.
|
||||
*
|
||||
|
@ -332,7 +388,7 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) {
|
|||
body.position);
|
||||
} else if (utils.contains(styleFuncs, func)) {
|
||||
// If we see a styling function, parse out the implict body
|
||||
var body = this.handleExpressionBody(start.result.position, mode);
|
||||
var body = this.handleExpressionBody(start.result.position, mode, true);
|
||||
return new ParseResult(
|
||||
new ParseNode("styling", {
|
||||
// Figure out what style to use by pulling out the style from
|
||||
|
|
|
@ -150,6 +150,16 @@ var functions = {
|
|||
type: "katex"
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
"\\over": {
|
||||
numArgs: 0,
|
||||
handler: function (func) {
|
||||
return {
|
||||
type: "infix",
|
||||
replaceWith: "\\frac"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -474,6 +474,94 @@ describe("A frac parser", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("An over parser", function() {
|
||||
var simpleOver = "1 \\over x";
|
||||
var complexOver = "1+2i \\over 3+4i";
|
||||
|
||||
it("should not fail", function () {
|
||||
expect(simpleOver).toParse();
|
||||
expect(complexOver).toParse();
|
||||
});
|
||||
|
||||
it("should produce a frac", function() {
|
||||
var parse;
|
||||
|
||||
parse = parseTree(simpleOver)[0];
|
||||
|
||||
expect(parse.type).toMatch("frac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
|
||||
parse = parseTree(complexOver)[0];
|
||||
|
||||
expect(parse.type).toMatch("frac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should create a numerator from the atoms before \\over", function () {
|
||||
var parse = parseTree(complexOver)[0];
|
||||
|
||||
var numer = parse.value.numer;
|
||||
expect(numer.value.length).toEqual(4);
|
||||
});
|
||||
|
||||
it("should create a demonimator from the atoms after \\over", function () {
|
||||
var parse = parseTree(complexOver)[0];
|
||||
|
||||
var denom = parse.value.numer;
|
||||
expect(denom.value.length).toEqual(4);
|
||||
});
|
||||
|
||||
it("should handle empty numerators", function () {
|
||||
var emptyNumerator = "\\over x";
|
||||
expect(emptyNumerator).toParse();
|
||||
|
||||
var parse = parseTree(emptyNumerator)[0];
|
||||
expect(parse.type).toMatch("frac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle empty denominators", function () {
|
||||
var emptyDenominator = "1 \\over";
|
||||
expect(emptyDenominator).toParse();
|
||||
|
||||
var parse = parseTree(emptyDenominator)[0];
|
||||
expect(parse.type).toMatch("frac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle \\displaystyle correctly", function () {
|
||||
var displaystyleExpression = "\\displaystyle 1 \\over 2";
|
||||
expect(displaystyleExpression).toParse();
|
||||
|
||||
var parse = parseTree(displaystyleExpression)[0];
|
||||
expect(parse.type).toMatch("frac");
|
||||
expect(parse.value.numer.value[0].type).toMatch("styling");
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle nested factions", function () {
|
||||
var nestedOverExpression = "{1 \\over 2} \\over 3";
|
||||
expect(nestedOverExpression).toParse();
|
||||
|
||||
var parse = parseTree(nestedOverExpression)[0];
|
||||
expect(parse.type).toMatch("frac");
|
||||
expect(parse.value.numer.value[0].type).toMatch("frac");
|
||||
expect(parse.value.numer.value[0].value.numer.value[0].value).toMatch(1);
|
||||
expect(parse.value.numer.value[0].value.denom.value[0].value).toMatch(2);
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.value.denom.value[0].value).toMatch(3);
|
||||
});
|
||||
|
||||
it("should fail with multiple overs in the same group", function () {
|
||||
var badMultipleOvers = "1 \\over 2 + 3 \\over 4";
|
||||
expect(badMultipleOvers).toNotParse();
|
||||
});
|
||||
});
|
||||
|
||||
describe("A sizing parser", function() {
|
||||
var sizeExpression = "\\Huge{x}\\small{x}";
|
||||
var nestedSizeExpression = "\\Huge{\\small{x}}";
|
||||
|
|
Loading…
Reference in New Issue
Block a user