microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc_codegen/src/qsharp.rs

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