- parse_do_body(loop_name: Option<&str>) — now validates that an op… #28
No reviewers
Labels
No labels
bug
dependencies
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
rust
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-rexx!28
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "end"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
…tional
END name matches the DO's control variable (case-insensitive). Mismatched
name on a controlled DO, or any name on a non-controlled DO (Simple /
Forever / Count / While / Until), raises RexxError::InvalidDataOnEnd (ANSI
Error 21). finish_do threads name.as_deref() through.
Code Review — END name validation (PR #28)
The core logic is correct:
loop_nameis threaded throughfinish_do→parse_do_bodyvianame.as_deref(), theeq_ignore_ascii_casecomparison is right, and the borrow split (end_symbol: Option<String>before callingself.advance()) is necessary and clean.RexxError::InvalidDataOnEnd => 21is confirmed correct inerror.rs. No correctness bugs found in the implementation itself.Three gaps worth addressing:
1. No integration test verifying "Error 21" appears in stderr
tests/phase2.rsEvery other parse-error test in this file uses the
run_rexx_fail→stderr.contains("Error N")pattern, e.g.:The new END name tests live only in the
parser.rsunit-test module. They verifyerr.error == RexxError::InvalidDataOnEnd(the Rust enum variant) but not what the interpreter actually prints. If the display impl forInvalidDataOnEndregresses — wrong number, wrong format — it would be invisible. Suggested additions tophase2.rs:2. Missing test: nested controlled DOs with END names
src/parser.rs(test module)No test covers nested loops where both ENDs carry names. The recursive call chain is:
A regression that passed the outer name down instead of the inner one would silently pass the current suite. Suggested tests:
3. Missing test: controlled DO with WHILE/UNTIL guard + END name
src/parser.rs(test module)bare_end_on_while_do_oktestsdo while 1(no control variable,name = None). There is no test for a controlled DO that also has a WHILE or UNTIL guard — a case wherename = Some("i")but the loop kind includes a guard:This exercises the path where
finish_dois called withname = Some("i")for a loop that also has a WHILE/UNTIL clause, confirming the name is correctly threaded through regardless of the loop'skind.No other issues found. The implementation is sound — these are test-coverage gaps only.
Code Review — PR #28: END-name validation
Summary: The implementation is correct. Error 21 is the right ANSI number, the case-insensitive match (
eq_ignore_ascii_case) is properly applied, nested-DO recursion handles eachEND [name]at the right stack frame, and LEAVE/ITERATE name comparison is sound by construction (bothtry_consume_symbol_nameatparser.rs:698andparse_controlled_doatparser.rs:478uppercase their symbols before storing, sosignal_matches'sln == nameateval.rs:1663always compares two uppercase strings).Issue 1 — Missing negative test coverage for
DO WHILE/DO UNTIL+ END name (test gap, not a code bug)src/parser.rs:531–577— TheNonearm of the match correctly fires Error 21 when a name follows END on a WHILE or UNTIL DO (both arrive viafinish_do(..., None)soloop_nameis alwaysNone). However the PR's eight DO checkpoints omit the two negative cases for these variants:There's a
bare_end_on_while_do_okpositive test but no corresponding negative, and no UNTIL tests at all. If someone later changesparse_doto pass a name for these variants the logic would silently invert with no regression signal. The integration suite intests/phase2.rsalso has no coverage for these two paths.Suggested additions (unit tests in
src/parser.rs, mirroring the existing pattern):And two matching
run_rexx_failchecks intests/phase2.rsasserting"Error 21".Issue 2 —
peek_kind()borrow lifetime exposes a latent inconsistency between DO body and SELECTsrc/parser.rs:544–548vssrc/parser.rs:600–601— The DO-body path extracts the symbol name via a clone intoend_symbol: Option<String>before theif let Some(s) = end_symbolblock, releasing thepeek_kind()borrow in time for the subsequentself.loc()andself.advance()calls. The SELECT path clones inside theif letblock (let s = s.clone()), also correct.Both patterns compile correctly today, but the DO-body version has an extra heap allocation for the
Option<String>that's immediately matched away. This is not a bug, just a note that the two adjacent code paths use different idioms for the same pattern.Verified correct
InvalidDataOnEnd→ 21 (error.rs:136) matches ANSI X3.274-1996 §A.parser.rs:478;eq_ignore_ascii_caseatparser.rs:552handlesEND Imatchingdo i = 1 to 5and vice-versa.parser.rs:599–605is correct and consistent with the DO check.parse_clause()recursion means each inner DO'sparse_do_body(inner_name)consumes its ownEND [name]before returning, so outer contexts see a clean token stream.Err(RexxDiagnostic::new(...)). Theunreachable!atparser.rs:476is guarded by the caller'sTokenKind::Symbol(_)check at line 444.duplicate_for_keyword_error,_while_,_until_): theconsume_unique_keywordslot check triggers correctly for all three newly covered keywords.