From fa8fbc0c18e5e3fe98f347ceed3a48699d561c72 Mon Sep 17 00:00:00 2001 From: ylemkimon Date: Sat, 30 Nov 2019 05:08:22 +0900 Subject: [PATCH] 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. --- src/Parser.js | 31 ++++++++----------- src/buildHTML.js | 8 ++--- src/defineFunction.js | 5 +-- src/environments/array.js | 9 +++--- src/functions/accent.js | 13 ++++---- src/functions/genfrac.js | 23 +++++--------- src/functions/horizBrace.js | 13 ++++---- src/functions/op.js | 11 +++---- src/functions/operatorname.js | 11 +++---- src/functions/supsub.js | 8 ++--- src/parseNode.js | 58 ++--------------------------------- 11 files changed, 55 insertions(+), 135 deletions(-) diff --git a/src/Parser.js b/src/Parser.js index 1ca2df9b..c79fb948 100644 --- a/src/Parser.js +++ b/src/Parser.js @@ -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 === "^") { diff --git a/src/buildHTML.js b/src/buildHTML.js index 2bc79edb..541b46f7 100644 --- a/src/buildHTML.js +++ b/src/buildHTML.js @@ -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]); diff --git a/src/defineFunction.js b/src/defineFunction.js index 286d6284..d0711569 100644 --- a/src/defineFunction.js +++ b/src/defineFunction.js @@ -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({ // 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]; }; diff --git a/src/environments/array.js b/src/environments/array.js index 045e40c5..2500ea39 100644 --- a/src/environments/array.js +++ b/src/environments/array.js @@ -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); diff --git a/src/functions/accent.js b/src/functions/accent.js index 79bbb604..79087496 100644 --- a/src/functions/accent.js +++ b/src/functions/accent.js @@ -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; diff --git a/src/functions/genfrac.js b/src/functions/genfrac.js index 48c013ca..be0c1ea7 100644 --- a/src/functions/genfrac.js +++ b/src/functions/genfrac.js @@ -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)]; } diff --git a/src/functions/horizBrace.js b/src/functions/horizBrace.js index d1bbd14e..259f0d60 100644 --- a/src/functions/horizBrace.js +++ b/src/functions/horizBrace.js @@ -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"); } diff --git a/src/functions/op.js b/src/functions/op.js index 3cf98ba7..fa167d59 100644 --- a/src/functions/op.js +++ b/src/functions/op.js @@ -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"); diff --git a/src/functions/operatorname.js b/src/functions/operatorname.js index 4f009e7c..f931d62f 100644 --- a/src/functions/operatorname.js +++ b/src/functions/operatorname.js @@ -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"); diff --git a/src/functions/supsub.js b/src/functions/supsub.js index 2129cabe..d0363079 100644 --- a/src/functions/supsub.js +++ b/src/functions/supsub.js @@ -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; } } diff --git a/src/parseNode.js b/src/parseNode.js index 49e7de0c..b83d3dde 100644 --- a/src/parseNode.js +++ b/src/parseNode.js @@ -441,66 +441,12 @@ export function assertNodeType( node: ?AnyParseNode, type: NODETYPE, ): ParseNode { - 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( - node: ?AnyParseNode, - type: NODETYPE, -): ?ParseNode { - if (node && node.type === type) { - // The definition of ParseNode 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; } /**