diff --git a/CMakeLists.txt b/CMakeLists.txt index e6d4026..d5a637a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ endif() # ========== Project ========== project(patternia - VERSION 0.9.3 + VERSION 0.9.4 DESCRIPTION "Header-only pattern matching library for modern C++" LANGUAGES CXX ) diff --git a/README.md b/README.md index bad2544..5aded00 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ target_link_libraries(your_target PRIVATE patternia::patternia) include(FetchContent) FetchContent_Declare(patternia GIT_REPOSITORY https://github.com/sentomk/patternia.git - GIT_TAG v0.9.3 + GIT_TAG v0.9.4 ) FetchContent_MakeAvailable(patternia) diff --git a/docs/changelog/releases.md b/docs/changelog/releases.md index 8705711..d61c3e1 100644 --- a/docs/changelog/releases.md +++ b/docs/changelog/releases.md @@ -29,6 +29,7 @@ reflect the current supported API surface. - [v0.8.5](v0.8.5.md) - March 10, 2026 ## 0.9.x +- [v0.9.4](v0.9.4.md) - August 2026 - [v0.9.3](v0.9.3.md) - May 2026 - [v0.9.2](v0.9.2.md) - April 10, 2026 - [v0.9.1](v0.9.1.md) - March 18, 2026 diff --git a/docs/changelog/v0.9.4.md b/docs/changelog/v0.9.4.md new file mode 100644 index 0000000..ff5ff80 --- /dev/null +++ b/docs/changelog/v0.9.4.md @@ -0,0 +1,159 @@ +# Patternia v0.9.4 Release Note + +**Release Date:** August 2026 +**Version:** 0.9.4 + +--- + +## Overview + +Patternia v0.9.4 is a guard-focused release. It introduces `PTN_BIND` +member-anchored named placeholders for structural guards, unifies the +placeholder syntax around `_` and `PTN_BIND`, and adds operator sugar +(`!p`, `(a || b)`, `(a && b)`) for the pattern combinators. + +This release contains **breaking changes**; see +[Breaking Changes](#breaking-changes) and the +[Migration Guide](#migration-guide) below. + +--- + +## Breaking Changes + +### Positional guard APIs removed + +The positional guard spellings are removed in favor of `_` and +`PTN_BIND`: + +| Removed | Replacement | +| -------------------------- | ------------------------------ | +| `__` (double-underscore) | `_` | +| `_0` | `_` | +| `arg` | `PTN_BIND` names | +| `PTN_LET(v, expr)` | `PTN_BIND` + guard expression | +| `PTN_WHERE((a, b), expr)` | `PTN_BIND` + guard expression | + +`_` now serves both as the single-value guard placeholder and as the +wildcard fallback. + +### `PTN_BIND` names must be members of the type + +`PTN_BIND(Type, names...)` expands each name to +`member_t<&Type::name>`. Placeholder names that were aliases rather +than real members of `Type` no longer compile; use the member names +themselves. Misspellings are now caught at the `PTN_BIND` line. + +--- + +## New Features + +### `PTN_BIND(Type, names...)` — named guard placeholders + +Declares member-anchored named placeholders for guards attached to +`has<...>`, supporting one to ten names: + +```cpp +struct Point { int x; int y; }; +PTN_BIND(Point, x, y); + +match(p) | on( + $(has<&Point::x, &Point::y>)[x * x + y * y == 25] >> "on circle", + _ >> "elsewhere" +); +``` + +Names follow **members, not positions**: each name resolves to the +position of its member in the `has<...>` member list at compile time, +so the order of member pointers in `has<...>` does not matter: + +```cpp +$(has<&Point::y, &Point::x>)[x == 3 && y == 4] // x is still .x +``` + +Misuse is caught at compile time: a misspelled member name fails at +the `PTN_BIND` line, and a name whose member is not listed in +`has<...>` fails a static_assert. + +Declarations are valid at namespace or block scope. Block-scope +declarations use static storage duration, so they can be referenced +inside `PTN_ON`'s captureless caching lambda: + +```cpp +int classify(const Point &p) { + PTN_BIND(Point, x, y); + return match(p) | PTN_ON( + $(has<&Point::x, &Point::y>)[x * x + y * y == 25] >> 1, + _ >> 0); +} +``` + +### Operator sugar for combinators + +The pattern algebra now has operator forms: + +```cpp +match(status) | on( + !val<200> >> "error", // !p == neg(p) + (lit(301) || lit(302)) >> "redirect", // (a||b) == any(a, b) + (pred(is_json) && !lit(0)) >> "json", // (a&&b) == all(a, b) + _ >> "ok" +); +``` + +The operators only accept pattern operands, so guard-level `&&` / `||` +inside `[...]` keep their existing meaning. Note that `>>` binds +tighter than `||` and `&&`, so combined patterns need parentheses in a +case; unary `!` needs none. + +--- + +## Internal Improvements + +- CI: commit-style PR validation, clang-format check, LLVM + source-based coverage, and a fix letting docs-only PRs satisfy + branch protection. +- Bench: compile-time translation units are generated into the build + tree instead of the source tree. +- Docs: contributing guide now documents the CI-enforced PR rules. + +--- + +## Migration Guide + +### `PTN_LET` / `PTN_WHERE` + +```cpp +// v0.9.3 +auto g1 = PTN_LET(v, v == 1); +auto g2 = PTN_WHERE((x, y), x < y); + +// v0.9.4 — single bound value: use `_` +$[_ == 1] >> ...; + +// v0.9.4 — multiple bound values: declare names once +PTN_BIND(Point, x, y); +$(has<&Point::x, &Point::y>)[x < y] >> ...; +``` + +### `arg` / `_0` / `__` + +```cpp +// v0.9.3 +$[_0 > 0] >> ...; +$(has<&Point::x, &Point::y>)[arg<0> < arg<1>] >> ...; + +// v0.9.4 +$[_ > 0] >> ...; +PTN_BIND(Point, x, y); +$(has<&Point::x, &Point::y>)[x < y] >> ...; +``` + +### Alias-style `PTN_BIND` names + +```cpp +// main-between-releases only (never in a tagged release): +PTN_BIND(Point, point_x, point_y); // alias names + +// v0.9.4 — names must be members of Point: +PTN_BIND(Point, x, y); +``` diff --git a/docs/roadmap.md b/docs/roadmap.md index f8a3530..5e0477a 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -11,9 +11,18 @@ Status labels: ## FINISHED +Completed in [v0.9.4](changelog/v0.9.4.md): + +- `PTN_BIND(Type, names...)` member-anchored named guard + placeholders (one to ten names), replacing the positional guard + APIs (`__`, `_0`, `arg`, `PTN_LET`, `PTN_WHERE`). +- Block-scope `PTN_BIND` names usable inside `PTN_ON`. +- Pattern operator sugar: `!p`, `(a || b)`, `(a && b)`. + Completed in [v0.9.3](changelog/v0.9.3.md): - `pred(callable)` predicate pattern for lifting arbitrary unary predicates into first-class patterns. +- `neg(p)` negation pattern. Completed in [v0.9.2](changelog/v0.9.2.md): @@ -30,54 +39,7 @@ Completed in [v0.9.1](changelog/v0.9.1.md): ## WIP -Current workstream for upcoming releases. - -### `neg(p)` — negation pattern - -Invert the result of a sub-pattern. - -```cpp -match(x) | on( - neg(val<0>) >> "non-zero", - _ >> "zero" -); -``` - ---- - -### `PTN_BIND` arity 10 — chained arity macros - -Raise the named-placeholder limit from 5 to 10 member names and -refactor the arity macros into chained composition -(`PTN_BIND_N` = `PTN_BIND_{N-1}` + one declaration), so future -extensions cost one short macro per level. See PR #44. - ---- - -### Member-anchored `PTN_BIND` placeholders - -`PTN_BIND(Type, ...)` names expand to `member_t<&Type::name>` -instead of positional `arg_t`. Guards resolve each name to the -position of its member in the `has<...>` member list at compile -time: - -- names follow members, so `has<...>` order no longer matters; -- misspelled member names fail at the `PTN_BIND` line; -- a name used with a `has<...>` that lacks its member fails a - static_assert. - -This also settles the previously deferred `Type`-validation item -without static reflection. - ---- - -### Pattern operator sugar — `!p`, `(a || b)`, `(a && b)` - -Operator forms of the combinators: `!p` for `neg(p)`, `(a || b)` for -`any(a, b)`, and `(a && b)` for `all(a, b)`. The overloads live in -`ptn::pat::base` so ADL finds them for every pattern via the shared -`pattern_base` base class, and they reject guard predicates so the -guard-level `&&` / `||` semantics are untouched. +No active workstream. See NEXT for candidates. --- diff --git a/mkdocs.yml b/mkdocs.yml index 0d39fc7..47e4c03 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -98,6 +98,8 @@ nav: - Changelog: - Releases: changelog/releases.md + - v0.9.4: changelog/v0.9.4.md + - v0.9.3: changelog/v0.9.3.md - v0.9.2: changelog/v0.9.2.md - v0.9.1: changelog/v0.9.1.md - v0.9.0: changelog/v0.9.0.md diff --git a/packaging/vcpkg/vcpkg.json b/packaging/vcpkg/vcpkg.json index e337aca..df8313e 100644 --- a/packaging/vcpkg/vcpkg.json +++ b/packaging/vcpkg/vcpkg.json @@ -1,6 +1,6 @@ { "name": "patternia", - "version": "0.9.2", + "version": "0.9.4", "description": "Header-only pattern matching library for modern C++", "homepage": "https://github.com/SentoMK/patternia", "license": "MIT",