3.6 KiB
3.6 KiB
Task 4 — CircuitAnalyzer (AST-based gate listing)
Goal
Expose AST-based gate enumeration as a public utility so explain_result (Task 8) and any other consumer can iterate gates without re-parsing or string-matching the QASM source. Wraps the AST traversal already present in executor::extract_gate_ops.
Prerequisites
- Task 0 merged.
Files
- Create:
src/circuit_analyzer.rs - Modify:
src/executor.rs(add publiclist_gate_calls) - Modify:
src/lib.rs
Steps
- Step 1: Create
src/circuit_analyzer.rswith failing tests
//! Pure AST-based gate listing for OpenQASM 3.0 circuits.
use crate::error::BridgeError;
use crate::types::CircuitSource;
#[derive(Debug, Clone, PartialEq)]
pub struct GateCallInfo {
pub name: String,
pub params: Vec<f64>,
pub qubits: Vec<usize>,
}
pub struct CircuitAnalyzer;
impl CircuitAnalyzer {
pub fn list_gates(source: &CircuitSource) -> Result<Vec<GateCallInfo>, BridgeError> {
crate::executor::list_gate_calls(source)
}
}
#[cfg(test)]
mod tests {
use super::*;
const BELL: &str = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;";
#[test]
fn list_gates_for_bell_returns_h_then_cx() {
let gates = CircuitAnalyzer::list_gates(&CircuitSource(BELL.into())).unwrap();
assert_eq!(gates.len(), 2);
assert_eq!(gates[0].name, "h");
assert_eq!(gates[0].qubits, vec![0]);
assert_eq!(gates[1].name, "cx");
assert_eq!(gates[1].qubits, vec![0, 1]);
}
#[test]
fn list_gates_ignores_measure() {
let gates = CircuitAnalyzer::list_gates(&CircuitSource(BELL.into())).unwrap();
assert!(gates.iter().all(|g| g.name != "measure"));
}
#[test]
fn list_gates_returns_empty_for_circuit_with_no_gates() {
let identity = "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[1] q;\nbit[1] c;\nc = measure q;";
let gates = CircuitAnalyzer::list_gates(&CircuitSource(identity.into())).unwrap();
assert!(gates.is_empty());
}
}
- Step 2: Expose
list_gate_callsinsrc/executor.rs
Add the public function near the existing extract_gate_ops helper (or below it). Reuses the same parser path as LocalSimulator::run.
use crate::circuit_analyzer::GateCallInfo;
/// Public AST-based gate enumeration. Reuses the parser path of `run`.
pub fn list_gate_calls(source: &CircuitSource) -> Result<Vec<GateCallInfo>, BridgeError> {
let parse_result = parse_source_string(&source.0, Some("circuit.qasm"), None::<&[&str]>);
if parse_result.any_syntax_errors() {
return Err(BridgeError::Simulation("circuit contains syntax errors".into()));
}
let context = parse_result.take_context();
let symbol_table = context.symbol_table();
let program = context.program();
let (_, register_offsets) = build_register_map(program, symbol_table);
let ops = extract_gate_ops(program, symbol_table, ®ister_offsets)?;
Ok(ops
.into_iter()
.map(|(name, params, qubits)| GateCallInfo { name, params, qubits })
.collect())
}
- Step 3: Register
circuit_analyzerinsrc/lib.rs
pub mod circuit_analyzer;
- Step 4: Run tests
cargo test circuit_analyzer::tests 2>&1 | grep -E "test result|FAILED"
Expected: test result: ok. 3 passed.
- Step 5: Commit
git add src/circuit_analyzer.rs src/executor.rs src/lib.rs
git commit -m "feat: add CircuitAnalyzer for AST-based gate enumeration"