From 48907e3b62c8ee0d889a1eec88c8370dc34aaa1b Mon Sep 17 00:00:00 2001 From: sentomk Date: Sat, 1 Aug 2026 14:04:17 +0800 Subject: [PATCH] docs: sync contributing rules and roadmap with CI and plans Problem - CONTRIBUTING.md did not document the PR requirements that validate.yml enforces mechanically, so contributors learned about them only from failing CI. - README showed no PTN_BIND example despite highlighting it. - roadmap.md did not record the multi-subject matching direction or the syntax ideas that were evaluated and rejected. Implementation - CONTRIBUTING.md: document PR title format, required PR body sections (**Summary**/**Changes**/**Testing**), the one-commit-per- PR squash convention, and the mechanically checked commit subject rules (imperative mood, lowercase, no trailing period, 72-char body wrap). - README.md: add a self-contained structural match example using PTN_BIND named placeholders in a guard; verified compilable. - roadmap.md: note the PTN_BIND arity-10 workstream under WIP, add multi-subject matching (match(a, b) + tup(...)) under NEXT with its relation to some/none, and add a Considered and Declined section for guard operator!, member-call placeholders, chained comparisons, and deferred PTN_BIND Type validation. Tests - Docs-only change; the new README snippet was compiled and run against the current headers with GCC in C++17 mode. --- CONTRIBUTING.md | 32 +++++++++++++++++++++++++++++ README.md | 19 ++++++++++++++++++ docs/roadmap.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 897123b..794318a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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), @@ -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: ``` diff --git a/README.md b/README.md index bad8c67..fed4936 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/roadmap.md b/docs/roadmap.md index 835dc80..f74e4bb 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -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. @@ -63,6 +72,33 @@ 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 @@ -70,3 +106,20 @@ match(v) | on( - 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).