From eb7099a236c849ecb9bd89e40c252fe8629bc21f Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Thu, 28 Mar 2024 14:34:08 -0400 Subject: [PATCH] Add tests of the example code in the OQ3 spec This is the start of a big project. Especially becaue a good amount of the code fails. This is in part because we have been increasing the amount of semantic analysis. This is good because less incorrect code is silently allowed. However the are many false positives. This exercise is a good way to identify and organize features that are not supported or that have bugs. This commit covers all of "comments.rst" and 16 percent of the file "types.rst". --- crates/oq3_semantics/tests/spec.rs | 174 +++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 crates/oq3_semantics/tests/spec.rs diff --git a/crates/oq3_semantics/tests/spec.rs b/crates/oq3_semantics/tests/spec.rs new file mode 100644 index 0000000..7587c9a --- /dev/null +++ b/crates/oq3_semantics/tests/spec.rs @@ -0,0 +1,174 @@ +use oq3_semantics::asg; +use oq3_semantics::semantic_error::SemanticErrorList; +use oq3_semantics::symbols::SymbolTable; +use oq3_semantics::syntax_to_semantics::parse_source_string; + +// This file tests code in the written OpenQASM 3 spec. +// +// The commit from which the example code was taken is written above each test. +// +// Tests that cause the parser to panic are commented out. +// +// Tests of unimplemented features are marked "Not supported". Note that if possible +// these tests are designed to pass. The + +fn parse_string(code: &str) -> (asg::Program, SemanticErrorList, SymbolTable) { + parse_source_string(code, None, None::<&[&std::path::Path]>) + .take_context() + .as_tuple() +} + +// +// comments.rst +// + +// 17dedf +#[test] +fn test_spec_comments_1() { + let code = r#" +// A comment line + +/* +A comment block +*/ +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert!(program.is_empty()); +} + +// 17dedf +// NOTE! Two problems here. One: In this version of the spec, +// the file is stdgates.qasm rather than the correct stdgates.inc +// Two: This parser panics rather than gracefully recording an error +// if an included file is not found. +// There is a PR open to fix the spec https://github.com/openqasm/openqasm/pull/523 +// In the meantime, I took the liberty of changing the code in the spec and testing that +// instead. +// Note that neither of the non-comment lines is translated to a statement, so the +// program is still empty. +#[test] +fn test_spec_comments_2() { + let code = r#" +// First non-comment is a version string +OPENQASM 3.0; + +include "stdgates.inc"; + +// Rest of QASM program +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert!(program.is_empty()); +} + +// +// types.rst +// + +// 17dedf +#[test] +fn test_spec_types_1() { + let code = r#" +qubit q0; +qubit q1; +qubit q2; + +// and to declare a set of classical variables + +int[32] a; +float[32] b = 5.5; +bit[3] c; +bool my_bool = false; +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert_eq!(program.len(), 7); +} + +// 17dedf +// Not supported +// Issue #211 +// #[test] +// fn test_spec_types_2() { +// let code = r#" +// // Valid statements + +// include "stdgates.inc"; + +// qubit[5] q1; +// const uint SIZE = 4; +// uint runtime_u = 2; +// qubit[SIZE] q2; // Declare a 4-qubit register. + +// x q1[0]; +// z q2[SIZE - 2]; // The index operand is of type `const uint`. + +// // Validity is implementation-defined. + +// x q1[runtime_u]; +// // Indexing with a value with a non-`const` type (`uint`, in this case) is +// // not guaranteed to be supported. +// "#; +// let (_program, errors, _symbol_table) = parse_string(code); +// assert_eq!(errors.len(), 0); +// } + +// 17dedf +#[test] +fn test_spec_types_3() { + let code = r#" +// Declare a qubit +qubit gamma; +// Declare a qubit with a Unicode name +qubit γ; +// Declare a qubit register with 20 qubits +qubit[20] qubit_array; +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert_eq!(program.len(), 3); +} + +// 17dedf +#[test] +fn test_spec_types_4() { + let code = r#" +// Not in spec code block +include "stdgates.inc"; + +// CNOT gate between physical qubits 0 and 1 +CX $0, $1; +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert_eq!(program.len(), 1); +} + +// 17dedf +// Bug +// Incorrect syntax error recorded. +// Not supported in the semantic analysis. +// Issue #210 +#[test] +fn test_spec_types_5() { + let code = r#" +defcal h $0 { } +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert_eq!(program.len(), 0); +} + +#[test] +fn test_spec_types_6() { + let code = r#" +// Declare a register of 20 bits +bit[20] bit_array; +// Declare and assign a register of bits with decimal value of 15 +bit[8] name = "00001111"; +"#; + let (program, errors, _symbol_table) = parse_string(code); + assert!(errors.is_empty()); + assert_eq!(program.len(), 2); +}