Make ParseNodeTypes more regular (#1373)

Make ParseNodeTypes more regular: make 'size' and 'url' node values be objects.
This commit is contained in:
Kevin Barabash
2018-05-28 18:55:59 +02:00
committed by Ashish Myles
parent 659b4e30c8
commit 3ec752f5f1
12 changed files with 2993 additions and 2088 deletions

4988
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -38,23 +38,15 @@ export default class ParseNode<TYPE: NodeType> {
export type NodeType = $Keys<ParseNodeTypes>;
export type NodeValue<TYPE: NodeType> = $ElementType<ParseNodeTypes, TYPE>;
export type AccentStructType = {|
type: "accent" | "accentUnder",
label: string,
isStretchy?: boolean,
isShifty?: boolean,
base: ParseNode<*>,
|};
export type LeftRightDelimType = {|
type?: "leftright",
type: "leftright",
body: ParseNode<*>[],
left: string,
right: string,
|};
// Map from `type` field value to corresponding `value` type.
type ParseNodeTypes = {
export type ParseNodeTypes = {
"array": ArrayEnvNodeData,
"color": {|
type: "color",
@@ -62,14 +54,6 @@ type ParseNodeTypes = {
value: ParseNode<*>[],
|},
"color-token": string,
"leftright": {|
body: [{|
type: "array",
hskipBeforeAndAfter: boolean,
|} | ParseNode<*>],
left: string,
right: string,
|},
// To avoid requiring run-time type assertions, this more carefully captures
// the requirements on the fields per the op.js htmlBuilder logic:
// - `body` and `value` are NEVER set simultanouesly.
@@ -92,18 +76,23 @@ type ParseNodeTypes = {
value: ParseNode<*>[],
|},
"ordgroup": ParseNode<*>[],
"size": Measurement,
"size": {|
type: "size",
value: Measurement,
|},
"styling": {|
type: "styling",
style: StyleStr,
value: ParseNode<*>[],
|},
"supsub": {|
type: "supsub",
base: ?ParseNode<*>,
sup?: ?ParseNode<*>,
sub?: ?ParseNode<*>,
|},
"tag": {|
type: "tag",
body: ParseNode<*>[],
tag: ParseNode<*>[],
|},
@@ -112,8 +101,12 @@ type ParseNodeTypes = {
body: ParseNode<*>[],
font?: string,
|},
"url": string,
"url": {|
type: "url",
value: string,
|},
"verb": {|
type: "verb",
body: string,
star: boolean,
|},
@@ -133,8 +126,20 @@ type ParseNodeTypes = {
"textord": string,
// From functions.js and functions/*.js. See also "color", "op", "styling",
// and "text" above.
"accent": AccentStructType,
"accentUnder": AccentStructType,
"accent": {|
type: "accent",
label: string,
isStretchy?: boolean,
isShifty?: boolean,
base: ParseNode<*>,
|},
"accentUnder": {|
type: "accentUnder",
label: string,
isStretchy?: boolean,
isShifty?: boolean,
base: ParseNode<*>,
|},
"cr": {|
type: "cr",
newRow: boolean,

View File

@@ -407,6 +407,7 @@ export default class Parser {
if (superscript || subscript) {
// If we got either a superscript or subscript, create a supsub
return new ParseNode("supsub", {
type: "supsub",
base: base,
sup: superscript,
sub: subscript,
@@ -794,7 +795,10 @@ export default class Parser {
// and keep them as-is. Some browser will replace backslashes with
// forward slashes.
const url = raw.replace(/\\([#$%&~_^{}])/g, '$1');
return newArgument(new ParseNode("url", url, this.mode), res);
return newArgument(new ParseNode("url", {
type: "url",
value: url,
}, this.mode), res);
}
/**
@@ -822,7 +826,10 @@ export default class Parser {
if (!validUnit(data)) {
throw new ParseError("Invalid unit: '" + data.unit + "'", res);
}
return newArgument(new ParseNode("size", data, this.mode), res);
return newArgument(new ParseNode("size", {
type: "size",
value: data,
}, this.mode), res);
}
/**
@@ -936,6 +943,7 @@ export default class Parser {
arg = arg.slice(1, -1); // remove first and last char
return newArgument(
new ParseNode("verb", {
type: "verb",
body: arg,
star: star,
}, "text"), nucleus);

View File

@@ -207,7 +207,7 @@ const htmlBuilder = function(group, options) {
const rowGap = groupValue.rowGaps[r];
let gap = 0;
if (rowGap) {
gap = calculateSize(rowGap.value, options);
gap = calculateSize(rowGap.value.value, options);
if (gap > 0) { // \@argarraycr
gap += arstrutDepth;
if (depth < gap) {
@@ -502,6 +502,7 @@ defineEnvironment({
res = parseArray(context.parser, res, dCellStyle(context.envName));
if (delimiters) {
res = new ParseNode("leftright", {
type: "leftright",
body: [res],
left: delimiters[0],
right: delimiters[1],
@@ -549,6 +550,7 @@ defineEnvironment({
};
res = parseArray(context.parser, res, dCellStyle(context.envName));
res = new ParseNode("leftright", {
type: "leftright",
body: [res],
left: "\\{",
right: ".",

View File

@@ -58,7 +58,7 @@ defineFunction({
span.classes.push("newline");
if (group.value.size) {
span.style.marginTop =
calculateSize(group.value.size.value, options) + "em";
calculateSize(group.value.size.value.value, options) + "em";
}
}
return span;
@@ -70,7 +70,7 @@ defineFunction({
node.setAttribute("linebreak", "newline");
if (group.value.size) {
node.setAttribute("height",
calculateSize(group.value.size.value, options) + "em");
calculateSize(group.value.size.value.value, options) + "em");
}
}
return node;

View File

@@ -15,7 +15,7 @@ defineFunction({
},
handler: (context, args) => {
const body = args[1];
const href = assertNodeType(args[0], "url").value;
const href = assertNodeType(args[0], "url").value.value;
return {
type: "href",
href: href,

View File

@@ -4,7 +4,8 @@
import defineFunction from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import { calculateSize } from "../units";
import {calculateSize} from "../units";
import {assertNodeType} from "../ParseNode";
// TODO: \hskip and \mskip should support plus and minus in lengths
@@ -17,14 +18,15 @@ defineFunction({
allowedInText: true,
},
handler: (context, args) => {
const size = assertNodeType(args[0], "size");
if (context.parser.settings.strict) {
const mathFunction = (context.funcName[1] === 'm'); // \mkern, \mskip
const muUnit = (args[0].value.unit === 'mu');
const muUnit = (size.value.value.unit === 'mu');
if (mathFunction) {
if (!muUnit) {
context.parser.settings.reportNonstrict("mathVsTextUnits",
`LaTeX's ${context.funcName} supports only mu units, ` +
`not ${args[0].value.unit} units`);
`not ${size.value.value.unit} units`);
}
if (context.parser.mode !== "math") {
context.parser.settings.reportNonstrict("mathVsTextUnits",
@@ -39,7 +41,7 @@ defineFunction({
}
return {
type: "kern",
dimension: args[0].value,
dimension: size.value.value,
};
},
htmlBuilder: (group, options) => {

View File

@@ -83,6 +83,7 @@ defineFunction({
}, baseArg.mode);
const supsub = new ParseNode("supsub", {
type: "supsub",
base: baseOp,
sup: context.funcName === "\\underset" ? null : shiftedArg,
sub: context.funcName === "\\underset" ? shiftedArg : null,

View File

@@ -39,7 +39,7 @@ defineFunction({
size: 6, // simulate \normalsize
}, group.mode);
const body = sizing.htmlBuilder(sizedText, options);
const dy = calculateSize(group.value.dy.value, options);
const dy = calculateSize(group.value.dy.value.value, options);
return buildCommon.makeVList({
positionType: "shift",
positionData: -dy,
@@ -49,7 +49,8 @@ defineFunction({
mathmlBuilder(group, options) {
const node = new mathMLTree.MathNode(
"mpadded", [mml.buildGroup(group.value.body, options)]);
const dy = group.value.dy.value.number + group.value.dy.value.unit;
const dy =
group.value.dy.value.value.number + group.value.dy.value.value.unit;
node.setAttribute("voffset", dy);
return node;
},

View File

@@ -20,8 +20,8 @@ defineFunction({
return {
type: "rule",
shift: shift && shift.value,
width: width.value,
height: height.value,
width: width.value.value,
height: height.value.value,
};
},
htmlBuilder(group, options) {

View File

@@ -28,6 +28,7 @@ const parseTree = function(toParse: string, settings: Settings): ParseNode<*>[]
}
parser.gullet.feed("\\df@tag");
tree = [new ParseNode("tag", {
type: "tag",
body: tree,
tag: parser.parse(),
}, "text")];

View File

@@ -1803,6 +1803,7 @@ describe("A parse tree generator", function() {
{
"type": "supsub",
"value": {
"type": "supsub",
"base": {
"type": "mathord",
"value": "\\sigma",