Skip to content

Commit d24e88b

Browse files
orpuente-MSidavis
authored andcommitted
Compile annotations into attributes (#2271)
1 parent a8022c8 commit d24e88b

File tree

10 files changed

+226
-93
lines changed

10 files changed

+226
-93
lines changed

compiler/qsc_qasm3/src/ast_builder.rs

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use qsc_ast::ast::{
1414
use qsc_data_structures::span::Span;
1515

1616
use crate::{
17-
parser::ast::list_from_iter,
17+
parser::ast::{list_from_iter, List},
1818
runtime::RuntimeFunctions,
1919
stdlib::angle::Angle,
2020
types::{ArrayDimensions, Complex},
@@ -1459,15 +1459,14 @@ pub(crate) fn build_end_stmt(span: Span) -> Stmt {
14591459
};
14601460

14611461
let kind = ExprKind::Fail(Box::new(message));
1462-
Stmt {
1463-
kind: Box::new(StmtKind::Expr(Box::new(Expr {
1464-
kind: Box::new(kind),
1465-
span,
1466-
..Default::default()
1467-
}))),
1462+
1463+
let expr = Expr {
1464+
kind: Box::new(kind),
14681465
span,
14691466
..Default::default()
1470-
}
1467+
};
1468+
1469+
build_stmt_semi_from_expr_with_span(expr, span)
14711470
}
14721471

14731472
pub(crate) fn build_index_expr(expr: Expr, index_expr: Expr, span: Span) -> Expr {
@@ -1484,19 +1483,6 @@ pub(crate) fn build_barrier_call(span: Span) -> Stmt {
14841483
build_stmt_semi_from_expr(expr)
14851484
}
14861485

1487-
pub(crate) fn build_attr(text: String, span: Span) -> Attr {
1488-
Attr {
1489-
id: NodeId::default(),
1490-
span,
1491-
name: Box::new(Ident {
1492-
name: Rc::from(text),
1493-
span,
1494-
..Default::default()
1495-
}),
1496-
arg: Box::new(create_unit_expr(span)),
1497-
}
1498-
}
1499-
15001486
pub(crate) fn build_gate_decl(
15011487
name: String,
15021488
cargs: Vec<(String, Ty, Pat)>,
@@ -1703,6 +1689,7 @@ pub(crate) fn build_function_or_operation(
17031689
return_type: Option<Ty>,
17041690
kind: CallableKind,
17051691
functors: Option<FunctorExpr>,
1692+
attrs: List<Attr>,
17061693
) -> Stmt {
17071694
let args = cargs
17081695
.into_iter()
@@ -1763,6 +1750,7 @@ pub(crate) fn build_function_or_operation(
17631750
let item = Item {
17641751
span: gate_span,
17651752
kind: Box::new(ast::ItemKind::Callable(Box::new(decl))),
1753+
attrs,
17661754
..Default::default()
17671755
};
17681756

@@ -1807,3 +1795,48 @@ fn build_idents(idents: &[&str]) -> Option<Box<[Ident]>> {
18071795
Some(idents.into())
18081796
}
18091797
}
1798+
1799+
pub(crate) fn build_attr<S>(name: S, value: Option<S>, span: Span) -> Attr
1800+
where
1801+
S: AsRef<str>,
1802+
{
1803+
let name = Box::new(Ident {
1804+
span,
1805+
name: name.as_ref().into(),
1806+
..Default::default()
1807+
});
1808+
1809+
let arg = if let Some(value) = value {
1810+
Box::new(Expr {
1811+
span,
1812+
kind: Box::new(ExprKind::Paren(Box::new(Expr {
1813+
span,
1814+
kind: Box::new(ExprKind::Path(PathKind::Ok(Box::new(Path {
1815+
id: Default::default(),
1816+
span,
1817+
segments: None,
1818+
name: Box::new(Ident {
1819+
span,
1820+
name: value.as_ref().into(),
1821+
..Default::default()
1822+
}),
1823+
})))),
1824+
id: Default::default(),
1825+
}))),
1826+
id: Default::default(),
1827+
})
1828+
} else {
1829+
Box::new(Expr {
1830+
span,
1831+
kind: Box::new(ExprKind::Tuple(Box::default())),
1832+
id: Default::default(),
1833+
})
1834+
};
1835+
1836+
Attr {
1837+
span,
1838+
name,
1839+
arg,
1840+
id: Default::default(),
1841+
}
1842+
}

compiler/qsc_qasm3/src/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ impl QasmCompiler {
415415
let span = span_for_syntax_node(stmt.syntax());
416416
if let "@SimulatableIntrinsic" = text.as_str() {
417417
let (_at, name) = text.split_at(1);
418-
Some(build_attr(name.to_string(), span))
418+
Some(build_attr(name.to_string(), None, span))
419419
} else {
420420
let span = span_for_syntax_node(stmt.syntax());
421421
let kind = SemanticErrorKind::UnknownAnnotation(text.to_string(), span);

compiler/qsc_qasm3/src/compiler.rs

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ use qsc_frontend::{compile::SourceMap, error::WithSource};
1111
use crate::{
1212
ast_builder::{
1313
build_adj_plus_ctl_functor, build_arg_pat, build_array_reverse_expr,
14-
build_assignment_statement, build_barrier_call, build_binary_expr, build_call_no_params,
15-
build_call_with_param, build_call_with_params, build_cast_call_by_name,
16-
build_classical_decl, build_complex_from_expr, build_convert_call_expr,
17-
build_expr_array_expr, build_for_stmt, build_function_or_operation,
18-
build_gate_call_param_expr, build_gate_call_with_params_and_callee,
19-
build_global_call_with_two_params, build_if_expr_then_block,
20-
build_if_expr_then_block_else_block, build_if_expr_then_block_else_expr,
21-
build_if_expr_then_expr_else_expr, build_implicit_return_stmt,
22-
build_indexed_assignment_statement, build_lit_angle_expr, build_lit_bigint_expr,
23-
build_lit_bool_expr, build_lit_complex_expr, build_lit_double_expr, build_lit_int_expr,
24-
build_lit_result_array_expr_from_bitstring, build_lit_result_expr,
14+
build_assignment_statement, build_attr, build_barrier_call, build_binary_expr,
15+
build_call_no_params, build_call_with_param, build_call_with_params,
16+
build_cast_call_by_name, build_classical_decl, build_complex_from_expr,
17+
build_convert_call_expr, build_end_stmt, build_expr_array_expr, build_for_stmt,
18+
build_function_or_operation, build_gate_call_param_expr,
19+
build_gate_call_with_params_and_callee, build_global_call_with_two_params,
20+
build_if_expr_then_block, build_if_expr_then_block_else_block,
21+
build_if_expr_then_block_else_expr, build_if_expr_then_expr_else_expr,
22+
build_implicit_return_stmt, build_indexed_assignment_statement, build_lit_angle_expr,
23+
build_lit_bigint_expr, build_lit_bool_expr, build_lit_complex_expr, build_lit_double_expr,
24+
build_lit_int_expr, build_lit_result_array_expr_from_bitstring, build_lit_result_expr,
2525
build_managed_qubit_alloc, build_math_call_from_exprs, build_math_call_no_params,
2626
build_measure_call, build_operation_with_stmts, build_path_ident_expr,
2727
build_qasm_import_decl, build_qasm_import_items, build_range_expr, build_reset_call,
@@ -379,6 +379,19 @@ impl QasmCompiler {
379379
}
380380

381381
fn compile_stmt(&mut self, stmt: &crate::semantic::ast::Stmt) -> Option<qsast::Stmt> {
382+
if !stmt.annotations.is_empty()
383+
&& !matches!(
384+
stmt.kind.as_ref(),
385+
semast::StmtKind::QuantumGateDefinition(..) | semast::StmtKind::Def(..)
386+
)
387+
{
388+
for annotation in &stmt.annotations {
389+
self.push_semantic_error(SemanticErrorKind::InvalidAnnotationTarget(
390+
annotation.span,
391+
));
392+
}
393+
}
394+
382395
match stmt.kind.as_ref() {
383396
semast::StmtKind::Alias(stmt) => self.compile_alias_decl_stmt(stmt),
384397
semast::StmtKind::Assign(stmt) => self.compile_assign_stmt(stmt),
@@ -391,10 +404,10 @@ impl QasmCompiler {
391404
self.compile_calibration_grammar_stmt(stmt)
392405
}
393406
semast::StmtKind::ClassicalDecl(stmt) => self.compile_classical_decl(stmt),
394-
semast::StmtKind::Def(stmt) => self.compile_def_stmt(stmt),
407+
semast::StmtKind::Def(def_stmt) => self.compile_def_stmt(def_stmt, &stmt.annotations),
395408
semast::StmtKind::DefCal(stmt) => self.compile_def_cal_stmt(stmt),
396409
semast::StmtKind::Delay(stmt) => self.compile_delay_stmt(stmt),
397-
semast::StmtKind::End(stmt) => self.compile_end_stmt(stmt),
410+
semast::StmtKind::End(stmt) => Self::compile_end_stmt(stmt),
398411
semast::StmtKind::ExprStmt(stmt) => self.compile_expr_stmt(stmt),
399412
semast::StmtKind::ExternDecl(stmt) => self.compile_extern_stmt(stmt),
400413
semast::StmtKind::For(stmt) => self.compile_for_stmt(stmt),
@@ -405,7 +418,9 @@ impl QasmCompiler {
405418
semast::StmtKind::OutputDeclaration(stmt) => self.compile_output_decl_stmt(stmt),
406419
semast::StmtKind::MeasureArrow(stmt) => self.compile_measure_stmt(stmt),
407420
semast::StmtKind::Pragma(stmt) => self.compile_pragma_stmt(stmt),
408-
semast::StmtKind::QuantumGateDefinition(stmt) => self.compile_gate_decl_stmt(stmt),
421+
semast::StmtKind::QuantumGateDefinition(gate_stmt) => {
422+
self.compile_gate_decl_stmt(gate_stmt, &stmt.annotations)
423+
}
409424
semast::StmtKind::QubitDecl(stmt) => self.compile_qubit_decl_stmt(stmt),
410425
semast::StmtKind::QubitArrayDecl(stmt) => self.compile_qubit_array_decl_stmt(stmt),
411426
semast::StmtKind::Reset(stmt) => self.compile_reset_stmt(stmt),
@@ -600,7 +615,11 @@ impl QasmCompiler {
600615
Some(stmt)
601616
}
602617

603-
fn compile_def_stmt(&mut self, stmt: &semast::DefStmt) -> Option<qsast::Stmt> {
618+
fn compile_def_stmt(
619+
&mut self,
620+
stmt: &semast::DefStmt,
621+
annotations: &List<semast::Annotation>,
622+
) -> Option<qsast::Stmt> {
604623
let symbol = self.symbols[stmt.symbol_id].clone();
605624
let name = symbol.name.clone();
606625

@@ -627,6 +646,10 @@ impl QasmCompiler {
627646
qsast::CallableKind::Function
628647
};
629648

649+
let attrs = annotations
650+
.iter()
651+
.filter_map(|annotation| self.compile_annotation(annotation));
652+
630653
// We use the same primitives used for declaring gates, because def declarations
631654
// in QASM3 can take qubits as arguments and call quantum gates.
632655
Some(build_function_or_operation(
@@ -640,6 +663,7 @@ impl QasmCompiler {
640663
return_type,
641664
kind,
642665
None,
666+
list_from_iter(attrs),
643667
))
644668
}
645669

@@ -653,9 +677,8 @@ impl QasmCompiler {
653677
None
654678
}
655679

656-
fn compile_end_stmt(&mut self, stmt: &semast::EndStmt) -> Option<qsast::Stmt> {
657-
self.push_unimplemented_error_message("end statements", stmt.span);
658-
None
680+
fn compile_end_stmt(stmt: &semast::EndStmt) -> Option<qsast::Stmt> {
681+
Some(build_end_stmt(stmt.span))
659682
}
660683

661684
fn compile_expr_stmt(&mut self, stmt: &semast::ExprStmt) -> Option<qsast::Stmt> {
@@ -866,6 +889,7 @@ impl QasmCompiler {
866889
fn compile_gate_decl_stmt(
867890
&mut self,
868891
stmt: &semast::QuantumGateDefinition,
892+
annotations: &List<semast::Annotation>,
869893
) -> Option<qsast::Stmt> {
870894
let symbol = self.symbols[stmt.symbol_id].clone();
871895
let name = symbol.name.clone();
@@ -902,6 +926,10 @@ impl QasmCompiler {
902926

903927
let body = Some(self.compile_block(&stmt.body));
904928

929+
let attrs = annotations
930+
.iter()
931+
.filter_map(|annotation| self.compile_annotation(annotation));
932+
905933
Some(build_function_or_operation(
906934
name,
907935
cargs,
@@ -913,9 +941,27 @@ impl QasmCompiler {
913941
None,
914942
qsast::CallableKind::Operation,
915943
Some(build_adj_plus_ctl_functor()),
944+
list_from_iter(attrs),
916945
))
917946
}
918947

948+
fn compile_annotation(&mut self, annotation: &semast::Annotation) -> Option<qsast::Attr> {
949+
match annotation.identifier.as_ref() {
950+
"SimulatableIntrinsic" | "Config" => Some(build_attr(
951+
&annotation.identifier,
952+
annotation.value.as_ref(),
953+
annotation.span,
954+
)),
955+
_ => {
956+
self.push_semantic_error(SemanticErrorKind::UnknownAnnotation(
957+
format!("@{}", annotation.identifier),
958+
annotation.span,
959+
));
960+
None
961+
}
962+
}
963+
}
964+
919965
fn compile_qubit_decl_stmt(&mut self, stmt: &semast::QubitDeclaration) -> Option<qsast::Stmt> {
920966
let symbol = self.symbols[stmt.symbol_id].clone();
921967
let name = &symbol.name;

compiler/qsc_qasm3/src/parser/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub enum ErrorKind {
9898
#[error("Empty statements are not supported")]
9999
#[diagnostic(code("Qasm3.Parse.EmptyStatement"))]
100100
EmptyStatement(#[label] Span),
101-
#[error("expected statement after annotation")]
101+
#[error("Annotation missing target statement.")]
102102
#[diagnostic(code("Qasm3.Parse.FloatingAnnotation"))]
103103
FloatingAnnotation(#[label] Span),
104104
#[error("expected {0}, found {1}")]

compiler/qsc_qasm3/src/parser/stmt.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,16 @@ pub(super) fn parse(s: &mut ParserContext) -> Result<Stmt> {
156156
} else if let Some(stmt) = opt(s, parse_measure_stmt)? {
157157
StmtKind::Measure(stmt)
158158
} else {
159-
return Err(Error::new(ErrorKind::Rule(
160-
"statement",
161-
s.peek().kind,
162-
s.peek().span,
163-
)));
159+
return if attrs.is_empty() {
160+
Err(Error::new(ErrorKind::Rule(
161+
"statement",
162+
s.peek().kind,
163+
s.peek().span,
164+
)))
165+
} else {
166+
let span = attrs.last().expect("there is at least one annotation").span;
167+
Err(Error::new(ErrorKind::FloatingAnnotation(span)))
168+
};
164169
};
165170

166171
Ok(Stmt {

compiler/qsc_qasm3/src/semantic/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub enum SemanticErrorKind {
120120
#[error("Indexed must be a single expression.")]
121121
#[diagnostic(code("Qsc.Qasm3.Compile.IndexMustBeSingleExpr"))]
122122
IndexMustBeSingleExpr(#[label] Span),
123-
#[error("Annotations only valid on gate definitions.")]
123+
#[error("Annotations only valid on def and gate statements.")]
124124
#[diagnostic(code("Qsc.Qasm3.Compile.InvalidAnnotationTarget"))]
125125
InvalidAnnotationTarget(#[label] Span),
126126
#[error("Assigning {0} values to {1} must be in a range that be converted to {1}.")]

0 commit comments

Comments
 (0)