/**
 * @param {string} value
 * @returns {RegExp}
 * */

/**
 * @param {RegExp | string } re
 * @returns {string}
 */
function source(re) {
  if (!re) return null;
  if (typeof re === "string") return re;

  return re.source;
}

/**
 * @param {...(RegExp | string) } args
 * @returns {string}
 */
function concat(...args) {
  const joined = args.map((x) => source(x)).join("");
  return joined;
}

/*
Language: Augmented Backus-Naur Form
Author: Alex McKibben <alex@nullscope.net>
Website: https://tools.ietf.org/html/rfc5234
Audit: 2020
*/

/** @type LanguageFn */
function abnf(hljs) {
  const IDENT = /^[a-zA-Z][a-zA-Z0-9-]*/;

  const KEYWORDS = [
    "ALPHA",
    "BIT",
    "CHAR",
    "CR",
    "CRLF",
    "CTL",
    "DIGIT",
    "DQUOTE",
    "HEXDIG",
    "HTAB",
    "LF",
    "LWSP",
    "OCTET",
    "SP",
    "VCHAR",
    "WSP"
  ];

  const COMMENT = hljs.COMMENT(/;/, /$/);

  const TERMINAL_BINARY = {
    scope: "symbol",
    match: /%b[0-1]+(-[0-1]+|(\.[0-1]+)+)?/
  };

  const TERMINAL_DECIMAL = {
    scope: "symbol",
    match: /%d[0-9]+(-[0-9]+|(\.[0-9]+)+)?/
  };

  const TERMINAL_HEXADECIMAL = {
    scope: "symbol",
    match: /%x[0-9A-F]+(-[0-9A-F]+|(\.[0-9A-F]+)+)?/
  };

  const CASE_SENSITIVITY = {
    scope: "symbol",
    match: /%[si](?=".*")/
  };

  const RULE_DECLARATION = {
    scope: "attribute",
    match: concat(IDENT, /(?=\s*=)/)
  };

  const ASSIGNMENT = {
    scope: "operator",
    match: /=\/?/
  };

  return {
    name: 'Augmented Backus-Naur Form',
    illegal: /[!@#$^&',?+~`|:]/,
    keywords: KEYWORDS,
    contains: [
      ASSIGNMENT,
      RULE_DECLARATION,
      COMMENT,
      TERMINAL_BINARY,
      TERMINAL_DECIMAL,
      TERMINAL_HEXADECIMAL,
      CASE_SENSITIVITY,
      hljs.QUOTE_STRING_MODE,
      hljs.NUMBER_MODE
    ]
  };
}

module.exports = abnf;
