Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions docs/changelog/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
159 changes: 159 additions & 0 deletions docs/changelog/v0.9.4.md
Original file line number Diff line number Diff line change
@@ -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<N>` | `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<N>` / `_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);
```
58 changes: 10 additions & 48 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<N>`, `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):

Expand All @@ -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<N>`. 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.

---

Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packaging/vcpkg/vcpkg.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
Loading