// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of dart.core;

/**
 * A regular expression pattern.
 *
 * Regular expressions are [Pattern]s, and can as such be used to match strings
 * or parts of strings.
 *
 * Dart regular expressions have the same syntax and semantics as
 * JavaScript regular expressions. See
 * <https://ecma-international.org/ecma-262/9.0/#sec-regexp-regular-expression-objects>
 * for the specification of JavaScript regular expressions.
 *
 * [firstMatch] is the main implementation method that applies a regular
 * expression to a string and returns the first [RegExpMatch]. All
 * other methods in [RegExp] can build on it.
 *
 * Use [allMatches] to look for all matches of a regular expression in
 * a string.
 *
 * The following example finds all matches of a regular expression in
 * a string.
 * ```dart
 * RegExp exp = new RegExp(r"(\w+)");
 * String str = "Parse my string";
 * Iterable<RegExpMatch> matches = exp.allMatches(str);
 * ```
 *
 * Note the use of a _raw string_ (a string prefixed with `r`)
 * in the example above. Use a raw string to treat each character in a string
 * as a literal character.
 */
abstract class RegExp implements Pattern {
  /**
   * Constructs a regular expression.
   *
   * Throws a [FormatException] if [source] is not valid regular
   * expression syntax.
   *
   * If `multiLine` is enabled, then `^` and `$` will match the beginning and
   * end of a _line_, in addition to matching beginning and end of input,
   * respectively.
   *
   * If `caseSensitive` is disabled, then case is ignored.
   *
   * If `unicode` is enabled, then the pattern is treated as a Unicode
   * pattern as described by the ECMAScript standard.
   *
   * If `dotAll` is enabled, then the `.` pattern will match _all_ characters,
   * including line terminators.
   *
   * Example:
   *
   * ```dart
   * var wordPattern = RegExp(r"(\w+)");
   * var bracketedNumberValue = RegExp("$key: \\[\\d+\\]");
   * ```
   *
   * Notice the use of a _raw string_ in the first example, and a regular
   * string in the second. Because of the many character classes used in
   * regular expressions, it is common to use a raw string here, unless string
   * interpolation is required.
   */
  external factory RegExp(String source,
      {bool multiLine = false,
      bool caseSensitive = true,
      @Since("2.4") bool unicode = false,
      @Since("2.4") bool dotAll = false});

  /**
   * Returns a regular expression that matches [text].
   *
   * If [text] contains characters that are meaningful in regular expressions,
   * the resulting regular expression will match those characters literally.
   * If [text] contains no characters that have special meaning in a regular
   * expression, it is returned unmodified.
   *
   * The characters that have special meaning in regular expressions are:
   * `(`, `)`, `[`, `]`, `{`, `}`, `*`, `+`, `?`, `.`, `^`, `$`, `|` and `\`.
   */
  external static String escape(String text);

  /**
   * Searches for the first match of the regular expression
   * in the string [input]. Returns `null` if there is no match.
   */
  RegExpMatch firstMatch(String input);

  /**
   * Returns an iterable of the matches of the regular expression on [input].
   *
   * If [start] is provided, only start looking for matches at `start`.
   */
  Iterable<RegExpMatch> allMatches(String input, [int start = 0]);

  /**
   * Returns whether the regular expression has a match in the string [input].
   */
  bool hasMatch(String input);

  /**
   * Returns the first substring match of this regular expression in [input].
   */
  String stringMatch(String input);

  /**
   * The source regular expression string used to create this `RegExp`.
   */
  String get pattern;

  /**
   * Whether this regular expression matches multiple lines.
   *
   * If the regexp does match multiple lines, the "^" and "$" characters
   * match the beginning and end of lines. If not, the character match the
   * beginning and end of the input.
   */
  bool get isMultiLine;

  /**
   * Whether this regular expression is case sensitive.
   *
   * If the regular expression is not case sensitive, it will match an input
   * letter with a pattern letter even if the two letters are different case
   * versions of the same letter.
   */
  bool get isCaseSensitive;

  /**
   * Whether this regular expression is in Unicode mode.
   *
   * In Unicode mode, UTF-16 surrogate pairs in the original string will be
   * treated as a single code point and will not match separately. Otherwise,
   * the target string will be treated purely as a sequence of individual code
   * units and surrogates will not be treated specially.
   *
   * In Unicode mode, the syntax of the RegExp pattern is more restricted, but
   * some pattern features, like Unicode property escapes, are only available in
   * this mode.
   */
  @Since("2.4")
  bool get isUnicode;

  /**
   * Whether "." in this regular expression matches line terminators.
   *
   * When false, the "." character matches a single character, unless that
   * character is a line terminator. When true, then the "." character will
   * match any single character including line terminators.
   *
   * This feature is distinct from [isMultiline], as they affect the behavior
   * of different pattern characters, and so they can be used together or
   * separately.
   */
  @Since("2.4")
  bool get isDotAll;
}

/**
 * A regular expression match.
 *
 * Regular expression matches are [Match]es, but also include the ability
 * to retrieve the names for any named capture groups and to retrieve
 * matches for named capture groups by name instead of their index.
 */
@Since("2.3")
abstract class RegExpMatch implements Match {
  /**
   * The string matched by the group named [name].
   *
   * Returns the string matched by the capture group named [name], or
   * `null` if no string was matched by that capture group as part of
   * this match.
   *
   * The [name] must be the name of a named capture group in the regular
   * expression creating this match (that is, the name must be in
   * [groupNames]).
   */
  String namedGroup(String name);

  /**
   * The names of the captured groups in the match.
   */
  Iterable<String> get groupNames;
}
