nemeth_util.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.openingFraction = openingFraction;
  4. exports.closingFraction = closingFraction;
  5. exports.overFraction = overFraction;
  6. exports.overBevelledFraction = overBevelledFraction;
  7. exports.hyperFractionBoundary = hyperFractionBoundary;
  8. exports.openingRadical = openingRadical;
  9. exports.closingRadical = closingRadical;
  10. exports.indexRadical = indexRadical;
  11. exports.relationIterator = relationIterator;
  12. exports.implicitIterator = implicitIterator;
  13. exports.contentIterator = contentIterator;
  14. const auditory_description_js_1 = require("../audio/auditory_description.js");
  15. const span_js_1 = require("../audio/span.js");
  16. const DomUtil = require("../common/dom_util.js");
  17. const XpathUtil = require("../common/xpath_util.js");
  18. const grammar_js_1 = require("../rule_engine/grammar.js");
  19. const engine_js_1 = require("../common/engine.js");
  20. const semantic_annotations_js_1 = require("../semantic_tree/semantic_annotations.js");
  21. const semantic_annotator_js_1 = require("../semantic_tree/semantic_annotator.js");
  22. const semantic_meaning_js_1 = require("../semantic_tree/semantic_meaning.js");
  23. const locale_js_1 = require("../l10n/locale.js");
  24. const MathspeakUtil = require("./mathspeak_util.js");
  25. const store_util_js_1 = require("../rule_engine/store_util.js");
  26. function openingFraction(node) {
  27. const depth = MathspeakUtil.fractionNestingDepth(node);
  28. return span_js_1.Span.singleton(new Array(depth).join(locale_js_1.LOCALE.MESSAGES.MS.FRACTION_REPEAT) +
  29. locale_js_1.LOCALE.MESSAGES.MS.FRACTION_START);
  30. }
  31. function closingFraction(node) {
  32. const depth = MathspeakUtil.fractionNestingDepth(node);
  33. return span_js_1.Span.singleton(new Array(depth).join(locale_js_1.LOCALE.MESSAGES.MS.FRACTION_REPEAT) +
  34. locale_js_1.LOCALE.MESSAGES.MS.FRACTION_END);
  35. }
  36. function overFraction(node) {
  37. const depth = MathspeakUtil.fractionNestingDepth(node);
  38. return span_js_1.Span.singleton(new Array(depth).join(locale_js_1.LOCALE.MESSAGES.MS.FRACTION_REPEAT) +
  39. locale_js_1.LOCALE.MESSAGES.MS.FRACTION_OVER);
  40. }
  41. function overBevelledFraction(node) {
  42. const depth = MathspeakUtil.fractionNestingDepth(node);
  43. return span_js_1.Span.singleton(new Array(depth).join(locale_js_1.LOCALE.MESSAGES.MS.FRACTION_REPEAT) +
  44. '⠸' +
  45. locale_js_1.LOCALE.MESSAGES.MS.FRACTION_OVER);
  46. }
  47. function hyperFractionBoundary(node) {
  48. return locale_js_1.LOCALE.MESSAGES.regexp.HYPER ===
  49. MathspeakUtil.fractionNestingDepth(node).toString()
  50. ? [node]
  51. : [];
  52. }
  53. function nestedRadical(node, postfix) {
  54. const depth = radicalNestingDepth(node);
  55. return span_js_1.Span.singleton(depth === 1
  56. ? postfix
  57. : new Array(depth).join(locale_js_1.LOCALE.MESSAGES.MS.NESTED) + postfix);
  58. }
  59. function radicalNestingDepth(node, opt_depth) {
  60. const depth = opt_depth || 0;
  61. if (!node.parentNode) {
  62. return depth;
  63. }
  64. return radicalNestingDepth(node.parentNode, node.tagName === 'root' || node.tagName === 'sqrt' ? depth + 1 : depth);
  65. }
  66. function openingRadical(node) {
  67. return nestedRadical(node, locale_js_1.LOCALE.MESSAGES.MS.STARTROOT);
  68. }
  69. function closingRadical(node) {
  70. return nestedRadical(node, locale_js_1.LOCALE.MESSAGES.MS.ENDROOT);
  71. }
  72. function indexRadical(node) {
  73. return nestedRadical(node, locale_js_1.LOCALE.MESSAGES.MS.ROOTINDEX);
  74. }
  75. function enlargeFence(text) {
  76. const start = '⠠';
  77. if (text.length === 1) {
  78. return start + text;
  79. }
  80. const neut = '⠳';
  81. const split = text.split('');
  82. if (split.every(function (x) {
  83. return x === neut;
  84. })) {
  85. return start + split.join(start);
  86. }
  87. return text.slice(0, -1) + start + text.slice(-1);
  88. }
  89. grammar_js_1.Grammar.getInstance().setCorrection('enlargeFence', enlargeFence);
  90. const NUMBER_PROPAGATORS = [
  91. semantic_meaning_js_1.SemanticType.MULTIREL,
  92. semantic_meaning_js_1.SemanticType.RELSEQ,
  93. semantic_meaning_js_1.SemanticType.APPL,
  94. semantic_meaning_js_1.SemanticType.ROW,
  95. semantic_meaning_js_1.SemanticType.LINE
  96. ];
  97. const NUMBER_INHIBITORS = [
  98. semantic_meaning_js_1.SemanticType.SUBSCRIPT,
  99. semantic_meaning_js_1.SemanticType.SUPERSCRIPT,
  100. semantic_meaning_js_1.SemanticType.OVERSCORE,
  101. semantic_meaning_js_1.SemanticType.UNDERSCORE
  102. ];
  103. function checkParent(node, info) {
  104. const parent = node.parent;
  105. if (!parent) {
  106. return false;
  107. }
  108. const type = parent.type;
  109. if (NUMBER_PROPAGATORS.indexOf(type) !== -1 ||
  110. (type === semantic_meaning_js_1.SemanticType.PREFIXOP &&
  111. parent.role === semantic_meaning_js_1.SemanticRole.NEGATIVE &&
  112. !info.script &&
  113. !info.enclosed) ||
  114. (type === semantic_meaning_js_1.SemanticType.PREFIXOP &&
  115. parent.role === semantic_meaning_js_1.SemanticRole.GEOMETRY)) {
  116. return true;
  117. }
  118. if (type === semantic_meaning_js_1.SemanticType.PUNCTUATED) {
  119. if (!info.enclosed || parent.role === semantic_meaning_js_1.SemanticRole.TEXT) {
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. function propagateNumber(node, info) {
  126. if (!node.childNodes.length) {
  127. if (checkParent(node, info)) {
  128. info.number = true;
  129. info.script = false;
  130. info.enclosed = false;
  131. }
  132. return [
  133. info['number'] ? 'number' : '',
  134. { number: false, enclosed: info.enclosed, script: info.script }
  135. ];
  136. }
  137. if (NUMBER_INHIBITORS.indexOf(node.type) !== -1) {
  138. info.script = true;
  139. }
  140. if (node.type === semantic_meaning_js_1.SemanticType.FENCED) {
  141. info.number = false;
  142. info.enclosed = true;
  143. return ['', info];
  144. }
  145. if (node.type === semantic_meaning_js_1.SemanticType.PREFIXOP &&
  146. node.role !== semantic_meaning_js_1.SemanticRole.GEOMETRY &&
  147. node.role !== semantic_meaning_js_1.SemanticRole.NEGATIVE) {
  148. info.number = false;
  149. return ['', info];
  150. }
  151. if (checkParent(node, info)) {
  152. info.number = true;
  153. info.enclosed = false;
  154. }
  155. return ['', info];
  156. }
  157. (0, semantic_annotations_js_1.register)(new semantic_annotator_js_1.SemanticVisitor('nemeth', 'number', propagateNumber, { number: true }));
  158. function annotateDepth(node) {
  159. if (!node.parent) {
  160. return [1];
  161. }
  162. const depth = parseInt(node.parent.annotation['depth'][0]);
  163. return [depth + 1];
  164. }
  165. (0, semantic_annotations_js_1.register)(new semantic_annotator_js_1.SemanticVisitor('depth', 'depth', annotateDepth));
  166. (0, semantic_annotations_js_1.activate)('depth', 'depth');
  167. function relationIterator(nodes, context) {
  168. var _a;
  169. const childNodes = nodes.slice(0);
  170. let first = true;
  171. const parentNode = nodes[0].parentNode.parentNode;
  172. const match = (_a = parentNode.getAttribute('annotation')) === null || _a === void 0 ? void 0 : _a.match(/depth:(\d+)/);
  173. const depth = match ? match[1] : '';
  174. let contentNodes;
  175. if (nodes.length > 0) {
  176. contentNodes = XpathUtil.evalXPath('./content/*', parentNode);
  177. }
  178. else {
  179. contentNodes = [];
  180. }
  181. return function () {
  182. const content = contentNodes.shift();
  183. const leftChild = childNodes.shift();
  184. const rightChild = childNodes[0];
  185. const contextDescr = context
  186. ? [auditory_description_js_1.AuditoryDescription.create({ text: context }, { translate: true })]
  187. : [];
  188. if (!content) {
  189. return contextDescr;
  190. }
  191. const base = leftChild
  192. ? MathspeakUtil.nestedSubSuper(leftChild, '', {
  193. sup: locale_js_1.LOCALE.MESSAGES.MS.SUPER,
  194. sub: locale_js_1.LOCALE.MESSAGES.MS.SUB
  195. })
  196. : '';
  197. const left = (leftChild && DomUtil.tagName(leftChild) !== 'EMPTY') ||
  198. (first && parentNode && parentNode.previousSibling)
  199. ? [
  200. auditory_description_js_1.AuditoryDescription.create({ text: locale_js_1.LOCALE.MESSAGES.regexp.SPACE + base }, {})
  201. ]
  202. : [];
  203. const right = (rightChild && DomUtil.tagName(rightChild) !== 'EMPTY') ||
  204. (!contentNodes.length && parentNode && parentNode.nextSibling)
  205. ? [
  206. auditory_description_js_1.AuditoryDescription.create({ text: locale_js_1.LOCALE.MESSAGES.regexp.SPACE }, {})
  207. ]
  208. : [];
  209. const descrs = engine_js_1.Engine.evaluateNode(content);
  210. descrs.unshift(new auditory_description_js_1.AuditoryDescription({ text: '', layout: `beginrel${depth}` }));
  211. descrs.push(new auditory_description_js_1.AuditoryDescription({ text: '', layout: `endrel${depth}` }));
  212. first = false;
  213. return contextDescr.concat(left, descrs, right);
  214. };
  215. }
  216. function implicitIterator(nodes, context) {
  217. const childNodes = nodes.slice(0);
  218. let contentNodes;
  219. if (nodes.length > 0) {
  220. contentNodes = XpathUtil.evalXPath('../../content/*', nodes[0]);
  221. }
  222. else {
  223. contentNodes = [];
  224. }
  225. return function () {
  226. const leftChild = childNodes.shift();
  227. const rightChild = childNodes[0];
  228. const content = contentNodes.shift();
  229. const contextDescr = context
  230. ? [auditory_description_js_1.AuditoryDescription.create({ text: context }, { translate: true })]
  231. : [];
  232. if (!content) {
  233. return contextDescr;
  234. }
  235. const left = leftChild && DomUtil.tagName(leftChild) === 'NUMBER';
  236. const right = rightChild && DomUtil.tagName(rightChild) === 'NUMBER';
  237. return contextDescr.concat(left && right && content.getAttribute('role') === semantic_meaning_js_1.SemanticRole.SPACE
  238. ? [
  239. auditory_description_js_1.AuditoryDescription.create({ text: locale_js_1.LOCALE.MESSAGES.regexp.SPACE }, {})
  240. ]
  241. : []);
  242. };
  243. }
  244. function ignoreEnglish(text) {
  245. return (0, grammar_js_1.correctFont)(text, locale_js_1.LOCALE.ALPHABETS.languagePrefix.english);
  246. }
  247. grammar_js_1.Grammar.getInstance().setCorrection('ignoreEnglish', ignoreEnglish);
  248. function contentIterator(nodes, context) {
  249. var _a;
  250. const func = (0, store_util_js_1.contentIterator)(nodes, context);
  251. const parentNode = nodes[0].parentNode.parentNode;
  252. const match = (_a = parentNode.getAttribute('annotation')) === null || _a === void 0 ? void 0 : _a.match(/depth:(\d+)/);
  253. const depth = match ? match[1] : '';
  254. return function () {
  255. const descrs = func();
  256. descrs.unshift(new auditory_description_js_1.AuditoryDescription({ text: '', layout: `beginrel${depth}` }));
  257. descrs.push(new auditory_description_js_1.AuditoryDescription({ text: '', layout: `endrel${depth}` }));
  258. return descrs;
  259. };
  260. }
  261. function literal(text) {
  262. const evalStr = (e) => engine_js_1.Engine.getInstance().evaluator(e, engine_js_1.Engine.getInstance().dynamicCstr);
  263. return Array.from(text).map(evalStr).join('');
  264. }
  265. grammar_js_1.Grammar.getInstance().setCorrection('literal', literal);