Skip to content

Commit 9f8d6db

Browse files
orpuente-MSidavis
authored andcommitted
Lower control flow stmts in QASM3 parser (#2232)
This PR: 1. Aliases super::ast to semantic. 2. Fixes The bodies of if, for, and while to be `Stmt` instead of `List<Stmt>`. 3. Lowers the if, for, while, and switch stmts. 4. Refactors the pattern used to handle lowering of optional items by introducing the `short_circuit_opt_item!` macro.
1 parent 9aa6b90 commit 9f8d6db

File tree

13 files changed

+1128
-369
lines changed

13 files changed

+1128
-369
lines changed

Diff for: compiler/qsc_qasm3/src/parser/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,7 @@ impl Display for WhileLoop {
13691369
pub struct ForStmt {
13701370
pub span: Span,
13711371
pub ty: ScalarType,
1372-
pub identifier: Identifier,
1372+
pub ident: Ident,
13731373
pub set_declaration: Box<EnumerableSet>,
13741374
pub body: Stmt,
13751375
}
@@ -1378,7 +1378,7 @@ impl Display for ForStmt {
13781378
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
13791379
writeln_header(f, "ForStmt", self.span)?;
13801380
writeln_field(f, "variable_type", &self.ty)?;
1381-
writeln_field(f, "variable_name", &self.identifier)?;
1381+
writeln_field(f, "variable_name", &self.ident)?;
13821382
writeln_field(f, "iterable", &self.set_declaration)?;
13831383
write_field(f, "body", &self.body)
13841384
}

Diff for: compiler/qsc_qasm3/src/parser/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ fn walk_extern_stmt(vis: &mut impl MutVisitor, stmt: &mut ExternDecl) {
486486
fn walk_for_stmt(vis: &mut impl MutVisitor, stmt: &mut ForStmt) {
487487
vis.visit_span(&mut stmt.span);
488488
vis.visit_scalar_type(&mut stmt.ty);
489-
vis.visit_identifier(&mut stmt.identifier);
489+
vis.visit_ident(&mut stmt.ident);
490490
vis.visit_enumerable_set(&mut stmt.set_declaration);
491491
vis.visit_stmt(&mut stmt.body);
492492
}

Diff for: compiler/qsc_qasm3/src/parser/stmt.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub(super) fn parse(s: &mut ParserContext) -> Result<Stmt> {
119119
StmtKind::Switch(switch)
120120
} else if let Some(stmt) = opt(s, parse_if_stmt)? {
121121
StmtKind::If(stmt)
122-
} else if let Some(stmt) = opt(s, parse_for_loop)? {
122+
} else if let Some(stmt) = opt(s, parse_for_stmt)? {
123123
StmtKind::For(stmt)
124124
} else if let Some(stmt) = opt(s, parse_while_loop)? {
125125
StmtKind::WhileLoop(stmt)
@@ -1226,19 +1226,19 @@ fn for_loop_iterable_expr(s: &mut ParserContext) -> Result<EnumerableSet> {
12261226
/// Grammar:
12271227
/// `FOR scalarType Identifier IN (setExpression | LBRACKET rangeExpression RBRACKET | expression) body=statementOrScope`.
12281228
/// Reference: <https://openqasm.com/language/classical.html#for-loops>.
1229-
pub fn parse_for_loop(s: &mut ParserContext) -> Result<ForStmt> {
1229+
pub fn parse_for_stmt(s: &mut ParserContext) -> Result<ForStmt> {
12301230
let lo = s.peek().span.lo;
12311231
token(s, TokenKind::Keyword(Keyword::For))?;
12321232
let ty = scalar_type(s)?;
1233-
let identifier = Identifier::Ident(Box::new(prim::ident(s)?));
1233+
let ident = prim::ident(s)?;
12341234
token(s, TokenKind::Keyword(Keyword::In))?;
12351235
let set_declaration = Box::new(for_loop_iterable_expr(s)?);
12361236
let block = parse_block_or_stmt(s)?;
12371237

12381238
Ok(ForStmt {
12391239
span: s.span(lo),
12401240
ty,
1241-
identifier,
1241+
ident,
12421242
set_declaration,
12431243
body: block,
12441244
})

Diff for: compiler/qsc_qasm3/src/parser/stmt/tests/for_loops.rs

+31-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::parser::{stmt::parse, tests::check};
55
use expect_test::expect;
66

77
#[test]
8-
fn simple_for_loop() {
8+
fn simple_for_stmt() {
99
check(
1010
parse,
1111
"
@@ -38,7 +38,7 @@ fn simple_for_loop() {
3838
}
3939

4040
#[test]
41-
fn empty_for_loop() {
41+
fn empty_for_stmt_body() {
4242
check(
4343
parse,
4444
"for int x in {} {}",
@@ -58,7 +58,7 @@ fn empty_for_loop() {
5858
}
5959

6060
#[test]
61-
fn simple_for_loop_stmt_body() {
61+
fn simple_for_stmt_stmt_body() {
6262
check(
6363
parse,
6464
"
@@ -88,7 +88,7 @@ fn simple_for_loop_stmt_body() {
8888
}
8989

9090
#[test]
91-
fn for_loop_range() {
91+
fn for_stmt_iterating_over_range() {
9292
check(
9393
parse,
9494
"
@@ -120,7 +120,7 @@ fn for_loop_range() {
120120
}
121121

122122
#[test]
123-
fn for_loop_range_no_step() {
123+
fn for_stmt_iterating_over_range_no_step() {
124124
check(
125125
parse,
126126
"
@@ -152,7 +152,7 @@ fn for_loop_range_no_step() {
152152
}
153153

154154
#[test]
155-
fn for_loop_expr() {
155+
fn for_stmt_iterating_over_expr() {
156156
check(
157157
parse,
158158
"
@@ -181,7 +181,7 @@ fn for_loop_expr() {
181181
}
182182

183183
#[test]
184-
fn for_loop_with_continue_stmt() {
184+
fn for_stmt_with_continue_stmt() {
185185
check(
186186
parse,
187187
"
@@ -351,3 +351,27 @@ fn nested_single_stmt_for_stmt() {
351351
indices: <empty>"#]],
352352
);
353353
}
354+
355+
#[test]
356+
fn for_stmt_with_indented_identifier_errors() {
357+
check(
358+
parse,
359+
"for int x[2] in {} {}",
360+
&expect![[r#"
361+
Error(
362+
Token(
363+
Keyword(
364+
In,
365+
),
366+
Open(
367+
Bracket,
368+
),
369+
Span {
370+
lo: 9,
371+
hi: 10,
372+
},
373+
),
374+
)
375+
"#]],
376+
);
377+
}

Diff for: compiler/qsc_qasm3/src/semantic/ast.rs

+41-13
Original file line numberDiff line numberDiff line change
@@ -433,16 +433,16 @@ impl Display for DefCalStmt {
433433
pub struct IfStmt {
434434
pub span: Span,
435435
pub condition: Expr,
436-
pub if_block: List<Stmt>,
437-
pub else_block: Option<List<Stmt>>,
436+
pub if_body: Stmt,
437+
pub else_body: Option<Stmt>,
438438
}
439439

440440
impl Display for IfStmt {
441441
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
442442
writeln_header(f, "IfStmt", self.span)?;
443443
writeln_field(f, "condition", &self.condition)?;
444-
writeln_list_field(f, "if_block", &self.if_block)?;
445-
write_opt_list_field(f, "else_block", self.else_block.as_ref())
444+
writeln_field(f, "if_body", &self.if_body)?;
445+
write_opt_field(f, "else_body", self.else_body.as_ref())
446446
}
447447
}
448448

@@ -1316,33 +1316,31 @@ impl Display for ReturnStmt {
13161316
pub struct WhileLoop {
13171317
pub span: Span,
13181318
pub while_condition: Expr,
1319-
pub block: List<Stmt>,
1319+
pub body: Stmt,
13201320
}
13211321

13221322
impl Display for WhileLoop {
13231323
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
13241324
writeln_header(f, "WhileLoop", self.span)?;
13251325
writeln_field(f, "condition", &self.while_condition)?;
1326-
write_list_field(f, "block", &self.block)
1326+
write_field(f, "body", &self.body)
13271327
}
13281328
}
13291329

13301330
#[derive(Clone, Debug)]
13311331
pub struct ForStmt {
13321332
pub span: Span,
1333-
pub ty: ScalarType,
1334-
pub identifier: Identifier,
1333+
pub loop_variable: SymbolId,
13351334
pub set_declaration: Box<EnumerableSet>,
1336-
pub block: List<Stmt>,
1335+
pub body: Stmt,
13371336
}
13381337

13391338
impl Display for ForStmt {
13401339
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
13411340
writeln_header(f, "ForStmt", self.span)?;
1342-
writeln_field(f, "variable_type", &self.ty)?;
1343-
writeln_field(f, "variable_name", &self.identifier)?;
1341+
writeln_field(f, "loop_variable", &self.loop_variable)?;
13441342
writeln_field(f, "iterable", &self.set_declaration)?;
1345-
write_list_field(f, "block", &self.block)
1343+
write_field(f, "body", &self.body)
13461344
}
13471345
}
13481346

@@ -1599,13 +1597,43 @@ impl Display for LiteralKind {
15991597
}
16001598
}
16011599

1602-
#[derive(Debug, Clone, Copy, PartialEq)]
1600+
#[derive(Debug, Clone, Copy)]
16031601
pub struct Version {
16041602
pub major: u32,
16051603
pub minor: Option<u32>,
16061604
pub span: Span,
16071605
}
16081606

1607+
impl PartialEq for Version {
1608+
fn eq(&self, other: &Self) -> bool {
1609+
// If the minor versions are missing
1610+
// we assume them to be 0.
1611+
let self_minor = self.minor.unwrap_or_default();
1612+
let other_minor = other.minor.unwrap_or_default();
1613+
1614+
// Then we check if the major and minor version are equal.
1615+
self.major == other.major && self_minor == other_minor
1616+
}
1617+
}
1618+
1619+
impl PartialOrd for Version {
1620+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1621+
// If the minor versions are missing
1622+
// we assume them to be 0.
1623+
let self_minor = self.minor.unwrap_or_default();
1624+
let other_minor = other.minor.unwrap_or_default();
1625+
1626+
// We compare the major versions.
1627+
match self.major.partial_cmp(&other.major) {
1628+
// If they are equal, we disambiguate
1629+
// using the minor versions.
1630+
Some(core::cmp::Ordering::Equal) => self_minor.partial_cmp(&other_minor),
1631+
// Else, we return their ordering.
1632+
ord => ord,
1633+
}
1634+
}
1635+
}
1636+
16091637
impl fmt::Display for Version {
16101638
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16111639
match self.minor {

Diff for: compiler/qsc_qasm3/src/semantic/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ pub enum SemanticErrorKind {
132132
#[error("{0} are not supported.")]
133133
#[diagnostic(code("Qsc.Qasm3.Compile.NotSupported"))]
134134
NotSupported(String, #[label] Span),
135+
#[error("{0} were introduced in version {1}")]
136+
#[diagnostic(code("Qsc.Qasm3.Compile.NotSupportedInThisVersion"))]
137+
NotSupportedInThisVersion(String, String, #[label] Span),
135138
#[error("The operator {0} is not valid with lhs {1} and rhs {2}.")]
136139
#[diagnostic(code("Qsc.Qasm3.Compile.OperatorNotSupportedForTypes"))]
137140
OperatorNotSupportedForTypes(String, String, String, #[label] Span),
@@ -286,6 +289,9 @@ impl SemanticErrorKind {
286289
}
287290
Self::NegativeControlCount(span) => Self::NegativeControlCount(span + offset),
288291
Self::NotSupported(name, span) => Self::NotSupported(name, span + offset),
292+
Self::NotSupportedInThisVersion(name, version, span) => {
293+
Self::NotSupportedInThisVersion(name, version, span + offset)
294+
}
289295
Self::OperatorNotSupportedForTypes(op, lhs, rhs, span) => {
290296
Self::OperatorNotSupportedForTypes(op, lhs, rhs, span + offset)
291297
}

0 commit comments

Comments
 (0)