semantic_mathml.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.SemanticMathml = void 0;
  4. const DomUtil = require("../common/dom_util.js");
  5. const semantic_meaning_js_1 = require("./semantic_meaning.js");
  6. const semantic_attr_js_1 = require("./semantic_attr.js");
  7. const semantic_parser_js_1 = require("./semantic_parser.js");
  8. const SemanticPred = require("./semantic_pred.js");
  9. const semantic_processor_js_1 = require("./semantic_processor.js");
  10. const SemanticUtil = require("./semantic_util.js");
  11. const semantic_util_js_1 = require("../semantic_tree/semantic_util.js");
  12. const semantic_heuristic_factory_js_1 = require("./semantic_heuristic_factory.js");
  13. class SemanticMathml extends semantic_parser_js_1.SemanticAbstractParser {
  14. static getAttribute_(node, attr, def) {
  15. if (!node.hasAttribute(attr)) {
  16. return def;
  17. }
  18. const value = node.getAttribute(attr);
  19. if (value.match(/^\s*$/)) {
  20. return null;
  21. }
  22. return value;
  23. }
  24. constructor() {
  25. super('MathML');
  26. this.parseMap_ = new Map([
  27. [semantic_util_js_1.MMLTAGS.SEMANTICS, this.semantics_.bind(this)],
  28. [semantic_util_js_1.MMLTAGS.MATH, this.rows_.bind(this)],
  29. [semantic_util_js_1.MMLTAGS.MROW, this.rows_.bind(this)],
  30. [semantic_util_js_1.MMLTAGS.MPADDED, this.rows_.bind(this)],
  31. [semantic_util_js_1.MMLTAGS.MSTYLE, this.rows_.bind(this)],
  32. [semantic_util_js_1.MMLTAGS.MFRAC, this.fraction_.bind(this)],
  33. [semantic_util_js_1.MMLTAGS.MSUB, this.limits_.bind(this)],
  34. [semantic_util_js_1.MMLTAGS.MSUP, this.limits_.bind(this)],
  35. [semantic_util_js_1.MMLTAGS.MSUBSUP, this.limits_.bind(this)],
  36. [semantic_util_js_1.MMLTAGS.MOVER, this.limits_.bind(this)],
  37. [semantic_util_js_1.MMLTAGS.MUNDER, this.limits_.bind(this)],
  38. [semantic_util_js_1.MMLTAGS.MUNDEROVER, this.limits_.bind(this)],
  39. [semantic_util_js_1.MMLTAGS.MROOT, this.root_.bind(this)],
  40. [semantic_util_js_1.MMLTAGS.MSQRT, this.sqrt_.bind(this)],
  41. [semantic_util_js_1.MMLTAGS.MTABLE, this.table_.bind(this)],
  42. [semantic_util_js_1.MMLTAGS.MLABELEDTR, this.tableLabeledRow_.bind(this)],
  43. [semantic_util_js_1.MMLTAGS.MTR, this.tableRow_.bind(this)],
  44. [semantic_util_js_1.MMLTAGS.MTD, this.tableCell_.bind(this)],
  45. [semantic_util_js_1.MMLTAGS.MS, this.text_.bind(this)],
  46. [semantic_util_js_1.MMLTAGS.MTEXT, this.text_.bind(this)],
  47. [semantic_util_js_1.MMLTAGS.MSPACE, this.space_.bind(this)],
  48. [semantic_util_js_1.MMLTAGS.ANNOTATIONXML, this.text_.bind(this)],
  49. [semantic_util_js_1.MMLTAGS.MI, this.identifier_.bind(this)],
  50. [semantic_util_js_1.MMLTAGS.MN, this.number_.bind(this)],
  51. [semantic_util_js_1.MMLTAGS.MO, this.operator_.bind(this)],
  52. [semantic_util_js_1.MMLTAGS.MFENCED, this.fenced_.bind(this)],
  53. [semantic_util_js_1.MMLTAGS.MENCLOSE, this.enclosed_.bind(this)],
  54. [semantic_util_js_1.MMLTAGS.MMULTISCRIPTS, this.multiscripts_.bind(this)],
  55. [semantic_util_js_1.MMLTAGS.ANNOTATION, this.empty_.bind(this)],
  56. [semantic_util_js_1.MMLTAGS.NONE, this.empty_.bind(this)],
  57. [semantic_util_js_1.MMLTAGS.MACTION, this.action_.bind(this)]
  58. ]);
  59. const meaning = {
  60. type: semantic_meaning_js_1.SemanticType.IDENTIFIER,
  61. role: semantic_meaning_js_1.SemanticRole.NUMBERSET,
  62. font: semantic_meaning_js_1.SemanticFont.DOUBLESTRUCK
  63. };
  64. [
  65. 'C',
  66. 'H',
  67. 'N',
  68. 'P',
  69. 'Q',
  70. 'R',
  71. 'Z',
  72. 'ℂ',
  73. 'ℍ',
  74. 'ℕ',
  75. 'ℙ',
  76. 'ℚ',
  77. 'ℝ',
  78. 'ℤ'
  79. ].forEach(((x) => this.getFactory().defaultMap.set(x, meaning)).bind(this));
  80. }
  81. parse(mml) {
  82. semantic_processor_js_1.SemanticProcessor.getInstance().setNodeFactory(this.getFactory());
  83. const children = DomUtil.toArray(mml.childNodes);
  84. const tag = DomUtil.tagName(mml);
  85. const func = this.parseMap_.get(tag);
  86. const newNode = (func ? func : this.dummy_.bind(this))(mml, children);
  87. SemanticUtil.addAttributes(newNode, mml);
  88. if ([
  89. semantic_util_js_1.MMLTAGS.MATH,
  90. semantic_util_js_1.MMLTAGS.MROW,
  91. semantic_util_js_1.MMLTAGS.MPADDED,
  92. semantic_util_js_1.MMLTAGS.MSTYLE,
  93. semantic_util_js_1.MMLTAGS.SEMANTICS,
  94. semantic_util_js_1.MMLTAGS.MACTION
  95. ].indexOf(tag) !== -1) {
  96. return newNode;
  97. }
  98. newNode.mathml.unshift(mml);
  99. newNode.mathmlTree = mml;
  100. return newNode;
  101. }
  102. semantics_(_node, children) {
  103. return children.length
  104. ? this.parse(children[0])
  105. : this.getFactory().makeEmptyNode();
  106. }
  107. rows_(node, children) {
  108. const semantics = node.getAttribute('semantics');
  109. if (semantics && semantics.match('bspr_')) {
  110. return semantic_processor_js_1.SemanticProcessor.proof(node, semantics, this.parseList.bind(this));
  111. }
  112. children = SemanticUtil.purgeNodes(children);
  113. let newNode;
  114. if (children.length === 1) {
  115. newNode = this.parse(children[0]);
  116. if (newNode.type === semantic_meaning_js_1.SemanticType.EMPTY && !newNode.mathmlTree) {
  117. newNode.mathmlTree = node;
  118. }
  119. }
  120. else {
  121. const snode = semantic_heuristic_factory_js_1.SemanticHeuristics.run('function_from_identifiers', node);
  122. newNode =
  123. snode && snode !== node
  124. ? snode
  125. : semantic_processor_js_1.SemanticProcessor.getInstance().row(this.parseList(children));
  126. }
  127. newNode.mathml.unshift(node);
  128. return newNode;
  129. }
  130. fraction_(node, children) {
  131. if (!children.length) {
  132. return this.getFactory().makeEmptyNode();
  133. }
  134. const upper = this.parse(children[0]);
  135. const lower = children[1]
  136. ? this.parse(children[1])
  137. : this.getFactory().makeEmptyNode();
  138. const sem = semantic_processor_js_1.SemanticProcessor.getInstance().fractionLikeNode(upper, lower, node.getAttribute('linethickness'), node.getAttribute('bevelled') === 'true');
  139. return sem;
  140. }
  141. limits_(node, children) {
  142. return semantic_processor_js_1.SemanticProcessor.getInstance().limitNode(DomUtil.tagName(node), this.parseList(children));
  143. }
  144. root_(node, children) {
  145. if (!children[1]) {
  146. return this.sqrt_(node, children);
  147. }
  148. return this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.ROOT, [this.parse(children[1]), this.parse(children[0])], []);
  149. }
  150. sqrt_(_node, children) {
  151. const semNodes = this.parseList(SemanticUtil.purgeNodes(children));
  152. return this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.SQRT, [semantic_processor_js_1.SemanticProcessor.getInstance().row(semNodes)], []);
  153. }
  154. table_(node, children) {
  155. const semantics = node.getAttribute('semantics');
  156. if (semantics && semantics.match('bspr_')) {
  157. return semantic_processor_js_1.SemanticProcessor.proof(node, semantics, this.parseList.bind(this));
  158. }
  159. const newNode = this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.TABLE, this.parseList(children), []);
  160. newNode.mathmlTree = node;
  161. return semantic_processor_js_1.SemanticProcessor.tableToMultiline(newNode);
  162. }
  163. tableRow_(_node, children) {
  164. const newNode = this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.ROW, this.parseList(children), []);
  165. newNode.role = semantic_meaning_js_1.SemanticRole.TABLE;
  166. return newNode;
  167. }
  168. tableLabeledRow_(node, children) {
  169. var _a;
  170. if (!children.length) {
  171. return this.tableRow_(node, children);
  172. }
  173. const label = this.parse(children[0]);
  174. label.role = semantic_meaning_js_1.SemanticRole.LABEL;
  175. if (((_a = label.childNodes[0]) === null || _a === void 0 ? void 0 : _a.type) === semantic_meaning_js_1.SemanticType.TEXT) {
  176. label.childNodes[0].role = semantic_meaning_js_1.SemanticRole.LABEL;
  177. }
  178. const newNode = this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.ROW, this.parseList(children.slice(1)), [label]);
  179. newNode.role = semantic_meaning_js_1.SemanticRole.TABLE;
  180. return newNode;
  181. }
  182. tableCell_(_node, children) {
  183. const semNodes = this.parseList(SemanticUtil.purgeNodes(children));
  184. let childNodes;
  185. if (!semNodes.length) {
  186. childNodes = [];
  187. }
  188. else if (semNodes.length === 1 &&
  189. SemanticPred.isType(semNodes[0], semantic_meaning_js_1.SemanticType.EMPTY)) {
  190. childNodes = semNodes;
  191. }
  192. else {
  193. childNodes = [semantic_processor_js_1.SemanticProcessor.getInstance().row(semNodes)];
  194. }
  195. const newNode = this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.CELL, childNodes, []);
  196. newNode.role = semantic_meaning_js_1.SemanticRole.TABLE;
  197. return newNode;
  198. }
  199. space_(node, children) {
  200. const width = node.getAttribute('width');
  201. const match = width && width.match(/[a-z]*$/);
  202. if (!match) {
  203. return this.empty_(node, children);
  204. }
  205. const sizes = {
  206. cm: 0.4,
  207. pc: 0.5,
  208. em: 0.5,
  209. ex: 1,
  210. in: 0.15,
  211. pt: 5,
  212. mm: 5
  213. };
  214. const unit = match[0];
  215. const measure = parseFloat(width.slice(0, match.index));
  216. const size = sizes[unit];
  217. if (!size || isNaN(measure) || measure < size) {
  218. return this.empty_(node, children);
  219. }
  220. const newNode = this.getFactory().makeUnprocessed(node);
  221. return semantic_processor_js_1.SemanticProcessor.getInstance().text(newNode, DomUtil.tagName(node));
  222. }
  223. text_(node, children) {
  224. const newNode = this.leaf_(node, children);
  225. if (!node.textContent) {
  226. return newNode;
  227. }
  228. newNode.updateContent(node.textContent, true);
  229. return semantic_processor_js_1.SemanticProcessor.getInstance().text(newNode, DomUtil.tagName(node));
  230. }
  231. identifier_(node, children) {
  232. const newNode = this.leaf_(node, children);
  233. return semantic_processor_js_1.SemanticProcessor.getInstance().identifierNode(newNode, semantic_processor_js_1.SemanticProcessor.getInstance().font(node.getAttribute('mathvariant')), node.getAttribute('class'));
  234. }
  235. number_(node, children) {
  236. const newNode = this.leaf_(node, children);
  237. semantic_processor_js_1.SemanticProcessor.number(newNode);
  238. return newNode;
  239. }
  240. operator_(node, children) {
  241. const newNode = this.leaf_(node, children);
  242. semantic_processor_js_1.SemanticProcessor.getInstance().operatorNode(newNode);
  243. return newNode;
  244. }
  245. fenced_(node, children) {
  246. const semNodes = this.parseList(SemanticUtil.purgeNodes(children));
  247. const sepValue = SemanticMathml.getAttribute_(node, 'separators', ',');
  248. const open = SemanticMathml.getAttribute_(node, 'open', '(');
  249. const close = SemanticMathml.getAttribute_(node, 'close', ')');
  250. const newNode = semantic_processor_js_1.SemanticProcessor.getInstance().mfenced(open, close, sepValue, semNodes);
  251. const nodes = semantic_processor_js_1.SemanticProcessor.getInstance().tablesInRow([newNode]);
  252. return nodes[0];
  253. }
  254. enclosed_(node, children) {
  255. const semNodes = this.parseList(SemanticUtil.purgeNodes(children));
  256. const newNode = this.getFactory().makeBranchNode(semantic_meaning_js_1.SemanticType.ENCLOSE, [semantic_processor_js_1.SemanticProcessor.getInstance().row(semNodes)], []);
  257. newNode.role =
  258. node.getAttribute('notation') || semantic_meaning_js_1.SemanticRole.UNKNOWN;
  259. return newNode;
  260. }
  261. multiscripts_(_node, children) {
  262. if (!children.length) {
  263. return this.getFactory().makeEmptyNode();
  264. }
  265. const base = this.parse(children.shift());
  266. if (!children.length) {
  267. return base;
  268. }
  269. const lsup = [];
  270. const lsub = [];
  271. const rsup = [];
  272. const rsub = [];
  273. let prescripts = false;
  274. let scriptcount = 0;
  275. for (let i = 0, child; (child = children[i]); i++) {
  276. if (DomUtil.tagName(child) === semantic_util_js_1.MMLTAGS.MPRESCRIPTS) {
  277. prescripts = true;
  278. scriptcount = 0;
  279. continue;
  280. }
  281. prescripts
  282. ? scriptcount & 1
  283. ? lsup.push(child)
  284. : lsub.push(child)
  285. : scriptcount & 1
  286. ? rsup.push(child)
  287. : rsub.push(child);
  288. scriptcount++;
  289. }
  290. if (!SemanticUtil.purgeNodes(lsup).length &&
  291. !SemanticUtil.purgeNodes(lsub).length) {
  292. return semantic_processor_js_1.SemanticProcessor.getInstance().pseudoTensor(base, this.parseList(rsub), this.parseList(rsup));
  293. }
  294. return semantic_processor_js_1.SemanticProcessor.getInstance().tensor(base, this.parseList(lsub), this.parseList(lsup), this.parseList(rsub), this.parseList(rsup));
  295. }
  296. empty_(_node, _children) {
  297. return this.getFactory().makeEmptyNode();
  298. }
  299. action_(node, children) {
  300. const selection = children[node.hasAttribute('selection')
  301. ? parseInt(node.getAttribute('selection'), 10) - 1
  302. : 0];
  303. const stree = this.parse(selection);
  304. stree.mathmlTree = selection;
  305. return stree;
  306. }
  307. dummy_(node, _children) {
  308. const unknown = this.getFactory().makeUnprocessed(node);
  309. unknown.role = node.tagName;
  310. unknown.textContent = node.textContent;
  311. return unknown;
  312. }
  313. leaf_(mml, children) {
  314. if (children.length === 1 &&
  315. children[0].nodeType !== DomUtil.NodeType.TEXT_NODE) {
  316. const node = this.getFactory().makeUnprocessed(mml);
  317. node.role = children[0].tagName;
  318. SemanticUtil.addAttributes(node, children[0]);
  319. return node;
  320. }
  321. const node = this.getFactory().makeLeafNode(mml.textContent, semantic_processor_js_1.SemanticProcessor.getInstance().font(mml.getAttribute('mathvariant')));
  322. if (mml.hasAttribute('data-latex')) {
  323. semantic_attr_js_1.SemanticMap.LatexCommands.set(mml.getAttribute('data-latex'), mml.textContent);
  324. }
  325. return node;
  326. }
  327. }
  328. exports.SemanticMathml = SemanticMathml;