summaryrefslogtreecommitdiffstats
path: root/js/public/RegExpFlags.h
blob: 4fa36031b0306fbe8ce2e2e57a77d87659a26d10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* Regular expression flags. */

#ifndef js_RegExpFlags_h
#define js_RegExpFlags_h

#include "mozilla/Assertions.h"  // MOZ_ASSERT
#include "mozilla/Attributes.h"  // MOZ_IMPLICIT

#include <stdint.h>  // uint8_t

namespace JS {

/**
 * Regular expression flag values, suitable for initializing a collection of
 * regular expression flags as defined below in |RegExpFlags|.  Flags are listed
 * in alphabetical order by syntax -- /d, /g, /i, /m, /s, /u, /y.
 */
class RegExpFlag {
  // WARNING TO SPIDERMONKEY HACKERS (embedders must assume these values can
  // change):
  //
  // Flag-bit values appear in XDR and structured clone data formats, so none of
  // these values can be changed (including to assign values in numerically
  // ascending order) unless you also add a translation layer.

 public:
  /**
   * Add .indices property to the match result, i.e. /d
   */
  static constexpr uint8_t HasIndices = 0b100'0000;

  /**
   * Act globally and find *all* matches (rather than stopping after just the
   * first one), i.e. /g.
   */
  static constexpr uint8_t Global = 0b000'0010;

  /**
   * Interpret regular expression source text case-insensitively by folding
   * uppercase letters to lowercase, i.e. /i.
   */
  static constexpr uint8_t IgnoreCase = 0b000'0001;

  /** Treat ^ and $ as begin and end of line, i.e. /m. */
  static constexpr uint8_t Multiline = 0b000'0100;

  /* Allow . to match newline characters, i.e. /s. */
  static constexpr uint8_t DotAll = 0b010'0000;

  /** Use Unicode semantics, i.e. /u. */
  static constexpr uint8_t Unicode = 0b001'0000;

  /** Only match starting from <regular expression>.lastIndex, i.e. /y. */
  static constexpr uint8_t Sticky = 0b000'1000;

  /** No regular expression flags. */
  static constexpr uint8_t NoFlags = 0b000'0000;

  /** All regular expression flags. */
  static constexpr uint8_t AllFlags = 0b111'1111;
};

/**
 * A collection of regular expression flags.  Individual flag values may be
 * combined into a collection using bitwise operators.
 */
class RegExpFlags {
 public:
  using Flag = uint8_t;

 private:
  Flag flags_;

 public:
  RegExpFlags() = default;

  MOZ_IMPLICIT RegExpFlags(Flag flags) : flags_(flags) {
    MOZ_ASSERT((flags & RegExpFlag::AllFlags) == flags,
               "flags must not contain unrecognized flags");
  }

  RegExpFlags(const RegExpFlags&) = default;

  bool operator==(const RegExpFlags& other) const {
    return flags_ == other.flags_;
  }

  bool operator!=(const RegExpFlags& other) const { return !(*this == other); }

  RegExpFlags& operator&=(const RegExpFlags& rhs) {
    flags_ &= rhs.flags_;
    return *this;
  }

  RegExpFlags& operator|=(const RegExpFlags& rhs) {
    flags_ |= rhs.flags_;
    return *this;
  }

  RegExpFlags operator&(Flag flag) const { return RegExpFlags(flags_ & flag); }

  RegExpFlags operator|(Flag flag) const { return RegExpFlags(flags_ | flag); }

  RegExpFlags operator^(Flag flag) const { return RegExpFlags(flags_ ^ flag); }

  RegExpFlags operator~() const {
    return RegExpFlags(~flags_ & RegExpFlag::AllFlags);
  }

  bool hasIndices() const { return flags_ & RegExpFlag::HasIndices; }
  bool global() const { return flags_ & RegExpFlag::Global; }
  bool ignoreCase() const { return flags_ & RegExpFlag::IgnoreCase; }
  bool multiline() const { return flags_ & RegExpFlag::Multiline; }
  bool dotAll() const { return flags_ & RegExpFlag::DotAll; }
  bool unicode() const { return flags_ & RegExpFlag::Unicode; }
  bool sticky() const { return flags_ & RegExpFlag::Sticky; }

  explicit operator bool() const { return flags_ != 0; }

  Flag value() const { return flags_; }
};

inline RegExpFlags& operator&=(RegExpFlags& flags, RegExpFlags::Flag flag) {
  flags = flags & flag;
  return flags;
}

inline RegExpFlags& operator|=(RegExpFlags& flags, RegExpFlags::Flag flag) {
  flags = flags | flag;
  return flags;
}

inline RegExpFlags& operator^=(RegExpFlags& flags, RegExpFlags::Flag flag) {
  flags = flags ^ flag;
  return flags;
}

inline RegExpFlags operator&(const RegExpFlags& lhs, const RegExpFlags& rhs) {
  RegExpFlags result = lhs;
  result &= rhs;
  return lhs;
}

inline RegExpFlags operator|(const RegExpFlags& lhs, const RegExpFlags& rhs) {
  RegExpFlags result = lhs;
  result |= rhs;
  return result;
}

}  // namespace JS

#endif  // js_RegExpFlags_h