Skip to content

Read include patterns as mask_t::assign_glob reads them - #8

Merged
jwiegley merged 1 commit into
mainfrom
johnw/include-glob-escapes
Nov 5, 2026
Merged

jwiegley merged 1 commit into
mainfrom
johnw/include-glob-escapes

Conversation

@jwiegley

@jwiegley jwiegley commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Ledger PR ledger/ledger#3328 made mask_t::assign_glob read every character of an include pattern literally except ?, * and a bracketed set: a backslash makes the next character literal, and a [ that no ] closes stands for itself. The driver read such patterns another way. splice deleted every backslash before matching, so \[f].dat became the set [f] and included f.dat, and globPaths handed an unclosed [ to compileRegex, which rejected it, so d[e.dat included nothing. This pull request makes the driver read include patterns as the C++ implementation does.

  • globComponent builds the regex for one path component as assign_glob builds it. ^ and $ stand in for \A and \z, and a ] directly after [ or [^ is escaped, because Boost reads that ] as a member of the set while compileRegex would close the set there.
  • splice passes the pattern through unchanged.
  • globPaths descends only into directories and includes only regular files, as expand_glob_path does. Before, an include whose last component matched a directory, or a wildcard after a component that matched a regular file, stopped the driver with an uncaught exception, and the files after it in the same run went unread.

Witness. Ledger's regress/include-glob-escapes.test, added by ledger/ledger#3335, which moves the pin to this commit. Through that pull request's check_all.py, the test fails against 8342e12, whose driver reads only the escaped letter of its six includes, and passes against this commit. Over ledger's full suite at ledger main 0c4084087 with that pull request merged, 4406 test files, check_all.py reports 3827 PASS and 0 FAIL with both ratchet bins empty, and exits with status 0.

Base. This commit sits on 8342e12, the current main and the revision that ledger main pins. It is the change first pushed as 628bbbc on 5376d29, re-cut after #3, #5 and #7 landed, with the same patch (git patch-id --stable agrees); only the witness numbers in its message changed. To keep the pinned commit reachable, please land it by fast-forward or with a merge commit, not by squash or rebase.

Not covered. Bracket expressions are still parsed by compileRegex, which has no POSIX classes such as [:digit:] and reads \d inside a set as the letter d. No ledger test uses either.

Checked. The oracle builds from this tree on aarch64-darwin, so every proof still checks; this pull request's CI builds it on all three platforms.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RJzsmMnVxXmrLUh9RGykQL

Ledger PR #3328, merged as 9c21ab852, made mask_t::assign_glob treat
every character of an include pattern literally except `?`, `*` and a
bracketed set: a backslash makes the next character literal, and a `[`
that no `]` closes stands for itself.  The driver read such patterns
another way.  `splice` deleted every backslash before `globPaths` saw
the pattern, so `\[f].dat` became the set `[f]` and included f.dat, and
`globPaths` handed an unclosed `[` to `compileRegex`, which rejected the
regex, so `d[e.dat` included nothing.

`globComponent` now builds the regex for one path component as
assign_glob builds it, escaping the same characters and leaving a `]`
bare, and `splice` passes the pattern through unchanged.  Two
differences between Boost and `compileRegex` are bridged there.  `^`
and `$` stand in for `\A` and `\z`, which `compileRegex` lacks, and a
`]` directly after `[` or `[^`, which Boost reads as a member of the
set, is escaped, because `compileRegex` would close an empty set at that
point.  A component without a wildcard or a set is still joined as a
path, now with its escapes removed.

`globPaths` also follows expand_glob_path (src/textual_directives.cc)
in descending only into directories and including only regular files.
Before this change, an include whose last component matched a directory
made `splice` read the directory, and a wildcard after a component that
matched a regular file made `readDir` fail.  In both cases the driver
stopped with an uncaught exception and exit status 1, before reaching
the files after it.  C++ reports such an include as not found.

The witness is ledger's regress/include-glob-escapes.test, which ledger
adds together with the pin that moves to this commit.  Through ledger's
test/semantic/check_all.py, as updated in the same pull request, it
fails against 8342e12, whose driver reads only the escaped letter of
its six includes, and passes against this commit.  Over ledger's
full suite of 4406 test files, at ledger main 0c4084087 with that pull
request merged, check_all.py then reports 3827 PASS and 0 FAIL, with
both ratchet bins empty, and exits with status 0.

Bracket expressions are still parsed by `compileRegex`, which has no
POSIX classes such as `[:digit:]` and reads `\d` inside a set as the
letter `d`.  No ledger test uses either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RJzsmMnVxXmrLUh9RGykQL
@jwiegley
jwiegley force-pushed the johnw/include-glob-escapes branch from 628bbbc to d5c7eec Compare November 5, 2026 05:03
jwiegley added a commit to ledger/ledger that referenced this pull request Nov 5, 2026
The oracle deleted every backslash from an include pattern before
matching it, and rejected a [ that no ] closes, so the include paths
that #3328 fixed in C++ could be tested only in t_value.cc.
ledger/ledger-semantics#8 reads an include pattern as
mask_t::assign_glob() does.  It also descends only into directories and
includes only regular files, as expand_glob_path() does; an include
that matched a directory used to stop the oracle's whole run.

Since #3336 the flake input is the oracle's only pin: flake.nix's URL
and flake.lock now name ledger-semantics d5c7eec, the head of that pull
request, one commit on top of 8342e12, the previous pin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RJzsmMnVxXmrLUh9RGykQL
@jwiegley
jwiegley merged commit 8163279 into main Nov 5, 2026
3 checks passed
@jwiegley
jwiegley deleted the johnw/include-glob-escapes branch November 5, 2026 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant