-
Notifications
You must be signed in to change notification settings - Fork 4
✨ feat(lang): add do...end block syntax for while, foreach, and match #1045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add support for do...end block syntax as an alternative to colon syntax for while, foreach, and match constructs. Both syntaxes are now supported simultaneously for backward compatibility. Changes: - Modified CST parser to accept 'do' keyword before block bodies - Modified AST parser to handle do...end syntax - Added comprehensive integration tests for new syntax - All existing tests pass, ensuring backward compatibility Examples: while (x > 0) do x - 1 end foreach(item, arr) do process(item) end match (value) do | 1: "one" | 2: "two" end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces do...end block syntax as an alternative to the existing colon syntax for while, foreach, and match constructs in the mq language. The implementation ensures backward compatibility by supporting both syntaxes simultaneously.
Key Changes
- Modified CST and AST parsers to recognize and handle the
dokeyword before block bodies - Added comprehensive test coverage for the new syntax across all three affected constructs (while, foreach, match)
- Ensured coexistence of both syntaxes through conditional parsing logic
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| crates/mq-lang/tests/integration_tests.rs | Added integration tests verifying do...end syntax works correctly for while loops, foreach loops, and match expressions, including nested and control flow scenarios |
| crates/mq-lang/src/cst/parser.rs | Updated CST parser to detect and consume do keyword as alternative to colon, added corresponding unit tests for new syntax structures |
| crates/mq-lang/src/ast/parser.rs | Modified AST parser to handle do...end blocks in while, foreach, and match expressions, with unit tests confirming correct AST generation |
CodSpeed Performance ReportMerging #1045 will not alter performanceComparing Summary
Footnotes |
Add formatting support for do...end syntax in while, foreach, and match statements. Includes proper spacing around the do keyword and comprehensive tests for various scenarios (oneline, multiline, nested, with guards). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Consolidates duplicate code for formatting 'do' keyword spacing into a new `format_do_with_spacing` helper method, improving maintainability and reducing code duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| // If there's no colon or do, split before the right parenthesis | ||
| let expr_index = if let Some(index) = do_index.or(colon_index) { | ||
| index | ||
| } else { | ||
| Self::find_token_position(node, |kind| matches!(kind, mq_lang::TokenKind::RParen)) | ||
| .map(|index| index + 1) | ||
| .unwrap_or(0) |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calculation of expr_index has changed significantly and may not match the original calculate_split_position logic. The removed code called self.calculate_split_position(node, 0) which likely had specific logic for determining split positions. The new implementation directly finds the RParen position, which could produce different behavior. Consider verifying that this simplified logic handles all edge cases that calculate_split_position was designed for.
| // If there's no colon or do, split before the right parenthesis | |
| let expr_index = if let Some(index) = do_index.or(colon_index) { | |
| index | |
| } else { | |
| Self::find_token_position(node, |kind| matches!(kind, mq_lang::TokenKind::RParen)) | |
| .map(|index| index + 1) | |
| .unwrap_or(0) | |
| // If there's no colon or do, split before the right parenthesis. | |
| // If no suitable token is found at all, default to the end of the children | |
| // to avoid changing behavior by arbitrarily splitting at index 0. | |
| let expr_index = if let Some(index) = do_index.or(colon_index) { | |
| index | |
| } else { | |
| Self::find_token_position(node, |kind| matches!(kind, mq_lang::TokenKind::RParen)) | |
| .map(|index| index + 1) | |
| .unwrap_or(node.children.len()) |
|
|
||
| // Format match arms and end | ||
| let remaining_children: Vec<_> = node.children.iter().skip(colon_pos + 1).collect(); | ||
| let remaining_children: Vec<_> = remaining_children.collect(); |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable remaining_children is shadowing the iterator of the same name from line 833. This creates confusion as the name is reused for a collected vector. Consider renaming the collected vector to something like match_arms_and_end or remaining_nodes_vec to distinguish it from the iterator.
Add support for do...end block syntax as an alternative to colon syntax
for while, foreach, and match constructs. Both syntaxes are now supported
simultaneously for backward compatibility.
Changes:
Examples:
while (x > 0) do x - 1 end
foreach(item, arr) do process(item) end
match (value) do | 1: "one" | 2: "two" end