microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
cesarzc/ssa-panic

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc_codegen/src/qsharp.rs

761lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#[cfg(test)]
5mod spec_decls;
6
7#[cfg(test)]
8mod tests;
9
10#[cfg(test)]
11mod test_utils;
12
13use std::io::Write;
14use std::vec;
15
16use qsc_ast::ast::{
17 self, Attr, BinOp, Block, CallableBody, CallableDecl, CallableKind, Expr, ExprKind, Functor,
18 FunctorExpr, FunctorExprKind, Ident, Item, ItemKind, Lit, Mutability, Pat, PatKind, Path,
19 Pauli, QubitInit, QubitInitKind, QubitSource, SetOp, SpecBody, SpecDecl, SpecGen, Stmt,
20 StmtKind, StringComponent, TernOp, TopLevelNode, Ty, TyDef, TyDefKind, TyKind, UnOp,
21 Visibility, VisibilityKind,
22};
23use qsc_ast::ast::{Namespace, Package};
24use qsc_ast::visit::Visitor;
25use qsc_formatter::formatter::format_str;
26use qsc_frontend::compile::PackageStore;
27
28fn write<W: Write>(output: W, packages: &[&Package]) {
29 let mut gen = QSharpGen::new(output);
30 for package in packages {
31 gen.visit_package(package);
32 }
33}
34
35pub fn write_store<W: Write>(output: W, store: &PackageStore) {
36 let mut gen = QSharpGen::new(output);
37 for (_, unit) in store {
38 gen.visit_package(&unit.ast.package);
39 }
40}
41
42#[must_use]
43pub fn write_store_string(store: &PackageStore) -> Vec<String> {
44 let mut package_strings: Vec<_> = vec![];
45 for (_, unit) in store {
46 package_strings.push(write_package_string(&unit.ast.package));
47 }
48 package_strings
49}
50
51#[must_use]
52pub fn write_package_string(package: &Package) -> String {
53 let mut output = Vec::new();
54 write(&mut output, &[package]);
55 let s = match std::str::from_utf8(&output) {
56 Ok(v) => v.to_owned(),
57 Err(e) => format!("Invalid UTF-8 sequence: {e}"),
58 };
59
60 output.clear();
61 format_str(&s)
62}
63
64struct QSharpGen<W: Write> {
65 pub(crate) output: W,
66}
67
68impl<W> QSharpGen<W>
69where
70 W: Write,
71{
72 pub fn new(output: W) -> Self {
73 Self { output }
74 }
75
76 pub fn write(&mut self, args: &str) {
77 write!(&mut self.output, "{args}").expect("write failed");
78 }
79
80 pub fn writeln(&mut self, args: &str) {
81 self.write(args);
82 self.write("\n");
83 }
84
85 /// special case for tuple with one element
86 /// otherwise we are changing the semantics of the program
87 fn ensure_trailing_comma_for_arity_one_tuples<T>(&mut self, most: &[T]) {
88 if most.is_empty() {
89 self.write(",");
90 }
91 }
92}
93
94impl<W: Write> Visitor<'_> for QSharpGen<W> {
95 fn visit_package(&mut self, package: &'_ Package) {
96 package.nodes.iter().for_each(|n| match n {
97 TopLevelNode::Namespace(ns) => {
98 self.visit_namespace(ns);
99 }
100 TopLevelNode::Stmt(stmt) => self.visit_stmt(stmt),
101 });
102 package.entry.iter().for_each(|e| self.visit_expr(e));
103 }
104
105 fn visit_namespace(&mut self, namespace: &'_ Namespace) {
106 self.write("namespace ");
107 self.visit_ident(&namespace.name);
108 self.writeln("{");
109 namespace.items.iter().for_each(|i| {
110 self.visit_item(i);
111 });
112 self.write("}");
113 }
114
115 fn visit_item(&mut self, item: &'_ Item) {
116 item.attrs.iter().for_each(|a| self.visit_attr(a));
117 item.visibility
118 .iter()
119 .for_each(|v| self.visit_visibility(v));
120 match &*item.kind {
121 ItemKind::Err => {
122 unreachable!()
123 }
124 ItemKind::Callable(decl) => self.visit_callable_decl(decl),
125 ItemKind::Open(ns, alias) => {
126 self.write("open ");
127 self.visit_ident(ns);
128 if let Some(alias) = alias {
129 self.write(" as ");
130 self.visit_ident(alias);
131 }
132 self.writeln(";");
133 }
134 ItemKind::Ty(ident, def) => {
135 self.write("newtype ");
136 self.visit_ident(ident);
137 self.write(" = ");
138 self.visit_ty_def(def);
139 self.writeln(";");
140 }
141 }
142 }
143
144 fn visit_attr(&mut self, attr: &'_ Attr) {
145 self.write("@");
146 self.visit_ident(&attr.name);
147 self.visit_expr(&attr.arg);
148 self.writeln("");
149 }
150
151 fn visit_visibility(&mut self, vis: &'_ Visibility) {
152 match vis.kind {
153 VisibilityKind::Public => {}
154 VisibilityKind::Internal => self.write("internal "),
155 }
156 }
157
158 fn visit_ty_def(&mut self, def: &'_ TyDef) {
159 match &*def.kind {
160 TyDefKind::Field(name, ty) => {
161 for n in name {
162 self.visit_ident(n);
163 self.write(": ");
164 }
165 self.visit_ty(ty);
166 }
167 TyDefKind::Paren(def) => self.visit_ty_def(def),
168 TyDefKind::Tuple(defs) => {
169 self.write("(");
170 if let Some((last, most)) = defs.split_last() {
171 for i in most {
172 self.visit_ty_def(i);
173 self.write(", ");
174 }
175 self.visit_ty_def(last);
176 self.ensure_trailing_comma_for_arity_one_tuples(most);
177 }
178 self.write(")");
179 }
180 TyDefKind::Err => {}
181 }
182 }
183
184 fn visit_callable_decl(&mut self, decl: &'_ CallableDecl) {
185 match decl.kind {
186 CallableKind::Function => self.write("function "),
187 CallableKind::Operation => self.write("operation "),
188 }
189 self.visit_ident(&decl.name);
190 if !decl.generics.is_empty() {
191 self.write("<");
192 if let Some((last, most)) = decl.generics.split_last() {
193 for i in most {
194 self.visit_ident(i);
195 self.write(", ");
196 }
197 self.visit_ident(last);
198 }
199
200 self.write(">");
201 }
202
203 self.visit_pat(&decl.input);
204 self.write(" : ");
205 self.visit_ty(&decl.output);
206 if let Some(functors) = decl.functors.as_deref() {
207 self.write(" is ");
208 self.visit_functor_expr(functors);
209 }
210
211 match &*decl.body {
212 CallableBody::Block(block) => {
213 self.visit_block(block);
214 }
215 CallableBody::Specs(specs) => {
216 self.writeln("{");
217 specs.iter().for_each(|s| self.visit_spec_decl(s));
218 self.writeln("}");
219 }
220 }
221 }
222
223 fn visit_spec_decl(&mut self, decl: &'_ SpecDecl) {
224 match decl.spec {
225 ast::Spec::Body => self.write("body "),
226 ast::Spec::Adj => self.write("adjoint "),
227 ast::Spec::Ctl => self.write("controlled "),
228 ast::Spec::CtlAdj => self.write("controlled adjoint "),
229 }
230 match &decl.body {
231 SpecBody::Gen(spec) => match spec {
232 SpecGen::Auto => self.writeln("auto;"),
233 SpecGen::Distribute => self.writeln("distribute;"),
234 SpecGen::Intrinsic => self.writeln("intrinsic;"),
235 SpecGen::Invert => self.writeln("invert;"),
236 SpecGen::Slf => self.writeln("self;"),
237 },
238 SpecBody::Impl(pat, block) => {
239 self.visit_pat(pat);
240 self.visit_block(block);
241 }
242 }
243 }
244
245 fn visit_functor_expr(&mut self, expr: &'_ FunctorExpr) {
246 match &*expr.kind {
247 FunctorExprKind::BinOp(op, lhs, rhs) => {
248 self.visit_functor_expr(lhs);
249 match op {
250 SetOp::Union => self.write(" + "),
251 SetOp::Intersect => self.write(" * "),
252 }
253 self.visit_functor_expr(rhs);
254 }
255 FunctorExprKind::Lit(functor) => match functor {
256 Functor::Adj => self.write("Adj"),
257 Functor::Ctl => self.write("Ctl"),
258 },
259 FunctorExprKind::Paren(expr) => {
260 self.write("(");
261 self.visit_functor_expr(expr);
262 self.write(")");
263 }
264 }
265 }
266
267 fn visit_ty(&mut self, ty: &'_ Ty) {
268 match &*ty.kind {
269 TyKind::Array(item) => {
270 self.visit_ty(item);
271 self.write("[]");
272 }
273 TyKind::Arrow(kind, lhs, rhs, functors) => {
274 self.visit_ty(lhs);
275 match kind {
276 CallableKind::Function => self.write(" -> "),
277 CallableKind::Operation => self.write(" => "),
278 }
279 self.visit_ty(rhs);
280 if let Some(functors) = functors.as_deref() {
281 self.write(" is ");
282 self.visit_functor_expr(functors);
283 }
284 }
285 TyKind::Hole => self.write("_"),
286 TyKind::Paren(ty) => {
287 self.write("(");
288 self.visit_ty(ty);
289 self.write(")");
290 }
291 TyKind::Path(path) => self.visit_path(path),
292 TyKind::Param(name) => self.visit_ident(name),
293 TyKind::Tuple(tys) => {
294 if tys.is_empty() {
295 self.write("()");
296 } else {
297 self.write("(");
298 if let Some((last, most)) = tys.split_last() {
299 for t in most {
300 self.visit_ty(t);
301 self.write(", ");
302 }
303 self.visit_ty(last);
304 self.ensure_trailing_comma_for_arity_one_tuples(most);
305 }
306 self.write(")");
307 }
308 }
309 TyKind::Err => unreachable!(),
310 }
311 }
312
313 fn visit_block(&mut self, block: &'_ Block) {
314 self.writeln(" {");
315 block.stmts.iter().for_each(|s| {
316 self.visit_stmt(s);
317 });
318 self.writeln("}");
319 }
320
321 fn visit_stmt(&mut self, stmt: &'_ Stmt) {
322 match &*stmt.kind {
323 StmtKind::Empty | StmtKind::Err => {}
324 StmtKind::Semi(expr) => {
325 self.visit_expr(expr);
326 self.writeln(";");
327 }
328 StmtKind::Expr(expr) => {
329 self.visit_expr(expr);
330 }
331 StmtKind::Item(item) => self.visit_item(item),
332 StmtKind::Local(mutability, pat, value) => {
333 match mutability {
334 Mutability::Mutable => self.write("mutable "),
335 Mutability::Immutable => self.write("let "),
336 }
337 self.visit_pat(pat);
338 self.write(" = ");
339 self.visit_expr(value);
340 self.writeln(";");
341 }
342 StmtKind::Qubit(source, pat, init, block) => {
343 match source {
344 QubitSource::Dirty => self.write("borrow "),
345 QubitSource::Fresh => self.write("use "),
346 }
347 self.visit_pat(pat);
348 self.write(" = ");
349 self.visit_qubit_init(init);
350 if let Some(b) = block {
351 self.visit_block(b);
352 } else {
353 self.writeln(";");
354 }
355 }
356 }
357 }
358
359 #[allow(clippy::too_many_lines)]
360 fn visit_expr(&mut self, expr: &'_ Expr) {
361 match &*expr.kind {
362 ExprKind::Array(exprs) => {
363 self.write("[");
364 if let Some((last, most)) = exprs.split_last() {
365 for e in most {
366 self.visit_expr(e);
367 self.write(", ");
368 }
369 self.visit_expr(last);
370 }
371 self.write("]");
372 }
373 ExprKind::ArrayRepeat(item, size) => {
374 self.write("[");
375 self.visit_expr(item);
376 self.write(", size = ");
377 self.visit_expr(size);
378 self.write("]");
379 }
380 ExprKind::Assign(lhs, rhs) => {
381 self.write("set ");
382 self.visit_expr(lhs);
383 self.write(" = ");
384 self.visit_expr(rhs);
385 }
386 ExprKind::AssignOp(op, lhs, rhs) => {
387 self.write("set ");
388 self.visit_expr(lhs);
389 self.write(" ");
390 let op_str = binop_as_str(op);
391 self.write(op_str);
392 self.write("= ");
393 self.visit_expr(rhs);
394 }
395 ExprKind::BinOp(op, lhs, rhs) => {
396 self.visit_expr(lhs);
397 self.write(" ");
398 let op_str = binop_as_str(op);
399 self.write(op_str);
400 self.write(" ");
401 self.visit_expr(rhs);
402 }
403 ExprKind::AssignUpdate(record, index, value) => {
404 self.write("set ");
405 self.visit_expr(record);
406 self.write(" w/= ");
407 self.visit_expr(index);
408 self.write(" <- ");
409 self.visit_expr(value);
410 }
411 ExprKind::Block(block) => self.visit_block(block),
412 ExprKind::Call(callee, arg) => {
413 self.visit_expr(callee);
414 self.visit_expr(arg);
415 }
416 ExprKind::Conjugate(within, apply) => {
417 self.write("within");
418 self.visit_block(within);
419 self.write("apply");
420 self.visit_block(apply);
421 }
422 ExprKind::Fail(msg) => {
423 self.write("fail ");
424 self.visit_expr(msg);
425 }
426 ExprKind::Field(record, name) => {
427 self.visit_expr(record);
428 self.write("::");
429 self.visit_ident(name);
430 }
431 ExprKind::For(pat, iter, block) => {
432 self.write("for ");
433 self.visit_pat(pat);
434 self.write(" in ");
435 self.visit_expr(iter);
436 self.write(" ");
437 self.visit_block(block);
438 }
439 ExprKind::If(cond, body, otherwise) => {
440 self.write("if ");
441 self.visit_expr(cond);
442 self.write(" ");
443 self.visit_block(body);
444 for expr in otherwise {
445 if matches!(*expr.kind, ExprKind::If(..)) {
446 // visiting expr as if writes 'if' to make 'elif'
447 self.write(" el");
448 } else {
449 self.write(" else ");
450 }
451 self.visit_expr(expr);
452 }
453 }
454 ExprKind::Index(array, index) => {
455 self.visit_expr(array);
456 self.write("[");
457 self.visit_expr(index);
458 self.write("]");
459 }
460 ExprKind::Interpolate(components) => {
461 self.write("$\"");
462 for component in components.as_ref() {
463 match component {
464 StringComponent::Expr(expr) => {
465 self.write("{");
466 self.visit_expr(expr.as_ref());
467 self.write("}");
468 }
469 StringComponent::Lit(lit) => {
470 self.write(lit);
471 }
472 }
473 }
474 self.write("\"");
475 }
476 ExprKind::Lambda(kind, pat, expr) => {
477 self.visit_pat(pat);
478 match kind {
479 CallableKind::Function => self.write(" -> "),
480 CallableKind::Operation => self.write(" => "),
481 }
482 self.visit_expr(expr);
483 }
484 ExprKind::Paren(expr) => {
485 self.write("(");
486 self.visit_expr(expr);
487 self.write(")");
488 }
489 ExprKind::Return(expr) => {
490 self.write("return ");
491 self.visit_expr(expr);
492 }
493 ExprKind::UnOp(op, expr) => {
494 let op_str = unop_as_str(op);
495 if op == &UnOp::Unwrap {
496 self.visit_expr(expr);
497 self.write(op_str);
498 } else {
499 self.write(op_str);
500 self.visit_expr(expr);
501 }
502 }
503 ExprKind::Path(path) => self.visit_path(path),
504 ExprKind::Range(start, step, end) => {
505 // A range: `start..step..end`, `start..end`, `start...`, `...end`, or `...`.
506 match (start, step, end) {
507 (None, None, None) => {
508 self.write("...");
509 }
510 (None, None, Some(end)) => {
511 self.write("...");
512 self.visit_expr(end);
513 }
514 (None, Some(step), None) => {
515 self.write("...");
516 self.visit_expr(step);
517 self.write("...");
518 }
519 (None, Some(step), Some(end)) => {
520 self.write("...");
521 self.visit_expr(step);
522 self.write("..");
523 self.visit_expr(end);
524 }
525 (Some(start), None, None) => {
526 self.visit_expr(start);
527 self.write("...");
528 }
529 (Some(start), None, Some(end)) => {
530 self.visit_expr(start);
531 self.write("..");
532 self.visit_expr(end);
533 }
534 (Some(start), Some(step), None) => {
535 self.visit_expr(start);
536 self.write("..");
537 self.visit_expr(step);
538 self.write("...");
539 }
540 (Some(start), Some(step), Some(end)) => {
541 self.visit_expr(start);
542 self.write("..");
543 self.visit_expr(step);
544 self.write("..");
545 self.visit_expr(end);
546 }
547 }
548 }
549 ExprKind::Repeat(body, until, fixup) => {
550 self.write("repeat ");
551 self.visit_block(body);
552 self.write("until ");
553 self.visit_expr(until);
554 for fixup in fixup {
555 self.write(" fixup ");
556 self.visit_block(fixup);
557 }
558 }
559 ExprKind::TernOp(op, e1, e2, e3) => {
560 match op {
561 TernOp::Cond => {
562 // Conditional: `a ? b | c`.
563 self.visit_expr(e1);
564 self.write(" ? ");
565 self.visit_expr(e2);
566 self.write(" | ");
567 self.visit_expr(e3);
568 }
569 TernOp::Update => {
570 // Aggregate update: `a w/ b <- c`.
571 self.visit_expr(e1);
572 self.write(" w/ ");
573 self.visit_expr(e2);
574 self.write(" <- ");
575 self.visit_expr(e3);
576 }
577 }
578 }
579 ExprKind::Tuple(exprs) => {
580 self.write("(");
581 if let Some((last, most)) = exprs.split_last() {
582 for e in most {
583 self.visit_expr(e);
584 self.write(", ");
585 }
586 self.visit_expr(last);
587 self.ensure_trailing_comma_for_arity_one_tuples(most);
588 }
589 self.write(")");
590 }
591 ExprKind::While(cond, block) => {
592 self.write("while ");
593 self.visit_expr(cond);
594 self.visit_block(block);
595 }
596 ExprKind::Lit(lit) => match lit.as_ref() {
597 Lit::BigInt(value) => {
598 self.write(value.to_string().as_str());
599 self.write("L");
600 }
601 Lit::Bool(value) => {
602 if *value {
603 self.write("true");
604 } else {
605 self.write("false");
606 }
607 }
608 Lit::Double(value) => {
609 let num_str = if value.fract() == 0.0 {
610 format!("{value}.")
611 } else {
612 format!("{value}")
613 };
614 self.write(&num_str);
615 }
616 Lit::Int(value) => self.write(&value.to_string()),
617 Lit::Pauli(value) => match value {
618 Pauli::I => self.write("PauliI"),
619 Pauli::X => self.write("PauliX"),
620 Pauli::Y => self.write("PauliY"),
621 Pauli::Z => self.write("PauliZ"),
622 },
623 Lit::Result(value) => match value {
624 ast::Result::One => self.write("One"),
625 ast::Result::Zero => self.write("Zero"),
626 },
627 Lit::String(value) => {
628 self.write("\"");
629 self.write(value.as_ref());
630 self.write("\"");
631 }
632 },
633 ExprKind::Hole => {
634 self.write("_");
635 }
636 ExprKind::Err => {
637 unreachable!();
638 }
639 }
640 }
641
642 fn visit_pat(&mut self, pat: &'_ Pat) {
643 match &*pat.kind {
644 PatKind::Bind(name, ty) => {
645 self.visit_ident(name);
646
647 for t in ty {
648 self.write(": ");
649 self.visit_ty(t);
650 }
651 }
652 PatKind::Discard(ty) => {
653 self.write("_");
654 for t in ty {
655 self.write(": ");
656 self.visit_ty(t);
657 }
658 }
659 PatKind::Elided => {
660 self.write("...");
661 }
662 PatKind::Paren(pat) => {
663 self.write("(");
664 self.visit_pat(pat);
665 self.write(")");
666 }
667 PatKind::Tuple(pats) => {
668 self.write("(");
669 if let Some((last, most)) = pats.split_last() {
670 for pat in most {
671 self.visit_pat(pat);
672 self.write(", ");
673 }
674 self.visit_pat(last);
675 self.ensure_trailing_comma_for_arity_one_tuples(most);
676 }
677 self.write(")");
678 }
679 PatKind::Err => {
680 unreachable!();
681 }
682 }
683 }
684
685 fn visit_qubit_init(&mut self, init: &'_ QubitInit) {
686 match &*init.kind {
687 QubitInitKind::Array(len) => {
688 self.write("Qubit[");
689 self.visit_expr(len);
690 self.write("]");
691 }
692 QubitInitKind::Paren(init) => self.visit_qubit_init(init),
693 QubitInitKind::Single => {
694 self.write("Qubit()");
695 }
696 QubitInitKind::Tuple(inits) => {
697 self.write("(");
698 if let Some((last, most)) = inits.split_last() {
699 for init in most {
700 self.visit_qubit_init(init);
701 self.write(", ");
702 }
703 self.visit_qubit_init(last);
704 self.ensure_trailing_comma_for_arity_one_tuples(most);
705 }
706 self.write(")");
707 }
708 QubitInitKind::Err => unreachable!(),
709 }
710 }
711
712 fn visit_path(&mut self, path: &'_ Path) {
713 for ns in &path.namespace {
714 self.visit_ident(ns);
715 self.write(".");
716 }
717 self.visit_ident(&path.name);
718 }
719
720 fn visit_ident(&mut self, id: &'_ Ident) {
721 self.write(&id.name);
722 }
723}
724
725fn binop_as_str(op: &BinOp) -> &str {
726 match op {
727 BinOp::Add => "+",
728 BinOp::AndB => "&&&",
729 BinOp::AndL => "and",
730 BinOp::Div => "/",
731 BinOp::Eq => "==",
732 BinOp::Exp => "^",
733 BinOp::Gt => ">",
734 BinOp::Gte => ">=",
735 BinOp::Lt => "<",
736 BinOp::Lte => "<=",
737 BinOp::Mod => "%",
738 BinOp::Mul => "*",
739 BinOp::Neq => "!=",
740 BinOp::OrB => "|||",
741 BinOp::OrL => "or",
742 BinOp::Shl => "<<<",
743 BinOp::Shr => ">>>",
744 BinOp::Sub => "-",
745 BinOp::XorB => "^^^",
746 }
747}
748
749fn unop_as_str(op: &UnOp) -> &str {
750 match op {
751 UnOp::Functor(functor) => match functor {
752 Functor::Adj => "Adjoint ",
753 Functor::Ctl => "Controlled ",
754 },
755 UnOp::Neg => "-",
756 UnOp::NotB => "~~~",
757 UnOp::NotL => "not ",
758 UnOp::Pos => "+",
759 UnOp::Unwrap => "!",
760 }
761}
762