semantic_pred.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import { NamedSymbol, SemanticMap } from './semantic_attr.js';
  2. import { SemanticRole, SemanticType, SemanticSecondary } from './semantic_meaning.js';
  3. import { getEmbellishedInner } from './semantic_util.js';
  4. export function isType(node, attr) {
  5. return node.type === attr;
  6. }
  7. function embellishedType(node, attr) {
  8. return node.embellished === attr;
  9. }
  10. export function isRole(node, attr) {
  11. return node.role === attr;
  12. }
  13. export function isAccent(node) {
  14. return (isType(node, SemanticType.FENCE) ||
  15. isType(node, SemanticType.PUNCTUATION) ||
  16. isType(node, SemanticType.OPERATOR) ||
  17. isType(node, SemanticType.RELATION));
  18. }
  19. export function isSimpleFunctionScope(node) {
  20. const children = node.childNodes;
  21. if (children.length === 0) {
  22. return true;
  23. }
  24. if (children.length > 1) {
  25. return false;
  26. }
  27. const child = children[0];
  28. if (child.type === SemanticType.INFIXOP) {
  29. if (child.role !== SemanticRole.IMPLICIT) {
  30. return false;
  31. }
  32. if (child.childNodes.some((x) => isType(x, SemanticType.INFIXOP))) {
  33. return false;
  34. }
  35. }
  36. return true;
  37. }
  38. export function isPrefixFunctionBoundary(node) {
  39. return ((isOperator(node) && !isRole(node, SemanticRole.DIVISION)) ||
  40. isType(node, SemanticType.APPL) ||
  41. isGeneralFunctionBoundary(node));
  42. }
  43. export function isBigOpBoundary(node) {
  44. return isOperator(node) || isGeneralFunctionBoundary(node);
  45. }
  46. export function isIntegralDxBoundary(firstNode, secondNode) {
  47. return (!!secondNode &&
  48. isType(secondNode, SemanticType.IDENTIFIER) &&
  49. SemanticMap.Secondary.has(firstNode.textContent, SemanticSecondary.D));
  50. }
  51. export function isIntegralDxBoundarySingle(node) {
  52. if (isType(node, SemanticType.IDENTIFIER)) {
  53. const firstChar = node.textContent[0];
  54. return (firstChar &&
  55. node.textContent[1] &&
  56. SemanticMap.Secondary.has(firstChar, SemanticSecondary.D));
  57. }
  58. return false;
  59. }
  60. export function isGeneralFunctionBoundary(node) {
  61. return isRelation(node) || isPunctuation(node);
  62. }
  63. export function isEmbellished(node) {
  64. if (node.embellished) {
  65. return node.embellished;
  66. }
  67. if (isEmbellishedType(node.type)) {
  68. return node.type;
  69. }
  70. return null;
  71. }
  72. function isEmbellishedType(type) {
  73. return (type === SemanticType.OPERATOR ||
  74. type === SemanticType.RELATION ||
  75. type === SemanticType.FENCE ||
  76. type === SemanticType.PUNCTUATION);
  77. }
  78. export function isOperator(node) {
  79. return (isType(node, SemanticType.OPERATOR) ||
  80. embellishedType(node, SemanticType.OPERATOR));
  81. }
  82. export function isRelation(node) {
  83. return (isType(node, SemanticType.RELATION) ||
  84. embellishedType(node, SemanticType.RELATION));
  85. }
  86. export function isPunctuation(node) {
  87. return (isType(node, SemanticType.PUNCTUATION) ||
  88. embellishedType(node, SemanticType.PUNCTUATION));
  89. }
  90. export function isFence(node) {
  91. return (isType(node, SemanticType.FENCE) ||
  92. embellishedType(node, SemanticType.FENCE));
  93. }
  94. export function isElligibleEmbellishedFence(node) {
  95. if (!node || !isFence(node)) {
  96. return false;
  97. }
  98. if (!node.embellished) {
  99. return true;
  100. }
  101. return recurseBaseNode(node);
  102. }
  103. function bothSide(node) {
  104. return (isType(node, SemanticType.TENSOR) &&
  105. (!isType(node.childNodes[1], SemanticType.EMPTY) ||
  106. !isType(node.childNodes[2], SemanticType.EMPTY)) &&
  107. (!isType(node.childNodes[3], SemanticType.EMPTY) ||
  108. !isType(node.childNodes[4], SemanticType.EMPTY)));
  109. }
  110. function recurseBaseNode(node) {
  111. if (!node.embellished) {
  112. return true;
  113. }
  114. if (bothSide(node)) {
  115. return false;
  116. }
  117. if (isRole(node, SemanticRole.CLOSE) && isType(node, SemanticType.TENSOR)) {
  118. return false;
  119. }
  120. if (isRole(node, SemanticRole.OPEN) &&
  121. (isType(node, SemanticType.SUBSCRIPT) ||
  122. isType(node, SemanticType.SUPERSCRIPT))) {
  123. return false;
  124. }
  125. return recurseBaseNode(node.childNodes[0]);
  126. }
  127. export function isTableOrMultiline(node) {
  128. return (!!node &&
  129. (isType(node, SemanticType.TABLE) || isType(node, SemanticType.MULTILINE)));
  130. }
  131. export function tableIsMatrixOrVector(node) {
  132. return (!!node && isFencedElement(node) && isTableOrMultiline(node.childNodes[0]));
  133. }
  134. export function isFencedElement(node) {
  135. return (!!node &&
  136. isType(node, SemanticType.FENCED) &&
  137. (isRole(node, SemanticRole.LEFTRIGHT) || isNeutralFence(node)) &&
  138. node.childNodes.length === 1);
  139. }
  140. export function tableIsCases(_table, prevNodes) {
  141. return (prevNodes.length > 0 &&
  142. isRole(prevNodes[prevNodes.length - 1], SemanticRole.OPENFENCE));
  143. }
  144. export function tableIsMultiline(table) {
  145. return table.childNodes.every(function (row) {
  146. const length = row.childNodes.length;
  147. return length <= 1;
  148. });
  149. }
  150. export function lineIsLabelled(line) {
  151. return (isType(line, SemanticType.LINE) &&
  152. line.contentNodes.length &&
  153. isRole(line.contentNodes[0], SemanticRole.LABEL));
  154. }
  155. export function isBinomial(table) {
  156. return table.childNodes.length === 2;
  157. }
  158. export function isLimitBase(node) {
  159. return (isType(node, SemanticType.LARGEOP) ||
  160. isType(node, SemanticType.LIMBOTH) ||
  161. isType(node, SemanticType.LIMLOWER) ||
  162. isType(node, SemanticType.LIMUPPER) ||
  163. (isType(node, SemanticType.FUNCTION) &&
  164. isRole(node, SemanticRole.LIMFUNC)) ||
  165. ((isType(node, SemanticType.OVERSCORE) ||
  166. isType(node, SemanticType.UNDERSCORE)) &&
  167. isLimitBase(node.childNodes[0])));
  168. }
  169. export function isSimpleFunctionHead(node) {
  170. return (node.type === SemanticType.IDENTIFIER ||
  171. node.role === SemanticRole.LATINLETTER ||
  172. node.role === SemanticRole.GREEKLETTER ||
  173. node.role === SemanticRole.OTHERLETTER);
  174. }
  175. export function singlePunctAtPosition(nodes, puncts, position) {
  176. return (puncts.length === 1 &&
  177. (nodes[position].type === SemanticType.PUNCTUATION ||
  178. nodes[position].embellished === SemanticType.PUNCTUATION) &&
  179. nodes[position] === puncts[0]);
  180. }
  181. export function isSimpleFunction(node) {
  182. return (isType(node, SemanticType.IDENTIFIER) &&
  183. isRole(node, SemanticRole.SIMPLEFUNC));
  184. }
  185. function isLeftBrace(node) {
  186. const leftBrace = ['{', '﹛', '{'];
  187. return !!node && leftBrace.indexOf(node.textContent) !== -1;
  188. }
  189. function isRightBrace(node) {
  190. const rightBrace = ['}', '﹜', '}'];
  191. return !!node && rightBrace.indexOf(node.textContent) !== -1;
  192. }
  193. export function isSetNode(node) {
  194. return (isLeftBrace(node.contentNodes[0]) && isRightBrace(node.contentNodes[1]));
  195. }
  196. const illegalSingleton = [
  197. SemanticType.PUNCTUATION,
  198. SemanticType.PUNCTUATED,
  199. SemanticType.RELSEQ,
  200. SemanticType.MULTIREL,
  201. SemanticType.TABLE,
  202. SemanticType.MULTILINE,
  203. SemanticType.CASES,
  204. SemanticType.INFERENCE
  205. ];
  206. const scriptedElement = [
  207. SemanticType.LIMUPPER,
  208. SemanticType.LIMLOWER,
  209. SemanticType.LIMBOTH,
  210. SemanticType.SUBSCRIPT,
  211. SemanticType.SUPERSCRIPT,
  212. SemanticType.UNDERSCORE,
  213. SemanticType.OVERSCORE,
  214. SemanticType.TENSOR
  215. ];
  216. export function isSingletonSetContent(node) {
  217. const type = node.type;
  218. if (illegalSingleton.indexOf(type) !== -1 ||
  219. (type === SemanticType.INFIXOP && node.role !== SemanticRole.IMPLICIT)) {
  220. return false;
  221. }
  222. if (type === SemanticType.FENCED) {
  223. return node.role === SemanticRole.LEFTRIGHT
  224. ? isSingletonSetContent(node.childNodes[0])
  225. : true;
  226. }
  227. if (scriptedElement.indexOf(type) !== -1) {
  228. return isSingletonSetContent(node.childNodes[0]);
  229. }
  230. return true;
  231. }
  232. function isNumber(node) {
  233. return (node.type === SemanticType.NUMBER &&
  234. (node.role === SemanticRole.INTEGER || node.role === SemanticRole.FLOAT));
  235. }
  236. export function isUnitCounter(node) {
  237. return (isNumber(node) ||
  238. node.role === SemanticRole.VULGAR ||
  239. node.role === SemanticRole.MIXED);
  240. }
  241. export function isPureUnit(node) {
  242. const children = node.childNodes;
  243. return (node.role === SemanticRole.UNIT &&
  244. (!children.length || children[0].role === SemanticRole.UNIT));
  245. }
  246. export function isUnitProduct(node) {
  247. const children = node.childNodes;
  248. return (node.type === SemanticType.INFIXOP &&
  249. (node.role === SemanticRole.MULTIPLICATION ||
  250. node.role === SemanticRole.IMPLICIT) &&
  251. children.length &&
  252. (isPureUnit(children[0]) || isUnitCounter(children[0])) &&
  253. node.childNodes.slice(1).every(isPureUnit));
  254. }
  255. export function isImplicit(node) {
  256. return (node.type === SemanticType.INFIXOP &&
  257. (node.role === SemanticRole.IMPLICIT ||
  258. (node.role === SemanticRole.UNIT &&
  259. !!node.contentNodes.length &&
  260. node.contentNodes[0].textContent === NamedSymbol.invisibleTimes)));
  261. }
  262. export function isImplicitOp(node) {
  263. return (node.type === SemanticType.INFIXOP && node.role === SemanticRole.IMPLICIT);
  264. }
  265. export function isNeutralFence(fence) {
  266. return (fence.role === SemanticRole.NEUTRAL || fence.role === SemanticRole.METRIC);
  267. }
  268. export function compareNeutralFences(fence1, fence2) {
  269. return (isNeutralFence(fence1) &&
  270. isNeutralFence(fence2) &&
  271. getEmbellishedInner(fence1).textContent ===
  272. getEmbellishedInner(fence2).textContent);
  273. }
  274. export function elligibleLeftNeutral(fence) {
  275. if (!isNeutralFence(fence)) {
  276. return false;
  277. }
  278. if (!fence.embellished) {
  279. return true;
  280. }
  281. if (fence.type === SemanticType.SUPERSCRIPT ||
  282. fence.type === SemanticType.SUBSCRIPT) {
  283. return false;
  284. }
  285. if (fence.type === SemanticType.TENSOR &&
  286. (fence.childNodes[3].type !== SemanticType.EMPTY ||
  287. fence.childNodes[4].type !== SemanticType.EMPTY)) {
  288. return false;
  289. }
  290. return true;
  291. }
  292. export function elligibleRightNeutral(fence) {
  293. if (!isNeutralFence(fence)) {
  294. return false;
  295. }
  296. if (!fence.embellished) {
  297. return true;
  298. }
  299. if (fence.type === SemanticType.TENSOR &&
  300. (fence.childNodes[1].type !== SemanticType.EMPTY ||
  301. fence.childNodes[2].type !== SemanticType.EMPTY)) {
  302. return false;
  303. }
  304. return true;
  305. }
  306. export function isMembership(element) {
  307. return [
  308. SemanticRole.ELEMENT,
  309. SemanticRole.NONELEMENT,
  310. SemanticRole.REELEMENT,
  311. SemanticRole.RENONELEMENT
  312. ].includes(element.role);
  313. }