From 3895f429f1947aac1d2465d89c7bcd3ce38fc70e Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 27 Jul 2026 21:04:50 +0800 Subject: docs(sidebar): archive resolved issues with _ prefix Archive three resolved issues by renaming files with an _ prefix and adding archival note banners --- docs/dev/_sidebar.md | 6 +- docs/dev/pages/issues/_add-picker2.md | 104 +++++++++++++++++++++++++ docs/dev/pages/issues/_remove-r-print-macro.md | 101 ++++++++++++++++++++++++ docs/dev/pages/issues/_the-mod-pathfinder.md | 68 ++++++++++++++++ docs/dev/pages/issues/add-picker2.md | 100 ------------------------ docs/dev/pages/issues/remove-r-print-macro.md | 97 ----------------------- docs/dev/pages/issues/the-mod-pathfinder.md | 64 --------------- 7 files changed, 276 insertions(+), 264 deletions(-) create mode 100644 docs/dev/pages/issues/_add-picker2.md create mode 100644 docs/dev/pages/issues/_remove-r-print-macro.md create mode 100644 docs/dev/pages/issues/_the-mod-pathfinder.md delete mode 100644 docs/dev/pages/issues/add-picker2.md delete mode 100644 docs/dev/pages/issues/remove-r-print-macro.md delete mode 100644 docs/dev/pages/issues/the-mod-pathfinder.md (limited to 'docs/dev') diff --git a/docs/dev/_sidebar.md b/docs/dev/_sidebar.md index 6b58d56..576a2cf 100644 --- a/docs/dev/_sidebar.md +++ b/docs/dev/_sidebar.md @@ -1,8 +1,8 @@ - [Welcome!](README) * ❓ Issues - * [The Picker2 Arguments Parser](pages/issues/add-picker2) - * [Remove r_print! and r_println! Macros](pages/issues/remove-r-print-macro) - * [The Mod Pathfinder](pages/issues/the-mod-pathfinder) + * [[Solved] The Picker2 Arguments Parser](pages/issues/_add-picker2) + * [[Solved] Remove r_print! and r_println! Macros](pages/issues/_remove-r-print-macro) + * [[Solved] The Mod Pathfinder](pages/issues/_the-mod-pathfinder) * [Some Situations Where You'd Be Like "Shit!"](pages/issues/the-shit-time) * 💡 Abouts * [AI Translation Rule](pages/abouts/ai-translation-rule) diff --git a/docs/dev/pages/issues/_add-picker2.md b/docs/dev/pages/issues/_add-picker2.md new file mode 100644 index 0000000..fcd6786 --- /dev/null +++ b/docs/dev/pages/issues/_add-picker2.md @@ -0,0 +1,104 @@ +

[Solved] The Picker2 Arguments Parser

+

+ A smarter, faster alternative to Picker +

+ +> [!NOTE] +> +> This issue has been fully resolved and is thus archived for preservation. + +## Intro + +Mingling's `parser` feature is a temporary argument parsing solution created in the early stages of the project. While it can handle basic argument parsing tasks, its functionality is incomplete and has many limitations. + +This article aims to propose the design and development plan for the new Picker2 (feature name: `picker`). + +### Picker2 Expected Syntax + +1. **Pos args & flag args no longer depend on parsing order:** In `parser`, all flag args must be parsed before pos args. Picker2 removes this restriction. +2. **Declare flags with declarative macros:** Use `positional!()`, `flag![-X, --x]` etc. to declare flags — cleaner and more concise. +3. **One-shot `parse()` replaces step-by-step `unpack()`:** Defers the entire parsing flow to the final step, leaving more room for compile-time optimization. + +```rust +#[chain] +fn handle_hello(args: EntryHello) { + let parsed = args + .pick::(positional!()) + .pick::(flag![--help, -h]) + .parse(); +} +``` + +4. **Post-processing & routing control:** Use `after`, `after_route` to control post-processing logic. The route type is explicitly specified by the first `route` method. + +```rust +#[chain] +fn handle_hello(args: EntryHello) { + let parsed = args + .pick::(positional!()) + .after(|v| format!("\"{}\"", v)) // post-processing + .parse(); +} +``` + +```rust +#[chain] +fn handle_hello(args: EntryHello) -> Next { + // requires impl Grouped<_> + // | + let parsed = args // vvvvvvvvvvvvvvvvvvv + .pick_route::(positional!(), ErrorNoNameProvided) + .after_route(|v| Ok(format!("\"{}\"", v))) // post-process & route + .parse(); + let routed_parsed = route!(parsed); + empty_result!() +} +``` + +5. **Keep the `Pickable` Trait** +6. **Keep `PickableEnum` & provide a derive macro** +7. **Use `pick_optional`, `pick_vec` instead of implementing trait separately for `Option`, `Vec`** +8. **Use `pick_flag` instead of `pick::`** +9. **Provide `YesOrNo`, `TrueOrFalse` etc. that implement the `BoolFlag` trait for explicit bool extraction** +10. **Provide a `MultiFlag` derive macro, supporting arg modes like `pacman`** + +```rust +#[derive(MultiFlag)] +pub struct SomeToggles { + // default [-i] + pub install: bool, + + #[flag('U')] + pub uninstall: bool, + + #[flag('X')] + pub execute: bool, +} + +// Auto-implements Pickable, supports parsing args like `-iUX` +``` + +11. **Support multiple arg formats:** e.g. `--key=value`, `/Key=Value`, controlled by global config `PickerConfig` (or: `Picker::from_with_cfg(prev.inner, PickerConfig::default())`) + +12. `.parse()` no longer returns a bare tuple, but instead returns: + +```rust +pub struct PickerResult { + pub result: Tuple, + pub remains_argument: Arguments, +} +``` + +--- + +## 🕘 Progress + +- [x] In Progress + - [x] Added `Picker` struct and related call chain + - [x] Added `parselib` providing parsing logic + - [x] Added `Pickable` for extensibility + - [x] Comprehensive testing! + - [x] Improve documentation + - [x] Add examples + - [x] Update README +- [x] Complete diff --git a/docs/dev/pages/issues/_remove-r-print-macro.md b/docs/dev/pages/issues/_remove-r-print-macro.md new file mode 100644 index 0000000..1aed5f7 --- /dev/null +++ b/docs/dev/pages/issues/_remove-r-print-macro.md @@ -0,0 +1,101 @@ +

[Solved] Remove r_print! and r_println! Macros

+ +> [!NOTE] +> +> This issue has been fully resolved and is thus archived for preservation. + +`r_print!` and `r_println!` are important macros in Mingling for use inside `#[help]` and `#[renderer]` functions, but their implementation is not clean: they implicitly introduce a `__renderer_inner_result` field. While this might look elegant at the API level, it is **incorrect** and even **objectionable**. + +## Why **Objectionable**? + +Because you can't define declarative macros with `macro_rules` that wrap them. + +This is because `r_println!` depends on the implicit variable `__renderer_inner_result` injected by the `#[renderer]` proc macro into the function body. However, when a `macro_rules` declarative macro expands, **its internal code is placed in the caller's context**, which does not contain `__renderer_inner_result` — that variable only exists within the direct scope of the function body processed by `#[renderer]`. + +Let's look at some code to see why: + +```rust +// Suppose you want to write a wrapper macro: +macro_rules! my_println { + ($($arg:tt)*) => { + // When expanded here, the context is the call site of my_println!, + // not the location where the renderer function's injected variables live. + // So __renderer_inner_result is NOT visible here! + r_println!("Custom: {}", format!($($arg)*)); + }; +} + +#[renderer] +fn render_something(_p: ResultSomething) { + // Although this function body has __renderer_inner_result injected, + // the code from my_println! does NOT expand "inside this function body" — + // macro_rules expansion is essentially text replacement. The replaced code + // lives at the line where my_println! is called, and any variables referenced + // inside that macro must resolve to identifiers accessible at the call site. + // __renderer_inner_result is not a public, path-accessible variable; + // it's a hygienic local variable generated by the `#[renderer]` macro, + // and external macros cannot directly access it by name. + my_println!("{}", box_val); // Compile error: cannot find __renderer_inner_result +} +``` + +## Deeper Issues + +I have to admit, this is an early design flaw. After re-examining the code, I found the problem goes beyond "can't be wrapped". + +This isn't just a "can't wrap" issue — it reflects that `r_println!`'s design fundamentally violates Rust's macro hygiene principles: + +- **Implicit dependency**: Users of the macro must know that a variable named `__renderer_inner_result` exists — but this variable is neither part of the public API nor explicitly documented anywhere. +- **Scope leakage**: Variables injected by a proc macro should be confined to the scope processed by that macro. But `r_println!` attempts to make that variable accessible across macro calls, which effectively breaks Rust's identifier hygiene. +- **Non-composable**: Any attempt to wrap `r_println!` will fail, because declarative macros cannot "pass through" access to implicit variables. Even using a proc macro to wrap it would encounter similar hygiene issues. + +## Desired New Syntax + +I've designed two alternative approaches and will choose based on actual needs. + +### Option 1: Explicit Return + +```rust +#[renderer] +fn render_something(prev: ResultSomething) -> RenderResult { + let mut result = RenderResult::new(); + result.println(prev.to_string()); + // or + write!(result, "{}", prev.to_string()); + + result // return here +} +``` + +Clear boundaries — the entire rendering process is confined within the function body decorated by `#[help]` or `#[renderer]`, without introducing extra out-of-scope dependencies. The trade-off is slightly more boilerplate compared to the original approach. + +### Option 2: Resource Injection + +```rust +#[renderer] +fn render_something(prev: ResultSomething, result: &mut ResRenderResult) { + result.println(prev.to_string()); + // or + write!(result, "{}", prev.to_string()); + + result // return here +} +``` + +More flexible, but blurs the boundary between logic functions like `#[chain]` and rendering functions like `#[help]`. + +### Preferred Direction + +I lean toward **Option 1 (Explicit Return)**. There's no need to turn `RenderResult` into `ResRenderResult` as a global resource. + +As for rendering in logic functions like `#[chain]`, that should be handled by a separate system — not discussed here. + +## 🕘 Progress + +- [x] In Progress + - [x] Remove `r_println!` and `r_print!` macros + - [x] Modify `#[renderer]` and `#[help]` macros, remove implicit injection + - [x] Provide **no-return-value mode** and **RenderResult return value mode** for `#[renderer]` and `#[help]` macros + - [x] Add new simplified syntax + - [x] Update documentation and test cases, ensure **all pass** +- [x] Complete diff --git a/docs/dev/pages/issues/_the-mod-pathfinder.md b/docs/dev/pages/issues/_the-mod-pathfinder.md new file mode 100644 index 0000000..8869beb --- /dev/null +++ b/docs/dev/pages/issues/_the-mod-pathfinder.md @@ -0,0 +1,68 @@ +

[Solved] The Mod Pathfinder

+

+ A build-time analyzer that computes full module paths for Mingling types, resolving path ambiguity in macros. +

+ +> [!NOTE] +> +> This issue has been fully resolved and is thus archived for preservation. + +## Background + +Currently, `gen_program!` requires all involved types to be `use`d within their module. Mingling lacks a complete module path analyzer — waiting for `proc-macro-span` to stabilize is clearly not practical, so a solution for obtaining module paths is needed. + +## Solution + +We plan to create an analyzer called `mingling-mod-pathf`, enabled via Mingling's `"pathf"` feature, to compute the full paths of all defined Mingling types. + +### Behavior When Enabled + +**`mingling_core`**: If the `builds` feature is enabled, introduces the `mingling::build::analyze_and_build_type_mapping()` method (analysis completed at Build-Time) + +**`mingling_macros`**: Modifies the behavior of the `gen_program!()` macro — automatically loads the mapping table from the analysis file generated by `mingling::build::analyze_and_build_type_mapping()`, and directly uses the full `mod::path` instead of `TypeName` (injected at Compile-Time) + +## Challenges + +`mingling-mod-pathf` needs to understand **all** Mingling syntax features. +Fortunately, Mingling's type creation is almost always explicit: + +```rust +mod sub { + mingling::macros::pack!(ResultMyName = String); // directly creates ..::sub::ResultMyName +} +``` + +There are a few exceptions, such as the implicit Dispatcher provided by `extra_macros`, but these can be inferred from the node name: + +```rust +dispatcher!("remote.add"); // although the type is unknown, we can infer CMDRemoteAdd and EntryRemoteAdd +``` + +And also `#[program_setup]`: + +```rust +#[program_setup] // can infer CustomSetup from the function name `custom_setup` +fn custom_setup(program: &mut Program) { + program.with_dispatchers((CMD1, CMD2, CMD3, CMD4, CMD5)); +} +``` + +## Pathf Output Format + +Uses TOML key-value pairs, formatted as follows: + +```toml +ResultRemoteAdd = "crate::mymod::ResultRemoteAdd" +``` + +Recommended storage location is under the target directory: + +``` +/target/{target}/{crate-name}/type-mapping.toml +``` + +## Other Issues + +This solution is limited to Mingling's own syntax system. If types like `dispatcher!`, `pack!` are indirectly expanded through macros, the analyzer will not be able to discover them. + +However, this approach solves the current main pain points, so this issue can be set aside for now and addressed later. diff --git a/docs/dev/pages/issues/add-picker2.md b/docs/dev/pages/issues/add-picker2.md deleted file mode 100644 index a2b5a10..0000000 --- a/docs/dev/pages/issues/add-picker2.md +++ /dev/null @@ -1,100 +0,0 @@ -

The Picker2 Arguments Parser

-

- A smarter, faster alternative to Picker -

- -## Intro - -Mingling's `parser` feature is a temporary argument parsing solution created in the early stages of the project. While it can handle basic argument parsing tasks, its functionality is incomplete and has many limitations. - -This article aims to propose the design and development plan for the new Picker2 (feature name: `picker`). - -### Picker2 Expected Syntax - -1. **Pos args & flag args no longer depend on parsing order:** In `parser`, all flag args must be parsed before pos args. Picker2 removes this restriction. -2. **Declare flags with declarative macros:** Use `positional!()`, `flag![-X, --x]` etc. to declare flags — cleaner and more concise. -3. **One-shot `parse()` replaces step-by-step `unpack()`:** Defers the entire parsing flow to the final step, leaving more room for compile-time optimization. - -```rust -#[chain] -fn handle_hello(args: EntryHello) { - let parsed = args - .pick::(positional!()) - .pick::(flag![--help, -h]) - .parse(); -} -``` - -4. **Post-processing & routing control:** Use `after`, `after_route` to control post-processing logic. The route type is explicitly specified by the first `route` method. - -```rust -#[chain] -fn handle_hello(args: EntryHello) { - let parsed = args - .pick::(positional!()) - .after(|v| format!("\"{}\"", v)) // post-processing - .parse(); -} -``` - -```rust -#[chain] -fn handle_hello(args: EntryHello) -> Next { - // requires impl Grouped<_> - // | - let parsed = args // vvvvvvvvvvvvvvvvvvv - .pick_route::(positional!(), ErrorNoNameProvided) - .after_route(|v| Ok(format!("\"{}\"", v))) // post-process & route - .parse(); - let routed_parsed = route!(parsed); - empty_result!() -} -``` - -5. **Keep the `Pickable` Trait** -6. **Keep `PickableEnum` & provide a derive macro** -7. **Use `pick_optional`, `pick_vec` instead of implementing trait separately for `Option`, `Vec`** -8. **Use `pick_flag` instead of `pick::`** -9. **Provide `YesOrNo`, `TrueOrFalse` etc. that implement the `BoolFlag` trait for explicit bool extraction** -10. **Provide a `MultiFlag` derive macro, supporting arg modes like `pacman`** - -```rust -#[derive(MultiFlag)] -pub struct SomeToggles { - // default [-i] - pub install: bool, - - #[flag('U')] - pub uninstall: bool, - - #[flag('X')] - pub execute: bool, -} - -// Auto-implements Pickable, supports parsing args like `-iUX` -``` - -11. **Support multiple arg formats:** e.g. `--key=value`, `/Key=Value`, controlled by global config `PickerConfig` (or: `Picker::from_with_cfg(prev.inner, PickerConfig::default())`) - -12. `.parse()` no longer returns a bare tuple, but instead returns: - -```rust -pub struct PickerResult { - pub result: Tuple, - pub remains_argument: Arguments, -} -``` - ---- - -## 🕘 Progress - -- [x] In Progress - - [x] Added `Picker` struct and related call chain - - [x] Added `parselib` providing parsing logic - - [x] Added `Pickable` for extensibility - - [x] Comprehensive testing! - - [ ] Improve documentation - - [x] Add examples - - [ ] Update README -- [ ] Complete diff --git a/docs/dev/pages/issues/remove-r-print-macro.md b/docs/dev/pages/issues/remove-r-print-macro.md deleted file mode 100644 index 43d2740..0000000 --- a/docs/dev/pages/issues/remove-r-print-macro.md +++ /dev/null @@ -1,97 +0,0 @@ -

Remove r_print! and r_println! Macros

- -`r_print!` and `r_println!` are important macros in Mingling for use inside `#[help]` and `#[renderer]` functions, but their implementation is not clean: they implicitly introduce a `__renderer_inner_result` field. While this might look elegant at the API level, it is **incorrect** and even **objectionable**. - -## Why **Objectionable**? - -Because you can't define declarative macros with `macro_rules` that wrap them. - -This is because `r_println!` depends on the implicit variable `__renderer_inner_result` injected by the `#[renderer]` proc macro into the function body. However, when a `macro_rules` declarative macro expands, **its internal code is placed in the caller's context**, which does not contain `__renderer_inner_result` — that variable only exists within the direct scope of the function body processed by `#[renderer]`. - -Let's look at some code to see why: - -```rust -// Suppose you want to write a wrapper macro: -macro_rules! my_println { - ($($arg:tt)*) => { - // When expanded here, the context is the call site of my_println!, - // not the location where the renderer function's injected variables live. - // So __renderer_inner_result is NOT visible here! - r_println!("Custom: {}", format!($($arg)*)); - }; -} - -#[renderer] -fn render_something(_p: ResultSomething) { - // Although this function body has __renderer_inner_result injected, - // the code from my_println! does NOT expand "inside this function body" — - // macro_rules expansion is essentially text replacement. The replaced code - // lives at the line where my_println! is called, and any variables referenced - // inside that macro must resolve to identifiers accessible at the call site. - // __renderer_inner_result is not a public, path-accessible variable; - // it's a hygienic local variable generated by the `#[renderer]` macro, - // and external macros cannot directly access it by name. - my_println!("{}", box_val); // Compile error: cannot find __renderer_inner_result -} -``` - -## Deeper Issues - -I have to admit, this is an early design flaw. After re-examining the code, I found the problem goes beyond "can't be wrapped". - -This isn't just a "can't wrap" issue — it reflects that `r_println!`'s design fundamentally violates Rust's macro hygiene principles: - -- **Implicit dependency**: Users of the macro must know that a variable named `__renderer_inner_result` exists — but this variable is neither part of the public API nor explicitly documented anywhere. -- **Scope leakage**: Variables injected by a proc macro should be confined to the scope processed by that macro. But `r_println!` attempts to make that variable accessible across macro calls, which effectively breaks Rust's identifier hygiene. -- **Non-composable**: Any attempt to wrap `r_println!` will fail, because declarative macros cannot "pass through" access to implicit variables. Even using a proc macro to wrap it would encounter similar hygiene issues. - -## Desired New Syntax - -I've designed two alternative approaches and will choose based on actual needs. - -### Option 1: Explicit Return - -```rust -#[renderer] -fn render_something(prev: ResultSomething) -> RenderResult { - let mut result = RenderResult::new(); - result.println(prev.to_string()); - // or - write!(result, "{}", prev.to_string()); - - result // return here -} -``` - -Clear boundaries — the entire rendering process is confined within the function body decorated by `#[help]` or `#[renderer]`, without introducing extra out-of-scope dependencies. The trade-off is slightly more boilerplate compared to the original approach. - -### Option 2: Resource Injection - -```rust -#[renderer] -fn render_something(prev: ResultSomething, result: &mut ResRenderResult) { - result.println(prev.to_string()); - // or - write!(result, "{}", prev.to_string()); - - result // return here -} -``` - -More flexible, but blurs the boundary between logic functions like `#[chain]` and rendering functions like `#[help]`. - -### Preferred Direction - -I lean toward **Option 1 (Explicit Return)**. There's no need to turn `RenderResult` into `ResRenderResult` as a global resource. - -As for rendering in logic functions like `#[chain]`, that should be handled by a separate system — not discussed here. - -## 🕘 Progress - -- [x] In Progress - - [x] Remove `r_println!` and `r_print!` macros - - [x] Modify `#[renderer]` and `#[help]` macros, remove implicit injection - - [x] Provide **no-return-value mode** and **RenderResult return value mode** for `#[renderer]` and `#[help]` macros - - [x] Add new simplified syntax - - [x] Update documentation and test cases, ensure **all pass** -- [x] Complete diff --git a/docs/dev/pages/issues/the-mod-pathfinder.md b/docs/dev/pages/issues/the-mod-pathfinder.md deleted file mode 100644 index 676251d..0000000 --- a/docs/dev/pages/issues/the-mod-pathfinder.md +++ /dev/null @@ -1,64 +0,0 @@ -

The Mod Pathfinder

-

- A build-time analyzer that computes full module paths for Mingling types, resolving path ambiguity in macros. -

- -## Background - -Currently, `gen_program!` requires all involved types to be `use`d within their module. Mingling lacks a complete module path analyzer — waiting for `proc-macro-span` to stabilize is clearly not practical, so a solution for obtaining module paths is needed. - -## Solution - -We plan to create an analyzer called `mingling-mod-pathf`, enabled via Mingling's `"pathf"` feature, to compute the full paths of all defined Mingling types. - -### Behavior When Enabled - -**`mingling_core`**: If the `builds` feature is enabled, introduces the `mingling::build::analyze_and_build_type_mapping()` method (analysis completed at Build-Time) - -**`mingling_macros`**: Modifies the behavior of the `gen_program!()` macro — automatically loads the mapping table from the analysis file generated by `mingling::build::analyze_and_build_type_mapping()`, and directly uses the full `mod::path` instead of `TypeName` (injected at Compile-Time) - -## Challenges - -`mingling-mod-pathf` needs to understand **all** Mingling syntax features. -Fortunately, Mingling's type creation is almost always explicit: - -```rust -mod sub { - mingling::macros::pack!(ResultMyName = String); // directly creates ..::sub::ResultMyName -} -``` - -There are a few exceptions, such as the implicit Dispatcher provided by `extra_macros`, but these can be inferred from the node name: - -```rust -dispatcher!("remote.add"); // although the type is unknown, we can infer CMDRemoteAdd and EntryRemoteAdd -``` - -And also `#[program_setup]`: - -```rust -#[program_setup] // can infer CustomSetup from the function name `custom_setup` -fn custom_setup(program: &mut Program) { - program.with_dispatchers((CMD1, CMD2, CMD3, CMD4, CMD5)); -} -``` - -## Pathf Output Format - -Uses TOML key-value pairs, formatted as follows: - -```toml -ResultRemoteAdd = "crate::mymod::ResultRemoteAdd" -``` - -Recommended storage location is under the target directory: - -``` -/target/{target}/{crate-name}/type-mapping.toml -``` - -## Other Issues - -This solution is limited to Mingling's own syntax system. If types like `dispatcher!`, `pack!` are indirectly expanded through macros, the analyzer will not be able to discover them. - -However, this approach solves the current main pain points, so this issue can be set aside for now and addressed later. -- cgit