Repository: rigetti/quil-rs (language: python)

Issue:
The parser is not robust to whitespace
The parser considers 4 spaces as an indentation token, which means that 8 spaces should be considered 2 indentations. The parser is "flexible" in that it allows for extra spaces after the initial 4, but that has less precedence than recognizing an additional indentation, so 4-7 spaces becomes the valid range for a single indentation. This doesn't necessarily seem incorrect to me, but it is brittle, and not really made clear to the user.

Since quil-rs serializes program to Quil using tabs for whitespace, and many editors and terminals default to rendering 8 spaces for tabs, this leads to a surprising error when attempting to roundtrip a serialized program copied from one's editor or terminal.

Ideas:

* Allow configuration of whitespace when serializing a program. I can see this as an enum with a method that returns the desired whitespace. The serialization routine would then inject that whitespace instead of hardcoding '\t'
* Implement Python-esque handling of whitespace, where indentation must be consistent within a block, but the composition of said whitespace can vary.


Discussion / hints:
Capturing additional feedback from team discussion:

* Whatever solution should be consistent with the Quil spec.
* The Quil spec may give us some leeway here. For example, Quil may not allow for nested blocks which means we could allow for irregular indentation by making 1 or many indentations equivalent to 1.

Fix patch:
diff --git a/quil-rs/src/instruction/calibration.rs b/quil-rs/src/instruction/calibration.rs
index 88b5f3e0..ee75d4d6 100644
--- a/quil-rs/src/instruction/calibration.rs
+++ b/quil-rs/src/instruction/calibration.rs
@@ -3,7 +3,7 @@ use crate::{
         write_expression_parameter_string, write_instruction_block, Expression, GateModifier,
         Instruction, Qubit,
     },
-    quil::Quil,
+    quil::{Quil, INDENT},
     validation::identifier::{validate_identifier, IdentifierValidationError},
 };
 
@@ -62,7 +62,7 @@ impl Quil for Calibration {
         write_qubit_parameters(f, fall_back_to_debug, &self.qubits)?;
         write!(f, ":")?;
         for instruction in &self.instructions {
-            write!(f, "\n\t")?;
+            write!(f, "\n{INDENT}")?;
             instruction.write(f, fall_back_to_debug)?;
         }
         Ok(())
diff --git a/quil-rs/src/instruction/circuit.rs b/quil-rs/src/instruction/circuit.rs
index 90e4ccba..51fc7aee 100644
--- a/quil-rs/src/instruction/circuit.rs
+++ b/quil-rs/src/instruction/circuit.rs
@@ -1,4 +1,4 @@
-use crate::quil::Quil;
+use crate::quil::{Quil, INDENT};
 
 use super::Instruction;
 
@@ -55,7 +55,7 @@ impl Quil for CircuitDefinition {
                 false => instruction.to_quil()?,
             };
             for line in lines.split('\n') {
-                writeln!(writer, "\t{line}")?;
+                writeln!(writer, "{INDENT}{line}")?;
             }
         }
 
diff --git a/quil-rs/src/instruction/frame.rs b/quil-rs/src/instruction/frame.rs
index e9ced8a2..0413a51d 100644
--- a/quil-rs/src/instruction/frame.rs
+++ b/quil-rs/src/instruction/frame.rs
@@ -8,7 +8,7 @@ use crate::{
     expression::Expression,
     parser::{common::parse_frame_identifier, lex, ParseError},
     program::{disallow_leftover, SyntaxError},
-    quil::Quil,
+    quil::{Quil, INDENT},
 };
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, strum::EnumTryAs)]
@@ -58,7 +58,7 @@ impl Quil for FrameDefinition {
         self.identifier.write(writer, fall_back_to_debug)?;
         write!(writer, ":")?;
         for (key, value) in &self.attributes {
-            write!(writer, "\n\t{}: ", key)?;
+            write!(writer, "\n{INDENT}{key}: ")?;
             value.write(writer, fall_back_to_debug)?;
         }
 
diff --git a/quil-rs/src/instruction/gate.rs b/quil-rs/src/instruction/gate.rs
index 859b6688..bd4e7bcb 100644
--- a/quil-rs/src/instruction/gate.rs
+++ b/quil-rs/src/instruction/gate.rs
@@ -2,7 +2,7 @@ use crate::{
     expression::Expression,
     imag,
     instruction::{write_expression_parameter_string, write_parameter_string, write_qubits, Qubit},
-    quil::{write_join_quil, Quil},
+    quil::{write_join_quil, Quil, INDENT},
     real,
     validation::identifier::{
         validate_identifier, validate_user_identifier, IdentifierValidationError,
@@ -870,13 +870,13 @@ impl Quil for GateSpecification {
         match self {
             GateSpecification::Matrix(matrix) => {
                 for row in matrix {
-                    write!(f, "\t")?;
+                    write!(f, "{INDENT}")?;
                     write_join_quil(f, fall_back_to_debug, row.iter(), ", ", "")?;
                     writeln!(f)?;
                 }
             }
             GateSpecification::Permutation(permutation) => {
-                write!(f, "\t")?;
+                write!(f, "{INDENT}")?;
                 if let Some(i) = permutation.first() {
                     write!(f, "{i}")?;
                 }
@@ -887,7 +887,7 @@ impl Quil for GateSpecification {
             }
             GateSpecification::PauliSum(pauli_sum) => {
                 for term in &pauli_sum.terms {
-                    write!(f, "\t")?;
+                    write!(f, "{INDENT}")?;
                     for word in term.word() {
                         write!(f, "{word}")?;
                     }
diff --git a/quil-rs/src/instruction/waveform.rs b/quil-rs/src/instruction/waveform.rs
index 9c85cf4c..69f6f1cc 100644
--- a/quil-rs/src/instruction/waveform.rs
+++ b/quil-rs/src/instruction/waveform.rs
@@ -2,7 +2,7 @@ use indexmap::IndexMap;
 
 use crate::{
     expression::Expression,
-    quil::{write_join_quil, Quil},
+    quil::{write_join_quil, Quil, INDENT},
 };
 
 use super::write_parameter_string;
@@ -39,7 +39,7 @@ impl Quil for WaveformDefinition {
     ) -> crate::quil::ToQuilResult<()> {
         write!(f, "DEFWAVEFORM {}", self.name)?;
         write_parameter_string(f, &self.definition.parameters)?;
-        write!(f, ":\n\t")?;
+        write!(f, ":\n{INDENT}")?;
         write_join_quil(f, fall_back_to_debug, &self.definition.matrix, ", ", "")
             .map_err(Into::into)
     }
diff --git a/quil-rs/src/parser/lexer/mod.rs b/quil-rs/src/parser/lexer/mod.rs
index 235bc810..cd4d95a0 100644
--- a/quil-rs/src/parser/lexer/mod.rs
+++ b/quil-rs/src/parser/lexer/mod.rs
@@ -139,15 +139,24 @@ fn _lex(input: LexInput) -> InternalLexResult<Vec<TokenWithLocation>> {
     terminated(
         many0(alt(
             "indentation or a token preceded by whitespace",
-            (
-                token_with_location(value(Token::Indentation, tag("    "))),
-                preceded(many0(tag(" ")), lex_token),
-            ),
+            (lex_indent, preceded(many0(tag(" ")), lex_token)),
         )),
         many0(one_of("\n\t ")),
     )(input)
 }
 
+/// The Quil spec defines an indent as exactly 4 spaces. However, the lexer recognizes tabs as well
+/// to allow for more flexible formatting.
+fn lex_indent(input: LexInput) -> InternalLexResult<TokenWithLocation> {
+    alt(
+        "indentation",
+        (
+            token_with_location(value(Token::Indentation, tag("    "))),
+            token_with_location(value(Token::Indentation, tag("\t"))),
+        ),
+    )(input)
+}
+
 fn lex_token(input: LexInput) -> InternalLexResult<TokenWithLocation> {
     alt(
         "a token",
diff --git a/quil-rs/src/program/mod.rs b/quil-rs/src/program/mod.rs
index 7846bb79..f5b07aa3 100644
--- a/quil-rs/src/program/mod.rs
+++ b/quil-rs/src/program/mod.rs
@@ -702,7 +702,7 @@ mod tests {
             Gate, Instruction, Jump, JumpUnless, JumpWhen, Label, Matrix, MemoryReference, Qubit,
             QubitPlaceholder, Target, TargetPlaceholder,
         },
-        quil::Quil,
+        quil::{Quil, INDENT},
         real,
     };
     use approx::assert_abs_diff_eq;
@@ -800,11 +800,11 @@ I 0
             program.to_quil().unwrap(),
             "DECLARE ro BIT[5]
 DEFFRAME 0 \"rx\":
-\tHARDWARE-OBJECT: \"hardware\"
+    HARDWARE-OBJECT: \"hardware\"
 DEFWAVEFORM custom:
-\t1, 2
+    1, 2
 DEFCAL I 0:
-\tDELAY 0 1
+    DELAY 0 1
 I 0
 "
         );
@@ -1153,21 +1153,23 @@ I 0
     /// consistent results.
     #[test]
     fn test_to_instructions() {
-        let input = "DECLARE foo REAL[1]
+        let input = format!(
+            "DECLARE foo REAL[1]
 DEFFRAME 1 \"rx\":
-\tHARDWARE-OBJECT: \"hardware\"
+{INDENT}HARDWARE-OBJECT: \"hardware\"
 DEFWAVEFORM custom2:
-\t1, 2
+{INDENT}1, 2
 DEFCAL I 1:
-\tDELAY 0 1
+{INDENT}DELAY 0 1
 DEFGATE BAR AS MATRIX:
-\t0, 1
-\t1, 0
+{INDENT}0, 1
+{INDENT}1, 0
 
 H 1
 CNOT 2 3
-";
-        let program = Program::from_str(input).unwrap();
+"
+        );
+        let program = Program::from_str(&input).unwrap();
         assert_debug_snapshot!(program.to_instructions());
         assert_eq!(program.to_quil().unwrap(), input);
         assert_eq!(program.to_instructions(), program.into_instructions());
diff --git a/quil-rs/src/quil.rs b/quil-rs/src/quil.rs
index ae5aca57..27f9153b 100644
--- a/quil-rs/src/quil.rs
+++ b/quil-rs/src/quil.rs
@@ -29,6 +29,10 @@ pub trait Quil: std::fmt::Debug {
     ) -> Result<(), ToQuilError>;
 }
 
+/// Per the Quil specification, an indentation is exactly 4 spaces.
+/// See [Quil 3-2](https://quil-lang.github.io/#3-2Syntactic-Rudiments)
+pub(crate) const INDENT: &str = "    ";
+
 pub type ToQuilResult<T> = Result<T, ToQuilError>;
 
 /// Errors which can occur when converting a Quil item to a string.


Test patch:
diff --git a/quil-py/test/program/__snapshots__/test_program.ambr b/quil-py/test/program/__snapshots__/test_program.ambr
index 79a305ea..8ceda0c8 100644
--- a/quil-py/test/program/__snapshots__/test_program.ambr
+++ b/quil-py/test/program/__snapshots__/test_program.ambr
@@ -2,8 +2,8 @@
   '''
   DECLARE foo REAL[1]
   DEFGATE BAR AS MATRIX:
-  	0, 1
-  	1, 0
+      0, 1
+      1, 0
   
   H 1
   CNOT 2 3
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition No Params.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition No Params.snap
index 8fba7c5d..2b9d03e3 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition No Params.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition No Params.snap
@@ -1,8 +1,7 @@
 ---
 source: quil-rs/src/instruction/circuit.rs
-expression: circuit_def.to_string()
+expression: circuit_def.to_quil_or_debug()
 ---
 DEFCIRCUIT BELL a b:
-	H a
-	CNOT a b
-
+    H a
+    CNOT a b
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Params.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Params.snap
index 8d61c97d..60182c10 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Params.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Params.snap
@@ -1,11 +1,10 @@
 ---
 source: quil-rs/src/instruction/circuit.rs
-expression: circuit_def.to_string()
+expression: circuit_def.to_quil_or_debug()
 ---
 DEFCIRCUIT BELL(%a, %b) a b:
-	RZ(%a) a
-	RZ(%b) a
-	RX(%a) a
-	RZ(%a) a
-	CNOT a b
-
+    RZ(%a) a
+    RZ(%b) a
+    RX(%a) a
+    RZ(%a) a
+    CNOT a b
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Single Param.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Single Param.snap
index 74a75f4f..ff903060 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Single Param.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__circuit__test_circuit_definition__display@CircuitDefinition With Single Param.snap
@@ -3,8 +3,7 @@ source: quil-rs/src/instruction/circuit.rs
 expression: circuit_def.to_quil_or_debug()
 ---
 DEFCIRCUIT BELL(%a) a b:
-	RZ(%a) a
-	RX(%a) a
-	RZ(%a) a
-	CNOT a b
-
+    RZ(%a) a
+    RX(%a) a
+    RZ(%a) a
+    CNOT a b
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Parameterized GateDefinition.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Parameterized GateDefinition.snap
index a3fade6c..728be535 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Parameterized GateDefinition.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Parameterized GateDefinition.snap
@@ -1,8 +1,7 @@
 ---
 source: quil-rs/src/instruction/gate.rs
-expression: gate_def.to_string()
+expression: gate_def.to_quil_or_debug()
 ---
 DEFGATE ParamGate(%theta) AS MATRIX:
-	cos(%theta/2), -1.0i*sin(%theta/2)
-	-1.0i*sin(%theta/2), cos(%theta/2)
-
+    cos(%theta/2), -1.0i*sin(%theta/2)
+    -1.0i*sin(%theta/2), cos(%theta/2)
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Pauli Sum GateDefinition.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Pauli Sum GateDefinition.snap
index 2196c663..131bea0c 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Pauli Sum GateDefinition.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Pauli Sum GateDefinition.snap
@@ -1,9 +1,8 @@
 ---
 source: quil-rs/src/instruction/gate.rs
-expression: gate_def.to_string()
+expression: gate_def.to_quil_or_debug()
 ---
 DEFGATE PauliSumGate(%theta) p q AS PAULI-SUM:
-	ZZ(-%theta/4) p q
-	Y(%theta/4) p
-	X(%theta/4) q
-
+    ZZ(-%theta/4) p q
+    Y(%theta/4) p
+    X(%theta/4) q
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Permutation GateDefinition.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Permutation GateDefinition.snap
index f5b3794d..e0fb8f52 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Permutation GateDefinition.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__gate__test_gate_definition__display@Permutation GateDefinition.snap
@@ -1,7 +1,6 @@
 ---
 source: quil-rs/src/instruction/gate.rs
-expression: gate_def.to_string()
+expression: gate_def.to_quil_or_debug()
 ---
 DEFGATE PermGate AS PERMUTATION:
-	0, 1, 2, 3, 4, 5, 7, 6
-
+    0, 1, 2, 3, 4, 5, 7, 6
diff --git a/quil-rs/src/instruction/snapshots/quil_rs__instruction__waveform__test_waveform_definition__display@Simple WaveformDefinition.snap b/quil-rs/src/instruction/snapshots/quil_rs__instruction__waveform__test_waveform_definition__display@Simple WaveformDefinition.snap
index c8e614a1..d6b60a84 100644
--- a/quil-rs/src/instruction/snapshots/quil_rs__instruction__waveform__test_waveform_definition__display@Simple WaveformDefinition.snap
+++ b/quil-rs/src/instruction/snapshots/quil_rs__instruction__waveform__test_waveform_definition__display@Simple WaveformDefinition.snap
@@ -1,6 +1,6 @@
 ---
 source: quil-rs/src/instruction/waveform.rs
-expression: waveform_def.to_string()
+expression: waveform_def.to_quil_or_debug()
 ---
 DEFWAVEFORM WF(%theta):
-	0, 0, 0.00027685415721916584
+    0, 0, 0.00027685415721916584
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Instruction-Match.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Instruction-Match.snap
index 1a4b0b49..b27f4788 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Instruction-Match.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Instruction-Match.snap
@@ -1,10 +1,9 @@
 ---
 source: quil-rs/src/program/calibration.rs
-expression: calibrated_program.to_string()
+expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL X 0:
-	Y 0
+    Y 0
 DEFCAL Y 0:
-	PULSE 0 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
+    PULSE 0 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 PULSE 0 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Literal-Parameter.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Literal-Parameter.snap
index e2d428f6..11e57f00 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Literal-Parameter.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Literal-Parameter.snap
@@ -1,8 +1,7 @@
 ---
 source: quil-rs/src/program/calibration.rs
-expression: calibrated_program.to_string()
+expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL RX(3.141592653589793) 0:
-	NOP
+    NOP
 NOP
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Param-Precedence.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Param-Precedence.snap
index 368eaac7..6bac65ca 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Param-Precedence.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Param-Precedence.snap
@@ -3,12 +3,11 @@ source: quil-rs/src/program/calibration.rs
 expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL RX(%theta) qubit:
-	PULSE 1 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
+    PULSE 1 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 DEFCAL RX(%theta) 0:
-	PULSE 2 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
+    PULSE 2 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 DEFCAL RX(pi/2) 0:
-	PULSE 3 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
+    PULSE 3 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 PULSE 1 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 PULSE 2 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 PULSE 3 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Simple.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Simple.snap
index 44c8e037..74ddddb9 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Simple.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Simple.snap
@@ -1,8 +1,7 @@
 ---
 source: quil-rs/src/program/calibration.rs
-expression: calibrated_program.to_string()
+expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL X 0:
-	PULSE 0 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
+    PULSE 0 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
 PULSE 0 "xy" gaussian(duration: 1, fwhm: 2, t0: 3)
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Variable-Qubit.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Variable-Qubit.snap
index c1b1443b..d22096fb 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Variable-Qubit.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@Calibration-Variable-Qubit.snap
@@ -3,6 +3,5 @@ source: quil-rs/src/program/calibration.rs
 expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL I q:
-	DELAY q 4e-8
+    DELAY q 4e-8
 DELAY 0 4e-8
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@FenceVariableQubit.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@FenceVariableQubit.snap
index 9bfdddf9..267dee72 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@FenceVariableQubit.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@FenceVariableQubit.snap
@@ -3,8 +3,7 @@ source: quil-rs/src/program/calibration.rs
 expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL FENCES q0 q1:
-	FENCE q0
-	FENCE q1
+    FENCE q0
+    FENCE q1
 FENCE 0
 FENCE 1
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@ShiftPhase.snap b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@ShiftPhase.snap
index b62a573e..779b80eb 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@ShiftPhase.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__calibration__tests__expansion@ShiftPhase.snap
@@ -3,6 +3,5 @@ source: quil-rs/src/program/calibration.rs
 expression: calibrated_program.to_quil_or_debug()
 ---
 DEFCAL RZ(%theta) q:
-	SHIFT-PHASE q "rf" -%theta
+    SHIFT-PHASE q "rf" -%theta
 SHIFT-PHASE 0 "rf" -pi
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__tests__filter_instructions.snap b/quil-rs/src/program/snapshots/quil_rs__program__tests__filter_instructions.snap
index e12ff500..c6edb875 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__tests__filter_instructions.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__tests__filter_instructions.snap
@@ -4,9 +4,8 @@ expression: program_without_quil_t.to_quil().unwrap()
 ---
 DECLARE foo REAL[1]
 DEFGATE BAR AS MATRIX:
-	0, 1
-	1, 0
+    0, 1
+    1, 0
 
 H 1
 CNOT 2 3
-
diff --git a/quil-rs/src/program/snapshots/quil_rs__program__tests__wrap_in_loop.snap b/quil-rs/src/program/snapshots/quil_rs__program__tests__wrap_in_loop.snap
index 7d7f44e0..bffeb29d 100644
--- a/quil-rs/src/program/snapshots/quil_rs__program__tests__wrap_in_loop.snap
+++ b/quil-rs/src/program/snapshots/quil_rs__program__tests__wrap_in_loop.snap
@@ -5,11 +5,11 @@ expression: program.to_quil().unwrap()
 DECLARE ro BIT[1]
 DECLARE shot_count INTEGER[1]
 DEFFRAME 0 "rx":
-	HARDWARE-OBJECT: "hardware"
+    HARDWARE-OBJECT: "hardware"
 DEFWAVEFORM custom:
-	1, 2
+    1, 2
 DEFCAL I 0:
-	DELAY 0 1
+    DELAY 0 1
 MOVE shot_count[0] 10
 LABEL @loop-start
 MEASURE q ro[0]
@@ -21,4 +21,3 @@ SUB shot_count[0] 1
 JUMP-UNLESS @loop-end shot_count[0]
 JUMP @loop-start
 LABEL @loop-end
-
diff --git a/quil-rs/tests/snapshots/calibration_test__calibration_cz.quil.snap b/quil-rs/tests/snapshots/calibration_test__calibration_cz.quil.snap
index 9d9dbab6..3a1f3150 100644
--- a/quil-rs/tests/snapshots/calibration_test__calibration_cz.quil.snap
+++ b/quil-rs/tests/snapshots/calibration_test__calibration_cz.quil.snap
@@ -1,31 +1,30 @@
 ---
 source: quil-rs/tests/calibration_test.rs
-expression: program.to_string()
+expression: program.to_quil_or_debug()
 ---
 DEFCAL CZ 110 111:
-	FENCE
-	NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
-	DELAY 110 "rf" 1.6e-7
-	SHIFT-PHASE 110 "rf" 0.6
-	DELAY 111 "rf" 1.6e-7
-	SHIFT-PHASE 111 "rf" 0.4
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.3
-	SHIFT-PHASE 110 117 "xy" 0.3
-	SHIFT-PHASE 110 111 "xy" -0.2
-	SHIFT-PHASE 111 112 "xy" -0.2
-	SHIFT-PHASE 111 126 "xy" -0.2
+    FENCE
+    NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
+    DELAY 110 "rf" 1.6e-7
+    SHIFT-PHASE 110 "rf" 0.6
+    DELAY 111 "rf" 1.6e-7
+    SHIFT-PHASE 111 "rf" 0.4
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.3
+    SHIFT-PHASE 110 117 "xy" 0.3
+    SHIFT-PHASE 110 111 "xy" -0.2
+    SHIFT-PHASE 111 112 "xy" -0.2
+    SHIFT-PHASE 111 126 "xy" -0.2
 DEFCAL CZ 111 110:
-	FENCE
-	NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
-	DELAY 110 "rf" 1.6e-7
-	SHIFT-PHASE 110 "rf" 0.6
-	DELAY 111 "rf" 1.6e-7
-	SHIFT-PHASE 111 "rf" 0.4
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.3
-	SHIFT-PHASE 110 117 "xy" 0.3
-	SHIFT-PHASE 110 111 "xy" -0.2
-	SHIFT-PHASE 111 112 "xy" -0.2
-	SHIFT-PHASE 111 126 "xy" -0.2
-
+    FENCE
+    NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
+    DELAY 110 "rf" 1.6e-7
+    SHIFT-PHASE 110 "rf" 0.6
+    DELAY 111 "rf" 1.6e-7
+    SHIFT-PHASE 111 "rf" 0.4
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.3
+    SHIFT-PHASE 110 117 "xy" 0.3
+    SHIFT-PHASE 110 111 "xy" -0.2
+    SHIFT-PHASE 111 112 "xy" -0.2
+    SHIFT-PHASE 111 126 "xy" -0.2
diff --git a/quil-rs/tests/snapshots/calibration_test__calibration_cz_phase.quil.snap b/quil-rs/tests/snapshots/calibration_test__calibration_cz_phase.quil.snap
index 18b7d532..e3efb7f4 100644
--- a/quil-rs/tests/snapshots/calibration_test__calibration_cz_phase.quil.snap
+++ b/quil-rs/tests/snapshots/calibration_test__calibration_cz_phase.quil.snap
@@ -1,63 +1,62 @@
 ---
 source: quil-rs/tests/calibration_test.rs
-expression: program.to_string()
+expression: program.to_quil_or_debug()
 ---
 DEFCAL CZ 110 111:
-	FENCE
-	NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
-	DELAY 110 "rf" 1.6e-7
-	SHIFT-PHASE 110 "rf" 0.6
-	DELAY 111 "rf" 1.6e-7
-	SHIFT-PHASE 111 "rf" 0.4
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.3
-	SHIFT-PHASE 110 117 "xy" 0.3
-	SHIFT-PHASE 110 111 "xy" -0.2
-	SHIFT-PHASE 111 112 "xy" -0.2
-	SHIFT-PHASE 111 126 "xy" -0.2
+    FENCE
+    NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
+    DELAY 110 "rf" 1.6e-7
+    SHIFT-PHASE 110 "rf" 0.6
+    DELAY 111 "rf" 1.6e-7
+    SHIFT-PHASE 111 "rf" 0.4
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.3
+    SHIFT-PHASE 110 117 "xy" 0.3
+    SHIFT-PHASE 110 111 "xy" -0.2
+    SHIFT-PHASE 111 112 "xy" -0.2
+    SHIFT-PHASE 111 126 "xy" -0.2
 DEFCAL CZ 111 110:
-	FENCE
-	NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
-	DELAY 110 "rf" 1.6e-7
-	SHIFT-PHASE 110 "rf" 0.6
-	DELAY 111 "rf" 1.6e-7
-	SHIFT-PHASE 111 "rf" 0.4
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.3
-	SHIFT-PHASE 110 117 "xy" 0.3
-	SHIFT-PHASE 110 111 "xy" -0.2
-	SHIFT-PHASE 111 112 "xy" -0.2
-	SHIFT-PHASE 111 126 "xy" -0.2
+    FENCE
+    NONBLOCKING PULSE 110 111 "cz" q110_q111_cz/CZ
+    DELAY 110 "rf" 1.6e-7
+    SHIFT-PHASE 110 "rf" 0.6
+    DELAY 111 "rf" 1.6e-7
+    SHIFT-PHASE 111 "rf" 0.4
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.3
+    SHIFT-PHASE 110 117 "xy" 0.3
+    SHIFT-PHASE 110 111 "xy" -0.2
+    SHIFT-PHASE 111 112 "xy" -0.2
+    SHIFT-PHASE 111 126 "xy" -0.2
 DEFCAL CPHASE(%theta) 110 111:
-	FENCE
-	NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
-	SHIFT-PHASE 110 111 "cphase" -1.2+(0.5*%theta)
-	NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
-	SHIFT-PHASE 110 111 "cphase" -1*(-1.2+(0.5*%theta))
-	DELAY 110 "rf" 3.2e-7
-	SHIFT-PHASE 110 "rf" 2.2
-	DELAY 111 "rf" 3.2e-7
-	SHIFT-PHASE 111 "rf" 1.2
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 1.1
-	SHIFT-PHASE 110 117 "xy" 1.1
-	SHIFT-PHASE 110 111 "xy" -0.6
-	SHIFT-PHASE 111 112 "xy" -0.6
-	SHIFT-PHASE 111 126 "xy" -0.6
+    FENCE
+    NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
+    SHIFT-PHASE 110 111 "cphase" -1.2+(0.5*%theta)
+    NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
+    SHIFT-PHASE 110 111 "cphase" -1*(-1.2+(0.5*%theta))
+    DELAY 110 "rf" 3.2e-7
+    SHIFT-PHASE 110 "rf" 2.2
+    DELAY 111 "rf" 3.2e-7
+    SHIFT-PHASE 111 "rf" 1.2
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 1.1
+    SHIFT-PHASE 110 117 "xy" 1.1
+    SHIFT-PHASE 110 111 "xy" -0.6
+    SHIFT-PHASE 111 112 "xy" -0.6
+    SHIFT-PHASE 111 126 "xy" -0.6
 DEFCAL CPHASE(%theta) 111 110:
-	FENCE
-	NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
-	SHIFT-PHASE 110 111 "cphase" -1.2+(0.5*%theta)
-	NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
-	SHIFT-PHASE 110 111 "cphase" -1*(-1.2+(0.5*%theta))
-	DELAY 110 "rf" 3.2e-7
-	SHIFT-PHASE 110 "rf" 2.2
-	DELAY 111 "rf" 3.2e-7
-	SHIFT-PHASE 111 "rf" 1.2
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 1.1
-	SHIFT-PHASE 110 117 "xy" 1.1
-	SHIFT-PHASE 110 111 "xy" -0.6
-	SHIFT-PHASE 111 112 "xy" -0.6
-	SHIFT-PHASE 111 126 "xy" -0.6
-
+    FENCE
+    NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
+    SHIFT-PHASE 110 111 "cphase" -1.2+(0.5*%theta)
+    NONBLOCKING PULSE 110 111 "cphase" q110_q111_cphase/sqrtCPHASE
+    SHIFT-PHASE 110 111 "cphase" -1*(-1.2+(0.5*%theta))
+    DELAY 110 "rf" 3.2e-7
+    SHIFT-PHASE 110 "rf" 2.2
+    DELAY 111 "rf" 3.2e-7
+    SHIFT-PHASE 111 "rf" 1.2
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 1.1
+    SHIFT-PHASE 110 117 "xy" 1.1
+    SHIFT-PHASE 110 111 "xy" -0.6
+    SHIFT-PHASE 111 112 "xy" -0.6
+    SHIFT-PHASE 111 126 "xy" -0.6
diff --git a/quil-rs/tests/snapshots/calibration_test__calibration_rx.quil.snap b/quil-rs/tests/snapshots/calibration_test__calibration_rx.quil.snap
index b2f4904a..8de2c092 100644
--- a/quil-rs/tests/snapshots/calibration_test__calibration_rx.quil.snap
+++ b/quil-rs/tests/snapshots/calibration_test__calibration_rx.quil.snap
@@ -1,37 +1,36 @@
 ---
 source: quil-rs/tests/calibration_test.rs
-expression: program.to_string()
+expression: program.to_quil_or_debug()
 ---
 DEFCAL RX(pi/2) 0:
-	FENCE 0
-	NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.1, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.1, t0: 1e-8)
-	FENCE 0
+    FENCE 0
+    NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.1, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.1, t0: 1e-8)
+    FENCE 0
 DEFCAL RX(-pi/2) 0:
-	FENCE 0
-	NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.2, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.2, t0: 1e-8)
-	FENCE 0
+    FENCE 0
+    NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.2, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.2, t0: 1e-8)
+    FENCE 0
 DEFCAL RX(pi) 0:
-	FENCE 0
-	NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.3, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.3, t0: 1e-8)
-	FENCE 0
+    FENCE 0
+    NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.3, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.3, t0: 1e-8)
+    FENCE 0
 DEFCAL RX(-pi) 0:
-	FENCE 0
-	NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.4, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.4, t0: 1e-8)
-	FENCE 0
+    FENCE 0
+    NONBLOCKING PULSE 0 "rf" drag_gaussian(alpha: -0.4, anh: -100000000, detuning: 0, duration: 1e-8, fwhm: 1e-8, phase: 0, scale: 0.4, t0: 1e-8)
+    FENCE 0
 DEFCAL RX(pi/2) 3:
-	FENCE 3
-	NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.1, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.1, t0: 1e-8)
-	FENCE 3
+    FENCE 3
+    NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.1, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.1, t0: 1e-8)
+    FENCE 3
 DEFCAL RX(-pi/2) 3:
-	FENCE 3
-	NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.2, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.2, t0: 1e-8)
-	FENCE 3
+    FENCE 3
+    NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.2, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.2, t0: 1e-8)
+    FENCE 3
 DEFCAL RX(pi) 3:
-	FENCE 3
-	NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.3, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.3, t0: 1e-8)
-	FENCE 3
+    FENCE 3
+    NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.3, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.3, t0: 1e-8)
+    FENCE 3
 DEFCAL RX(-pi) 3:
-	FENCE 3
-	NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.4, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.4, t0: 1e-8)
-	FENCE 3
-
+    FENCE 3
+    NONBLOCKING PULSE 3 "rf" drag_gaussian(alpha: -0.4, anh: -100000000, detuning: 0, duration: 2e-8, fwhm: 1e-8, phase: 0, scale: 0.4, t0: 1e-8)
+    FENCE 3
diff --git a/quil-rs/tests/snapshots/calibration_test__calibration_xy.quil.snap b/quil-rs/tests/snapshots/calibration_test__calibration_xy.quil.snap
index ec05a295..b00ae708 100644
--- a/quil-rs/tests/snapshots/calibration_test__calibration_xy.quil.snap
+++ b/quil-rs/tests/snapshots/calibration_test__calibration_xy.quil.snap
@@ -1,55 +1,54 @@
 ---
 source: quil-rs/tests/calibration_test.rs
-expression: program.to_string()
+expression: program.to_quil_or_debug()
 ---
 DEFCAL XY(%theta) 110 111:
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.4
-	NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
-	SHIFT-PHASE 110 111 "xy" -0.4
-	SHIFT-PHASE 110 111 "xy" 1.8+(-0.5*%theta)
-	NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
-	SHIFT-PHASE 110 111 "xy" -1*(1.8+(-0.5*%theta))
-	DELAY 110 "rf" 1.2e-7
-	SHIFT-PHASE 110 "rf" 0.8
-	DELAY 111 "rf" 1.2e-7
-	SHIFT-PHASE 111 "rf" 0.4
-	SHIFT-PHASE 111 "rf" 0.5*%theta
-	SHIFT-PHASE 110 "rf" -0.5*%theta
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.4
-	SHIFT-PHASE 110 117 "xy" 0.4
-	SHIFT-PHASE 110 111 "xy" -0.2
-	SHIFT-PHASE 111 112 "xy" -0.2
-	SHIFT-PHASE 111 126 "xy" -0.2
-	SHIFT-PHASE 110 111 "xy" -0.25*%theta
-	SHIFT-PHASE 111 112 "xy" -0.25*%theta
-	SHIFT-PHASE 111 126 "xy" -0.25*%theta
-	SHIFT-PHASE 110 111 "xy" -0.25*%theta
-	SHIFT-PHASE 110 117 "xy" -0.25*%theta
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.4
+    NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
+    SHIFT-PHASE 110 111 "xy" -0.4
+    SHIFT-PHASE 110 111 "xy" 1.8+(-0.5*%theta)
+    NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
+    SHIFT-PHASE 110 111 "xy" -1*(1.8+(-0.5*%theta))
+    DELAY 110 "rf" 1.2e-7
+    SHIFT-PHASE 110 "rf" 0.8
+    DELAY 111 "rf" 1.2e-7
+    SHIFT-PHASE 111 "rf" 0.4
+    SHIFT-PHASE 111 "rf" 0.5*%theta
+    SHIFT-PHASE 110 "rf" -0.5*%theta
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.4
+    SHIFT-PHASE 110 117 "xy" 0.4
+    SHIFT-PHASE 110 111 "xy" -0.2
+    SHIFT-PHASE 111 112 "xy" -0.2
+    SHIFT-PHASE 111 126 "xy" -0.2
+    SHIFT-PHASE 110 111 "xy" -0.25*%theta
+    SHIFT-PHASE 111 112 "xy" -0.25*%theta
+    SHIFT-PHASE 111 126 "xy" -0.25*%theta
+    SHIFT-PHASE 110 111 "xy" -0.25*%theta
+    SHIFT-PHASE 110 117 "xy" -0.25*%theta
 DEFCAL XY(%theta) 111 110:
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.4
-	NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
-	SHIFT-PHASE 110 111 "xy" -0.4
-	SHIFT-PHASE 110 111 "xy" 1.8+(-0.5*%theta)
-	NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
-	SHIFT-PHASE 110 111 "xy" -1*(1.8+(-0.5*%theta))
-	DELAY 110 "rf" 1.2e-7
-	SHIFT-PHASE 110 "rf" 0.8
-	DELAY 111 "rf" 1.2e-7
-	SHIFT-PHASE 111 "rf" 0.4
-	SHIFT-PHASE 111 "rf" 0.5*%theta
-	SHIFT-PHASE 110 "rf" -0.5*%theta
-	FENCE
-	SHIFT-PHASE 110 111 "xy" 0.4
-	SHIFT-PHASE 110 117 "xy" 0.4
-	SHIFT-PHASE 110 111 "xy" -0.2
-	SHIFT-PHASE 111 112 "xy" -0.2
-	SHIFT-PHASE 111 126 "xy" -0.2
-	SHIFT-PHASE 110 111 "xy" -0.25*%theta
-	SHIFT-PHASE 111 112 "xy" -0.25*%theta
-	SHIFT-PHASE 111 126 "xy" -0.25*%theta
-	SHIFT-PHASE 110 111 "xy" -0.25*%theta
-	SHIFT-PHASE 110 117 "xy" -0.25*%theta
-
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.4
+    NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
+    SHIFT-PHASE 110 111 "xy" -0.4
+    SHIFT-PHASE 110 111 "xy" 1.8+(-0.5*%theta)
+    NONBLOCKING PULSE 110 111 "xy" q110_q111_xy/sqrtiSWAP
+    SHIFT-PHASE 110 111 "xy" -1*(1.8+(-0.5*%theta))
+    DELAY 110 "rf" 1.2e-7
+    SHIFT-PHASE 110 "rf" 0.8
+    DELAY 111 "rf" 1.2e-7
+    SHIFT-PHASE 111 "rf" 0.4
+    SHIFT-PHASE 111 "rf" 0.5*%theta
+    SHIFT-PHASE 110 "rf" -0.5*%theta
+    FENCE
+    SHIFT-PHASE 110 111 "xy" 0.4
+    SHIFT-PHASE 110 117 "xy" 0.4
+    SHIFT-PHASE 110 111 "xy" -0.2
+    SHIFT-PHASE 111 112 "xy" -0.2
+    SHIFT-PHASE 111 126 "xy" -0.2
+    SHIFT-PHASE 110 111 "xy" -0.25*%theta
+    SHIFT-PHASE 111 112 "xy" -0.25*%theta
+    SHIFT-PHASE 111 126 "xy" -0.25*%theta
+    SHIFT-PHASE 110 111 "xy" -0.25*%theta
+    SHIFT-PHASE 110 117 "xy" -0.25*%theta