"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const ast = require("./ast.js");
const beforeEditPositionMapper = require("./beforeEditPositionMapper.js");
const smallImmutableSet = require("./smallImmutableSet.js");
const length = require("./length.js");
const concat23Trees = require("./concat23Trees.js");
const nodeReader = require("./nodeReader.js");
function parseDocument(tokenizer, edits, oldNode, createImmutableLists) {
  const parser = new Parser(tokenizer, edits, oldNode, createImmutableLists);
  return parser.parseDocument();
}
class Parser {
  constructor(tokenizer, edits, oldNode, createImmutableLists) {
    this.tokenizer = tokenizer;
    this.createImmutableLists = createImmutableLists;
    this._itemsConstructed = 0;
    this._itemsFromCache = 0;
    if (oldNode && createImmutableLists) {
      throw new Error("Not supported");
    }
    this.oldNodeReader = oldNode ? new nodeReader.NodeReader(oldNode) : void 0;
    this.positionMapper = new beforeEditPositionMapper.BeforeEditPositionMapper(edits, tokenizer.length);
  }
  parseDocument() {
    this._itemsConstructed = 0;
    this._itemsFromCache = 0;
    let result = this.parseList(smallImmutableSet.SmallImmutableSet.getEmpty());
    if (!result) {
      result = ast.ListAstNode.getEmpty();
    }
    return result;
  }
  parseList(openedBracketIds) {
    const items = new Array();
    while (true) {
      const token = this.tokenizer.peek();
      if (!token || token.kind === 2 && token.bracketIds.intersects(openedBracketIds)) {
        break;
      }
      const child = this.parseChild(openedBracketIds);
      if (child.kind === 4 && child.childrenLength === 0) {
        continue;
      }
      items.push(child);
    }
    const result = this.oldNodeReader ? concat23Trees.concat23Trees(items) : concat23Trees.concat23TreesOfSameHeight(items, this.createImmutableLists);
    return result;
  }
  parseChild(openedBracketIds) {
    if (this.oldNodeReader) {
      const maxCacheableLength = this.positionMapper.getDistanceToNextChange(this.tokenizer.offset);
      if (!length.lengthIsZero(maxCacheableLength)) {
        const cachedNode = this.oldNodeReader.readLongestNodeAt(this.positionMapper.getOffsetBeforeChange(this.tokenizer.offset), (curNode) => {
          if (!length.lengthLessThan(curNode.length, maxCacheableLength)) {
            return false;
          }
          const canBeReused = curNode.canBeReused(openedBracketIds);
          return canBeReused;
        });
        if (cachedNode) {
          this._itemsFromCache++;
          this.tokenizer.skip(cachedNode.length);
          return cachedNode;
        }
      }
    }
    this._itemsConstructed++;
    const token = this.tokenizer.read();
    switch (token.kind) {
      case 2:
        return new ast.InvalidBracketAstNode(token.bracketIds, token.length);
      case 0:
        return token.astNode;
      case 1: {
        const set = openedBracketIds.merge(token.bracketIds);
        const child = this.parseList(set);
        const nextToken = this.tokenizer.peek();
        if (nextToken && nextToken.kind === 2 && (nextToken.bracketId === token.bracketId || nextToken.bracketIds.intersects(token.bracketIds))) {
          this.tokenizer.read();
          return ast.PairAstNode.create(token.astNode, child, nextToken.astNode);
        } else {
          return ast.PairAstNode.create(token.astNode, child, null);
        }
      }
      default:
        throw new Error("unexpected");
    }
  }
}
exports.parseDocument = parseDocument;
