commit
5722b45633
|
@ -120,21 +120,77 @@ Parser.prototype.parseInput = function(pos, mode) {
|
||||||
/**
|
/**
|
||||||
* Handles a body of an expression.
|
* Handles a body of an expression.
|
||||||
*/
|
*/
|
||||||
Parser.prototype.handleExpressionBody = function(pos, mode) {
|
Parser.prototype.handleExpressionBody = function(pos, mode, breakOnInfix) {
|
||||||
var body = [];
|
var body = [];
|
||||||
var atom;
|
var atom;
|
||||||
// Keep adding atoms to the body until we can't parse any more atoms (either
|
// Keep adding atoms to the body until we can't parse any more atoms (either
|
||||||
// we reached the end, a }, or a \right)
|
// we reached the end, a }, or a \right)
|
||||||
while ((atom = this.parseAtom(pos, mode))) {
|
while ((atom = this.parseAtom(pos, mode))) {
|
||||||
body.push(atom.result);
|
if (breakOnInfix && atom.result.type === "infix") {
|
||||||
pos = atom.position;
|
break;
|
||||||
|
} else {
|
||||||
|
body.push(atom.result);
|
||||||
|
pos = atom.position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
body: body,
|
body: this.handleInfixNodes(body, mode),
|
||||||
position: pos
|
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.
|
* Parses an "expression", which is a list of atoms.
|
||||||
*
|
*
|
||||||
|
@ -332,7 +388,7 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) {
|
||||||
body.position);
|
body.position);
|
||||||
} else if (utils.contains(styleFuncs, func)) {
|
} else if (utils.contains(styleFuncs, func)) {
|
||||||
// If we see a styling function, parse out the implict body
|
// 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(
|
return new ParseResult(
|
||||||
new ParseNode("styling", {
|
new ParseNode("styling", {
|
||||||
// Figure out what style to use by pulling out the style from
|
// Figure out what style to use by pulling out the style from
|
||||||
|
|
|
@ -150,6 +150,16 @@ var functions = {
|
||||||
type: "katex"
|
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() {
|
describe("A sizing parser", function() {
|
||||||
var sizeExpression = "\\Huge{x}\\small{x}";
|
var sizeExpression = "\\Huge{x}\\small{x}";
|
||||||
var nestedSizeExpression = "\\Huge{\\small{x}}";
|
var nestedSizeExpression = "\\Huge{\\small{x}}";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user