commit c08fadfaa93b22016c05cdb3905bd4973e91339b
parent bcd6e8687f114169a9e3463ea07ff6008d3f76e6
Author: Ben Alpert <spicyjalapeno@gmail.com>
Date: Tue, 16 Jul 2013 22:00:54 -0700
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
Diffstat:
3 files changed, 83 insertions(+), 34 deletions(-)
diff --git a/Parser.js b/Parser.js
@@ -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);
+ nextPos = node.position;
+ sup = node.result;
+ continue;
+ }
+ if ((node = this.parseSubscript(nextPos))) {
+ if (sub) {
+ throw "Parse error: Double subscript";
}
- } else {
- return nucleus;
+ 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;
}
}
diff --git a/katex.js b/katex.js
@@ -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") {
diff --git a/test/katex-tests.js b/test/katex-tests.js
@@ -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() {