microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
ff48c1817f4645fcb1e9a9ecce338699afb736e4

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_codegen/src/qsharp.rs

767lines · 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, Idents, Item, ItemKind, Lit, Mutability, Pat, PatKind,
19 Path, 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_idents(&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_idents(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 // TODO verify that we actually don't want to do anything here
142 ItemKind::Export(_) | ItemKind::Import(_) => (),
143 }
144 }
145
146 fn visit_attr(&mut self, attr: &'_ Attr) {
147 self.write("@");
148 self.visit_ident(&attr.name);
149 self.visit_expr(&attr.arg);
150 self.writeln("");
151 }
152
153 fn visit_visibility(&mut self, vis: &'_ Visibility) {
154 match vis.kind {
155 VisibilityKind::Public => {}
156 VisibilityKind::Internal => self.write("internal "),
157 }
158 }
159
160 fn visit_ty_def(&mut self, def: &'_ TyDef) {
161 match &*def.kind {
162 TyDefKind::Field(name, ty) => {
163 for n in name {
164 self.visit_ident(n);
165 self.write(": ");
166 }
167 self.visit_ty(ty);
168 }
169 TyDefKind::Paren(def) => self.visit_ty_def(def),
170 TyDefKind::Tuple(defs) => {
171 self.write("(");
172 if let Some((last, most)) = defs.split_last() {
173 for i in most {
174 self.visit_ty_def(i);
175 self.write(", ");
176 }
177 self.visit_ty_def(last);
178 self.ensure_trailing_comma_for_arity_one_tuples(most);
179 }
180 self.write(")");
181 }
182 TyDefKind::Err => {}
183 }
184 }
185
186 fn visit_callable_decl(&mut self, decl: &'_ CallableDecl) {
187 match decl.kind {
188 CallableKind::Function => self.write("function "),
189 CallableKind::Operation => self.write("operation "),
190 }
191 self.visit_ident(&decl.name);
192 if !decl.generics.is_empty() {
193 self.write("<");
194 if let Some((last, most)) = decl.generics.split_last() {
195 for i in most {
196 self.visit_ident(i);
197 self.write(", ");
198 }
199 self.visit_ident(last);
200 }
201
202 self.write(">");
203 }
204
205 self.visit_pat(&decl.input);
206 self.write(" : ");
207 self.visit_ty(&decl.output);
208 if let Some(functors) = decl.functors.as_deref() {
209 self.write(" is ");
210 self.visit_functor_expr(functors);
211 }
212
213 match &*decl.body {
214 CallableBody::Block(block) => {
215 self.visit_block(block);
216 }
217 CallableBody::Specs(specs) => {
218 self.writeln("{");
219 specs.iter().for_each(|s| self.visit_spec_decl(s));
220 self.writeln("}");
221 }
222 }
223 }
224
225 fn visit_spec_decl(&mut self, decl: &'_ SpecDecl) {
226 match decl.spec {
227 ast::Spec::Body => self.write("body "),
228 ast::Spec::Adj => self.write("adjoint "),
229 ast::Spec::Ctl => self.write("controlled "),
230 ast::Spec::CtlAdj => self.write("controlled adjoint "),
231 }
232 match &decl.body {
233 SpecBody::Gen(spec) => match spec {
234 SpecGen::Auto => self.writeln("auto;"),
235 SpecGen::Distribute => self.writeln("distribute;"),
236 SpecGen::Intrinsic => self.writeln("intrinsic;"),
237 SpecGen::Invert => self.writeln("invert;"),
238 SpecGen::Slf => self.writeln("self;"),
239 },
240 SpecBody::Impl(pat, block) => {
241 self.visit_pat(pat);
242 self.visit_block(block);
243 }
244 }
245 }
246
247 fn visit_functor_expr(&mut self, expr: &'_ FunctorExpr) {
248 match &*expr.kind {
249 FunctorExprKind::BinOp(op, lhs, rhs) => {
250 self.visit_functor_expr(lhs);
251 match op {
252 SetOp::Union => self.write(" + "),
253 SetOp::Intersect => self.write(" * "),
254 }
255 self.visit_functor_expr(rhs);
256 }
257 FunctorExprKind::Lit(functor) => match functor {
258 Functor::Adj => self.write("Adj"),
259 Functor::Ctl => self.write("Ctl"),
260 },
261 FunctorExprKind::Paren(expr) => {
262 self.write("(");
263 self.visit_functor_expr(expr);
264 self.write(")");
265 }
266 }
267 }
268
269 fn visit_ty(&mut self, ty: &'_ Ty) {
270 match &*ty.kind {
271 TyKind::Array(item) => {
272 self.visit_ty(item);
273 self.write("[]");
274 }
275 TyKind::Arrow(kind, lhs, rhs, functors) => {
276 self.visit_ty(lhs);
277 match kind {
278 CallableKind::Function => self.write(" -> "),
279 CallableKind::Operation => self.write(" => "),
280 }
281 self.visit_ty(rhs);
282 if let Some(functors) = functors.as_deref() {
283 self.write(" is ");
284 self.visit_functor_expr(functors);
285 }
286 }
287 TyKind::Hole => self.write("_"),
288 TyKind::Paren(ty) => {
289 self.write("(");
290 self.visit_ty(ty);
291 self.write(")");
292 }
293 TyKind::Path(path) => self.visit_path(path),
294 TyKind::Param(name) => self.visit_ident(name),
295 TyKind::Tuple(tys) => {
296 if tys.is_empty() {
297 self.write("()");
298 } else {
299 self.write("(");
300 if let Some((last, most)) = tys.split_last() {
301 for t in most {
302 self.visit_ty(t);
303 self.write(", ");
304 }
305 self.visit_ty(last);
306 self.ensure_trailing_comma_for_arity_one_tuples(most);
307 }
308 self.write(")");
309 }
310 }
311 TyKind::Err => unreachable!(),
312 }
313 }
314
315 fn visit_block(&mut self, block: &'_ Block) {
316 self.writeln(" {");
317 block.stmts.iter().for_each(|s| {
318 self.visit_stmt(s);
319 });
320 self.writeln("}");
321 }
322
323 fn visit_stmt(&mut self, stmt: &'_ Stmt) {
324 match &*stmt.kind {
325 StmtKind::Empty | StmtKind::Err => {}
326 StmtKind::Semi(expr) => {
327 self.visit_expr(expr);
328 self.writeln(";");
329 }
330 StmtKind::Expr(expr) => {
331 self.visit_expr(expr);
332 }
333 StmtKind::Item(item) => self.visit_item(item),
334 StmtKind::Local(mutability, pat, value) => {
335 match mutability {
336 Mutability::Mutable => self.write("mutable "),
337 Mutability::Immutable => self.write("let "),
338 }
339 self.visit_pat(pat);
340 self.write(" = ");
341 self.visit_expr(value);
342 self.writeln(";");
343 }
344 StmtKind::Qubit(source, pat, init, block) => {
345 match source {
346 QubitSource::Dirty => self.write("borrow "),
347 QubitSource::Fresh => self.write("use "),
348 }
349 self.visit_pat(pat);
350 self.write(" = ");
351 self.visit_qubit_init(init);
352 if let Some(b) = block {
353 self.visit_block(b);
354 } else {
355 self.writeln(";");
356 }
357 }
358 }
359 }
360
361 #[allow(clippy::too_many_lines)]
362 fn visit_expr(&mut self, expr: &'_ Expr) {
363 match &*expr.kind {
364 ExprKind::Array(exprs) => {
365 self.write("[");
366 if let Some((last, most)) = exprs.split_last() {
367 for e in most {
368 self.visit_expr(e);
369 self.write(", ");
370 }
371 self.visit_expr(last);
372 }
373 self.write("]");
374 }
375 ExprKind::ArrayRepeat(item, size) => {
376 self.write("[");
377 self.visit_expr(item);
378 self.write(", size = ");
379 self.visit_expr(size);
380 self.write("]");
381 }
382 ExprKind::Assign(lhs, rhs) => {
383 self.write("set ");
384 self.visit_expr(lhs);
385 self.write(" = ");
386 self.visit_expr(rhs);
387 }
388 ExprKind::AssignOp(op, lhs, rhs) => {
389 self.write("set ");
390 self.visit_expr(lhs);
391 self.write(" ");
392 let op_str = binop_as_str(op);
393 self.write(op_str);
394 self.write("= ");
395 self.visit_expr(rhs);
396 }
397 ExprKind::BinOp(op, lhs, rhs) => {
398 self.visit_expr(lhs);
399 self.write(" ");
400 let op_str = binop_as_str(op);
401 self.write(op_str);
402 self.write(" ");
403 self.visit_expr(rhs);
404 }
405 ExprKind::AssignUpdate(record, index, value) => {
406 self.write("set ");
407 self.visit_expr(record);
408 self.write(" w/= ");
409 self.visit_expr(index);
410 self.write(" <- ");
411 self.visit_expr(value);
412 }
413 ExprKind::Block(block) => self.visit_block(block),
414 ExprKind::Call(callee, arg) => {
415 self.visit_expr(callee);
416 self.visit_expr(arg);
417 }
418 ExprKind::Conjugate(within, apply) => {
419 self.write("within");
420 self.visit_block(within);
421 self.write("apply");
422 self.visit_block(apply);
423 }
424 ExprKind::Fail(msg) => {
425 self.write("fail ");
426 self.visit_expr(msg);
427 }
428 ExprKind::Field(record, name) => {
429 self.visit_expr(record);
430 self.write("::");
431 self.visit_ident(name);
432 }
433 ExprKind::For(pat, iter, block) => {
434 self.write("for ");
435 self.visit_pat(pat);
436 self.write(" in ");
437 self.visit_expr(iter);
438 self.write(" ");
439 self.visit_block(block);
440 }
441 ExprKind::If(cond, body, otherwise) => {
442 self.write("if ");
443 self.visit_expr(cond);
444 self.write(" ");
445 self.visit_block(body);
446 for expr in otherwise {
447 if matches!(*expr.kind, ExprKind::If(..)) {
448 // visiting expr as if writes 'if' to make 'elif'
449 self.write(" el");
450 } else {
451 self.write(" else ");
452 }
453 self.visit_expr(expr);
454 }
455 }
456 ExprKind::Index(array, index) => {
457 self.visit_expr(array);
458 self.write("[");
459 self.visit_expr(index);
460 self.write("]");
461 }
462 ExprKind::Interpolate(components) => {
463 self.write("$\"");
464 for component in components.as_ref() {
465 match component {
466 StringComponent::Expr(expr) => {
467 self.write("{");
468 self.visit_expr(expr.as_ref());
469 self.write("}");
470 }
471 StringComponent::Lit(lit) => {
472 self.write(lit);
473 }
474 }
475 }
476 self.write("\"");
477 }
478 ExprKind::Lambda(kind, pat, expr) => {
479 self.visit_pat(pat);
480 match kind {
481 CallableKind::Function => self.write(" -> "),
482 CallableKind::Operation => self.write(" => "),
483 }
484 self.visit_expr(expr);
485 }
486 ExprKind::Paren(expr) => {
487 self.write("(");
488 self.visit_expr(expr);
489 self.write(")");
490 }
491 ExprKind::Return(expr) => {
492 self.write("return ");
493 self.visit_expr(expr);
494 }
495 ExprKind::UnOp(op, expr) => {
496 let op_str = unop_as_str(op);
497 if op == &UnOp::Unwrap {
498 self.visit_expr(expr);
499 self.write(op_str);
500 } else {
501 self.write(op_str);
502 self.visit_expr(expr);
503 }
504 }
505 ExprKind::Path(path) => self.visit_path(path),
506 ExprKind::Range(start, step, end) => {
507 // A range: `start..step..end`, `start..end`, `start...`, `...end`, or `...`.
508 match (start, step, end) {
509 (None, None, None) => {
510 self.write("...");
511 }
512 (None, None, Some(end)) => {
513 self.write("...");
514 self.visit_expr(end);
515 }
516 (None, Some(step), None) => {
517 self.write("...");
518 self.visit_expr(step);
519 self.write("...");
520 }
521 (None, Some(step), Some(end)) => {
522 self.write("...");
523 self.visit_expr(step);
524 self.write("..");
525 self.visit_expr(end);
526 }
527 (Some(start), None, None) => {
528 self.visit_expr(start);
529 self.write("...");
530 }
531 (Some(start), None, Some(end)) => {
532 self.visit_expr(start);
533 self.write("..");
534 self.visit_expr(end);
535 }
536 (Some(start), Some(step), None) => {
537 self.visit_expr(start);
538 self.write("..");
539 self.visit_expr(step);
540 self.write("...");
541 }
542 (Some(start), Some(step), Some(end)) => {
543 self.visit_expr(start);
544 self.write("..");
545 self.visit_expr(step);
546 self.write("..");
547 self.visit_expr(end);
548 }
549 }
550 }
551 ExprKind::Repeat(body, until, fixup) => {
552 self.write("repeat ");
553 self.visit_block(body);
554 self.write("until ");
555 self.visit_expr(until);
556 for fixup in fixup {
557 self.write(" fixup ");
558 self.visit_block(fixup);
559 }
560 }
561 ExprKind::TernOp(op, e1, e2, e3) => {
562 match op {
563 TernOp::Cond => {
564 // Conditional: `a ? b | c`.
565 self.visit_expr(e1);
566 self.write(" ? ");
567 self.visit_expr(e2);
568 self.write(" | ");
569 self.visit_expr(e3);
570 }
571 TernOp::Update => {
572 // Aggregate update: `a w/ b <- c`.
573 self.visit_expr(e1);
574 self.write(" w/ ");
575 self.visit_expr(e2);
576 self.write(" <- ");
577 self.visit_expr(e3);
578 }
579 }
580 }
581 ExprKind::Tuple(exprs) => {
582 self.write("(");
583 if let Some((last, most)) = exprs.split_last() {
584 for e in most {
585 self.visit_expr(e);
586 self.write(", ");
587 }
588 self.visit_expr(last);
589 self.ensure_trailing_comma_for_arity_one_tuples(most);
590 }
591 self.write(")");
592 }
593 ExprKind::While(cond, block) => {
594 self.write("while ");
595 self.visit_expr(cond);
596 self.visit_block(block);
597 }
598 ExprKind::Lit(lit) => match lit.as_ref() {
599 Lit::BigInt(value) => {
600 self.write(value.to_string().as_str());
601 self.write("L");
602 }
603 Lit::Bool(value) => {
604 if *value {
605 self.write("true");
606 } else {
607 self.write("false");
608 }
609 }
610 Lit::Double(value) => {
611 let num_str = if value.fract() == 0.0 {
612 format!("{value}.")
613 } else {
614 format!("{value}")
615 };
616 self.write(&num_str);
617 }
618 Lit::Int(value) => self.write(&value.to_string()),
619 Lit::Pauli(value) => match value {
620 Pauli::I => self.write("PauliI"),
621 Pauli::X => self.write("PauliX"),
622 Pauli::Y => self.write("PauliY"),
623 Pauli::Z => self.write("PauliZ"),
624 },
625 Lit::Result(value) => match value {
626 ast::Result::One => self.write("One"),
627 ast::Result::Zero => self.write("Zero"),
628 },
629 Lit::String(value) => {
630 self.write("\"");
631 self.write(value.as_ref());
632 self.write("\"");
633 }
634 },
635 ExprKind::Hole => {
636 self.write("_");
637 }
638 ExprKind::Err => {
639 unreachable!();
640 }
641 }
642 }
643
644 fn visit_pat(&mut self, pat: &'_ Pat) {
645 match &*pat.kind {
646 PatKind::Bind(name, ty) => {
647 self.visit_ident(name);
648
649 for t in ty {
650 self.write(": ");
651 self.visit_ty(t);
652 }
653 }
654 PatKind::Discard(ty) => {
655 self.write("_");
656 for t in ty {
657 self.write(": ");
658 self.visit_ty(t);
659 }
660 }
661 PatKind::Elided => {
662 self.write("...");
663 }
664 PatKind::Paren(pat) => {
665 self.write("(");
666 self.visit_pat(pat);
667 self.write(")");
668 }
669 PatKind::Tuple(pats) => {
670 self.write("(");
671 if let Some((last, most)) = pats.split_last() {
672 for pat in most {
673 self.visit_pat(pat);
674 self.write(", ");
675 }
676 self.visit_pat(last);
677 self.ensure_trailing_comma_for_arity_one_tuples(most);
678 }
679 self.write(")");
680 }
681 PatKind::Err => {
682 unreachable!();
683 }
684 }
685 }
686
687 fn visit_qubit_init(&mut self, init: &'_ QubitInit) {
688 match &*init.kind {
689 QubitInitKind::Array(len) => {
690 self.write("Qubit[");
691 self.visit_expr(len);
692 self.write("]");
693 }
694 QubitInitKind::Paren(init) => self.visit_qubit_init(init),
695 QubitInitKind::Single => {
696 self.write("Qubit()");
697 }
698 QubitInitKind::Tuple(inits) => {
699 self.write("(");
700 if let Some((last, most)) = inits.split_last() {
701 for init in most {
702 self.visit_qubit_init(init);
703 self.write(", ");
704 }
705 self.visit_qubit_init(last);
706 self.ensure_trailing_comma_for_arity_one_tuples(most);
707 }
708 self.write(")");
709 }
710 QubitInitKind::Err => unreachable!(),
711 }
712 }
713
714 fn visit_path(&mut self, path: &'_ Path) {
715 if let Some(ns) = &path.namespace {
716 self.visit_idents(ns);
717 self.write(".");
718 }
719 self.visit_ident(&path.name);
720 }
721
722 fn visit_ident(&mut self, id: &'_ Ident) {
723 self.write(&id.name);
724 }
725
726 fn visit_idents(&mut self, idents: &'_ Idents) {
727 self.write(&idents.name::<String>());
728 }
729}
730
731fn binop_as_str(op: &BinOp) -> &str {
732 match op {
733 BinOp::Add => "+",
734 BinOp::AndB => "&&&",
735 BinOp::AndL => "and",
736 BinOp::Div => "/",
737 BinOp::Eq => "==",
738 BinOp::Exp => "^",
739 BinOp::Gt => ">",
740 BinOp::Gte => ">=",
741 BinOp::Lt => "<",
742 BinOp::Lte => "<=",
743 BinOp::Mod => "%",
744 BinOp::Mul => "*",
745 BinOp::Neq => "!=",
746 BinOp::OrB => "|||",
747 BinOp::OrL => "or",
748 BinOp::Shl => "<<<",
749 BinOp::Shr => ">>>",
750 BinOp::Sub => "-",
751 BinOp::XorB => "^^^",
752 }
753}
754
755fn unop_as_str(op: &UnOp) -> &str {
756 match op {
757 UnOp::Functor(functor) => match functor {
758 Functor::Adj => "Adjoint ",
759 Functor::Ctl => "Controlled ",
760 },
761 UnOp::Neg => "-",
762 UnOp::NotB => "~~~",
763 UnOp::NotL => "not ",
764 UnOp::Pos => "+",
765 UnOp::Unwrap => "!",
766 }
767}
768