1use std::collections::HashMap;
2use std::ops::Range;
3
4use logos::Logos;
5use miette::Diagnostic as MietteDiagnostic;
6use thiserror::Error;
7
8use crate::ast::{
9 BackendEscapes, BraceSide, Circuit, Control, EscapeBlock, Group, Layout, MeasurementShape,
10 NoteSide, Operation, OperationKind, Orientation, ParityBasis, Shape, Span, Style, Wire,
11 WireKind,
12};
13
14#[derive(Debug, Clone, PartialEq, Eq, MietteDiagnostic, Error)]
19#[error("{message}")]
20#[non_exhaustive]
21pub struct Diagnostic {
22 pub message: String,
24 pub span: Span,
26 #[help]
28 pub help: Option<String>,
29 #[label]
30 label: Option<miette::SourceSpan>,
31 #[related]
32 related: Box<[Diagnostic]>,
33}
34
35impl Diagnostic {
36 fn new(message: impl Into<String>, span: Span) -> Self {
37 Self {
38 message: message.into(),
39 span,
40 help: None,
41 label: Some(span.into()),
42 related: Box::default(),
43 }
44 }
45
46 fn with_help(message: impl Into<String>, help: impl Into<String>, span: Span) -> Self {
47 Self {
48 message: message.into(),
49 span,
50 help: Some(help.into()),
51 label: Some(span.into()),
52 related: Box::default(),
53 }
54 }
55
56 fn multiple(mut diagnostics: Vec<Self>) -> Self {
57 debug_assert!(!diagnostics.is_empty());
58 if diagnostics.len() == 1 {
59 return diagnostics.pop().expect("one diagnostic exists");
60 }
61 Self {
62 message: format!("{} errors found", diagnostics.len()),
63 span: diagnostics[0].span,
64 help: None,
65 label: None,
66 related: diagnostics.into_boxed_slice(),
67 }
68 }
69
70 pub fn related(&self) -> &[Self] {
72 &self.related
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
77enum TokenKind {
78 Identifier(String),
79 String(String),
80 Number(String),
81 LeftBrace,
82 RightBrace,
83 LeftParen,
84 RightParen,
85 LeftBracket,
86 RightBracket,
87 Colon,
88 Equal,
89 Comma,
90 Bang,
91 Arrow,
92 DotDot,
93 Newline,
94 End,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
98struct Token {
99 kind: TokenKind,
100 span: Span,
101}
102
103#[derive(Logos, Debug, Clone, Copy, PartialEq, Eq)]
104#[logos(skip r"[ \t\r]+")]
105#[logos(skip(r"//[^\n]*", allow_greedy = true))]
106enum Lexeme {
107 #[regex(r"[A-Za-z_][A-Za-z0-9_]*")]
108 Identifier,
109 #[regex(r#""([^"\\\n]|\\.)*""#)]
110 String,
111 #[regex(r"[0-9]+(\.[0-9]+)?")]
112 Number,
113 #[token("{")]
114 LeftBrace,
115 #[token("}")]
116 RightBrace,
117 #[token("(")]
118 LeftParen,
119 #[token(")")]
120 RightParen,
121 #[token("[")]
122 LeftBracket,
123 #[token("]")]
124 RightBracket,
125 #[token(":")]
126 Colon,
127 #[token("=")]
128 Equal,
129 #[token(",")]
130 Comma,
131 #[token("!")]
132 Bang,
133 #[token("->")]
134 Arrow,
135 #[token("..")]
136 DotDot,
137 #[token("\n")]
138 #[token(";")]
139 Newline,
140}
141
142pub fn parse(source: &str) -> Result<Circuit, Diagnostic> {
146 Parser::new(lex(source)?).parse_circuit()
147}
148
149fn lex(source: &str) -> Result<Vec<Token>, Diagnostic> {
150 let line_starts = std::iter::once(0)
151 .chain(source.match_indices('\n').map(|(offset, _)| offset + 1))
152 .collect::<Vec<_>>();
153 let mut lexer = Lexeme::lexer(source);
154 let mut tokens = Vec::new();
155 while let Some(lexeme) = lexer.next() {
156 let range = lexer.span();
157 let span = source_span(source, &line_starts, range.clone());
158 let lexeme = lexeme.map_err(|()| lex_error(source, &line_starts, range.clone()))?;
159 let kind = match lexeme {
160 Lexeme::Identifier => TokenKind::Identifier(lexer.slice().into()),
161 Lexeme::String => {
162 TokenKind::String(decode_string(source, &line_starts, range.clone())?)
163 }
164 Lexeme::Number => TokenKind::Number(lexer.slice().into()),
165 Lexeme::LeftBrace => TokenKind::LeftBrace,
166 Lexeme::RightBrace => TokenKind::RightBrace,
167 Lexeme::LeftParen => TokenKind::LeftParen,
168 Lexeme::RightParen => TokenKind::RightParen,
169 Lexeme::LeftBracket => TokenKind::LeftBracket,
170 Lexeme::RightBracket => TokenKind::RightBracket,
171 Lexeme::Colon => TokenKind::Colon,
172 Lexeme::Equal => TokenKind::Equal,
173 Lexeme::Comma => TokenKind::Comma,
174 Lexeme::Bang => TokenKind::Bang,
175 Lexeme::Arrow => TokenKind::Arrow,
176 Lexeme::DotDot => TokenKind::DotDot,
177 Lexeme::Newline => TokenKind::Newline,
178 };
179 tokens.push(Token { kind, span });
180 }
181 tokens.push(Token {
182 kind: TokenKind::End,
183 span: source_span(source, &line_starts, source.len()..source.len()),
184 });
185 Ok(tokens)
186}
187
188fn source_span(source: &str, line_starts: &[usize], range: Range<usize>) -> Span {
189 let line_index = line_starts
190 .partition_point(|start| *start <= range.start)
191 .saturating_sub(1);
192 Span {
193 offset: range.start,
194 length: range.len(),
195 line: line_index + 1,
196 column: source[line_starts[line_index]..range.start].chars().count() + 1,
197 }
198}
199
200fn decode_string(
201 source: &str,
202 line_starts: &[usize],
203 range: Range<usize>,
204) -> Result<String, Diagnostic> {
205 let mut value = String::new();
206 let mut characters = source[range.start + 1..range.end - 1].char_indices();
207 while let Some((_, character)) = characters.next() {
208 if character != '\\' {
209 value.push(character);
210 continue;
211 }
212 let (offset, escaped) = characters
213 .next()
214 .expect("the string token ends after a complete escape");
215 match escaped {
216 'n' => value.push('\n'),
217 'r' => value.push('\r'),
218 't' => value.push('\t'),
219 '"' | '\\' => value.push(escaped),
220 '$' => value.push_str(r"\$"),
221 _ => {
222 let start = range.start + 1 + offset;
223 return Err(Diagnostic::new(
224 format!("unknown string escape `\\{escaped}`"),
225 source_span(source, line_starts, start..start + escaped.len_utf8()),
226 ));
227 }
228 }
229 }
230 Ok(value)
231}
232
233fn lex_error(source: &str, line_starts: &[usize], range: Range<usize>) -> Diagnostic {
234 let character = source[range.clone()]
235 .chars()
236 .next()
237 .expect("logos errors cover at least one character");
238 if character != '"' {
239 return Diagnostic::new(
240 format!("unexpected character `{character}`"),
241 source_span(source, line_starts, range),
242 );
243 }
244
245 let opening = source_span(source, line_starts, range.clone());
246 let mut characters = source[range.end..].char_indices();
247 while let Some((offset, character)) = characters.next() {
248 if character == '\n' {
249 let start = range.end + offset;
250 return Diagnostic::new(
251 "strings cannot cross lines",
252 source_span(source, line_starts, start..start + 1),
253 );
254 }
255 if character == '\\' {
256 match characters.next() {
257 Some((offset, '\n')) => {
258 let start = range.end + offset;
259 return Diagnostic::new(
260 "strings cannot cross lines",
261 source_span(source, line_starts, start..start + 1),
262 );
263 }
264 Some(_) => {}
265 None => return Diagnostic::new("unterminated string escape", opening),
266 }
267 }
268 }
269 Diagnostic::new("unterminated string", opening)
270}
271
272fn is_reserved_statement(name: &str) -> bool {
273 matches!(
274 name,
275 "circuit"
276 | "import"
277 | "fn"
278 | "let"
279 | "style"
280 | "layout"
281 | "backend"
282 | "qubit"
283 | "bit"
284 | "hidden"
285 | "ellipsis"
286 | "autowires"
287 | "h"
288 | "x"
289 | "y"
290 | "z"
291 | "s"
292 | "t"
293 | "gate"
294 | "phase"
295 | "measure"
296 | "swap"
297 | "barrier"
298 | "set"
299 | "start"
300 | "end"
301 | "label"
302 | "equals"
303 | "bundle"
304 | "permute"
305 | "space"
306 | "touch"
307 | "repeat"
308 | "reverse"
309 | "parallel"
310 | "overlay"
311 | "labels"
312 | "brace"
313 | "note"
314 | "above"
315 | "below"
316 | "cut"
317 | "mark"
318 | "group"
319 | "if"
320 | "on"
321 | "as"
322 | "to"
323 | "from"
324 | "here"
325 | "with"
326 | "using"
327 | "braced"
328 | "latex"
329 | "typst"
330 | "preamble"
331 | "before"
332 | "after"
333 )
334}
335
336fn is_style_property(name: &str) -> bool {
337 matches!(
338 name,
339 "stroke" | "fill" | "link" | "width" | "height" | "size" | "shape" | "dash" | "opacity"
340 )
341}
342
343struct Parser {
344 tokens: Vec<Token>,
345 position: usize,
346 wires: Vec<Wire>,
347 wire_indices: HashMap<String, usize>,
348 operations: Vec<Operation>,
349 layout: Layout,
350 functions: HashMap<String, Function>,
351 values: HashMap<String, String>,
352 styles: HashMap<String, Style>,
353 in_function: bool,
354 operation_block_depth: usize,
355 marks: HashMap<String, usize>,
356 groups: Vec<Group>,
357 escapes: BackendEscapes,
358 auto_wires: bool,
359 next_overlay: usize,
360}
361
362#[derive(Clone, Copy)]
363struct Checkpoint {
364 position: usize,
365 wires: usize,
366 operations: usize,
367 groups: usize,
368 operation_block_depth: usize,
369 next_overlay: usize,
370}
371
372#[derive(Clone)]
373struct Function {
374 parameters: Vec<String>,
375 body: Vec<Operation>,
376}
377
378impl Parser {
379 fn new(tokens: Vec<Token>) -> Self {
380 Self {
381 tokens,
382 position: 0,
383 wires: Vec::new(),
384 wire_indices: HashMap::new(),
385 operations: Vec::new(),
386 layout: Layout::default(),
387 functions: HashMap::new(),
388 values: HashMap::new(),
389 styles: HashMap::new(),
390 in_function: false,
391 operation_block_depth: 0,
392 marks: HashMap::new(),
393 groups: Vec::new(),
394 escapes: BackendEscapes::default(),
395 auto_wires: false,
396 next_overlay: 0,
397 }
398 }
399
400 fn parse_circuit(mut self) -> Result<Circuit, Diagnostic> {
401 self.skip_newlines();
402 while self.at_keyword("fn") || self.at_keyword("let") || self.at_keyword("style") {
403 if self.at_keyword("fn") {
404 self.parse_function_definition()?;
405 } else if self.at_keyword("let") {
406 self.parse_value_definition()?;
407 } else {
408 self.parse_style_definition()?;
409 }
410 self.skip_newlines();
411 }
412 self.expect_keyword("circuit")?;
413 let name = self.take_identifier("circuit name")?;
414 self.expect(TokenKind::LeftBrace, "`{`")?;
415 self.skip_newlines();
416
417 let mut diagnostics = Vec::new();
418 while !self.at(&TokenKind::RightBrace) && !self.at(&TokenKind::End) {
419 let checkpoint = self.checkpoint();
420 if let Err(diagnostic) = self.parse_statement() {
421 self.restore(checkpoint);
422 self.recover_statement();
423 diagnostics.push(diagnostic);
424 }
425 self.skip_newlines();
426 }
427 if self.at(&TokenKind::End) {
428 diagnostics.push(self.error("expected `}` to close the circuit"));
429 } else {
430 self.advance();
431 self.skip_newlines();
432 if let Err(diagnostic) = self.expect(TokenKind::End, "end of file") {
433 diagnostics.push(diagnostic);
434 }
435 }
436 if !diagnostics.is_empty() {
437 return Err(Diagnostic::multiple(diagnostics));
438 }
439
440 if self.wires.is_empty() {
441 return Err(Diagnostic::new(
442 "a circuit needs at least one wire",
443 Span {
444 offset: 0,
445 length: 0,
446 line: 1,
447 column: 1,
448 },
449 ));
450 }
451 self.resolve_active_defaults()?;
452
453 Ok(Circuit {
454 name,
455 layout: self.layout,
456 wires: self.wires,
457 operations: self.operations,
458 groups: self.groups,
459 escapes: self.escapes,
460 })
461 }
462
463 fn checkpoint(&self) -> Checkpoint {
464 Checkpoint {
465 position: self.position,
466 wires: self.wires.len(),
467 operations: self.operations.len(),
468 groups: self.groups.len(),
469 operation_block_depth: self.operation_block_depth,
470 next_overlay: self.next_overlay,
471 }
472 }
473
474 fn restore(&mut self, checkpoint: Checkpoint) {
475 self.position = checkpoint.position;
476 self.wires.truncate(checkpoint.wires);
477 self.wire_indices.retain(|_, wire| *wire < checkpoint.wires);
478 self.operations.truncate(checkpoint.operations);
479 self.groups.truncate(checkpoint.groups);
480 self.operation_block_depth = checkpoint.operation_block_depth;
481 self.next_overlay = checkpoint.next_overlay;
482 }
483
484 fn resolve_active_defaults(&mut self) -> Result<(), Diagnostic> {
485 let wire_count = self.wires.len();
486 let mut active = (0..wire_count)
487 .map(|wire| {
488 !self
489 .operations
490 .iter()
491 .find_map(|operation| {
492 if let OperationKind::Endpoint { wires, start, .. } = &operation.kind
493 && (wires.is_empty() || wires.contains(&wire))
494 {
495 Some(*start)
496 } else {
497 None
498 }
499 })
500 .unwrap_or(false)
501 })
502 .collect::<Vec<_>>();
503
504 for operation in &mut self.operations {
505 let active_wires = || {
506 active
507 .iter()
508 .enumerate()
509 .filter_map(|(wire, is_active)| is_active.then_some(wire))
510 .collect::<Vec<_>>()
511 };
512 let inactive_wires = || {
513 active
514 .iter()
515 .enumerate()
516 .filter_map(|(wire, is_active)| (!is_active).then_some(wire))
517 .collect::<Vec<_>>()
518 };
519
520 let defaulted_empty = match &mut operation.kind {
521 OperationKind::Endpoint { wires, start, .. } if wires.is_empty() => {
522 *wires = if *start {
523 inactive_wires()
524 } else {
525 active_wires()
526 };
527 wires.is_empty()
528 }
529 OperationKind::Barrier { wires }
530 | OperationKind::Label { wires, .. }
531 | OperationKind::Phantom { wires }
532 | OperationKind::Touch { wires }
533 | OperationKind::WireLabels { wires, .. }
534 | OperationKind::Brace { wires, .. }
535 | OperationKind::Note { wires, .. }
536 | OperationKind::Cut { wires, .. }
537 if wires.is_empty() =>
538 {
539 *wires = active_wires();
540 wires.is_empty()
541 }
542 _ => false,
543 };
544 if defaulted_empty {
545 return Err(Diagnostic::new(
546 "the targetless statement has no applicable active wires",
547 operation.span,
548 ));
549 }
550 if let OperationKind::WireLabels { wires, labels } = &operation.kind
551 && labels.len() != 1
552 && labels.len() != wires.len()
553 {
554 return Err(Diagnostic::new(
555 format!(
556 "labels needs one label or one per selected wire ({}), but got {}",
557 wires.len(),
558 labels.len()
559 ),
560 operation.span,
561 ));
562 }
563 if let OperationKind::Endpoint { wires, start, .. } = &operation.kind {
564 for wire in wires {
565 active[*wire] = *start;
566 }
567 }
568 }
569 Ok(())
570 }
571
572 fn parse_value_definition(&mut self) -> Result<(), Diagnostic> {
573 let span = self.current().span;
574 self.expect_keyword("let")?;
575 let name = self.take_identifier("value name")?;
576 if is_reserved_statement(&name)
577 || self.values.contains_key(&name)
578 || self.styles.contains_key(&name)
579 || self.functions.contains_key(&name)
580 {
581 return Err(Diagnostic::new(
582 format!("definition name `{name}` is reserved or already used"),
583 span,
584 ));
585 }
586 self.expect(TokenKind::Equal, "`=`")?;
587 let value = self.take_label("string or earlier value")?;
588 self.expect_statement_end()?;
589 self.values.insert(name, value);
590 Ok(())
591 }
592
593 fn parse_style_definition(&mut self) -> Result<(), Diagnostic> {
594 let span = self.current().span;
595 self.expect_keyword("style")?;
596 let name = self.take_identifier("style name")?;
597 if is_reserved_statement(&name)
598 || is_style_property(&name)
599 || self.values.contains_key(&name)
600 || self.styles.contains_key(&name)
601 || self.functions.contains_key(&name)
602 {
603 return Err(Diagnostic::new(
604 format!("definition name `{name}` is reserved or already used"),
605 span,
606 ));
607 }
608 self.expect(TokenKind::LeftBrace, "`{`")?;
609 let mut style = Style::default();
610 self.skip_newlines();
611 while !self.at(&TokenKind::RightBrace) {
612 self.parse_style_property(&mut style)?;
613 self.expect_statement_end()?;
614 self.skip_newlines();
615 }
616 self.advance();
617 self.expect_statement_end()?;
618 self.styles.insert(name, style);
619 Ok(())
620 }
621
622 fn parse_function_definition(&mut self) -> Result<(), Diagnostic> {
623 let span = self.current().span;
624 self.expect_keyword("fn")?;
625 let name = self.take_identifier("function name")?;
626 if is_reserved_statement(&name) {
627 return Err(Diagnostic::new(
628 format!("function name `{name}` is reserved"),
629 span,
630 ));
631 }
632 if self.functions.contains_key(&name)
633 || self.values.contains_key(&name)
634 || self.styles.contains_key(&name)
635 {
636 return Err(Diagnostic::new(
637 format!("function `{name}` is already defined"),
638 span,
639 ));
640 }
641 self.expect(TokenKind::LeftParen, "`(`")?;
642 let mut parameters = Vec::new();
643 if !self.at(&TokenKind::RightParen) {
644 loop {
645 let parameter_span = self.current().span;
646 let parameter = self.take_identifier("parameter name")?;
647 if parameters.contains(¶meter) {
648 return Err(Diagnostic::new(
649 format!("parameter `{parameter}` is repeated"),
650 parameter_span,
651 ));
652 }
653 parameters.push(parameter);
654 if !self.consume(&TokenKind::Comma) {
655 break;
656 }
657 }
658 }
659 self.expect(TokenKind::RightParen, "`)`")?;
660 self.expect(TokenKind::LeftBrace, "`{`")?;
661
662 let circuit_wires = std::mem::take(&mut self.wires);
663 let circuit_indices = std::mem::take(&mut self.wire_indices);
664 let circuit_operations = std::mem::take(&mut self.operations);
665 self.wires = parameters
666 .iter()
667 .map(|parameter| Wire {
668 name: parameter.clone(),
669 kind: WireKind::Quantum,
670 ellipsis: false,
671 input: None,
672 output: None,
673 style: Style::default(),
674 })
675 .collect();
676 self.wire_indices = parameters
677 .iter()
678 .enumerate()
679 .map(|(index, parameter)| (parameter.clone(), index))
680 .collect();
681 self.in_function = true;
682 self.skip_newlines();
683 while !self.at(&TokenKind::RightBrace) {
684 if self.at(&TokenKind::End) {
685 return Err(self.error("expected `}` to close the function"));
686 }
687 self.parse_statement()?;
688 self.skip_newlines();
689 }
690 self.advance();
691 let body = std::mem::take(&mut self.operations);
692 self.wires = circuit_wires;
693 self.wire_indices = circuit_indices;
694 self.operations = circuit_operations;
695 self.in_function = false;
696 self.functions.insert(name, Function { parameters, body });
697 self.expect_statement_end()
698 }
699
700 fn parse_statement(&mut self) -> Result<(), Diagnostic> {
701 let span = self.current().span;
702 let keyword = self.take_identifier("statement")?;
703 if (self.in_function || self.operation_block_depth > 0)
704 && matches!(
705 keyword.as_str(),
706 "layout" | "backend" | "qubit" | "bit" | "hidden" | "autowires" | "mark" | "group"
707 )
708 {
709 return Err(Diagnostic::new(
710 "operation blocks may contain operations and function calls, not declarations",
711 span,
712 ));
713 }
714 match keyword.as_str() {
715 "layout" => self.parse_layout(),
716 "backend" => self.parse_backend(),
717 "qubit" => self.parse_wire_declaration(WireKind::Quantum, false),
718 "bit" => self.parse_wire_declaration(WireKind::Classical, false),
719 "hidden" => self.parse_wire_declaration(WireKind::Hidden, false),
720 "ellipsis" => self.parse_wire_declaration(WireKind::Hidden, true),
721 "autowires" => self.parse_autowires(),
722 "h" | "x" | "y" | "z" | "s" | "t" => {
723 self.parse_builtin_gate(keyword.to_ascii_uppercase(), span)
724 }
725 "gate" => self.parse_named_gate(span),
726 "phase" => self.parse_phase_gate(span),
727 "measure" => self.parse_measure(span),
728 "swap" => self.parse_swap(span),
729 "barrier" => self.parse_barrier(span),
730 "set" => self.parse_wire_change(span),
731 "start" => self.parse_endpoint(span, true),
732 "end" => self.parse_endpoint(span, false),
733 "label" => self.parse_label(span),
734 "equals" => self.parse_equals(span),
735 "bundle" => self.parse_bundle(span),
736 "permute" => self.parse_permute(span),
737 "space" => self.parse_phantom(span),
738 "touch" => self.parse_touch(span),
739 "repeat" => self.parse_repeat(span),
740 "reverse" => self.parse_reverse(span),
741 "parallel" => self.parse_parallel(span),
742 "overlay" => self.parse_overlay(span),
743 "labels" => self.parse_wire_labels(span),
744 "brace" => self.parse_brace(span),
745 "note" => self.parse_note(span),
746 "cut" => self.parse_cut(span),
747 "mark" => self.parse_mark(span),
748 "group" => self.parse_group(span),
749 name if self.functions.contains_key(name) => self.parse_function_call(name, span),
750 _ => Err(Diagnostic::new(
751 format!("unknown statement `{keyword}`"),
752 span,
753 )),
754 }
755 }
756
757 fn parse_function_call(&mut self, name: &str, span: Span) -> Result<(), Diagnostic> {
758 self.expect(TokenKind::LeftParen, "`(` after the function name")?;
759 let mut arguments = Vec::new();
760 if !self.at(&TokenKind::RightParen) {
761 loop {
762 arguments.extend(self.parse_wire_selection(true)?);
763 if !self.consume(&TokenKind::Comma) {
764 break;
765 }
766 }
767 }
768 self.expect(TokenKind::RightParen, "`)`")?;
769 self.expect_statement_end()?;
770 let function = self
771 .functions
772 .get(name)
773 .cloned()
774 .expect("function dispatch checked the name");
775 if arguments.len() != function.parameters.len() {
776 return Err(Diagnostic::new(
777 format!(
778 "function `{name}` expects {} wire argument(s), but got {}",
779 function.parameters.len(),
780 arguments.len()
781 ),
782 span,
783 ));
784 }
785 self.ensure_unique(&arguments, span, "function argument")?;
786 let start = self.operations.len();
787 self.operations
788 .extend(function.body.into_iter().map(|operation| Operation {
789 kind: operation.kind.remap_wires(&arguments),
790 span,
791 style: operation.style,
792 overlay: operation.overlay,
793 }));
794 self.freshen_overlays(start);
795 Ok(())
796 }
797
798 fn parse_repeat(&mut self, span: Span) -> Result<(), Diagnostic> {
799 let count = self.take_number("repeat count")?;
800 let body = self.parse_operation_block("repeat")?;
801 let added = body
802 .len()
803 .checked_mul(count)
804 .ok_or_else(|| Diagnostic::new("repeat block is too large", span))?;
805 self.operations
806 .try_reserve(added)
807 .map_err(|_| Diagnostic::new("repeat block is too large", span))?;
808 for _ in 0..count {
809 let start = self.operations.len();
810 self.operations.extend(body.iter().cloned());
811 self.freshen_overlays(start);
812 }
813 Ok(())
814 }
815
816 fn parse_reverse(&mut self, span: Span) -> Result<(), Diagnostic> {
817 let mut body = if self.consume_keyword("from") {
818 let start_span = self.current().span;
819 let start_name = self.take_identifier("start mark")?;
820 let start = self.marks.get(&start_name).copied().ok_or_else(|| {
821 Diagnostic::new(format!("unknown mark `{start_name}`"), start_span)
822 })?;
823 self.expect_keyword("to")?;
824 let end = if self.consume_keyword("here") {
825 self.operations.len()
826 } else {
827 let end_span = self.current().span;
828 let end_name = self.take_identifier("end mark or `here`")?;
829 self.marks.get(&end_name).copied().ok_or_else(|| {
830 Diagnostic::new(format!("unknown mark `{end_name}`"), end_span)
831 })?
832 };
833 self.expect_statement_end()?;
834 if start >= end {
835 return Err(Diagnostic::new(
836 "a reversed range must contain at least one operation",
837 span,
838 ));
839 }
840 self.operations[start..end].to_vec()
841 } else {
842 self.parse_operation_block("reverse")?
843 };
844 body.reverse();
845 let start = self.operations.len();
846 self.operations.extend(body);
847 self.freshen_overlays(start);
848 Ok(())
849 }
850
851 fn parse_parallel(&mut self, span: Span) -> Result<(), Diagnostic> {
852 let body = self.parse_operation_block("parallel")?;
853 if body.is_empty() {
854 return Ok(());
855 }
856 let touch = || Operation {
857 kind: OperationKind::Touch { wires: Vec::new() },
858 span,
859 style: Style::default(),
860 overlay: None,
861 };
862 self.operations.push(touch());
863 self.operations.extend(body);
864 self.operations.push(touch());
865 Ok(())
866 }
867
868 fn parse_overlay(&mut self, span: Span) -> Result<(), Diagnostic> {
869 let mut body = self.parse_operation_block("overlay")?;
870 if body.is_empty() {
871 return Ok(());
872 }
873 if let Some(operation) = body.iter().find(|operation| {
874 matches!(
875 operation.kind,
876 OperationKind::Endpoint { .. } | OperationKind::Permute { .. }
877 )
878 }) {
879 return Err(Diagnostic::new(
880 "overlay blocks cannot contain lifecycle changes or permutations",
881 operation.span,
882 ));
883 }
884 let mut occupied = vec![false; self.wires.len()];
885 for operation in &body {
886 if matches!(operation.kind, OperationKind::Note { .. }) {
887 continue;
888 }
889 for wire in operation
890 .kind
891 .occupied_wires(self.wires.len())
892 .iter()
893 .copied()
894 {
895 if std::mem::replace(&mut occupied[wire], true) {
896 return Err(Diagnostic::with_help(
897 format!(
898 "overlay operations cannot share wire `{}`",
899 self.wires[wire].name
900 ),
901 "use `parallel` to serialize operations on the same wire",
902 span,
903 ));
904 }
905 }
906 }
907 let overlay = self.next_overlay;
908 self.next_overlay += 1;
909 for operation in &mut body {
910 operation.overlay = Some(overlay);
911 }
912 self.operations.extend(body);
913 Ok(())
914 }
915
916 fn freshen_overlays(&mut self, start: usize) {
917 let mut overlays = HashMap::new();
918 for operation in &mut self.operations[start..] {
919 let Some(old) = operation.overlay else {
920 continue;
921 };
922 let next_overlay = &mut self.next_overlay;
923 operation.overlay = Some(*overlays.entry(old).or_insert_with(|| {
924 let overlay = *next_overlay;
925 *next_overlay += 1;
926 overlay
927 }));
928 }
929 }
930
931 fn parse_operation_block(&mut self, name: &str) -> Result<Vec<Operation>, Diagnostic> {
932 self.expect(TokenKind::LeftBrace, "`{`")?;
933 let start = self.operations.len();
934 self.operation_block_depth += 1;
936 self.skip_newlines();
937 while !self.at(&TokenKind::RightBrace) {
938 if self.at(&TokenKind::End) {
939 return Err(self.error(format!("expected `}}` to close the {name} block")));
940 }
941 self.parse_statement()?;
942 self.skip_newlines();
943 }
944 self.advance();
945 self.operation_block_depth -= 1;
946 let body = self.operations.split_off(start);
947 self.expect_statement_end()?;
948 Ok(body)
949 }
950
951 fn recover_statement(&mut self) {
952 let mut braces = 0_usize;
953 loop {
954 match self.current().kind {
955 TokenKind::End => break,
956 TokenKind::LeftBrace => {
957 braces += 1;
958 self.advance();
959 }
960 TokenKind::RightBrace if braces == 0 => break,
961 TokenKind::RightBrace => {
962 braces -= 1;
963 self.advance();
964 if braces == 0 {
965 break;
966 }
967 }
968 TokenKind::Newline if braces == 0 => {
969 self.advance();
970 break;
971 }
972 _ => self.advance(),
973 }
974 }
975 }
976
977 fn parse_layout(&mut self) -> Result<(), Diagnostic> {
978 let mut layout = self.layout.clone();
979 self.expect(TokenKind::LeftBrace, "`{`")?;
980 self.skip_newlines();
981 while !self.at(&TokenKind::RightBrace) {
982 let span = self.current().span;
983 let property = self.take_identifier("layout property")?;
984 self.expect(TokenKind::Colon, "`:`")?;
985 match property.as_str() {
986 "orientation" => {
987 let value = self.take_identifier("`horizontal` or `vertical`")?;
988 layout.orientation = match value.as_str() {
989 "horizontal" => Orientation::Horizontal,
990 "vertical" => Orientation::Vertical,
991 _ => {
992 return Err(Diagnostic::new(
993 "orientation must be `horizontal` or `vertical`",
994 span,
995 ));
996 }
997 };
998 }
999 "scale" => {
1000 layout.scale = self.take_positive_scalar("layout scale")?;
1001 }
1002 "column_gap" => {
1003 layout.column_gap = self.take_positive_scalar("column gap")?;
1004 }
1005 "wire_gap" => {
1006 layout.wire_gap = self.take_positive_scalar("wire gap")?;
1007 }
1008 "gate_size" => {
1009 layout.gate_size = self.take_positive_scalar("gate size")?;
1010 }
1011 "corner_radius" => {
1012 layout.corner_radius = self.take_scalar("corner radius")?;
1013 if layout.corner_radius < 0.0 {
1014 return Err(Diagnostic::new("corner radius cannot be negative", span));
1015 }
1016 }
1017 "comment_width" => {
1018 layout.comment_width = self.take_positive_scalar("comment width")?;
1019 }
1020 "background" => layout.background = self.take_color("background color")?,
1021 _ => {
1022 return Err(Diagnostic::new(
1023 format!("unknown layout property `{property}`"),
1024 span,
1025 ));
1026 }
1027 }
1028 self.expect_statement_end()?;
1029 self.skip_newlines();
1030 }
1031 self.advance();
1032 self.expect_statement_end()?;
1033 self.layout = layout;
1034 Ok(())
1035 }
1036
1037 fn parse_backend(&mut self) -> Result<(), Diagnostic> {
1038 let target_span = self.current().span;
1039 let target = self.take_identifier("`latex` or `typst`")?;
1040 if !matches!(target.as_str(), "latex" | "typst") {
1041 return Err(Diagnostic::new(
1042 "backend target must be `latex` or `typst`",
1043 target_span,
1044 ));
1045 }
1046 self.expect(TokenKind::LeftBrace, "`{`")?;
1047 let mut block = EscapeBlock::default();
1048 self.skip_newlines();
1049 while !self.at(&TokenKind::RightBrace) {
1050 let section_span = self.current().span;
1051 let section = self.take_identifier("`preamble`, `before`, or `after`")?;
1052 self.expect(TokenKind::Colon, "`:`")?;
1053 let code = self.take_string("backend code string")?;
1054 match section.as_str() {
1055 "preamble" => block.preamble.push(code),
1056 "before" => block.before.push(code),
1057 "after" => block.after.push(code),
1058 _ => {
1059 return Err(Diagnostic::new(
1060 "backend section must be `preamble`, `before`, or `after`",
1061 section_span,
1062 ));
1063 }
1064 }
1065 self.expect_statement_end()?;
1066 self.skip_newlines();
1067 }
1068 self.advance();
1069 self.expect_statement_end()?;
1070
1071 let destination = if target == "latex" {
1072 &mut self.escapes.latex
1073 } else {
1074 &mut self.escapes.typst
1075 };
1076 destination.preamble.extend(block.preamble);
1077 destination.before.extend(block.before);
1078 destination.after.extend(block.after);
1079 Ok(())
1080 }
1081
1082 fn parse_wire_declaration(&mut self, kind: WireKind, ellipsis: bool) -> Result<(), Diagnostic> {
1083 let span = self.current().span;
1084 let base = self.take_identifier("wire name")?;
1085 let count = if self.consume(&TokenKind::LeftBracket) {
1086 let count = self.take_number("wire count")?;
1087 self.expect(TokenKind::RightBracket, "`]`")?;
1088 if count == 0 {
1089 return Err(Diagnostic::new("wire arrays cannot be empty", span));
1090 }
1091 Some(count)
1092 } else {
1093 None
1094 };
1095 let input = if self.consume(&TokenKind::Colon) {
1096 Some(self.take_string("input label")?)
1097 } else {
1098 None
1099 };
1100 let output = if self.consume(&TokenKind::Arrow) {
1101 Some(self.take_string("output label")?)
1102 } else {
1103 None
1104 };
1105 let style = self.parse_style()?;
1106 self.expect_statement_end()?;
1107
1108 if ellipsis && count.is_some() {
1109 return Err(Diagnostic::new(
1110 "an ellipsis declaration names one visual gap",
1111 span,
1112 ));
1113 }
1114
1115 let names = count.map_or_else(
1116 || vec![base.clone()],
1117 |length| {
1118 (0..length)
1119 .map(|index| format!("{base}[{index}]"))
1120 .collect()
1121 },
1122 );
1123 for name in names {
1124 if self.wire_indices.contains_key(&name) {
1125 return Err(Diagnostic::new(
1126 format!("wire `{name}` is already declared"),
1127 span,
1128 ));
1129 }
1130 let index = self.wires.len();
1131 self.wire_indices.insert(name.clone(), index);
1132 self.wires.push(Wire {
1133 name,
1134 kind,
1135 ellipsis,
1136 input: input.clone().or_else(|| ellipsis.then(|| "...".into())),
1137 output: output.clone().or_else(|| ellipsis.then(|| "...".into())),
1138 style: style.clone(),
1139 });
1140 }
1141 Ok(())
1142 }
1143
1144 fn parse_autowires(&mut self) -> Result<(), Diagnostic> {
1145 self.expect_statement_end()?;
1146 self.auto_wires = true;
1147 Ok(())
1148 }
1149
1150 fn parse_builtin_gate(&mut self, label: String, span: Span) -> Result<(), Diagnostic> {
1151 let target = self.parse_wire_reference()?;
1152 let controls = self.parse_controls()?;
1153 let style = self.parse_style()?;
1154 self.expect_statement_end()?;
1155 self.push_gate(label, vec![target], controls, style, span)
1156 }
1157
1158 fn parse_named_gate(&mut self, span: Span) -> Result<(), Diagnostic> {
1159 let label = self.take_label("gate label")?;
1160 self.expect_keyword("on")?;
1161 let targets = self.parse_wire_list()?;
1162 let controls = self.parse_controls()?;
1163 let style = self.parse_style()?;
1164 self.expect_statement_end()?;
1165 self.push_gate(label, targets, controls, style, span)
1166 }
1167
1168 fn parse_phase_gate(&mut self, span: Span) -> Result<(), Diagnostic> {
1169 let phase = self.take_label("phase label")?;
1170 self.expect_keyword("on")?;
1171 let target = self.parse_wire_reference()?;
1172 let controls = self.parse_controls()?;
1173 let mut style = self.parse_style()?;
1174 style.shape.get_or_insert(Shape::Circle);
1178 self.expect_statement_end()?;
1179 self.push_gate(phase, vec![target], controls, style, span)
1180 }
1181
1182 fn parse_measure(&mut self, span: Span) -> Result<(), Diagnostic> {
1183 let targets = self.parse_wire_list()?;
1184 let label = if self.consume_keyword("as") {
1185 Some(self.take_label("measurement label")?)
1186 } else {
1187 None
1188 };
1189 let explicit_shape = self.consume_keyword("using");
1190 let shape = if explicit_shape {
1191 let shape_span = self.current().span;
1192 match self.take_identifier("`d` or `tag`")?.as_str() {
1193 "d" => MeasurementShape::D,
1194 "tag" => MeasurementShape::Tag,
1195 _ => {
1196 return Err(Diagnostic::new(
1197 "measurement shape must be `d` or `tag`",
1198 shape_span,
1199 ));
1200 }
1201 }
1202 } else {
1203 MeasurementShape::D
1204 };
1205 let style = self.parse_style()?;
1206 self.expect_statement_end()?;
1207 if label.is_none() && explicit_shape {
1208 return Err(Diagnostic::new(
1209 "a shaped measurement needs a label introduced by `as`",
1210 span,
1211 ));
1212 }
1213 if style.shape.is_some() {
1214 return Err(Diagnostic::with_help(
1215 "the generic `shape` style does not apply to measurements",
1216 "use `using d` or `using tag` after the measurement target",
1217 span,
1218 ));
1219 }
1220 self.ensure_unique(&targets, span, "measurement target")?;
1221 self.operations.push(Operation {
1222 kind: OperationKind::Measure {
1223 targets,
1224 label,
1225 shape,
1226 },
1227 span,
1228 style,
1229 overlay: None,
1230 });
1231 Ok(())
1232 }
1233
1234 fn parse_swap(&mut self, span: Span) -> Result<(), Diagnostic> {
1235 let left = self.parse_wire_reference()?;
1236 self.expect(TokenKind::Comma, "`,`")?;
1237 let right = self.parse_wire_reference()?;
1238 let style = self.parse_style()?;
1239 self.expect_statement_end()?;
1240 if left == right {
1241 return Err(Diagnostic::new(
1242 "a wire cannot be swapped with itself",
1243 span,
1244 ));
1245 }
1246 self.operations.push(Operation {
1247 kind: OperationKind::Swap { left, right },
1248 span,
1249 style,
1250 overlay: None,
1251 });
1252 Ok(())
1253 }
1254
1255 fn parse_barrier(&mut self, span: Span) -> Result<(), Diagnostic> {
1256 let wires = if self.at_statement_end() || self.at_keyword("with") {
1257 Vec::new()
1258 } else {
1259 self.parse_wire_list()?
1260 };
1261 let style = self.parse_style()?;
1262 self.expect_statement_end()?;
1263 self.ensure_unique(&wires, span, "barrier wire")?;
1264 self.operations.push(Operation {
1265 kind: OperationKind::Barrier { wires },
1266 span,
1267 style,
1268 overlay: None,
1269 });
1270 Ok(())
1271 }
1272
1273 fn parse_wire_change(&mut self, span: Span) -> Result<(), Diagnostic> {
1274 let wires = self.parse_wire_list()?;
1275 self.expect_keyword("to")?;
1276 let kind = self.parse_wire_kind()?;
1277 let label = if self.consume_keyword("as") {
1278 Some(self.take_label("known wire value")?)
1279 } else {
1280 None
1281 };
1282 let style = self.parse_style()?;
1283 self.expect_statement_end()?;
1284 if label.is_some() && kind == WireKind::Classical {
1285 return Err(Diagnostic::new(
1286 "known-value markers only apply to `quantum` or `hidden` transitions",
1287 span,
1288 ));
1289 }
1290 self.ensure_unique(&wires, span, "wire")?;
1291 self.operations.push(Operation {
1292 kind: OperationKind::WireChange { wires, kind, label },
1293 span,
1294 style,
1295 overlay: None,
1296 });
1297 Ok(())
1298 }
1299
1300 fn parse_endpoint(&mut self, span: Span, start: bool) -> Result<(), Diagnostic> {
1301 let wires = if self.at_statement_end() || self.at_keyword("as") || self.at_keyword("with") {
1302 Vec::new()
1303 } else {
1304 self.parse_wire_list()?
1305 };
1306 let label = if self.consume_keyword("as") {
1307 Some(self.take_label("endpoint label")?)
1308 } else {
1309 None
1310 };
1311 let style = self.parse_style()?;
1312 self.expect_statement_end()?;
1313 self.ensure_unique(&wires, span, "endpoint wire")?;
1314 self.operations.push(Operation {
1315 kind: OperationKind::Endpoint {
1316 wires,
1317 start,
1318 label,
1319 },
1320 span,
1321 style,
1322 overlay: None,
1323 });
1324 Ok(())
1325 }
1326
1327 fn parse_label(&mut self, span: Span) -> Result<(), Diagnostic> {
1328 let label = self.take_label("label text")?;
1329 let wires = if self.consume_keyword("on") {
1330 self.parse_wire_list()?
1331 } else {
1332 Vec::new()
1333 };
1334 let style = self.parse_style()?;
1335 self.expect_statement_end()?;
1336 self.ensure_unique(&wires, span, "label wire")?;
1337 self.operations.push(Operation {
1338 kind: OperationKind::Label {
1339 wires,
1340 label,
1341 brace: None,
1342 },
1343 span,
1344 style,
1345 overlay: None,
1346 });
1347 Ok(())
1348 }
1349
1350 fn parse_equals(&mut self, span: Span) -> Result<(), Diagnostic> {
1351 let label = if self.at_statement_end()
1352 || self.at_keyword("on")
1353 || self.at_keyword("braced")
1354 || self.at_keyword("with")
1355 {
1356 "=".into()
1357 } else {
1358 self.take_label("equals label")?
1359 };
1360 let wires = if self.consume_keyword("on") {
1361 self.parse_wire_list()?
1362 } else {
1363 Vec::new()
1364 };
1365 let brace = if self.consume_keyword("braced") {
1366 let brace_span = self.current().span;
1367 Some(
1368 match self.take_identifier("`left`, `right`, or `both`")?.as_str() {
1369 "left" => BraceSide::Left,
1370 "right" => BraceSide::Right,
1371 "both" => BraceSide::Both,
1372 _ => {
1373 return Err(Diagnostic::new(
1374 "brace side must be `left`, `right`, or `both`",
1375 brace_span,
1376 ));
1377 }
1378 },
1379 )
1380 } else {
1381 None
1382 };
1383 let style = self.parse_style()?;
1384 self.expect_statement_end()?;
1385 self.ensure_unique(&wires, span, "equals wire")?;
1386 self.operations.push(Operation {
1387 kind: OperationKind::Label {
1388 wires,
1389 label,
1390 brace,
1391 },
1392 span,
1393 style,
1394 overlay: None,
1395 });
1396 Ok(())
1397 }
1398
1399 fn parse_wire_labels(&mut self, span: Span) -> Result<(), Diagnostic> {
1400 let mut labels = vec![self.take_label("wire label")?];
1401 while self.consume(&TokenKind::Comma) {
1402 labels.push(self.take_label("wire label")?);
1403 }
1404 let wires = if self.consume_keyword("on") {
1405 self.parse_wire_list()?
1406 } else {
1407 Vec::new()
1408 };
1409 let style = self.parse_style()?;
1410 self.expect_statement_end()?;
1411 self.ensure_unique(&wires, span, "label wire")?;
1412 self.operations.push(Operation {
1413 kind: OperationKind::WireLabels { wires, labels },
1414 span,
1415 style,
1416 overlay: None,
1417 });
1418 Ok(())
1419 }
1420
1421 fn parse_brace(&mut self, span: Span) -> Result<(), Diagnostic> {
1422 let side_span = self.current().span;
1423 let side = match self.take_identifier("`left`, `right`, or `both`")?.as_str() {
1424 "left" => BraceSide::Left,
1425 "right" => BraceSide::Right,
1426 "both" => BraceSide::Both,
1427 _ => {
1428 return Err(Diagnostic::new(
1429 "brace side must be `left`, `right`, or `both`",
1430 side_span,
1431 ));
1432 }
1433 };
1434 let label = self.take_label("brace label")?;
1435 let wires = if self.consume_keyword("on") {
1436 self.parse_wire_list()?
1437 } else {
1438 Vec::new()
1439 };
1440 let style = self.parse_style()?;
1441 self.expect_statement_end()?;
1442 self.ensure_unique(&wires, span, "brace wire")?;
1443 self.operations.push(Operation {
1444 kind: OperationKind::Brace { wires, label, side },
1445 span,
1446 style,
1447 overlay: None,
1448 });
1449 Ok(())
1450 }
1451
1452 fn parse_note(&mut self, span: Span) -> Result<(), Diagnostic> {
1453 let side = if self.consume_keyword("below") {
1454 NoteSide::Below
1455 } else {
1456 self.consume_keyword("above");
1457 NoteSide::Above
1458 };
1459 let text = self.take_label("note text")?;
1460 let wires = if self.consume_keyword("on") {
1461 self.parse_wire_list()?
1462 } else {
1463 Vec::new()
1464 };
1465 let style = self.parse_style()?;
1466 self.expect_statement_end()?;
1467 self.ensure_unique(&wires, span, "note wire")?;
1468 self.operations.push(Operation {
1469 kind: OperationKind::Note { wires, text, side },
1470 span,
1471 style,
1472 overlay: None,
1473 });
1474 Ok(())
1475 }
1476
1477 fn parse_cut(&mut self, span: Span) -> Result<(), Diagnostic> {
1478 let wires = if self.consume_keyword("on") {
1479 self.parse_wire_list()?
1480 } else {
1481 Vec::new()
1482 };
1483 let label = if self.consume_keyword("as") {
1484 Some(self.take_label("cut label")?)
1485 } else {
1486 None
1487 };
1488 let style = self.parse_style()?;
1489 self.expect_statement_end()?;
1490 self.ensure_unique(&wires, span, "cut wire")?;
1491 self.operations.push(Operation {
1492 kind: OperationKind::Cut { wires, label },
1493 span,
1494 style,
1495 overlay: None,
1496 });
1497 Ok(())
1498 }
1499
1500 fn parse_mark(&mut self, span: Span) -> Result<(), Diagnostic> {
1501 let name = self.take_identifier("mark name")?;
1502 self.expect_statement_end()?;
1503 if self.marks.contains_key(&name) {
1504 return Err(Diagnostic::new(
1505 format!("mark `{name}` is already defined"),
1506 span,
1507 ));
1508 }
1509 self.marks.insert(name, self.operations.len());
1510 Ok(())
1511 }
1512
1513 fn parse_group(&mut self, span: Span) -> Result<(), Diagnostic> {
1514 let label = self.take_label("group label")?;
1515 self.expect_keyword("from")?;
1516 let start_span = self.current().span;
1517 let start_name = self.take_identifier("start mark")?;
1518 let start =
1519 self.marks.get(&start_name).copied().ok_or_else(|| {
1520 Diagnostic::new(format!("unknown mark `{start_name}`"), start_span)
1521 })?;
1522 self.expect_keyword("to")?;
1523 let end = if self.consume_keyword("here") {
1524 self.operations.len()
1525 } else {
1526 let end_span = self.current().span;
1527 let end_name = self.take_identifier("end mark or `here`")?;
1528 self.marks
1529 .get(&end_name)
1530 .copied()
1531 .ok_or_else(|| Diagnostic::new(format!("unknown mark `{end_name}`"), end_span))?
1532 };
1533 let wires = if self.consume_keyword("on") {
1534 self.parse_wire_list()?
1535 } else {
1536 Vec::new()
1537 };
1538 let style = self.parse_style()?;
1539 self.expect_statement_end()?;
1540 self.ensure_unique(&wires, span, "group wire")?;
1541 if start >= end {
1542 return Err(Diagnostic::new(
1543 "a group must contain at least one operation after its start mark",
1544 span,
1545 ));
1546 }
1547 self.groups.push(Group {
1548 label,
1549 wires,
1550 start,
1551 end,
1552 style,
1553 });
1554 Ok(())
1555 }
1556
1557 fn parse_bundle(&mut self, span: Span) -> Result<(), Diagnostic> {
1558 let label = self.take_label("bundle label")?;
1559 self.expect_keyword("on")?;
1560 let wire = self.parse_wire_reference()?;
1561 let style = self.parse_style()?;
1562 self.expect_statement_end()?;
1563 self.operations.push(Operation {
1564 kind: OperationKind::Bundle { wire, label },
1565 span,
1566 style,
1567 overlay: None,
1568 });
1569 Ok(())
1570 }
1571
1572 fn parse_permute(&mut self, span: Span) -> Result<(), Diagnostic> {
1573 let wires = self.parse_wire_list()?;
1574 let style = self.parse_style()?;
1575 self.expect_statement_end()?;
1576 if wires.len() < 2 {
1577 return Err(Diagnostic::new("permute needs at least two wires", span));
1578 }
1579 self.ensure_unique(&wires, span, "permutation wire")?;
1580 self.operations.push(Operation {
1581 kind: OperationKind::Permute { wires },
1582 span,
1583 style,
1584 overlay: None,
1585 });
1586 Ok(())
1587 }
1588
1589 fn parse_phantom(&mut self, span: Span) -> Result<(), Diagnostic> {
1590 let wires = self.parse_optional_wires()?;
1591 let style = self.parse_style()?;
1592 self.expect_statement_end()?;
1593 self.ensure_unique(&wires, span, "space wire")?;
1594 self.operations.push(Operation {
1595 kind: OperationKind::Phantom { wires },
1596 span,
1597 style,
1598 overlay: None,
1599 });
1600 Ok(())
1601 }
1602
1603 fn parse_touch(&mut self, span: Span) -> Result<(), Diagnostic> {
1604 let wires = self.parse_optional_wires()?;
1605 let style = self.parse_style()?;
1606 self.expect_statement_end()?;
1607 self.ensure_unique(&wires, span, "touch wire")?;
1608 self.operations.push(Operation {
1609 kind: OperationKind::Touch { wires },
1610 span,
1611 style,
1612 overlay: None,
1613 });
1614 Ok(())
1615 }
1616
1617 fn parse_optional_wires(&mut self) -> Result<Vec<usize>, Diagnostic> {
1618 if self.at_statement_end() || self.at_keyword("with") {
1619 Ok(Vec::new())
1620 } else {
1621 self.parse_wire_list()
1622 }
1623 }
1624
1625 fn parse_wire_kind(&mut self) -> Result<WireKind, Diagnostic> {
1626 let span = self.current().span;
1627 let kind = self.take_identifier("wire type")?;
1628 match kind.as_str() {
1629 "quantum" | "qubit" => Ok(WireKind::Quantum),
1630 "classical" | "bit" => Ok(WireKind::Classical),
1631 "hidden" | "off" => Ok(WireKind::Hidden),
1632 _ => Err(Diagnostic::new(
1633 "wire type must be `quantum`, `classical`, or `hidden`",
1634 span,
1635 )),
1636 }
1637 }
1638
1639 fn push_gate(
1640 &mut self,
1641 label: String,
1642 targets: Vec<usize>,
1643 controls: Vec<Control>,
1644 style: Style,
1645 span: Span,
1646 ) -> Result<(), Diagnostic> {
1647 self.ensure_unique(&targets, span, "gate target")?;
1648 let control_wires = controls
1649 .iter()
1650 .map(|control| control.wire)
1651 .collect::<Vec<_>>();
1652 self.ensure_unique(&control_wires, span, "gate control")?;
1653 if let Some(wire) = targets.iter().find(|target| control_wires.contains(target)) {
1654 return Err(Diagnostic::new(
1655 format!(
1656 "wire `{}` cannot be both a target and a control",
1657 self.wires[*wire].name
1658 ),
1659 span,
1660 ));
1661 }
1662 self.operations.push(Operation {
1663 kind: OperationKind::Gate {
1664 label,
1665 targets,
1666 controls,
1667 },
1668 span,
1669 style,
1670 overlay: None,
1671 });
1672 Ok(())
1673 }
1674
1675 fn parse_controls(&mut self) -> Result<Vec<Control>, Diagnostic> {
1676 if !self.consume_keyword("if") {
1677 return Ok(Vec::new());
1678 }
1679 let mut controls = Vec::new();
1680 loop {
1681 let parity = match (&self.current().kind, self.tokens.get(self.position + 1)) {
1682 (
1683 TokenKind::Identifier(name),
1684 Some(Token {
1685 kind: TokenKind::LeftParen,
1686 ..
1687 }),
1688 ) => match name.as_str() {
1689 "parity_x" => Some(ParityBasis::X),
1690 "parity_y" => Some(ParityBasis::Y),
1691 "parity" | "parity_z" => Some(ParityBasis::Z),
1692 _ => None,
1693 },
1694 _ => None,
1695 };
1696 let (wires, positive) = if parity.is_some() {
1697 self.advance();
1698 self.expect(TokenKind::LeftParen, "`(` after the parity control")?;
1699 let wires = self.parse_wire_list()?;
1700 self.expect(TokenKind::RightParen, "`)`")?;
1701 (wires, true)
1702 } else {
1703 let positive = !self.consume(&TokenKind::Bang);
1704 (self.parse_wire_selection(true)?, positive)
1705 };
1706 controls.extend(wires.into_iter().map(|wire| Control {
1707 wire,
1708 positive,
1709 parity,
1710 }));
1711 if !self.consume(&TokenKind::Comma) {
1712 break;
1713 }
1714 }
1715 Ok(controls)
1716 }
1717
1718 fn parse_style(&mut self) -> Result<Style, Diagnostic> {
1719 if !self.consume_keyword("with") {
1720 return Ok(Style::default());
1721 }
1722
1723 let mut style = if let TokenKind::Identifier(name) = &self.current().kind
1724 && let Some(style) = self.styles.get(name).cloned()
1725 {
1726 self.advance();
1727 if !self.consume(&TokenKind::Comma) {
1728 return Ok(style);
1729 }
1730 style
1731 } else {
1732 Style::default()
1733 };
1734 loop {
1735 self.parse_style_property(&mut style)?;
1736 if !self.consume(&TokenKind::Comma) {
1737 break;
1738 }
1739 }
1740 Ok(style)
1741 }
1742
1743 fn parse_style_property(&mut self, style: &mut Style) -> Result<(), Diagnostic> {
1744 let span = self.current().span;
1745 let property = self.take_identifier("style property")?;
1746 self.expect(TokenKind::Colon, "`:`")?;
1747 match property.as_str() {
1748 "stroke" => style.stroke = Some(self.take_color("stroke color")?),
1749 "fill" => style.fill = Some(self.take_color("fill color")?),
1750 "link" => style.link = Some(self.take_link()?),
1751 "width" => style.width = Some(self.take_positive_scalar("gate width")?),
1752 "height" => style.height = Some(self.take_positive_scalar("gate height")?),
1753 "size" => {
1754 let size = self.take_positive_scalar("gate size")?;
1755 style.width = Some(size);
1756 style.height = Some(size);
1757 }
1758 "shape" => {
1759 let value = self.take_identifier("shape")?;
1760 style.shape = Some(match value.as_str() {
1761 "box" => Shape::Box,
1762 "circle" => Shape::Circle,
1763 "ellipse" => Shape::Ellipse,
1764 "none" => Shape::None,
1765 _ => {
1766 return Err(Diagnostic::new(
1767 "shape must be `box`, `circle`, `ellipse`, or `none`",
1768 span,
1769 ));
1770 }
1771 });
1772 }
1773 "dash" => {
1774 let value = self.take_identifier("`dashed` or `solid`")?;
1775 style.dashed = match value.as_str() {
1776 "dashed" | "true" => true,
1777 "solid" | "false" => false,
1778 _ => return Err(Diagnostic::new("dash must be `dashed` or `solid`", span)),
1779 };
1780 }
1781 "opacity" => {
1782 let opacity = self.take_scalar("opacity")?;
1783 if !(0.0..=1.0).contains(&opacity) {
1784 return Err(Diagnostic::new("opacity must be between 0 and 1", span));
1785 }
1786 style.opacity = Some(opacity);
1787 }
1788 _ => {
1789 return Err(Diagnostic::new(
1790 format!("unknown style property `{property}`"),
1791 span,
1792 ));
1793 }
1794 }
1795 Ok(())
1796 }
1797
1798 fn parse_wire_list(&mut self) -> Result<Vec<usize>, Diagnostic> {
1799 let mut wires = self.parse_wire_selection(true)?;
1800 while self.consume(&TokenKind::Comma) {
1801 wires.extend(self.parse_wire_selection(true)?);
1802 }
1803 Ok(wires)
1804 }
1805
1806 fn parse_wire_reference(&mut self) -> Result<usize, Diagnostic> {
1807 Ok(self
1810 .parse_wire_selection(false)?
1811 .into_iter()
1812 .next()
1813 .expect("a wire selection is not empty"))
1814 }
1815
1816 fn parse_wire_selection(&mut self, allow_range: bool) -> Result<Vec<usize>, Diagnostic> {
1817 let span = self.current().span;
1818 let base = self.take_identifier("wire name")?;
1819 if self.consume(&TokenKind::LeftBracket) {
1820 let start = self.take_number("wire index")?;
1821 if self.consume(&TokenKind::DotDot) {
1822 if !allow_range {
1823 return Err(Diagnostic::new(
1824 "a wire range is not valid where one wire is required",
1825 span,
1826 ));
1827 }
1828 let end = self.take_number("wire range end")?;
1829 self.expect(TokenKind::RightBracket, "`]`")?;
1830 if start >= end {
1831 return Err(Diagnostic::new(
1832 "a wire range must have an end greater than its start",
1833 span,
1834 ));
1835 }
1836 return (start..end)
1837 .map(|index| self.resolve_wire(&format!("{base}[{index}]"), span))
1838 .collect();
1839 }
1840 self.expect(TokenKind::RightBracket, "`]`")?;
1841 return self
1842 .resolve_wire(&format!("{base}[{start}]"), span)
1843 .map(|wire| vec![wire]);
1844 }
1845 self.resolve_wire(&base, span).map(|wire| vec![wire])
1846 }
1847
1848 fn resolve_wire(&mut self, name: &str, span: Span) -> Result<usize, Diagnostic> {
1849 if let Some(wire) = self.wire_indices.get(name) {
1850 return Ok(*wire);
1851 }
1852 if !self.auto_wires {
1853 return Err(Diagnostic::with_help(
1854 format!("unknown wire `{name}`"),
1855 "declare it before use or enable `autowires`",
1856 span,
1857 ));
1858 }
1859 let wire = self.wires.len();
1860 self.wire_indices.insert(name.into(), wire);
1861 self.wires.push(Wire {
1862 name: name.into(),
1863 kind: WireKind::Quantum,
1864 ellipsis: false,
1865 input: Some(name.into()),
1866 output: None,
1867 style: Style::default(),
1868 });
1869 Ok(wire)
1870 }
1871
1872 fn ensure_unique(
1873 &self,
1874 wires: &[usize],
1875 span: Span,
1876 description: &str,
1877 ) -> Result<(), Diagnostic> {
1878 let mut sorted = wires.to_vec();
1879 sorted.sort_unstable();
1880 if let Some(pair) = sorted.windows(2).find(|pair| pair[0] == pair[1]) {
1881 return Err(Diagnostic::new(
1882 format!("{} `{}` is repeated", description, self.wires[pair[0]].name),
1883 span,
1884 ));
1885 }
1886 Ok(())
1887 }
1888
1889 fn take_label(&mut self, expected: &str) -> Result<String, Diagnostic> {
1890 match self.current().kind.clone() {
1891 TokenKind::String(value) => {
1892 self.advance();
1893 Ok(value)
1894 }
1895 TokenKind::Identifier(name) => {
1896 let value = self.values.get(&name).cloned().unwrap_or(name);
1897 self.advance();
1898 Ok(value)
1899 }
1900 _ => Err(self.error(format!("expected {expected}"))),
1901 }
1902 }
1903
1904 fn take_color(&mut self, expected: &str) -> Result<String, Diagnostic> {
1905 let span = self.current().span;
1906 let color = self.take_label(expected)?;
1907 if color.len() == 7
1908 && color.starts_with('#')
1909 && color[1..]
1910 .chars()
1911 .all(|character| character.is_ascii_hexdigit())
1912 {
1913 return Ok(color.to_ascii_uppercase());
1914 }
1915 if [
1916 "black", "white", "gray", "red", "green", "blue", "teal", "purple", "orange", "yellow",
1917 "olive", "lime",
1918 ]
1919 .contains(&color.as_str())
1920 {
1921 Ok(color)
1922 } else {
1923 Err(Diagnostic::new(
1924 format!(
1925 "{expected} `{color}` is not a portable named color or six-digit hex color"
1926 ),
1927 span,
1928 ))
1929 }
1930 }
1931
1932 fn take_link(&mut self) -> Result<String, Diagnostic> {
1933 let span = self.current().span;
1934 let link = self.take_string("link URL")?;
1935 let valid_scheme = ["https://", "http://", "mailto:"]
1936 .iter()
1937 .any(|scheme| link.starts_with(scheme));
1938 let safe_characters = link.chars().all(|character| {
1939 character.is_ascii_alphanumeric() || ":/?#[]@!$&'()*+,-._~=%".contains(character)
1940 });
1941 if valid_scheme && safe_characters {
1942 Ok(link)
1943 } else {
1944 Err(Diagnostic::new(
1945 "link must be a safe absolute http, https, or mailto URL",
1946 span,
1947 ))
1948 }
1949 }
1950
1951 fn take_identifier(&mut self, expected: &str) -> Result<String, Diagnostic> {
1952 if let TokenKind::Identifier(value) = &self.current().kind {
1953 let value = value.clone();
1954 self.advance();
1955 Ok(value)
1956 } else {
1957 Err(self.error(format!("expected {expected}")))
1958 }
1959 }
1960
1961 fn take_string(&mut self, expected: &str) -> Result<String, Diagnostic> {
1962 if let TokenKind::String(value) = &self.current().kind {
1963 let value = value.clone();
1964 self.advance();
1965 Ok(value)
1966 } else {
1967 Err(self.error(format!("expected {expected} string")))
1968 }
1969 }
1970
1971 fn take_number(&mut self, expected: &str) -> Result<usize, Diagnostic> {
1972 if let TokenKind::Number(value) = &self.current().kind {
1973 let value = value.parse().map_err(|_| {
1974 self.error(format!("expected {expected} as a non-negative integer"))
1975 })?;
1976 self.advance();
1977 Ok(value)
1978 } else {
1979 Err(self.error(format!("expected {expected}")))
1980 }
1981 }
1982
1983 fn take_scalar(&mut self, expected: &str) -> Result<f32, Diagnostic> {
1984 if let TokenKind::Number(value) = &self.current().kind {
1985 let value = value
1986 .parse()
1987 .map_err(|_| self.error(format!("invalid {expected}")))?;
1988 if !f32::is_finite(value) {
1989 return Err(self.error(format!("invalid {expected}")));
1990 }
1991 self.advance();
1992 Ok(value)
1993 } else {
1994 Err(self.error(format!("expected {expected}")))
1995 }
1996 }
1997
1998 fn take_positive_scalar(&mut self, expected: &str) -> Result<f32, Diagnostic> {
1999 let span = self.current().span;
2000 let value = self.take_scalar(expected)?;
2001 if value > 0.0 {
2002 Ok(value)
2003 } else {
2004 Err(Diagnostic::new(
2005 format!("{expected} must be greater than zero"),
2006 span,
2007 ))
2008 }
2009 }
2010
2011 fn expect_keyword(&mut self, keyword: &str) -> Result<(), Diagnostic> {
2012 if self.consume_keyword(keyword) {
2013 Ok(())
2014 } else {
2015 Err(self.error(format!("expected `{keyword}`")))
2016 }
2017 }
2018
2019 fn consume_keyword(&mut self, keyword: &str) -> bool {
2020 let matches = self.at_keyword(keyword);
2021 if matches {
2022 self.advance();
2023 }
2024 matches
2025 }
2026
2027 fn at_keyword(&self, keyword: &str) -> bool {
2028 matches!(&self.current().kind, TokenKind::Identifier(value) if value == keyword)
2029 }
2030
2031 fn expect(&mut self, kind: TokenKind, expected: &str) -> Result<(), Diagnostic> {
2032 if self.consume(&kind) {
2033 Ok(())
2034 } else {
2035 Err(self.error(format!("expected {expected}")))
2036 }
2037 }
2038
2039 fn consume(&mut self, kind: &TokenKind) -> bool {
2040 if self.at(kind) {
2041 self.advance();
2042 true
2043 } else {
2044 false
2045 }
2046 }
2047
2048 fn expect_statement_end(&mut self) -> Result<(), Diagnostic> {
2049 if self.at_statement_end() {
2050 Ok(())
2051 } else {
2052 Err(self.error("expected a newline or `;` after the statement"))
2053 }
2054 }
2055
2056 fn at_statement_end(&self) -> bool {
2057 self.at(&TokenKind::Newline) || self.at(&TokenKind::RightBrace) || self.at(&TokenKind::End)
2058 }
2059
2060 fn skip_newlines(&mut self) {
2061 while self.consume(&TokenKind::Newline) {}
2062 }
2063
2064 fn at(&self, kind: &TokenKind) -> bool {
2065 self.current().kind == *kind
2066 }
2067
2068 fn advance(&mut self) {
2069 if self.position + 1 < self.tokens.len() {
2071 self.position += 1;
2072 }
2073 }
2074
2075 fn current(&self) -> &Token {
2076 &self.tokens[self.position]
2077 }
2078
2079 fn error(&self, message: impl Into<String>) -> Diagnostic {
2080 Diagnostic::new(message, self.current().span)
2081 }
2082}
2083
2084#[cfg(test)]
2085mod tests {
2086 use super::*;
2087
2088 #[test]
2089 fn lexer_tracks_byte_ranges_and_derived_locations() {
2090 let tokens = lex("\tqubit q\n").expect("valid tokens");
2091 let span = tokens[0].span;
2092 assert_eq!(
2093 (span.offset, span.length, span.line, span.column),
2094 (1, 5, 1, 2)
2095 );
2096
2097 let error = lex("circuit 💥").expect_err("non-ASCII punctuation must fail");
2098 assert_eq!(
2099 (
2100 error.span.offset,
2101 error.span.length,
2102 error.span.line,
2103 error.span.column
2104 ),
2105 (8, 4, 1, 9)
2106 );
2107
2108 let error = lex("circuit\u{c}bad").expect_err("form feed must fail");
2109 assert_eq!(error.message, "unexpected character `\u{c}`");
2110 }
2111
2112 #[test]
2113 fn parses_a_readable_bell_circuit() {
2114 let circuit = parse(
2115 r#"
2116 circuit bell {
2117 qubit q[2]: "|0>" -> "bell"
2118
2119 h q[0]
2120 x q[1] if q[0]
2121 measure q[0], q[1]
2122 }
2123 "#,
2124 )
2125 .expect("valid circuit");
2126
2127 assert_eq!(circuit.name, "bell");
2128 assert_eq!(circuit.wires.len(), 2);
2129 assert_eq!(circuit.operations.len(), 3);
2130 assert!(matches!(
2131 circuit.operations[1].kind,
2132 OperationKind::Gate {
2133 ref label,
2134 ref targets,
2135 ref controls,
2136 } if label == "X"
2137 && targets == &[1]
2138 && controls == &[Control { wire: 0, positive: true, parity: None }]
2139 ));
2140 }
2141
2142 #[test]
2143 fn parses_xyz_parity_controls() {
2144 let circuit = parse(
2145 r#"
2146 circuit parity_controls {
2147 qubit top
2148 qubit middle
2149 qubit bottom
2150 s top if middle, bottom
2151 s top if parity(middle, bottom)
2152 s top if parity_x(middle, bottom)
2153 s top if parity_y(middle, bottom)
2154 s top if parity_z(middle, bottom)
2155 }
2156 "#,
2157 )
2158 .expect("valid parity controls");
2159
2160 let controls = circuit
2161 .operations
2162 .iter()
2163 .map(|operation| match &operation.kind {
2164 OperationKind::Gate { controls, .. } => (controls.len(), controls[0].parity),
2165 _ => unreachable!("fixture contains only gates"),
2166 })
2167 .collect::<Vec<_>>();
2168 assert_eq!(
2169 controls,
2170 [
2171 (2, None),
2172 (2, Some(ParityBasis::Z)),
2173 (2, Some(ParityBasis::X)),
2174 (2, Some(ParityBasis::Y)),
2175 (2, Some(ParityBasis::Z)),
2176 ]
2177 );
2178 }
2179
2180 #[test]
2181 fn reports_unknown_wires_at_the_source_location() {
2182 let error = parse("circuit bad {\n qubit q\n h missing\n}\n")
2183 .expect_err("unknown wire should fail");
2184
2185 assert_eq!(
2186 (
2187 error.span.offset,
2188 error.span.length,
2189 error.span.line,
2190 error.span.column
2191 ),
2192 (28, 7, 3, 5)
2193 );
2194 assert!(error.message.contains("unknown wire `missing`"));
2195 assert_eq!(
2196 error.help.as_deref(),
2197 Some("declare it before use or enable `autowires`")
2198 );
2199 }
2200
2201 #[test]
2202 fn recovers_at_statement_boundaries_to_report_multiple_errors() {
2203 let error = parse("circuit bad {\n qubit q\n h missing\n x absent\n}\n")
2204 .expect_err("both unknown wires should fail");
2205
2206 assert_eq!(error.message, "2 errors found");
2207 assert_eq!(error.related().len(), 2);
2208 assert!(error.related()[0].message.contains("`missing`"));
2209 assert!(error.related()[1].message.contains("`absent`"));
2210 }
2211
2212 #[test]
2213 fn recovery_checkpoints_scale_to_generated_circuits() {
2214 let mut source = String::from("circuit generated {\nqubit q\n");
2215 for _ in 0..5_000 {
2216 source.push_str("h q\n");
2217 }
2218 source.push_str("}\n");
2219
2220 let started = std::time::Instant::now();
2221 let circuit = parse(&source).expect("large generated circuit should parse");
2222 assert_eq!(circuit.operations.len(), 5_000);
2223 assert!(
2224 started.elapsed() < std::time::Duration::from_secs(1),
2225 "5,000 statements took {:?}",
2226 started.elapsed()
2227 );
2228 }
2229
2230 #[test]
2231 fn autowires_declares_quantum_wires_on_first_use() {
2232 let circuit = parse(
2233 r#"
2234 circuit sketch {
2235 autowires
2236 h control
2237 x target if control
2238 gate "U" on work[0..2]
2239 }
2240 "#,
2241 )
2242 .expect("valid automatic wires");
2243
2244 assert_eq!(
2245 circuit
2246 .wires
2247 .iter()
2248 .map(|wire| wire.name.as_str())
2249 .collect::<Vec<_>>(),
2250 ["control", "target", "work[0]", "work[1]"]
2251 );
2252 assert!(
2253 circuit
2254 .wires
2255 .iter()
2256 .all(|wire| wire.kind == WireKind::Quantum && wire.input.is_some())
2257 );
2258 }
2259
2260 #[test]
2261 fn parses_structured_layout_and_portable_styles() {
2262 let circuit = parse(
2263 r##"
2264 circuit styled {
2265 layout {
2266 orientation: vertical
2267 scale: 1.25
2268 gate_size: 24
2269 corner_radius: 2
2270 comment_width: 96
2271 background: "#f7f8fc"
2272 }
2273 qubit q[2] with stroke: "#336699"
2274 h q[0] with fill: yellow, shape: circle, size: 20, link: "https://example.com/gate?id=H"
2275 }
2276 "##,
2277 )
2278 .expect("valid styled circuit");
2279
2280 assert_eq!(circuit.layout.orientation, Orientation::Vertical);
2281 assert_eq!(circuit.layout.scale, 1.25);
2282 assert_eq!(circuit.layout.gate_size, 24.0);
2283 assert_eq!(circuit.layout.corner_radius, 2.0);
2284 assert_eq!(circuit.layout.comment_width, 96.0);
2285 assert_eq!(circuit.layout.background, "#F7F8FC");
2286 assert_eq!(circuit.wires[0].style.stroke.as_deref(), Some("#336699"));
2287 assert_eq!(circuit.operations[0].style.shape, Some(Shape::Circle));
2288 assert_eq!(circuit.operations[0].style.width, Some(20.0));
2289 assert_eq!(
2290 circuit.operations[0].style.link.as_deref(),
2291 Some("https://example.com/gate?id=H")
2292 );
2293
2294 let error = parse("circuit bad { qubit q with stroke: \"#12ZZ99\" }")
2295 .expect_err("invalid hex color should fail");
2296 assert!(error.message.contains("six-digit hex color"));
2297 assert!(
2298 parse("circuit bad { qubit q; h q with link: \"javascript:alert(1)\" }")
2299 .expect_err("unsafe link should fail")
2300 .message
2301 .contains("safe absolute")
2302 );
2303 }
2304
2305 #[test]
2306 fn isolates_explicit_backend_escape_blocks() {
2307 let circuit = parse(
2308 r##"
2309 circuit hooks {
2310 backend latex {
2311 preamble: "\\newcommand{\\hook}{ok}"
2312 before: "\\node {ok};"
2313 }
2314 backend typst {
2315 after: "#v(1pt)"
2316 }
2317 qubit q
2318 }
2319 "##,
2320 )
2321 .expect("valid backend hooks");
2322
2323 assert_eq!(circuit.escapes.latex.preamble, ["\\newcommand{\\hook}{ok}"]);
2324 assert_eq!(circuit.escapes.latex.before, ["\\node {ok};"]);
2325 assert_eq!(circuit.escapes.typst.after, ["#v(1pt)"]);
2326 }
2327
2328 #[test]
2329 fn parses_wire_lifecycle_and_placement_statements() {
2330 let circuit = parse(
2331 r#"
2332 circuit lifecycle {
2333 qubit q[3]
2334 start q[2] as "aux"
2335 bundle "3" on q[0]
2336 label "middle" on q[0], q[2]
2337 permute q[2], q[0], q[1]
2338 set q[0] to classical
2339 space q[1] with width: 12
2340 touch q[0], q[2]
2341 end q[2]
2342 }
2343 "#,
2344 )
2345 .expect("valid lifecycle circuit");
2346
2347 assert_eq!(circuit.operations.len(), 8);
2348 assert!(matches!(
2349 circuit.operations[0].kind,
2350 OperationKind::Endpoint {
2351 start: true,
2352 ref label,
2353 ..
2354 } if label.as_deref() == Some("aux")
2355 ));
2356 assert!(matches!(
2357 circuit.operations[3].kind,
2358 OperationKind::Permute { ref wires } if wires == &[2, 0, 1]
2359 ));
2360 assert!(matches!(
2361 circuit.operations[4].kind,
2362 OperationKind::WireChange {
2363 kind: WireKind::Classical,
2364 ..
2365 }
2366 ));
2367 assert!(matches!(
2368 circuit.operations[6].kind,
2369 OperationKind::Touch { ref wires } if wires == &[0, 2]
2370 ));
2371 }
2372
2373 #[test]
2374 fn targetless_statements_use_only_active_wires() {
2375 let circuit = parse(
2376 r#"
2377 circuit active_defaults {
2378 qubit q[3]
2379 touch
2380 start q[2]
2381 end q[0]
2382 label "active"
2383 end q[2]
2384 barrier
2385 }
2386 "#,
2387 )
2388 .expect("valid lifecycle defaults");
2389
2390 assert!(matches!(
2391 circuit.operations[0].kind,
2392 OperationKind::Touch { ref wires } if wires == &[0, 1]
2393 ));
2394 assert!(matches!(
2395 circuit.operations[3].kind,
2396 OperationKind::Label { ref wires, .. } if wires == &[1, 2]
2397 ));
2398 assert!(matches!(
2399 circuit.operations[5].kind,
2400 OperationKind::Barrier { ref wires } if wires == &[1]
2401 ));
2402 }
2403
2404 #[test]
2405 fn targetless_statements_require_an_active_wire() {
2406 let error = parse("circuit inactive { qubit q[2]; end q[0]; end q[1]; barrier }")
2407 .expect_err("a targetless statement cannot select ended wires");
2408
2409 assert!(error.message.contains("no applicable active wires"));
2410 }
2411
2412 #[test]
2413 fn wire_label_arity_is_checked_after_autowires_finish() {
2414 let error = parse("circuit labels { autowires; h a; h b; labels \"p\", \"q\"; h c }")
2415 .expect_err("late automatic wires must be included in label arity");
2416
2417 assert!(error.message.contains("selected wire (3)"));
2418 }
2419
2420 #[test]
2421 fn rejects_non_finite_scalars() {
2422 let error = parse(
2423 "circuit huge { layout { scale: 99999999999999999999999999999999999999999999999999 }; qubit q }",
2424 )
2425 .expect_err("an overflowing scalar must not render as infinity");
2426
2427 assert!(error.message.contains("invalid layout scale"));
2428 }
2429
2430 #[test]
2431 fn parses_named_measurement_shapes() {
2432 let circuit = parse(
2433 r#"
2434 circuit measurements {
2435 qubit q[3]
2436 measure q[0]
2437 measure q[1] as "Z"
2438 measure q[2] as "X" using tag
2439 }
2440 "#,
2441 )
2442 .expect("valid measurement shapes");
2443
2444 assert!(matches!(
2445 circuit.operations[1].kind,
2446 OperationKind::Measure {
2447 shape: MeasurementShape::D,
2448 ..
2449 }
2450 ));
2451 assert!(matches!(
2452 circuit.operations[2].kind,
2453 OperationKind::Measure {
2454 shape: MeasurementShape::Tag,
2455 ..
2456 }
2457 ));
2458 assert!(
2459 parse("circuit bad { qubit q; measure q using tag }")
2460 .expect_err("tag needs a label")
2461 .message
2462 .contains("needs a label")
2463 );
2464 }
2465
2466 #[test]
2467 fn parses_known_value_wire_transitions() {
2468 let circuit = parse(
2469 r#"
2470 circuit values {
2471 qubit q
2472 set q to hidden as "0"
2473 set q to quantum as "1"
2474 }
2475 "#,
2476 )
2477 .expect("valid known-value transitions");
2478
2479 assert!(matches!(
2480 circuit.operations[0].kind,
2481 OperationKind::WireChange {
2482 kind: WireKind::Hidden,
2483 label: Some(ref label),
2484 ..
2485 } if label == "0"
2486 ));
2487 assert!(
2488 parse("circuit bad { bit c; set c to classical as \"0\" }")
2489 .expect_err("classical transition cannot carry a value marker")
2490 .message
2491 .contains("quantum` or `hidden")
2492 );
2493 }
2494
2495 #[test]
2496 fn parses_an_ellipsis_wire_as_a_visual_gap() {
2497 let circuit = parse(
2498 "circuit gap { qubit first; ellipsis omitted; qubit last; label \"...\" on omitted }",
2499 )
2500 .expect("valid ellipsis wire");
2501
2502 assert_eq!(circuit.wires.len(), 3);
2503 assert!(circuit.wires[1].ellipsis);
2504 assert_eq!(circuit.wires[1].kind, WireKind::Hidden);
2505 assert_eq!(circuit.wires[1].input.as_deref(), Some("..."));
2506 assert_eq!(circuit.wires[1].output.as_deref(), Some("..."));
2507 assert!(
2508 parse("circuit bad { ellipsis gap[2] }")
2509 .expect_err("ellipsis arrays are ambiguous")
2510 .message
2511 .contains("one visual gap")
2512 );
2513 }
2514
2515 #[test]
2516 fn parses_and_lowers_typed_function_calls() {
2517 let circuit = parse(
2518 r#"
2519 fn entangle(control, target) {
2520 h control
2521 x target if control
2522 gate "control" on target
2523 }
2524
2525 fn ghz(a, b, c) {
2526 entangle(a, b)
2527 x c if b
2528 barrier
2529 }
2530
2531 circuit functions {
2532 qubit q[3]
2533 ghz(q[2], q[0], q[1])
2534 }
2535 "#,
2536 )
2537 .expect("valid functions");
2538
2539 assert_eq!(circuit.operations.len(), 5);
2540 assert!(matches!(
2541 circuit.operations[1].kind,
2542 OperationKind::Gate {
2543 ref label,
2544 ref targets,
2545 ref controls,
2546 } if label == "X"
2547 && targets == &[0]
2548 && controls == &[Control { wire: 2, positive: true, parity: None }]
2549 ));
2550 assert!(matches!(
2551 circuit.operations[2].kind,
2552 OperationKind::Gate { ref label, .. } if label == "control"
2553 ));
2554 assert!(matches!(
2555 circuit.operations[4].kind,
2556 OperationKind::Barrier { ref wires } if wires == &[2, 0, 1]
2557 ));
2558 }
2559
2560 #[test]
2561 fn resolves_typed_values_and_named_styles() {
2562 let circuit = parse(
2563 r##"
2564 let operator = "U"
2565 let accent = "#ddeeff"
2566
2567 style highlighted {
2568 fill: accent
2569 stroke: blue
2570 shape: circle
2571 }
2572
2573 circuit declarations {
2574 qubit q
2575 gate operator on q with highlighted, opacity: 0.5
2576 }
2577 "##,
2578 )
2579 .expect("valid typed declarations");
2580
2581 assert!(matches!(
2582 circuit.operations[0].kind,
2583 OperationKind::Gate { ref label, .. } if label == "U"
2584 ));
2585 assert_eq!(circuit.operations[0].style.fill.as_deref(), Some("#DDEEFF"));
2586 assert_eq!(circuit.operations[0].style.shape, Some(Shape::Circle));
2587 assert_eq!(circuit.operations[0].style.opacity, Some(0.5));
2588 assert!(
2589 parse("let h = \"bad\"; circuit bad { qubit q }")
2590 .expect_err("reserved definition name should fail")
2591 .message
2592 .contains("reserved or already used")
2593 );
2594 }
2595
2596 #[test]
2597 fn reports_function_arity_at_the_call() {
2598 let error =
2599 parse("fn one(a) { h a }\n\ncircuit bad {\n qubit q[2]\n one(q[0], q[1])\n}\n")
2600 .expect_err("wrong arity should fail");
2601
2602 assert_eq!((error.span.line, error.span.column), (5, 3));
2603 assert!(
2604 error
2605 .message
2606 .contains("expects 1 wire argument(s), but got 2")
2607 );
2608 }
2609
2610 #[test]
2611 fn expands_ranges_and_structured_operation_blocks() {
2612 let circuit = parse(
2613 r#"
2614 fn pair(a, b) {
2615 parallel {
2616 h a
2617 h b
2618 }
2619 }
2620
2621 circuit structured {
2622 qubit q[4]
2623 pair(q[1..3])
2624 repeat 2 {
2625 measure q[0..2]
2626 }
2627 }
2628 "#,
2629 )
2630 .expect("valid structured blocks");
2631
2632 assert_eq!(circuit.operations.len(), 6);
2633 assert!(matches!(
2634 circuit.operations[0].kind,
2635 OperationKind::Touch { ref wires } if wires == &[1, 2]
2636 ));
2637 assert!(matches!(
2638 circuit.operations[4].kind,
2639 OperationKind::Measure { ref targets, .. } if targets == &[0, 1]
2640 ));
2641 assert!(matches!(
2642 circuit.operations[5].kind,
2643 OperationKind::Measure { ref targets, .. } if targets == &[0, 1]
2644 ));
2645 }
2646
2647 #[test]
2648 fn reverses_blocks_and_marked_ranges() {
2649 let circuit = parse(
2650 r#"
2651 circuit reverse_order {
2652 qubit q[3]
2653 mark forward
2654 reverse {
2655 h q[0]
2656 measure q[1]
2657 z q[2]
2658 }
2659 mark reversed
2660 reverse from forward to reversed
2661 }
2662 "#,
2663 )
2664 .expect("valid reverse block");
2665
2666 let kinds = circuit
2667 .operations
2668 .iter()
2669 .map(|operation| match &operation.kind {
2670 OperationKind::Gate { label, .. } => label.as_str(),
2671 OperationKind::Measure { .. } => "M",
2672 _ => panic!("unexpected reverse fixture operation"),
2673 })
2674 .collect::<Vec<_>>();
2675 assert_eq!(kinds, ["Z", "M", "H", "H", "M", "Z"]);
2676 }
2677
2678 #[test]
2679 fn rejects_a_range_where_one_wire_is_required() {
2680 let error = parse("circuit bad {\n qubit q[2]\n h q[0..2]\n}\n")
2681 .expect_err("range target should fail");
2682
2683 assert!(error.message.contains("where one wire is required"));
2684 }
2685
2686 #[test]
2687 fn parses_labels_braces_notes_and_cuts() {
2688 let circuit = parse(
2689 r#"
2690 circuit annotations {
2691 qubit q[3]
2692 labels "a", "b", "c" on q[0..3]
2693 brace both "register" on q[0..3]
2694 note below "decode" on q[1]
2695 cut on q[0..2] as "stage" with stroke: blue
2696 }
2697 "#,
2698 )
2699 .expect("valid annotations");
2700
2701 assert!(matches!(
2702 circuit.operations[0].kind,
2703 OperationKind::WireLabels { ref wires, ref labels }
2704 if wires == &[0, 1, 2] && labels == &["a", "b", "c"]
2705 ));
2706 assert!(matches!(
2707 circuit.operations[1].kind,
2708 OperationKind::Brace {
2709 side: BraceSide::Both,
2710 ..
2711 }
2712 ));
2713 assert!(matches!(
2714 circuit.operations[2].kind,
2715 OperationKind::Note {
2716 side: NoteSide::Below,
2717 ..
2718 }
2719 ));
2720 assert!(matches!(
2721 circuit.operations[3].kind,
2722 OperationKind::Cut { ref wires, ref label }
2723 if wires == &[0, 1] && label.as_deref() == Some("stage")
2724 ));
2725 }
2726
2727 #[test]
2728 fn parses_centered_equals_with_optional_braces() {
2729 let circuit = parse(
2730 r#"
2731 circuit equals {
2732 qubit q[2]
2733 equals on q[0..2]
2734 equals "stage" on q[0..2] braced both with stroke: blue
2735 }
2736 "#,
2737 )
2738 .expect("valid equals statements");
2739
2740 assert!(matches!(
2741 circuit.operations[0].kind,
2742 OperationKind::Label {
2743 ref label,
2744 brace: None,
2745 ..
2746 } if label == "="
2747 ));
2748 assert!(matches!(
2749 circuit.operations[1].kind,
2750 OperationKind::Label {
2751 ref label,
2752 brace: Some(BraceSide::Both),
2753 ..
2754 } if label == "stage"
2755 ));
2756 }
2757
2758 #[test]
2759 fn resolves_marked_group_ranges() {
2760 let circuit = parse(
2761 r#"
2762 circuit regions {
2763 qubit q[2]
2764 mark start
2765 h q[0]
2766 mark middle
2767 x q[1]
2768 group "first" from start to middle on q[0]
2769 group "all" from start to here with fill: yellow, opacity: 0.2
2770 }
2771 "#,
2772 )
2773 .expect("valid groups");
2774
2775 assert_eq!(circuit.groups.len(), 2);
2776 assert_eq!((circuit.groups[0].start, circuit.groups[0].end), (0, 1));
2777 assert_eq!((circuit.groups[1].start, circuit.groups[1].end), (0, 2));
2778 assert_eq!(circuit.groups[0].wires, [0]);
2779 assert_eq!(circuit.groups[1].style.opacity, Some(0.2));
2780 }
2781}