Stack.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2009-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview The Stack for the TeX parser.
  19. *
  20. * @author v.sorge@mathjax.org (Volker Sorge)
  21. */
  22. import NodeUtil from './NodeUtil.js';
  23. import {MmlNode} from '../../core/MmlTree/MmlNode.js';
  24. import {StackItem, EnvList} from './StackItem.js';
  25. import StackItemFactory from './StackItemFactory.js';
  26. export default class Stack {
  27. /**
  28. * @type {EnvList}
  29. */
  30. public global: EnvList = {};
  31. /**
  32. * The actual stack, a list of stack items.
  33. * @type {Array.<StackItem>}
  34. */
  35. private stack: StackItem[] = [];
  36. /**
  37. * @constructor
  38. * @param {StackItemFactory} factory The stack item factory.
  39. * @param {EnvList} env The environment.
  40. * @param {boolean} inner True if parser has been called recursively.
  41. */
  42. constructor(private _factory: StackItemFactory,
  43. private _env: EnvList, inner: boolean) {
  44. this.global = {isInner: inner};
  45. this.stack = [ this._factory.create('start', this.global) ];
  46. if (_env) {
  47. this.stack[0].env = _env;
  48. }
  49. this.env = this.stack[0].env;
  50. }
  51. /**
  52. * Set the environment of the stack.
  53. * @param {EnvList} env The new environment.
  54. */
  55. public set env(env: EnvList) {
  56. this._env = env;
  57. }
  58. /**
  59. * Retrieves the environment of that stack.
  60. * @return {EnvList} The current environment.
  61. */
  62. public get env(): EnvList {
  63. return this._env;
  64. }
  65. /**
  66. * Pushes items or nodes onto stack.
  67. * @param {...StackItem|MmlNode} args A list of items to push.
  68. */
  69. public Push(...args: (StackItem | MmlNode)[]) {
  70. for (const node of args) {
  71. if (!node) {
  72. continue;
  73. }
  74. const item = NodeUtil.isNode(node) ?
  75. this._factory.create('mml', node) : node as StackItem;
  76. item.global = this.global;
  77. const [top, success] =
  78. this.stack.length ? this.Top().checkItem(item) : [null, true];
  79. if (!success) {
  80. continue;
  81. }
  82. if (top) {
  83. this.Pop();
  84. this.Push(...top);
  85. continue;
  86. }
  87. this.stack.push(item);
  88. if (item.env) {
  89. if (item.copyEnv) {
  90. Object.assign(item.env, this.env);
  91. }
  92. this.env = item.env;
  93. } else {
  94. item.env = this.env;
  95. }
  96. }
  97. }
  98. /**
  99. * Pop the topmost elements off the stack.
  100. * @return {StackItem} A stack item.
  101. */
  102. public Pop(): StackItem {
  103. const item = this.stack.pop();
  104. if (!item.isOpen) {
  105. delete item.env;
  106. }
  107. this.env = (this.stack.length ? this.Top().env : {});
  108. return item;
  109. }
  110. /**
  111. * Lookup the nth elements on the stack without removing them.
  112. * @param {number=} n Position of element that should be returned. Default 1.
  113. * @return {StackItem} Nth item on the stack.
  114. */
  115. public Top(n: number = 1): StackItem {
  116. return this.stack.length < n ? null : this.stack[this.stack.length - n];
  117. }
  118. /**
  119. * Lookup the topmost element on the stack, returning the Mml node in that
  120. * item. Optionally pops the Mml node from that stack item.
  121. * @param {boolean=} noPop Pop top item if true.
  122. * @return {MmlNode} The Mml node in the topmost stack item.
  123. */
  124. public Prev(noPop?: boolean): MmlNode | void {
  125. const top = this.Top();
  126. return noPop ? top.First : top.Pop();
  127. }
  128. /**
  129. * @override
  130. */
  131. public toString() {
  132. return 'stack[\n ' + this.stack.join('\n ') + '\n]';
  133. }
  134. }