Remove checkNodeType and assert/checkAtomFamily (#2137)

We used functions with $FlowFixMe as Flow couldn't refine ParseNode 
using its type. It seems the issue has been fixed and complicated 
function calls can be removed.
This commit is contained in:
ylemkimon
2019-11-30 05:08:22 +09:00
committed by Kevin Barabash
parent 981a9ea3a0
commit fa8fbc0c18
11 changed files with 55 additions and 135 deletions

View File

@@ -7,7 +7,6 @@ import {validUnit} from "./units";
import {supportedCodepoint} from "./unicodeScripts";
import unicodeAccents from "./unicodeAccents";
import unicodeSymbols from "./unicodeSymbols";
import {checkNodeType} from "./parseNode";
import ParseError from "./ParseError";
import {combiningDiacriticalMarksEndRegex} from "./Lexer";
import Settings from "./Settings";
@@ -206,15 +205,14 @@ export default class Parser {
let funcName;
for (let i = 0; i < body.length; i++) {
const node = checkNodeType(body[i], "infix");
if (node) {
if (body[i].type === "infix") {
if (overIndex !== -1) {
throw new ParseError(
"only one infix operator per group",
node.token);
body[i].token);
}
overIndex = i;
funcName = node.replaceWith;
funcName = body[i].replaceWith;
}
}
@@ -329,21 +327,18 @@ export default class Parser {
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
// We got a limit control
let opNode = checkNodeType(base, "op");
if (opNode) {
if (base && base.type === "op") {
const limits = lex.text === "\\limits";
opNode.limits = limits;
opNode.alwaysHandleSupSub = true;
base.limits = limits;
base.alwaysHandleSupSub = true;
} else if (base && base.type === "operatorname"
&& base.alwaysHandleSupSub) {
const limits = lex.text === "\\limits";
base.limits = limits;
} else {
opNode = checkNodeType(base, "operatorname");
if (opNode && opNode.alwaysHandleSupSub) {
const limits = lex.text === "\\limits";
opNode.limits = limits;
} else {
throw new ParseError(
"Limit controls must follow a math operator",
lex);
}
throw new ParseError(
"Limit controls must follow a math operator",
lex);
}
this.consume();
} else if (lex.text === "^") {

View File

@@ -11,7 +11,6 @@ import Style from "./Style";
import buildCommon from "./buildCommon";
import {Anchor} from "./domTree";
import utils from "./utils";
import {checkNodeType} from "./parseNode";
import {spacings, tightSpacings} from "./spacingData";
import {_htmlGroupBuilders as groupBuilders} from "./defineFunction";
import {DocumentFragment} from "./tree";
@@ -83,11 +82,8 @@ export const buildExpression = function(
let glueOptions = options;
if (expression.length === 1) {
const node = checkNodeType(expression[0], "sizing") ||
checkNodeType(expression[0], "styling");
if (!node) {
// No match.
} else if (node.type === "sizing") {
const node = expression[0];
if (node.type === "sizing") {
glueOptions = options.havingSize(node.size);
} else if (node.type === "styling") {
glueOptions = options.havingStyle(styleMap[node.style]);

View File

@@ -1,6 +1,4 @@
// @flow
import {checkNodeType} from "./parseNode";
import type Parser from "./Parser";
import type {ParseNode, AnyParseNode, NodeType, UnsupportedCmdParseNode}
from "./parseNode";
@@ -228,6 +226,5 @@ export function defineFunctionBuilders<NODETYPE: NodeType>({
// Since the corresponding buildHTML/buildMathML function expects a
// list of elements, we normalize for different kinds of arguments
export const ordargument = function(arg: AnyParseNode): AnyParseNode[] {
const node = checkNodeType(arg, "ordgroup");
return node ? node.body : [arg];
return arg.type === "ordgroup" ? arg.body : [arg];
};

View File

@@ -6,7 +6,7 @@ import defineFunction from "../defineFunction";
import mathMLTree from "../mathMLTree";
import ParseError from "../ParseError";
import {assertNodeType, assertSymbolNodeType} from "../parseNode";
import {checkNodeType, checkSymbolNodeType} from "../parseNode";
import {checkSymbolNodeType} from "../parseNode";
import {calculateSize} from "../units";
import utils from "../utils";
@@ -547,11 +547,10 @@ const alignedHandler = function(context, args) {
mode: context.mode,
body: [],
};
const ordgroup = checkNodeType(args[0], "ordgroup");
if (ordgroup) {
if (args[0] && args[0].type === "ordgroup") {
let arg0 = "";
for (let i = 0; i < ordgroup.body.length; i++) {
const textord = assertNodeType(ordgroup.body[i], "textord");
for (let i = 0; i < args[0].body.length; i++) {
const textord = assertNodeType(args[0].body[i], "textord");
arg0 += textord.text;
}
numMaths = Number(arg0);

View File

@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import utils from "../utils";
import stretchy from "../stretchy";
import {assertNodeType, checkNodeType} from "../parseNode";
import {assertNodeType} from "../parseNode";
import {assertSpan, assertSymbolDomNode} from "../domTree";
import * as html from "../buildHTML";
@@ -20,9 +20,8 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
let base: AnyParseNode;
let group: ParseNode<"accent">;
const supSub: ?ParseNode<"supsub"> = checkNodeType(grp, "supsub");
let supSubGroup;
if (supSub) {
if (grp && grp.type === "supsub") {
// If our base is a character box, and we have superscripts and
// subscripts, the supsub will defer to us. In particular, we want
// to attach the superscripts and subscripts to the inner body (so
@@ -32,18 +31,18 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
// rendering that, while keeping track of where the accent is.
// The real accent group is the base of the supsub group
group = assertNodeType(supSub.base, "accent");
group = assertNodeType(grp.base, "accent");
// The character box is the base of the accent group
base = group.base;
// Stick the character box into the base of the supsub group
supSub.base = base;
grp.base = base;
// Rerender the supsub group with its new base, and store that
// result.
supSubGroup = assertSpan(html.buildGroup(supSub, options));
supSubGroup = assertSpan(html.buildGroup(grp, options));
// reset original base
supSub.base = group;
grp.base = group;
} else {
group = assertNodeType(grp, "accent");
base = group.base;

View File

@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
import delimiter from "../delimiter";
import mathMLTree from "../mathMLTree";
import Style from "../Style";
import {assertNodeType, assertAtomFamily, checkNodeType} from "../parseNode";
import {assertNodeType} from "../parseNode";
import {assert} from "../utils";
import * as html from "../buildHTML";
@@ -382,17 +382,10 @@ defineFunction({
const denom = args[5];
// Look into the parse nodes to get the desired delimiters.
let leftNode = checkNodeType(args[0], "atom");
if (leftNode) {
leftNode = assertAtomFamily(args[0], "open");
}
const leftDelim = leftNode ? delimFromValue(leftNode.text) : null;
let rightNode = checkNodeType(args[1], "atom");
if (rightNode) {
rightNode = assertAtomFamily(args[1], "close");
}
const rightDelim = rightNode ? delimFromValue(rightNode.text) : null;
const leftDelim = args[0].type === "atom" && args[0].family === "open"
? delimFromValue(args[0].text) : null;
const rightDelim = args[1].type === "atom" && args[1].family === "close"
? delimFromValue(args[1].text) : null;
const barNode = assertNodeType(args[2], "size");
let hasBarLine;
@@ -409,14 +402,14 @@ defineFunction({
// Find out if we want displaystyle, textstyle, etc.
let size = "auto";
let styl = checkNodeType(args[3], "ordgroup");
if (styl) {
let styl = args[3];
if (styl.type === "ordgroup") {
if (styl.body.length > 0) {
const textOrd = assertNodeType(styl.body[0], "textord");
size = stylArray[Number(textOrd.text)];
}
} else {
styl = assertNodeType(args[3], "textord");
styl = assertNodeType(styl, "textord");
size = stylArray[Number(styl.text)];
}

View File

@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import stretchy from "../stretchy";
import Style from "../Style";
import {assertNodeType, checkNodeType} from "../parseNode";
import {assertNodeType} from "../parseNode";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
@@ -20,15 +20,14 @@ export const htmlBuilder: HtmlBuilderSupSub<"horizBrace"> = (grp, options) => {
// Pull out the `ParseNode<"horizBrace">` if `grp` is a "supsub" node.
let supSubGroup;
let group: ParseNode<"horizBrace">;
const supSub = checkNodeType(grp, "supsub");
if (supSub) {
if (grp.type === "supsub") {
// Ref: LaTeX source2e: }}}}\limits}
// i.e. LaTeX treats the brace similar to an op and passes it
// with \limits, so we need to assign supsub style.
supSubGroup = supSub.sup ?
html.buildGroup(supSub.sup, options.havingStyle(style.sup()), options) :
html.buildGroup(supSub.sub, options.havingStyle(style.sub()), options);
group = assertNodeType(supSub.base, "horizBrace");
supSubGroup = grp.sup ?
html.buildGroup(grp.sup, options.havingStyle(style.sup()), options) :
html.buildGroup(grp.sub, options.havingStyle(style.sub()), options);
group = assertNodeType(grp.base, "horizBrace");
} else {
group = assertNodeType(grp, "horizBrace");
}

View File

@@ -7,7 +7,7 @@ import * as mathMLTree from "../mathMLTree";
import utils from "../utils";
import Style from "../Style";
import {assembleSupSub} from "./utils/assembleSupSub";
import {assertNodeType, checkNodeType} from "../parseNode";
import {assertNodeType} from "../parseNode";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
@@ -28,14 +28,13 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
let subGroup;
let hasLimits = false;
let group: ParseNode<"op">;
const supSub = checkNodeType(grp, "supsub");
if (supSub) {
if (grp.type === "supsub") {
// If we have limits, supsub will pass us its group to handle. Pull
// out the superscript and subscript and set the group to the op in
// its base.
supGroup = supSub.sup;
subGroup = supSub.sub;
group = assertNodeType(supSub.base, "op");
supGroup = grp.sup;
subGroup = grp.sub;
group = assertNodeType(grp.base, "op");
hasLimits = true;
} else {
group = assertNodeType(grp, "op");

View File

@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import {SymbolNode} from "../domTree";
import {assembleSupSub} from "./utils/assembleSupSub";
import {assertNodeType, checkNodeType} from "../parseNode";
import {assertNodeType} from "../parseNode";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
@@ -21,14 +21,13 @@ export const htmlBuilder: HtmlBuilderSupSub<"operatorname"> = (grp, options) =>
let subGroup;
let hasLimits = false;
let group: ParseNode<"operatorname">;
const supSub = checkNodeType(grp, "supsub");
if (supSub) {
if (grp.type === "supsub") {
// If we have limits, supsub will pass us its group to handle. Pull
// out the superscript and subscript and set the group to the op in
// its base.
supGroup = supSub.sup;
subGroup = supSub.sub;
group = assertNodeType(supSub.base, "operatorname");
supGroup = grp.sup;
subGroup = grp.sub;
group = assertNodeType(grp.base, "operatorname");
hasLimits = true;
} else {
group = assertNodeType(grp, "operatorname");

View File

@@ -5,7 +5,6 @@ import {SymbolNode} from "../domTree";
import mathMLTree from "../mathMLTree";
import utils from "../utils";
import Style from "../Style";
import {checkNodeType} from "../parseNode";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
@@ -197,12 +196,11 @@ defineFunctionBuilders({
let isOver;
let isSup;
const horizBrace = checkNodeType(group.base, "horizBrace");
if (horizBrace) {
if (group.base && group.base.type === "horizBrace") {
isSup = !!group.sup;
if (isSup === horizBrace.isOver) {
if (isSup === group.base.isOver) {
isBrace = true;
isOver = horizBrace.isOver;
isOver = group.base.isOver;
}
}

View File

@@ -441,66 +441,12 @@ export function assertNodeType<NODETYPE: NodeType>(
node: ?AnyParseNode,
type: NODETYPE,
): ParseNode<NODETYPE> {
const typedNode = checkNodeType(node, type);
if (!typedNode) {
if (!node || node.type !== type) {
throw new Error(
`Expected node of type ${type}, but got ` +
(node ? `node of type ${node.type}` : String(node)));
}
// $FlowFixMe: Unsure why.
return typedNode;
}
/**
* Returns the node more strictly typed iff it is of the given type. Otherwise,
* returns null.
*/
export function checkNodeType<NODETYPE: NodeType>(
node: ?AnyParseNode,
type: NODETYPE,
): ?ParseNode<NODETYPE> {
if (node && node.type === type) {
// The definition of ParseNode<TYPE> doesn't communicate to flow that
// `type: TYPE` (as that's not explicitly mentioned anywhere), though that
// happens to be true for all our value types.
// $FlowFixMe
return node;
}
return null;
}
/**
* Asserts that the node is of the given type and returns it with stricter
* typing. Throws if the node's type does not match.
*/
export function assertAtomFamily(
node: ?AnyParseNode,
family: Atom,
): ParseNode<"atom"> {
const typedNode = checkAtomFamily(node, family);
if (!typedNode) {
throw new Error(
`Expected node of type "atom" and family "${family}", but got ` +
(node ?
(node.type === "atom" ?
`atom of family ${node.family}` :
`node of type ${node.type}`) :
String(node)));
}
return typedNode;
}
/**
* Returns the node more strictly typed iff it is of the given type. Otherwise,
* returns null.
*/
export function checkAtomFamily(
node: ?AnyParseNode,
family: Atom,
): ?ParseNode<"atom"> {
return node && node.type === "atom" && node.family === family ?
node :
null;
return node;
}
/**