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
32 changes: 32 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ Pull request titles should follow the same style as commit subjects, such as
`feat(pattern): add case-insensitive string matching` or
`fix(eval): correct match_result type inference`.

Pull requests are validated automatically by CI
(`.github/workflows/validate.yml`). Requirements:

- **PR title** must follow the conventional commit format:
`type(scope): description`.
- **PR body** must be at least 50 characters and contain three
sections, each as a bold header on its own line:
- `**Summary**` — overview of the change
- `**Changes**` — bullet list of what changed
- `**Testing**` — how the change was verified
- **Exactly one commit** per pull request. Pull requests are
squash-merged, so a single-commit branch keeps the result
predictable:

```bash
git reset --soft $(git merge-base HEAD origin/main)
git commit -m 'type(scope): description'
git push --force-with-lease
```

### 2. Discuss First

For non-trivial changes (new features, API changes, or behavior modifications),
Expand Down Expand Up @@ -88,6 +108,18 @@ Suggested body sections:
- `Tests`
- `Notes`

The subject line is checked mechanically by CI
(`scripts/check_commit_msg.py`):

- Description uses the imperative mood ("add", not "added"/"adds").
- Description starts lowercase and has no trailing period.
- Description is specific, not a vague placeholder
("fix bug", "wip", "update").
- Subjects over 72 characters trigger a warning (aim for 50-72).

Prose lines in the body should wrap at 72 characters; CI enforces
this as well (bullet and indented lines are exempt).

Example:

```
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ int magnitude2(const Point &p) {
}
```

### Structural match with named placeholders

Declare readable names once with `PTN_BIND` (one to ten names), then
use them directly in guard expressions:

```cpp
using namespace ptn;

struct Point { int x; int y; };
PTN_BIND(Point, x, y);

bool on_circle_radius5(const Point &p) {
return match(p) | on(
$(has<&Point::x, &Point::y>)[x * x + y * y == 25] >> true,
_ >> false
);
}
```

### Variant match

```cpp
Expand Down
53 changes: 53 additions & 0 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ match(x) | on(

---

### `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.

---

## NEXT

Potential follow-up items after current WIP scope is stabilized.
Expand All @@ -63,10 +72,54 @@ match(v) | on(

---

### Multi-subject matching — `match(a, b)` with slot composition

Match on combinations of values, in the spirit of Rust's
`match (a, b)`. `match(a, b)` packs the subjects into a tuple; a
slot-wise pattern (working name `tup(...)`, alternative `each(...)`)
matches each position with its own sub-pattern and flattens the
bindings in order:

```cpp
match(x, y) | on(
tup(lit(0), lit(0)) >> "origin",
tup(lit(0), _) >> "on y axis",
tup(_, lit(0)) >> "on x axis",
_ >> "elsewhere"
);
```

Design notes:

- Pure front-end sugar: the engine is untouched; `tup` is a pattern
combinator in the same family as `any`/`all`.
- Shares the slot-composition machinery (per-slot match/bind plus
binding flattening) with `some`/`none`. The two should be designed
together so their binding semantics stay consistent.

---

## Design Principles for New API

- Stateless compile-time patterns should be variable templates, not
function templates that return default-constructed objects.
- Function template forms are reserved for patterns that require runtime
arguments (e.g., `lit(value)`, `lit_ci(value)`, `rng(lo, hi)`).
- Names should be short, lowercase, and read naturally in the DSL.

## Considered and Declined

Syntax ideas that were evaluated and intentionally rejected, kept
here so they are not re-proposed without new motivation.

- **Guard `operator!`**: intentionally not provided; rewrite the
comparison instead (e.g. `!(x < y)` becomes `y <= x`).
- **Member-call placeholders** (`_.size() > 3`): not expressible —
C++ has no `operator.` overloading, so `.size()` cannot become an
expression node. Use `pred` with a lambda.
- **Chained comparisons** (`1 <= _ <= 10`): breaks predicate
semantics and produces unreadable diagnostics. Use `rng(lo, hi)`
with explicit range modes.
- **`PTN_BIND` `Type` validation**: deferred. The `Type` argument is
documentary for now; member-name checking becomes feasible with
static reflection (C++26).
Loading