Parse single superscripts and subscripts

Summary:
Add the ability to parse lone `^x` and `_y`, etc. This basically just
involves more checking of cases in the increasingly ugly `parseAtom` function.
Also, now we manually check for the cases of double superscripts and
subscripts.

Test Plan: Make sure the tests pass. Make sure things like `^x` and `_y` parse.

Reviewers: emily

Reviewed By: emily

Differential Revision: http://phabricator.khanacademy.org/D3095
This commit is contained in:
Ben Alpert 2013-07-16 22:00:54 -07:00
parent bcd6e8687f
commit c08fadfaa9
3 changed files with 84 additions and 35 deletions

View File

@ -110,42 +110,55 @@ Parser.prototype.parseSubscript = function(pos) {
Parser.prototype.parseAtom = function(pos) {
// Parse the nucleus
var nucleus = this.parseGroup(pos);
var nextPos = pos;
var nucleusNode;
if (nucleus) {
// Now, we try to parse a subscript or a superscript. If one of those
// succeeds, we then try to parse the opposite one, and depending on
// whether that succeeds, we return the correct type.
var sup, sub;
if (sup = this.parseSuperscript(nucleus.position)) {
if (sub = this.parseSubscript(sup.position)) {
return new ParseResult(
new ParseNode("supsub",
{base: nucleus.result, sup: sup.result,
sub: sub.result}),
sub.position);
} else {
return new ParseResult(
new ParseNode("sup",
{base: nucleus.result, sup: sup.result}),
sup.position);
nextPos = nucleus.position;
nucleusNode = nucleus.result;
}
var sup;
var sub;
// Now, we try to parse a subscript or a superscript (or both!), and
// depending on whether those succeed, we return the correct type.
while (true) {
var node;
if ((node = this.parseSuperscript(nextPos))) {
if (sup) {
throw "Parse error: Double superscript";
}
} else if (sub = this.parseSubscript(nucleus.position)) {
if (sup = this.parseSuperscript(sub.position)) {
return new ParseResult(
new ParseNode("supsub",
{base: nucleus.result, sup: sup.result,
sub: sub.result}),
sup.position);
} else {
return new ParseResult(
new ParseNode("sub",
{base: nucleus.result, sub: sub.result}),
sub.position);
}
} else {
return nucleus;
nextPos = node.position;
sup = node.result;
continue;
}
if ((node = this.parseSubscript(nextPos))) {
if (sub) {
throw "Parse error: Double subscript";
}
nextPos = node.position;
sub = node.result;
continue;
}
break;
}
if (sup && sub) {
return new ParseResult(
new ParseNode("supsub", {base: nucleusNode, sup: sup,
sub: sub}),
nextPos);
} else if (sup) {
return new ParseResult(
new ParseNode("sup", {base: nucleusNode, sup: sup}),
nextPos);
} else if (sub) {
return new ParseResult(
new ParseNode("sub", {base: nucleusNode, sub: sub}),
nextPos);
} else {
return null;
return nucleus;
}
}

View File

@ -27,6 +27,10 @@ var makeSpan = function(className, children) {
};
var buildGroup = function(style, color, group, prev) {
if (!group) {
return makeSpan();
}
if (group.type === "mathord") {
return makeSpan("mord" + color, [mathit(group.value)]);
} else if (group.type === "textord") {

View File

@ -164,6 +164,24 @@ describe("A subscript and superscript parser", function() {
}).not.toThrow();
});
it("should not fail when there is no nucleus", function() {
expect(function() {
parseTree("^3");
}).not.toThrow();
expect(function() {
parseTree("_2");
}).not.toThrow();
expect(function() {
parseTree("^3_2");
}).not.toThrow();
expect(function() {
parseTree("_2^3");
}).not.toThrow();
});
it("should produce sups for superscript", function() {
var parse = parseTree("x^2")[0];
@ -207,16 +225,30 @@ describe("A subscript and superscript parser", function() {
expect(parseA).toEqual(parseB);
});
it("should not parse x^x^x", function() {
it("should not parse double subscripts or superscripts", function() {
expect(function() {
parseTree("x^x^x");
}).toThrow();
});
it("should not parse x_x_x", function() {
expect(function() {
parseTree("x_x_x");
}).toThrow();
expect(function() {
parseTree("x_x^x_x");
}).toThrow();
expect(function() {
parseTree("x_x^x^x");
}).toThrow();
expect(function() {
parseTree("x^x_x_x");
}).toThrow();
expect(function() {
parseTree("x^x_x^x");
}).toThrow();
});
it("should work correctly with {}s", function() {