Skip to content

Commit 9bde7f6

Browse files
0xrinegadeclaude
andcommitted
feat(ovsm): add C-style brace syntax support for control flow
Added support for C-style braces alongside existing Python-style syntax, allowing users to choose their preferred coding style: Python-style (colon + indentation): FOR $i IN [1..10]: $sum = $sum + $i RETURN $sum C-style (braces + semicolons): FOR $i IN [1..10] { $sum = $sum + $i; } RETURN $sum Changes: - Modified FOR loop parser to accept either ':' or '{' after iterable - Modified WHILE loop parser to accept either ':' or '{' after condition - Modified IF/ELSE parser to accept either 'THEN' or '{' after condition - Updated error messages to reflect both syntax styles - Semicolons already worked as statement separators - Both styles can be mixed in the same script - Backward compatible - all existing Python-style code works Tests verified: ✅ C-style FOR loops with single and multiple statements ✅ C-style WHILE loops ✅ C-style IF/ELSE statements ✅ Nested C-style loops ✅ Mixed Python/C style in same script ✅ Complex nested conditionals ✅ Python-style syntax still works perfectly This makes OVSM more approachable for developers from C/Java/JavaScript backgrounds while maintaining full Python-style support. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent d4e1710 commit 9bde7f6

File tree

2 files changed

+123
-32
lines changed

2 files changed

+123
-32
lines changed

crates/ovsm/src/parser/mod.rs

Lines changed: 122 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -189,28 +189,73 @@ impl Parser {
189189

190190
let condition = self.expression()?;
191191

192-
self.consume(TokenKind::Then, "Expected THEN after IF condition")?;
193-
self.skip_newlines();
192+
// Support both Python-style (THEN) and C-style (braces) syntax
193+
let then_branch = if self.match_token(&TokenKind::LeftBrace) {
194+
// C-style: IF condition { statements; }
195+
self.advance(); // consume {
196+
self.skip_newlines();
197+
198+
let mut statements = Vec::new();
199+
while !self.check(&TokenKind::RightBrace) && !self.is_at_end() {
200+
self.skip_newlines();
201+
if self.check(&TokenKind::RightBrace) {
202+
break;
203+
}
204+
statements.push(self.statement()?);
205+
self.skip_newlines();
206+
}
194207

195-
let mut then_branch = Vec::new();
196-
while !self.check(&TokenKind::Else)
197-
&& !self.check(&TokenKind::Eof)
198-
&& !self.is_end_of_block()
199-
{
200-
then_branch.push(self.statement()?);
208+
self.consume(TokenKind::RightBrace, "Expected '}' after IF block")?;
201209
self.skip_newlines();
202-
}
210+
statements
211+
} else {
212+
// Python-style: IF condition THEN statements
213+
self.consume(TokenKind::Then, "Expected THEN or '{' after IF condition")?;
214+
self.skip_newlines();
215+
216+
let mut statements = Vec::new();
217+
while !self.check(&TokenKind::Else)
218+
&& !self.check(&TokenKind::Eof)
219+
&& !self.is_end_of_block()
220+
{
221+
statements.push(self.statement()?);
222+
self.skip_newlines();
223+
}
224+
statements
225+
};
203226

204227
let else_branch = if self.match_token(&TokenKind::Else) {
205228
self.advance();
206229
self.skip_newlines();
207230

208-
let mut else_stmts = Vec::new();
209-
while !self.is_end_of_block() && !self.is_at_end() {
210-
else_stmts.push(self.statement()?);
231+
// ELSE can also use braces
232+
if self.match_token(&TokenKind::LeftBrace) {
233+
// C-style: ELSE { statements; }
234+
self.advance(); // consume {
211235
self.skip_newlines();
236+
237+
let mut statements = Vec::new();
238+
while !self.check(&TokenKind::RightBrace) && !self.is_at_end() {
239+
self.skip_newlines();
240+
if self.check(&TokenKind::RightBrace) {
241+
break;
242+
}
243+
statements.push(self.statement()?);
244+
self.skip_newlines();
245+
}
246+
247+
self.consume(TokenKind::RightBrace, "Expected '}' after ELSE block")?;
248+
self.skip_newlines();
249+
Some(statements)
250+
} else {
251+
// Python-style: ELSE statements
252+
let mut statements = Vec::new();
253+
while !self.is_end_of_block() && !self.is_at_end() {
254+
statements.push(self.statement()?);
255+
self.skip_newlines();
256+
}
257+
Some(statements)
212258
}
213-
Some(else_stmts)
214259
} else {
215260
None
216261
};
@@ -227,17 +272,40 @@ impl Parser {
227272

228273
let condition = self.expression()?;
229274

230-
self.consume(TokenKind::Colon, "Expected ':' after WHILE condition")?;
231-
self.skip_newlines();
275+
// Support both Python-style (colon) and C-style (braces) syntax
276+
let body = if self.match_token(&TokenKind::LeftBrace) {
277+
// C-style: WHILE condition { statements; }
278+
self.advance(); // consume {
279+
self.skip_newlines();
232280

233-
let mut body = Vec::new();
234-
while !self.is_at_end() {
235-
self.skip_newlines(); // Skip newlines before checking end condition
236-
if self.is_end_of_loop_block() {
237-
break;
281+
let mut statements = Vec::new();
282+
while !self.check(&TokenKind::RightBrace) && !self.is_at_end() {
283+
self.skip_newlines();
284+
if self.check(&TokenKind::RightBrace) {
285+
break;
286+
}
287+
statements.push(self.statement()?);
288+
self.skip_newlines();
238289
}
239-
body.push(self.statement()?);
240-
}
290+
291+
self.consume(TokenKind::RightBrace, "Expected '}' after WHILE block")?;
292+
self.skip_newlines();
293+
statements
294+
} else {
295+
// Python-style: WHILE condition: statements
296+
self.consume(TokenKind::Colon, "Expected ':' or '{' after WHILE condition")?;
297+
self.skip_newlines();
298+
299+
let mut statements = Vec::new();
300+
while !self.is_at_end() {
301+
self.skip_newlines();
302+
if self.is_end_of_loop_block() {
303+
break;
304+
}
305+
statements.push(self.statement()?);
306+
}
307+
statements
308+
};
241309

242310
Ok(Statement::While { condition, body })
243311
}
@@ -255,17 +323,40 @@ impl Parser {
255323

256324
let iterable = self.expression()?;
257325

258-
self.consume(TokenKind::Colon, "Expected ':' after FOR iterable")?;
259-
self.skip_newlines();
326+
// Support both Python-style (colon) and C-style (braces) syntax
327+
let body = if self.match_token(&TokenKind::LeftBrace) {
328+
// C-style: FOR $i IN [1..10] { statements; }
329+
self.advance(); // consume {
330+
self.skip_newlines();
260331

261-
let mut body = Vec::new();
262-
while !self.is_at_end() {
263-
self.skip_newlines(); // Skip newlines before checking end condition
264-
if self.is_end_of_loop_block() {
265-
break;
332+
let mut statements = Vec::new();
333+
while !self.check(&TokenKind::RightBrace) && !self.is_at_end() {
334+
self.skip_newlines();
335+
if self.check(&TokenKind::RightBrace) {
336+
break;
337+
}
338+
statements.push(self.statement()?);
339+
self.skip_newlines();
266340
}
267-
body.push(self.statement()?);
268-
}
341+
342+
self.consume(TokenKind::RightBrace, "Expected '}' after FOR block")?;
343+
self.skip_newlines();
344+
statements
345+
} else {
346+
// Python-style: FOR $i IN [1..10]: statements
347+
self.consume(TokenKind::Colon, "Expected ':' or '{' after FOR iterable")?;
348+
self.skip_newlines();
349+
350+
let mut statements = Vec::new();
351+
while !self.is_at_end() {
352+
self.skip_newlines();
353+
if self.is_end_of_loop_block() {
354+
break;
355+
}
356+
statements.push(self.statement()?);
357+
}
358+
statements
359+
};
269360

270361
Ok(Statement::For {
271362
variable,

src/services/ovsm_service.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl OvsmService {
7878
let result = self
7979
.evaluator
8080
.execute(&program)
81-
.context("Failed to execute OVSM program. Note: OVSM requires proper indentation (like Python). Single-line colon syntax is not supported for loops.")?;
81+
.context("Failed to execute OVSM program. Note: OVSM supports both Python-style (colon + indentation) and C-style (braces) syntax for control flow.")?;
8282

8383
if self.verbose {
8484
println!("✨ Execution completed successfully");

0 commit comments

Comments
 (0)