[libc-commits] [libc] [libc][regex] Add Kleene star and canonical AST normalisation (PR #233980)
Alex Strelnikov via libc-commits
libc-commits at lists.llvm.org
Thu Oct 22 07:57:22 PDT 2026
================
@@ -59,70 +60,115 @@ constexpr bool is_unimplemented_ere_escape(char c) {
}
}
-} // namespace
-
-ErrorOr<ExprId> parse_ere(cpp::string_view pattern, int cflags,
- ExprPool &pool) {
- ErrorOr<ExprId> cur = pool.empty_str();
- if (!cur.has_value())
- return cur;
-
- cpp::string_view rem = pattern;
- while (!rem.empty()) {
- char c = rem.front();
+// Parses a single ERE atom and an optional trailing '*' quantifier.
+ErrorOr<ExprId> parse_quantified_atom(cpp::string_view &rem, int cflags,
+ ExprPool &pool) {
+ char c = rem.front();
+ rem.remove_prefix(1);
+ ErrorOr<ExprId> atom = INVALID_EXPR_ID;
+ bool can_repeat = true;
+ switch (c) {
+ case '\\': {
+ if (rem.empty())
+ return Error(REG_EESCAPE);
+ c = rem.front();
rem.remove_prefix(1);
- ErrorOr<ExprId> atom = INVALID_EXPR_ID;
- switch (c) {
- case '\\': {
- if (rem.empty())
- return Error(REG_EESCAPE);
- c = rem.front();
- rem.remove_prefix(1);
- if (is_unimplemented_ere_escape(c))
- return Error(REG_BADPAT);
- atom = pool.make_lit(c);
- break;
- }
- case '.': {
- ByteSet bs;
- if (cflags & REG_NEWLINE) {
- bs.set_range(0, '\n' - 1);
- bs.set_range('\n' + 1, BYTE_SET_BITS - 1);
- } else {
- bs.flip();
- }
- atom = pool.make_byte_set(bs);
- break;
- }
- case '^':
- atom = pool.make_anchor(ANCHOR_BOL);
- break;
- case '$':
- atom = pool.make_anchor(ANCHOR_EOL);
- break;
- // TODO: Wire ERE metacharacters as each operator is implemented in
- // subsequent patches.
- case '*':
- case '+':
- case '?':
- case '(':
- case ')':
- case '[':
- case '{':
- case '|':
+ if (is_unimplemented_ere_escape(c))
return Error(REG_BADPAT);
- default:
- atom = pool.make_lit(c);
- break;
+ atom = pool.make_lit(c);
+ break;
+ }
+ case '.': {
+ ByteSet bs;
+ if (cflags & REG_NEWLINE) {
+ bs.set_range(0, '\n' - 1);
+ bs.set_range('\n' + 1, BYTE_SET_BITS - 1);
+ } else {
+ bs.flip();
}
+ atom = pool.make_byte_set(bs);
+ break;
+ }
+ case '^':
+ atom = pool.make_anchor(ANCHOR_BOL);
+ can_repeat = false;
+ break;
+ case '$':
+ atom = pool.make_anchor(ANCHOR_EOL);
+ can_repeat = false;
+ break;
+ // Valid postfix '*' is consumed after a repeatable atom below; reaching a
+ // quantifier at the start of an atom means it has no preceding repeatable
+ // atom (e.g. "*a", "^*", or doubled "a**").
+ case '*':
+ case '+':
+ case '?':
+ return Error(REG_BADRPT);
+ case '{':
+ if (!rem.empty() && rem.front() >= '0' && rem.front() <= '9')
+ return Error(REG_BADRPT);
+ return Error(REG_BADPAT);
+ // TODO: Wire ERE metacharacters as each operator is implemented in
+ // subsequent patches.
+ case '(':
+ case ')':
+ case '[':
+ case '|':
+ return Error(REG_BADPAT);
+ default:
+ atom = pool.make_lit(c);
+ break;
+ }
+ if (!atom.has_value() || !can_repeat)
+ return atom;
+ if (rem.starts_with('*')) {
+ rem.remove_prefix(1);
+ return pool.make_star(*atom);
+ }
+ if (rem.starts_with('+') || rem.starts_with('?') || rem.starts_with('{'))
+ return Error(REG_BADPAT);
+ return atom;
+}
+
+// Folds concatenated atoms right-to-left in 64-atom (256-byte) stack chunks so
+// right-associative make_concat stays O(1) without orphaned prefixes and
+// recursion is bounded to <= 157 frames across MAX_NODE_LIMIT.
----------------
strel-12 wrote:
Nit: If `MAX_NODE_LIMIT` is ever updated, I think it would be easy to forget to update the `157`, so how about `⌈MAX_NODE_LIMIT / 64⌉` instead?
https://github.com/llvm/llvm-project/pull/233980
More information about the libc-commits
mailing list