Skip to content

Commit 5480691

Browse files
orpuente-MSidavis
authored andcommitted
Make assignment a StmtKind (#2216)
This PR turns assignment into a StmtKind (it was a ExprKind before).
1 parent ea70d7c commit 5480691

File tree

13 files changed

+443
-177
lines changed

13 files changed

+443
-177
lines changed

compiler/qsc_qasm3/src/ast.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ impl Display for AliasDeclStmt {
312312
#[derive(Clone, Debug, Default)]
313313
pub enum StmtKind {
314314
Alias(AliasDeclStmt),
315+
Assign(AssignStmt),
316+
AssignOp(AssignOpStmt),
315317
Barrier(BarrierStmt),
316318
Box(BoxStmt),
317319
Break(BreakStmt),
@@ -351,6 +353,8 @@ pub enum StmtKind {
351353
impl Display for StmtKind {
352354
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
353355
match self {
356+
StmtKind::Assign(stmt) => write!(f, "{stmt}"),
357+
StmtKind::AssignOp(stmt) => write!(f, "{stmt}"),
354358
StmtKind::Alias(alias) => write!(f, "{alias}"),
355359
StmtKind::Barrier(barrier) => write!(f, "{barrier}"),
356360
StmtKind::Box(box_stmt) => write!(f, "{box_stmt}"),
@@ -1432,8 +1436,6 @@ impl Display for SwitchCase {
14321436

14331437
#[derive(Clone, Debug, Default)]
14341438
pub enum ExprKind {
1435-
Assign(AssignExpr),
1436-
AssignOp(AssignOpExpr),
14371439
/// An expression with invalid syntax that can't be parsed.
14381440
#[default]
14391441
Err,
@@ -1458,37 +1460,37 @@ impl Display for ExprKind {
14581460
ExprKind::FunctionCall(call) => write!(f, "{call}"),
14591461
ExprKind::Cast(expr) => write!(f, "{expr}"),
14601462
ExprKind::IndexExpr(expr) => write!(f, "{expr}"),
1461-
ExprKind::Assign(expr) => write!(f, "{expr}"),
1462-
ExprKind::AssignOp(expr) => write!(f, "{expr}"),
14631463
ExprKind::Paren(expr) => write!(f, "Paren {expr}"),
14641464
}
14651465
}
14661466
}
14671467

14681468
#[derive(Clone, Debug)]
1469-
pub struct AssignExpr {
1470-
pub lhs: Expr,
1469+
pub struct AssignStmt {
1470+
pub span: Span,
1471+
pub lhs: IndexedIdent,
14711472
pub rhs: Expr,
14721473
}
14731474

1474-
impl Display for AssignExpr {
1475+
impl Display for AssignStmt {
14751476
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1476-
writeln!(f, "AssignExpr:")?;
1477+
writeln_header(f, "AssignStmt", self.span)?;
14771478
writeln_field(f, "lhs", &self.lhs)?;
14781479
write_field(f, "rhs", &self.rhs)
14791480
}
14801481
}
14811482

14821483
#[derive(Clone, Debug)]
1483-
pub struct AssignOpExpr {
1484+
pub struct AssignOpStmt {
1485+
pub span: Span,
14841486
pub op: BinOp,
1485-
pub lhs: Expr,
1487+
pub lhs: IndexedIdent,
14861488
pub rhs: Expr,
14871489
}
14881490

1489-
impl Display for AssignOpExpr {
1491+
impl Display for AssignOpStmt {
14901492
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1491-
writeln!(f, "AssignOpExpr:")?;
1493+
writeln_header(f, "AssignOpStmt", self.span)?;
14921494
writeln_field(f, "op", &self.op)?;
14931495
writeln_field(f, "lhs", &self.lhs)?;
14941496
write_field(f, "rhs", &self.rhs)

compiler/qsc_qasm3/src/parser/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ pub enum ErrorKind {
134134
#[error("invalid gate call designator")]
135135
#[diagnostic(code("Qasm3.Parse.InvalidGateCallDesignator"))]
136136
InvalidGateCallDesignator(#[label] Span),
137+
#[error("multiple index operators are only allowed in assignments")]
138+
#[diagnostic(code("Qasm3.Parse.MultipleIndexOperators"))]
139+
MultipleIndexOperators(#[label] Span),
137140
}
138141

139142
impl ErrorKind {
@@ -156,6 +159,7 @@ impl ErrorKind {
156159
Self::ExpectedItem(token, span) => Self::ExpectedItem(token, span + offset),
157160
Self::GPhaseInvalidArguments(span) => Self::GPhaseInvalidArguments(span + offset),
158161
Self::InvalidGateCallDesignator(span) => Self::InvalidGateCallDesignator(span + offset),
162+
Self::MultipleIndexOperators(span) => Self::MultipleIndexOperators(span + offset),
159163
}
160164
}
161165
}

compiler/qsc_qasm3/src/parser/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ fn cast_op(s: &mut ParserContext, r#type: TypeDef) -> Result<ExprKind> {
468468
}
469469

470470
fn index_expr(s: &mut ParserContext, lhs: Expr) -> Result<ExprKind> {
471-
let lo = s.span(0).hi - 1;
471+
let lo = lhs.span.lo;
472472
let index = index_element(s)?;
473473
recovering_token(s, TokenKind::Close(Delim::Bracket));
474474
Ok(ExprKind::IndexExpr(IndexExpr {

compiler/qsc_qasm3/src/parser/expr/tests.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ fn index_expr() {
953953
check_expr(
954954
"foo[1]",
955955
&expect![[r#"
956-
Expr [0-6]: IndexExpr [3-6]:
956+
Expr [0-6]: IndexExpr [0-6]:
957957
collection: Expr [0-3]: Ident [0-3] "foo"
958958
index: IndexSet [4-5]:
959959
values:
@@ -966,7 +966,7 @@ fn index_set() {
966966
check_expr(
967967
"foo[{1, 4, 5}]",
968968
&expect![[r#"
969-
Expr [0-14]: IndexExpr [3-14]:
969+
Expr [0-14]: IndexExpr [0-14]:
970970
collection: Expr [0-3]: Ident [0-3] "foo"
971971
index: DiscreteSet [4-13]:
972972
values:
@@ -981,7 +981,7 @@ fn index_multiple_ranges() {
981981
check_expr(
982982
"foo[1:5, 3:7, 4:8]",
983983
&expect![[r#"
984-
Expr [0-18]: IndexExpr [3-18]:
984+
Expr [0-18]: IndexExpr [0-18]:
985985
collection: Expr [0-3]: Ident [0-3] "foo"
986986
index: IndexSet [4-17]:
987987
values:
@@ -1005,7 +1005,7 @@ fn index_range() {
10051005
check_expr(
10061006
"foo[1:5:2]",
10071007
&expect![[r#"
1008-
Expr [0-10]: IndexExpr [3-10]:
1008+
Expr [0-10]: IndexExpr [0-10]:
10091009
collection: Expr [0-3]: Ident [0-3] "foo"
10101010
index: IndexSet [4-9]:
10111011
values:
@@ -1021,7 +1021,7 @@ fn index_full_range() {
10211021
check_expr(
10221022
"foo[:]",
10231023
&expect![[r#"
1024-
Expr [0-6]: IndexExpr [3-6]:
1024+
Expr [0-6]: IndexExpr [0-6]:
10251025
collection: Expr [0-3]: Ident [0-3] "foo"
10261026
index: IndexSet [4-5]:
10271027
values:
@@ -1037,7 +1037,7 @@ fn index_range_start() {
10371037
check_expr(
10381038
"foo[1:]",
10391039
&expect![[r#"
1040-
Expr [0-7]: IndexExpr [3-7]:
1040+
Expr [0-7]: IndexExpr [0-7]:
10411041
collection: Expr [0-3]: Ident [0-3] "foo"
10421042
index: IndexSet [4-6]:
10431043
values:
@@ -1053,7 +1053,7 @@ fn index_range_end() {
10531053
check_expr(
10541054
"foo[:5]",
10551055
&expect![[r#"
1056-
Expr [0-7]: IndexExpr [3-7]:
1056+
Expr [0-7]: IndexExpr [0-7]:
10571057
collection: Expr [0-3]: Ident [0-3] "foo"
10581058
index: IndexSet [4-6]:
10591059
values:
@@ -1069,7 +1069,7 @@ fn index_range_step() {
10691069
check_expr(
10701070
"foo[:2:]",
10711071
&expect![[r#"
1072-
Expr [0-8]: IndexExpr [3-8]:
1072+
Expr [0-8]: IndexExpr [0-8]:
10731073
collection: Expr [0-3]: Ident [0-3] "foo"
10741074
index: IndexSet [4-7]:
10751075
values:

compiler/qsc_qasm3/src/parser/stmt.rs

Lines changed: 123 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use super::{
1717
use crate::{
1818
ast::{
1919
list_from_iter, AccessControl, AliasDeclStmt, AngleType, Annotation, ArrayBaseTypeKind,
20-
ArrayReferenceType, ArrayType, ArrayTypedParameter, AssignExpr, BarrierStmt, BitType,
21-
Block, BoxStmt, BreakStmt, CalibrationGrammarStmt, CalibrationStmt, Cast,
20+
ArrayReferenceType, ArrayType, ArrayTypedParameter, AssignOpStmt, AssignStmt, BarrierStmt,
21+
BitType, Block, BoxStmt, BreakStmt, CalibrationGrammarStmt, CalibrationStmt, Cast,
2222
ClassicalDeclarationStmt, ComplexType, ConstantDeclStmt, ContinueStmt, DefCalStmt, DefStmt,
2323
DelayStmt, EndStmt, EnumerableSet, Expr, ExprKind, ExprStmt, ExternDecl, ExternParameter,
2424
FloatType, ForStmt, FunctionCall, GPhase, GateCall, GateModifierKind, GateOperand,
@@ -107,6 +107,81 @@ pub(super) fn parse(s: &mut ParserContext) -> Result<Box<Stmt>> {
107107
Box::new(StmtKind::Break(stmt))
108108
} else if let Some(stmt) = opt(s, parse_end_stmt)? {
109109
Box::new(StmtKind::End(stmt))
110+
} else if let Some(indexed_ident) = opt(s, indexed_identifier)? {
111+
if s.peek().kind == TokenKind::Eq {
112+
s.advance();
113+
let expr = expr::expr(s)?;
114+
recovering_semi(s);
115+
Box::new(StmtKind::Assign(AssignStmt {
116+
span: s.span(lo),
117+
lhs: indexed_ident,
118+
rhs: expr,
119+
}))
120+
} else if let TokenKind::BinOpEq(op) = s.peek().kind {
121+
s.advance();
122+
let op = expr::closed_bin_op(op);
123+
let expr = expr::expr(s)?;
124+
recovering_semi(s);
125+
Box::new(StmtKind::AssignOp(AssignOpStmt {
126+
span: s.span(lo),
127+
op,
128+
lhs: indexed_ident,
129+
rhs: expr,
130+
}))
131+
} else if s.peek().kind == TokenKind::Open(Delim::Paren) {
132+
if !indexed_ident.indices.is_empty() {
133+
s.push_error(Error::new(ErrorKind::Convert(
134+
"Ident",
135+
"IndexedIdent",
136+
indexed_ident.span,
137+
)));
138+
}
139+
140+
let ident = indexed_ident.name;
141+
142+
s.advance();
143+
let (args, _) = seq(s, expr::expr)?;
144+
token(s, TokenKind::Close(Delim::Paren))?;
145+
146+
let funcall = Expr {
147+
span: s.span(lo),
148+
kind: Box::new(ExprKind::FunctionCall(FunctionCall {
149+
span: s.span(lo),
150+
name: ident,
151+
args: args.into_iter().map(Box::new).collect(),
152+
})),
153+
};
154+
155+
let expr = expr::expr_with_lhs(s, funcall)?;
156+
157+
Box::new(parse_gate_call_with_expr(s, expr)?)
158+
} else {
159+
let kind = if indexed_ident.indices.is_empty() {
160+
ExprKind::Ident(indexed_ident.name)
161+
} else {
162+
if indexed_ident.indices.len() > 1 {
163+
s.push_error(Error::new(ErrorKind::MultipleIndexOperators(
164+
indexed_ident.span,
165+
)));
166+
}
167+
168+
ExprKind::IndexExpr(IndexExpr {
169+
span: indexed_ident.span,
170+
collection: Expr {
171+
span: indexed_ident.name.span,
172+
kind: Box::new(ExprKind::Ident(indexed_ident.name)),
173+
},
174+
index: *indexed_ident.indices[0].clone(),
175+
})
176+
};
177+
178+
let expr = Expr {
179+
span: indexed_ident.span,
180+
kind: Box::new(kind),
181+
};
182+
183+
Box::new(parse_gate_call_with_expr(s, expr)?)
184+
}
110185
} else if let Some(stmt_kind) = opt(s, parse_gate_call_stmt)? {
111186
Box::new(stmt_kind)
112187
} else if let Some(stmt) = opt(s, |s| parse_expression_stmt(s, None))? {
@@ -1098,27 +1173,7 @@ fn parse_end_stmt(s: &mut ParserContext) -> Result<EndStmt> {
10981173
/// Grammar: `(expression | assignExpr | AssignOpExpr) SEMICOLON`.
10991174
fn parse_expression_stmt(s: &mut ParserContext, lhs: Option<Expr>) -> Result<ExprStmt> {
11001175
let expr = if let Some(lhs) = lhs {
1101-
if opt(s, |s| token(s, TokenKind::Eq))?.is_some() {
1102-
let rhs = expr::expr(s)?;
1103-
Expr {
1104-
span: s.span(lhs.span.lo),
1105-
kind: Box::new(ExprKind::Assign(AssignExpr { lhs, rhs })),
1106-
}
1107-
} else if let TokenKind::BinOpEq(op) = s.peek().kind {
1108-
s.advance();
1109-
let op = expr::closed_bin_op(op);
1110-
let rhs = expr::expr(s)?;
1111-
Expr {
1112-
span: s.span(lhs.span.lo),
1113-
kind: Box::new(ExprKind::AssignOp(crate::ast::AssignOpExpr {
1114-
op,
1115-
lhs,
1116-
rhs,
1117-
})),
1118-
}
1119-
} else {
1120-
expr::expr_with_lhs(s, lhs)?
1121-
}
1176+
expr::expr_with_lhs(s, lhs)?
11221177
} else {
11231178
expr::expr(s)?
11241179
};
@@ -1296,6 +1351,51 @@ fn parse_gate_call_stmt(s: &mut ParserContext) -> Result<StmtKind> {
12961351
}))
12971352
}
12981353

1354+
/// This parser is used to disambiguate statements starting with an index
1355+
/// identifier. It is a simplified version of `parse_gate_call_stmt`.
1356+
fn parse_gate_call_with_expr(s: &mut ParserContext, gate_or_expr: Expr) -> Result<StmtKind> {
1357+
let lo = gate_or_expr.span.lo;
1358+
let mut duration = opt(s, designator)?;
1359+
let qubits = gate_operand_list(s)?;
1360+
1361+
// If didn't parse modifiers, a duration, nor qubit args then this is an expr, not a gate call.
1362+
if duration.is_none() && qubits.is_empty() {
1363+
return Ok(StmtKind::ExprStmt(parse_expression_stmt(
1364+
s,
1365+
Some(gate_or_expr),
1366+
)?));
1367+
}
1368+
1369+
// We parse the recovering semi after we call parse_expr_stmt.
1370+
recovering_semi(s);
1371+
1372+
// Reinterpret the function call or ident as a gate call.
1373+
let (name, args) = match *gate_or_expr.kind {
1374+
ExprKind::FunctionCall(FunctionCall { name, args, .. }) => (name, args),
1375+
ExprKind::Ident(ident) => (ident, Default::default()),
1376+
ExprKind::IndexExpr(index_expr) => reinterpret_index_expr(index_expr, &mut duration)?,
1377+
_ => {
1378+
return Err(Error::new(ErrorKind::ExpectedItem(
1379+
TokenKind::Identifier,
1380+
gate_or_expr.span,
1381+
)))
1382+
}
1383+
};
1384+
1385+
if qubits.is_empty() {
1386+
s.push_error(Error::new(ErrorKind::MissingGateCallOperands(s.span(lo))));
1387+
}
1388+
1389+
Ok(StmtKind::GateCall(GateCall {
1390+
span: s.span(lo),
1391+
modifiers: Default::default(),
1392+
name,
1393+
args,
1394+
qubits,
1395+
duration,
1396+
}))
1397+
}
1398+
12991399
/// This helper function reinterprets an indexed expression as
13001400
/// a gate call. There are two valid cases we are interested in:
13011401
/// 1. Ident[4]

compiler/qsc_qasm3/src/parser/stmt/tests/alias.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn concatenation_alias() {
3131
kind: AliasDeclStmt [0-32]:
3232
ident: Ident [4-5] "x"
3333
exprs:
34-
Expr [8-14]: IndexExpr [9-14]:
34+
Expr [8-14]: IndexExpr [8-14]:
3535
collection: Expr [8-9]: Ident [8-9] "a"
3636
index: IndexSet [10-13]:
3737
values:
@@ -40,7 +40,7 @@ fn concatenation_alias() {
4040
step: <none>
4141
end: Expr [12-13]: Lit: Int(2)
4242
Expr [18-19]: Ident [18-19] "b"
43-
Expr [23-31]: IndexExpr [24-31]:
43+
Expr [23-31]: IndexExpr [23-31]:
4444
collection: Expr [23-24]: Ident [23-24] "c"
4545
index: IndexSet [25-30]:
4646
values:

0 commit comments

Comments
 (0)