Flatten a bunch of non-pervasive ParseNode types (part 1) (#1551)

* Flatten "url" ParseNode.

* Flatten "href" ParseNode.

* Flatten "verb" ParseNode.

* Flatten "tag" ParseNode.

* Flatten "cr" ParseNode.

* Flatten "delimsizing" ParseNode.

* Flatten "middle" ParseNode.

* Flatten "leftright" ParseNode.

* Flatten "leftright-right" ParseNode.

* Flatten "mathchoice" ParseNode.

* Remove unused ParseNode type "mod".

* Flatten "mclass" ParseNode.

* Flatten "font" ParseNode.

* Flatten "phantom" ParseNode.

* Flatten "hphantom" ParseNode.

* Flatten "vphantom" ParseNode.
This commit is contained in:
Ashish Myles
2018-08-05 22:49:43 -04:00
committed by ylemkimon
parent b2d38104cd
commit 1506dc1d88
17 changed files with 212 additions and 357 deletions

View File

@@ -942,10 +942,7 @@ export default class Parser {
const urlArg = { const urlArg = {
type: "url", type: "url",
mode: this.mode, mode: this.mode,
value: { url,
type: "url",
value: url,
},
}; };
this.consume(); this.consume();
if (funcName === "\\href") { // two arguments if (funcName === "\\href") { // two arguments
@@ -983,11 +980,8 @@ export default class Parser {
return newArgument({ return newArgument({
type: "verb", type: "verb",
mode: "text", mode: "text",
value: { body: arg,
type: "verb", star,
body: arg,
star: star,
},
}, nucleus); }, nucleus);
} }
// At this point, we should have a symbol, possibly with accents. // At this point, we should have a symbol, possibly with accents.

View File

@@ -613,8 +613,8 @@ const makeVList = function(params: VListParam, options: Options): DomSpan {
// Converts verb group into body string, dealing with \verb* form // Converts verb group into body string, dealing with \verb* form
const makeVerb = function(group: ParseNode<"verb">, options: Options): string { const makeVerb = function(group: ParseNode<"verb">, options: Options): string {
let text = group.value.body; let text = group.body;
if (group.value.star) { if (group.star) {
text = text.replace(/ /g, '\u2423'); // Open Box text = text.replace(/ /g, '\u2423'); // Open Box
} else { } else {
text = text.replace(/ /g, '\xA0'); // No-Break Space text = text.replace(/ /g, '\xA0'); // No-Break Space

View File

@@ -309,8 +309,8 @@ export default function buildHTML(tree: AnyParseNode[], options: Options): DomSp
// Strip off outer tag wrapper for processing below. // Strip off outer tag wrapper for processing below.
let tag = null; let tag = null;
if (tree.length === 1 && tree[0].type === "tag") { if (tree.length === 1 && tree[0].type === "tag") {
tag = tree[0].value.tag; tag = tree[0].tag;
tree = tree[0].value.body; tree = tree[0].body;
} }
// Build the expression contained in the tree // Build the expression contained in the tree

View File

@@ -139,7 +139,7 @@ function parseArray(
if (!cr) { if (!cr) {
throw new ParseError(`Failed to parse function after ${next}`); throw new ParseError(`Failed to parse function after ${next}`);
} }
rowGaps.push(assertNodeType(cr, "cr").value.size); rowGaps.push(assertNodeType(cr, "cr").size);
// check for \hline(s) following the row separator // check for \hline(s) following the row separator
hLinesBeforeRow.push(getHLines(parser)); hLinesBeforeRow.push(getHLines(parser));
@@ -563,12 +563,9 @@ defineEnvironment({
return delimiters ? { return delimiters ? {
type: "leftright", type: "leftright",
mode: context.mode, mode: context.mode,
value: { body: [res],
type: "leftright", left: delimiters[0],
body: [res], right: delimiters[1],
left: delimiters[0],
right: delimiters[1],
},
} : res; } : res;
}, },
htmlBuilder, htmlBuilder,
@@ -614,12 +611,9 @@ defineEnvironment({
return { return {
type: "leftright", type: "leftright",
mode: context.mode, mode: context.mode,
value: { body: [res],
type: "leftright", left: "\\{",
body: [res], right: ".",
left: "\\{",
right: ".",
},
}; };
}, },
htmlBuilder, htmlBuilder,

View File

@@ -40,12 +40,9 @@ defineFunction({
return { return {
type: "cr", type: "cr",
mode: parser.mode, mode: parser.mode,
value: { newLine,
type: "cr", newRow,
newLine, size: size && assertNodeType(size, "size"),
newRow,
size: size && assertNodeType(size, "size"),
},
}; };
}, },
@@ -53,16 +50,16 @@ defineFunction({
// not within tabular/array environments. // not within tabular/array environments.
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
if (group.value.newRow) { if (group.newRow) {
throw new ParseError( throw new ParseError(
"\\cr valid only within a tabular/array environment"); "\\cr valid only within a tabular/array environment");
} }
const span = buildCommon.makeSpan(["mspace"], [], options); const span = buildCommon.makeSpan(["mspace"], [], options);
if (group.value.newLine) { if (group.newLine) {
span.classes.push("newline"); span.classes.push("newline");
if (group.value.size) { if (group.size) {
span.style.marginTop = span.style.marginTop =
calculateSize(group.value.size.value.value, options) + "em"; calculateSize(group.size.value.value, options) + "em";
} }
} }
return span; return span;
@@ -70,11 +67,11 @@ defineFunction({
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const node = new mathMLTree.MathNode("mspace"); const node = new mathMLTree.MathNode("mspace");
if (group.value.newLine) { if (group.newLine) {
node.setAttribute("linebreak", "newline"); node.setAttribute("linebreak", "newline");
if (group.value.size) { if (group.size) {
node.setAttribute("height", node.setAttribute("height",
calculateSize(group.value.size.value.value, options) + "em"); calculateSize(group.size.value.value, options) + "em");
} }
} }
return node; return node;

View File

@@ -12,7 +12,6 @@ import * as mml from "../buildMathML";
import type Options from "../Options"; import type Options from "../Options";
import type {AnyParseNode, ParseNode, SymbolParseNode} from "../parseNode"; import type {AnyParseNode, ParseNode, SymbolParseNode} from "../parseNode";
import type {LeftRightDelimType} from "../parseNode";
import type {FunctionContext} from "../defineFunction"; import type {FunctionContext} from "../defineFunction";
// Extra data needed for the delimiter handler down below // Extra data needed for the delimiter handler down below
@@ -52,7 +51,7 @@ const delimiters = [
".", ".",
]; ];
type IsMiddle = {value: string, options: Options}; type IsMiddle = {delim: string, options: Options};
// Delimiter functions // Delimiter functions
function checkDelimiter( function checkDelimiter(
@@ -87,39 +86,33 @@ defineFunction({
return { return {
type: "delimsizing", type: "delimsizing",
mode: context.parser.mode, mode: context.parser.mode,
value: { size: delimiterSizes[context.funcName].size,
type: "delimsizing", mclass: delimiterSizes[context.funcName].mclass,
size: delimiterSizes[context.funcName].size, delim: delim.value,
mclass: delimiterSizes[context.funcName].mclass,
value: delim.value,
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
const delim = group.value.value; if (group.delim === ".") {
if (delim === ".") {
// Empty delimiters still count as elements, even though they don't // Empty delimiters still count as elements, even though they don't
// show anything. // show anything.
return buildCommon.makeSpan([group.value.mclass]); return buildCommon.makeSpan([group.mclass]);
} }
// Use delimiter.sizedDelim to generate the delimiter. // Use delimiter.sizedDelim to generate the delimiter.
return delimiter.sizedDelim( return delimiter.sizedDelim(
delim, group.value.size, options, group.mode, group.delim, group.size, options, group.mode, [group.mclass]);
[group.value.mclass]);
}, },
mathmlBuilder: (group) => { mathmlBuilder: (group) => {
const children = []; const children = [];
if (group.value.value !== ".") { if (group.delim !== ".") {
children.push(mml.makeText(group.value.value, group.mode)); children.push(mml.makeText(group.delim, group.mode));
} }
const node = new mathMLTree.MathNode("mo", children); const node = new mathMLTree.MathNode("mo", children);
if (group.value.mclass === "mopen" || if (group.mclass === "mopen" ||
group.value.mclass === "mclose") { group.mclass === "mclose") {
// Only some of the delimsizing functions act as fences, and they // Only some of the delimsizing functions act as fences, and they
// return "mopen" or "mclose" mclass. // return "mopen" or "mclose" mclass.
node.setAttribute("fence", "true"); node.setAttribute("fence", "true");
@@ -134,11 +127,10 @@ defineFunction({
}); });
function leftRightGroupValue(group: ParseNode<"leftright">): LeftRightDelimType { function assertParsed(group: ParseNode<"leftright">) {
if (!group.value.body) { if (!group.body) {
throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
} }
return group.value;
} }
@@ -155,10 +147,7 @@ defineFunction({
return { return {
type: "leftright-right", type: "leftright-right",
mode: context.parser.mode, mode: context.parser.mode,
value: { delim: checkDelimiter(args[0], context).value,
type: "leftright-right",
value: checkDelimiter(args[0], context).value,
},
}; };
}, },
}); });
@@ -188,18 +177,15 @@ defineFunction({
return { return {
type: "leftright", type: "leftright",
mode: parser.mode, mode: parser.mode,
value: { body,
type: "leftright", left: delim.value,
body: body, right: assertNodeType(right, "leftright-right").delim,
left: delim.value,
right: assertNodeType(right, "leftright-right").value.value,
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
const groupValue = leftRightGroupValue(group); assertParsed(group);
// Build the inner expression // Build the inner expression
const inner = html.buildExpression(groupValue.body, options, true, const inner = html.buildExpression(group.body, options, true,
[null, "mclose"]); [null, "mclose"]);
let innerHeight = 0; let innerHeight = 0;
@@ -226,14 +212,14 @@ defineFunction({
innerDepth *= options.sizeMultiplier; innerDepth *= options.sizeMultiplier;
let leftDelim; let leftDelim;
if (groupValue.left === ".") { if (group.left === ".") {
// Empty delimiters in \left and \right make null delimiter spaces. // Empty delimiters in \left and \right make null delimiter spaces.
leftDelim = html.makeNullDelimiter(options, ["mopen"]); leftDelim = html.makeNullDelimiter(options, ["mopen"]);
} else { } else {
// Otherwise, use leftRightDelim to generate the correct sized // Otherwise, use leftRightDelim to generate the correct sized
// delimiter. // delimiter.
leftDelim = delimiter.leftRightDelim( leftDelim = delimiter.leftRightDelim(
groupValue.left, innerHeight, innerDepth, options, group.left, innerHeight, innerDepth, options,
group.mode, ["mopen"]); group.mode, ["mopen"]);
} }
// Add it to the beginning of the expression // Add it to the beginning of the expression
@@ -250,7 +236,7 @@ defineFunction({
if (isMiddle) { if (isMiddle) {
// Apply the options that were active when \middle was called // Apply the options that were active when \middle was called
inner[i] = delimiter.leftRightDelim( inner[i] = delimiter.leftRightDelim(
isMiddle.value, innerHeight, innerDepth, isMiddle.delim, innerHeight, innerDepth,
isMiddle.options, group.mode, []); isMiddle.options, group.mode, []);
} }
} }
@@ -258,11 +244,11 @@ defineFunction({
let rightDelim; let rightDelim;
// Same for the right delimiter // Same for the right delimiter
if (groupValue.right === ".") { if (group.right === ".") {
rightDelim = html.makeNullDelimiter(options, ["mclose"]); rightDelim = html.makeNullDelimiter(options, ["mclose"]);
} else { } else {
rightDelim = delimiter.leftRightDelim( rightDelim = delimiter.leftRightDelim(
groupValue.right, innerHeight, innerDepth, options, group.right, innerHeight, innerDepth, options,
group.mode, ["mclose"]); group.mode, ["mclose"]);
} }
// Add it to the end of the expression. // Add it to the end of the expression.
@@ -271,21 +257,21 @@ defineFunction({
return buildCommon.makeSpan(["minner"], inner, options); return buildCommon.makeSpan(["minner"], inner, options);
}, },
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const groupValue = leftRightGroupValue(group); assertParsed(group);
const inner = mml.buildExpression(groupValue.body, options); const inner = mml.buildExpression(group.body, options);
if (groupValue.left !== ".") { if (group.left !== ".") {
const leftNode = new mathMLTree.MathNode( const leftNode = new mathMLTree.MathNode(
"mo", [mml.makeText(groupValue.left, group.mode)]); "mo", [mml.makeText(group.left, group.mode)]);
leftNode.setAttribute("fence", "true"); leftNode.setAttribute("fence", "true");
inner.unshift(leftNode); inner.unshift(leftNode);
} }
if (groupValue.right !== ".") { if (group.right !== ".") {
const rightNode = new mathMLTree.MathNode( const rightNode = new mathMLTree.MathNode(
"mo", [mml.makeText(groupValue.right, group.mode)]); "mo", [mml.makeText(group.right, group.mode)]);
rightNode.setAttribute("fence", "true"); rightNode.setAttribute("fence", "true");
@@ -311,22 +297,19 @@ defineFunction({
return { return {
type: "middle", type: "middle",
mode: context.parser.mode, mode: context.parser.mode,
value: { delim: delim.value,
type: "middle",
value: delim.value,
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
let middleDelim; let middleDelim;
if (group.value.value === ".") { if (group.delim === ".") {
middleDelim = html.makeNullDelimiter(options, []); middleDelim = html.makeNullDelimiter(options, []);
} else { } else {
middleDelim = delimiter.sizedDelim( middleDelim = delimiter.sizedDelim(
group.value.value, 1, options, group.delim, 1, options,
group.mode, []); group.mode, []);
const isMiddle: IsMiddle = {value: group.value.value, options}; const isMiddle: IsMiddle = {delim: group.delim, options};
// Property `isMiddle` not defined on `span`. It is only used in // Property `isMiddle` not defined on `span`. It is only used in
// this file above. // this file above.
// TODO: Fix this violation of the `span` type and possibly rename // TODO: Fix this violation of the `span` type and possibly rename
@@ -338,7 +321,7 @@ defineFunction({
}, },
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const middleNode = new mathMLTree.MathNode( const middleNode = new mathMLTree.MathNode(
"mo", [mml.makeText(group.value.value, group.mode)]); "mo", [mml.makeText(group.delim, group.mode)]);
middleNode.setAttribute("fence", "true"); middleNode.setAttribute("fence", "true");
return middleNode; return middleNode;
}, },

View File

@@ -7,17 +7,18 @@ import defineFunction from "../defineFunction";
import * as html from "../buildHTML"; import * as html from "../buildHTML";
import * as mml from "../buildMathML"; import * as mml from "../buildMathML";
import type {ParseNode} from "../parseNode";
const htmlBuilder = (group, options) => { const htmlBuilder = (group: ParseNode<"font">, options) => {
const font = group.value.font; const font = group.font;
const newOptions = options.withFont(font); const newOptions = options.withFont(font);
return html.buildGroup(group.value.body, newOptions); return html.buildGroup(group.body, newOptions);
}; };
const mathmlBuilder = (group, options) => { const mathmlBuilder = (group: ParseNode<"font">, options) => {
const font = group.value.font; const font = group.font;
const newOptions = options.withFont(font); const newOptions = options.withFont(font);
return mml.buildGroup(group.value.body, newOptions); return mml.buildGroup(group.body, newOptions);
}; };
const fontAliases = { const fontAliases = {
@@ -53,11 +54,8 @@ defineFunction({
return { return {
type: "font", type: "font",
mode: parser.mode, mode: parser.mode,
value: { font: func.slice(1),
type: "font", body,
font: func.slice(1),
body,
},
}; };
}, },
htmlBuilder, htmlBuilder,
@@ -78,21 +76,15 @@ defineFunction({
return { return {
type: "mclass", type: "mclass",
mode: parser.mode, mode: parser.mode,
value: { mclass: binrelClass(body),
type: "mclass", body: [
mclass: binrelClass(body), {
value: [ type: "font",
{ mode: parser.mode,
type: "font", font: "boldsymbol",
mode: parser.mode, body,
value: { },
type: "font", ],
font: "boldsymbol",
body,
},
},
],
},
}; };
}, },
}); });
@@ -114,14 +106,11 @@ defineFunction({
return { return {
type: "font", type: "font",
mode: mode, mode: mode,
value: { font: style,
type: "font", body: {
font: style, type: "ordgroup",
body: { mode: parser.mode,
type: "ordgroup", value: body,
mode: parser.mode,
value: body,
},
}, },
}; };
}, },

View File

@@ -18,31 +18,21 @@ defineFunction({
}, },
handler: ({parser}, args) => { handler: ({parser}, args) => {
const body = args[1]; const body = args[1];
const href = assertNodeType(args[0], "url").value.value; const href = assertNodeType(args[0], "url").url;
return { return {
type: "href", type: "href",
mode: parser.mode, mode: parser.mode,
value: { href,
type: "href", body: ordargument(body),
href: href,
body: ordargument(body),
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
const elements = html.buildExpression( const elements = html.buildExpression(group.body, options, false);
group.value.body, return new buildCommon.makeAnchor(group.href, [], elements, options);
options,
false
);
const href = group.value.href;
return new buildCommon.makeAnchor(href, [], elements, options);
}, },
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const math = mml.buildExpressionRow(group.value.body, options); const math = mml.buildExpressionRow(group.body, options);
assertType(math, MathNode).setAttribute("href", group.value.href); assertType(math, MathNode).setAttribute("href", group.href);
return math; return math;
}, },
}); });
@@ -56,7 +46,7 @@ defineFunction({
allowedInText: true, allowedInText: true,
}, },
handler: ({parser}, args) => { handler: ({parser}, args) => {
const href = assertNodeType(args[0], "url").value.value; const href = assertNodeType(args[0], "url").url;
const chars = []; const chars = [];
for (let i = 0; i < href.length; i++) { for (let i = 0; i < href.length; i++) {
let c = href[i]; let c = href[i];
@@ -81,11 +71,8 @@ defineFunction({
return { return {
type: "href", type: "href",
mode: parser.mode, mode: parser.mode,
value: { href,
type: "href", body: ordargument(body),
href: href,
body: ordargument(body),
},
}; };
}, },
}); });

View File

@@ -6,19 +6,16 @@ import Style from "../Style";
import * as html from "../buildHTML"; import * as html from "../buildHTML";
import * as mml from "../buildMathML"; import * as mml from "../buildMathML";
const chooseMathStyle = (group, options) => { import type {ParseNode} from "../parseNode";
const style = options.style;
if (style.size === Style.DISPLAY.size) {
return group.value.display;
} else if (style.size === Style.TEXT.size) {
return group.value.text;
} else if (style.size === Style.SCRIPT.size) {
return group.value.script;
} else if (style.size === Style.SCRIPTSCRIPT.size) {
return group.value.scriptscript;
}
return group.value.text;
const chooseMathStyle = (group: ParseNode<"mathchoice">, options) => {
switch (options.style.size) {
case Style.DISPLAY.size: return group.display;
case Style.TEXT.size: return group.text;
case Style.SCRIPT.size: return group.script;
case Style.SCRIPTSCRIPT.size: return group.scriptscript;
default: return group.text;
}
}; };
defineFunction({ defineFunction({
@@ -31,13 +28,10 @@ defineFunction({
return { return {
type: "mathchoice", type: "mathchoice",
mode: parser.mode, mode: parser.mode,
value: { display: ordargument(args[0]),
type: "mathchoice", text: ordargument(args[1]),
display: ordargument(args[0]), script: ordargument(args[2]),
text: ordargument(args[1]), scriptscript: ordargument(args[3]),
script: ordargument(args[2]),
scriptscript: ordargument(args[3]),
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {

View File

@@ -7,15 +7,17 @@ import type {AnyParseNode} from "../parseNode";
import * as html from "../buildHTML"; import * as html from "../buildHTML";
import * as mml from "../buildMathML"; import * as mml from "../buildMathML";
import type {ParseNode} from "../parseNode";
const makeSpan = buildCommon.makeSpan; const makeSpan = buildCommon.makeSpan;
function htmlBuilder(group, options) { function htmlBuilder(group: ParseNode<"mclass">, options) {
const elements = html.buildExpression(group.value.value, options, true); const elements = html.buildExpression(group.body, options, true);
return makeSpan([group.value.mclass], elements, options); return makeSpan([group.mclass], elements, options);
} }
function mathmlBuilder(group, options) { function mathmlBuilder(group: ParseNode<"mclass">, options) {
const inner = mml.buildExpression(group.value.value, options); const inner = mml.buildExpression(group.body, options);
return mathMLTree.newDocumentFragment(inner); return mathMLTree.newDocumentFragment(inner);
} }
@@ -34,11 +36,8 @@ defineFunction({
return { return {
type: "mclass", type: "mclass",
mode: parser.mode, mode: parser.mode,
value: { mclass: "m" + funcName.substr(5),
type: "mclass", body: ordargument(body),
mclass: "m" + funcName.substr(5),
value: ordargument(body),
},
}; };
}, },
htmlBuilder, htmlBuilder,
@@ -70,11 +69,8 @@ defineFunction({
return { return {
type: "mclass", type: "mclass",
mode: parser.mode, mode: parser.mode,
value: { mclass: binrelClass(args[0]),
type: "mclass", body: [args[1]],
mclass: binrelClass(args[0]),
value: [args[1]],
},
}; };
}, },
}); });
@@ -119,11 +115,8 @@ defineFunction({
return { return {
type: "mclass", type: "mclass",
mode: parser.mode, mode: parser.mode,
value: { mclass,
type: "mclass", body: [supsub],
mclass: mclass,
value: [supsub],
},
}; };
}, },
htmlBuilder, htmlBuilder,

View File

@@ -18,15 +18,12 @@ defineFunction({
return { return {
type: "phantom", type: "phantom",
mode: parser.mode, mode: parser.mode,
value: { body: ordargument(body),
type: "phantom",
value: ordargument(body),
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
const elements = html.buildExpression( const elements = html.buildExpression(
group.value.value, group.body,
options.withPhantom(), options.withPhantom(),
false false
); );
@@ -36,7 +33,7 @@ defineFunction({
return new buildCommon.makeFragment(elements); return new buildCommon.makeFragment(elements);
}, },
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const inner = mml.buildExpression(group.value.value, options); const inner = mml.buildExpression(group.body, options);
return new mathMLTree.MathNode("mphantom", inner); return new mathMLTree.MathNode("mphantom", inner);
}, },
}); });
@@ -53,16 +50,12 @@ defineFunction({
return { return {
type: "hphantom", type: "hphantom",
mode: parser.mode, mode: parser.mode,
value: { body,
type: "hphantom",
value: ordargument(body),
body: body,
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
let node = buildCommon.makeSpan( let node = buildCommon.makeSpan(
[], [html.buildGroup(group.value.body, options.withPhantom())]); [], [html.buildGroup(group.body, options.withPhantom())]);
node.height = 0; node.height = 0;
node.depth = 0; node.depth = 0;
if (node.children) { if (node.children) {
@@ -81,7 +74,7 @@ defineFunction({
return node; return node;
}, },
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const inner = mml.buildExpression(group.value.value, options); const inner = mml.buildExpression(ordargument(group.body), options);
const node = new mathMLTree.MathNode("mphantom", inner); const node = new mathMLTree.MathNode("mphantom", inner);
node.setAttribute("height", "0px"); node.setAttribute("height", "0px");
return node; return node;
@@ -100,23 +93,19 @@ defineFunction({
return { return {
type: "vphantom", type: "vphantom",
mode: parser.mode, mode: parser.mode,
value: { body,
type: "vphantom",
value: ordargument(body),
body: body,
},
}; };
}, },
htmlBuilder: (group, options) => { htmlBuilder: (group, options) => {
const inner = buildCommon.makeSpan( const inner = buildCommon.makeSpan(
["inner"], ["inner"],
[html.buildGroup(group.value.body, options.withPhantom())]); [html.buildGroup(group.body, options.withPhantom())]);
const fix = buildCommon.makeSpan(["fix"], []); const fix = buildCommon.makeSpan(["fix"], []);
return buildCommon.makeSpan( return buildCommon.makeSpan(
["mord", "rlap"], [inner, fix], options); ["mord", "rlap"], [inner, fix], options);
}, },
mathmlBuilder: (group, options) => { mathmlBuilder: (group, options) => {
const inner = mml.buildExpression(group.value.value, options); const inner = mml.buildExpression(ordargument(group.body), options);
const node = new mathMLTree.MathNode("mphantom", inner); const node = new mathMLTree.MathNode("mphantom", inner);
node.setAttribute("width", "0px"); node.setAttribute("width", "0px");
return node; return node;

View File

@@ -10,10 +10,10 @@ defineFunctionBuilders({
const table = new mathMLTree.MathNode("mtable", [ const table = new mathMLTree.MathNode("mtable", [
new mathMLTree.MathNode("mlabeledtr", [ new mathMLTree.MathNode("mlabeledtr", [
new mathMLTree.MathNode("mtd", [ new mathMLTree.MathNode("mtd", [
mml.buildExpressionRow(group.value.tag, options), mml.buildExpressionRow(group.tag, options),
]), ]),
new mathMLTree.MathNode("mtd", [ new mathMLTree.MathNode("mtd", [
mml.buildExpressionRow(group.value.body, options), mml.buildExpressionRow(group.body, options),
]), ]),
]), ]),
]); ]);

View File

@@ -10,13 +10,6 @@ import type {Measurement} from "./units";
export type NodeType = $Keys<ParseNodeTypes>; export type NodeType = $Keys<ParseNodeTypes>;
export type ParseNode<TYPE: NodeType> = $ElementType<ParseNodeTypes, TYPE>; export type ParseNode<TYPE: NodeType> = $ElementType<ParseNodeTypes, TYPE>;
export type LeftRightDelimType = {|
type: "leftright",
body: AnyParseNode[],
left: string,
right: string,
|};
// ParseNode's corresponding to Symbol `Group`s in symbols.js. // ParseNode's corresponding to Symbol `Group`s in symbols.js.
export type SymbolParseNode = export type SymbolParseNode =
ParseNode<"atom"> | ParseNode<"atom"> |
@@ -116,11 +109,8 @@ type ParseNodeTypes = {
type: "tag", type: "tag",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| body: AnyParseNode[],
type: "tag", tag: AnyParseNode[],
body: AnyParseNode[],
tag: AnyParseNode[],
|},
|}, |},
"text": {| "text": {|
type: "text", type: "text",
@@ -136,20 +126,14 @@ type ParseNodeTypes = {
type: "url", type: "url",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| url: string,
type: "url",
value: string,
|},
|}, |},
"verb": {| "verb": {|
type: "verb", type: "verb",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| body: string,
type: "verb", star: boolean,
body: string,
star: boolean,
|},
|}, |},
// From symbol groups, constructed in Parser.js via `symbols` lookup. // From symbol groups, constructed in Parser.js via `symbols` lookup.
// (Some of these have "-token" suffix to distinguish them from existing // (Some of these have "-token" suffix to distinguish them from existing
@@ -216,23 +200,17 @@ type ParseNodeTypes = {
type: "cr", type: "cr",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| newRow: boolean,
type: "cr", newLine: boolean,
newRow: boolean, size: ?ParseNode<"size">,
newLine: boolean,
size: ?ParseNode<"size">,
|},
|}, |},
"delimsizing": {| "delimsizing": {|
type: "delimsizing", type: "delimsizing",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| size: 1 | 2 | 3 | 4,
type: "delimsizing", mclass: "mopen" | "mclose" | "mrel" | "mord",
size: 1 | 2 | 3 | 4, delim: string,
mclass: "mopen" | "mclose" | "mrel" | "mord",
value: string,
|},
|}, |},
"enclose": {| "enclose": {|
type: "enclose", type: "enclose",
@@ -260,11 +238,8 @@ type ParseNodeTypes = {
type: "font", type: "font",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| font: string,
type: "font", body: AnyParseNode,
font: string,
body: AnyParseNode,
|},
|}, |},
"genfrac": {| "genfrac": {|
type: "genfrac", type: "genfrac",
@@ -294,11 +269,8 @@ type ParseNodeTypes = {
type: "href", type: "href",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| href: string,
type: "href", body: AnyParseNode[],
href: string,
body: AnyParseNode[],
|},
|}, |},
"htmlmathml": {| "htmlmathml": {|
type: "htmlmathml", type: "htmlmathml",
@@ -344,57 +316,37 @@ type ParseNodeTypes = {
type: "leftright", type: "leftright",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: LeftRightDelimType, body: AnyParseNode[],
left: string,
right: string,
|}, |},
"leftright-right": {| "leftright-right": {|
type: "leftright-right", type: "leftright-right",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| delim: string,
type: "leftright-right",
value: string,
|},
|}, |},
"mathchoice": {| "mathchoice": {|
type: "mathchoice", type: "mathchoice",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| display: AnyParseNode[],
type: "mathchoice", text: AnyParseNode[],
display: AnyParseNode[], script: AnyParseNode[],
text: AnyParseNode[], scriptscript: AnyParseNode[],
script: AnyParseNode[],
scriptscript: AnyParseNode[],
|},
|}, |},
"middle": {| "middle": {|
type: "middle", type: "middle",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| delim: string,
type: "middle",
value: string,
|},
|}, |},
"mclass": {| "mclass": {|
type: "mclass", type: "mclass",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| mclass: string,
type: "mclass", body: AnyParseNode[],
mclass: string,
value: AnyParseNode[],
|},
|},
"mod": {|
type: "mod",
mode: Mode,
loc?: ?SourceLocation,
value: {|
type: "mod",
modType: string,
value: ?AnyParseNode[],
|},
|}, |},
"operatorname": {| "operatorname": {|
type: "operatorname", type: "operatorname",
@@ -418,30 +370,19 @@ type ParseNodeTypes = {
type: "phantom", type: "phantom",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| body: AnyParseNode[],
type: "phantom",
value: AnyParseNode[],
|},
|}, |},
"hphantom": {| "hphantom": {|
type: "hphantom", type: "hphantom",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| body: AnyParseNode,
type: "hphantom",
body: AnyParseNode,
value: AnyParseNode[],
|},
|}, |},
"vphantom": {| "vphantom": {|
type: "vphantom", type: "vphantom",
mode: Mode, mode: Mode,
loc?: ?SourceLocation, loc?: ?SourceLocation,
value: {| body: AnyParseNode,
type: "vphantom",
body: AnyParseNode,
value: AnyParseNode[],
|},
|}, |},
"raisebox": {| "raisebox": {|
type: "raisebox", type: "raisebox",

View File

@@ -32,11 +32,8 @@ const parseTree = function(toParse: string, settings: Settings): AnyParseNode[]
tree = [{ tree = [{
type: "tag", type: "tag",
mode: "text", mode: "text",
value: { body: tree,
type: "tag", tag: parser.parse(),
body: tree,
tag: parser.parse(),
},
}]; }];
} }

View File

@@ -110,7 +110,7 @@ const getBaseElem = function(group: AnyParseNode): AnyParseNode {
return group; return group;
} }
} else if (group.type === "font") { } else if (group.type === "font") {
return getBaseElem(group.value.body); return getBaseElem(group.body);
} else { } else {
return group; return group;
} }

View File

@@ -751,22 +751,19 @@ exports[`An implicit group parser within optional groups should work with old fo
"value": [ "value": [
{ {
"type": "font", "type": "font",
"mode": "math", "body": {
"value": { "type": "ordgroup",
"type": "font", "mode": "math",
"body": { "value": [
"type": "ordgroup", {
"mode": "math", "type": "textord",
"value": [ "mode": "math",
{ "value": "3"
"type": "textord", }
"mode": "math", ]
"value": "3" },
} "font": "mathtt",
] "mode": "math"
},
"font": "mathtt"
}
} }
] ]
} }

View File

@@ -95,7 +95,7 @@ describe("A rel parser", function() {
group = group.value.html[0]; group = group.value.html[0];
} }
if (group.type === "mclass") { if (group.type === "mclass") {
expect(group.value.mclass).toEqual("mrel"); expect(group.mclass).toEqual("mrel");
} else { } else {
expect(group.type).toEqual("atom"); expect(group.type).toEqual("atom");
expect(group.family).toEqual("rel"); expect(group.family).toEqual("rel");
@@ -895,16 +895,16 @@ describe("A delimiter sizing parser", function() {
const leftParse = getParsed(normalDelim)[0]; const leftParse = getParsed(normalDelim)[0];
const rightParse = getParsed(bigDelim)[0]; const rightParse = getParsed(bigDelim)[0];
expect(leftParse.value.mclass).toEqual("mopen"); expect(leftParse.mclass).toEqual("mopen");
expect(rightParse.value.mclass).toEqual("mclose"); expect(rightParse.mclass).toEqual("mclose");
}); });
it("should parse the correct size delimiter", function() { it("should parse the correct size delimiter", function() {
const smallParse = getParsed(normalDelim)[0]; const smallParse = getParsed(normalDelim)[0];
const bigParse = getParsed(bigDelim)[0]; const bigParse = getParsed(bigDelim)[0];
expect(smallParse.value.size).toEqual(1); expect(smallParse.size).toEqual(1);
expect(bigParse.value.size).toEqual(4); expect(bigParse.size).toEqual(4);
}); });
}); });
@@ -1122,8 +1122,8 @@ describe("A left/right parser", function() {
const parse = getParsed(normalLeftRight)[0]; const parse = getParsed(normalLeftRight)[0];
expect(parse.type).toEqual("leftright"); expect(parse.type).toEqual("leftright");
expect(parse.value.left).toEqual("("); expect(parse.left).toEqual("(");
expect(parse.value.right).toEqual(")"); expect(parse.right).toEqual(")");
}); });
it("should error when it is mismatched", function() { it("should error when it is mismatched", function() {
@@ -1476,37 +1476,37 @@ describe("A font parser", function() {
it("should produce the correct fonts", function() { it("should produce the correct fonts", function() {
const mathbbParse = getParsed`\mathbb x`[0]; const mathbbParse = getParsed`\mathbb x`[0];
expect(mathbbParse.value.font).toEqual("mathbb"); expect(mathbbParse.font).toEqual("mathbb");
expect(mathbbParse.value.type).toEqual("font"); expect(mathbbParse.type).toEqual("font");
const mathrmParse = getParsed`\mathrm x`[0]; const mathrmParse = getParsed`\mathrm x`[0];
expect(mathrmParse.value.font).toEqual("mathrm"); expect(mathrmParse.font).toEqual("mathrm");
expect(mathrmParse.value.type).toEqual("font"); expect(mathrmParse.type).toEqual("font");
const mathitParse = getParsed`\mathit x`[0]; const mathitParse = getParsed`\mathit x`[0];
expect(mathitParse.value.font).toEqual("mathit"); expect(mathitParse.font).toEqual("mathit");
expect(mathitParse.value.type).toEqual("font"); expect(mathitParse.type).toEqual("font");
const mathcalParse = getParsed`\mathcal C`[0]; const mathcalParse = getParsed`\mathcal C`[0];
expect(mathcalParse.value.font).toEqual("mathcal"); expect(mathcalParse.font).toEqual("mathcal");
expect(mathcalParse.value.type).toEqual("font"); expect(mathcalParse.type).toEqual("font");
const mathfrakParse = getParsed`\mathfrak C`[0]; const mathfrakParse = getParsed`\mathfrak C`[0];
expect(mathfrakParse.value.font).toEqual("mathfrak"); expect(mathfrakParse.font).toEqual("mathfrak");
expect(mathfrakParse.value.type).toEqual("font"); expect(mathfrakParse.type).toEqual("font");
}); });
it("should parse nested font commands", function() { it("should parse nested font commands", function() {
const nestedParse = getParsed`\mathbb{R \neq \mathrm{R}}`[0]; const nestedParse = getParsed`\mathbb{R \neq \mathrm{R}}`[0];
expect(nestedParse.value.font).toEqual("mathbb"); expect(nestedParse.font).toEqual("mathbb");
expect(nestedParse.value.type).toEqual("font"); expect(nestedParse.type).toEqual("font");
const bbBody = nestedParse.value.body.value; const bbBody = nestedParse.body.value;
expect(bbBody).toHaveLength(3); expect(bbBody).toHaveLength(3);
expect(bbBody[0].type).toEqual("mathord"); expect(bbBody[0].type).toEqual("mathord");
expect(bbBody[2].type).toEqual("font"); expect(bbBody[2].type).toEqual("font");
expect(bbBody[2].value.font).toEqual("mathrm"); expect(bbBody[2].font).toEqual("mathrm");
expect(bbBody[2].value.type).toEqual("font"); expect(bbBody[2].type).toEqual("font");
}); });
it("should work with \\textcolor", function() { it("should work with \\textcolor", function() {
@@ -1515,8 +1515,8 @@ describe("A font parser", function() {
expect(colorMathbbParse.value.color).toEqual("blue"); expect(colorMathbbParse.value.color).toEqual("blue");
const body = colorMathbbParse.value.value; const body = colorMathbbParse.value.value;
expect(body).toHaveLength(1); expect(body).toHaveLength(1);
expect(body[0].value.type).toEqual("font"); expect(body[0].type).toEqual("font");
expect(body[0].value.font).toEqual("mathbb"); expect(body[0].font).toEqual("mathbb");
}); });
it("should not parse a series of font commands", function() { it("should not parse a series of font commands", function() {
@@ -1525,13 +1525,13 @@ describe("A font parser", function() {
it("should nest fonts correctly", function() { it("should nest fonts correctly", function() {
const bf = getParsed`\mathbf{a\mathrm{b}c}`[0]; const bf = getParsed`\mathbf{a\mathrm{b}c}`[0];
expect(bf.value.type).toEqual("font"); expect(bf.type).toEqual("font");
expect(bf.value.font).toEqual("mathbf"); expect(bf.font).toEqual("mathbf");
expect(bf.value.body.value).toHaveLength(3); expect(bf.body.value).toHaveLength(3);
expect(bf.value.body.value[0].value).toEqual("a"); expect(bf.body.value[0].value).toEqual("a");
expect(bf.value.body.value[1].value.type).toEqual("font"); expect(bf.body.value[1].type).toEqual("font");
expect(bf.value.body.value[1].value.font).toEqual("mathrm"); expect(bf.body.value[1].font).toEqual("mathrm");
expect(bf.value.body.value[2].value).toEqual("c"); expect(bf.body.value[2].value).toEqual("c");
}); });
it("should have the correct greediness", function() { it("should have the correct greediness", function() {
@@ -2292,7 +2292,7 @@ describe("A phantom parser", function() {
const parse = getParsed`\phantom{x}`[0]; const parse = getParsed`\phantom{x}`[0];
expect(parse.type).toEqual("phantom"); expect(parse.type).toEqual("phantom");
expect(parse.value.value).toBeDefined(); expect(parse.body).toBeDefined();
}); });
}); });
@@ -2499,17 +2499,17 @@ describe("href and url commands", function() {
it("should allow letters [#$%&~_^] without escaping", function() { it("should allow letters [#$%&~_^] without escaping", function() {
const url = "http://example.org/~bar/#top?foo=$foo&bar=ba^r_boo%20baz"; const url = "http://example.org/~bar/#top?foo=$foo&bar=ba^r_boo%20baz";
const parsed1 = getParsed(`\\href{${url}}{\\alpha}`)[0]; const parsed1 = getParsed(`\\href{${url}}{\\alpha}`)[0];
expect(parsed1.value.href).toBe(url); expect(parsed1.href).toBe(url);
const parsed2 = getParsed(`\\url{${url}}`)[0]; const parsed2 = getParsed(`\\url{${url}}`)[0];
expect(parsed2.value.href).toBe(url); expect(parsed2.href).toBe(url);
}); });
it("should allow balanced braces in url", function() { it("should allow balanced braces in url", function() {
const url = "http://example.org/{too}"; const url = "http://example.org/{too}";
const parsed1 = getParsed(`\\href{${url}}{\\alpha}`)[0]; const parsed1 = getParsed(`\\href{${url}}{\\alpha}`)[0];
expect(parsed1.value.href).toBe(url); expect(parsed1.href).toBe(url);
const parsed2 = getParsed(`\\url{${url}}`)[0]; const parsed2 = getParsed(`\\url{${url}}`)[0];
expect(parsed2.value.href).toBe(url); expect(parsed2.href).toBe(url);
}); });
it("should not allow unbalanced brace(s) in url", function() { it("should not allow unbalanced brace(s) in url", function() {
@@ -2523,9 +2523,9 @@ describe("href and url commands", function() {
const url = "http://example.org/~bar/#top?foo=$}foo{&bar=bar^r_boo%20baz"; const url = "http://example.org/~bar/#top?foo=$}foo{&bar=bar^r_boo%20baz";
const input = url.replace(/([#$%&~_^{}])/g, '\\$1'); const input = url.replace(/([#$%&~_^{}])/g, '\\$1');
const parsed1 = getParsed(`\\href{${input}}{\\alpha}`)[0]; const parsed1 = getParsed(`\\href{${input}}{\\alpha}`)[0];
expect(parsed1.value.href).toBe(url); expect(parsed1.href).toBe(url);
const parsed2 = getParsed(`\\url{${input}}`)[0]; const parsed2 = getParsed(`\\url{${input}}`)[0];
expect(parsed2.value.href).toBe(url); expect(parsed2.href).toBe(url);
}); });
it("should be marked up correctly", function() { it("should be marked up correctly", function() {