import "../chevrotain/lib-src-parse-parser-parser.js";
import { Lexer } from "../chevrotain/lib-src-scan-lexer_public.js";
import "../chevrotain/lib-src-scan-tokens_public.js";
import "../chevrotain/lib-src-parse-grammar-lookahead.js";
import "../chevrotain/lib-src-parse-errors_public.js";
import "../chevrotain/lib-src-parse-exceptions_public.js";
import { isTerminalRule, isParserRule, isKeyword } from "./lib-languages-generated-ast.js";
import { streamAllContents } from "./lib-utils-ast-utils.js";
import { getAllReachableRules, terminalRegex } from "./lib-utils-grammar-utils.js";
import { isWhitespace, getCaseInsensitivePattern, partialMatches } from "./lib-utils-regexp-utils.js";
import { stream } from "./lib-utils-stream.js";
class DefaultTokenBuilder {
  constructor() {
    this.diagnostics = [];
  }
  buildTokens(grammar, options) {
    const reachableRules = stream(getAllReachableRules(grammar, false));
    const terminalTokens = this.buildTerminalTokens(reachableRules);
    const tokens = this.buildKeywordTokens(reachableRules, terminalTokens, options);
    terminalTokens.forEach((terminalToken) => {
      const pattern = terminalToken.PATTERN;
      if (typeof pattern === "object" && pattern && "test" in pattern && isWhitespace(pattern)) {
        tokens.unshift(terminalToken);
      } else {
        tokens.push(terminalToken);
      }
    });
    return tokens;
  }
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  flushLexingReport(text) {
    return { diagnostics: this.popDiagnostics() };
  }
  popDiagnostics() {
    const diagnostics = [...this.diagnostics];
    this.diagnostics = [];
    return diagnostics;
  }
  buildTerminalTokens(rules) {
    return rules.filter(isTerminalRule).filter((e) => !e.fragment).map((terminal) => this.buildTerminalToken(terminal)).toArray();
  }
  buildTerminalToken(terminal) {
    const regex = terminalRegex(terminal);
    const pattern = this.requiresCustomPattern(regex) ? this.regexPatternFunction(regex) : regex;
    const tokenType = {
      name: terminal.name,
      PATTERN: pattern
    };
    if (typeof pattern === "function") {
      tokenType.LINE_BREAKS = true;
    }
    if (terminal.hidden) {
      tokenType.GROUP = isWhitespace(regex) ? Lexer.SKIPPED : "hidden";
    }
    return tokenType;
  }
  requiresCustomPattern(regex) {
    if (regex.flags.includes("u") || regex.flags.includes("s")) {
      return true;
    } else if (regex.source.includes("?<=") || regex.source.includes("?<!")) {
      return true;
    } else {
      return false;
    }
  }
  regexPatternFunction(regex) {
    const stickyRegex = new RegExp(regex, regex.flags + "y");
    return (text, offset) => {
      stickyRegex.lastIndex = offset;
      const execResult = stickyRegex.exec(text);
      return execResult;
    };
  }
  buildKeywordTokens(rules, terminalTokens, options) {
    return rules.filter(isParserRule).flatMap((rule) => streamAllContents(rule).filter(isKeyword)).distinct((e) => e.value).toArray().sort((a, b) => b.value.length - a.value.length).map((keyword) => this.buildKeywordToken(keyword, terminalTokens, Boolean(options === null || options === void 0 ? void 0 : options.caseInsensitive)));
  }
  buildKeywordToken(keyword, terminalTokens, caseInsensitive) {
    const keywordPattern = this.buildKeywordPattern(keyword, caseInsensitive);
    const tokenType = {
      name: keyword.value,
      PATTERN: keywordPattern,
      LONGER_ALT: this.findLongerAlt(keyword, terminalTokens)
    };
    if (typeof keywordPattern === "function") {
      tokenType.LINE_BREAKS = true;
    }
    return tokenType;
  }
  buildKeywordPattern(keyword, caseInsensitive) {
    return caseInsensitive ? new RegExp(getCaseInsensitivePattern(keyword.value)) : keyword.value;
  }
  findLongerAlt(keyword, terminalTokens) {
    return terminalTokens.reduce((longerAlts, token) => {
      const pattern = token === null || token === void 0 ? void 0 : token.PATTERN;
      if ((pattern === null || pattern === void 0 ? void 0 : pattern.source) && partialMatches("^" + pattern.source + "$", keyword.value)) {
        longerAlts.push(token);
      }
      return longerAlts;
    }, []);
  }
}
export {
  DefaultTokenBuilder
};
//# sourceMappingURL=lib-parser-token-builder.js.map
