[Lean Squad] feat(fv): Task 2 — informal spec for CommandLineParser.ParseOptionAndSeparators#7919
Conversation
…Separators
Extracts a precise informal specification for the ParseOptionAndSeparators
local function in CommandLineParser. Documents:
- Pure string-split function: first-occurrence of ':' or '=' delimiter
- 16 named properties across 5 groups (no-delimiter, delimiter-present,
reconstructibility, determinism, edge cases)
- TrimStart('-') normalization of option-name prefix
- Edge case: empty option name when delimiter immediately follows dashes
(e.g. '--:value' produces currentOption = '')
- Interaction with TryUnescape (caller passes currentArg after Trim())
- Approximations for Lean 4 model (List.dropWhile, List.findIdx?)
- 5 concrete Lean examples for #eval tests
Advances CommandLineParser.ParseOptionAndSeparators from phase 1 to phase 2.
Updates TARGETS.md to reflect current phase state of all 7 targets.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds/updates Lean Squad formal-verification documentation for command-line parsing, specifically capturing an informal spec for the CommandLineParser.ParseOptionAndSeparators split semantics and reflecting that progress in the FV target tracker.
Changes:
- Added an informal specification doc for
CommandLineParser.ParseOptionAndSeparators. - Updated
formal-verification/TARGETS.mdto mark additional targets as Phase 2 (informal spec extracted) and refreshed priority notes.
Show a summary per file
| File | Description |
|---|---|
| formal-verification/specs/commandlineparser_parseoptionandseparators_informal.md | New informal spec describing split behavior on : / = and Lean modeling notes |
| formal-verification/TARGETS.md | Updates FV target phases/status and priority-order notes |
Copilot's findings
Comments suppressed due to low confidence (3)
formal-verification/specs/commandlineparser_parseoptionandseparators_informal.md:180
- The “Open Question 2” section includes an in-line correction (“Wait — actually …”) and intermediate reasoning that makes the spec harder to read. Consider rewriting it as a concise, final statement of the intended behavior (e.g., “splits at the first raw
:/=; quoting is not interpreted by this function”).
### Open Question 2 — Delimiter within quoted value
`"--option='a:b'"` produces `currentOption = "option"` and `currentArg = "'a:b'"`. The colon is inside quotes, but `ParseOptionAndSeparators` does NOT understand quoting — it splits on the first raw `:`. For `"--option:a"`, split occurs before seeing quotes. For `"--option='a:b'"`, the first `:` is index 9 (before `'a`), so `currentArg = "'a:b'"`. Wait — actually `"--option='a:b'"` has `=` at index 8, not `:` first. So `currentOption = "option"`, `currentArg = "'a:b'"`. This is correct. But `"--option:'a:b'"` would split at the first `:` (index 8), giving `currentOption = "option"` and `currentArg = "'a:b'"`. The second `:` is preserved in the value. This seems correct.
formal-verification/specs/commandlineparser_parseoptionandseparators_informal.md:114
- Property 12 says “Delimiter priority is lexicographic order”, but the behavior described is positional/leftmost.
IndexOfAnydoes not choose based on character ordering; it returns the smallest index of any of the searched characters, regardless of whether it’s:or=.
11. **Purity**: `ParseOptionAndSeparators` is a pure function — same input always yields same output.
12. **Delimiter priority is lexicographic order**: `IndexOfAny` finds the leftmost occurrence of either delimiter character. The type of delimiter (`:` vs `=`) is irrelevant; only position matters.
13. **Which delimiter came first determines the split**: If `arg = "x=y:z"`, then `currentOption = "x"` and `currentArg = "y:z"`. If `arg = "x:y=z"`, then `currentOption = "x"` and `currentArg = "y=z"`.
formal-verification/specs/commandlineparser_parseoptionandseparators_informal.md:173
- The recommendation in “Issue 1 — Empty option name not rejected” suggests setting
currentOption = null, but earlier sections (Data Model/Invariants) assertcurrentOptionis never null. Please align the recommendation with the stated model (e.g., keepcurrentOptionnon-null and report an error via the parse result), or update the invariants/model to reflect a nullable option name if that’s the intended contract.
### Issue 1 — Empty option name not rejected
**Observation**: The function does not validate that `currentOption` is non-empty after `TrimStart('-')`. Inputs like `"--:value"` or `"--="` produce `currentOption = ""`, which is then treated as a valid option name by the caller. The caller does not re-validate.
**Consequence**: The parser silently creates a `CommandLineParseOption` with option name `""` instead of reporting an error. Attempting to look up this option in the registered options table will fail to find a match (but may produce an unhelpful error message downstream).
**Severity**: Minor / edge case. In practice, callers pass well-formed command lines. The preconditions exclude `--:` inputs via the `arg[2] != '-'` check only if we consider `:` as a non-dash character — which it is — but the preconditions do NOT exclude `--:` specifically.
**Recommendation**: Add a post-split guard: `if (string.IsNullOrEmpty(currentOption)) { errors.Add(...); currentOption = null; }`.
- Files reviewed: 2/2 changed files
- Comments generated: 2
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (2)
formal-verification/specs/commandlineparser_parseoptionandseparators_informal.md:146
- Invariant 3 (“The function never throws”) is only true under the non-null input precondition. As written, it reads like a total guarantee; passing
nullforargwould throw atarg.IndexOfAny(...). Please scope this invariant explicitly toarg != null(or restate it as “does not throw for any non-nullarg”).
1. `currentOption` is never `null` — it is always a `string` (possibly empty).
2. `currentArg` is `null` if and only if no delimiter character appears in `arg`.
3. The function never throws (no index-out-of-bounds; `arg[..delimiterIndex]` with `delimiterIndex ≥ 0` is always valid; `arg[(delimiterIndex + 1)..]` when `delimiterIndex = arg.Length - 1` yields `""`).
4. `currentOption` contains no `:` and no `=`.
formal-verification/specs/commandlineparser_parseoptionandseparators_informal.md:176
- The “Open Question 2” section contains a self-correction (“Wait — actually …”) and an intermediate incorrect index claim. For a formal-verification spec, this is confusing and easy to misread; please rewrite this paragraph to present the final, correct reasoning directly (optionally with one precise worked example per delimiter style).
### Open Question 2 — Delimiter within quoted value
`"--option='a:b'"` produces `currentOption = "option"` and `currentArg = "'a:b'"`. The colon is inside quotes, but `ParseOptionAndSeparators` does NOT understand quoting — it splits on the first raw `:`. For `"--option:a"`, split occurs before seeing quotes. For `"--option='a:b'"`, the first `:` is index 9 (before `'a`), so `currentArg = "'a:b'"`. Wait — actually `"--option='a:b'"` has `=` at index 8, not `:` first. So `currentOption = "option"`, `currentArg = "'a:b'"`. This is correct. But `"--option:'a:b'"` would split at the first `:` (index 8), giving `currentOption = "option"` and `currentArg = "'a:b'"`. The second `:` is preserved in the value. This seems correct.
- Files reviewed: 2/2 changed files
- Comments generated: 2
|
@copilot resolve the merge conflicts in this pull request |
Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Extract a precise informal specification for CommandLineParseResult.Equals, the structural-equality implementation for the command-line parse result type.
The spec documents:
Next: Task 3 — write ArgumentArity.lean (highest priority Lean target)
🔬 Lean Squad — automated FV agent
Fixes #7911 #7907