UNPKG

speech-rule-engine

Version:

A standalone speech rule engine for XML structures, based on the original engine from ChromeVox.

1,120 lines 92.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SemanticProcessor = void 0; const DomUtil = __importStar(require("../common/dom_util.js")); const semantic_attr_js_1 = require("./semantic_attr.js"); const semantic_meaning_js_1 = require("./semantic_meaning.js"); const semantic_heuristic_factory_js_1 = require("./semantic_heuristic_factory.js"); const semantic_node_factory_js_1 = require("./semantic_node_factory.js"); const SemanticPred = __importStar(require("./semantic_pred.js")); const SemanticUtil = __importStar(require("./semantic_util.js")); const semantic_util_js_1 = require("./semantic_util.js"); class SemanticProcessor { static getInstance() { SemanticProcessor.instance = SemanticProcessor.instance || new SemanticProcessor(); return SemanticProcessor.instance; } static tableToMultiline(table) { if (!SemanticPred.tableIsMultiline(table)) { return semantic_heuristic_factory_js_1.SemanticHeuristics.run('rewrite_subcases', table, SemanticProcessor.classifyTable); } table.type = semantic_meaning_js_1.SemanticType.MULTILINE; for (let i = 0, row; (row = table.childNodes[i]); i++) { SemanticProcessor.rowToLine_(row, semantic_meaning_js_1.SemanticRole.MULTILINE); } if (table.childNodes.length === 1 && !SemanticPred.lineIsLabelled(table.childNodes[0]) && SemanticPred.isFencedElement(table.childNodes[0].childNodes[0])) { SemanticProcessor.tableToMatrixOrVector_(SemanticProcessor.rewriteFencedLine_(table)); } SemanticProcessor.binomialForm_(table); SemanticProcessor.classifyMultiline(table); return table; } static number(node) { if (node.type === semantic_meaning_js_1.SemanticType.UNKNOWN || node.type === semantic_meaning_js_1.SemanticType.IDENTIFIER) { node.type = semantic_meaning_js_1.SemanticType.NUMBER; } SemanticProcessor.meaningFromContent(node, SemanticProcessor.numberRole_); SemanticProcessor.exprFont_(node); } static classifyMultiline(multiline) { let index = 0; const length = multiline.childNodes.length; let line; while (index < length && (!(line = multiline.childNodes[index]) || !line.childNodes.length)) { index++; } if (index >= length) { return; } const firstRole = line.childNodes[0].role; if (firstRole !== semantic_meaning_js_1.SemanticRole.UNKNOWN && multiline.childNodes.every(function (x) { const cell = x.childNodes[0]; return (!cell || (cell.role === firstRole && (SemanticPred.isType(cell, semantic_meaning_js_1.SemanticType.RELATION) || SemanticPred.isType(cell, semantic_meaning_js_1.SemanticType.RELSEQ)))); })) { multiline.role = firstRole; } } static classifyTable(table) { const columns = SemanticProcessor.computeColumns_(table); SemanticProcessor.classifyByColumns_(table, columns, semantic_meaning_js_1.SemanticRole.EQUALITY) || SemanticProcessor.classifyByColumns_(table, columns, semantic_meaning_js_1.SemanticRole.INEQUALITY, [semantic_meaning_js_1.SemanticRole.EQUALITY]) || SemanticProcessor.classifyByColumns_(table, columns, semantic_meaning_js_1.SemanticRole.ARROW) || SemanticProcessor.detectCaleyTable(table); return table; } static detectCaleyTable(table) { if (!table.mathmlTree) { return false; } const tree = table.mathmlTree; const cl = tree.getAttribute('columnlines'); const rl = tree.getAttribute('rowlines'); if (!cl || !rl) { return false; } if (SemanticProcessor.cayleySpacing(cl) && SemanticProcessor.cayleySpacing(rl)) { table.role = semantic_meaning_js_1.SemanticRole.CAYLEY; return true; } return false; } static cayleySpacing(lines) { const list = lines.split(' '); return ((list[0] === 'solid' || list[0] === 'dashed') && list.slice(1).every((x) => x === 'none')); } static proof(node, semantics, parse) { const attrs = SemanticProcessor.separateSemantics(semantics); return SemanticProcessor.getInstance().proof(node, attrs, parse); } static findSemantics(node, attr, opt_value) { const value = opt_value == null ? null : opt_value; const semantics = SemanticProcessor.getSemantics(node); if (!semantics) { return false; } if (!semantics[attr]) { return false; } return value == null ? true : semantics[attr] === value; } static getSemantics(node) { const semantics = node.getAttribute('semantics'); if (!semantics) { return null; } return SemanticProcessor.separateSemantics(semantics); } static removePrefix(name) { const [, ...rest] = name.split('_'); return rest.join('_'); } static separateSemantics(attr) { const result = {}; attr.split(';').forEach(function (x) { const [name, value] = x.split(':'); result[SemanticProcessor.removePrefix(name)] = value; }); return result; } static matchSpaces_(nodes, ops) { for (let i = 0, op; (op = ops[i]); i++) { const node = nodes[i]; const mt1 = node.mathmlTree; const mt2 = nodes[i + 1].mathmlTree; if (!mt1 || !mt2) { continue; } const sibling = mt1.nextSibling; if (!sibling || sibling === mt2) { continue; } const spacer = SemanticProcessor.getSpacer_(sibling); if (spacer) { op.mathml.push(spacer); op.mathmlTree = spacer; op.role = semantic_meaning_js_1.SemanticRole.SPACE; } } } static getSpacer_(node) { if (DomUtil.tagName(node) === semantic_util_js_1.MMLTAGS.MSPACE) { return node; } while (SemanticUtil.hasEmptyTag(node) && node.childNodes.length === 1) { node = node.childNodes[0]; if (DomUtil.tagName(node) === semantic_util_js_1.MMLTAGS.MSPACE) { return node; } } return null; } static fenceToPunct_(fence) { const newRole = SemanticProcessor.FENCE_TO_PUNCT_[fence.role]; if (!newRole) { return; } while (fence.embellished) { fence.embellished = semantic_meaning_js_1.SemanticType.PUNCTUATION; if (!(SemanticPred.isRole(fence, semantic_meaning_js_1.SemanticRole.SUBSUP) || SemanticPred.isRole(fence, semantic_meaning_js_1.SemanticRole.UNDEROVER))) { fence.role = newRole; } fence = fence.childNodes[0]; } fence.type = semantic_meaning_js_1.SemanticType.PUNCTUATION; fence.role = newRole; } static classifyFunction_(funcNode, restNodes) { if (funcNode.type === semantic_meaning_js_1.SemanticType.APPL || funcNode.type === semantic_meaning_js_1.SemanticType.BIGOP || funcNode.type === semantic_meaning_js_1.SemanticType.INTEGRAL) { return ''; } if (restNodes[0] && restNodes[0].textContent === semantic_attr_js_1.NamedSymbol.functionApplication) { SemanticProcessor.getInstance().funcAppls[funcNode.id] = restNodes.shift(); let role = semantic_meaning_js_1.SemanticRole.SIMPLEFUNC; semantic_heuristic_factory_js_1.SemanticHeuristics.run('simple2prefix', funcNode); if (funcNode.role === semantic_meaning_js_1.SemanticRole.PREFIXFUNC || funcNode.role === semantic_meaning_js_1.SemanticRole.LIMFUNC) { role = funcNode.role; } SemanticProcessor.propagateFunctionRole_(funcNode, role); return 'prefix'; } const kind = SemanticProcessor.CLASSIFY_FUNCTION_[funcNode.role]; return kind ? kind : SemanticPred.isSimpleFunctionHead(funcNode) ? 'simple' : ''; } static propagateFunctionRole_(funcNode, tag) { if (funcNode) { if (funcNode.type === semantic_meaning_js_1.SemanticType.INFIXOP) { return; } if (!(SemanticPred.isRole(funcNode, semantic_meaning_js_1.SemanticRole.SUBSUP) || SemanticPred.isRole(funcNode, semantic_meaning_js_1.SemanticRole.UNDEROVER))) { funcNode.role = tag; } SemanticProcessor.propagateFunctionRole_(funcNode.childNodes[0], tag); } } static getFunctionOp_(tree, pred) { if (pred(tree)) { return tree; } for (let i = 0, child; (child = tree.childNodes[i]); i++) { const op = SemanticProcessor.getFunctionOp_(child, pred); if (op) { return op; } } return null; } static tableToMatrixOrVector_(node) { const matrix = node.childNodes[0]; SemanticPred.isType(matrix, semantic_meaning_js_1.SemanticType.MULTILINE) ? SemanticProcessor.tableToVector_(node) : SemanticProcessor.tableToMatrix_(node); node.contentNodes.forEach(matrix.appendContentNode.bind(matrix)); for (let i = 0, row; (row = matrix.childNodes[i]); i++) { SemanticProcessor.assignRoleToRow_(row, SemanticProcessor.getComponentRoles_(matrix)); } matrix.parent = null; return matrix; } static tableToVector_(node) { const vector = node.childNodes[0]; vector.type = semantic_meaning_js_1.SemanticType.VECTOR; if (vector.childNodes.length === 1) { SemanticProcessor.tableToSquare_(node); return; } SemanticProcessor.binomialForm_(vector); } static binomialForm_(node) { if (!SemanticPred.isRole(node, semantic_meaning_js_1.SemanticRole.UNKNOWN)) { return; } if (SemanticPred.isBinomial(node)) { node.role = semantic_meaning_js_1.SemanticRole.BINOMIAL; node.childNodes[0].role = semantic_meaning_js_1.SemanticRole.BINOMIAL; node.childNodes[1].role = semantic_meaning_js_1.SemanticRole.BINOMIAL; } } static tableToMatrix_(node) { const matrix = node.childNodes[0]; matrix.type = semantic_meaning_js_1.SemanticType.MATRIX; if (matrix.childNodes && matrix.childNodes.length > 0 && matrix.childNodes[0].childNodes && matrix.childNodes.length === matrix.childNodes[0].childNodes.length) { SemanticProcessor.tableToSquare_(node); return; } if (matrix.childNodes && matrix.childNodes.length === 1) { matrix.role = semantic_meaning_js_1.SemanticRole.ROWVECTOR; } } static tableToSquare_(node) { const matrix = node.childNodes[0]; if (!SemanticPred.isRole(matrix, semantic_meaning_js_1.SemanticRole.UNKNOWN)) { return; } if (SemanticPred.isNeutralFence(node)) { matrix.role = semantic_meaning_js_1.SemanticRole.DETERMINANT; return; } matrix.role = semantic_meaning_js_1.SemanticRole.SQUAREMATRIX; } static getComponentRoles_(node) { const role = node.role; if (role && role !== semantic_meaning_js_1.SemanticRole.UNKNOWN) { return role; } return node.type.toLowerCase() || semantic_meaning_js_1.SemanticRole.UNKNOWN; } static tableToCases_(table, openFence) { for (let i = 0, row; (row = table.childNodes[i]); i++) { SemanticProcessor.assignRoleToRow_(row, semantic_meaning_js_1.SemanticRole.CASES); } table.type = semantic_meaning_js_1.SemanticType.CASES; table.appendContentNode(openFence); if (SemanticPred.tableIsMultiline(table)) { SemanticProcessor.binomialForm_(table); } return table; } static rewriteFencedLine_(table) { const line = table.childNodes[0]; const fenced = table.childNodes[0].childNodes[0]; const element = table.childNodes[0].childNodes[0].childNodes[0]; fenced.parent = table.parent; table.parent = fenced; element.parent = line; fenced.childNodes = [table]; line.childNodes = [element]; return fenced; } static rowToLine_(row, opt_role) { const role = opt_role || semantic_meaning_js_1.SemanticRole.UNKNOWN; if (SemanticPred.isType(row, semantic_meaning_js_1.SemanticType.ROW)) { row.type = semantic_meaning_js_1.SemanticType.LINE; row.role = role; if (row.childNodes.length === 1 && SemanticPred.isType(row.childNodes[0], semantic_meaning_js_1.SemanticType.CELL)) { row.childNodes = row.childNodes[0].childNodes; row.childNodes.forEach(function (x) { x.parent = row; }); } } } static assignRoleToRow_(row, role) { if (SemanticPred.isType(row, semantic_meaning_js_1.SemanticType.LINE)) { row.role = role; return; } if (SemanticPred.isType(row, semantic_meaning_js_1.SemanticType.ROW)) { row.role = role; row.childNodes.forEach(function (cell) { if (SemanticPred.isType(cell, semantic_meaning_js_1.SemanticType.CELL)) { cell.role = role; } }); } } static nextSeparatorFunction_(separators) { let sepList; if (separators) { if (separators.match(/^\s+$/)) { return null; } else { sepList = separators .replace(/\s/g, '') .split('') .filter(function (x) { return x; }); } } else { sepList = [',']; } return function () { if (sepList.length > 1) { return sepList.shift(); } return sepList[0]; }; } static meaningFromContent(node, func) { const content = [...node.textContent].filter((x) => x.match(/[^\s]/)); const meaning = content.map((x) => semantic_attr_js_1.SemanticMap.Meaning.get(x)); func(node, content, meaning); } static numberRole_(node, content, meaning) { if (node.role !== semantic_meaning_js_1.SemanticRole.UNKNOWN) { return; } if (meaning.every(function (x) { return ((x.type === semantic_meaning_js_1.SemanticType.NUMBER && x.role === semantic_meaning_js_1.SemanticRole.INTEGER) || (x.type === semantic_meaning_js_1.SemanticType.PUNCTUATION && x.role === semantic_meaning_js_1.SemanticRole.COMMA)); })) { node.role = semantic_meaning_js_1.SemanticRole.INTEGER; if (content[0] === '0') { node.addAnnotation('general', 'basenumber'); } return; } if (meaning.every(function (x) { return ((x.type === semantic_meaning_js_1.SemanticType.NUMBER && x.role === semantic_meaning_js_1.SemanticRole.INTEGER) || x.type === semantic_meaning_js_1.SemanticType.PUNCTUATION); })) { node.role = semantic_meaning_js_1.SemanticRole.FLOAT; return; } node.role = semantic_meaning_js_1.SemanticRole.OTHERNUMBER; } static exprFont_(node) { if (node.font !== semantic_meaning_js_1.SemanticFont.UNKNOWN) { return; } SemanticProcessor.compSemantics(node, 'font', semantic_meaning_js_1.SemanticFont); } static compSemantics(node, field, sem) { const content = [...node.textContent]; const meaning = content.map((x) => semantic_attr_js_1.SemanticMap.Meaning.get(x)); const single = meaning.reduce(function (prev, curr) { if (!prev || !curr[field] || curr[field] === sem.UNKNOWN || curr[field] === prev) { return prev; } if (prev === sem.UNKNOWN) { return curr[field]; } return null; }, sem.UNKNOWN); if (single) { node[field] = single; } } static purgeFences_(partition) { const rel = partition.rel; const comp = partition.comp; const newRel = []; const newComp = []; while (rel.length > 0) { const currentRel = rel.shift(); let currentComp = comp.shift(); if (SemanticPred.isElligibleEmbellishedFence(currentRel)) { newRel.push(currentRel); newComp.push(currentComp); continue; } SemanticProcessor.fenceToPunct_(currentRel); currentComp.push(currentRel); currentComp = currentComp.concat(comp.shift()); comp.unshift(currentComp); } newComp.push(comp.shift()); return { rel: newRel, comp: newComp }; } static rewriteFencedNode_(fenced) { const ofence = fenced.contentNodes[0]; const cfence = fenced.contentNodes[1]; let rewritten = SemanticProcessor.rewriteFence_(fenced, ofence); fenced.contentNodes[0] = rewritten.fence; rewritten = SemanticProcessor.rewriteFence_(rewritten.node, cfence); fenced.contentNodes[1] = rewritten.fence; fenced.contentNodes[0].parent = fenced; fenced.contentNodes[1].parent = fenced; rewritten.node.parent = null; return rewritten.node; } static rewriteFence_(node, fence) { if (!fence.embellished) { return { node: node, fence: fence }; } const newFence = fence.childNodes[0]; const rewritten = SemanticProcessor.rewriteFence_(node, newFence); if (SemanticPred.isType(fence, semantic_meaning_js_1.SemanticType.SUPERSCRIPT) || SemanticPred.isType(fence, semantic_meaning_js_1.SemanticType.SUBSCRIPT) || SemanticPred.isType(fence, semantic_meaning_js_1.SemanticType.TENSOR)) { if (!SemanticPred.isRole(fence, semantic_meaning_js_1.SemanticRole.SUBSUP)) { fence.role = node.role; } if (newFence !== rewritten.node) { fence.replaceChild(newFence, rewritten.node); newFence.parent = node; } SemanticProcessor.propagateFencePointer_(fence, newFence); return { node: fence, fence: rewritten.fence }; } fence.replaceChild(newFence, rewritten.fence); if (fence.mathmlTree && fence.mathml.indexOf(fence.mathmlTree) === -1) { fence.mathml.push(fence.mathmlTree); } return { node: rewritten.node, fence: fence }; } static propagateFencePointer_(oldNode, newNode) { oldNode.fencePointer = newNode.fencePointer || newNode.id.toString(); oldNode.embellished = null; } static classifyByColumns_(table, columns, relation, alternatives = []) { const relations = [relation].concat(alternatives); const test1 = (x) => SemanticProcessor.isPureRelation_(x, relations); const test2 = (x) => SemanticProcessor.isEndRelation_(x, relations) || SemanticProcessor.isPureRelation_(x, relations); const test3 = (x) => SemanticProcessor.isEndRelation_(x, relations, true) || SemanticProcessor.isPureRelation_(x, relations); if ((columns.length === 3 && SemanticProcessor.testColumns_(columns, 1, test1)) || (columns.length === 2 && (SemanticProcessor.testColumns_(columns, 1, test2) || SemanticProcessor.testColumns_(columns, 0, test3)))) { table.role = relation; return true; } return false; } static isEndRelation_(node, relations, opt_right) { const position = opt_right ? node.childNodes.length - 1 : 0; return (SemanticPred.isType(node, semantic_meaning_js_1.SemanticType.RELSEQ) && relations.some((relation) => SemanticPred.isRole(node, relation)) && SemanticPred.isType(node.childNodes[position], semantic_meaning_js_1.SemanticType.EMPTY)); } static isPureRelation_(node, relations) { return (SemanticPred.isType(node, semantic_meaning_js_1.SemanticType.RELATION) && relations.some((relation) => SemanticPred.isRole(node, relation))); } static computeColumns_(table) { const columns = []; for (let i = 0, row; (row = table.childNodes[i]); i++) { for (let j = 0, cell; (cell = row.childNodes[j]); j++) { const column = columns[j]; column ? columns[j].push(cell) : (columns[j] = [cell]); } } return columns; } static testColumns_(columns, index, pred) { const column = columns[index]; return column ? column.some(function (cell) { return (cell.childNodes.length && pred(cell.childNodes[0])); }) && column.every(function (cell) { return (!cell.childNodes.length || pred(cell.childNodes[0])); }) : false; } setNodeFactory(factory) { SemanticProcessor.getInstance().factory_ = factory; semantic_heuristic_factory_js_1.SemanticHeuristics.updateFactory(SemanticProcessor.getInstance().factory_); } getNodeFactory() { return SemanticProcessor.getInstance().factory_; } identifierNode(leaf, font, unit) { if (unit === 'MathML-Unit') { leaf.type = semantic_meaning_js_1.SemanticType.IDENTIFIER; leaf.role = semantic_meaning_js_1.SemanticRole.UNIT; } else if (!font && leaf.textContent.length === 1 && (leaf.role === semantic_meaning_js_1.SemanticRole.INTEGER || leaf.role === semantic_meaning_js_1.SemanticRole.LATINLETTER || leaf.role === semantic_meaning_js_1.SemanticRole.GREEKLETTER) && leaf.font === semantic_meaning_js_1.SemanticFont.NORMAL) { leaf.font = semantic_meaning_js_1.SemanticFont.ITALIC; return semantic_heuristic_factory_js_1.SemanticHeuristics.run('simpleNamedFunction', leaf); } if (leaf.type === semantic_meaning_js_1.SemanticType.UNKNOWN) { leaf.type = semantic_meaning_js_1.SemanticType.IDENTIFIER; } SemanticProcessor.exprFont_(leaf); return semantic_heuristic_factory_js_1.SemanticHeuristics.run('simpleNamedFunction', leaf); } implicitNode(nodes) { nodes = SemanticProcessor.getInstance().getMixedNumbers_(nodes); nodes = SemanticProcessor.getInstance().combineUnits_(nodes); if (nodes.length === 1) { return nodes[0]; } const node = SemanticProcessor.getInstance().implicitNode_(nodes); return semantic_heuristic_factory_js_1.SemanticHeuristics.run('combine_juxtaposition', node); } text(leaf, type) { SemanticProcessor.exprFont_(leaf); leaf.type = semantic_meaning_js_1.SemanticType.TEXT; if (type === semantic_util_js_1.MMLTAGS.ANNOTATIONXML) { leaf.role = semantic_meaning_js_1.SemanticRole.ANNOTATION; return leaf; } if (type === semantic_util_js_1.MMLTAGS.MS) { leaf.role = semantic_meaning_js_1.SemanticRole.STRING; return leaf; } if (type === semantic_util_js_1.MMLTAGS.MSPACE || leaf.textContent.match(/^\s*$/)) { leaf.role = semantic_meaning_js_1.SemanticRole.SPACE; return leaf; } if (/\s/.exec(leaf.textContent)) { leaf.role = semantic_meaning_js_1.SemanticRole.TEXT; return leaf; } leaf.role = semantic_meaning_js_1.SemanticRole.UNKNOWN; return leaf; } row(nodes) { nodes = nodes.filter(function (x) { return !SemanticPred.isType(x, semantic_meaning_js_1.SemanticType.EMPTY); }); if (nodes.length === 0) { return SemanticProcessor.getInstance().factory_.makeEmptyNode(); } nodes = SemanticProcessor.getInstance().getFencesInRow_(nodes); nodes = SemanticProcessor.getInstance().tablesInRow(nodes); nodes = SemanticProcessor.getInstance().getPunctuationInRow_(nodes); nodes = SemanticProcessor.getInstance().getTextInRow_(nodes); nodes = SemanticProcessor.getInstance().getFunctionsInRow_(nodes); return SemanticProcessor.getInstance().relationsInRow_(nodes); } limitNode(mmlTag, children) { if (!children.length) { return SemanticProcessor.getInstance().factory_.makeEmptyNode(); } let center = children[0]; let type = semantic_meaning_js_1.SemanticType.UNKNOWN; if (!children[1]) { return center; } let result; semantic_heuristic_factory_js_1.SemanticHeuristics.run('op_with_limits', children); if (SemanticPred.isLimitBase(center)) { result = SemanticProcessor.MML_TO_LIMIT_[mmlTag]; const length = result.length; type = result.type; children = children.slice(0, result.length + 1); if ((length === 1 && SemanticPred.isAccent(children[1])) || (length === 2 && SemanticPred.isAccent(children[1]) && SemanticPred.isAccent(children[2]))) { result = SemanticProcessor.MML_TO_BOUNDS_[mmlTag]; return SemanticProcessor.getInstance().accentNode_(center, children, result.type, result.length, result.accent); } if (length === 2) { if (SemanticPred.isAccent(children[1])) { center = SemanticProcessor.getInstance().accentNode_(center, [center, children[1]], { MSUBSUP: semantic_meaning_js_1.SemanticType.SUBSCRIPT, MUNDEROVER: semantic_meaning_js_1.SemanticType.UNDERSCORE }[mmlTag], 1, true); return !children[2] ? center : SemanticProcessor.getInstance().makeLimitNode_(center, [center, children[2]], null, semantic_meaning_js_1.SemanticType.LIMUPPER); } if (children[2] && SemanticPred.isAccent(children[2])) { center = SemanticProcessor.getInstance().accentNode_(center, [center, children[2]], { MSUBSUP: semantic_meaning_js_1.SemanticType.SUPERSCRIPT, MUNDEROVER: semantic_meaning_js_1.SemanticType.OVERSCORE }[mmlTag], 1, true); return SemanticProcessor.getInstance().makeLimitNode_(center, [center, children[1]], null, semantic_meaning_js_1.SemanticType.LIMLOWER); } if (!children[length]) { type = semantic_meaning_js_1.SemanticType.LIMLOWER; } } return SemanticProcessor.getInstance().makeLimitNode_(center, children, null, type); } result = SemanticProcessor.MML_TO_BOUNDS_[mmlTag]; return SemanticProcessor.getInstance().accentNode_(center, children, result.type, result.length, result.accent); } tablesInRow(nodes) { let partition = SemanticUtil.partitionNodes(nodes, SemanticPred.tableIsMatrixOrVector); let result = []; for (let i = 0, matrix; (matrix = partition.rel[i]); i++) { result = result.concat(partition.comp.shift()); result.push(SemanticProcessor.tableToMatrixOrVector_(matrix)); } result = result.concat(partition.comp.shift()); partition = SemanticUtil.partitionNodes(result, SemanticPred.isTableOrMultiline); result = []; for (let i = 0, table; (table = partition.rel[i]); i++) { const prevNodes = partition.comp.shift(); if (SemanticPred.tableIsCases(table, prevNodes)) { SemanticProcessor.tableToCases_(table, prevNodes.pop()); } result = result.concat(prevNodes); result.push(table); } return result.concat(partition.comp.shift()); } mfenced(open, close, sepValue, children) { if (sepValue && children.length > 0) { const separators = SemanticProcessor.nextSeparatorFunction_(sepValue); const newChildren = [children.shift()]; children.forEach((child) => { newChildren.push(SemanticProcessor.getInstance().factory_.makeContentNode(separators())); newChildren.push(child); }); children = newChildren; } if (open && close) { return SemanticProcessor.getInstance().horizontalFencedNode_(SemanticProcessor.getInstance().factory_.makeContentNode(open), SemanticProcessor.getInstance().factory_.makeContentNode(close), children); } if (open) { children.unshift(SemanticProcessor.getInstance().factory_.makeContentNode(open)); } if (close) { children.push(SemanticProcessor.getInstance().factory_.makeContentNode(close)); } return SemanticProcessor.getInstance().row(children); } fractionLikeNode(denom, enume, linethickness, bevelled) { let node; if (!bevelled && SemanticUtil.isZeroLength(linethickness)) { const child0 = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.LINE, [denom], []); const child1 = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.LINE, [enume], []); node = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.MULTILINE, [child0, child1], []); SemanticProcessor.binomialForm_(node); SemanticProcessor.classifyMultiline(node); return node; } else { node = SemanticProcessor.getInstance().fractionNode_(denom, enume); if (bevelled) { node.addAnnotation('general', 'bevelled'); } return node; } } tensor(base, lsub, lsup, rsub, rsup) { const newNode = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.TENSOR, [ base, SemanticProcessor.getInstance().scriptNode_(lsub, semantic_meaning_js_1.SemanticRole.LEFTSUB), SemanticProcessor.getInstance().scriptNode_(lsup, semantic_meaning_js_1.SemanticRole.LEFTSUPER), SemanticProcessor.getInstance().scriptNode_(rsub, semantic_meaning_js_1.SemanticRole.RIGHTSUB), SemanticProcessor.getInstance().scriptNode_(rsup, semantic_meaning_js_1.SemanticRole.RIGHTSUPER) ], []); newNode.role = base.role; newNode.embellished = SemanticPred.isEmbellished(base); return newNode; } pseudoTensor(base, sub, sup) { const isEmpty = (x) => !SemanticPred.isType(x, semantic_meaning_js_1.SemanticType.EMPTY); const nonEmptySub = sub.filter(isEmpty).length; const nonEmptySup = sup.filter(isEmpty).length; if (!nonEmptySub && !nonEmptySup) { return base; } const mmlTag = nonEmptySub ? nonEmptySup ? semantic_util_js_1.MMLTAGS.MSUBSUP : semantic_util_js_1.MMLTAGS.MSUB : semantic_util_js_1.MMLTAGS.MSUP; const mmlchild = [base]; if (nonEmptySub) { mmlchild.push(SemanticProcessor.getInstance().scriptNode_(sub, semantic_meaning_js_1.SemanticRole.RIGHTSUB, true)); } if (nonEmptySup) { mmlchild.push(SemanticProcessor.getInstance().scriptNode_(sup, semantic_meaning_js_1.SemanticRole.RIGHTSUPER, true)); } return SemanticProcessor.getInstance().limitNode(mmlTag, mmlchild); } font(font) { const mathjaxFont = SemanticProcessor.MATHJAX_FONTS[font]; return mathjaxFont ? mathjaxFont : font; } proof(node, semantics, parse) { if (!semantics['inference'] && !semantics['axiom']) { console.log('Noise'); } if (semantics['axiom']) { const cleaned = SemanticProcessor.getInstance().cleanInference(node.childNodes); const axiom = cleaned.length ? SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.INFERENCE, parse(cleaned), []) : SemanticProcessor.getInstance().factory_.makeEmptyNode(); axiom.role = semantic_meaning_js_1.SemanticRole.AXIOM; axiom.mathmlTree = node; return axiom; } const inference = SemanticProcessor.getInstance().inference(node, semantics, parse); if (semantics['proof']) { inference.role = semantic_meaning_js_1.SemanticRole.PROOF; inference.childNodes[0].role = semantic_meaning_js_1.SemanticRole.FINAL; } return inference; } inference(node, semantics, parse) { if (semantics['inferenceRule']) { const formulas = SemanticProcessor.getInstance().getFormulas(node, [], parse); const inference = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.INFERENCE, [formulas.conclusion, formulas.premises], []); return inference; } const label = semantics['labelledRule']; const children = DomUtil.toArray(node.childNodes); const content = []; if (label === 'left' || label === 'both') { content.push(SemanticProcessor.getInstance().getLabel(node, children, parse, semantic_meaning_js_1.SemanticRole.LEFT)); } if (label === 'right' || label === 'both') { content.push(SemanticProcessor.getInstance().getLabel(node, children, parse, semantic_meaning_js_1.SemanticRole.RIGHT)); } const formulas = SemanticProcessor.getInstance().getFormulas(node, children, parse); const inference = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.INFERENCE, [formulas.conclusion, formulas.premises], content); inference.mathmlTree = node; return inference; } getLabel(_node, children, parse, side) { const label = SemanticProcessor.getInstance().findNestedRow(children, 'prooflabel', side); const sem = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.RULELABEL, parse(DomUtil.toArray(label.childNodes)), []); sem.role = side; sem.mathmlTree = label; return sem; } getFormulas(node, children, parse) { const inf = children.length ? SemanticProcessor.getInstance().findNestedRow(children, 'inferenceRule') : node; const up = SemanticProcessor.getSemantics(inf)['inferenceRule'] === 'up'; const premRow = up ? inf.childNodes[1] : inf.childNodes[0]; const concRow = up ? inf.childNodes[0] : inf.childNodes[1]; const premTable = premRow.childNodes[0].childNodes[0]; const topRow = DomUtil.toArray(premTable.childNodes[0].childNodes); const premNodes = []; let i = 1; for (const cell of topRow) { if (i % 2) { premNodes.push(cell.childNodes[0]); } i++; } const premises = parse(premNodes); const conclusion = parse(DomUtil.toArray(concRow.childNodes[0].childNodes))[0]; const prem = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.PREMISES, premises, []); prem.mathmlTree = premTable; const conc = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.CONCLUSION, [conclusion], []); conc.mathmlTree = concRow.childNodes[0].childNodes[0]; return { conclusion: conc, premises: prem }; } findNestedRow(nodes, semantic, opt_value) { return SemanticProcessor.getInstance().findNestedRow_(nodes, semantic, 0, opt_value); } cleanInference(nodes) { return DomUtil.toArray(nodes).filter(function (x) { return DomUtil.tagName(x) !== 'MSPACE'; }); } operatorNode(node) { if (node.type === semantic_meaning_js_1.SemanticType.UNKNOWN) { node.type = semantic_meaning_js_1.SemanticType.OPERATOR; } return semantic_heuristic_factory_js_1.SemanticHeuristics.run('multioperator', node); } constructor() { this.funcAppls = {}; this.splitRoles = new Map([ [semantic_meaning_js_1.SemanticRole.SUBTRACTION, semantic_meaning_js_1.SemanticRole.NEGATIVE], [semantic_meaning_js_1.SemanticRole.ADDITION, semantic_meaning_js_1.SemanticRole.POSITIVE] ]); this.splitOps = ['−', '-', '‐', '‑', '+']; this.factory_ = new semantic_node_factory_js_1.SemanticNodeFactory(); semantic_heuristic_factory_js_1.SemanticHeuristics.updateFactory(this.factory_); } implicitNode_(nodes) { const operators = SemanticProcessor.getInstance().factory_.makeMultipleContentNodes(nodes.length - 1, semantic_attr_js_1.NamedSymbol.invisibleTimes); SemanticProcessor.matchSpaces_(nodes, operators); const newNode = SemanticProcessor.getInstance().infixNode_(nodes, operators[0]); newNode.role = semantic_meaning_js_1.SemanticRole.IMPLICIT; operators.forEach(function (op) { op.parent = newNode; }); newNode.contentNodes = operators; return newNode; } infixNode_(children, opNode) { const node = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.INFIXOP, children, [opNode], SemanticUtil.getEmbellishedInner(opNode).textContent); node.role = opNode.role; return semantic_heuristic_factory_js_1.SemanticHeuristics.run('propagateSimpleFunction', node); } explicitMixed_(nodes) { const partition = SemanticUtil.partitionNodes(nodes, function (x) { return x.textContent === semantic_attr_js_1.NamedSymbol.invisiblePlus; }); if (!partition.rel.length) { return nodes; } let result = []; for (let i = 0, rel; (rel = partition.rel[i]); i++) { const prev = partition.comp[i]; const next = partition.comp[i + 1]; const last = prev.length - 1; if (prev[last] && next[0] && SemanticPred.isType(prev[last], semantic_meaning_js_1.SemanticType.NUMBER) && !SemanticPred.isRole(prev[last], semantic_meaning_js_1.SemanticRole.MIXED) && SemanticPred.isType(next[0], semantic_meaning_js_1.SemanticType.FRACTION)) { const newNode = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.NUMBER, [prev[last], next[0]], []); newNode.role = semantic_meaning_js_1.SemanticRole.MIXED; result = result.concat(prev.slice(0, last)); result.push(newNode); next.shift(); } else { result = result.concat(prev); result.push(rel); } } return result.concat(partition.comp[partition.comp.length - 1]); } concatNode_(inner, nodeList, type) { if (nodeList.length === 0) { return inner; } const content = nodeList .map(function (x) { return SemanticUtil.getEmbellishedInner(x).textContent; }) .join(' '); const newNode = SemanticProcessor.getInstance().factory_.makeBranchNode(type, [inner], nodeList, content); if (nodeList.length > 1) { newNode.role = semantic_meaning_js_1.SemanticRole.MULTIOP; } return newNode; } prefixNode_(node, prefixes) { const newPrefixes = this.splitSingles(prefixes); let newNode = node; while (newPrefixes.length > 0) { const op = newPrefixes.pop(); newNode = SemanticProcessor.getInstance().concatNode_(newNode, op, semantic_meaning_js_1.SemanticType.PREFIXOP); if (op.length === 1 && this.splitOps.indexOf(op[0].textContent) !== -1) { newNode.role = this.splitRoles.get(op[0].role); } } return newNode; } splitSingles(prefixes) { let lastOp = 0; const result = []; let i = 0; while (i < prefixes.length) { const op = prefixes[i]; if (this.splitRoles.has(op.role) && (!prefixes[i - 1] || prefixes[i - 1].role !== op.role) && (!prefixes[i + 1] || prefixes[i + 1].role !== op.role) && this.splitOps.indexOf(op.textContent) !== -1) { result.push(prefixes.slice(lastOp, i)); result.push(prefixes.slice(i, i + 1)); lastOp = i + 1; } i++; } if (lastOp < i) { result.push(prefixes.slice(lastOp, i)); } return result; } postfixNode_(node, postfixes) { if (!postfixes.length) { return node; } return SemanticProcessor.getInstance().concatNode_(node, postfixes, semantic_meaning_js_1.SemanticType.POSTFIXOP); } combineUnits_(nodes) { const partition = SemanticUtil.partitionNodes(nodes, function (x) { return !SemanticPred.isRole(x, semantic_meaning_js_1.SemanticRole.UNIT); }); if (nodes.length === partition.rel.length) { return partition.rel; } const result = []; let rel; let last; do { const comp = partition.comp.shift(); rel = partition.rel.shift(); let unitNode = null; last = result.pop(); if (last) { if (!comp.length || !SemanticPred.isUnitCounter(last)) { result.push(last); } else { comp.unshift(last); } } if (comp.length === 1) { unitNode = comp.pop(); } if (comp.length > 1) { unitNode = SemanticProcessor.getInstance().implicitNode_(comp); unitNode.role = semantic_meaning_js_1.SemanticRole.UNIT; } if (unitNode) { result.push(unitNode); } if (rel) { result.push(rel); } } while (rel); return result; } getMixedNumbers_(nodes) { const partition = SemanticUtil.partitionNodes(nodes, function (x) { return (SemanticPred.isType(x, semantic_meaning_js_1.SemanticType.FRACTION) && SemanticPred.isRole(x, semantic_meaning_js_1.SemanticRole.VULGAR)); }); if (!partition.rel.length) { return nodes; } let result = []; for (let i = 0, rel; (rel = partition.rel[i]); i++) { const comp = partition.comp[i]; const last = comp.length - 1; if (comp[last] && SemanticPred.isType(comp[last], semantic_meaning_js_1.SemanticType.NUMBER) && (SemanticPred.isRole(comp[last], semantic_meaning_js_1.SemanticRole.INTEGER) || SemanticPred.isRole(comp[last], semantic_meaning_js_1.SemanticRole.FLOAT))) { const newNode = SemanticProcessor.getInstance().factory_.makeBranchNode(semantic_meaning_js_1.SemanticType.NUMBER, [comp[last], rel], []); newNode.role = semantic_meaning_js_1.SemanticRole.MIXED; result = result.concat(comp.slice(0, last)); result.push(newNode); } else { result = result.concat(comp); result.push(rel); } } return result.concat(partition.comp[partition.comp.length - 1]); } getTextInRow_(nodes) { if (nodes.length === 0) { return nodes; } if (nodes.length === 1) { if (nodes[0].type === semantic_meaning_js_1.SemanticType.TEXT && nodes[0].role === semantic_meaning_js_1.SemanticRole.UNKNOWN) { nodes[0].role = semantic_meaning_js_1.SemanticRole.ANNOTATION; } return nodes; } const { rel: rel, comp: comp } = SemanticUtil.partitionNodes(nodes, (x) => SemanticPred.isType(x, semantic_meaning_js_1.SemanticType.TEXT)); if (rel.length === 0) { return nodes; } const result = []; let prevComp = comp.shift(); while (rel.length > 0) { let currentRel = rel.shift(); let nextComp = comp.shift(); const text = []; while (!nextComp.length && rel.length && currentRel.role !== semantic_meaning_js_1.SemanticRole.SPACE && rel[0].role !== semantic_meaning_js_1.SemanticRole.SPACE) { text.push(currentRel); currentRel = rel.shift(); nextComp = comp.shift(); } if (text.length) { if (prevComp.length) { result.push(SemanticProcessor.getInstance().row(prevComp)); } text.push(currentRel); const dummy = SemanticProcessor.getInstance().dummyNode_(text); result.push(dummy); prevComp = nextComp; continue; } if (currentRel.role !== semantic_meaning_js_1.SemanticRole.UNKNOWN) { if (prevComp.length) { result.push(SemanticProcessor.getInstance().row(prevComp)); } result.push(currentRel); prevComp = nextComp; continue; } const meaning = semantic_attr_js_1.SemanticMap.Meaning.get(currentRel.textContent); if (meaning.type === semantic_meaning_js_1.SemanticType.PUNCTUATION) { currentRel.role = meaning.role; currentRel.font = meaning.font; if (prevComp.length) { result.push(SemanticProcessor.getInstance().row(prevComp)); } result.push(currentRel); prevComp = nextComp; continue; } if (meaning.type !== semantic_meaning_js_1.SemanticType.UNKNOWN) { currentRel.type = meaning.type; currentRel.role = meaning.role; currentRel.font = meaning.font; currentRel.addAnnotation('general', 'text'); prevComp.push(currentRel); prevComp = prevComp.concat(nextComp); continue; } SemanticProcessor.meaningFromContent(currentRel, (n, c, m) => { if (n.role !== semantic_meaning_js_1.SemanticRole.UNKNOWN) { return; } SemanticProcessor.numberRole_(n, c, m); if (n.role !== semantic_meaning_js_1.SemanticRole.OTHERNUMBER) { n.type = semantic_meaning_js_1.SemanticType.NUMBER; return; } if (m.some((x) => x.type !== semantic_meaning_js_1.SemanticType.NUMBER && x.type !== semantic_meaning_js_1.Sema