semantic_heuristics.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const debugger_js_1 = require("../common/debugger.js");
  4. const engine_js_1 = require("../common/engine.js");
  5. const semantic_attr_js_1 = require("./semantic_attr.js");
  6. const semantic_heuristic_factory_js_1 = require("./semantic_heuristic_factory.js");
  7. const semantic_heuristic_js_1 = require("./semantic_heuristic.js");
  8. const semantic_meaning_js_1 = require("./semantic_meaning.js");
  9. const SemanticPred = require("./semantic_pred.js");
  10. const semantic_processor_js_1 = require("./semantic_processor.js");
  11. const SemanticUtil = require("./semantic_util.js");
  12. const semantic_skeleton_js_1 = require("./semantic_skeleton.js");
  13. const semantic_util_js_1 = require("../semantic_tree/semantic_util.js");
  14. const DomUtil = require("../common/dom_util.js");
  15. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('combine_juxtaposition', combineJuxtaposition));
  16. function combineJuxtaposition(root) {
  17. for (let i = root.childNodes.length - 1, child; (child = root.childNodes[i]); i--) {
  18. if (!SemanticPred.isImplicitOp(child) || child.nobreaking) {
  19. continue;
  20. }
  21. root.childNodes.splice(i, 1, ...child.childNodes);
  22. root.contentNodes.splice(i, 0, ...child.contentNodes);
  23. child.childNodes.concat(child.contentNodes).forEach(function (x) {
  24. x.parent = root;
  25. });
  26. root.addMathmlNodes(child.mathml);
  27. }
  28. return root;
  29. }
  30. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('propagateSimpleFunction', (node) => {
  31. if ((node.type === semantic_meaning_js_1.SemanticType.INFIXOP ||
  32. node.type === semantic_meaning_js_1.SemanticType.FRACTION) &&
  33. node.childNodes.every(SemanticPred.isSimpleFunction)) {
  34. node.role = semantic_meaning_js_1.SemanticRole.COMPFUNC;
  35. }
  36. return node;
  37. }, (_node) => engine_js_1.Engine.getInstance().domain === 'clearspeak'));
  38. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('simpleNamedFunction', (node) => {
  39. const specialFunctions = ['f', 'g', 'h', 'F', 'G', 'H'];
  40. if (node.role !== semantic_meaning_js_1.SemanticRole.UNIT &&
  41. specialFunctions.indexOf(node.textContent) !== -1) {
  42. node.role = semantic_meaning_js_1.SemanticRole.SIMPLEFUNC;
  43. }
  44. return node;
  45. }, (_node) => engine_js_1.Engine.getInstance().domain === 'clearspeak'));
  46. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('propagateComposedFunction', (node) => {
  47. if (node.type === semantic_meaning_js_1.SemanticType.FENCED &&
  48. node.childNodes[0].role === semantic_meaning_js_1.SemanticRole.COMPFUNC) {
  49. node.role = semantic_meaning_js_1.SemanticRole.COMPFUNC;
  50. }
  51. return node;
  52. }, (_node) => engine_js_1.Engine.getInstance().domain === 'clearspeak'));
  53. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('multioperator', (node) => {
  54. if (node.role !== semantic_meaning_js_1.SemanticRole.UNKNOWN || node.textContent.length <= 1) {
  55. return;
  56. }
  57. semantic_processor_js_1.SemanticProcessor.compSemantics(node, 'role', semantic_meaning_js_1.SemanticRole);
  58. semantic_processor_js_1.SemanticProcessor.compSemantics(node, 'type', semantic_meaning_js_1.SemanticType);
  59. }));
  60. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticMultiHeuristic('convert_juxtaposition', (nodes) => {
  61. let partition = SemanticUtil.partitionNodes(nodes, function (x) {
  62. return (x.textContent === semantic_attr_js_1.NamedSymbol.invisibleTimes &&
  63. x.type === semantic_meaning_js_1.SemanticType.OPERATOR);
  64. });
  65. partition = partition.rel.length
  66. ? juxtapositionPrePost(partition)
  67. : partition;
  68. nodes = partition.comp[0];
  69. for (let i = 1, c, r; (c = partition.comp[i]), (r = partition.rel[i - 1]); i++) {
  70. nodes.push(r);
  71. nodes = nodes.concat(c);
  72. }
  73. partition = SemanticUtil.partitionNodes(nodes, function (x) {
  74. return (x.textContent === semantic_attr_js_1.NamedSymbol.invisibleTimes &&
  75. (x.type === semantic_meaning_js_1.SemanticType.OPERATOR || x.type === semantic_meaning_js_1.SemanticType.INFIXOP));
  76. });
  77. if (!partition.rel.length) {
  78. return nodes;
  79. }
  80. return recurseJuxtaposition(partition.comp.shift(), partition.rel, partition.comp);
  81. }));
  82. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('simple2prefix', (node) => {
  83. if (node.textContent.length > 1 &&
  84. !node.textContent[0].match(/[A-Z]/)) {
  85. node.role = semantic_meaning_js_1.SemanticRole.PREFIXFUNC;
  86. }
  87. return node;
  88. }, (node) => engine_js_1.Engine.getInstance().modality === 'braille' &&
  89. node.type === semantic_meaning_js_1.SemanticType.IDENTIFIER));
  90. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('detect_cycle', (node) => {
  91. node.type = semantic_meaning_js_1.SemanticType.MATRIX;
  92. node.role = semantic_meaning_js_1.SemanticRole.CYCLE;
  93. const row = node.childNodes[0];
  94. row.type = semantic_meaning_js_1.SemanticType.ROW;
  95. row.role = semantic_meaning_js_1.SemanticRole.CYCLE;
  96. row.textContent = '';
  97. row.contentNodes = [];
  98. return node;
  99. }, (node) => node.type === semantic_meaning_js_1.SemanticType.FENCED &&
  100. node.childNodes[0].type === semantic_meaning_js_1.SemanticType.INFIXOP &&
  101. node.childNodes[0].role === semantic_meaning_js_1.SemanticRole.IMPLICIT &&
  102. node.childNodes[0].childNodes.every(function (x) {
  103. return x.type === semantic_meaning_js_1.SemanticType.NUMBER;
  104. }) &&
  105. node.childNodes[0].contentNodes.every(function (x) {
  106. return x.role === semantic_meaning_js_1.SemanticRole.SPACE;
  107. })));
  108. function juxtapositionPrePost(partition) {
  109. const rels = [];
  110. const comps = [];
  111. let next = partition.comp.shift();
  112. let rel = null;
  113. let collect = [];
  114. while (partition.comp.length) {
  115. collect = [];
  116. if (next.length) {
  117. if (rel) {
  118. rels.push(rel);
  119. }
  120. comps.push(next);
  121. rel = partition.rel.shift();
  122. next = partition.comp.shift();
  123. continue;
  124. }
  125. if (rel) {
  126. collect.push(rel);
  127. }
  128. while (!next.length && partition.comp.length) {
  129. next = partition.comp.shift();
  130. collect.push(partition.rel.shift());
  131. }
  132. rel = convertPrePost(collect, next, comps);
  133. }
  134. if (!collect.length && !next.length) {
  135. collect.push(rel);
  136. convertPrePost(collect, next, comps);
  137. }
  138. else {
  139. rels.push(rel);
  140. comps.push(next);
  141. }
  142. return { rel: rels, comp: comps };
  143. }
  144. function convertPrePost(collect, next, comps) {
  145. let rel = null;
  146. if (!collect.length) {
  147. return rel;
  148. }
  149. const prev = comps[comps.length - 1];
  150. const prevExists = prev && prev.length;
  151. const nextExists = next && next.length;
  152. const processor = semantic_processor_js_1.SemanticProcessor.getInstance();
  153. if (prevExists && nextExists) {
  154. if (next[0].type === semantic_meaning_js_1.SemanticType.INFIXOP &&
  155. next[0].role === semantic_meaning_js_1.SemanticRole.IMPLICIT) {
  156. rel = collect.pop();
  157. prev.push(processor['postfixNode_'](prev.pop(), collect));
  158. return rel;
  159. }
  160. rel = collect.shift();
  161. const result = processor['prefixNode_'](next.shift(), collect);
  162. next.unshift(result);
  163. return rel;
  164. }
  165. if (prevExists) {
  166. prev.push(processor['postfixNode_'](prev.pop(), collect));
  167. return rel;
  168. }
  169. if (nextExists) {
  170. next.unshift(processor['prefixNode_'](next.shift(), collect));
  171. }
  172. return rel;
  173. }
  174. function recurseJuxtaposition(acc, ops, elements) {
  175. if (!ops.length) {
  176. return acc;
  177. }
  178. const left = acc.pop();
  179. const op = ops.shift();
  180. const first = elements.shift();
  181. if (op.type === semantic_meaning_js_1.SemanticType.INFIXOP &&
  182. (op.role === semantic_meaning_js_1.SemanticRole.IMPLICIT || op.role === semantic_meaning_js_1.SemanticRole.UNIT)) {
  183. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 2');
  184. const right = (left ? [left, op] : [op]).concat(first);
  185. return recurseJuxtaposition(acc.concat(right), ops, elements);
  186. }
  187. if (!left) {
  188. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 3');
  189. return recurseJuxtaposition([op].concat(first), ops, elements);
  190. }
  191. const right = first.shift();
  192. if (!right) {
  193. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 9');
  194. const newOp = semantic_heuristic_factory_js_1.SemanticHeuristics.factory.makeBranchNode(semantic_meaning_js_1.SemanticType.INFIXOP, [left, ops.shift()], [op], op.textContent);
  195. newOp.role = semantic_meaning_js_1.SemanticRole.IMPLICIT;
  196. semantic_heuristic_factory_js_1.SemanticHeuristics.run('combine_juxtaposition', newOp);
  197. ops.unshift(newOp);
  198. return recurseJuxtaposition(acc, ops, elements);
  199. }
  200. if (SemanticPred.isOperator(left) || SemanticPred.isOperator(right)) {
  201. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 4');
  202. return recurseJuxtaposition(acc.concat([left, op, right]).concat(first), ops, elements);
  203. }
  204. let result = null;
  205. if (SemanticPred.isImplicitOp(left) && SemanticPred.isImplicitOp(right)) {
  206. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 5');
  207. left.contentNodes.push(op);
  208. left.contentNodes = left.contentNodes.concat(right.contentNodes);
  209. left.childNodes.push(right);
  210. left.childNodes = left.childNodes.concat(right.childNodes);
  211. right.childNodes.forEach((x) => (x.parent = left));
  212. op.parent = left;
  213. left.addMathmlNodes(op.mathml);
  214. left.addMathmlNodes(right.mathml);
  215. result = left;
  216. }
  217. else if (SemanticPred.isImplicitOp(left)) {
  218. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 6');
  219. left.contentNodes.push(op);
  220. left.childNodes.push(right);
  221. right.parent = left;
  222. op.parent = left;
  223. left.addMathmlNodes(op.mathml);
  224. left.addMathmlNodes(right.mathml);
  225. result = left;
  226. }
  227. else if (SemanticPred.isImplicitOp(right)) {
  228. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 7');
  229. right.contentNodes.unshift(op);
  230. right.childNodes.unshift(left);
  231. left.parent = right;
  232. op.parent = right;
  233. right.addMathmlNodes(op.mathml);
  234. right.addMathmlNodes(left.mathml);
  235. result = right;
  236. }
  237. else {
  238. debugger_js_1.Debugger.getInstance().output('Juxta Heuristic Case 8');
  239. result = semantic_heuristic_factory_js_1.SemanticHeuristics.factory.makeBranchNode(semantic_meaning_js_1.SemanticType.INFIXOP, [left, right], [op], op.textContent);
  240. result.role = semantic_meaning_js_1.SemanticRole.IMPLICIT;
  241. }
  242. acc.push(result);
  243. return recurseJuxtaposition(acc.concat(first), ops, elements);
  244. }
  245. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticMultiHeuristic('intvar_from_implicit', implicitUnpack, (nodes) => nodes[0] && SemanticPred.isImplicit(nodes[0])));
  246. function implicitUnpack(nodes) {
  247. const children = nodes[0].childNodes;
  248. nodes.splice(0, 1, ...children);
  249. }
  250. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('intvar_from_fraction', integralFractionArg, (node) => {
  251. if (node.type !== semantic_meaning_js_1.SemanticType.INTEGRAL)
  252. return false;
  253. const [, integrand, intvar] = node.childNodes;
  254. return (intvar.type === semantic_meaning_js_1.SemanticType.EMPTY &&
  255. integrand.type === semantic_meaning_js_1.SemanticType.FRACTION);
  256. }));
  257. function integralFractionArg(node) {
  258. const integrand = node.childNodes[1];
  259. const enumerator = integrand.childNodes[0];
  260. if (SemanticPred.isIntegralDxBoundarySingle(enumerator)) {
  261. enumerator.role = semantic_meaning_js_1.SemanticRole.INTEGRAL;
  262. return;
  263. }
  264. if (!SemanticPred.isImplicit(enumerator))
  265. return;
  266. const length = enumerator.childNodes.length;
  267. const first = enumerator.childNodes[length - 2];
  268. const second = enumerator.childNodes[length - 1];
  269. if (SemanticPred.isIntegralDxBoundarySingle(second)) {
  270. second.role = semantic_meaning_js_1.SemanticRole.INTEGRAL;
  271. return;
  272. }
  273. if (SemanticPred.isIntegralDxBoundary(first, second)) {
  274. const prefix = semantic_processor_js_1.SemanticProcessor.getInstance()['prefixNode_'](second, [
  275. first
  276. ]);
  277. prefix.role = semantic_meaning_js_1.SemanticRole.INTEGRAL;
  278. if (length === 2) {
  279. integrand.childNodes[0] = prefix;
  280. }
  281. else {
  282. enumerator.childNodes.pop();
  283. enumerator.contentNodes.pop();
  284. enumerator.childNodes[length - 2] = prefix;
  285. prefix.parent = enumerator;
  286. }
  287. }
  288. }
  289. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticTreeHeuristic('rewrite_subcases', rewriteSubcasesTable, (table) => {
  290. let left = true;
  291. let right = true;
  292. const topLeft = table.childNodes[0].childNodes[0];
  293. if (!eligibleNode(topLeft.mathmlTree)) {
  294. left = false;
  295. }
  296. else {
  297. for (let i = 1, row; (row = table.childNodes[i]); i++) {
  298. if (row.childNodes[0].childNodes.length) {
  299. left = false;
  300. break;
  301. }
  302. }
  303. }
  304. if (left) {
  305. table.addAnnotation('Emph', 'left');
  306. }
  307. const topRight = table.childNodes[0].childNodes[table.childNodes[0].childNodes.length - 1];
  308. if (!eligibleNode(topRight.mathmlTree)) {
  309. right = false;
  310. }
  311. else {
  312. const firstRow = table.childNodes[0].childNodes.length;
  313. for (let i = 1, row; (row = table.childNodes[i]); i++) {
  314. if (row.childNodes.length >= firstRow) {
  315. right = false;
  316. break;
  317. }
  318. }
  319. }
  320. if (right) {
  321. table.addAnnotation('Emph', 'right');
  322. }
  323. return left || right;
  324. }));
  325. function eligibleNode(node) {
  326. return (node.childNodes[0] &&
  327. node.childNodes[0].childNodes[0] &&
  328. DomUtil.tagName(node.childNodes[0]) === semantic_util_js_1.MMLTAGS.MPADDED &&
  329. DomUtil.tagName(node.childNodes[0].childNodes[0]) ===
  330. semantic_util_js_1.MMLTAGS.MPADDED &&
  331. DomUtil.tagName(node.childNodes[0].childNodes[node.childNodes[0].childNodes.length - 1]) === semantic_util_js_1.MMLTAGS.MPHANTOM);
  332. }
  333. const rewritable = [
  334. semantic_meaning_js_1.SemanticType.PUNCTUATED,
  335. semantic_meaning_js_1.SemanticType.RELSEQ,
  336. semantic_meaning_js_1.SemanticType.MULTIREL,
  337. semantic_meaning_js_1.SemanticType.INFIXOP,
  338. semantic_meaning_js_1.SemanticType.PREFIXOP,
  339. semantic_meaning_js_1.SemanticType.POSTFIXOP
  340. ];
  341. function rewriteSubcasesTable(table) {
  342. table.addAnnotation('Emph', 'top');
  343. let row = [];
  344. if (table.hasAnnotation('Emph', 'left')) {
  345. const topLeft = table.childNodes[0].childNodes[0].childNodes[0];
  346. const cells = rewriteCell(topLeft, true);
  347. cells.forEach((x) => x.addAnnotation('Emph', 'left'));
  348. row = row.concat(cells);
  349. for (let i = 0, line; (line = table.childNodes[i]); i++) {
  350. line.childNodes.shift();
  351. }
  352. }
  353. row.push(table);
  354. if (table.hasAnnotation('Emph', 'right')) {
  355. const topRight = table.childNodes[0].childNodes[table.childNodes[0].childNodes.length - 1]
  356. .childNodes[0];
  357. const cells = rewriteCell(topRight);
  358. cells.forEach((x) => x.addAnnotation('Emph', 'left'));
  359. row = row.concat(cells);
  360. table.childNodes[0].childNodes.pop();
  361. }
  362. semantic_processor_js_1.SemanticProcessor.tableToMultiline(table);
  363. const newNode = semantic_processor_js_1.SemanticProcessor.getInstance().row(row);
  364. const annotation = table.annotation['Emph'];
  365. table.annotation['Emph'] = ['table'];
  366. annotation.forEach((x) => newNode.addAnnotation('Emph', x));
  367. return newNode;
  368. }
  369. function rewriteCell(cell, left) {
  370. if (!cell.childNodes.length) {
  371. rewriteFence(cell);
  372. return [cell];
  373. }
  374. let fence = null;
  375. if (cell.type === semantic_meaning_js_1.SemanticType.PUNCTUATED &&
  376. (left
  377. ? cell.role === semantic_meaning_js_1.SemanticRole.ENDPUNCT
  378. : cell.role === semantic_meaning_js_1.SemanticRole.STARTPUNCT)) {
  379. const children = cell.childNodes;
  380. if (rewriteFence(children[left ? children.length - 1 : 0])) {
  381. cell = children[left ? 0 : children.length - 1];
  382. fence = children[left ? children.length - 1 : 0];
  383. }
  384. }
  385. if (rewritable.indexOf(cell.type) !== -1) {
  386. const children = cell.childNodes;
  387. rewriteFence(children[left ? children.length - 1 : 0]);
  388. const newNodes = semantic_skeleton_js_1.SemanticSkeleton.combineContentChildren(cell.type, cell.role, cell.contentNodes, cell.childNodes);
  389. if (fence) {
  390. if (left) {
  391. newNodes.push(fence);
  392. }
  393. else {
  394. newNodes.unshift(fence);
  395. }
  396. }
  397. return newNodes;
  398. }
  399. return fence ? (left ? [cell, fence] : [fence, cell]) : [cell];
  400. }
  401. const PUNCT_TO_FENCE_ = {
  402. [semantic_meaning_js_1.SemanticRole.METRIC]: semantic_meaning_js_1.SemanticRole.METRIC,
  403. [semantic_meaning_js_1.SemanticRole.VBAR]: semantic_meaning_js_1.SemanticRole.NEUTRAL,
  404. [semantic_meaning_js_1.SemanticRole.OPENFENCE]: semantic_meaning_js_1.SemanticRole.OPEN,
  405. [semantic_meaning_js_1.SemanticRole.CLOSEFENCE]: semantic_meaning_js_1.SemanticRole.CLOSE
  406. };
  407. function rewriteFence(fence) {
  408. if (fence.type !== semantic_meaning_js_1.SemanticType.PUNCTUATION) {
  409. return false;
  410. }
  411. const role = PUNCT_TO_FENCE_[fence.role];
  412. if (!role) {
  413. return false;
  414. }
  415. fence.role = role;
  416. fence.type = semantic_meaning_js_1.SemanticType.FENCE;
  417. fence.addAnnotation('Emph', 'fence');
  418. return true;
  419. }
  420. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticMultiHeuristic('ellipses', (nodes) => {
  421. const newNodes = [];
  422. let current = nodes.shift();
  423. while (current) {
  424. [current, nodes] = combineNodes(current, nodes, semantic_meaning_js_1.SemanticRole.FULLSTOP, semantic_meaning_js_1.SemanticRole.ELLIPSIS);
  425. [current, nodes] = combineNodes(current, nodes, semantic_meaning_js_1.SemanticRole.DASH);
  426. newNodes.push(current);
  427. current = nodes.shift();
  428. }
  429. return newNodes;
  430. }, (nodes) => nodes.length > 1));
  431. function combineNodes(current, nodes, src, target = src) {
  432. const collect = [];
  433. while (current && current.role === src) {
  434. collect.push(current);
  435. current = nodes.shift();
  436. }
  437. if (!collect.length) {
  438. return [current, nodes];
  439. }
  440. if (current) {
  441. nodes.unshift(current);
  442. }
  443. return [
  444. collect.length === 1 ? collect[0] : combinedNodes(collect, target),
  445. nodes
  446. ];
  447. }
  448. function combinedNodes(nodes, role) {
  449. const node = semantic_heuristic_factory_js_1.SemanticHeuristics.factory.makeBranchNode(semantic_meaning_js_1.SemanticType.PUNCTUATION, nodes, []);
  450. node.role = role;
  451. return node;
  452. }
  453. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticMultiHeuristic('op_with_limits', (nodes) => {
  454. const center = nodes[0];
  455. center.type = semantic_meaning_js_1.SemanticType.LARGEOP;
  456. center.role = semantic_meaning_js_1.SemanticRole.SUM;
  457. return nodes;
  458. }, (nodes) => {
  459. return (nodes[0].type === semantic_meaning_js_1.SemanticType.OPERATOR &&
  460. nodes
  461. .slice(1)
  462. .some((node) => node.type === semantic_meaning_js_1.SemanticType.RELSEQ ||
  463. node.type === semantic_meaning_js_1.SemanticType.MULTIREL ||
  464. (node.type === semantic_meaning_js_1.SemanticType.INFIXOP &&
  465. node.role === semantic_meaning_js_1.SemanticRole.ELEMENT) ||
  466. (node.type === semantic_meaning_js_1.SemanticType.PUNCTUATED &&
  467. node.role === semantic_meaning_js_1.SemanticRole.SEQUENCE)));
  468. }));
  469. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticMultiHeuristic('bracketed_interval', (nodes) => {
  470. const leftFence = nodes[0];
  471. const rightFence = nodes[1];
  472. const content = nodes.slice(2);
  473. const childNode = semantic_processor_js_1.SemanticProcessor.getInstance().row(content);
  474. const fenced = semantic_heuristic_factory_js_1.SemanticHeuristics.factory.makeBranchNode(semantic_meaning_js_1.SemanticType.FENCED, [childNode], [leftFence, rightFence]);
  475. fenced.role = semantic_meaning_js_1.SemanticRole.LEFTRIGHT;
  476. return fenced;
  477. }, (nodes) => {
  478. const leftFence = nodes[0];
  479. const rightFence = nodes[1];
  480. const content = nodes.slice(2);
  481. if (!(leftFence &&
  482. (leftFence.textContent === ']' || leftFence.textContent === '[') &&
  483. rightFence &&
  484. (rightFence.textContent === ']' || rightFence.textContent === '['))) {
  485. return false;
  486. }
  487. const partition = SemanticUtil.partitionNodes(content, SemanticPred.isPunctuation);
  488. return !!(partition.rel.length === 1 &&
  489. partition.comp[0].length &&
  490. partition.comp[1].length);
  491. }));
  492. semantic_heuristic_factory_js_1.SemanticHeuristics.add(new semantic_heuristic_js_1.SemanticMmlHeuristic('function_from_identifiers', (node) => {
  493. const expr = DomUtil.toArray(node.childNodes)
  494. .map((x) => x.textContent.trim())
  495. .join('');
  496. const meaning = semantic_attr_js_1.SemanticMap.Meaning.get(expr);
  497. if (meaning.type === semantic_meaning_js_1.SemanticType.UNKNOWN) {
  498. return node;
  499. }
  500. const snode = semantic_heuristic_factory_js_1.SemanticHeuristics.factory.makeLeafNode(expr, semantic_processor_js_1.SemanticProcessor.getInstance().font(node.getAttribute('mathvariant')));
  501. snode.mathmlTree = node;
  502. return snode;
  503. }, (node) => {
  504. const children = DomUtil.toArray(node.childNodes);
  505. if (children.length < 2) {
  506. return false;
  507. }
  508. return children.every((child) => DomUtil.tagName(child) === semantic_util_js_1.MMLTAGS.MI &&
  509. semantic_attr_js_1.SemanticMap.Meaning.get(child.textContent.trim()).role ===
  510. semantic_meaning_js_1.SemanticRole.LATINLETTER);
  511. }));