Skip to content

Commit 1287d30

Browse files
Circuit Editor (#2238)
This PR adds a custom editor view in the VS Code extension for files with the .qsc extension. The editor makes use of the same library code that is used to draw circuit diagrams elsewhere in the VS Code extension. The editor provides basic drag-and-drop editing of circuits with a simple gate set, including the ability to have controlled gates, and gates with arguments. The circuit files are included in Q# projects and can be called into from Q# as if they were Q# operations. This is done by generating Q# files for circuit files when compiling. --------- Co-authored-by: Mine Starks <[email protected]> Co-authored-by: Mine Starks <[email protected]>
1 parent c115078 commit 1287d30

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+7089
-1151
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/qsc/src/compile.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ pub enum ErrorKind {
3737
#[error("Cycle in dependency graph")]
3838
/// `DependencyCycle` occurs when there is a cycle in the dependency graph.
3939
DependencyCycle,
40+
41+
#[error("{0}")]
42+
/// `CircuitParse` variant represents errors that occur while parsing circuit files.
43+
CircuitParse(String),
4044
}
4145

4246
/// Compiles a package from its AST representation.

compiler/qsc/src/interpret/circuit_tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ fn custom_intrinsic_mixed_args() {
512512
"]]
513513
.assert_eq(&circ.to_string());
514514

515-
assert_eq!(circ.operations.len(), 1);
515+
assert_eq!(circ.component_grid.len(), 1);
516+
assert_eq!(circ.component_grid[0].components.len(), 1);
516517
}
517518

518519
#[test]

compiler/qsc/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ pub mod linter {
6464
pub use qsc_doc_gen::{display, generate_docs};
6565

6666
pub mod circuit {
67-
pub use qsc_circuit::{operations::*, Circuit, Operation};
67+
pub use qsc_circuit::{
68+
circuit_to_qsharp::circuits_to_qsharp, json_to_circuit::json_to_circuits, operations::*,
69+
Circuit, CircuitGroup, Operation, CURRENT_VERSION,
70+
};
6871
}
6972

7073
pub mod parse {

compiler/qsc/src/packages.rs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
// Licensed under the MIT License.
33

44
use crate::{
5-
compile::{self, ErrorKind},
5+
compile::{self, Error, ErrorKind},
66
hir::PackageId,
77
PackageStore, TargetCapabilityFlags,
88
};
9+
use qsc_circuit::circuit_to_qsharp::circuits_to_qsharp;
910
use qsc_data_structures::language_features::LanguageFeatures;
1011
use qsc_frontend::compile::SourceMap;
1112
use qsc_passes::PackageType;
@@ -36,6 +37,44 @@ impl BuildableProgram {
3637
}
3738
}
3839

40+
/// Converts circuit files to Q# source code.
41+
fn convert_circuit_sources(
42+
sources: Vec<(Arc<str>, Arc<str>)>,
43+
errors: &mut Vec<Error>,
44+
) -> Vec<(Arc<str>, Arc<str>)> {
45+
let mut processed_sources: Vec<(Arc<str>, Arc<str>)> = Vec::new();
46+
47+
for (name, content) in sources {
48+
let name_path = std::path::Path::new(name.as_ref());
49+
50+
// Check if the file extension is "qsc"
51+
if name_path.extension().and_then(|ext| ext.to_str()) == Some("qsc") {
52+
let file_stem = name_path
53+
.file_stem()
54+
.and_then(|stem| stem.to_str())
55+
.unwrap_or(name.as_ref());
56+
57+
// Convert circuit files to Q# source code
58+
match circuits_to_qsharp(file_stem, content.as_ref()) {
59+
Ok(transformed_content) => {
60+
processed_sources.push((name, Arc::from(transformed_content)));
61+
}
62+
Err(error_message) => {
63+
errors.push(Error::from_map(
64+
&SourceMap::default(),
65+
ErrorKind::CircuitParse(error_message),
66+
));
67+
}
68+
}
69+
} else {
70+
// Leave other files unchanged
71+
processed_sources.push((name, content));
72+
}
73+
}
74+
75+
processed_sources
76+
}
77+
3978
/// Given a program config, prepare the package store by compiling all dependencies in the correct order and inserting them.
4079
#[must_use]
4180
pub fn prepare_package_store(
@@ -54,16 +93,16 @@ pub fn prepare_package_store(
5493
} else {
5594
// If there was a cycle in the dependencies, we treat the compilation as if
5695
// there were no dependencies, and report the error upwards
57-
dependency_errors.push(qsc_frontend::error::WithSource::from_map(
96+
dependency_errors.push(Error::from_map(
5897
&SourceMap::default(),
5998
ErrorKind::DependencyCycle,
6099
));
61100
vec![]
62101
};
63102

64103
for (package_name, package_to_compile) in ordered_packages {
65-
let sources: Vec<(Arc<str>, Arc<str>)> =
66-
package_to_compile.sources.into_iter().collect::<Vec<_>>();
104+
let sources = convert_circuit_sources(package_to_compile.sources, &mut dependency_errors);
105+
67106
let source_map = SourceMap::new(sources, None);
68107
let dependencies = package_to_compile
69108
.dependencies
@@ -97,6 +136,16 @@ pub fn prepare_package_store(
97136
canonical_package_identifier_to_package_id_mapping.insert(package_name, package_id);
98137
}
99138

139+
// Convert circuit files in user code to generated Q#
140+
let converted_user_code_sources =
141+
convert_circuit_sources(user_code.sources, &mut dependency_errors);
142+
let user_code = qsc_project::PackageInfo {
143+
sources: converted_user_code_sources,
144+
language_features: user_code.language_features,
145+
dependencies: user_code.dependencies,
146+
package_type: user_code.package_type,
147+
};
148+
100149
let user_code_dependencies = user_code
101150
.dependencies
102151
.iter()

compiler/qsc_circuit/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ qsc_data_structures = { path = "../qsc_data_structures" }
1919
qsc_frontend = { path = "../qsc_frontend" }
2020
qsc_fir = { path = "../qsc_fir" }
2121
qsc_hir = { path = "../qsc_hir" }
22+
regex-lite = { workspace = true }
2223
rustc-hash = { workspace = true }
2324
serde = { workspace = true, features = ["derive"] }
2425
serde_json = { workspace = true }
@@ -29,5 +30,8 @@ expect-test = { workspace = true }
2930
indoc = { workspace = true }
3031
qsc_passes = { path = "../qsc_passes" }
3132

33+
[lints]
34+
workspace = true
35+
3236
[lib]
3337
doctest = false

0 commit comments

Comments
 (0)