microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
alex/bounds

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc_codegen/src/qsharp.rs

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