text: import { Parser, NodeSet, NodeType, DefaultBufferLength, NodeProp, Tree } from '../../common/dist/index.js';
  
  /// A parse stack. These are used internally by the parser to track
  /// parsing progress. They also provide some properties and methods
  /// that external code such as a tokenizer can use to get information
  /// about the parse state.
  class Stack {
      /// @internal
      constructor(
      /// The parse that this stack is part of @internal
      p, 
      /// Holds state, input pos, buffer index triplets for all but the
      /// top state @internal
      stack, 
      /// The current parse state @internal
      state, 
      // The position at which the next reduce should take place. This
      // can be less than `this.pos` when skipped expressions have been
      // added to the stack (which should be moved outside of the next
      // reduction)
      /// @internal
      reducePos, 
      /// The input position up to which this stack has parsed.
      pos, 
      /// The dynamic score of the stack, including dynamic precedence
      /// and error-recovery penalties
      /// @internal
      score, 
      // The output buffer. Holds (type, start, end, size) quads
      // representing nodes created by the parser, where `size` is
      // amount of buffer array entries covered by this node.
      /// @internal
      buffer, 
      // The base offset of the buffer. When stacks are split, the split
      // instance shared the buffer history with its parent up to
      // `bufferBase`, which is the absolute offset (including the
      // offset of previous splits) into the buffer at which this stack
      // starts writing.
      /// @internal
      bufferBase, 
      /// @internal
      curContext, 
      /// @internal
      lookAhead = 0, 
      // A parent stack from which this was split off, if any. This is
      // set up so that it always points to a stack that has some
      // additional buffer content, never to a stack with an equal
      // `bufferBase`.
      /// @internal
      parent) {
          this.p = p;
          this.stack = stack;
          this.state = state;
          this.reducePos = reducePos;
          this.pos = pos;
          this.score = score;
          this.buffer = buffer;
          this.bufferBase = bufferBase;
          this.curContext = curContext;
          this.lookAhead = lookAhead;
          this.parent = parent;
      }
      /// @internal
      toString() {
          return `[${this.stack.filter((_, i) => i % 3 == 0).concat(this.state)}]@${this.pos}${this.score ? "!" + this.score : ""}`;
      }
      // Start an empty stack
      /// @internal
      static start(p, state, pos = 0) {
          let cx = p.parser.context;
          return new Stack(p, [], state, pos, pos, 0, [], 0, cx ? new StackContext(cx, cx.start) : null, 0, null);
      }
      /// The stack's current [context](#lr.ContextTracker) value, if
      /// any. Its type will depend on the context tracker's type
      /// parameter, or it will be `null` if there is no context
      /// tracker.
      get context() { return this.curContext ? this.curContext.context : null; }
      // Push a state onto the stack, tracking its start position as well
      // as the buffer base at that point.
      /// @internal
      pushState(state, start) {
          this.stack.push(this.state, start, this.bufferBase + this.buffer.length);
          this.state = state;
      }
      // Apply a reduce action
      /// @internal
      reduce(action) {
          let depth = action >> 19 /* ReduceDepthShift */, type = action & 65535 /* ValueMask */;
          let { parser } = this.p;
          let dPrec = parser.dynamicPrecedence(type);
          if (dPrec)
              this.score += dPrec;
          if (depth == 0) {
              // Zero-depth reductions are a special case—they add stuff to
              // the stack without popping anything off.
              if (type < parser.minRepeatTerm)
                  this.storeNode(type, this.reducePos, this.reducePos, 4, true);
              this.pushState(parser.getGoto(this.state, type, true), this.reducePos);
              this.reduceContext(type, this.reducePos);
              return;
          }
          // Find the base index into `this.stack`, content after which will
          // be dropped. Note that with `StayFlag` reductions we need to
          // consume two extra frames (the dummy parent node for the skipped
          // expression and the state that we'll be staying in, which should
          // be moved to `this.state`).
          let base = this.stack.length - ((depth - 1) * 3) - (action & 262144 /* StayFlag */ ? 6 : 0);
          let start = this.stack[base - 2];
          let bufferBase = this.stack[base - 1], count = this.bufferBase + this.buffer.length - bufferBase;
          // Store normal terms or `R -> R R` repeat reductions
          if (type < parser.minRepeatTerm || (action & 131072 /* RepeatFlag */)) {
              let pos = parser.stateFlag(this.state, 1 /* Skipped */) ? this.pos : this.reducePos;
              this.storeNode(type, start, pos, count + 4, true);
          }
          if (action & 262144 /* StayFlag */) {
              this.state = this.stack[base];
          }
          else {
              let baseStateID = this.stack[base - 3];
              this.state = parser.getGoto(baseStateID, type, true);
          }
          while (this.stack.length > base)
              this.stack.pop();
          this.reduceContext(type, start);
      }
      // Shift a value into the buffer
      /// @internal
      storeNode(term, start, end, size = 4, isReduce = false) {
          if (term == 0 /* Err */) { // Try to omit/merge adjacent error nodes
              let cur = this, top = this.buffer.length;
              if (top == 0 && cur.parent) {
                  top = cur.bufferBase - cur.parent.bufferBase;
                  cur = cur.parent;
              }
              if (top > 0 && cur.buffer[top - 4] == 0 /* Err */ && cur.buffer[top - 1] > -1) {
                  if (start == end)
                      return;
                  if (cur.buffer[top - 2] >= start) {
                      cur.buffer[top - 2] = end;
                      return;
                  }
              }
          }
          if (!isReduce || this.pos == end) { // Simple case, just append
              this.buffer.push(term, start, end, size);
          }
          else { // There may be skipped nodes that have to be moved forward
              let index = this.buffer.length;
              if (index > 0 && this.buffer[index - 4] != 0 /* Err */)
                  while (index > 0 && this.buffer[index - 2] > end) {
                      // Move this record forward
                      this.buffer[index] = this.buffer[index - 4];
                      this.buffer[index + 1] = this.buffer[index - 3];
                      this.buffer[index + 2] = this.buffer[index - 2];
                      this.buffer[index + 3] = this.buffer[index - 1];
                      index -= 4;
                      if (size > 4)
                          size -= 4;
                  }
              this.buffer[index] = term;
              this.buffer[index + 1] = start;
              this.buffer[index + 2] = end;
              this.buffer[index + 3] = size;
          }
      }
      // Apply a shift action
      /// @internal
      shift(action, next, nextEnd) {
          let start = this.pos;
          if (action & 131072 /* GotoFlag */) {
              this.pushState(action & 65535 /* ValueMask */, this.pos);
          }
          else if ((action & 262144 /* StayFlag */) == 0) { // Regular shift
              let nextState = action, { parser } = this.p;
              if (nextEnd > this.pos || next <= parser.maxNode) {
                  this.pos = nextEnd;
                  if (!parser.stateFlag(nextState, 1 /* Skipped */))
                      this.reducePos = nextEnd;
              }
              this.pushState(nextState, start);
              this.shiftContext(next, start);
              if (next <= parser.maxNode)
                  this.buffer.push(next, start, nextEnd, 4);
          }
          else { // Shift-and-stay, which means this is a skipped token
              this.pos = nextEnd;
              this.shiftContext(next, start);
              if (next <= this.p.parser.maxNode)
                  this.buffer.push(next, start, nextEnd, 4);
          }
      }
      // Apply an action
      /// @internal
      apply(action, next, nextEnd) {
          if (action & 65536 /* ReduceFlag */)
              this.reduce(action);
          else
              this.shift(action, next, nextEnd);
      }
      // Add a prebuilt (reused) node into the buffer. @internal
      useNode(value, next) {
          let index = this.p.reused.length - 1;
          if (index < 0 || this.p.reused[index] != value) {
              this.p.reused.push(value);
              index++;
          }
          let start = this.pos;
          this.reducePos = this.pos = start + value.length;
          this.pushState(next, start);
          this.buffer.push(index, start, this.reducePos, -1 /* size == -1 means this is a reused value */);
          if (this.curContext)
              this.updateContext(this.curContext.tracker.reuse(this.curContext.context, value, this, this.p.stream.reset(this.pos - value.length)));
      }
      // Split the stack. Due to the buffer sharing and the fact
      // that `this.stack` tends to stay quite shallow, this isn't very
      // expensive.
      /// @internal
      split() {
          let parent = this;
          let off = parent.buffer.length;
          // Because the top of the buffer (after this.pos) may be mutated
          // to reorder reductions and skipped tokens, and shared buffers
          // should be immutable, this copies any outstanding skipped tokens
          // to the new buffer, and puts the base pointer before them.
          while (off > 0 && parent.buffer[off - 2] > parent.reducePos)
              off -= 4;
          let buffer = parent.buffer.slice(off), base = parent.bufferBase + off;
          // Make sure parent points to an actual parent with content, if there is such a parent.
          while (parent && base == parent.bufferBase)
              parent = parent.parent;
          return new Stack(this.p, this.stack.slice(), this.state, this.reducePos, this.pos, this.score, buffer, base, this.curContext, this.lookAhead, parent);
      }
      // Try to recover from an error by 'deleting' (ignoring) one token.
      /// @internal
      recoverByDelete(next, nextEnd) {
          let isNode = next <= this.p.parser.maxNode;
          if (isNode)
              this.storeNode(next, this.pos, nextEnd, 4);
          this.storeNode(0 /* Err */, this.pos, nextEnd, isNode ? 8 : 4);
          this.pos = this.reducePos = nextEnd;
          this.score -= 190 /* Delete */;
      }
      /// Check if the given term would be able to be shifted (optionally
      /// after some reductions) on this stack. This can be useful for
      /// external tokenizers that want to make sure they only provide a
      /// given token when it applies.
      canShift(term) {
          for (let sim = new SimulatedStack(this);;) {
              let action = this.p.parser.stateSlot(sim.state, 4 /* DefaultReduce */) || this.p.parser.hasAction(sim.state, term);
              if ((action & 65536 /* ReduceFlag */) == 0)
                  return true;
              if (action == 0)
                  return false;
              sim.reduce(action);
          }
      }
      // Apply up to Recover.MaxNext recovery actions that conceptually
      // inserts some missing token or rule.
      /// @internal
      recoverByInsert(next) {
          if (this.stack.length >= 300 /* MaxInsertStackDepth */)
              return [];
          let nextStates = this.p.parser.nextStates(this.state);
          if (nextStates.length > 4 /* MaxNext */ << 1 || this.stack.length >= 120 /* DampenInsertStackDepth */) {
              let best = [];
              for (let i = 0, s; i < nextStates.length; i += 2) {
                  if ((s = nextStates[i + 1]) != this.state && this.p.parser.hasAction(s, next))
                      best.push(nextStates[i], s);
              }
              if (this.stack.length < 120 /* DampenInsertStackDepth */)
                  for (let i = 0; best.length < 4 /* MaxNext */ << 1 && i < nextStates.length; i += 2) {
                      let s = nextStates[i + 1];
                      if (!best.some((v, i) => (i & 1) && v == s))
                          best.push(nextStates[i], s);
                  }
              nextStates = best;
          }
          let result = [];
          for (let i = 0; i < nextStates.length && result.length < 4 /* MaxNext */; i += 2) {
              let s = nextStates[i + 1];
              if (s == this.state)
                  continue;
              let stack = this.split();
              stack.storeNode(0 /* Err */, stack.pos, stack.pos, 4, true);
              stack.pushState(s, this.pos);
              stack.shiftContext(nextStates[i], this.pos);
              stack.score -= 200 /* Insert */;
              result.push(stack);
          }
          return result;
      }
      // Force a reduce, if possible. Return false if that can't
      // be done.
      /// @internal
      forceReduce() {
          let reduce = this.p.parser.stateSlot(this.state, 5 /* ForcedReduce */);
          if ((reduce & 65536 /* ReduceFlag */) == 0)
              return false;
          let { parser } = this.p;
          if (!parser.validAction(this.state, reduce)) {
              let depth = reduce >> 19 /* ReduceDepthShift */, term = reduce & 65535 /* ValueMask */;
              let target = this.stack.length - depth * 3;
              if (target < 0 || parser.getGoto(this.stack[target], term, false) < 0)
                  return false;
              this.storeNode(0 /* Err */, this.reducePos, this.reducePos, 4, true);
              this.score -= 100 /* Reduce */;
          }
          this.reduce(reduce);
          return true;
      }
      /// @internal
      forceAll() {
          while (!this.p.parser.stateFlag(this.state, 2 /* Accepting */) && this.forceReduce()) { }
          return this;
      }
      /// Check whether this state has no further actions (assumed to be a direct descendant of the
      /// top state, since any other states must be able to continue
      /// somehow). @internal
      get deadEnd() {
          if (this.stack.length != 3)
              return false;
          let { parser } = this.p;
          return parser.data[parser.stateSlot(this.state, 1 /* Actions */)] == 65535 /* End */ &&
              !parser.stateSlot(this.state, 4 /* DefaultReduce */);
      }
      /// Restart the stack (put it back in its start state). Only safe
      /// when this.stack.length == 3 (state is directly below the top
      /// state). @internal
      restart() {
          this.state = this.stack[0];
          this.stack.length = 0;
      }
      /// @internal
      sameState(other) {
          if (this.state != other.state || this.stack.length != other.stack.length)
              return false;
          for (let i = 0; i < this.stack.length; i += 3)
              if (this.stack[i] != other.stack[i])
                  return false;
          return true;
      }
      /// Get the parser used by this stack.
      get parser() { return this.p.parser; }
      /// Test whether a given dialect (by numeric ID, as exported from
      /// the terms file) is enabled.
      dialectEnabled(dialectID) { return this.p.parser.dialect.flags[dialectID]; }
      shiftContext(term, start) {
          if (this.curContext)
              this.updateContext(this.curContext.tracker.shift(this.curContext.context, term, this, this.p.stream.reset(start)));
      }
      reduceContext(term, start) {
          if (this.curContext)
              this.updateContext(this.curContext.tracker.reduce(this.curContext.context, term, this, this.p.stream.reset(start)));
      }
      /// @internal
      emitContext() {
          let last = this.buffer.length - 1;
          if (last < 0 || this.buffer[last] != -3)
              this.buffer.push(this.curContext.hash, this.reducePos, this.reducePos, -3);
      }
      /// @internal
      emitLookAhead() {
          let last = this.buffer.length - 1;
          if (last < 0 || this.buffer[last] != -4)
              this.buffer.push(this.lookAhead, this.reducePos, this.reducePos, -4);
      }
      updateContext(context) {
          if (context != this.curContext.context) {
              let newCx = new StackContext(this.curContext.tracker, context);
              if (newCx.hash != this.curContext.hash)
                  this.emitContext();
              this.curContext = newCx;
          }
      }
      /// @internal
      setLookAhead(lookAhead) {
          if (lookAhead > this.lookAhead) {
              this.emitLookAhead();
              this.lookAhead = lookAhead;
          }
      }
      /// @internal
      close() {
          if (this.curContext && this.curContext.tracker.strict)
              this.emitContext();
          if (this.lookAhead > 0)
              this.emitLookAhead();
      }
  }
  class StackContext {
      constructor(tracker, context) {
          this.tracker = tracker;
          this.context = context;
          this.hash = tracker.strict ? tracker.hash(context) : 0;
      }
  }
  var Recover;
  (function (Recover) {
      Recover[Recover["Insert"] = 200] = "Insert";
      Recover[Recover["Delete"] = 190] = "Delete";
      Recover[Recover["Reduce"] = 100] = "Reduce";
      Recover[Recover["MaxNext"] = 4] = "MaxNext";
      Recover[Recover["MaxInsertStackDepth"] = 300] = "MaxInsertStackDepth";
      Recover[Recover["DampenInsertStackDepth"] = 120] = "DampenInsertStackDepth";
  })(Recover || (Recover = {}));
  // Used to cheaply run some reductions to scan ahead without mutating
  // an entire stack
  class SimulatedStack {
      constructor(start) {
          this.start = start;
          this.state = start.state;
          this.stack = start.stack;
          this.base = this.stack.length;
      }
      reduce(action) {
          let term = action & 65535 /* ValueMask */, depth = action >> 19 /* ReduceDepthShift */;
          if (depth == 0) {
              if (this.stack == this.start.stack)
                  this.stack = this.stack.slice();
              this.stack.push(this.state, 0, 0);
              this.base += 3;
          }
          else {
              this.base -= (depth - 1) * 3;
          }
          let goto = this.start.p.parser.getGoto(this.stack[this.base - 3], term, true);
          this.state = goto;
      }
  }
  // This is given to `Tree.build` to build a buffer, and encapsulates
  // the parent-stack-walking necessary to read the nodes.
  class StackBufferCursor {
      constructor(stack, pos, index) {
          this.stack = stack;
          this.pos = pos;
          this.index = index;
          this.buffer = stack.buffer;
          if (this.index == 0)
              this.maybeNext();
      }
      static create(stack, pos = stack.bufferBase + stack.buffer.length) {
          return new StackBufferCursor(stack, pos, pos - stack.bufferBase);
      }
      maybeNext() {
          let next = this.stack.parent;
          if (next != null) {
              this.index = this.stack.bufferBase - next.bufferBase;
              this.stack = next;
              this.buffer = next.buffer;
          }
      }
      get id() { return this.buffer[this.index - 4]; }
      get start() { return this.buffer[this.index - 3]; }
      get end() { return this.buffer[this.index - 2]; }
      get size() { return this.buffer[this.index - 1]; }
      next() {
          this.index -= 4;
          this.pos -= 4;
          if (this.index == 0)
              this.maybeNext();
      }
      fork() {
          return new StackBufferCursor(this.stack, this.pos, this.index);
      }
  }
  
  class CachedToken {
      constructor() {
          this.start = -1;
          this.value = -1;
          this.end = -1;
          this.extended = -1;
          this.lookAhead = 0;
          this.mask = 0;
          this.context = 0;
      }
  }
  const nullToken = new CachedToken;
  /// [Tokenizers](#lr.ExternalTokenizer) interact with the input
  /// through this interface. It presents the input as a stream of
  /// characters, tracking lookahead and hiding the complexity of
  /// [ranges](#common.Parser.parse^ranges) from tokenizer code.
  class InputStream {
      /// @internal
      constructor(
      /// @internal
      input, 
      /// @internal
      ranges) {
          this.input = input;
          this.ranges = ranges;
          /// @internal
          this.chunk = "";
          /// @internal
          this.chunkOff = 0;
          /// Backup chunk
          this.chunk2 = "";
          this.chunk2Pos = 0;
          /// The character code of the next code unit in the input, or -1
          /// when the stream is at the end of the input.
          this.next = -1;
          /// @internal
          this.token = nullToken;
          this.rangeIndex = 0;
          this.pos = this.chunkPos = ranges[0].from;
          this.range = ranges[0];
          this.end = ranges[ranges.length - 1].to;
          this.readNext();
      }
      resolveOffset(offset, assoc) {
          let range = this.range, index = this.rangeIndex;
          let pos = this.pos + offset;
          while (pos < range.from) {
              if (!index)
                  return null;
              let next = this.ranges[--index];
              pos -= range.from - next.to;
              range = next;
          }
          while (assoc < 0 ? pos > range.to : pos >= range.to) {
              if (index == this.ranges.length - 1)
                  return null;
              let next = this.ranges[++index];
              pos += next.from - range.to;
              range = next;
          }
          return pos;
      }
      /// Look at a code unit near the stream position. `.peek(0)` equals
      /// `.next`, `.peek(-1)` gives you the previous character, and so
      /// on.
      ///
      /// Note that looking around during tokenizing creates dependencies
      /// on potentially far-away content, which may reduce the
      /// effectiveness incremental parsing—when looking forward—or even
      /// cause invalid reparses when looking backward more than 25 code
      /// units, since the library does not track lookbehind.
      peek(offset) {
          let idx = this.chunkOff + offset, pos, result;
          if (idx >= 0 && idx < this.chunk.length) {
              pos = this.pos + offset;
              result = this.chunk.charCodeAt(idx);
          }
          else {
              let resolved = this.resolveOffset(offset, 1);
              if (resolved == null)
                  return -1;
              pos = resolved;
              if (pos >= this.chunk2Pos && pos < this.chunk2Pos + this.chunk2.length) {
                  result = this.chunk2.charCodeAt(pos - this.chunk2Pos);
              }
              else {
                  let i = this.rangeIndex, range = this.range;
                  while (range.to <= pos)
                      range = this.ranges[++i];
                  this.chunk2 = this.input.chunk(this.chunk2Pos = pos);
                  if (pos + this.chunk2.length > range.to)
                      this.chunk2 = this.chunk2.slice(0, range.to - pos);
                  result = this.chunk2.charCodeAt(0);
              }
          }
          if (pos > this.token.lookAhead)
              this.token.lookAhead = pos;
          return result;
      }
      /// Accept a token. By default, the end of the token is set to the
      /// current stream position, but you can pass an offset (relative to
      /// the stream position) to change that.
      acceptToken(token, endOffset = 0) {
          let end = endOffset ? this.resolveOffset(endOffset, -1) : this.pos;
          if (end == null || end < this.token.start)
              throw new RangeError("Token end out of bounds");
          this.token.value = token;
          this.token.end = end;
      }
      getChunk() {
          if (this.pos >= this.chunk2Pos && this.pos < this.chunk2Pos + this.chunk2.length) {
              let { chunk, chunkPos } = this;
              this.chunk = this.chunk2;
              this.chunkPos = this.chunk2Pos;
              this.chunk2 = chunk;
              this.chunk2Pos = chunkPos;
              this.chunkOff = this.pos - this.chunkPos;
          }
          else {
              this.chunk2 = this.chunk;
              this.chunk2Pos = this.chunkPos;
              let nextChunk = this.input.chunk(this.pos);
              let end = this.pos + nextChunk.length;
              this.chunk = end > this.range.to ? nextChunk.slice(0, this.range.to - this.pos) : nextChunk;
              this.chunkPos = this.pos;
              this.chunkOff = 0;
          }
      }
      readNext() {
          if (this.chunkOff >= this.chunk.length) {
              this.getChunk();
              if (this.chunkOff == this.chunk.length)
                  return this.next = -1;
          }
          return this.next = this.chunk.charCodeAt(this.chunkOff);
      }
      /// Move the stream forward N (defaults to 1) code units. Returns
      /// the new value of [`next`](#lr.InputStream.next).
      advance(n = 1) {
          this.chunkOff += n;
          while (this.pos + n >= this.range.to) {
              if (this.rangeIndex == this.ranges.length - 1)
                  return this.setDone();
              n -= this.range.to - this.pos;
              this.range = this.ranges[++this.rangeIndex];
              this.pos = this.range.from;
          }
          this.pos += n;
          if (this.pos > this.token.lookAhead)
              this.token.lookAhead = this.pos;
          return this.readNext();
      }
      setDone() {
          this.pos = this.chunkPos = this.end;
          this.range = this.ranges[this.rangeIndex = this.ranges.length - 1];
          this.chunk = "";
          return this.next = -1;
      }
      /// @internal
      reset(pos, token) {
          if (token) {
              this.token = token;
              token.start = token.lookAhead = pos;
              token.value = token.extended = -1;
          }
          else {
              this.token = nullToken;
          }
          if (this.pos != pos) {
              this.pos = pos;
              if (pos == this.end) {
                  this.setDone();
                  return this;
              }
              while (pos < this.range.from)
                  this.range = this.ranges[--this.rangeIndex];
              while (pos >= this.range.to)
                  this.range = this.ranges[++this.rangeIndex];
              if (pos >= this.chunkPos && pos < this.chunkPos + this.chunk.length) {
                  this.chunkOff = pos - this.chunkPos;
              }
              else {
                  this.chunk = "";
                  this.chunkOff = 0;
              }
              this.readNext();
          }
          return this;
      }
      /// @internal
      read(from, to) {
          if (from >= this.chunkPos && to <= this.chunkPos + this.chunk.length)
              return this.chunk.slice(from - this.chunkPos, to - this.chunkPos);
          if (from >= this.range.from && to <= this.range.to)
              return this.input.read(from, to);
          let result = "";
          for (let r of this.ranges) {
              if (r.from >= to)
                  break;
              if (r.to > from)
                  result += this.input.read(Math.max(r.from, from), Math.min(r.to, to));
          }
          return result;
      }
  }
  /// @internal
  class TokenGroup {
      constructor(data, id) {
          this.data = data;
          this.id = id;
      }
      token(input, stack) { readToken(this.data, input, stack, this.id); }
  }
  TokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false;
  /// `@external tokens` declarations in the grammar should resolve to
  /// an instance of this class.
  class ExternalTokenizer {
      /// Create a tokenizer. The first argument is the function that,
      /// given an input stream, scans for the types of tokens it
      /// recognizes at the stream's position, and calls
      /// [`acceptToken`](#lr.InputStream.acceptToken) when it finds
      /// one.
      constructor(
      /// @internal
      token, options = {}) {
          this.token = token;
          this.contextual = !!options.contextual;
          this.fallback = !!options.fallback;
          this.extend = !!options.extend;
      }
  }
  // Tokenizer data is stored a big uint16 array containing, for each
  // state:
  //
  //  - A group bitmask, indicating what token groups are reachable from
  //    this state, so that paths that can only lead to tokens not in
  //    any of the current groups can be cut off early.
  //
  //  - The position of the end of the state's sequence of accepting
  //    tokens
  //
  //  - The number of outgoing edges for the state
  //
  //  - The accepting tokens, as (token id, group mask) pairs
  //
  //  - The outgoing edges, as (start character, end character, state
  //    index) triples, with end character being exclusive
  //
  // This function interprets that data, running through a stream as
  // long as new states with the a matching group mask can be reached,
  // and updating `token` when it matches a token.
  function readToken(data, input, stack, group) {
      let state = 0, groupMask = 1 << group, { parser } = stack.p, { dialect } = parser;
      scan: for (;;) {
          if ((groupMask & data[state]) == 0)
              break;
          let accEnd = data[state + 1];
          // Check whether this state can lead to a token in the current group
          // Accept tokens in this state, possibly overwriting
          // lower-precedence / shorter tokens
          for (let i = state + 3; i < accEnd; i += 2)
              if ((data[i + 1] & groupMask) > 0) {
                  let term = data[i];
                  if (dialect.allows(term) &&
                      (input.token.value == -1 || input.token.value == term || parser.overrides(term, input.token.value))) {
                      input.acceptToken(term);
                      break;
                  }
              }
          // Do a binary search on the state's edges
          for (let next = input.next, low = 0, high = data[state + 2]; low < high;) {
              let mid = (low + high) >> 1;
              let index = accEnd + mid + (mid << 1);
              let from = data[index], to = data[index + 1];
              if (next < from)
                  high = mid;
              else if (next >= to)
                  low = mid + 1;
              else {
                  state = data[index + 2];
                  input.advance();
                  continue scan;
              }
          }
          break;
      }
  }
  
  // See lezer-generator/src/encode.ts for comments about the encoding
  // used here
  function decodeArray(input, Type = Uint16Array) {
      if (typeof input != "string")
          return input;
      let array = null;
      for (let pos = 0, out = 0; pos < input.length;) {
          let value = 0;
          for (;;) {
              let next = input.charCodeAt(pos++), stop = false;
              if (next == 126 /* BigValCode */) {
                  value = 65535 /* BigVal */;
                  break;
              }
              if (next >= 92 /* Gap2 */)
                  next--;
              if (next >= 34 /* Gap1 */)
                  next--;
              let digit = next - 32 /* Start */;
              if (digit >= 46 /* Base */) {
                  digit -= 46 /* Base */;
                  stop = true;
              }
              value += digit;
              if (stop)
                  break;
              value *= 46 /* Base */;
          }
          if (array)
              array[out++] = value;
          else
              array = new Type(value);
      }
      return array;
  }
  
  // FIXME find some way to reduce recovery work done when the input
  // doesn't match the grammar at all.
  // Environment variable used to control console output
  const verbose = typeof process != "undefined" && /\bparse\b/.test(process.env.LOG);
  let stackIDs = null;
  var Safety;
  (function (Safety) {
      Safety[Safety["Margin"] = 25] = "Margin";
  })(Safety || (Safety = {}));
  function cutAt(tree, pos, side) {
      let cursor = tree.fullCursor();
      cursor.moveTo(pos);
      for (;;) {
          if (!(side < 0 ? cursor.childBefore(pos) : cursor.childAfter(pos)))
              for (;;) {
                  if ((side < 0 ? cursor.to < pos : cursor.from > pos) && !cursor.type.isError)
                      return side < 0 ? Math.max(0, Math.min(cursor.to - 1, pos - 25 /* Margin */))
                          : Math.min(tree.length, Math.max(cursor.from + 1, pos + 25 /* Margin */));
                  if (side < 0 ? cursor.prevSibling() : cursor.nextSibling())
                      break;
                  if (!cursor.parent())
                      return side < 0 ? 0 : tree.length;
              }
      }
  }
  class FragmentCursor {
      constructor(fragments, nodeSet) {
          this.fragments = fragments;
          this.nodeSet = nodeSet;
          this.i = 0;
          this.fragment = null;
          this.safeFrom = -1;
          this.safeTo = -1;
          this.trees = [];
          this.start = [];
          this.index = [];
          this.nextFragment();
      }
      nextFragment() {
          let fr = this.fragment = this.i == this.fragments.length ? null : this.fragments[this.i++];
          if (fr) {
              this.safeFrom = fr.openStart ? cutAt(fr.tree, fr.from + fr.offset, 1) - fr.offset : fr.from;
              this.safeTo = fr.openEnd ? cutAt(fr.tree, fr.to + fr.offset, -1) - fr.offset : fr.to;
              while (this.trees.length) {
                  this.trees.pop();
                  this.start.pop();
                  this.index.pop();
              }
              this.trees.push(fr.tree);
              this.start.push(-fr.offset);
              this.index.push(0);
              this.nextStart = this.safeFrom;
          }
          else {
              this.nextStart = 1e9;
          }
      }
      // `pos` must be >= any previously given `pos` for this cursor
      nodeAt(pos) {
          if (pos < this.nextStart)
              return null;
          while (this.fragment && this.safeTo <= pos)
              this.nextFragment();
          if (!this.fragment)
              return null;
          for (;;) {
              let last = this.trees.length - 1;
              if (last < 0) { // End of tree
                  this.nextFragment();
                  return null;
              }
              let top = this.trees[last], index = this.index[last];
              if (index == top.children.length) {
                  this.trees.pop();
                  this.start.pop();
                  this.index.pop();
                  continue;
              }
              let next = top.children[index];
              let start = this.start[last] + top.positions[index];
              if (start > pos) {
                  this.nextStart = start;
                  return null;
              }
              if (next instanceof Tree) {
                  if (start == pos) {
                      if (start < this.safeFrom)
                          return null;
                      let end = start + next.length;
                      if (end <= this.safeTo) {
                          let lookAhead = next.prop(NodeProp.lookAhead);
                          if (!lookAhead || end + lookAhead < this.fragment.to)
                              return next;
                      }
                  }
                  this.index[last]++;
                  if (start + next.length >= Math.max(this.safeFrom, pos)) { // Enter this node
                      this.trees.push(next);
                      this.start.push(start);
                      this.index.push(0);
                  }
              }
              else {
                  this.index[last]++;
                  this.nextStart = start + next.length;
              }
          }
      }
  }
  class TokenCache {
      constructor(parser, stream) {
          this.stream = stream;
          this.tokens = [];
          this.mainToken = null;
          this.actions = [];
          this.tokens = parser.tokenizers.map(_ => new CachedToken);
      }
      getActions(stack) {
          let actionIndex = 0;
          let main = null;
          let { parser } = stack.p, { tokenizers } = parser;
          let mask = parser.stateSlot(stack.state, 3 /* TokenizerMask */);
          let context = stack.curContext ? stack.curContext.hash : 0;
          let lookAhead = 0;
          for (let i = 0; i < tokenizers.length; i++) {
              if (((1 << i) & mask) == 0)
                  continue;
              let tokenizer = tokenizers[i], token = this.tokens[i];
              if (main && !tokenizer.fallback)
                  continue;
              if (tokenizer.contextual || token.start != stack.pos || token.mask != mask || token.context != context) {
                  this.updateCachedToken(token, tokenizer, stack);
                  token.mask = mask;
                  token.context = context;
              }
              if (token.lookAhead > token.end + 25 /* Margin */)
                  lookAhead = Math.max(token.lookAhead, lookAhead);
              if (token.value != 0 /* Err */) {
                  let startIndex = actionIndex;
                  if (token.extended > -1)
                      actionIndex = this.addActions(stack, token.extended, token.end, actionIndex);
                  actionIndex = this.addActions(stack, token.value, token.end, actionIndex);
                  if (!tokenizer.extend) {
                      main = token;
                      if (actionIndex > startIndex)
                          break;
                  }
              }
          }
          while (this.actions.length > actionIndex)
              this.actions.pop();
          if (lookAhead)
              stack.setLookAhead(lookAhead);
          if (!main && stack.pos == this.stream.end) {
              main = new CachedToken;
              main.value = stack.p.parser.eofTerm;
              main.start = main.end = stack.pos;
              actionIndex = this.addActions(stack, main.value, main.end, actionIndex);
          }
          this.mainToken = main;
          return this.actions;
      }
      getMainToken(stack) {
          if (this.mainToken)
              return this.mainToken;
          let main = new CachedToken, { pos, p } = stack;
          main.start = pos;
          main.end = Math.min(pos + 1, p.stream.end);
          main.value = pos == p.stream.end ? p.parser.eofTerm : 0 /* Err */;
          return main;
      }
      updateCachedToken(token, tokenizer, stack) {
          tokenizer.token(this.stream.reset(stack.pos, token), stack);
          if (token.value > -1) {
              let { parser } = stack.p;
              for (let i = 0; i < parser.specialized.length; i++)
                  if (parser.specialized[i] == token.value) {
                      let result = parser.specializers[i](this.stream.read(token.start, token.end), stack);
                      if (result >= 0 && stack.p.parser.dialect.allows(result >> 1)) {
                          if ((result & 1) == 0 /* Specialize */)
                              token.value = result >> 1;
                          else
                              token.extended = result >> 1;
                          break;
                      }
                  }
          }
          else {
              token.value = 0 /* Err */;
              token.end = Math.min(stack.p.stream.end, stack.pos + 1);
          }
      }
      putAction(action, token, end, index) {
          // Don't add duplicate actions
          for (let i = 0; i < index; i += 3)
              if (this.actions[i] == action)
                  return index;
          this.actions[index++] = action;
          this.actions[index++] = token;
          this.actions[index++] = end;
          return index;
      }
      addActions(stack, token, end, index) {
          let { state } = stack, { parser } = stack.p, { data } = parser;
          for (let set = 0; set < 2; set++) {
              for (let i = parser.stateSlot(state, set ? 2 /* Skip */ : 1 /* Actions */);; i += 3) {
                  if (data[i] == 65535 /* End */) {
                      if (data[i + 1] == 1 /* Next */) {
                          i = pair(data, i + 2);
                      }
                      else {
                          if (index == 0 && data[i + 1] == 2 /* Other */)
                              index = this.putAction(pair(data, i + 1), token, end, index);
                          break;
                      }
                  }
                  if (data[i] == token)
                      index = this.putAction(pair(data, i + 1), token, end, index);
              }
          }
          return index;
      }
  }
  var Rec;
  (function (Rec) {
      Rec[Rec["Distance"] = 5] = "Distance";
      Rec[Rec["MaxRemainingPerStep"] = 3] = "MaxRemainingPerStep";
      Rec[Rec["MinBufferLengthPrune"] = 200] = "MinBufferLengthPrune";
      Rec[Rec["ForceReduceLimit"] = 10] = "ForceReduceLimit";
  })(Rec || (Rec = {}));
  class Parse {
      constructor(parser, input, fragments, ranges) {
          this.parser = parser;
          this.input = input;
          this.ranges = ranges;
          this.recovering = 0;
          this.nextStackID = 0x2654;
          this.minStackPos = 0;
          this.reused = [];
          this.stoppedAt = null;
          this.stream = new InputStream(input, ranges);
          this.tokens = new TokenCache(parser, this.stream);
          this.topTerm = parser.top[1];
          let { from } = ranges[0];
          this.stacks = [Stack.start(this, parser.top[0], from)];
          this.fragments = fragments.length && this.stream.end - from > parser.bufferLength * 4
              ? new FragmentCursor(fragments, parser.nodeSet) : null;
      }
      get parsedPos() {
          return this.minStackPos;
      }
      // Move the parser forward. This will process all parse stacks at
      // `this.pos` and try to advance them to a further position. If no
      // stack for such a position is found, it'll start error-recovery.
      //
      // When the parse is finished, this will return a syntax tree. When
      // not, it returns `null`.
      advance() {
          let stacks = this.stacks, pos = this.minStackPos;
          // This will hold stacks beyond `pos`.
          let newStacks = this.stacks = [];
          let stopped, stoppedTokens;
          // Keep advancing any stacks at `pos` until they either move
          // forward or can't be advanced. Gather stacks that can't be
          // advanced further in `stopped`.
          for (let i = 0; i < stacks.length; i++) {
              let stack = stacks[i];
              for (;;) {
                  this.tokens.mainToken = null;
                  if (stack.pos > pos) {
                      newStacks.push(stack);
                  }
                  else if (this.advanceStack(stack, newStacks, stacks)) {
                      continue;
                  }
                  else {
                      if (!stopped) {
                          stopped = [];
                          stoppedTokens = [];
                      }
                      stopped.push(stack);
                      let tok = this.tokens.getMainToken(stack);
                      stoppedTokens.push(tok.value, tok.end);
                  }
                  break;
              }
          }
          if (!newStacks.length) {
              let finished = stopped && findFinished(stopped);
              if (finished)
                  return this.stackToTree(finished);
              if (this.parser.strict) {
                  if (verbose && stopped)
                      console.log("Stuck with token " + (this.tokens.mainToken ? this.parser.getName(this.tokens.mainToken.value) : "none"));
                  throw new SyntaxError("No parse at " + pos);
              }
              if (!this.recovering)
                  this.recovering = 5 /* Distance */;
          }
          if (this.recovering && stopped) {
              let finished = this.runRecovery(stopped, stoppedTokens, newStacks);
              if (finished)
                  return this.stackToTree(finished.forceAll());
          }
          if (this.recovering) {
              let maxRemaining = this.recovering == 1 ? 1 : this.recovering * 3 /* MaxRemainingPerStep */;
              if (newStacks.length > maxRemaining) {
                  newStacks.sort((a, b) => b.score - a.score);
                  while (newStacks.length > maxRemaining)
                      newStacks.pop();
              }
              if (newStacks.some(s => s.reducePos > pos))
                  this.recovering--;
          }
          else if (newStacks.length > 1) {
              // Prune stacks that are in the same state, or that have been
              // running without splitting for a while, to avoid getting stuck
              // with multiple successful stacks running endlessly on.
              outer: for (let i = 0; i < newStacks.length - 1; i++) {
                  let stack = newStacks[i];
                  for (let j = i + 1; j < newStacks.length; j++) {
                      let other = newStacks[j];
                      if (stack.sameState(other) ||
                          stack.buffer.length > 200 /* MinBufferLengthPrune */ && other.buffer.length > 200 /* MinBufferLengthPrune */) {
                          if (((stack.score - other.score) || (stack.buffer.length - other.buffer.length)) > 0) {
                              newStacks.splice(j--, 1);
                          }
                          else {
                              newStacks.splice(i--, 1);
                              continue outer;
                          }
                      }
                  }
              }
          }
          this.minStackPos = newStacks[0].pos;
          for (let i = 1; i < newStacks.length; i++)
              if (newStacks[i].pos < this.minStackPos)
                  this.minStackPos = newStacks[i].pos;
          return null;
      }
      stopAt(pos) {
          if (this.stoppedAt != null && this.stoppedAt < pos)
              throw new RangeError("Can't move stoppedAt forward");
          this.stoppedAt = pos;
      }
      // Returns an updated version of the given stack, or null if the
      // stack can't advance normally. When `split` and `stacks` are
      // given, stacks split off by ambiguous operations will be pushed to
      // `split`, or added to `stacks` if they move `pos` forward.
      advanceStack(stack, stacks, split) {
          let start = stack.pos, { parser } = this;
          let base = verbose ? this.stackID(stack) + " -> " : "";
          if (this.stoppedAt != null && start > this.stoppedAt)
              return stack.forceReduce() ? stack : null;
          if (this.fragments) {
              let strictCx = stack.curContext && stack.curContext.tracker.strict, cxHash = strictCx ? stack.curContext.hash : 0;
              for (let cached = this.fragments.nodeAt(start); cached;) {
                  let match = this.parser.nodeSet.types[cached.type.id] == cached.type ? parser.getGoto(stack.state, cached.type.id) : -1;
                  if (match > -1 && cached.length && (!strictCx || (cached.prop(NodeProp.contextHash) || 0) == cxHash)) {
                      stack.useNode(cached, match);
                      if (verbose)
                          console.log(base + this.stackID(stack) + ` (via reuse of ${parser.getName(cached.type.id)})`);
                      return true;
                  }
                  if (!(cached instanceof Tree) || cached.children.length == 0 || cached.positions[0] > 0)
                      break;
                  let inner = cached.children[0];
                  if (inner instanceof Tree && cached.positions[0] == 0)
                      cached = inner;
                  else
                      break;
              }
          }
          let defaultReduce = parser.stateSlot(stack.state, 4 /* DefaultReduce */);
          if (defaultReduce > 0) {
              stack.reduce(defaultReduce);
              if (verbose)
                  console.log(base + this.stackID(stack) + ` (via always-reduce ${parser.getName(defaultReduce & 65535 /* ValueMask */)})`);
              return true;
          }
          let actions = this.tokens.getActions(stack);
          for (let i = 0; i < actions.length;) {
              let action = actions[i++], term = actions[i++], end = actions[i++];
              let last = i == actions.length || !split;
              let localStack = last ? stack : stack.split();
              localStack.apply(action, term, end);
              if (verbose)
                  console.log(base + this.stackID(localStack) + ` (via ${(action & 65536 /* ReduceFlag */) == 0 ? "shift"
                      : `reduce of ${parser.getName(action & 65535 /* ValueMask */)}`} for ${parser.getName(term)} @ ${start}${localStack == stack ? "" : ", split"})`);
              if (last)
                  return true;
              else if (localStack.pos > start)
                  stacks.push(localStack);
              else
                  split.push(localStack);
          }
          return false;
      }
      // Advance a given stack forward as far as it will go. Returns the
      // (possibly updated) stack if it got stuck, or null if it moved
      // forward and was given to `pushStackDedup`.
      advanceFully(stack, newStacks) {
          let pos = stack.pos;
          for (;;) {
              if (!this.advanceStack(stack, null, null))
                  return false;
              if (stack.pos > pos) {
                  pushStackDedup(stack, newStacks);
                  return true;
              }
          }
      }
      runRecovery(stacks, tokens, newStacks) {
          let finished = null, restarted = false;
          for (let i = 0; i < stacks.length; i++) {
              let stack = stacks[i], token = tokens[i << 1], tokenEnd = tokens[(i << 1) + 1];
              let base = verbose ? this.stackID(stack) + " -> " : "";
              if (stack.deadEnd) {
                  if (restarted)
                      continue;
                  restarted = true;
                  stack.restart();
                  if (verbose)
                      console.log(base + this.stackID(stack) + " (restarted)");
                  let done = this.advanceFully(stack, newStacks);
                  if (done)
                      continue;
              }
              let force = stack.split(), forceBase = base;
              for (let j = 0; force.forceReduce() && j < 10 /* ForceReduceLimit */; j++) {
                  if (verbose)
                      console.log(forceBase + this.stackID(force) + " (via force-reduce)");
                  let done = this.advanceFully(force, newStacks);
                  if (done)
                      break;
                  if (verbose)
                      forceBase = this.stackID(force) + " -> ";
              }
              for (let insert of stack.recoverByInsert(token)) {
                  if (verbose)
                      console.log(base + this.stackID(insert) + " (via recover-insert)");
                  this.advanceFully(insert, newStacks);
              }
              if (this.stream.end > stack.pos) {
                  if (tokenEnd == stack.pos) {
                      tokenEnd++;
                      token = 0 /* Err */;
                  }
                  stack.recoverByDelete(token, tokenEnd);
                  if (verbose)
                      console.log(base + this.stackID(stack) + ` (via recover-delete ${this.parser.getName(token)})`);
                  pushStackDedup(stack, newStacks);
              }
              else if (!finished || finished.score < stack.score) {
                  finished = stack;
              }
          }
          return finished;
      }
      // Convert the stack's buffer to a syntax tree.
      stackToTree(stack) {
          stack.close();
          return Tree.build({ buffer: StackBufferCursor.create(stack),
              nodeSet: this.parser.nodeSet,
              topID: this.topTerm,
              maxBufferLength: this.parser.bufferLength,
              reused: this.reused,
              start: this.ranges[0].from,
              length: stack.pos - this.ranges[0].from,
              minRepeatType: this.parser.minRepeatTerm });
      }
      stackID(stack) {
          let id = (stackIDs || (stackIDs = new WeakMap)).get(stack);
          if (!id)
              stackIDs.set(stack, id = String.fromCodePoint(this.nextStackID++));
          return id + stack;
      }
  }
  function pushStackDedup(stack, newStacks) {
      for (let i = 0; i < newStacks.length; i++) {
          let other = newStacks[i];
          if (other.pos == stack.pos && other.sameState(stack)) {
              if (newStacks[i].score < stack.score)
                  newStacks[i] = stack;
              return;
          }
      }
      newStacks.push(stack);
  }
  class Dialect {
      constructor(source, flags, disabled) {
          this.source = source;
          this.flags = flags;
          this.disabled = disabled;
      }
      allows(term) { return !this.disabled || this.disabled[term] == 0; }
  }
  const id = x => x;
  /// Context trackers are used to track stateful context (such as
  /// indentation in the Python grammar, or parent elements in the XML
  /// grammar) needed by external tokenizers. You declare them in a
  /// grammar file as `@context exportName from "module"`.
  ///
  /// Context values should be immutable, and can be updated (replaced)
  /// on shift or reduce actions.
  ///
  /// The export used in a `@context` declaration should be of this
  /// type.
  class ContextTracker {
      /// Define a context tracker.
      constructor(spec) {
          this.start = spec.start;
          this.shift = spec.shift || id;
          this.reduce = spec.reduce || id;
          this.reuse = spec.reuse || id;
          this.hash = spec.hash || (() => 0);
          this.strict = spec.strict !== false;
      }
  }
  /// A parser holds the parse tables for a given grammar, as generated
  /// by `lezer-generator`.
  class LRParser extends Parser {
      /// @internal
      constructor(spec) {
          super();
          /// @internal
          this.wrappers = [];
          if (spec.version != 13 /* Version */)
              throw new RangeError(`Parser version (${spec.version}) doesn't match runtime version (${13 /* Version */})`);
          let nodeNames = spec.nodeNames.split(" ");
          this.minRepeatTerm = nodeNames.length;
          for (let i = 0; i < spec.repeatNodeCount; i++)
              nodeNames.push("");
          let topTerms = Object.keys(spec.topRules).map(r => spec.topRules[r][1]);
          let nodeProps = [];
          for (let i = 0; i < nodeNames.length; i++)
              nodeProps.push([]);
          function setProp(nodeID, prop, value) {
              nodeProps[nodeID].push([prop, prop.deserialize(String(value))]);
          }
          if (spec.nodeProps)
              for (let propSpec of spec.nodeProps) {
                  let prop = propSpec[0];
                  for (let i = 1; i < propSpec.length;) {
                      let next = propSpec[i++];
                      if (next >= 0) {
                          setProp(next, prop, propSpec[i++]);
                      }
                      else {
                          let value = propSpec[i + -next];
                          for (let j = -next; j > 0; j--)
                              setProp(propSpec[i++], prop, value);
                          i++;
                      }
                  }
              }
          this.nodeSet = new NodeSet(nodeNames.map((name, i) => NodeType.define({
              name: i >= this.minRepeatTerm ? undefined : name,
              id: i,
              props: nodeProps[i],
              top: topTerms.indexOf(i) > -1,
              error: i == 0,
              skipped: spec.skippedNodes && spec.skippedNodes.indexOf(i) > -1
          })));
          this.strict = false;
          this.bufferLength = DefaultBufferLength;
          let tokenArray = decodeArray(spec.tokenData);
          this.context = spec.context;
          this.specialized = new Uint16Array(spec.specialized ? spec.specialized.length : 0);
          this.specializers = [];
          if (spec.specialized)
              for (let i = 0; i < spec.specialized.length; i++) {
                  this.specialized[i] = spec.specialized[i].term;
                  this.specializers[i] = spec.specialized[i].get;
              }
          this.states = decodeArray(spec.states, Uint32Array);
          this.data = decodeArray(spec.stateData);
          this.goto = decodeArray(spec.goto);
          this.maxTerm = spec.maxTerm;
          this.tokenizers = spec.tokenizers.map(value => typeof value == "number" ? new TokenGroup(tokenArray, value) : value);
          this.topRules = spec.topRules;
          this.dialects = spec.dialects || {};
          this.dynamicPrecedences = spec.dynamicPrecedences || null;
          this.tokenPrecTable = spec.tokenPrec;
          this.termNames = spec.termNames || null;
          this.maxNode = this.nodeSet.types.length - 1;
          this.dialect = this.parseDialect();
          this.top = this.topRules[Object.keys(this.topRules)[0]];
      }
      createParse(input, fragments, ranges) {
          let parse = new Parse(this, input, fragments, ranges);
          for (let w of this.wrappers)
              parse = w(parse, input, fragments, ranges);
          return parse;
      }
      /// Get a goto table entry @internal
      getGoto(state, term, loose = false) {
          let table = this.goto;
          if (term >= table[0])
              return -1;
          for (let pos = table[term + 1];;) {
              let groupTag = table[pos++], last = groupTag & 1;
              let target = table[pos++];
              if (last && loose)
                  return target;
              for (let end = pos + (groupTag >> 1); pos < end; pos++)
                  if (table[pos] == state)
                      return target;
              if (last)
                  return -1;
          }
      }
      /// Check if this state has an action for a given terminal @internal
      hasAction(state, terminal) {
          let data = this.data;
          for (let set = 0; set < 2; set++) {
              for (let i = this.stateSlot(state, set ? 2 /* Skip */ : 1 /* Actions */), next;; i += 3) {
                  if ((next = data[i]) == 65535 /* End */) {
                      if (data[i + 1] == 1 /* Next */)
                          next = data[i = pair(data, i + 2)];
                      else if (data[i + 1] == 2 /* Other */)
                          return pair(data, i + 2);
                      else
                          break;
                  }
                  if (next == terminal || next == 0 /* Err */)
                      return pair(data, i + 1);
              }
          }
          return 0;
      }
      /// @internal
      stateSlot(state, slot) {
          return this.states[(state * 6 /* Size */) + slot];
      }
      /// @internal
      stateFlag(state, flag) {
          return (this.stateSlot(state, 0 /* Flags */) & flag) > 0;
      }
      /// @internal
      validAction(state, action) {
          if (action == this.stateSlot(state, 4 /* DefaultReduce */))
              return true;
          for (let i = this.stateSlot(state, 1 /* Actions */);; i += 3) {
              if (this.data[i] == 65535 /* End */) {
                  if (this.data[i + 1] == 1 /* Next */)
                      i = pair(this.data, i + 2);
                  else
                      return false;
              }
              if (action == pair(this.data, i + 1))
                  return true;
          }
      }
      /// Get the states that can follow this one through shift actions or
      /// goto jumps. @internal
      nextStates(state) {
          let result = [];
          for (let i = this.stateSlot(state, 1 /* Actions */);; i += 3) {
              if (this.data[i] == 65535 /* End */) {
                  if (this.data[i + 1] == 1 /* Next */)
                      i = pair(this.data, i + 2);
                  else
                      break;
              }
              if ((this.data[i + 2] & (65536 /* ReduceFlag */ >> 16)) == 0) {
                  let value = this.data[i + 1];
                  if (!result.some((v, i) => (i & 1) && v == value))
                      result.push(this.data[i], value);
              }
          }
          return result;
      }
      /// @internal
      overrides(token, prev) {
          let iPrev = findOffset(this.data, this.tokenPrecTable, prev);
          return iPrev < 0 || findOffset(this.data, this.tokenPrecTable, token) < iPrev;
      }
      /// Configure the parser. Returns a new parser instance that has the
      /// given settings modified. Settings not provided in `config` are
      /// kept from the original parser.
      configure(config) {
          // Hideous reflection-based kludge to make it easy to create a
          // slightly modified copy of a parser.
          let copy = Object.assign(Object.create(LRParser.prototype), this);
          if (config.props)
              copy.nodeSet = this.nodeSet.extend(...config.props);
          if (config.top) {
              let info = this.topRules[config.top];
              if (!info)
                  throw new RangeError(`Invalid top rule name ${config.top}`);
              copy.top = info;
          }
          if (config.tokenizers)
              copy.tokenizers = this.tokenizers.map(t => {
                  let found = config.tokenizers.find(r => r.from == t);
                  return found ? found.to : t;
              });
          if (config.contextTracker)
              copy.context = config.contextTracker;
          if (config.dialect)
              copy.dialect = this.parseDialect(config.dialect);
          if (config.strict != null)
              copy.strict = config.strict;
          if (config.wrap)
              copy.wrappers = copy.wrappers.concat(config.wrap);
          if (config.bufferLength != null)
              copy.bufferLength = config.bufferLength;
          return copy;
      }
      /// Returns the name associated with a given term. This will only
      /// work for all terms when the parser was generated with the
      /// `--names` option. By default, only the names of tagged terms are
      /// stored.
      getName(term) {
          return this.termNames ? this.termNames[term] : String(term <= this.maxNode && this.nodeSet.types[term].name || term);
      }
      /// The eof term id is always allocated directly after the node
      /// types. @internal
      get eofTerm() { return this.maxNode + 1; }
      /// The type of top node produced by the parser.
      get topNode() { return this.nodeSet.types[this.top[1]]; }
      /// @internal
      dynamicPrecedence(term) {
          let prec = this.dynamicPrecedences;
          return prec == null ? 0 : prec[term] || 0;
      }
      /// @internal
      parseDialect(dialect) {
          let values = Object.keys(this.dialects), flags = values.map(() => false);
          if (dialect)
              for (let part of dialect.split(" ")) {
                  let id = values.indexOf(part);
                  if (id >= 0)
                      flags[id] = true;
              }
          let disabled = null;
          for (let i = 0; i < values.length; i++)
              if (!flags[i]) {
                  for (let j = this.dialects[values[i]], id; (id = this.data[j++]) != 65535 /* End */;)
                      (disabled || (disabled = new Uint8Array(this.maxTerm + 1)))[id] = 1;
              }
          return new Dialect(dialect, flags, disabled);
      }
      /// (used by the output of the parser generator) @internal
      static deserialize(spec) {
          return new LRParser(spec);
      }
  }
  function pair(data, off) { return data[off] | (data[off + 1] << 16); }
  function findOffset(data, start, term) {
      for (let i = start, next; (next = data[i]) != 65535 /* End */; i++)
          if (next == term)
              return i - start;
      return -1;
  }
  function findFinished(stacks) {
      let best = null;
      for (let stack of stacks) {
          let stopped = stack.p.stoppedAt;
          if ((stack.pos == stack.p.stream.end || stopped != null && stack.pos > stopped) &&
              stack.p.parser.stateFlag(stack.state, 2 /* Accepting */) &&
              (!best || best.score < stack.score))
              best = stack;
      }
      return best;
  }
  
  export { ContextTracker, ExternalTokenizer, InputStream, LRParser, Stack };
  