From 9dfb97ef45c8473c9b77e9b89242257bd418048d Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 17 Jan 2024 16:45:01 -0800 Subject: [PATCH 01/74] basic spike with dummy format rule --- language_service/src/format.rs | 33 ++++++++++++++++++++ language_service/src/lib.rs | 9 +++++- language_service/src/protocol.rs | 6 ++++ npm/src/language-service/language-service.ts | 19 +++++++++++ npm/src/language-service/worker-proxy.ts | 1 + vscode/src/extension.ts | 9 ++++++ vscode/src/format.ts | 30 ++++++++++++++++++ wasm/src/language_service.rs | 17 ++++++++++ 8 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 language_service/src/format.rs create mode 100644 vscode/src/format.ts diff --git a/language_service/src/format.rs b/language_service/src/format.rs new file mode 100644 index 0000000000..93b606c7c0 --- /dev/null +++ b/language_service/src/format.rs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::{ + compilation::Compilation, + protocol::{Span, TextEdit}, +}; + +pub(crate) fn get_format_changes( + compilation: &Compilation, + source_name: &str, + offset: u32, +) -> Vec { + let contents = compilation + .user_unit() + .sources + .find_by_name(source_name) + .expect("can't find source by name") + .contents + .clone(); + + let mut edits = vec![]; + + // This is a dummy format rule + if !contents.starts_with("42") { + edits.push(TextEdit { + contents: "42\n".to_string(), + span: Span { start: 0, end: 0 }, + }) + } + + edits +} diff --git a/language_service/src/lib.rs b/language_service/src/lib.rs index 67d8f85a1d..029235ab1d 100644 --- a/language_service/src/lib.rs +++ b/language_service/src/lib.rs @@ -8,6 +8,7 @@ mod compilation; pub mod completion; pub mod definition; mod display; +pub mod format; pub mod hover; mod name_locator; mod project_system; @@ -27,7 +28,7 @@ use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use futures_util::StreamExt; use log::{trace, warn}; use protocol::{ - CompletionList, DiagnosticUpdate, Hover, Location, NotebookMetadata, SignatureHelp, + CompletionList, DiagnosticUpdate, Hover, Location, NotebookMetadata, SignatureHelp, TextEdit, WorkspaceConfigurationUpdate, }; use qsc_project::JSFileEntry; @@ -195,6 +196,12 @@ impl LanguageService { ) } + /// LSP: textDocument/format + #[must_use] + pub fn get_format_changes(&self, uri: &str) -> Vec { + self.document_op(format::get_format_changes, "get_format_changes", uri, 0) + } + /// LSP: textDocument/hover #[must_use] pub fn get_hover(&self, uri: &str, offset: u32) -> Option { diff --git a/language_service/src/protocol.rs b/language_service/src/protocol.rs index c0e36e2d38..ac9bda9468 100644 --- a/language_service/src/protocol.rs +++ b/language_service/src/protocol.rs @@ -104,6 +104,12 @@ pub struct Hover { pub span: Span, } +#[derive(Debug, PartialEq)] +pub struct TextEdit { + pub contents: String, + pub span: Span, +} + #[derive(Debug, PartialEq)] pub struct SignatureHelp { pub signatures: Vec, diff --git a/npm/src/language-service/language-service.ts b/npm/src/language-service/language-service.ts index 953fbe8a88..1048b63fd4 100644 --- a/npm/src/language-service/language-service.ts +++ b/npm/src/language-service/language-service.ts @@ -52,6 +52,7 @@ export interface ILanguageService { closeDocument(uri: string): Promise; closeNotebookDocument(notebookUri: string): Promise; getCompletions(documentUri: string, offset: number): Promise; + getFormatChanges(documentUri: string): Promise; getHover(documentUri: string, offset: number): Promise; getDefinition( documentUri: string, @@ -207,6 +208,24 @@ export class QSharpLanguageService implements ILanguageService { return result; } + async getFormatChanges(documentUri: string): Promise { + const code = await this.loadFile(documentUri); + + if (code === null) { + log.error( + `getFormatChanges: expected ${documentUri} to be in the document map`, + ); + return []; + } + const results = this.languageService.get_format_changes(documentUri); + if (results && results.length > 0) { + for (const result of results) { + updateSpanFromUtf8ToUtf16(result.range, code); + } + } + return results; + } + async getHover( documentUri: string, offset: number, diff --git a/npm/src/language-service/worker-proxy.ts b/npm/src/language-service/worker-proxy.ts index 5f0b4e93ec..567360d435 100644 --- a/npm/src/language-service/worker-proxy.ts +++ b/npm/src/language-service/worker-proxy.ts @@ -18,6 +18,7 @@ const requests: MethodMap = { closeDocument: "request", closeNotebookDocument: "request", getCompletions: "request", + getFormatChanges: "request", getHover: "request", getDefinition: "request", getReferences: "request", diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts index e9d3be317a..9e7449ed39 100644 --- a/vscode/src/extension.ts +++ b/vscode/src/extension.ts @@ -41,6 +41,7 @@ import { createReferenceProvider } from "./references.js"; import { activateTargetProfileStatusBarItem } from "./statusbar.js"; import { initFileSystem } from "./memfs.js"; import { getManifest, readFile, listDir } from "./projectSystem.js"; +import { createFormatProvider } from "./format.js"; export async function activate(context: vscode.ExtensionContext) { initializeLogger(); @@ -188,6 +189,14 @@ async function activateLanguageService(extensionUri: vscode.Uri) { ), ); + // format document + subscriptions.push( + vscode.languages.registerDocumentFormattingEditProvider( + qsharpLanguageId, + createFormatProvider(languageService), + ), + ); + // hover subscriptions.push( vscode.languages.registerHoverProvider( diff --git a/vscode/src/format.ts b/vscode/src/format.ts new file mode 100644 index 0000000000..88204bf377 --- /dev/null +++ b/vscode/src/format.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { ILanguageService } from "qsharp-lang"; +import * as vscode from "vscode"; + +export function createFormatProvider(languageService: ILanguageService) { + return new QSharpFormatProvider(languageService); +} + +class QSharpFormatProvider implements vscode.DocumentFormattingEditProvider { + constructor(public languageService: ILanguageService) {} + + async provideDocumentFormattingEdits(document: vscode.TextDocument) { + const lsEdits = await this.languageService.getFormatChanges( + document.uri.toString(), + ); + + if (!lsEdits) return []; + const edits = []; + for (const edit of lsEdits) { + const referenceRange = new vscode.Range( + document.positionAt(edit.range.start), + document.positionAt(edit.range.end), + ); + edits.push(new vscode.TextEdit(referenceRange, edit.newText)); + } + return edits; + } +} diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs index 97f605c2b9..db0df52392 100644 --- a/wasm/src/language_service.rs +++ b/wasm/src/language_service.rs @@ -208,6 +208,23 @@ impl LanguageService { .collect() } + pub fn get_format_changes(&self, uri: &str) -> Vec { + let edits = self.0.get_format_changes(uri); + edits + .into_iter() + .map(|edit| { + TextEdit { + range: Span { + start: edit.span.start, + end: edit.span.end, + }, + newText: edit.contents, + } + .into() + }) + .collect() + } + pub fn get_hover(&self, uri: &str, offset: u32) -> Option { let hover = self.0.get_hover(uri, offset); hover.map(|hover| { From b368196050b330b3d2fda536ec26be87a84cc7f4 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 30 Jan 2024 11:20:09 -0800 Subject: [PATCH 02/74] expose raw tokens to the formatter --- compiler/qsc/src/lib.rs | 3 +++ compiler/qsc_frontend/src/lib.rs | 3 +++ compiler/qsc_parse/src/formatter.rs | 16 ++++++++++++++++ compiler/qsc_parse/src/lex.rs | 2 ++ compiler/qsc_parse/src/lex/raw.rs | 12 ++++++------ compiler/qsc_parse/src/lib.rs | 2 ++ language_service/src/format.rs | 9 ++++++++- 7 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 compiler/qsc_parse/src/formatter.rs diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs index 3d466dba66..6f7c8a38f6 100644 --- a/compiler/qsc/src/lib.rs +++ b/compiler/qsc/src/lib.rs @@ -10,6 +10,9 @@ pub mod incremental; pub mod interpret; pub mod target; +pub use qsc_frontend::formatter::Formatter; +pub use qsc_frontend::RawTokenKind; + pub use qsc_frontend::compile::{ CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName, }; diff --git a/compiler/qsc_frontend/src/lib.rs b/compiler/qsc_frontend/src/lib.rs index 24f1897812..a245869665 100644 --- a/compiler/qsc_frontend/src/lib.rs +++ b/compiler/qsc_frontend/src/lib.rs @@ -11,3 +11,6 @@ pub mod incremental; mod lower; pub mod resolve; pub mod typeck; + +pub use qsc_parse::formatter; +pub use qsc_parse::RawTokenKind; diff --git a/compiler/qsc_parse/src/formatter.rs b/compiler/qsc_parse/src/formatter.rs new file mode 100644 index 0000000000..ffc4a4d30a --- /dev/null +++ b/compiler/qsc_parse/src/formatter.rs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::lex::{RawLexer, RawToken}; + +pub struct Formatter { + pub tokens: Vec, +} + +impl Formatter { + pub fn new(input: &str) -> Self { + Self { + tokens: RawLexer::new(input).collect::>(), + } + } +} diff --git a/compiler/qsc_parse/src/lex.rs b/compiler/qsc_parse/src/lex.rs index 9c6d6721ba..cf4bbe1fb1 100644 --- a/compiler/qsc_parse/src/lex.rs +++ b/compiler/qsc_parse/src/lex.rs @@ -7,6 +7,8 @@ mod raw; use enum_iterator::Sequence; pub(super) use cooked::{ClosedBinOp, Error, Lexer, StringToken, Token, TokenKind}; +pub(super) use raw::Lexer as RawLexer; +pub use raw::{Token as RawToken, TokenKind as RawTokenKind}; /// A delimiter token. #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] diff --git a/compiler/qsc_parse/src/lex/raw.rs b/compiler/qsc_parse/src/lex/raw.rs index 26813661f9..3ab7dc63ea 100644 --- a/compiler/qsc_parse/src/lex/raw.rs +++ b/compiler/qsc_parse/src/lex/raw.rs @@ -25,15 +25,15 @@ use std::{ /// A raw token. #[derive(Clone, Debug, Eq, PartialEq)] -pub(super) struct Token { +pub struct Token { /// The token kind. - pub(super) kind: TokenKind, + pub kind: TokenKind, /// The byte offset of the token starting character. - pub(super) offset: u32, + pub offset: u32, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum TokenKind { +pub enum TokenKind { Comment(CommentKind), Ident, Number(Number), @@ -168,13 +168,13 @@ pub(crate) enum CommentKind { } #[derive(Clone)] -pub(super) struct Lexer<'a> { +pub struct Lexer<'a> { chars: Peekable>, interpolation: u8, } impl<'a> Lexer<'a> { - pub(super) fn new(input: &'a str) -> Self { + pub fn new(input: &'a str) -> Self { Self { chars: input.char_indices().peekable(), interpolation: 0, diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 834c43b065..3e38d48598 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -6,6 +6,7 @@ //! unique identifiers by a later stage. mod expr; +pub mod formatter; mod item; mod keyword; mod lex; @@ -16,6 +17,7 @@ mod stmt; mod tests; mod ty; +pub use lex::RawTokenKind; use lex::TokenKind; use miette::Diagnostic; use qsc_ast::ast::{Expr, Namespace, TopLevelNode}; diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 93b606c7c0..16afc936ef 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -6,6 +6,9 @@ use crate::{ protocol::{Span, TextEdit}, }; +use qsc::Formatter; +use qsc::RawTokenKind; + pub(crate) fn get_format_changes( compilation: &Compilation, source_name: &str, @@ -21,12 +24,16 @@ pub(crate) fn get_format_changes( let mut edits = vec![]; + let mut formatter = Formatter::new(&contents); + + for token in formatter.tokens.iter() {} + // This is a dummy format rule if !contents.starts_with("42") { edits.push(TextEdit { contents: "42\n".to_string(), span: Span { start: 0, end: 0 }, - }) + }); } edits From bf48ea3d653d7b2932410874733fc4b46f989f17 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 31 Jan 2024 11:58:33 -0800 Subject: [PATCH 03/74] Remove Trailing Whitespace --- compiler/qsc/src/lib.rs | 3 +- compiler/qsc_frontend/src/lib.rs | 3 +- compiler/qsc_parse/src/lib.rs | 2 +- language_service/src/format.rs | 50 +++++++++++++++++++++++++++----- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs index 6f7c8a38f6..52e68916f9 100644 --- a/compiler/qsc/src/lib.rs +++ b/compiler/qsc/src/lib.rs @@ -10,8 +10,7 @@ pub mod incremental; pub mod interpret; pub mod target; -pub use qsc_frontend::formatter::Formatter; -pub use qsc_frontend::RawTokenKind; +pub use qsc_frontend::{formatter, RawToken, RawTokenKind}; pub use qsc_frontend::compile::{ CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName, diff --git a/compiler/qsc_frontend/src/lib.rs b/compiler/qsc_frontend/src/lib.rs index a245869665..992f9e8513 100644 --- a/compiler/qsc_frontend/src/lib.rs +++ b/compiler/qsc_frontend/src/lib.rs @@ -12,5 +12,4 @@ mod lower; pub mod resolve; pub mod typeck; -pub use qsc_parse::formatter; -pub use qsc_parse::RawTokenKind; +pub use qsc_parse::{formatter, RawToken, RawTokenKind}; diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 3e38d48598..79ed241c37 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -17,8 +17,8 @@ mod stmt; mod tests; mod ty; -pub use lex::RawTokenKind; use lex::TokenKind; +pub use lex::{RawToken, RawTokenKind}; use miette::Diagnostic; use qsc_ast::ast::{Expr, Namespace, TopLevelNode}; use qsc_data_structures::span::Span; diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 16afc936ef..755ee605f4 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -6,8 +6,10 @@ use crate::{ protocol::{Span, TextEdit}, }; -use qsc::Formatter; +use qsc::formatter::Formatter; +use qsc::RawToken; use qsc::RawTokenKind; +use regex_lite::Regex; pub(crate) fn get_format_changes( compilation: &Compilation, @@ -24,16 +26,48 @@ pub(crate) fn get_format_changes( let mut edits = vec![]; - let mut formatter = Formatter::new(&contents); + let formatter = Formatter::new(&contents); - for token in formatter.tokens.iter() {} + edits.extend(RemoveTrailingWhitespace(&formatter.tokens, &contents)); // This is a dummy format rule - if !contents.starts_with("42") { - edits.push(TextEdit { - contents: "42\n".to_string(), - span: Span { start: 0, end: 0 }, - }); + // if !contents.starts_with("42") { + // edits.push(TextEdit { + // contents: "42\n".to_string(), + // span: Span { start: 0, end: 0 }, + // }); + // } + + edits +} + +fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { + let mut edits = vec![]; + + let trailing_spaces = Regex::new(r"(?[ \t]+)(?\n|\r\n)").unwrap(); + + for i in 0..tokens.len() { + let curr = &tokens[i]; + if matches!(curr.kind, RawTokenKind::Whitespace) { + let lo: usize = curr.offset.try_into().unwrap(); + let hi: usize = if i + 1 < tokens.len() { + let next = &tokens[i + 1]; + next.offset.try_into().unwrap() + } else { + contents.len() + }; + let text = contents.get(lo..hi).unwrap(); + for capture in trailing_spaces.captures_iter(text) { + let range = capture.name("spaces").unwrap().range(); + let length = range.len(); + let start = curr.offset + TryInto::::try_into(range.start).unwrap(); + let end = curr.offset + TryInto::::try_into(range.end).unwrap(); + edits.push(TextEdit { + contents: String::new(), + span: Span { start, end }, + }); + } + } } edits From 0ba17c25341dfa099357cae8f59bb12b1dab1a0d Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 1 Feb 2024 10:55:56 -0800 Subject: [PATCH 04/74] small change --- language_service/src/format.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 755ee605f4..2059ab6dd0 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -44,11 +44,11 @@ pub(crate) fn get_format_changes( fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { let mut edits = vec![]; - let trailing_spaces = Regex::new(r"(?[ \t]+)(?\n|\r\n)").unwrap(); + let trailing_spaces = Regex::new(r"(?[ \t]+)(?\n|(\r\n))").unwrap(); for i in 0..tokens.len() { let curr = &tokens[i]; - if matches!(curr.kind, RawTokenKind::Whitespace) { + if let RawTokenKind::Whitespace = &curr.kind { let lo: usize = curr.offset.try_into().unwrap(); let hi: usize = if i + 1 < tokens.len() { let next = &tokens[i + 1]; @@ -63,7 +63,8 @@ fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec::try_into(range.start).unwrap(); let end = curr.offset + TryInto::::try_into(range.end).unwrap(); edits.push(TextEdit { - contents: String::new(), + //contents: String::new(), + contents: "!".repeat(length), span: Span { start, end }, }); } From 97b333b5ad58fcd62b5d6f493cc47e27ba456ebb Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 1 Feb 2024 15:20:30 -0800 Subject: [PATCH 05/74] Improved to support comments --- compiler/qsc_parse/src/lex/raw.rs | 2 +- language_service/src/format.rs | 71 ++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/compiler/qsc_parse/src/lex/raw.rs b/compiler/qsc_parse/src/lex/raw.rs index 3ab7dc63ea..a35cc6fe18 100644 --- a/compiler/qsc_parse/src/lex/raw.rs +++ b/compiler/qsc_parse/src/lex/raw.rs @@ -162,7 +162,7 @@ enum StringKind { } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum CommentKind { +pub enum CommentKind { Normal, Doc, } diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 2059ab6dd0..b6da253604 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -44,30 +44,61 @@ pub(crate) fn get_format_changes( fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { let mut edits = vec![]; - let trailing_spaces = Regex::new(r"(?[ \t]+)(?\n|(\r\n))").unwrap(); + let trailing_spaces_newline = Regex::new(r"(?[ \t]+)(:?\n|\r\n)").unwrap(); + let trailing_spaces = Regex::new(r"(?[ \t]+)$").unwrap(); + let trailing_spaces_newline_or_end = Regex::new(r"(?[ \t]+)(:?\n|\r\n|$)").unwrap(); for i in 0..tokens.len() { let curr = &tokens[i]; - if let RawTokenKind::Whitespace = &curr.kind { - let lo: usize = curr.offset.try_into().unwrap(); - let hi: usize = if i + 1 < tokens.len() { - let next = &tokens[i + 1]; - next.offset.try_into().unwrap() - } else { - contents.len() - }; - let text = contents.get(lo..hi).unwrap(); - for capture in trailing_spaces.captures_iter(text) { - let range = capture.name("spaces").unwrap().range(); - let length = range.len(); - let start = curr.offset + TryInto::::try_into(range.start).unwrap(); - let end = curr.offset + TryInto::::try_into(range.end).unwrap(); - edits.push(TextEdit { - //contents: String::new(), - contents: "!".repeat(length), - span: Span { start, end }, - }); + match &curr.kind { + RawTokenKind::Comment(_) => { + let lo: usize = curr.offset.try_into().unwrap(); + let hi: usize = if i + 1 < tokens.len() { + let next = &tokens[i + 1]; + next.offset.try_into().unwrap() + } else { + contents.len() + }; + let text = contents.get(lo..hi).unwrap(); + for capture in trailing_spaces.captures_iter(text) { + let range = capture.name("spaces").unwrap().range(); + let length = range.len(); + let start = curr.offset + TryInto::::try_into(range.start).unwrap(); + let end = curr.offset + TryInto::::try_into(range.end).unwrap(); + edits.push(TextEdit { + contents: String::new(), + //contents: "!".repeat(length), + span: Span { start, end }, + }); + } } + RawTokenKind::Whitespace => { + let lo: usize = curr.offset.try_into().unwrap(); + let hi: usize = if i + 1 < tokens.len() { + let next = &tokens[i + 1]; + next.offset.try_into().unwrap() + } else { + contents.len() + }; + let text = contents.get(lo..hi).unwrap(); + let re = if i + 1 < tokens.len() { + &trailing_spaces_newline + } else { + &trailing_spaces_newline_or_end + }; + for capture in re.captures_iter(text) { + let range = capture.name("spaces").unwrap().range(); + let length = range.len(); + let start = curr.offset + TryInto::::try_into(range.start).unwrap(); + let end = curr.offset + TryInto::::try_into(range.end).unwrap(); + edits.push(TextEdit { + contents: String::new(), + //contents: "!".repeat(length), + span: Span { start, end }, + }); + } + } + _ => {} } } From c6902b257de0061a050381e5b85be7ecb9bdfb47 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 5 Feb 2024 14:56:19 -0800 Subject: [PATCH 06/74] rules are convolution over token stream --- compiler/qsc_parse/src/lex.rs | 1 + compiler/qsc_parse/src/lex/formatter.rs | 277 ++++++++++++++++++++++++ compiler/qsc_parse/src/lib.rs | 3 +- language_service/src/format.rs | 21 +- 4 files changed, 296 insertions(+), 6 deletions(-) create mode 100644 compiler/qsc_parse/src/lex/formatter.rs diff --git a/compiler/qsc_parse/src/lex.rs b/compiler/qsc_parse/src/lex.rs index cf4bbe1fb1..6a48fa0880 100644 --- a/compiler/qsc_parse/src/lex.rs +++ b/compiler/qsc_parse/src/lex.rs @@ -2,6 +2,7 @@ // Licensed under the MIT License. mod cooked; +pub mod formatter; mod raw; use enum_iterator::Sequence; diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs new file mode 100644 index 0000000000..abae192bfb --- /dev/null +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -0,0 +1,277 @@ +use std::iter::Peekable; + +use super::{ + raw::{Lexer, Single, TokenKind}, + Delim, +}; +use qsc_data_structures::span::Span; + +#[derive(Debug)] +pub struct Edit { + #[allow(dead_code)] // TODO: nobody's using this yet except for tests + pub span: Span, + #[allow(dead_code)] // TODO: nobody's using this yet except for tests + pub new_text: String, +} + +fn make_indent_string(level: usize) -> String { + " ".repeat(level) +} + +#[derive(Clone, Copy)] +struct SpannedToken { + pub kind: TokenKind, + pub span: Span, +} + +struct SpannedTokenIterator<'a> { + code: &'a str, + tokens: Peekable>, +} + +impl<'a> SpannedTokenIterator<'a> { + fn new(code: &'a str) -> Self { + Self { + code, + tokens: Lexer::new(code).peekable(), + } + } +} + +impl Iterator for SpannedTokenIterator<'_> { + type Item = SpannedToken; + + fn next(&mut self) -> Option { + let token = self.tokens.next()?; + let next = self.tokens.peek(); + Some(SpannedToken { + kind: token.kind, + span: Span { + lo: token.offset, + hi: next + .map(|t| t.offset) + .unwrap_or_else(|| self.code.len() as u32), + }, + }) + } +} + +pub fn format(code: &str) -> Vec { + let tokens = SpannedTokenIterator::new(code); + let mut edits = vec![]; + + let mut indent_level = 0; + + #[allow(unused_assignments)] // there's probably a better way of doing this, but this works + let mut one = None; + let mut two = None; + let mut three = None; + + for token in tokens { + // Advance the trio of tokens + one = two; + two = three; + three = Some(token); + + let mut edits_for_triple = match (one, two, three) { + (Some(one), Some(two), Some(three)) => { + // if the token is a {, increase the indent level + if one.kind == TokenKind::Single(Single::Open(Delim::Brace)) { + indent_level += 1; + } + // if the token is a }, decrease the indent level + if one.kind == TokenKind::Single(Single::Close(Delim::Brace)) { + indent_level -= 1; + } + + if one.kind == TokenKind::Whitespace { + // first token is whitespace, continue scanning + continue; + } else if two.kind == TokenKind::Whitespace { + // whitespace in the middle + apply_rule( + one, + &code[two.span.lo as usize..two.span.hi as usize], + three, + code, + indent_level, + ) + } else { + // one, two are adjacent tokens with no whitespace in the middle + apply_rule(one, "", two, code, indent_level) + } + } + _ => { + // not enough tokens to apply a rule + // TODO: we'll probably need to handle end-of-file cases here + continue; + } + }; + + edits.append(&mut edits_for_triple); + } + + edits +} + +fn fix_whitespace(whitespace: &str, indent_level: usize) -> String { + // + // when you see newline, insert the indent string + // and trim until the next newline or the end of the string + // + + let count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); + let mut new = "\n".repeat(count_newlines); + new.push_str(&make_indent_string(indent_level)); + new +} + +fn apply_rule( + left: SpannedToken, + whitespace: &str, + right: SpannedToken, + code: &str, + indent_level: usize, +) -> Vec { + let mut edits = vec![]; + // when we get here, neither left nor right should be whitespace + + // some comment + + // some other comment + // operation Foo() : Unit {} + + match (left.kind, right.kind) { + (TokenKind::Comment(_), _) => { + // fix indentation + // and fix trailing spaces on the left comment + let comment_contents = get_token_contents(code, left); + let new_comment_contents = comment_contents.trim_end(); + if comment_contents != new_comment_contents { + edits.push(Edit { + span: left.span, + new_text: new_comment_contents.to_string(), + }); + } + + // if the middle whitespace contains a new line, we need to + // fix the indentation + let new_whitespace = fix_whitespace(whitespace, indent_level); + if whitespace != new_whitespace { + edits.push(Edit { + span: Span { + lo: left.span.hi, + hi: right.span.lo, + }, + new_text: new_whitespace.to_string(), + }); + } + } + (TokenKind::Ident, TokenKind::Ident) + //| (TokenKind::Single(Single::Colon), TokenKind::Ident) + //| (TokenKind::Ident, TokenKind::Single(_)) + => { + // Put exactly one space in the middle + let old_whitespace = whitespace; + let new_whitespace = " "; + if old_whitespace != new_whitespace { + edits.push(Edit { + span: Span { + lo: left.span.hi, + hi: right.span.lo, + }, + new_text: new_whitespace.to_string(), + }); + } + } + _ => {} + } + + println!( + "edits for `{}` : {edits:?}", + &code[left.span.lo as usize..right.span.hi as usize] + ); + edits +} + +fn get_token_contents(code: &str, left: SpannedToken) -> &str { + &code[left.span.lo as usize..left.span.hi as usize] +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + #[test] + fn test_formatting() { + let code = "operation Foo ()"; + let edits = super::format(code); + expect![[r#" + [ + Edit { + span: Span { + lo: 9, + hi: 12, + }, + new_text: " ", + }, + Edit { + span: Span { + lo: 15, + hi: 18, + }, + new_text: " ", + }, + ] + "#]] + .assert_debug_eq(&edits); + } + + #[test] + fn test_formatting_2() { + let code = "/// # Sample + /// Joint Measurement + /// + /// # Description + /// Joint measurements, also known as Pauli measurements, are a generalization + /// of 2-outcome measurements to multiple qubits and other bases. + namespace Sample { + open Microsoft.Quantum.Diagnostics; + + @EntryPoint() + operation Main() : (Result, Result[]) { + // Prepare an entangled state. + use qs = Qubit[2]; // |00〉 + H(qs[0]); // 1/sqrt(2)(|00〉 + |10〉) + CNOT(qs[0], qs[1]); // 1/sqrt(2)(|00〉 + |11〉) + + // Show the quantum state before performing the joint measurement. + DumpMachine(); + + // The below code uses a joint measurement as a way to check the parity + // of the first two qubits. In this case, the parity measurement result + // will always be `Zero`. + // Notice how the state was not collapsed by the joint measurement. + let parityResult = Measure([PauliZ, PauliZ], qs[...1]); + DumpMachine(); + + // However, if we perform a measurement just on the first qubit, we can + // see how the state collapses. + let firstQubitResult = M(qs[0]); + DumpMachine(); + + // Measuring the last qubit does not change the quantum state + // since the state of the second qubit collapsed when the first qubit + // was measured because they were entangled. + let secondQubitResult = M(qs[1]); + DumpMachine(); + + ResetAll(qs); + return (parityResult, [firstQubitResult, secondQubitResult]); + } + } + "; + let edits = super::format(code); + expect![[r#""#]].assert_debug_eq(&edits); + } +} diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 79ed241c37..7c0f472ef1 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -6,7 +6,7 @@ //! unique identifiers by a later stage. mod expr; -pub mod formatter; +//pub mod formatter; mod item; mod keyword; mod lex; @@ -17,6 +17,7 @@ mod stmt; mod tests; mod ty; +pub use lex::formatter; use lex::TokenKind; pub use lex::{RawToken, RawTokenKind}; use miette::Diagnostic; diff --git a/language_service/src/format.rs b/language_service/src/format.rs index b6da253604..e532132987 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -6,7 +6,7 @@ use crate::{ protocol::{Span, TextEdit}, }; -use qsc::formatter::Formatter; +use qsc::formatter::{format, Edit}; use qsc::RawToken; use qsc::RawTokenKind; use regex_lite::Regex; @@ -24,11 +24,22 @@ pub(crate) fn get_format_changes( .contents .clone(); - let mut edits = vec![]; + //let mut edits = vec![]; + + //let formatter = Formatter::new(&contents); - let formatter = Formatter::new(&contents); + format(&contents) + .iter() + .map(|edit| TextEdit { + contents: edit.new_text.clone(), + span: Span { + start: edit.span.lo, + end: edit.span.hi, + }, + }) + .collect() - edits.extend(RemoveTrailingWhitespace(&formatter.tokens, &contents)); + //let temp = edits.extend(RemoveTrailingWhitespace(&formatter.tokens, &contents)); // This is a dummy format rule // if !contents.starts_with("42") { @@ -38,7 +49,7 @@ pub(crate) fn get_format_changes( // }); // } - edits + //edits } fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { From e31e583e614a60ea88df517bb453eb0d8f1c4f37 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 7 Feb 2024 15:50:17 -0800 Subject: [PATCH 07/74] added concrete tokens --- compiler/qsc_parse/src/lex.rs | 1 + compiler/qsc_parse/src/lex/concrete.rs | 90 ++++++++++++++++++++++++++ compiler/qsc_parse/src/lex/cooked.rs | 9 +++ 3 files changed, 100 insertions(+) create mode 100644 compiler/qsc_parse/src/lex/concrete.rs diff --git a/compiler/qsc_parse/src/lex.rs b/compiler/qsc_parse/src/lex.rs index 6a48fa0880..2fc23681c3 100644 --- a/compiler/qsc_parse/src/lex.rs +++ b/compiler/qsc_parse/src/lex.rs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +mod concrete; mod cooked; pub mod formatter; mod raw; diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs new file mode 100644 index 0000000000..fb1cd6f501 --- /dev/null +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use std::iter::Peekable; + +use qsc_data_structures::span::Span; + +use super::{cooked, raw}; + +enum ConcreteToken { + Cooked(cooked::Token), + Error(cooked::Error), + WhiteSpace(Span), + Comment(Span), +} + +struct ConcreteTokenIterator<'a> { + code: &'a str, + cooked_tokens: Peekable>, + non_compilation_tokens: Peekable>, +} + +impl<'a> ConcreteTokenIterator<'a> { + fn new(code: &'a str) -> Self { + Self { + code, + cooked_tokens: cooked::Lexer::new(code).peekable(), + non_compilation_tokens: raw::Lexer::new("").peekable(), + } + } + + fn get_tokens_from_span(&mut self, lo: u32, hi: u32) { + let lo = lo as usize; + let hi = hi as usize; + if let Some(slice) = self.code.get(lo..hi) { + self.non_compilation_tokens = raw::Lexer::new(slice).peekable(); + } + } + + fn get_next_lo(&mut self) -> u32 { + match self.non_compilation_tokens.peek() { + Some(next) => next.offset, + None => match self.cooked_tokens.peek() { + Some(next) => match next { + Ok(next) => next.span.lo, + Err(err) => err.get_span().lo, + }, + None => self + .code + .len() + .try_into() + .expect("expected length of code to fit into u32"), + }, + } + } +} + +impl Iterator for ConcreteTokenIterator<'_> { + type Item = ConcreteToken; + + fn next(&mut self) -> Option { + match self.non_compilation_tokens.next() { + Some(raw_token) => { + let next_lo = self.get_next_lo(); + let span = Span { + lo: raw_token.offset, + hi: next_lo, + }; + let concrete = match raw_token.kind { + crate::RawTokenKind::Comment(_) => ConcreteToken::Comment(span), + crate::RawTokenKind::Whitespace => ConcreteToken::WhiteSpace(span), + _ => panic!("only comments and whitespace should be non-compilable tokens"), // Todo: might need better handling + }; + Some(concrete) + } + None => match self.cooked_tokens.next()? { + Ok(token) => { + let next_lo = self.get_next_lo(); + self.get_tokens_from_span(token.span.hi, next_lo); + Some(ConcreteToken::Cooked(token)) + } + Err(err) => { + let next_lo = self.get_next_lo(); + self.get_tokens_from_span(err.get_span().hi, next_lo); + Some(ConcreteToken::Error(err)) + } + }, + } + } +} diff --git a/compiler/qsc_parse/src/lex/cooked.rs b/compiler/qsc_parse/src/lex/cooked.rs index 4cc0c9e41a..b41b1cc561 100644 --- a/compiler/qsc_parse/src/lex/cooked.rs +++ b/compiler/qsc_parse/src/lex/cooked.rs @@ -66,6 +66,15 @@ impl Error { Self::Unknown(c, span) => Self::Unknown(c, span + offset), } } + + pub(crate) fn get_span(self) -> Span { + match self { + Error::Incomplete(_, _, _, s) + | Error::IncompleteEof(_, _, s) + | Error::UnterminatedString(s) + | Error::Unknown(_, s) => s, + } + } } /// A token kind. From 33e74ce9b04f2f3aec9fb0781b1d927860c28582 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 16 Feb 2024 11:33:06 -0800 Subject: [PATCH 08/74] . --- compiler/qsc_parse/src/lib.rs | 2 +- language_service/src/format.rs | 146 ++++++++++++++++--------------- language_service/src/lib.rs | 10 ++- language_service/src/protocol.rs | 2 +- 4 files changed, 86 insertions(+), 74 deletions(-) diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 7c0f472ef1..09043d9a49 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -6,7 +6,7 @@ //! unique identifiers by a later stage. mod expr; -//pub mod formatter; +pub mod formatter; mod item; mod keyword; mod lex; diff --git a/language_service/src/format.rs b/language_service/src/format.rs index e532132987..65c5ac753d 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -1,20 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use crate::{ - compilation::Compilation, - protocol::{Span, TextEdit}, -}; +use crate::{compilation::Compilation, protocol::TextEdit}; use qsc::formatter::{format, Edit}; -use qsc::RawToken; -use qsc::RawTokenKind; -use regex_lite::Regex; +use qsc::line_column::{Encoding, Range}; +use qsc::Span; +//use qsc::RawToken; +//use qsc::RawTokenKind; +//use regex_lite::Regex; pub(crate) fn get_format_changes( compilation: &Compilation, source_name: &str, offset: u32, + encoding: Encoding, ) -> Vec { let contents = compilation .user_unit() @@ -32,10 +32,14 @@ pub(crate) fn get_format_changes( .iter() .map(|edit| TextEdit { contents: edit.new_text.clone(), - span: Span { - start: edit.span.lo, - end: edit.span.hi, - }, + span: Range::from_span( + encoding, + &contents, + &Span { + start: edit.span.lo, + end: edit.span.hi, + }, + ), }) .collect() @@ -52,66 +56,66 @@ pub(crate) fn get_format_changes( //edits } -fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { - let mut edits = vec![]; +// fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { +// let mut edits = vec![]; - let trailing_spaces_newline = Regex::new(r"(?[ \t]+)(:?\n|\r\n)").unwrap(); - let trailing_spaces = Regex::new(r"(?[ \t]+)$").unwrap(); - let trailing_spaces_newline_or_end = Regex::new(r"(?[ \t]+)(:?\n|\r\n|$)").unwrap(); +// let trailing_spaces_newline = Regex::new(r"(?[ \t]+)(:?\n|\r\n)").unwrap(); +// let trailing_spaces = Regex::new(r"(?[ \t]+)$").unwrap(); +// let trailing_spaces_newline_or_end = Regex::new(r"(?[ \t]+)(:?\n|\r\n|$)").unwrap(); - for i in 0..tokens.len() { - let curr = &tokens[i]; - match &curr.kind { - RawTokenKind::Comment(_) => { - let lo: usize = curr.offset.try_into().unwrap(); - let hi: usize = if i + 1 < tokens.len() { - let next = &tokens[i + 1]; - next.offset.try_into().unwrap() - } else { - contents.len() - }; - let text = contents.get(lo..hi).unwrap(); - for capture in trailing_spaces.captures_iter(text) { - let range = capture.name("spaces").unwrap().range(); - let length = range.len(); - let start = curr.offset + TryInto::::try_into(range.start).unwrap(); - let end = curr.offset + TryInto::::try_into(range.end).unwrap(); - edits.push(TextEdit { - contents: String::new(), - //contents: "!".repeat(length), - span: Span { start, end }, - }); - } - } - RawTokenKind::Whitespace => { - let lo: usize = curr.offset.try_into().unwrap(); - let hi: usize = if i + 1 < tokens.len() { - let next = &tokens[i + 1]; - next.offset.try_into().unwrap() - } else { - contents.len() - }; - let text = contents.get(lo..hi).unwrap(); - let re = if i + 1 < tokens.len() { - &trailing_spaces_newline - } else { - &trailing_spaces_newline_or_end - }; - for capture in re.captures_iter(text) { - let range = capture.name("spaces").unwrap().range(); - let length = range.len(); - let start = curr.offset + TryInto::::try_into(range.start).unwrap(); - let end = curr.offset + TryInto::::try_into(range.end).unwrap(); - edits.push(TextEdit { - contents: String::new(), - //contents: "!".repeat(length), - span: Span { start, end }, - }); - } - } - _ => {} - } - } +// for i in 0..tokens.len() { +// let curr = &tokens[i]; +// match &curr.kind { +// RawTokenKind::Comment(_) => { +// let lo: usize = curr.offset.try_into().unwrap(); +// let hi: usize = if i + 1 < tokens.len() { +// let next = &tokens[i + 1]; +// next.offset.try_into().unwrap() +// } else { +// contents.len() +// }; +// let text = contents.get(lo..hi).unwrap(); +// for capture in trailing_spaces.captures_iter(text) { +// let range = capture.name("spaces").unwrap().range(); +// let length = range.len(); +// let start = curr.offset + TryInto::::try_into(range.start).unwrap(); +// let end = curr.offset + TryInto::::try_into(range.end).unwrap(); +// edits.push(TextEdit { +// contents: String::new(), +// //contents: "!".repeat(length), +// span: Span { start, end }, +// }); +// } +// } +// RawTokenKind::Whitespace => { +// let lo: usize = curr.offset.try_into().unwrap(); +// let hi: usize = if i + 1 < tokens.len() { +// let next = &tokens[i + 1]; +// next.offset.try_into().unwrap() +// } else { +// contents.len() +// }; +// let text = contents.get(lo..hi).unwrap(); +// let re = if i + 1 < tokens.len() { +// &trailing_spaces_newline +// } else { +// &trailing_spaces_newline_or_end +// }; +// for capture in re.captures_iter(text) { +// let range = capture.name("spaces").unwrap().range(); +// let length = range.len(); +// let start = curr.offset + TryInto::::try_into(range.start).unwrap(); +// let end = curr.offset + TryInto::::try_into(range.end).unwrap(); +// edits.push(TextEdit { +// contents: String::new(), +// //contents: "!".repeat(length), +// span: Span { start, end }, +// }); +// } +// } +// _ => {} +// } +// } - edits -} +// edits +// } diff --git a/language_service/src/lib.rs b/language_service/src/lib.rs index 4fc8352939..47e11d7b9b 100644 --- a/language_service/src/lib.rs +++ b/language_service/src/lib.rs @@ -7,6 +7,7 @@ mod compilation; pub mod completion; pub mod definition; +pub mod format; pub mod hover; mod name_locator; mod project_system; @@ -35,7 +36,14 @@ use qsc::{ }; use qsc_project::JSFileEntry; use state::{CompilationState, CompilationStateUpdater}; -use std::{cell::RefCell, fmt::Debug, future::Future, pin::Pin, rc::Rc, sync::Arc}; +use std::{ + cell::RefCell, + fmt::{format, Debug}, + future::Future, + pin::Pin, + rc::Rc, + sync::Arc, +}; pub struct LanguageService { /// All [`Position`]s and [`Range`]s will be mapped using this encoding. diff --git a/language_service/src/protocol.rs b/language_service/src/protocol.rs index 22b6f21e23..3773b14a7e 100644 --- a/language_service/src/protocol.rs +++ b/language_service/src/protocol.rs @@ -95,7 +95,7 @@ pub struct Hover { #[derive(Debug, PartialEq)] pub struct TextEdit { pub contents: String, - pub span: Span, + pub span: Range, } #[derive(Debug, PartialEq)] From 94e30b747ef075e4970e3b6019c67d5ed24c87aa Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 16 Feb 2024 12:00:37 -0800 Subject: [PATCH 09/74] remove stuff that doesn't build --- compiler/qsc/src/lib.rs | 2 - compiler/qsc_frontend/src/lib.rs | 2 - compiler/qsc_parse/src/lex.rs | 4 -- compiler/qsc_parse/src/lib.rs | 3 -- language_service/src/format.rs | 40 ++++++++++---------- language_service/src/lib.rs | 7 +++- npm/src/language-service/language-service.ts | 16 +------- vscode/src/format.ts | 6 +-- wasm/src/language_service.rs | 13 +++++-- 9 files changed, 39 insertions(+), 54 deletions(-) diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs index 1b4c5b7447..a3d0808642 100644 --- a/compiler/qsc/src/lib.rs +++ b/compiler/qsc/src/lib.rs @@ -11,8 +11,6 @@ pub mod interpret; pub mod location; pub mod target; -pub use qsc_frontend::{formatter, RawToken, RawTokenKind}; - pub use qsc_frontend::compile::{ CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName, }; diff --git a/compiler/qsc_frontend/src/lib.rs b/compiler/qsc_frontend/src/lib.rs index 992f9e8513..24f1897812 100644 --- a/compiler/qsc_frontend/src/lib.rs +++ b/compiler/qsc_frontend/src/lib.rs @@ -11,5 +11,3 @@ pub mod incremental; mod lower; pub mod resolve; pub mod typeck; - -pub use qsc_parse::{formatter, RawToken, RawTokenKind}; diff --git a/compiler/qsc_parse/src/lex.rs b/compiler/qsc_parse/src/lex.rs index 2fc23681c3..9c6d6721ba 100644 --- a/compiler/qsc_parse/src/lex.rs +++ b/compiler/qsc_parse/src/lex.rs @@ -1,16 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -mod concrete; mod cooked; -pub mod formatter; mod raw; use enum_iterator::Sequence; pub(super) use cooked::{ClosedBinOp, Error, Lexer, StringToken, Token, TokenKind}; -pub(super) use raw::Lexer as RawLexer; -pub use raw::{Token as RawToken, TokenKind as RawTokenKind}; /// A delimiter token. #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 09043d9a49..834c43b065 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -6,7 +6,6 @@ //! unique identifiers by a later stage. mod expr; -pub mod formatter; mod item; mod keyword; mod lex; @@ -17,9 +16,7 @@ mod stmt; mod tests; mod ty; -pub use lex::formatter; use lex::TokenKind; -pub use lex::{RawToken, RawTokenKind}; use miette::Diagnostic; use qsc_ast::ast::{Expr, Namespace, TopLevelNode}; use qsc_data_structures::span::Span; diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 65c5ac753d..29a1a83362 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -3,9 +3,9 @@ use crate::{compilation::Compilation, protocol::TextEdit}; -use qsc::formatter::{format, Edit}; -use qsc::line_column::{Encoding, Range}; -use qsc::Span; +// use qsc::formatter::{format, Edit}; +use qsc::line_column::{Encoding, Position, Range}; +// use qsc::Span; //use qsc::RawToken; //use qsc::RawTokenKind; //use regex_lite::Regex; @@ -13,7 +13,7 @@ use qsc::Span; pub(crate) fn get_format_changes( compilation: &Compilation, source_name: &str, - offset: u32, + position: Position, encoding: Encoding, ) -> Vec { let contents = compilation @@ -24,24 +24,24 @@ pub(crate) fn get_format_changes( .contents .clone(); - //let mut edits = vec![]; + let mut edits = vec![]; //let formatter = Formatter::new(&contents); - format(&contents) - .iter() - .map(|edit| TextEdit { - contents: edit.new_text.clone(), - span: Range::from_span( - encoding, - &contents, - &Span { - start: edit.span.lo, - end: edit.span.hi, - }, - ), - }) - .collect() + // format(&contents) + // .iter() + // .map(|edit| TextEdit { + // contents: edit.new_text.clone(), + // span: Range::from_span( + // encoding, + // &contents, + // &Span { + // start: edit.span.lo, + // end: edit.span.hi, + // }, + // ), + // }) + // .collect() //let temp = edits.extend(RemoveTrailingWhitespace(&formatter.tokens, &contents)); @@ -53,7 +53,7 @@ pub(crate) fn get_format_changes( // }); // } - //edits + edits } // fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { diff --git a/language_service/src/lib.rs b/language_service/src/lib.rs index 47e11d7b9b..8f6be24cd4 100644 --- a/language_service/src/lib.rs +++ b/language_service/src/lib.rs @@ -231,7 +231,12 @@ impl LanguageService { /// LSP: textDocument/format #[must_use] pub fn get_format_changes(&self, uri: &str) -> Vec { - self.document_op(format::get_format_changes, "get_format_changes", uri, 0) + self.document_op( + format::get_format_changes, + "get_format_changes", + uri, + Position { line: 0, column: 0 }, + ) } /// LSP: textDocument/hover diff --git a/npm/src/language-service/language-service.ts b/npm/src/language-service/language-service.ts index ae5144299c..23fdb32b2c 100644 --- a/npm/src/language-service/language-service.ts +++ b/npm/src/language-service/language-service.ts @@ -163,21 +163,7 @@ export class QSharpLanguageService implements ILanguageService { } async getFormatChanges(documentUri: string): Promise { - const code = await this.loadFile(documentUri); - - if (code === null) { - log.error( - `getFormatChanges: expected ${documentUri} to be in the document map`, - ); - return []; - } - const results = this.languageService.get_format_changes(documentUri); - if (results && results.length > 0) { - for (const result of results) { - updateSpanFromUtf8ToUtf16(result.range, code); - } - } - return results; + return this.languageService.get_format_changes(documentUri); } async getHover( diff --git a/vscode/src/format.ts b/vscode/src/format.ts index 88204bf377..3390ae1ffc 100644 --- a/vscode/src/format.ts +++ b/vscode/src/format.ts @@ -3,6 +3,7 @@ import { ILanguageService } from "qsharp-lang"; import * as vscode from "vscode"; +import { toVscodeRange } from "./common"; export function createFormatProvider(languageService: ILanguageService) { return new QSharpFormatProvider(languageService); @@ -19,10 +20,7 @@ class QSharpFormatProvider implements vscode.DocumentFormattingEditProvider { if (!lsEdits) return []; const edits = []; for (const edit of lsEdits) { - const referenceRange = new vscode.Range( - document.positionAt(edit.range.start), - document.positionAt(edit.range.end), - ); + const referenceRange = toVscodeRange(edit.range); edits.push(new vscode.TextEdit(referenceRange, edit.newText)); } return edits; diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs index 81001c492e..21aed3132a 100644 --- a/wasm/src/language_service.rs +++ b/wasm/src/language_service.rs @@ -198,10 +198,17 @@ impl LanguageService { edits .into_iter() .map(|edit| { + // ToDo: is there an easier way to convert data types? TextEdit { - range: Span { - start: edit.span.start, - end: edit.span.end, + range: Range { + start: Position { + line: edit.span.start.line, + character: edit.span.start.column, + }, + end: Position { + line: edit.span.end.line, + character: edit.span.end.column, + }, }, newText: edit.contents, } From e7467e1ebee6465d1be1289a8ecd7383c83debbd Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 16 Feb 2024 13:44:19 -0800 Subject: [PATCH 10/74] fix things not being visible --- compiler/qsc/src/lib.rs | 2 ++ compiler/qsc_frontend/src/lib.rs | 2 ++ compiler/qsc_parse/src/lex.rs | 2 ++ compiler/qsc_parse/src/lex/concrete.rs | 4 ++-- compiler/qsc_parse/src/lib.rs | 1 + language_service/src/format.rs | 2 +- 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs index a3d0808642..1bf4c3e34d 100644 --- a/compiler/qsc/src/lib.rs +++ b/compiler/qsc/src/lib.rs @@ -11,6 +11,8 @@ pub mod interpret; pub mod location; pub mod target; +pub use qsc_frontend::formatter; + pub use qsc_frontend::compile::{ CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName, }; diff --git a/compiler/qsc_frontend/src/lib.rs b/compiler/qsc_frontend/src/lib.rs index 24f1897812..f641490e4c 100644 --- a/compiler/qsc_frontend/src/lib.rs +++ b/compiler/qsc_frontend/src/lib.rs @@ -11,3 +11,5 @@ pub mod incremental; mod lower; pub mod resolve; pub mod typeck; + +pub use qsc_parse::formatter; diff --git a/compiler/qsc_parse/src/lex.rs b/compiler/qsc_parse/src/lex.rs index 9c6d6721ba..ab361a3148 100644 --- a/compiler/qsc_parse/src/lex.rs +++ b/compiler/qsc_parse/src/lex.rs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +mod concrete; mod cooked; +pub mod formatter; mod raw; use enum_iterator::Sequence; diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index fb1cd6f501..abb40cfecf 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -67,8 +67,8 @@ impl Iterator for ConcreteTokenIterator<'_> { hi: next_lo, }; let concrete = match raw_token.kind { - crate::RawTokenKind::Comment(_) => ConcreteToken::Comment(span), - crate::RawTokenKind::Whitespace => ConcreteToken::WhiteSpace(span), + raw::TokenKind::Comment(_) => ConcreteToken::Comment(span), + raw::TokenKind::Whitespace => ConcreteToken::WhiteSpace(span), _ => panic!("only comments and whitespace should be non-compilable tokens"), // Todo: might need better handling }; Some(concrete) diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 834c43b065..2937de57f5 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -16,6 +16,7 @@ mod stmt; mod tests; mod ty; +pub use lex::formatter; use lex::TokenKind; use miette::Diagnostic; use qsc_ast::ast::{Expr, Namespace, TopLevelNode}; diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 29a1a83362..c218a5983d 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -3,7 +3,7 @@ use crate::{compilation::Compilation, protocol::TextEdit}; -// use qsc::formatter::{format, Edit}; +use qsc::formatter::{format, Edit}; use qsc::line_column::{Encoding, Position, Range}; // use qsc::Span; //use qsc::RawToken; From 2204a99837e3ab8326c3c87d8e1b1db203137d36 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 21 Feb 2024 10:56:08 -0800 Subject: [PATCH 11/74] got some basic rules working --- Cargo.lock | 1 + compiler/qsc_parse/Cargo.toml | 1 + compiler/qsc_parse/src/lex/concrete.rs | 20 +- compiler/qsc_parse/src/lex/formatter.rs | 282 +++++++++++++++++------- compiler/qsc_parse/src/lex/raw.rs | 13 +- language_service/src/format.rs | 25 +-- 6 files changed, 247 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53c50b7c5e..de87751fd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1023,6 +1023,7 @@ version = "0.0.0" dependencies = [ "enum-iterator", "expect-test", + "indoc", "miette", "num-bigint", "num-traits", diff --git a/compiler/qsc_parse/Cargo.toml b/compiler/qsc_parse/Cargo.toml index 22e0869c75..a39dd4c2dc 100644 --- a/compiler/qsc_parse/Cargo.toml +++ b/compiler/qsc_parse/Cargo.toml @@ -19,6 +19,7 @@ thiserror = { workspace = true } [dev-dependencies] expect-test = { workspace = true } +indoc = { workspace = true } [lib] doctest = false diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index abb40cfecf..c762d3e7d5 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -7,21 +7,31 @@ use qsc_data_structures::span::Span; use super::{cooked, raw}; -enum ConcreteToken { +pub(super) enum ConcreteToken { Cooked(cooked::Token), Error(cooked::Error), WhiteSpace(Span), Comment(Span), } -struct ConcreteTokenIterator<'a> { +pub(super) struct ConcreteTokenIterator<'a> { code: &'a str, cooked_tokens: Peekable>, non_compilation_tokens: Peekable>, } +impl ConcreteToken { + pub(super) fn get_span(&self) -> Span { + match self { + ConcreteToken::Cooked(cooked) => cooked.span, + ConcreteToken::Error(err) => err.get_span(), + ConcreteToken::WhiteSpace(span) | ConcreteToken::Comment(span) => *span, + } + } +} + impl<'a> ConcreteTokenIterator<'a> { - fn new(code: &'a str) -> Self { + pub(super) fn new(code: &'a str) -> Self { Self { code, cooked_tokens: cooked::Lexer::new(code).peekable(), @@ -30,10 +40,12 @@ impl<'a> ConcreteTokenIterator<'a> { } fn get_tokens_from_span(&mut self, lo: u32, hi: u32) { + let starting_offset = lo; let lo = lo as usize; let hi = hi as usize; if let Some(slice) = self.code.get(lo..hi) { - self.non_compilation_tokens = raw::Lexer::new(slice).peekable(); + self.non_compilation_tokens = + raw::Lexer::new_with_starting_offset(slice, starting_offset).peekable(); } } diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index abae192bfb..14cd92bba2 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -1,8 +1,13 @@ -use std::iter::Peekable; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//use std::iter::Peekable; use super::{ - raw::{Lexer, Single, TokenKind}, + concrete::{self, ConcreteToken}, + //raw::{Lexer, Single, TokenKind}, Delim, + TokenKind, }; use qsc_data_structures::span::Span; @@ -18,46 +23,46 @@ fn make_indent_string(level: usize) -> String { " ".repeat(level) } -#[derive(Clone, Copy)] -struct SpannedToken { - pub kind: TokenKind, - pub span: Span, -} - -struct SpannedTokenIterator<'a> { - code: &'a str, - tokens: Peekable>, -} - -impl<'a> SpannedTokenIterator<'a> { - fn new(code: &'a str) -> Self { - Self { - code, - tokens: Lexer::new(code).peekable(), - } - } -} - -impl Iterator for SpannedTokenIterator<'_> { - type Item = SpannedToken; - - fn next(&mut self) -> Option { - let token = self.tokens.next()?; - let next = self.tokens.peek(); - Some(SpannedToken { - kind: token.kind, - span: Span { - lo: token.offset, - hi: next - .map(|t| t.offset) - .unwrap_or_else(|| self.code.len() as u32), - }, - }) - } -} +// #[derive(Clone, Copy)] +// struct SpannedToken { +// pub kind: TokenKind, +// pub span: Span, +// } + +// struct SpannedTokenIterator<'a> { +// code: &'a str, +// tokens: Peekable>, +// } + +// impl<'a> SpannedTokenIterator<'a> { +// fn new(code: &'a str) -> Self { +// Self { +// code, +// tokens: Lexer::new(code).peekable(), +// } +// } +// } + +// impl Iterator for SpannedTokenIterator<'_> { +// type Item = SpannedToken; + +// fn next(&mut self) -> Option { +// let token = self.tokens.next()?; +// let next = self.tokens.peek(); +// Some(SpannedToken { +// kind: token.kind, +// span: Span { +// lo: token.offset, +// hi: next +// .map(|t| t.offset) +// .unwrap_or_else(|| self.code.len() as u32), +// }, +// }) +// } +// } pub fn format(code: &str) -> Vec { - let tokens = SpannedTokenIterator::new(code); + let tokens = concrete::ConcreteTokenIterator::new(code); let mut edits = vec![]; let mut indent_level = 0; @@ -73,25 +78,30 @@ pub fn format(code: &str) -> Vec { two = three; three = Some(token); - let mut edits_for_triple = match (one, two, three) { + let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { // if the token is a {, increase the indent level - if one.kind == TokenKind::Single(Single::Open(Delim::Brace)) { - indent_level += 1; + if let ConcreteToken::Cooked(cooked) = one { + if cooked.kind == TokenKind::Open(Delim::Brace) { + indent_level += 1; + } } + // if the token is a }, decrease the indent level - if one.kind == TokenKind::Single(Single::Close(Delim::Brace)) { - indent_level -= 1; + if let ConcreteToken::Cooked(cooked) = one { + if cooked.kind == TokenKind::Close(Delim::Brace) { + indent_level -= 1; + } } - if one.kind == TokenKind::Whitespace { + if let ConcreteToken::WhiteSpace(_) = one { // first token is whitespace, continue scanning continue; - } else if two.kind == TokenKind::Whitespace { + } else if let ConcreteToken::WhiteSpace(_) = two { // whitespace in the middle apply_rule( one, - &code[two.span.lo as usize..two.span.hi as usize], + get_token_contents(code, two), three, code, indent_level, @@ -120,36 +130,47 @@ fn fix_whitespace(whitespace: &str, indent_level: usize) -> String { // and trim until the next newline or the end of the string // - let count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); + let mut count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); + + // There should always be at least one newline + if count_newlines < 1 { + count_newlines = 1; + } let mut new = "\n".repeat(count_newlines); new.push_str(&make_indent_string(indent_level)); new } fn apply_rule( - left: SpannedToken, + left: &ConcreteToken, whitespace: &str, - right: SpannedToken, + right: &ConcreteToken, code: &str, indent_level: usize, ) -> Vec { let mut edits = vec![]; // when we get here, neither left nor right should be whitespace - // some comment - - // some other comment - // operation Foo() : Unit {} + // if the right is a close brace, the indent level should be one less + let indent_level = if let ConcreteToken::Cooked(cooked) = right { + if let TokenKind::Close(Delim::Brace) = cooked.kind { + indent_level - 1 + } else { + indent_level + } + } else { + indent_level + }; - match (left.kind, right.kind) { - (TokenKind::Comment(_), _) => { + match (&left, &right) { + (ConcreteToken::Comment(span), _) => { // fix indentation // and fix trailing spaces on the left comment let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { edits.push(Edit { - span: left.span, + span: *span, new_text: new_comment_contents.to_string(), }); } @@ -160,47 +181,130 @@ fn apply_rule( if whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.span.hi, - hi: right.span.lo, + lo: left.get_span().hi, + hi: right.get_span().lo, }, new_text: new_whitespace.to_string(), }); } } - (TokenKind::Ident, TokenKind::Ident) - //| (TokenKind::Single(Single::Colon), TokenKind::Ident) - //| (TokenKind::Ident, TokenKind::Single(_)) - => { - // Put exactly one space in the middle - let old_whitespace = whitespace; - let new_whitespace = " "; - if old_whitespace != new_whitespace { + (ConcreteToken::Cooked(cooked_left), _) + if matches!(cooked_left.kind, TokenKind::Open(Delim::Brace)) => + { + let span = cooked_left.span; + // fix indentation + // and fix trailing spaces on the left + let contents = get_token_contents(code, left); + let new_contents = contents.trim_end(); + if contents != new_contents { + edits.push(Edit { + span, + new_text: new_contents.to_string(), + }); + } + + // if the middle whitespace contains a new line, we need to + // fix the indentation + let new_whitespace = fix_whitespace(whitespace, indent_level); + if whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.span.hi, - hi: right.span.lo, + lo: left.get_span().hi, + hi: right.get_span().lo, }, new_text: new_whitespace.to_string(), }); } } + (ConcreteToken::Cooked(cooked_left), _) + if matches!(cooked_left.kind, TokenKind::Close(Delim::Brace)) => + { + let span = cooked_left.span; + // fix indentation + // and fix trailing spaces on the left + let contents = get_token_contents(code, left); + let new_contents = contents.trim_end(); + if contents != new_contents { + edits.push(Edit { + span, + new_text: new_contents.to_string(), + }); + } + + // if the middle whitespace contains a new line, we need to + // fix the indentation + let new_whitespace = fix_whitespace(whitespace, indent_level); + if whitespace != new_whitespace { + edits.push(Edit { + span: Span { + lo: left.get_span().hi, + hi: right.get_span().lo, + }, + new_text: new_whitespace.to_string(), + }); + } + } + (ConcreteToken::Cooked(cooked_left), ConcreteToken::Cooked(cooked_right)) => { + match (cooked_left.kind, cooked_right.kind) { + (TokenKind::Ident, TokenKind::Ident) + | (TokenKind::Keyword(_), TokenKind::Ident) => + //| (TokenKind::Single(Single::Colon), TokenKind::Ident) + //| (TokenKind::Ident, TokenKind::Single(_)) + { + // Put exactly one space in the middle + let old_whitespace = whitespace; + let new_whitespace = " "; + if old_whitespace != new_whitespace { + edits.push(Edit { + span: Span { + lo: left.get_span().hi, + hi: right.get_span().lo, + }, + new_text: new_whitespace.to_string(), + }); + } + } + (TokenKind::Ident, TokenKind::Open(Delim::Paren)) + | (TokenKind::Ident, TokenKind::Open(Delim::Bracket)) => { + // Put no space in the middle + let old_whitespace = whitespace; + let new_whitespace = ""; + if old_whitespace != new_whitespace { + edits.push(Edit { + span: Span { + lo: left.get_span().hi, + hi: right.get_span().lo, + }, + new_text: new_whitespace.to_string(), + }); + } + } + _ => {} + } + } _ => {} } println!( "edits for `{}` : {edits:?}", - &code[left.span.lo as usize..right.span.hi as usize] + &code[left.get_span().lo as usize..right.get_span().hi as usize] ); edits } -fn get_token_contents(code: &str, left: SpannedToken) -> &str { - &code[left.span.lo as usize..left.span.hi as usize] +fn get_token_contents<'a>(code: &'a str, token: &ConcreteToken) -> &'a str { + let span = match token { + ConcreteToken::Cooked(cooked) => cooked.span, + ConcreteToken::Error(err) => err.get_span(), + ConcreteToken::WhiteSpace(span) | ConcreteToken::Comment(span) => *span, + }; + &code[span.lo as usize..span.hi as usize] } #[cfg(test)] mod tests { use expect_test::expect; + use indoc::indoc; #[test] fn test_formatting() { @@ -220,7 +324,37 @@ mod tests { lo: 15, hi: 18, }, - new_text: " ", + new_text: "", + }, + ] + "#]] + .assert_debug_eq(&edits); + } + + #[test] + fn test_braces() { + let code = indoc! {r#" + operation Foo() : Unit {} + operation Bar() : Unit { + operation Baz() : Unit {} + } + "#}; + let edits = super::format(code); + expect![[r#" + [ + Edit { + span: Span { + lo: 24, + hi: 24, + }, + new_text: "\n", + }, + Edit { + span: Span { + lo: 79, + hi: 79, + }, + new_text: "\n ", }, ] "#]] diff --git a/compiler/qsc_parse/src/lex/raw.rs b/compiler/qsc_parse/src/lex/raw.rs index a35cc6fe18..8d20fb2df5 100644 --- a/compiler/qsc_parse/src/lex/raw.rs +++ b/compiler/qsc_parse/src/lex/raw.rs @@ -171,6 +171,7 @@ pub enum CommentKind { pub struct Lexer<'a> { chars: Peekable>, interpolation: u8, + starting_offset: u32, } impl<'a> Lexer<'a> { @@ -178,6 +179,15 @@ impl<'a> Lexer<'a> { Self { chars: input.char_indices().peekable(), interpolation: 0, + starting_offset: 0, + } + } + + pub fn new_with_starting_offset(input: &'a str, starting_offset: u32) -> Self { + Self { + chars: input.char_indices().peekable(), + interpolation: 0, + starting_offset, } } @@ -388,9 +398,10 @@ impl Iterator for Lexer<'_> { .or_else(|| single(c).map(TokenKind::Single)) .unwrap_or(TokenKind::Unknown) }; + let offset: u32 = offset.try_into().expect("offset should fit into u32"); Some(Token { kind, - offset: offset.try_into().expect("offset should fit into u32"), + offset: offset + self.starting_offset, }) } } diff --git a/language_service/src/format.rs b/language_service/src/format.rs index c218a5983d..c674e36b16 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -24,24 +24,17 @@ pub(crate) fn get_format_changes( .contents .clone(); - let mut edits = vec![]; + //let mut edits = vec![]; //let formatter = Formatter::new(&contents); - // format(&contents) - // .iter() - // .map(|edit| TextEdit { - // contents: edit.new_text.clone(), - // span: Range::from_span( - // encoding, - // &contents, - // &Span { - // start: edit.span.lo, - // end: edit.span.hi, - // }, - // ), - // }) - // .collect() + format(&contents) + .iter() + .map(|edit| TextEdit { + contents: edit.new_text.clone(), + span: Range::from_span(encoding, &contents, &edit.span), + }) + .collect() //let temp = edits.extend(RemoveTrailingWhitespace(&formatter.tokens, &contents)); @@ -53,7 +46,7 @@ pub(crate) fn get_format_changes( // }); // } - edits + //edits } // fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { From 6adc019d08048403271db2513df20f2af4fc259d Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 21 Feb 2024 11:18:15 -0800 Subject: [PATCH 12/74] changed data struct to have kind easier to get at. --- compiler/qsc_parse/src/lex/concrete.rs | 54 +++++++++++------ compiler/qsc_parse/src/lex/formatter.rs | 80 ++++++++++--------------- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index c762d3e7d5..52d4cef2e4 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -7,11 +7,16 @@ use qsc_data_structures::span::Span; use super::{cooked, raw}; -pub(super) enum ConcreteToken { - Cooked(cooked::Token), +pub(super) struct ConcreteToken { + pub kind: ConcreteTokenKind, + pub span: Span, +} + +pub(super) enum ConcreteTokenKind { + Cooked(cooked::TokenKind), Error(cooked::Error), - WhiteSpace(Span), - Comment(Span), + WhiteSpace, + Comment, } pub(super) struct ConcreteTokenIterator<'a> { @@ -20,15 +25,15 @@ pub(super) struct ConcreteTokenIterator<'a> { non_compilation_tokens: Peekable>, } -impl ConcreteToken { - pub(super) fn get_span(&self) -> Span { - match self { - ConcreteToken::Cooked(cooked) => cooked.span, - ConcreteToken::Error(err) => err.get_span(), - ConcreteToken::WhiteSpace(span) | ConcreteToken::Comment(span) => *span, - } - } -} +// impl ConcreteToken { +// pub(super) fn get_span(&self) -> Span { +// match self { +// ConcreteToken::Cooked(cooked) => cooked.span, +// ConcreteToken::Error(err) => err.get_span(), +// ConcreteToken::WhiteSpace(span) | ConcreteToken::Comment(span) => *span, +// } +// } +// } impl<'a> ConcreteTokenIterator<'a> { pub(super) fn new(code: &'a str) -> Self { @@ -79,8 +84,14 @@ impl Iterator for ConcreteTokenIterator<'_> { hi: next_lo, }; let concrete = match raw_token.kind { - raw::TokenKind::Comment(_) => ConcreteToken::Comment(span), - raw::TokenKind::Whitespace => ConcreteToken::WhiteSpace(span), + raw::TokenKind::Comment(_) => ConcreteToken { + kind: ConcreteTokenKind::Comment, + span, + }, + raw::TokenKind::Whitespace => ConcreteToken { + kind: ConcreteTokenKind::WhiteSpace, + span, + }, _ => panic!("only comments and whitespace should be non-compilable tokens"), // Todo: might need better handling }; Some(concrete) @@ -89,12 +100,19 @@ impl Iterator for ConcreteTokenIterator<'_> { Ok(token) => { let next_lo = self.get_next_lo(); self.get_tokens_from_span(token.span.hi, next_lo); - Some(ConcreteToken::Cooked(token)) + Some(ConcreteToken { + kind: ConcreteTokenKind::Cooked(token.kind), + span: token.span, + }) } Err(err) => { let next_lo = self.get_next_lo(); - self.get_tokens_from_span(err.get_span().hi, next_lo); - Some(ConcreteToken::Error(err)) + let span = err.get_span(); + self.get_tokens_from_span(span.hi, next_lo); + Some(ConcreteToken { + kind: ConcreteTokenKind::Error(err), + span, + }) } }, } diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 14cd92bba2..af735a16ca 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -4,7 +4,7 @@ //use std::iter::Peekable; use super::{ - concrete::{self, ConcreteToken}, + concrete::{self, ConcreteToken, ConcreteTokenKind}, //raw::{Lexer, Single, TokenKind}, Delim, TokenKind, @@ -81,23 +81,19 @@ pub fn format(code: &str) -> Vec { let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { // if the token is a {, increase the indent level - if let ConcreteToken::Cooked(cooked) = one { - if cooked.kind == TokenKind::Open(Delim::Brace) { - indent_level += 1; - } + if let ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)) = one.kind { + indent_level += 1; } // if the token is a }, decrease the indent level - if let ConcreteToken::Cooked(cooked) = one { - if cooked.kind == TokenKind::Close(Delim::Brace) { - indent_level -= 1; - } + if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = one.kind { + indent_level -= 1; } - if let ConcreteToken::WhiteSpace(_) = one { + if let ConcreteTokenKind::WhiteSpace = one.kind { // first token is whitespace, continue scanning continue; - } else if let ConcreteToken::WhiteSpace(_) = two { + } else if let ConcreteTokenKind::WhiteSpace = two.kind { // whitespace in the middle apply_rule( one, @@ -152,25 +148,22 @@ fn apply_rule( // when we get here, neither left nor right should be whitespace // if the right is a close brace, the indent level should be one less - let indent_level = if let ConcreteToken::Cooked(cooked) = right { - if let TokenKind::Close(Delim::Brace) = cooked.kind { - indent_level - 1 - } else { - indent_level - } + let indent_level = if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = right.kind + { + indent_level - 1 } else { indent_level }; - match (&left, &right) { - (ConcreteToken::Comment(span), _) => { + match (&left.kind, &right.kind) { + (ConcreteTokenKind::Comment, _) => { // fix indentation // and fix trailing spaces on the left comment let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { edits.push(Edit { - span: *span, + span: left.span, new_text: new_comment_contents.to_string(), }); } @@ -181,24 +174,21 @@ fn apply_rule( if whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.get_span().hi, - hi: right.get_span().lo, + lo: left.span.hi, + hi: right.span.lo, }, new_text: new_whitespace.to_string(), }); } } - (ConcreteToken::Cooked(cooked_left), _) - if matches!(cooked_left.kind, TokenKind::Open(Delim::Brace)) => - { - let span = cooked_left.span; + (ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)), _) => { // fix indentation // and fix trailing spaces on the left let contents = get_token_contents(code, left); let new_contents = contents.trim_end(); if contents != new_contents { edits.push(Edit { - span, + span: left.span, new_text: new_contents.to_string(), }); } @@ -209,24 +199,21 @@ fn apply_rule( if whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.get_span().hi, - hi: right.get_span().lo, + lo: left.span.hi, + hi: right.span.lo, }, new_text: new_whitespace.to_string(), }); } } - (ConcreteToken::Cooked(cooked_left), _) - if matches!(cooked_left.kind, TokenKind::Close(Delim::Brace)) => - { - let span = cooked_left.span; + (ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), _) => { // fix indentation // and fix trailing spaces on the left let contents = get_token_contents(code, left); let new_contents = contents.trim_end(); if contents != new_contents { edits.push(Edit { - span, + span: left.span, new_text: new_contents.to_string(), }); } @@ -237,15 +224,15 @@ fn apply_rule( if whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.get_span().hi, - hi: right.get_span().lo, + lo: left.span.hi, + hi: right.span.lo, }, new_text: new_whitespace.to_string(), }); } } - (ConcreteToken::Cooked(cooked_left), ConcreteToken::Cooked(cooked_right)) => { - match (cooked_left.kind, cooked_right.kind) { + (ConcreteTokenKind::Cooked(cooked_left), ConcreteTokenKind::Cooked(cooked_right)) => { + match (cooked_left, cooked_right) { (TokenKind::Ident, TokenKind::Ident) | (TokenKind::Keyword(_), TokenKind::Ident) => //| (TokenKind::Single(Single::Colon), TokenKind::Ident) @@ -257,8 +244,8 @@ fn apply_rule( if old_whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.get_span().hi, - hi: right.get_span().lo, + lo: left.span.hi, + hi: right.span.lo, }, new_text: new_whitespace.to_string(), }); @@ -272,8 +259,8 @@ fn apply_rule( if old_whitespace != new_whitespace { edits.push(Edit { span: Span { - lo: left.get_span().hi, - hi: right.get_span().lo, + lo: left.span.hi, + hi: right.span.lo, }, new_text: new_whitespace.to_string(), }); @@ -287,18 +274,13 @@ fn apply_rule( println!( "edits for `{}` : {edits:?}", - &code[left.get_span().lo as usize..right.get_span().hi as usize] + &code[left.span.lo as usize..right.span.hi as usize] ); edits } fn get_token_contents<'a>(code: &'a str, token: &ConcreteToken) -> &'a str { - let span = match token { - ConcreteToken::Cooked(cooked) => cooked.span, - ConcreteToken::Error(err) => err.get_span(), - ConcreteToken::WhiteSpace(span) | ConcreteToken::Comment(span) => *span, - }; - &code[span.lo as usize..span.hi as usize] + &code[token.span.lo as usize..token.span.hi as usize] } #[cfg(test)] From 31bb282edcfd62eff8179abf2a01e650aa0241cc Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 21 Feb 2024 13:21:22 -0800 Subject: [PATCH 13/74] rule for closing out empty delimiters --- compiler/qsc_parse/src/lex/formatter.rs | 35 +++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index af735a16ca..d52ad5d6e8 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -87,7 +87,9 @@ pub fn format(code: &str) -> Vec { // if the token is a }, decrease the indent level if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = one.kind { - indent_level -= 1; + if indent_level > 0 { + indent_level -= 1; + } } if let ConcreteTokenKind::WhiteSpace = one.kind { @@ -150,12 +152,31 @@ fn apply_rule( // if the right is a close brace, the indent level should be one less let indent_level = if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = right.kind { - indent_level - 1 + if indent_level > 0 { + indent_level - 1 + } else { + indent_level + } } else { indent_level }; match (&left.kind, &right.kind) { + ( + ConcreteTokenKind::Cooked(TokenKind::Open(l)), + ConcreteTokenKind::Cooked(TokenKind::Close(r)), + ) if l == r => { + let new_whitespace = ""; + if whitespace != new_whitespace { + edits.push(Edit { + span: Span { + lo: left.span.hi, + hi: right.span.lo, + }, + new_text: new_whitespace.to_string(), + }); + } + } (ConcreteTokenKind::Comment, _) => { // fix indentation // and fix trailing spaces on the left comment @@ -345,7 +366,8 @@ mod tests { #[test] fn test_formatting_2() { - let code = "/// # Sample + let code = indoc! {r#" + /// # Sample /// Joint Measurement /// /// # Description @@ -386,8 +408,11 @@ mod tests { return (parityResult, [firstQubitResult, secondQubitResult]); } } - "; + "#}; let edits = super::format(code); - expect![[r#""#]].assert_debug_eq(&edits); + expect![[r#" + [] + "#]] + .assert_debug_eq(&edits); } } From 9897873aed89d24aa2dee97522e8b466d5e1946a Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 21 Feb 2024 13:38:54 -0800 Subject: [PATCH 14/74] little bit of clean up --- compiler/qsc_parse/src/lex/formatter.rs | 130 +++++++----------------- 1 file changed, 38 insertions(+), 92 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index d52ad5d6e8..935c9e3ff7 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -19,48 +19,26 @@ pub struct Edit { pub new_text: String, } +impl Edit { + fn new(lo: u32, hi: u32, new_text: &str) -> Self { + Self { + span: Span { lo, hi }, + new_text: new_text.to_string(), + } + } + + fn new_with_span(span: Span, new_text: &str) -> Self { + Self { + span, + new_text: new_text.to_string(), + } + } +} + fn make_indent_string(level: usize) -> String { " ".repeat(level) } -// #[derive(Clone, Copy)] -// struct SpannedToken { -// pub kind: TokenKind, -// pub span: Span, -// } - -// struct SpannedTokenIterator<'a> { -// code: &'a str, -// tokens: Peekable>, -// } - -// impl<'a> SpannedTokenIterator<'a> { -// fn new(code: &'a str) -> Self { -// Self { -// code, -// tokens: Lexer::new(code).peekable(), -// } -// } -// } - -// impl Iterator for SpannedTokenIterator<'_> { -// type Item = SpannedToken; - -// fn next(&mut self) -> Option { -// let token = self.tokens.next()?; -// let next = self.tokens.peek(); -// Some(SpannedToken { -// kind: token.kind, -// span: Span { -// lo: token.offset, -// hi: next -// .map(|t| t.offset) -// .unwrap_or_else(|| self.code.len() as u32), -// }, -// }) -// } -// } - pub fn format(code: &str) -> Vec { let tokens = concrete::ConcreteTokenIterator::new(code); let mut edits = vec![]; @@ -87,6 +65,7 @@ pub fn format(code: &str) -> Vec { // if the token is a }, decrease the indent level if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = one.kind { + #[allow(clippy::implicit_saturating_sub)] if indent_level > 0 { indent_level -= 1; } @@ -168,13 +147,7 @@ fn apply_rule( ) if l == r => { let new_whitespace = ""; if whitespace != new_whitespace { - edits.push(Edit { - span: Span { - lo: left.span.hi, - hi: right.span.lo, - }, - new_text: new_whitespace.to_string(), - }); + edits.push(Edit::new(left.span.hi, right.span.lo, new_whitespace)); } } (ConcreteTokenKind::Comment, _) => { @@ -183,23 +156,18 @@ fn apply_rule( let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { - edits.push(Edit { - span: left.span, - new_text: new_comment_contents.to_string(), - }); + edits.push(Edit::new_with_span(left.span, new_comment_contents)); } // if the middle whitespace contains a new line, we need to // fix the indentation let new_whitespace = fix_whitespace(whitespace, indent_level); if whitespace != new_whitespace { - edits.push(Edit { - span: Span { - lo: left.span.hi, - hi: right.span.lo, - }, - new_text: new_whitespace.to_string(), - }); + edits.push(Edit::new( + left.span.hi, + right.span.lo, + new_whitespace.as_str(), + )); } } (ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)), _) => { @@ -208,23 +176,18 @@ fn apply_rule( let contents = get_token_contents(code, left); let new_contents = contents.trim_end(); if contents != new_contents { - edits.push(Edit { - span: left.span, - new_text: new_contents.to_string(), - }); + edits.push(Edit::new_with_span(left.span, new_contents)); } // if the middle whitespace contains a new line, we need to // fix the indentation let new_whitespace = fix_whitespace(whitespace, indent_level); if whitespace != new_whitespace { - edits.push(Edit { - span: Span { - lo: left.span.hi, - hi: right.span.lo, - }, - new_text: new_whitespace.to_string(), - }); + edits.push(Edit::new( + left.span.hi, + right.span.lo, + new_whitespace.as_str(), + )); } } (ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), _) => { @@ -233,23 +196,18 @@ fn apply_rule( let contents = get_token_contents(code, left); let new_contents = contents.trim_end(); if contents != new_contents { - edits.push(Edit { - span: left.span, - new_text: new_contents.to_string(), - }); + edits.push(Edit::new_with_span(left.span, new_contents)); } // if the middle whitespace contains a new line, we need to // fix the indentation let new_whitespace = fix_whitespace(whitespace, indent_level); if whitespace != new_whitespace { - edits.push(Edit { - span: Span { - lo: left.span.hi, - hi: right.span.lo, - }, - new_text: new_whitespace.to_string(), - }); + edits.push(Edit::new( + left.span.hi, + right.span.lo, + new_whitespace.as_str(), + )); } } (ConcreteTokenKind::Cooked(cooked_left), ConcreteTokenKind::Cooked(cooked_right)) => { @@ -263,13 +221,7 @@ fn apply_rule( let old_whitespace = whitespace; let new_whitespace = " "; if old_whitespace != new_whitespace { - edits.push(Edit { - span: Span { - lo: left.span.hi, - hi: right.span.lo, - }, - new_text: new_whitespace.to_string(), - }); + edits.push(Edit::new(left.span.hi, right.span.lo, new_whitespace)); } } (TokenKind::Ident, TokenKind::Open(Delim::Paren)) @@ -278,13 +230,7 @@ fn apply_rule( let old_whitespace = whitespace; let new_whitespace = ""; if old_whitespace != new_whitespace { - edits.push(Edit { - span: Span { - lo: left.span.hi, - hi: right.span.lo, - }, - new_text: new_whitespace.to_string(), - }); + edits.push(Edit::new(left.span.hi, right.span.lo, new_whitespace)); } } _ => {} From f9c96b211d431e4de8292a8c49327ea068ad37cf Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 21 Feb 2024 15:20:12 -0800 Subject: [PATCH 15/74] cleanup and more small rules --- compiler/qsc_parse/src/lex/formatter.rs | 154 ++++++++++++------------ 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 935c9e3ff7..7302ed964f 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -76,7 +76,7 @@ pub fn format(code: &str) -> Vec { continue; } else if let ConcreteTokenKind::WhiteSpace = two.kind { // whitespace in the middle - apply_rule( + apply_rules( one, get_token_contents(code, two), three, @@ -85,7 +85,7 @@ pub fn format(code: &str) -> Vec { ) } else { // one, two are adjacent tokens with no whitespace in the middle - apply_rule(one, "", two, code, indent_level) + apply_rules(one, "", two, code, indent_level) } } _ => { @@ -118,7 +118,7 @@ fn fix_whitespace(whitespace: &str, indent_level: usize) -> String { new } -fn apply_rule( +fn apply_rules( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, @@ -145,93 +145,43 @@ fn apply_rule( ConcreteTokenKind::Cooked(TokenKind::Open(l)), ConcreteTokenKind::Cooked(TokenKind::Close(r)), ) if l == r => { - let new_whitespace = ""; - if whitespace != new_whitespace { - edits.push(Edit::new(left.span.hi, right.span.lo, new_whitespace)); - } + rule_no_space(left, whitespace, right, &mut edits); } (ConcreteTokenKind::Comment, _) => { - // fix indentation - // and fix trailing spaces on the left comment - let comment_contents = get_token_contents(code, left); - let new_comment_contents = comment_contents.trim_end(); - if comment_contents != new_comment_contents { - edits.push(Edit::new_with_span(left.span, new_comment_contents)); - } - - // if the middle whitespace contains a new line, we need to - // fix the indentation - let new_whitespace = fix_whitespace(whitespace, indent_level); - if whitespace != new_whitespace { - edits.push(Edit::new( - left.span.hi, - right.span.lo, - new_whitespace.as_str(), - )); - } + rule_trim_comments(left, &mut edits, code); + rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)), _) => { - // fix indentation - // and fix trailing spaces on the left - let contents = get_token_contents(code, left); - let new_contents = contents.trim_end(); - if contents != new_contents { - edits.push(Edit::new_with_span(left.span, new_contents)); + (ConcreteTokenKind::Cooked(TokenKind::Semi), _) => match &right.kind { + ConcreteTokenKind::Comment => { + if whitespace.contains('\n') { + rule_indentation(left, whitespace, right, &mut edits, indent_level) + } } - - // if the middle whitespace contains a new line, we need to - // fix the indentation - let new_whitespace = fix_whitespace(whitespace, indent_level); - if whitespace != new_whitespace { - edits.push(Edit::new( - left.span.hi, - right.span.lo, - new_whitespace.as_str(), - )); + _ => { + rule_indentation(left, whitespace, right, &mut edits, indent_level); } + }, + (ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)), _) => { + rule_indentation(left, whitespace, right, &mut edits, indent_level); } (ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), _) => { - // fix indentation - // and fix trailing spaces on the left - let contents = get_token_contents(code, left); - let new_contents = contents.trim_end(); - if contents != new_contents { - edits.push(Edit::new_with_span(left.span, new_contents)); - } - - // if the middle whitespace contains a new line, we need to - // fix the indentation - let new_whitespace = fix_whitespace(whitespace, indent_level); - if whitespace != new_whitespace { - edits.push(Edit::new( - left.span.hi, - right.span.lo, - new_whitespace.as_str(), - )); - } + rule_indentation(left, whitespace, right, &mut edits, indent_level); } (ConcreteTokenKind::Cooked(cooked_left), ConcreteTokenKind::Cooked(cooked_right)) => { match (cooked_left, cooked_right) { (TokenKind::Ident, TokenKind::Ident) - | (TokenKind::Keyword(_), TokenKind::Ident) => - //| (TokenKind::Single(Single::Colon), TokenKind::Ident) - //| (TokenKind::Ident, TokenKind::Single(_)) - { - // Put exactly one space in the middle - let old_whitespace = whitespace; - let new_whitespace = " "; - if old_whitespace != new_whitespace { - edits.push(Edit::new(left.span.hi, right.span.lo, new_whitespace)); - } + | (TokenKind::Keyword(_), TokenKind::Ident) + | (TokenKind::Ident, TokenKind::Colon) + | (TokenKind::Colon, TokenKind::Ident) + | (TokenKind::Comma, _) => { + rule_single_space(left, whitespace, right, &mut edits); } (TokenKind::Ident, TokenKind::Open(Delim::Paren)) - | (TokenKind::Ident, TokenKind::Open(Delim::Bracket)) => { - // Put no space in the middle - let old_whitespace = whitespace; - let new_whitespace = ""; - if old_whitespace != new_whitespace { - edits.push(Edit::new(left.span.hi, right.span.lo, new_whitespace)); - } + | (TokenKind::Ident, TokenKind::Open(Delim::Bracket)) + | (TokenKind::Ident, TokenKind::Comma) + | (TokenKind::Open(_), _) + | (_, TokenKind::Close(_)) => { + rule_no_space(left, whitespace, right, &mut edits); } _ => {} } @@ -246,6 +196,56 @@ fn apply_rule( edits } +fn rule_no_space( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, +) { + if whitespace != "" { + edits.push(Edit::new(left.span.hi, right.span.lo, "")); + } +} + +fn rule_single_space( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, +) { + if whitespace != " " { + edits.push(Edit::new(left.span.hi, right.span.lo, " ")); + } +} + +fn rule_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { + // fix trailing spaces on the comment + let comment_contents = get_token_contents(code, left); + let new_comment_contents = comment_contents.trim_end(); + if comment_contents != new_comment_contents { + edits.push(Edit::new_with_span(left.span, new_comment_contents)); + } +} + +fn rule_indentation( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, + indent_level: usize, +) { + // if the middle whitespace contains a new line, we need to + // fix the indentation + let new_whitespace = fix_whitespace(whitespace, indent_level); + if whitespace != new_whitespace { + edits.push(Edit::new( + left.span.hi, + right.span.lo, + new_whitespace.as_str(), + )); + } +} + fn get_token_contents<'a>(code: &'a str, token: &ConcreteToken) -> &'a str { &code[token.span.lo as usize..token.span.hi as usize] } From 0e033a094fc77a86a36d4292fd2aa0d2c2972337 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 21 Feb 2024 15:47:55 -0800 Subject: [PATCH 16/74] I think I finished indentation? --- compiler/qsc_parse/src/lex/formatter.rs | 27 +++++++++++++++++++++---- language_service/src/format.rs | 4 ++-- language_service/src/lib.rs | 9 +-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 7302ed964f..690e47f274 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -3,6 +3,8 @@ //use std::iter::Peekable; +use crate::keyword::Keyword; + use super::{ concrete::{self, ConcreteToken, ConcreteTokenKind}, //raw::{Lexer, Single, TokenKind}, @@ -154,16 +156,33 @@ fn apply_rules( (ConcreteTokenKind::Cooked(TokenKind::Semi), _) => match &right.kind { ConcreteTokenKind::Comment => { if whitespace.contains('\n') { - rule_indentation(left, whitespace, right, &mut edits, indent_level) + rule_indentation(left, whitespace, right, &mut edits, indent_level); } } _ => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } }, + (_, ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace))) => { + rule_indentation(left, whitespace, right, &mut edits, indent_level); + } + ( + _, + ConcreteTokenKind::Cooked(TokenKind::Keyword( + Keyword::Operation | Keyword::Function | Keyword::Newtype | Keyword::Namespace, + )), + ) => { + rule_indentation(left, whitespace, right, &mut edits, indent_level); + } (ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } + ( + ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), + ConcreteTokenKind::Cooked(TokenKind::Semi), + ) => { + rule_no_space(left, whitespace, right, &mut edits); + } (ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -171,8 +190,8 @@ fn apply_rules( match (cooked_left, cooked_right) { (TokenKind::Ident, TokenKind::Ident) | (TokenKind::Keyword(_), TokenKind::Ident) - | (TokenKind::Ident, TokenKind::Colon) - | (TokenKind::Colon, TokenKind::Ident) + | (_, TokenKind::Colon) + | (TokenKind::Colon, _) | (TokenKind::Comma, _) => { rule_single_space(left, whitespace, right, &mut edits); } @@ -202,7 +221,7 @@ fn rule_no_space( right: &ConcreteToken, edits: &mut Vec, ) { - if whitespace != "" { + if !whitespace.is_empty() { edits.push(Edit::new(left.span.hi, right.span.lo, "")); } } diff --git a/language_service/src/format.rs b/language_service/src/format.rs index c674e36b16..709a8089bc 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -3,7 +3,7 @@ use crate::{compilation::Compilation, protocol::TextEdit}; -use qsc::formatter::{format, Edit}; +use qsc::formatter::format; use qsc::line_column::{Encoding, Position, Range}; // use qsc::Span; //use qsc::RawToken; @@ -13,7 +13,7 @@ use qsc::line_column::{Encoding, Position, Range}; pub(crate) fn get_format_changes( compilation: &Compilation, source_name: &str, - position: Position, + _position: Position, encoding: Encoding, ) -> Vec { let contents = compilation diff --git a/language_service/src/lib.rs b/language_service/src/lib.rs index 8f6be24cd4..1663a885ed 100644 --- a/language_service/src/lib.rs +++ b/language_service/src/lib.rs @@ -36,14 +36,7 @@ use qsc::{ }; use qsc_project::JSFileEntry; use state::{CompilationState, CompilationStateUpdater}; -use std::{ - cell::RefCell, - fmt::{format, Debug}, - future::Future, - pin::Pin, - rc::Rc, - sync::Arc, -}; +use std::{cell::RefCell, fmt::Debug, future::Future, pin::Pin, rc::Rc, sync::Arc}; pub struct LanguageService { /// All [`Position`]s and [`Range`]s will be mapped using this encoding. From a67043d3d18f69a7da2f0e86302ff81a186b9516 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 22 Feb 2024 09:15:42 -0800 Subject: [PATCH 17/74] remove commented out code --- language_service/src/format.rs | 84 ---------------------------------- 1 file changed, 84 deletions(-) diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 709a8089bc..3469fae9e5 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -5,10 +5,6 @@ use crate::{compilation::Compilation, protocol::TextEdit}; use qsc::formatter::format; use qsc::line_column::{Encoding, Position, Range}; -// use qsc::Span; -//use qsc::RawToken; -//use qsc::RawTokenKind; -//use regex_lite::Regex; pub(crate) fn get_format_changes( compilation: &Compilation, @@ -24,10 +20,6 @@ pub(crate) fn get_format_changes( .contents .clone(); - //let mut edits = vec![]; - - //let formatter = Formatter::new(&contents); - format(&contents) .iter() .map(|edit| TextEdit { @@ -35,80 +27,4 @@ pub(crate) fn get_format_changes( span: Range::from_span(encoding, &contents, &edit.span), }) .collect() - - //let temp = edits.extend(RemoveTrailingWhitespace(&formatter.tokens, &contents)); - - // This is a dummy format rule - // if !contents.starts_with("42") { - // edits.push(TextEdit { - // contents: "42\n".to_string(), - // span: Span { start: 0, end: 0 }, - // }); - // } - - //edits } - -// fn RemoveTrailingWhitespace(tokens: &[RawToken], contents: &str) -> Vec { -// let mut edits = vec![]; - -// let trailing_spaces_newline = Regex::new(r"(?[ \t]+)(:?\n|\r\n)").unwrap(); -// let trailing_spaces = Regex::new(r"(?[ \t]+)$").unwrap(); -// let trailing_spaces_newline_or_end = Regex::new(r"(?[ \t]+)(:?\n|\r\n|$)").unwrap(); - -// for i in 0..tokens.len() { -// let curr = &tokens[i]; -// match &curr.kind { -// RawTokenKind::Comment(_) => { -// let lo: usize = curr.offset.try_into().unwrap(); -// let hi: usize = if i + 1 < tokens.len() { -// let next = &tokens[i + 1]; -// next.offset.try_into().unwrap() -// } else { -// contents.len() -// }; -// let text = contents.get(lo..hi).unwrap(); -// for capture in trailing_spaces.captures_iter(text) { -// let range = capture.name("spaces").unwrap().range(); -// let length = range.len(); -// let start = curr.offset + TryInto::::try_into(range.start).unwrap(); -// let end = curr.offset + TryInto::::try_into(range.end).unwrap(); -// edits.push(TextEdit { -// contents: String::new(), -// //contents: "!".repeat(length), -// span: Span { start, end }, -// }); -// } -// } -// RawTokenKind::Whitespace => { -// let lo: usize = curr.offset.try_into().unwrap(); -// let hi: usize = if i + 1 < tokens.len() { -// let next = &tokens[i + 1]; -// next.offset.try_into().unwrap() -// } else { -// contents.len() -// }; -// let text = contents.get(lo..hi).unwrap(); -// let re = if i + 1 < tokens.len() { -// &trailing_spaces_newline -// } else { -// &trailing_spaces_newline_or_end -// }; -// for capture in re.captures_iter(text) { -// let range = capture.name("spaces").unwrap().range(); -// let length = range.len(); -// let start = curr.offset + TryInto::::try_into(range.start).unwrap(); -// let end = curr.offset + TryInto::::try_into(range.end).unwrap(); -// edits.push(TextEdit { -// contents: String::new(), -// //contents: "!".repeat(length), -// span: Span { start, end }, -// }); -// } -// } -// _ => {} -// } -// } - -// edits -// } From c432b9e6d94fa237f423e1fa3a11f81646f86610 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 23 Feb 2024 12:44:24 -0800 Subject: [PATCH 18/74] WIP of tests --- compiler/qsc_parse/src/formatter.rs | 16 -- compiler/qsc_parse/src/lex/concrete.rs | 11 +- compiler/qsc_parse/src/lex/formatter.rs | 139 ++--------- compiler/qsc_parse/src/lex/formatter/tests.rs | 221 ++++++++++++++++++ 4 files changed, 237 insertions(+), 150 deletions(-) delete mode 100644 compiler/qsc_parse/src/formatter.rs create mode 100644 compiler/qsc_parse/src/lex/formatter/tests.rs diff --git a/compiler/qsc_parse/src/formatter.rs b/compiler/qsc_parse/src/formatter.rs deleted file mode 100644 index ffc4a4d30a..0000000000 --- a/compiler/qsc_parse/src/formatter.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -use crate::lex::{RawLexer, RawToken}; - -pub struct Formatter { - pub tokens: Vec, -} - -impl Formatter { - pub fn new(input: &str) -> Self { - Self { - tokens: RawLexer::new(input).collect::>(), - } - } -} diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 52d4cef2e4..7778ff6bce 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -12,6 +12,7 @@ pub(super) struct ConcreteToken { pub span: Span, } +#[derive(PartialEq)] pub(super) enum ConcreteTokenKind { Cooked(cooked::TokenKind), Error(cooked::Error), @@ -25,16 +26,6 @@ pub(super) struct ConcreteTokenIterator<'a> { non_compilation_tokens: Peekable>, } -// impl ConcreteToken { -// pub(super) fn get_span(&self) -> Span { -// match self { -// ConcreteToken::Cooked(cooked) => cooked.span, -// ConcreteToken::Error(err) => err.get_span(), -// ConcreteToken::WhiteSpace(span) | ConcreteToken::Comment(span) => *span, -// } -// } -// } - impl<'a> ConcreteTokenIterator<'a> { pub(super) fn new(code: &'a str) -> Self { Self { diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 690e47f274..714c8d57dc 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -//use std::iter::Peekable; - use crate::keyword::Keyword; use super::{ @@ -13,6 +11,9 @@ use super::{ }; use qsc_data_structures::span::Span; +#[cfg(test)] +mod tests; + #[derive(Debug)] pub struct Edit { #[allow(dead_code)] // TODO: nobody's using this yet except for tests @@ -28,13 +29,6 @@ impl Edit { new_text: new_text.to_string(), } } - - fn new_with_span(span: Span, new_text: &str) -> Self { - Self { - span, - new_text: new_text.to_string(), - } - } } fn make_indent_string(level: usize) -> String { @@ -90,6 +84,16 @@ pub fn format(code: &str) -> Vec { apply_rules(one, "", two, code, indent_level) } } + (None, None, Some(three)) => { + let temp = format!("{:?}", three.kind); + + // Remove any whitespace at the start of a file + if ConcreteTokenKind::WhiteSpace == three.kind { + vec![Edit::new(three.span.hi, three.span.lo, "")] + } else { + vec![] + } + } _ => { // not enough tokens to apply a rule // TODO: we'll probably need to handle end-of-file cases here @@ -149,7 +153,7 @@ fn apply_rules( ) if l == r => { rule_no_space(left, whitespace, right, &mut edits); } - (ConcreteTokenKind::Comment, _) => { + (ConcreteTokenKind::Comment | ConcreteTokenKind::Cooked(TokenKind::DocComment), _) => { rule_trim_comments(left, &mut edits, code); rule_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -242,7 +246,7 @@ fn rule_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { - edits.push(Edit::new_with_span(left.span, new_comment_contents)); + edits.push(Edit::new(left.span.lo, left.span.hi, new_comment_contents)); } } @@ -268,116 +272,3 @@ fn rule_indentation( fn get_token_contents<'a>(code: &'a str, token: &ConcreteToken) -> &'a str { &code[token.span.lo as usize..token.span.hi as usize] } - -#[cfg(test)] -mod tests { - use expect_test::expect; - use indoc::indoc; - - #[test] - fn test_formatting() { - let code = "operation Foo ()"; - let edits = super::format(code); - expect![[r#" - [ - Edit { - span: Span { - lo: 9, - hi: 12, - }, - new_text: " ", - }, - Edit { - span: Span { - lo: 15, - hi: 18, - }, - new_text: "", - }, - ] - "#]] - .assert_debug_eq(&edits); - } - - #[test] - fn test_braces() { - let code = indoc! {r#" - operation Foo() : Unit {} - operation Bar() : Unit { - operation Baz() : Unit {} - } - "#}; - let edits = super::format(code); - expect![[r#" - [ - Edit { - span: Span { - lo: 24, - hi: 24, - }, - new_text: "\n", - }, - Edit { - span: Span { - lo: 79, - hi: 79, - }, - new_text: "\n ", - }, - ] - "#]] - .assert_debug_eq(&edits); - } - - #[test] - fn test_formatting_2() { - let code = indoc! {r#" - /// # Sample - /// Joint Measurement - /// - /// # Description - /// Joint measurements, also known as Pauli measurements, are a generalization - /// of 2-outcome measurements to multiple qubits and other bases. - namespace Sample { - open Microsoft.Quantum.Diagnostics; - - @EntryPoint() - operation Main() : (Result, Result[]) { - // Prepare an entangled state. - use qs = Qubit[2]; // |00〉 - H(qs[0]); // 1/sqrt(2)(|00〉 + |10〉) - CNOT(qs[0], qs[1]); // 1/sqrt(2)(|00〉 + |11〉) - - // Show the quantum state before performing the joint measurement. - DumpMachine(); - - // The below code uses a joint measurement as a way to check the parity - // of the first two qubits. In this case, the parity measurement result - // will always be `Zero`. - // Notice how the state was not collapsed by the joint measurement. - let parityResult = Measure([PauliZ, PauliZ], qs[...1]); - DumpMachine(); - - // However, if we perform a measurement just on the first qubit, we can - // see how the state collapses. - let firstQubitResult = M(qs[0]); - DumpMachine(); - - // Measuring the last qubit does not change the quantum state - // since the state of the second qubit collapsed when the first qubit - // was measured because they were entangled. - let secondQubitResult = M(qs[1]); - DumpMachine(); - - ResetAll(qs); - return (parityResult, [firstQubitResult, secondQubitResult]); - } - } - "#}; - let edits = super::format(code); - expect![[r#" - [] - "#]] - .assert_debug_eq(&edits); - } -} diff --git a/compiler/qsc_parse/src/lex/formatter/tests.rs b/compiler/qsc_parse/src/lex/formatter/tests.rs new file mode 100644 index 0000000000..cc9abcb786 --- /dev/null +++ b/compiler/qsc_parse/src/lex/formatter/tests.rs @@ -0,0 +1,221 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use expect_test::{expect, Expect}; +use indoc::indoc; + +fn check(input: &str, expect: &Expect) { + let actual = super::format(input); + expect.assert_debug_eq(&actual); +} + +#[test] +fn test_formatting() { + check( + "operation Foo ()", + &expect![[r#" + [ + Edit { + span: Span { + lo: 9, + hi: 12, + }, + new_text: " ", + }, + Edit { + span: Span { + lo: 15, + hi: 18, + }, + new_text: "", + }, + ] +"#]], + ); +} + +#[test] +fn test_indentation() { + check( + r#" + /// First +/// Second + /// Third + namespace MyQuantumProgram { + open Microsoft.Quantum.Diagnostics; + + @EntryPoint() + operation Main() : Int { + let x = 3; + let y = 4; + + // Comment + return 5; + } + } +"#, + &expect![[r#" + [ + Edit { + span: Span { + lo: 25, + hi: 30, + }, + new_text: "\n", + }, + Edit { + span: Span { + lo: 39, + hi: 48, + }, + new_text: "\n", + }, + Edit { + span: Span { + lo: 76, + hi: 85, + }, + new_text: "\n ", + }, + Edit { + span: Span { + lo: 120, + hi: 130, + }, + new_text: "\n\n ", + }, + Edit { + span: Span { + lo: 143, + hi: 152, + }, + new_text: "\n ", + }, + Edit { + span: Span { + lo: 176, + hi: 189, + }, + new_text: "\n ", + }, + Edit { + span: Span { + lo: 199, + hi: 212, + }, + new_text: "\n ", + }, + Edit { + span: Span { + lo: 222, + hi: 236, + }, + new_text: "\n\n ", + }, + Edit { + span: Span { + lo: 246, + hi: 259, + }, + new_text: "\n ", + }, + Edit { + span: Span { + lo: 268, + hi: 277, + }, + new_text: "\n ", + }, + Edit { + span: Span { + lo: 278, + hi: 291, + }, + new_text: "\n", + }, + ] + "#]], + ); +} + +#[test] +fn test_braces() { + let code = indoc! {r#" + operation Foo() : Unit {} + operation Bar() : Unit { + operation Baz() : Unit {} + } + "#}; + let edits = super::format(code); + expect![[r#" + [ + Edit { + span: Span { + lo: 24, + hi: 24, + }, + new_text: "\n", + }, + Edit { + span: Span { + lo: 79, + hi: 79, + }, + new_text: "\n ", + }, + ] + "#]] + .assert_debug_eq(&edits); +} + +#[test] +fn test_formatting_2() { + let code = indoc! {r#" + /// # Sample + /// Joint Measurement + /// + /// # Description + /// Joint measurements, also known as Pauli measurements, are a generalization + /// of 2-outcome measurements to multiple qubits and other bases. + namespace Sample { + open Microsoft.Quantum.Diagnostics; + + @EntryPoint() + operation Main() : (Result, Result[]) { + // Prepare an entangled state. + use qs = Qubit[2]; // |00〉 + H(qs[0]); // 1/sqrt(2)(|00〉 + |10〉) + CNOT(qs[0], qs[1]); // 1/sqrt(2)(|00〉 + |11〉) + + // Show the quantum state before performing the joint measurement. + DumpMachine(); + + // The below code uses a joint measurement as a way to check the parity + // of the first two qubits. In this case, the parity measurement result + // will always be `Zero`. + // Notice how the state was not collapsed by the joint measurement. + let parityResult = Measure([PauliZ, PauliZ], qs[...1]); + DumpMachine(); + + // However, if we perform a measurement just on the first qubit, we can + // see how the state collapses. + let firstQubitResult = M(qs[0]); + DumpMachine(); + + // Measuring the last qubit does not change the quantum state + // since the state of the second qubit collapsed when the first qubit + // was measured because they were entangled. + let secondQubitResult = M(qs[1]); + DumpMachine(); + + ResetAll(qs); + return (parityResult, [firstQubitResult, secondQubitResult]); + } + } + "#}; + let edits = super::format(code); + expect![[r#" + [] + "#]] + .assert_debug_eq(&edits); +} From 0623d8e47c3054c5dbce4e571ea42537fe1ae144 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 23 Feb 2024 13:26:20 -0800 Subject: [PATCH 19/74] added more tests --- compiler/qsc_parse/src/lex/concrete.rs | 2 +- compiler/qsc_parse/src/lex/formatter.rs | 6 +- compiler/qsc_parse/src/lex/formatter/tests.rs | 59 ++++++++++++++++++- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 7778ff6bce..d1b311b480 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -12,7 +12,7 @@ pub(super) struct ConcreteToken { pub span: Span, } -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub(super) enum ConcreteTokenKind { Cooked(cooked::TokenKind), Error(cooked::Error), diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 714c8d57dc..73498fe408 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -85,11 +85,9 @@ pub fn format(code: &str) -> Vec { } } (None, None, Some(three)) => { - let temp = format!("{:?}", three.kind); - // Remove any whitespace at the start of a file - if ConcreteTokenKind::WhiteSpace == three.kind { - vec![Edit::new(three.span.hi, three.span.lo, "")] + if three.span.lo != 0 { + vec![Edit::new(0, three.span.lo, "")] } else { vec![] } diff --git a/compiler/qsc_parse/src/lex/formatter/tests.rs b/compiler/qsc_parse/src/lex/formatter/tests.rs index cc9abcb786..455de46e47 100644 --- a/compiler/qsc_parse/src/lex/formatter/tests.rs +++ b/compiler/qsc_parse/src/lex/formatter/tests.rs @@ -35,7 +35,57 @@ fn test_formatting() { } #[test] -fn test_indentation() { +fn remove_trailing_spaces() { + let extra_spaces = " "; + let input = format!( + "/// Doc Comment with trailing spaces{extra_spaces} +operation Foo() : Unit {{ + // Comment with trailing spaces{extra_spaces} + let x = 3; // In-line comment with trailing spaces{extra_spaces} + let y = 4;{extra_spaces} +}} +" + ); + + check( + input.as_str(), + &expect![[r#" + [ + Edit { + span: Span { + lo: 0, + hi: 40, + }, + new_text: "/// Doc Comment with trailing spaces", + }, + Edit { + span: Span { + lo: 70, + hi: 105, + }, + new_text: "// Comment with trailing spaces", + }, + Edit { + span: Span { + lo: 123, + hi: 166, + }, + new_text: "// In-line comment with trailing spaces", + }, + Edit { + span: Span { + lo: 181, + hi: 186, + }, + new_text: "\n", + }, + ] + "#]], + ); +} + +#[test] +fn correct_indentation() { check( r#" /// First @@ -56,6 +106,13 @@ fn test_indentation() { "#, &expect![[r#" [ + Edit { + span: Span { + lo: 0, + hi: 5, + }, + new_text: "", + }, Edit { span: Span { lo: 25, From 5cf1a962f951df02d23f84adc73b0ac36517f2d5 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 23 Feb 2024 13:40:23 -0800 Subject: [PATCH 20/74] correct_empty_delimiters --- compiler/qsc_parse/src/lex/formatter/tests.rs | 71 +++++++++++++------ 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter/tests.rs b/compiler/qsc_parse/src/lex/formatter/tests.rs index 455de46e47..7eac7c6085 100644 --- a/compiler/qsc_parse/src/lex/formatter/tests.rs +++ b/compiler/qsc_parse/src/lex/formatter/tests.rs @@ -196,38 +196,68 @@ fn correct_indentation() { } #[test] -fn test_braces() { - let code = indoc! {r#" - operation Foo() : Unit {} +fn correct_empty_delimiters() { + check( + indoc! {r#" + operation Foo() : Unit { + } operation Bar() : Unit { - operation Baz() : Unit {} + operation Baz() : Unit { } + let x = { + + }; + let y : Int[] = [ ]; + let z = ( + + ); } - "#}; - let edits = super::format(code); - expect![[r#" + "#}, + &expect![[r#" [ Edit { span: Span { lo: 24, - hi: 24, + hi: 25, }, - new_text: "\n", + new_text: "", }, Edit { span: Span { - lo: 79, - hi: 79, + lo: 80, + hi: 83, }, - new_text: "\n ", + new_text: "", + }, + Edit { + span: Span { + lo: 98, + hi: 104, + }, + new_text: "", + }, + Edit { + span: Span { + lo: 128, + hi: 129, + }, + new_text: "", + }, + Edit { + span: Span { + lo: 145, + hi: 152, + }, + new_text: "", }, ] - "#]] - .assert_debug_eq(&edits); + "#]], + ); } #[test] -fn test_formatting_2() { - let code = indoc! {r#" +fn test_sample() { + check( + indoc! {r#" /// # Sample /// Joint Measurement /// @@ -269,10 +299,9 @@ fn test_formatting_2() { return (parityResult, [firstQubitResult, secondQubitResult]); } } - "#}; - let edits = super::format(code); - expect![[r#" + "#}, + &expect![[r#" [] - "#]] - .assert_debug_eq(&edits); + "#]], + ); } From a0a908803dc078d1e5397be35d6a6dce24948618 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 23 Feb 2024 14:51:32 -0800 Subject: [PATCH 21/74] . --- compiler/qsc_parse/src/lex/formatter.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 73498fe408..cd008eea50 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -5,9 +5,7 @@ use crate::keyword::Keyword; use super::{ concrete::{self, ConcreteToken, ConcreteTokenKind}, - //raw::{Lexer, Single, TokenKind}, - Delim, - TokenKind, + Delim, TokenKind, }; use qsc_data_structures::span::Span; From a2c40244fe1bad9c7ba8fb2903d993298fb54b2a Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 26 Feb 2024 10:59:21 -0800 Subject: [PATCH 22/74] aliased ConcreteTokenKind for readability --- compiler/qsc_parse/src/lex/formatter.rs | 39 ++++++++++--------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index cd008eea50..4587bed3c7 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -4,7 +4,7 @@ use crate::keyword::Keyword; use super::{ - concrete::{self, ConcreteToken, ConcreteTokenKind}, + concrete::{self, ConcreteToken, ConcreteTokenKind as CTK}, Delim, TokenKind, }; use qsc_data_structures::span::Span; @@ -53,22 +53,22 @@ pub fn format(code: &str) -> Vec { let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { // if the token is a {, increase the indent level - if let ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)) = one.kind { + if let CTK::Cooked(TokenKind::Open(Delim::Brace)) = one.kind { indent_level += 1; } // if the token is a }, decrease the indent level - if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = one.kind { + if let CTK::Cooked(TokenKind::Close(Delim::Brace)) = one.kind { #[allow(clippy::implicit_saturating_sub)] if indent_level > 0 { indent_level -= 1; } } - if let ConcreteTokenKind::WhiteSpace = one.kind { + if let CTK::WhiteSpace = one.kind { // first token is whitespace, continue scanning continue; - } else if let ConcreteTokenKind::WhiteSpace = two.kind { + } else if let CTK::WhiteSpace = two.kind { // whitespace in the middle apply_rules( one, @@ -131,8 +131,7 @@ fn apply_rules( // when we get here, neither left nor right should be whitespace // if the right is a close brace, the indent level should be one less - let indent_level = if let ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)) = right.kind - { + let indent_level = if let CTK::Cooked(TokenKind::Close(Delim::Brace)) = right.kind { if indent_level > 0 { indent_level - 1 } else { @@ -143,18 +142,15 @@ fn apply_rules( }; match (&left.kind, &right.kind) { - ( - ConcreteTokenKind::Cooked(TokenKind::Open(l)), - ConcreteTokenKind::Cooked(TokenKind::Close(r)), - ) if l == r => { + (CTK::Cooked(TokenKind::Open(l)), CTK::Cooked(TokenKind::Close(r))) if l == r => { rule_no_space(left, whitespace, right, &mut edits); } - (ConcreteTokenKind::Comment | ConcreteTokenKind::Cooked(TokenKind::DocComment), _) => { + (CTK::Comment | CTK::Cooked(TokenKind::DocComment), _) => { rule_trim_comments(left, &mut edits, code); rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (ConcreteTokenKind::Cooked(TokenKind::Semi), _) => match &right.kind { - ConcreteTokenKind::Comment => { + (CTK::Cooked(TokenKind::Semi), _) => match &right.kind { + CTK::Comment => { if whitespace.contains('\n') { rule_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -163,30 +159,27 @@ fn apply_rules( rule_indentation(left, whitespace, right, &mut edits, indent_level); } }, - (_, ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace))) => { + (_, CTK::Cooked(TokenKind::Close(Delim::Brace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } ( _, - ConcreteTokenKind::Cooked(TokenKind::Keyword( + CTK::Cooked(TokenKind::Keyword( Keyword::Operation | Keyword::Function | Keyword::Newtype | Keyword::Namespace, )), ) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (ConcreteTokenKind::Cooked(TokenKind::Open(Delim::Brace)), _) => { + (CTK::Cooked(TokenKind::Open(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - ( - ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), - ConcreteTokenKind::Cooked(TokenKind::Semi), - ) => { + (CTK::Cooked(TokenKind::Close(Delim::Brace)), CTK::Cooked(TokenKind::Semi)) => { rule_no_space(left, whitespace, right, &mut edits); } - (ConcreteTokenKind::Cooked(TokenKind::Close(Delim::Brace)), _) => { + (CTK::Cooked(TokenKind::Close(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (ConcreteTokenKind::Cooked(cooked_left), ConcreteTokenKind::Cooked(cooked_right)) => { + (CTK::Cooked(cooked_left), CTK::Cooked(cooked_right)) => { match (cooked_left, cooked_right) { (TokenKind::Ident, TokenKind::Ident) | (TokenKind::Keyword(_), TokenKind::Ident) From 3b4fbcc2459d2a092014da53333d2f1c5c01aeff Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 26 Feb 2024 14:38:33 -0800 Subject: [PATCH 23/74] match restructuring --- compiler/qsc_parse/src/lex/formatter.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 4587bed3c7..d4647ce81d 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -162,12 +162,10 @@ fn apply_rules( (_, CTK::Cooked(TokenKind::Close(Delim::Brace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - ( - _, - CTK::Cooked(TokenKind::Keyword( - Keyword::Operation | Keyword::Function | Keyword::Newtype | Keyword::Namespace, - )), - ) => { + (_, CTK::Cooked(TokenKind::Keyword(Keyword::Operation))) + | (_, CTK::Cooked(TokenKind::Keyword(Keyword::Function))) + | (_, CTK::Cooked(TokenKind::Keyword(Keyword::Newtype))) + | (_, CTK::Cooked(TokenKind::Keyword(Keyword::Namespace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } (CTK::Cooked(TokenKind::Open(Delim::Brace)), _) => { From 51e118f33a60ec9035bb4589141fbc2db55dc618 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 27 Feb 2024 10:56:08 -0800 Subject: [PATCH 24/74] rename Cooked to Syntax --- compiler/qsc_parse/src/lex/concrete.rs | 4 ++-- compiler/qsc_parse/src/lex/formatter.rs | 30 ++++++++++++------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index d1b311b480..037b56fefb 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -14,7 +14,7 @@ pub(super) struct ConcreteToken { #[derive(Debug, PartialEq)] pub(super) enum ConcreteTokenKind { - Cooked(cooked::TokenKind), + Syntax(cooked::TokenKind), Error(cooked::Error), WhiteSpace, Comment, @@ -92,7 +92,7 @@ impl Iterator for ConcreteTokenIterator<'_> { let next_lo = self.get_next_lo(); self.get_tokens_from_span(token.span.hi, next_lo); Some(ConcreteToken { - kind: ConcreteTokenKind::Cooked(token.kind), + kind: ConcreteTokenKind::Syntax(token.kind), span: token.span, }) } diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index d4647ce81d..a9d0ce31a5 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -53,12 +53,12 @@ pub fn format(code: &str) -> Vec { let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { // if the token is a {, increase the indent level - if let CTK::Cooked(TokenKind::Open(Delim::Brace)) = one.kind { + if let CTK::Syntax(TokenKind::Open(Delim::Brace)) = one.kind { indent_level += 1; } // if the token is a }, decrease the indent level - if let CTK::Cooked(TokenKind::Close(Delim::Brace)) = one.kind { + if let CTK::Syntax(TokenKind::Close(Delim::Brace)) = one.kind { #[allow(clippy::implicit_saturating_sub)] if indent_level > 0 { indent_level -= 1; @@ -131,7 +131,7 @@ fn apply_rules( // when we get here, neither left nor right should be whitespace // if the right is a close brace, the indent level should be one less - let indent_level = if let CTK::Cooked(TokenKind::Close(Delim::Brace)) = right.kind { + let indent_level = if let CTK::Syntax(TokenKind::Close(Delim::Brace)) = right.kind { if indent_level > 0 { indent_level - 1 } else { @@ -142,14 +142,14 @@ fn apply_rules( }; match (&left.kind, &right.kind) { - (CTK::Cooked(TokenKind::Open(l)), CTK::Cooked(TokenKind::Close(r))) if l == r => { + (CTK::Syntax(TokenKind::Open(l)), CTK::Syntax(TokenKind::Close(r))) if l == r => { rule_no_space(left, whitespace, right, &mut edits); } - (CTK::Comment | CTK::Cooked(TokenKind::DocComment), _) => { + (CTK::Comment | CTK::Syntax(TokenKind::DocComment), _) => { rule_trim_comments(left, &mut edits, code); rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Cooked(TokenKind::Semi), _) => match &right.kind { + (CTK::Syntax(TokenKind::Semi), _) => match &right.kind { CTK::Comment => { if whitespace.contains('\n') { rule_indentation(left, whitespace, right, &mut edits, indent_level); @@ -159,25 +159,25 @@ fn apply_rules( rule_indentation(left, whitespace, right, &mut edits, indent_level); } }, - (_, CTK::Cooked(TokenKind::Close(Delim::Brace))) => { + (_, CTK::Syntax(TokenKind::Close(Delim::Brace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (_, CTK::Cooked(TokenKind::Keyword(Keyword::Operation))) - | (_, CTK::Cooked(TokenKind::Keyword(Keyword::Function))) - | (_, CTK::Cooked(TokenKind::Keyword(Keyword::Newtype))) - | (_, CTK::Cooked(TokenKind::Keyword(Keyword::Namespace))) => { + (_, CTK::Syntax(TokenKind::Keyword(Keyword::Operation))) + | (_, CTK::Syntax(TokenKind::Keyword(Keyword::Function))) + | (_, CTK::Syntax(TokenKind::Keyword(Keyword::Newtype))) + | (_, CTK::Syntax(TokenKind::Keyword(Keyword::Namespace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Cooked(TokenKind::Open(Delim::Brace)), _) => { + (CTK::Syntax(TokenKind::Open(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Cooked(TokenKind::Close(Delim::Brace)), CTK::Cooked(TokenKind::Semi)) => { + (CTK::Syntax(TokenKind::Close(Delim::Brace)), CTK::Syntax(TokenKind::Semi)) => { rule_no_space(left, whitespace, right, &mut edits); } - (CTK::Cooked(TokenKind::Close(Delim::Brace)), _) => { + (CTK::Syntax(TokenKind::Close(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Cooked(cooked_left), CTK::Cooked(cooked_right)) => { + (CTK::Syntax(cooked_left), CTK::Syntax(cooked_right)) => { match (cooked_left, cooked_right) { (TokenKind::Ident, TokenKind::Ident) | (TokenKind::Keyword(_), TokenKind::Ident) From ae1955435022d9c97493af34f67a4cb0337a3b68 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 27 Feb 2024 11:00:16 -0800 Subject: [PATCH 25/74] deal with todo's --- compiler/qsc_parse/src/lex/concrete.rs | 3 ++- compiler/qsc_parse/src/lex/formatter.rs | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 037b56fefb..d33a5ca7eb 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -83,7 +83,8 @@ impl Iterator for ConcreteTokenIterator<'_> { kind: ConcreteTokenKind::WhiteSpace, span, }, - _ => panic!("only comments and whitespace should be non-compilable tokens"), // Todo: might need better handling + // This will panic if any content other than whitespace or comments are ignored when "cooking" the raw tokens + _ => panic!("only comments and whitespace should be non-compilable tokens"), }; Some(concrete) } diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index a9d0ce31a5..9cd7e71217 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -14,9 +14,7 @@ mod tests; #[derive(Debug)] pub struct Edit { - #[allow(dead_code)] // TODO: nobody's using this yet except for tests pub span: Span, - #[allow(dead_code)] // TODO: nobody's using this yet except for tests pub new_text: String, } @@ -39,7 +37,7 @@ pub fn format(code: &str) -> Vec { let mut indent_level = 0; - #[allow(unused_assignments)] // there's probably a better way of doing this, but this works + #[allow(unused_assignments)] let mut one = None; let mut two = None; let mut three = None; @@ -92,7 +90,6 @@ pub fn format(code: &str) -> Vec { } _ => { // not enough tokens to apply a rule - // TODO: we'll probably need to handle end-of-file cases here continue; } }; From d79ae4cec958145f6f8306e1250fa69db9ba0c06 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 27 Feb 2024 16:44:05 -0800 Subject: [PATCH 26/74] import enum variants directly --- compiler/qsc_parse/src/expr.rs | 6 +- compiler/qsc_parse/src/lex/cooked.rs | 14 +++-- compiler/qsc_parse/src/lex/cooked/tests.rs | 2 +- compiler/qsc_parse/src/lex/formatter.rs | 69 ++++++++++------------ 4 files changed, 44 insertions(+), 47 deletions(-) diff --git a/compiler/qsc_parse/src/expr.rs b/compiler/qsc_parse/src/expr.rs index cbe5d695cd..d3f825c4f1 100644 --- a/compiler/qsc_parse/src/expr.rs +++ b/compiler/qsc_parse/src/expr.rs @@ -317,7 +317,7 @@ fn expr_range_prefix(s: &mut Scanner) -> Result> { fn expr_interpolate(s: &mut Scanner) -> Result> { let token = s.peek(); - let TokenKind::String(StringToken::Interpolated(InterpolatedStart::DollarQuote, mut end)) = + let TokenKind::StringToken(StringToken::Interpolated(InterpolatedStart::DollarQuote, mut end)) = token.kind else { return Err(Error(ErrorKind::Rule( @@ -338,7 +338,7 @@ fn expr_interpolate(s: &mut Scanner) -> Result> { components.push(StringComponent::Expr(expr(s)?)); let token = s.peek(); - let TokenKind::String(StringToken::Interpolated(InterpolatedStart::RBrace, next_end)) = + let TokenKind::StringToken(StringToken::Interpolated(InterpolatedStart::RBrace, next_end)) = token.kind else { return Err(Error(ErrorKind::Rule( @@ -400,7 +400,7 @@ fn lit_token(lexeme: &str, token: Token) -> Result> { .ok_or(Error(ErrorKind::Lit("integer", token.span)))?; Ok(Some(Lit::Int(value))) } - TokenKind::String(StringToken::Normal) => { + TokenKind::StringToken(StringToken::Normal) => { let lexeme = shorten(1, 1, lexeme); let string = unescape(lexeme).map_err(|index| { let ch = lexeme[index + 1..] diff --git a/compiler/qsc_parse/src/lex/cooked.rs b/compiler/qsc_parse/src/lex/cooked.rs index b41b1cc561..6b74f6241b 100644 --- a/compiler/qsc_parse/src/lex/cooked.rs +++ b/compiler/qsc_parse/src/lex/cooked.rs @@ -148,7 +148,7 @@ pub(crate) enum TokenKind { /// `;` Semi, /// A string literal. - String(StringToken), + StringToken(StringToken), /// `~~~` TildeTildeTilde, /// `w/` @@ -197,7 +197,7 @@ impl Display for TokenKind { TokenKind::Question => f.write_str("`?`"), TokenKind::RArrow => f.write_str("`->`"), TokenKind::Semi => f.write_str("`;`"), - TokenKind::String(_) => f.write_str("string"), + TokenKind::StringToken(_) => f.write_str("string"), TokenKind::TildeTildeTilde => f.write_str("`~~~`"), TokenKind::WSlash => f.write_str("`w/`"), TokenKind::WSlashEq => f.write_str("`w/=`"), @@ -338,11 +338,13 @@ impl<'a> Lexer<'a> { raw::TokenKind::Number(number) => Ok(Some(number.into())), raw::TokenKind::Single(single) => self.single(single).map(Some), raw::TokenKind::String(raw::StringToken::Normal { terminated: true }) => { - Ok(Some(TokenKind::String(StringToken::Normal))) + Ok(Some(TokenKind::StringToken(StringToken::Normal))) + } + raw::TokenKind::String(raw::StringToken::Interpolated(start, Some(ending))) => { + Ok(Some(TokenKind::StringToken(StringToken::Interpolated( + start, ending, + )))) } - raw::TokenKind::String(raw::StringToken::Interpolated(start, Some(ending))) => Ok( - Some(TokenKind::String(StringToken::Interpolated(start, ending))), - ), raw::TokenKind::String( raw::StringToken::Normal { terminated: false } | raw::StringToken::Interpolated(_, None), diff --git a/compiler/qsc_parse/src/lex/cooked/tests.rs b/compiler/qsc_parse/src/lex/cooked/tests.rs index 3ffe487da1..7586f29fb4 100644 --- a/compiler/qsc_parse/src/lex/cooked/tests.rs +++ b/compiler/qsc_parse/src/lex/cooked/tests.rs @@ -53,7 +53,7 @@ fn op_string(kind: TokenKind) -> Option { | TokenKind::Ident | TokenKind::Int(_) | TokenKind::Keyword(_) - | TokenKind::String(_) => None, + | TokenKind::StringToken(_) => None, } } diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 9cd7e71217..81ef373a24 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -4,8 +4,9 @@ use crate::keyword::Keyword; use super::{ - concrete::{self, ConcreteToken, ConcreteTokenKind as CTK}, - Delim, TokenKind, + concrete::{self, ConcreteToken, ConcreteTokenKind::*}, + Delim, + TokenKind::*, }; use qsc_data_structures::span::Span; @@ -51,22 +52,22 @@ pub fn format(code: &str) -> Vec { let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { // if the token is a {, increase the indent level - if let CTK::Syntax(TokenKind::Open(Delim::Brace)) = one.kind { + if let Syntax(Open(Delim::Brace)) = one.kind { indent_level += 1; } // if the token is a }, decrease the indent level - if let CTK::Syntax(TokenKind::Close(Delim::Brace)) = one.kind { + if let Syntax(Close(Delim::Brace)) = one.kind { #[allow(clippy::implicit_saturating_sub)] if indent_level > 0 { indent_level -= 1; } } - if let CTK::WhiteSpace = one.kind { + if let WhiteSpace = one.kind { // first token is whitespace, continue scanning continue; - } else if let CTK::WhiteSpace = two.kind { + } else if let WhiteSpace = two.kind { // whitespace in the middle apply_rules( one, @@ -128,7 +129,7 @@ fn apply_rules( // when we get here, neither left nor right should be whitespace // if the right is a close brace, the indent level should be one less - let indent_level = if let CTK::Syntax(TokenKind::Close(Delim::Brace)) = right.kind { + let indent_level = if let Syntax(Close(Delim::Brace)) = right.kind { if indent_level > 0 { indent_level - 1 } else { @@ -139,15 +140,15 @@ fn apply_rules( }; match (&left.kind, &right.kind) { - (CTK::Syntax(TokenKind::Open(l)), CTK::Syntax(TokenKind::Close(r))) if l == r => { + (Syntax(Open(l)), Syntax(Close(r))) if l == r => { rule_no_space(left, whitespace, right, &mut edits); } - (CTK::Comment | CTK::Syntax(TokenKind::DocComment), _) => { + (Comment | Syntax(DocComment), _) => { rule_trim_comments(left, &mut edits, code); rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Syntax(TokenKind::Semi), _) => match &right.kind { - CTK::Comment => { + (Syntax(Semi), _) => match &right.kind { + Comment => { if whitespace.contains('\n') { rule_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -156,43 +157,37 @@ fn apply_rules( rule_indentation(left, whitespace, right, &mut edits, indent_level); } }, - (_, CTK::Syntax(TokenKind::Close(Delim::Brace))) => { + (_, Syntax(Close(Delim::Brace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (_, CTK::Syntax(TokenKind::Keyword(Keyword::Operation))) - | (_, CTK::Syntax(TokenKind::Keyword(Keyword::Function))) - | (_, CTK::Syntax(TokenKind::Keyword(Keyword::Newtype))) - | (_, CTK::Syntax(TokenKind::Keyword(Keyword::Namespace))) => { + (_, Syntax(Keyword(Keyword::Operation))) + | (_, Syntax(Keyword(Keyword::Function))) + | (_, Syntax(Keyword(Keyword::Newtype))) + | (_, Syntax(Keyword(Keyword::Namespace))) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Syntax(TokenKind::Open(Delim::Brace)), _) => { + (Syntax(Open(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Syntax(TokenKind::Close(Delim::Brace)), CTK::Syntax(TokenKind::Semi)) => { + (Syntax(Close(Delim::Brace)), Syntax(Semi)) => { rule_no_space(left, whitespace, right, &mut edits); } - (CTK::Syntax(TokenKind::Close(Delim::Brace)), _) => { + (Syntax(Close(Delim::Brace)), _) => { rule_indentation(left, whitespace, right, &mut edits, indent_level); } - (CTK::Syntax(cooked_left), CTK::Syntax(cooked_right)) => { - match (cooked_left, cooked_right) { - (TokenKind::Ident, TokenKind::Ident) - | (TokenKind::Keyword(_), TokenKind::Ident) - | (_, TokenKind::Colon) - | (TokenKind::Colon, _) - | (TokenKind::Comma, _) => { - rule_single_space(left, whitespace, right, &mut edits); - } - (TokenKind::Ident, TokenKind::Open(Delim::Paren)) - | (TokenKind::Ident, TokenKind::Open(Delim::Bracket)) - | (TokenKind::Ident, TokenKind::Comma) - | (TokenKind::Open(_), _) - | (_, TokenKind::Close(_)) => { - rule_no_space(left, whitespace, right, &mut edits); - } - _ => {} + (Syntax(cooked_left), Syntax(cooked_right)) => match (cooked_left, cooked_right) { + (Ident, Ident) | (Keyword(_), Ident) | (_, Colon) | (Colon, _) | (Comma, _) => { + rule_single_space(left, whitespace, right, &mut edits); } - } + (Ident, Open(Delim::Paren)) + | (Ident, Open(Delim::Bracket)) + | (Ident, Comma) + | (Open(_), _) + | (_, Close(_)) => { + rule_no_space(left, whitespace, right, &mut edits); + } + _ => {} + }, _ => {} } From f2f09d146391914cbad99ff9b88eb026881ac3e7 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 28 Feb 2024 10:27:16 -0800 Subject: [PATCH 27/74] Added documentation explaining the concrete tokens and the formatter algo --- compiler/qsc_parse/src/lex/concrete.rs | 12 ++++++++++++ compiler/qsc_parse/src/lex/formatter.rs | 13 ++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index d33a5ca7eb..4b1578e7df 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -7,11 +7,16 @@ use qsc_data_structures::span::Span; use super::{cooked, raw}; +/// This struct extends cooked tokens to include whitespace and comment tokens. +/// Whitespace and comment tokens were removed during the creation of cooked tokens +/// because they are generally not useful for compilation, but they are reintroduced +/// here because they are needed for formatting. pub(super) struct ConcreteToken { pub kind: ConcreteTokenKind, pub span: Span, } +/// This enum extends the cooked token kind to include whitespace and comment token kinds. #[derive(Debug, PartialEq)] pub(super) enum ConcreteTokenKind { Syntax(cooked::TokenKind), @@ -20,6 +25,13 @@ pub(super) enum ConcreteTokenKind { Comment, } +/// This is an iterator over ConcreteTokens, creating the tokens from a source str. +/// It works by running the cooked lexer on the source str, and iterating over +/// those cooked tokens. Whenever adjacent cooked tokens are found to have a gap +/// between their spans, the raw lexer is run on that slice of the source str to +/// generate the raw tokens (which should only produce the non-compilation whitespace +/// and comment tokens) for that slice, which are iterated over before continuing +/// with the cooked tokens. pub(super) struct ConcreteTokenIterator<'a> { code: &'a str, cooked_tokens: Peekable>, diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_parse/src/lex/formatter.rs index 81ef373a24..aa31a51199 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_parse/src/lex/formatter.rs @@ -1,6 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +/// This module contains the Q# formatter, which can be used by calling +/// the format function available from this module. The formatting algorithm +/// uses the cooked and concrete tokens from the parser crate to create a +/// token stream of the given source code string. It then uses a sliding window +/// over this token stream to apply formatting rules when the selected tokens +/// match certain patterns. Formatting rules will generate text edit objects +/// when the format of the input string does not match the expected format, and +/// these edits are returned on using the formatter. use crate::keyword::Keyword; use super::{ @@ -32,19 +40,22 @@ fn make_indent_string(level: usize) -> String { " ".repeat(level) } +/// Applies formatting rules to the given code str, generating edits where +/// the source code needs to be changed to comply with the format rules. pub fn format(code: &str) -> Vec { let tokens = concrete::ConcreteTokenIterator::new(code); let mut edits = vec![]; let mut indent_level = 0; + // The sliding window used is over three adjacent tokens #[allow(unused_assignments)] let mut one = None; let mut two = None; let mut three = None; for token in tokens { - // Advance the trio of tokens + // Advance the token window one = two; two = three; three = Some(token); From 745fde48852f34c2fabe23bfc3bbbcb9e192fa91 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 28 Feb 2024 11:17:50 -0800 Subject: [PATCH 28/74] Make qsc_formatter a separate crate. --- Cargo.lock | 11 ++++++++++ compiler/qsc/Cargo.toml | 1 + compiler/qsc/src/lib.rs | 2 +- compiler/qsc_formatter/Cargo.toml | 20 +++++++++++++++++++ .../lex => qsc_formatter/src}/formatter.rs | 9 ++++----- .../src}/formatter/tests.rs | 0 compiler/qsc_formatter/src/lib.rs | 4 ++++ compiler/qsc_frontend/src/lib.rs | 3 ++- compiler/qsc_parse/src/keyword.rs | 2 +- compiler/qsc_parse/src/lex.rs | 15 +++++++------- compiler/qsc_parse/src/lex/concrete.rs | 8 ++++---- compiler/qsc_parse/src/lex/cooked.rs | 8 ++++---- compiler/qsc_parse/src/lex/raw.rs | 6 +++--- compiler/qsc_parse/src/lib.rs | 5 ++--- 14 files changed, 64 insertions(+), 30 deletions(-) create mode 100644 compiler/qsc_formatter/Cargo.toml rename compiler/{qsc_parse/src/lex => qsc_formatter/src}/formatter.rs (98%) rename compiler/{qsc_parse/src/lex => qsc_formatter/src}/formatter/tests.rs (100%) create mode 100644 compiler/qsc_formatter/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index de87751fd5..74239e2d1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,6 +905,7 @@ dependencies = [ "qsc_doc_gen", "qsc_eval", "qsc_fir", + "qsc_formatter", "qsc_frontend", "qsc_hir", "qsc_passes", @@ -990,6 +991,16 @@ dependencies = [ "rustc-hash", ] +[[package]] +name = "qsc_formatter" +version = "0.0.0" +dependencies = [ + "expect-test", + "indoc", + "qsc_data_structures", + "qsc_frontend", +] + [[package]] name = "qsc_frontend" version = "0.0.0" diff --git a/compiler/qsc/Cargo.toml b/compiler/qsc/Cargo.toml index 6f700704df..5d464ca88d 100644 --- a/compiler/qsc/Cargo.toml +++ b/compiler/qsc/Cargo.toml @@ -19,6 +19,7 @@ num-complex = { workspace = true } qsc_codegen = { path = "../qsc_codegen" } qsc_data_structures = { path = "../qsc_data_structures" } qsc_doc_gen = { path = "../qsc_doc_gen" } +qsc_formatter = { path = "../qsc_formatter" } qsc_eval = { path = "../qsc_eval" } qsc_frontend = { path = "../qsc_frontend" } qsc_ast = { path = "../qsc_ast" } diff --git a/compiler/qsc/src/lib.rs b/compiler/qsc/src/lib.rs index 1bf4c3e34d..cdbac3a183 100644 --- a/compiler/qsc/src/lib.rs +++ b/compiler/qsc/src/lib.rs @@ -11,7 +11,7 @@ pub mod interpret; pub mod location; pub mod target; -pub use qsc_frontend::formatter; +pub use qsc_formatter::formatter; pub use qsc_frontend::compile::{ CompileUnit, PackageStore, RuntimeCapabilityFlags, SourceContents, SourceMap, SourceName, diff --git a/compiler/qsc_formatter/Cargo.toml b/compiler/qsc_formatter/Cargo.toml new file mode 100644 index 0000000000..9bc0f7544f --- /dev/null +++ b/compiler/qsc_formatter/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "qsc_formatter" + +version.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +qsc_data_structures = { path = "../qsc_data_structures" } +qsc_frontend = { path = "../qsc_frontend" } + +[dev-dependencies] +expect-test = { workspace = true } +indoc = { workspace = true } + +[lib] +doctest = false diff --git a/compiler/qsc_parse/src/lex/formatter.rs b/compiler/qsc_formatter/src/formatter.rs similarity index 98% rename from compiler/qsc_parse/src/lex/formatter.rs rename to compiler/qsc_formatter/src/formatter.rs index aa31a51199..07831119c1 100644 --- a/compiler/qsc_parse/src/lex/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -9,14 +9,13 @@ /// match certain patterns. Formatting rules will generate text edit objects /// when the format of the input string does not match the expected format, and /// these edits are returned on using the formatter. -use crate::keyword::Keyword; - -use super::{ +use qsc_data_structures::span::Span; +use qsc_frontend::keyword::Keyword; +use qsc_frontend::lex::{ concrete::{self, ConcreteToken, ConcreteTokenKind::*}, + cooked::TokenKind::*, Delim, - TokenKind::*, }; -use qsc_data_structures::span::Span; #[cfg(test)] mod tests; diff --git a/compiler/qsc_parse/src/lex/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs similarity index 100% rename from compiler/qsc_parse/src/lex/formatter/tests.rs rename to compiler/qsc_formatter/src/formatter/tests.rs diff --git a/compiler/qsc_formatter/src/lib.rs b/compiler/qsc_formatter/src/lib.rs new file mode 100644 index 0000000000..8c0d63bfc8 --- /dev/null +++ b/compiler/qsc_formatter/src/lib.rs @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +pub mod formatter; diff --git a/compiler/qsc_frontend/src/lib.rs b/compiler/qsc_frontend/src/lib.rs index f641490e4c..6e25066bd3 100644 --- a/compiler/qsc_frontend/src/lib.rs +++ b/compiler/qsc_frontend/src/lib.rs @@ -12,4 +12,5 @@ mod lower; pub mod resolve; pub mod typeck; -pub use qsc_parse::formatter; +pub use qsc_parse::keyword; +pub use qsc_parse::lex; diff --git a/compiler/qsc_parse/src/keyword.rs b/compiler/qsc_parse/src/keyword.rs index 22ab75ef15..2a808e7806 100644 --- a/compiler/qsc_parse/src/keyword.rs +++ b/compiler/qsc_parse/src/keyword.rs @@ -8,7 +8,7 @@ use std::{ }; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Sequence)] -pub(super) enum Keyword { +pub enum Keyword { Adj, Adjoint, AdjointUpper, diff --git a/compiler/qsc_parse/src/lex.rs b/compiler/qsc_parse/src/lex.rs index ab361a3148..96bfd98781 100644 --- a/compiler/qsc_parse/src/lex.rs +++ b/compiler/qsc_parse/src/lex.rs @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -mod concrete; -mod cooked; -pub mod formatter; -mod raw; +pub mod concrete; +pub mod cooked; +pub mod raw; use enum_iterator::Sequence; @@ -12,7 +11,7 @@ pub(super) use cooked::{ClosedBinOp, Error, Lexer, StringToken, Token, TokenKind /// A delimiter token. #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(super) enum Delim { +pub enum Delim { /// `{` or `}` Brace, /// `[` or `]` @@ -22,7 +21,7 @@ pub(super) enum Delim { } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(super) enum Radix { +pub enum Radix { Binary, Octal, Decimal, @@ -41,13 +40,13 @@ impl From for u32 { } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(super) enum InterpolatedStart { +pub enum InterpolatedStart { DollarQuote, RBrace, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(super) enum InterpolatedEnding { +pub enum InterpolatedEnding { Quote, LBrace, } diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 4b1578e7df..cb6f4165fb 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -11,14 +11,14 @@ use super::{cooked, raw}; /// Whitespace and comment tokens were removed during the creation of cooked tokens /// because they are generally not useful for compilation, but they are reintroduced /// here because they are needed for formatting. -pub(super) struct ConcreteToken { +pub struct ConcreteToken { pub kind: ConcreteTokenKind, pub span: Span, } /// This enum extends the cooked token kind to include whitespace and comment token kinds. #[derive(Debug, PartialEq)] -pub(super) enum ConcreteTokenKind { +pub enum ConcreteTokenKind { Syntax(cooked::TokenKind), Error(cooked::Error), WhiteSpace, @@ -32,14 +32,14 @@ pub(super) enum ConcreteTokenKind { /// generate the raw tokens (which should only produce the non-compilation whitespace /// and comment tokens) for that slice, which are iterated over before continuing /// with the cooked tokens. -pub(super) struct ConcreteTokenIterator<'a> { +pub struct ConcreteTokenIterator<'a> { code: &'a str, cooked_tokens: Peekable>, non_compilation_tokens: Peekable>, } impl<'a> ConcreteTokenIterator<'a> { - pub(super) fn new(code: &'a str) -> Self { + pub fn new(code: &'a str) -> Self { Self { code, cooked_tokens: cooked::Lexer::new(code).peekable(), diff --git a/compiler/qsc_parse/src/lex/cooked.rs b/compiler/qsc_parse/src/lex/cooked.rs index 6b74f6241b..fb95fb955e 100644 --- a/compiler/qsc_parse/src/lex/cooked.rs +++ b/compiler/qsc_parse/src/lex/cooked.rs @@ -35,7 +35,7 @@ pub(crate) struct Token { } #[derive(Clone, Copy, Debug, Diagnostic, Eq, Error, PartialEq)] -pub(crate) enum Error { +pub enum Error { #[error("expected {0} to complete {1}, found {2}")] #[diagnostic(code("Qsc.Lex.Incomplete"))] Incomplete(raw::TokenKind, TokenKind, raw::TokenKind, #[label] Span), @@ -79,7 +79,7 @@ impl Error { /// A token kind. #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum TokenKind { +pub enum TokenKind { /// `'T` /// used for generic parameters -- an apostrophe followed by an ident. AposIdent, @@ -219,7 +219,7 @@ impl From for TokenKind { /// the domain of the first operand is closed under this operation. These are candidates for /// compound assignment operators, like `+=`. #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum ClosedBinOp { +pub enum ClosedBinOp { /// `&&&` AmpAmpAmp, /// `and` @@ -269,7 +269,7 @@ impl Display for ClosedBinOp { } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum StringToken { +pub enum StringToken { Normal, Interpolated(InterpolatedStart, InterpolatedEnding), } diff --git a/compiler/qsc_parse/src/lex/raw.rs b/compiler/qsc_parse/src/lex/raw.rs index 8d20fb2df5..a9610649bc 100644 --- a/compiler/qsc_parse/src/lex/raw.rs +++ b/compiler/qsc_parse/src/lex/raw.rs @@ -62,7 +62,7 @@ impl Display for TokenKind { /// A single-character operator token. #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum Single { +pub enum Single { /// `&` Amp, /// `'` @@ -143,14 +143,14 @@ impl Display for Single { } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum Number { +pub enum Number { BigInt(Radix), Float, Int(Radix), } #[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)] -pub(crate) enum StringToken { +pub enum StringToken { Normal { terminated: bool }, Interpolated(InterpolatedStart, Option), } diff --git a/compiler/qsc_parse/src/lib.rs b/compiler/qsc_parse/src/lib.rs index 2937de57f5..e8963a9dbc 100644 --- a/compiler/qsc_parse/src/lib.rs +++ b/compiler/qsc_parse/src/lib.rs @@ -7,8 +7,8 @@ mod expr; mod item; -mod keyword; -mod lex; +pub mod keyword; +pub mod lex; mod prim; mod scan; mod stmt; @@ -16,7 +16,6 @@ mod stmt; mod tests; mod ty; -pub use lex::formatter; use lex::TokenKind; use miette::Diagnostic; use qsc_ast::ast::{Expr, Namespace, TopLevelNode}; From 5ab50c6350c27f4b724799872b18eb34d246c8c3 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 28 Feb 2024 12:07:37 -0800 Subject: [PATCH 29/74] merge fix up --- npm/src/language-service/language-service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/npm/src/language-service/language-service.ts b/npm/src/language-service/language-service.ts index e1e00a96d2..d3fa166214 100644 --- a/npm/src/language-service/language-service.ts +++ b/npm/src/language-service/language-service.ts @@ -280,6 +280,7 @@ export const languageServiceProtocol: ServiceProtocol< closeDocument: "request", closeNotebookDocument: "request", getCompletions: "request", + getFormatChanges: "request", getHover: "request", getDefinition: "request", getReferences: "request", From 77f72ff5eafb39c91cdf62f0ffd90eb19554f8a0 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 28 Feb 2024 16:01:21 -0800 Subject: [PATCH 30/74] fixed tests to say "StringToken" instead of "String" --- compiler/qsc_parse/src/lex/cooked/tests.rs | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/qsc_parse/src/lex/cooked/tests.rs b/compiler/qsc_parse/src/lex/cooked/tests.rs index 7586f29fb4..f0169c0886 100644 --- a/compiler/qsc_parse/src/lex/cooked/tests.rs +++ b/compiler/qsc_parse/src/lex/cooked/tests.rs @@ -929,7 +929,7 @@ fn string() { [ Ok( Token { - kind: String( + kind: StringToken( Normal, ), span: Span { @@ -951,7 +951,7 @@ fn string_empty() { [ Ok( Token { - kind: String( + kind: StringToken( Normal, ), span: Span { @@ -1011,7 +1011,7 @@ fn interpolated_string() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, Quote, @@ -1036,7 +1036,7 @@ fn interpolated_string_braced() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1059,7 +1059,7 @@ fn interpolated_string_braced() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1084,7 +1084,7 @@ fn interpolated_string_escape_brace() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, Quote, @@ -1109,7 +1109,7 @@ fn interpolated_string_unclosed_brace() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1134,7 +1134,7 @@ fn interpolated_string_unclosed_brace_quote() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1186,7 +1186,7 @@ fn interpolated_string_unopened_brace_quote() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, Quote, @@ -1211,7 +1211,7 @@ fn interpolated_string_braced_index() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1267,7 +1267,7 @@ fn interpolated_string_braced_index() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1292,7 +1292,7 @@ fn interpolated_string_two_braced() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1315,7 +1315,7 @@ fn interpolated_string_two_braced() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, LBrace, @@ -1338,7 +1338,7 @@ fn interpolated_string_two_braced() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1363,7 +1363,7 @@ fn interpolated_string_braced_normal_string() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1377,7 +1377,7 @@ fn interpolated_string_braced_normal_string() { ), Ok( Token { - kind: String( + kind: StringToken( Normal, ), span: Span { @@ -1388,7 +1388,7 @@ fn interpolated_string_braced_normal_string() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1413,7 +1413,7 @@ fn nested_interpolated_string() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1427,7 +1427,7 @@ fn nested_interpolated_string() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1450,7 +1450,7 @@ fn nested_interpolated_string() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1464,7 +1464,7 @@ fn nested_interpolated_string() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1489,7 +1489,7 @@ fn nested_interpolated_string_with_exprs() { [ Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1523,7 +1523,7 @@ fn nested_interpolated_string_with_exprs() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( DollarQuote, LBrace, @@ -1546,7 +1546,7 @@ fn nested_interpolated_string_with_exprs() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, @@ -1560,7 +1560,7 @@ fn nested_interpolated_string_with_exprs() { ), Ok( Token { - kind: String( + kind: StringToken( Interpolated( RBrace, Quote, From 98fa0eb8bf9d572926af8c12f8a628ac81817aa6 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 29 Feb 2024 10:08:13 -0800 Subject: [PATCH 31/74] Moved doc string for crate. --- compiler/qsc_formatter/src/formatter.rs | 8 -------- compiler/qsc_formatter/src/lib.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 07831119c1..de7b0e0a3d 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -1,14 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -/// This module contains the Q# formatter, which can be used by calling -/// the format function available from this module. The formatting algorithm -/// uses the cooked and concrete tokens from the parser crate to create a -/// token stream of the given source code string. It then uses a sliding window -/// over this token stream to apply formatting rules when the selected tokens -/// match certain patterns. Formatting rules will generate text edit objects -/// when the format of the input string does not match the expected format, and -/// these edits are returned on using the formatter. use qsc_data_structures::span::Span; use qsc_frontend::keyword::Keyword; use qsc_frontend::lex::{ diff --git a/compiler/qsc_formatter/src/lib.rs b/compiler/qsc_formatter/src/lib.rs index 8c0d63bfc8..dcfeb86981 100644 --- a/compiler/qsc_formatter/src/lib.rs +++ b/compiler/qsc_formatter/src/lib.rs @@ -1,4 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +//! This module contains the Q# formatter, which can be used by calling +//! the format function available from this module. The formatting algorithm +//! uses the cooked and concrete tokens from the parser crate to create a +//! token stream of the given source code string. It then uses a sliding window +//! over this token stream to apply formatting rules when the selected tokens +//! match certain patterns. Formatting rules will generate text edit objects +//! when the format of the input string does not match the expected format, and +//! these edits are returned on using the formatter. + pub mod formatter; From c0a5de447bebb209945105ec051ba24ea491b180 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 29 Feb 2024 11:11:39 -0800 Subject: [PATCH 32/74] moved enum use statements to the match statement. --- compiler/qsc_formatter/src/formatter.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index de7b0e0a3d..f048c89ef2 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -2,10 +2,9 @@ // Licensed under the MIT License. use qsc_data_structures::span::Span; -use qsc_frontend::keyword::Keyword; use qsc_frontend::lex::{ - concrete::{self, ConcreteToken, ConcreteTokenKind::*}, - cooked::TokenKind::*, + concrete::{self, ConcreteToken, ConcreteTokenKind}, + cooked::TokenKind, Delim, }; @@ -54,22 +53,22 @@ pub fn format(code: &str) -> Vec { let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { // if the token is a {, increase the indent level - if let Syntax(Open(Delim::Brace)) = one.kind { + if let ConcreteTokenKind::Syntax(TokenKind::Open(Delim::Brace)) = one.kind { indent_level += 1; } // if the token is a }, decrease the indent level - if let Syntax(Close(Delim::Brace)) = one.kind { + if let ConcreteTokenKind::Syntax(TokenKind::Close(Delim::Brace)) = one.kind { #[allow(clippy::implicit_saturating_sub)] if indent_level > 0 { indent_level -= 1; } } - if let WhiteSpace = one.kind { + if let ConcreteTokenKind::WhiteSpace = one.kind { // first token is whitespace, continue scanning continue; - } else if let WhiteSpace = two.kind { + } else if let ConcreteTokenKind::WhiteSpace = two.kind { // whitespace in the middle apply_rules( one, @@ -141,6 +140,9 @@ fn apply_rules( indent_level }; + use qsc_frontend::keyword::Keyword; + use ConcreteTokenKind::*; + use TokenKind::*; match (&left.kind, &right.kind) { (Syntax(Open(l)), Syntax(Close(r))) if l == r => { rule_no_space(left, whitespace, right, &mut edits); From ae29d7ce27081194fd818c5d4fc00e26efb5daab Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 29 Feb 2024 12:24:59 -0800 Subject: [PATCH 33/74] use saturating_sub --- compiler/qsc_formatter/src/formatter.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index f048c89ef2..4dc6d64bb8 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -36,7 +36,7 @@ pub fn format(code: &str) -> Vec { let tokens = concrete::ConcreteTokenIterator::new(code); let mut edits = vec![]; - let mut indent_level = 0; + let mut indent_level: usize = 0; // The sliding window used is over three adjacent tokens #[allow(unused_assignments)] @@ -59,10 +59,7 @@ pub fn format(code: &str) -> Vec { // if the token is a }, decrease the indent level if let ConcreteTokenKind::Syntax(TokenKind::Close(Delim::Brace)) = one.kind { - #[allow(clippy::implicit_saturating_sub)] - if indent_level > 0 { - indent_level -= 1; - } + indent_level = indent_level.saturating_sub(1); } if let ConcreteTokenKind::WhiteSpace = one.kind { From 97d16215f7267905503dc01694ac0db58afba3e7 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 29 Feb 2024 15:13:57 -0800 Subject: [PATCH 34/74] minor changes --- compiler/qsc_formatter/src/formatter.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 4dc6d64bb8..e90d11acea 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -52,20 +52,19 @@ pub fn format(code: &str) -> Vec { let mut edits_for_triple = match (&one, &two, &three) { (Some(one), Some(two), Some(three)) => { - // if the token is a {, increase the indent level - if let ConcreteTokenKind::Syntax(TokenKind::Open(Delim::Brace)) = one.kind { - indent_level += 1; - } - - // if the token is a }, decrease the indent level - if let ConcreteTokenKind::Syntax(TokenKind::Close(Delim::Brace)) = one.kind { - indent_level = indent_level.saturating_sub(1); + match one.kind { + ConcreteTokenKind::Syntax(TokenKind::Open(Delim::Brace)) => indent_level += 1, + ConcreteTokenKind::Syntax(TokenKind::Close(Delim::Brace)) => { + indent_level = indent_level.saturating_sub(1) + } + ConcreteTokenKind::WhiteSpace => continue, + _ => {} } if let ConcreteTokenKind::WhiteSpace = one.kind { // first token is whitespace, continue scanning continue; - } else if let ConcreteTokenKind::WhiteSpace = two.kind { + } else if matches!(two.kind, ConcreteTokenKind::WhiteSpace) { // whitespace in the middle apply_rules( one, @@ -128,11 +127,7 @@ fn apply_rules( // if the right is a close brace, the indent level should be one less let indent_level = if let Syntax(Close(Delim::Brace)) = right.kind { - if indent_level > 0 { - indent_level - 1 - } else { - indent_level - } + indent_level.saturating_sub(1) } else { indent_level }; From bd2ef3161c9fcae337697e902457287cedc31e71 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Fri, 1 Mar 2024 16:11:21 -0800 Subject: [PATCH 35/74] WIP trying to refactor the rules --- compiler/qsc_formatter/src/formatter.rs | 150 ++++++++++++++++++++---- 1 file changed, 127 insertions(+), 23 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index e90d11acea..f2dd407a57 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -126,61 +126,64 @@ fn apply_rules( // when we get here, neither left nor right should be whitespace // if the right is a close brace, the indent level should be one less - let indent_level = if let Syntax(Close(Delim::Brace)) = right.kind { + let indent_level = if let ConcreteTokenKind::Syntax(TokenKind::Close(Delim::Brace)) = right.kind + { indent_level.saturating_sub(1) } else { indent_level }; + // rule_trim_comments(left, &mut edits, code); + // rule_close_empty_delims(left, whitespace, right, &mut edits); + // rule_indentation(left, whitespace, right, &mut edits, indent_level); + // rule_operator_single_space(left, whitespace, right, &mut edits); + // rule_operator_no_space(left, whitespace, right, &mut edits); + use qsc_frontend::keyword::Keyword; use ConcreteTokenKind::*; use TokenKind::*; match (&left.kind, &right.kind) { (Syntax(Open(l)), Syntax(Close(r))) if l == r => { - rule_no_space(left, whitespace, right, &mut edits); + effect_no_space(left, whitespace, right, &mut edits); } (Comment | Syntax(DocComment), _) => { - rule_trim_comments(left, &mut edits, code); - rule_indentation(left, whitespace, right, &mut edits, indent_level); + effect_trim_comments(left, &mut edits, code); + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (Syntax(Semi), _) => match &right.kind { Comment => { if whitespace.contains('\n') { - rule_indentation(left, whitespace, right, &mut edits, indent_level); + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } } _ => { - rule_indentation(left, whitespace, right, &mut edits, indent_level); + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } }, - (_, Syntax(Close(Delim::Brace))) => { - rule_indentation(left, whitespace, right, &mut edits, indent_level); - } - (_, Syntax(Keyword(Keyword::Operation))) + (_, Syntax(Close(Delim::Brace))) + | (_, Syntax(Keyword(Keyword::Operation))) | (_, Syntax(Keyword(Keyword::Function))) | (_, Syntax(Keyword(Keyword::Newtype))) - | (_, Syntax(Keyword(Keyword::Namespace))) => { - rule_indentation(left, whitespace, right, &mut edits, indent_level); - } - (Syntax(Open(Delim::Brace)), _) => { - rule_indentation(left, whitespace, right, &mut edits, indent_level); + | (_, Syntax(Keyword(Keyword::Namespace))) + | (Syntax(Open(Delim::Brace)), _) => { + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (Syntax(Close(Delim::Brace)), Syntax(Semi)) => { - rule_no_space(left, whitespace, right, &mut edits); + effect_no_space(left, whitespace, right, &mut edits); } (Syntax(Close(Delim::Brace)), _) => { - rule_indentation(left, whitespace, right, &mut edits, indent_level); + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (Syntax(cooked_left), Syntax(cooked_right)) => match (cooked_left, cooked_right) { (Ident, Ident) | (Keyword(_), Ident) | (_, Colon) | (Colon, _) | (Comma, _) => { - rule_single_space(left, whitespace, right, &mut edits); + effect_single_space(left, whitespace, right, &mut edits); } (Ident, Open(Delim::Paren)) | (Ident, Open(Delim::Bracket)) | (Ident, Comma) | (Open(_), _) | (_, Close(_)) => { - rule_no_space(left, whitespace, right, &mut edits); + effect_no_space(left, whitespace, right, &mut edits); } _ => {} }, @@ -194,7 +197,108 @@ fn apply_rules( edits } -fn rule_no_space( +fn rule_operator_single_space( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, +) { + use ConcreteTokenKind::*; + use TokenKind::*; + if let (Syntax(cooked_left), Syntax(cooked_right)) = (&left.kind, &right.kind) { + match (cooked_left, cooked_right) { + (Comma, Close(_)) | (Semi, _) => {} // these have different rules + (Ident, Ident) | (Keyword(_), Ident) | (_, Colon) | (Colon, _) | (Comma, _) => { + effect_single_space(left, whitespace, right, edits); + } + _ => {} + } + } +} + +fn rule_operator_no_space( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, +) { + use ConcreteTokenKind::*; + use TokenKind::*; + if let (Syntax(cooked_left), Syntax(cooked_right)) = (&left.kind, &right.kind) { + match (cooked_left, cooked_right) { + (_, Colon) | (Colon, _) | (Semi, _) => {} // Colons get single spaces, and Semi has indentation logic + (Ident, Open(Delim::Paren)) + | (Ident, Open(Delim::Bracket)) + | (Ident, Comma) + | (Close(Delim::Brace), Semi) + | (Open(_), _) + | (_, Close(_)) => { + effect_no_space(left, whitespace, right, edits); + } + _ => {} + } + } +} + +fn rule_indentation( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, + indent_level: usize, +) { + use qsc_frontend::keyword::Keyword; + use ConcreteTokenKind::*; + use TokenKind::*; + let cond = match (&left.kind, &right.kind) { + (Comment | Syntax(DocComment), _) => true, + (Syntax(Semi), _) => match &right.kind { + Comment => whitespace.contains('\n'), + _ => true, + }, + (_, Syntax(Close(Delim::Brace))) + | (_, Syntax(Keyword(Keyword::Operation))) + | (_, Syntax(Keyword(Keyword::Function))) + | (_, Syntax(Keyword(Keyword::Newtype))) + | (_, Syntax(Keyword(Keyword::Namespace))) + | (Syntax(Open(Delim::Brace)), _) => true, + (Syntax(Close(Delim::Brace)), Syntax(Semi)) => false, + (Syntax(Close(Delim::Brace)), _) => true, + _ => false, + }; + + if cond { + effect_correct_indentation(left, whitespace, right, edits, indent_level); + } +} + +fn rule_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { + match &left.kind { + ConcreteTokenKind::Comment | ConcreteTokenKind::Syntax(TokenKind::DocComment) => { + effect_trim_comments(left, edits, code) + } + _ => {} + } +} + +fn rule_close_empty_delims( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, +) { + match (&left.kind, &right.kind) { + ( + ConcreteTokenKind::Syntax(TokenKind::Open(l)), + ConcreteTokenKind::Syntax(TokenKind::Close(r)), + ) if l == r => { + effect_no_space(left, whitespace, right, edits); + } + _ => {} + } +} + +fn effect_no_space( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, @@ -205,7 +309,7 @@ fn rule_no_space( } } -fn rule_single_space( +fn effect_single_space( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, @@ -216,7 +320,7 @@ fn rule_single_space( } } -fn rule_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { +fn effect_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { // fix trailing spaces on the comment let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); @@ -225,7 +329,7 @@ fn rule_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { } } -fn rule_indentation( +fn effect_correct_indentation( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, From d4199880ca0bc8a3421f37485440cbe4100e5400 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 4 Mar 2024 12:50:28 -0800 Subject: [PATCH 36/74] went back to big match, cleaned it up a bit --- compiler/qsc_formatter/src/formatter.rs | 174 ++++-------------------- 1 file changed, 30 insertions(+), 144 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index f2dd407a57..7ac6ee657a 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -61,7 +61,7 @@ pub fn format(code: &str) -> Vec { _ => {} } - if let ConcreteTokenKind::WhiteSpace = one.kind { + if matches!(one.kind, ConcreteTokenKind::WhiteSpace) { // first token is whitespace, continue scanning continue; } else if matches!(two.kind, ConcreteTokenKind::WhiteSpace) { @@ -98,23 +98,6 @@ pub fn format(code: &str) -> Vec { edits } -fn fix_whitespace(whitespace: &str, indent_level: usize) -> String { - // - // when you see newline, insert the indent string - // and trim until the next newline or the end of the string - // - - let mut count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); - - // There should always be at least one newline - if count_newlines < 1 { - count_newlines = 1; - } - let mut new = "\n".repeat(count_newlines); - new.push_str(&make_indent_string(indent_level)); - new -} - fn apply_rules( left: &ConcreteToken, whitespace: &str, @@ -133,33 +116,27 @@ fn apply_rules( indent_level }; - // rule_trim_comments(left, &mut edits, code); - // rule_close_empty_delims(left, whitespace, right, &mut edits); - // rule_indentation(left, whitespace, right, &mut edits, indent_level); - // rule_operator_single_space(left, whitespace, right, &mut edits); - // rule_operator_no_space(left, whitespace, right, &mut edits); - use qsc_frontend::keyword::Keyword; use ConcreteTokenKind::*; use TokenKind::*; match (&left.kind, &right.kind) { (Syntax(Open(l)), Syntax(Close(r))) if l == r => { + // close empty delimiter blocks, i.e. (), [], {} effect_no_space(left, whitespace, right, &mut edits); } (Comment | Syntax(DocComment), _) => { + // remove whitespace at the ends of comments effect_trim_comments(left, &mut edits, code); effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } - (Syntax(Semi), _) => match &right.kind { - Comment => { - if whitespace.contains('\n') { - effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); - } - } - _ => { + (Syntax(Semi), Comment) => { + if whitespace.contains('\n') { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } - }, + } + (Syntax(Semi), _) => { + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); + } (_, Syntax(Close(Delim::Brace))) | (_, Syntax(Keyword(Keyword::Operation))) | (_, Syntax(Keyword(Keyword::Function))) @@ -168,21 +145,26 @@ fn apply_rules( | (Syntax(Open(Delim::Brace)), _) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } - (Syntax(Close(Delim::Brace)), Syntax(Semi)) => { + (Syntax(Close(Delim::Brace)), Syntax(Semi)) + | (Syntax(Close(Delim::Brace)), Syntax(Comma)) => { + // remove any space between a close brace and a semicolon or comma effect_no_space(left, whitespace, right, &mut edits); } (Syntax(Close(Delim::Brace)), _) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (Syntax(cooked_left), Syntax(cooked_right)) => match (cooked_left, cooked_right) { - (Ident, Ident) | (Keyword(_), Ident) | (_, Colon) | (Colon, _) | (Comma, _) => { + (Ident, Ident) | (Keyword(_), Ident) // single spaces around identifiers + | (_, Colon) | (Colon, _) // single spaces around type-annotating colons + | (Comma, _) // single space after a comma + => { effect_single_space(left, whitespace, right, &mut edits); } - (Ident, Open(Delim::Paren)) - | (Ident, Open(Delim::Bracket)) - | (Ident, Comma) - | (Open(_), _) - | (_, Close(_)) => { + (Ident, Open(Delim::Paren)) // no space between callable name and argument tuple, i.e. foo() + | (Ident, Open(Delim::Bracket)) // no space between array name and brackets, i.e. foo[2] + | (Ident, Comma) // no space between identifier and following comma in a sequence + | (Open(_), _) // no space after an open delimiter + | (_, Close(_)) => { // no space before a close delimiter effect_no_space(left, whitespace, right, &mut edits); } _ => {} @@ -197,107 +179,6 @@ fn apply_rules( edits } -fn rule_operator_single_space( - left: &ConcreteToken, - whitespace: &str, - right: &ConcreteToken, - edits: &mut Vec, -) { - use ConcreteTokenKind::*; - use TokenKind::*; - if let (Syntax(cooked_left), Syntax(cooked_right)) = (&left.kind, &right.kind) { - match (cooked_left, cooked_right) { - (Comma, Close(_)) | (Semi, _) => {} // these have different rules - (Ident, Ident) | (Keyword(_), Ident) | (_, Colon) | (Colon, _) | (Comma, _) => { - effect_single_space(left, whitespace, right, edits); - } - _ => {} - } - } -} - -fn rule_operator_no_space( - left: &ConcreteToken, - whitespace: &str, - right: &ConcreteToken, - edits: &mut Vec, -) { - use ConcreteTokenKind::*; - use TokenKind::*; - if let (Syntax(cooked_left), Syntax(cooked_right)) = (&left.kind, &right.kind) { - match (cooked_left, cooked_right) { - (_, Colon) | (Colon, _) | (Semi, _) => {} // Colons get single spaces, and Semi has indentation logic - (Ident, Open(Delim::Paren)) - | (Ident, Open(Delim::Bracket)) - | (Ident, Comma) - | (Close(Delim::Brace), Semi) - | (Open(_), _) - | (_, Close(_)) => { - effect_no_space(left, whitespace, right, edits); - } - _ => {} - } - } -} - -fn rule_indentation( - left: &ConcreteToken, - whitespace: &str, - right: &ConcreteToken, - edits: &mut Vec, - indent_level: usize, -) { - use qsc_frontend::keyword::Keyword; - use ConcreteTokenKind::*; - use TokenKind::*; - let cond = match (&left.kind, &right.kind) { - (Comment | Syntax(DocComment), _) => true, - (Syntax(Semi), _) => match &right.kind { - Comment => whitespace.contains('\n'), - _ => true, - }, - (_, Syntax(Close(Delim::Brace))) - | (_, Syntax(Keyword(Keyword::Operation))) - | (_, Syntax(Keyword(Keyword::Function))) - | (_, Syntax(Keyword(Keyword::Newtype))) - | (_, Syntax(Keyword(Keyword::Namespace))) - | (Syntax(Open(Delim::Brace)), _) => true, - (Syntax(Close(Delim::Brace)), Syntax(Semi)) => false, - (Syntax(Close(Delim::Brace)), _) => true, - _ => false, - }; - - if cond { - effect_correct_indentation(left, whitespace, right, edits, indent_level); - } -} - -fn rule_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { - match &left.kind { - ConcreteTokenKind::Comment | ConcreteTokenKind::Syntax(TokenKind::DocComment) => { - effect_trim_comments(left, edits, code) - } - _ => {} - } -} - -fn rule_close_empty_delims( - left: &ConcreteToken, - whitespace: &str, - right: &ConcreteToken, - edits: &mut Vec, -) { - match (&left.kind, &right.kind) { - ( - ConcreteTokenKind::Syntax(TokenKind::Open(l)), - ConcreteTokenKind::Syntax(TokenKind::Close(r)), - ) if l == r => { - effect_no_space(left, whitespace, right, edits); - } - _ => {} - } -} - fn effect_no_space( left: &ConcreteToken, whitespace: &str, @@ -321,7 +202,6 @@ fn effect_single_space( } fn effect_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { - // fix trailing spaces on the comment let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { @@ -336,9 +216,15 @@ fn effect_correct_indentation( edits: &mut Vec, indent_level: usize, ) { - // if the middle whitespace contains a new line, we need to - // fix the indentation - let new_whitespace = fix_whitespace(whitespace, indent_level); + let mut count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); + + // There should always be at least one newline + if count_newlines < 1 { + count_newlines = 1; + } + + let mut new_whitespace = "\n".repeat(count_newlines); + new_whitespace.push_str(&make_indent_string(indent_level)); if whitespace != new_whitespace { edits.push(Edit::new( left.span.hi, From 163d4854959c870f1daed327625e1201d35e2ec4 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 4 Mar 2024 12:53:09 -0800 Subject: [PATCH 37/74] change name "comments" -> "comment" --- compiler/qsc_formatter/src/formatter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 7ac6ee657a..4217c1e6ac 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -126,7 +126,7 @@ fn apply_rules( } (Comment | Syntax(DocComment), _) => { // remove whitespace at the ends of comments - effect_trim_comments(left, &mut edits, code); + effect_trim_comment(left, &mut edits, code); effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (Syntax(Semi), Comment) => { @@ -201,7 +201,7 @@ fn effect_single_space( } } -fn effect_trim_comments(left: &ConcreteToken, edits: &mut Vec, code: &str) { +fn effect_trim_comment(left: &ConcreteToken, edits: &mut Vec, code: &str) { let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { From b3f598ca45eaec7669cc5a5ba09d59af94ce9c25 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 4 Mar 2024 12:55:43 -0800 Subject: [PATCH 38/74] reversed String TokenKind rename --- compiler/qsc_parse/src/expr.rs | 6 +++--- compiler/qsc_parse/src/lex/cooked.rs | 14 ++++++-------- compiler/qsc_parse/src/lex/cooked/tests.rs | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/qsc_parse/src/expr.rs b/compiler/qsc_parse/src/expr.rs index fcdb2a04c0..62567a397d 100644 --- a/compiler/qsc_parse/src/expr.rs +++ b/compiler/qsc_parse/src/expr.rs @@ -317,7 +317,7 @@ fn expr_range_prefix(s: &mut ParserContext) -> Result> { fn expr_interpolate(s: &mut ParserContext) -> Result> { let token = s.peek(); - let TokenKind::StringToken(StringToken::Interpolated(InterpolatedStart::DollarQuote, mut end)) = + let TokenKind::String(StringToken::Interpolated(InterpolatedStart::DollarQuote, mut end)) = token.kind else { return Err(Error(ErrorKind::Rule( @@ -338,7 +338,7 @@ fn expr_interpolate(s: &mut ParserContext) -> Result> { components.push(StringComponent::Expr(expr(s)?)); let token = s.peek(); - let TokenKind::StringToken(StringToken::Interpolated(InterpolatedStart::RBrace, next_end)) = + let TokenKind::String(StringToken::Interpolated(InterpolatedStart::RBrace, next_end)) = token.kind else { return Err(Error(ErrorKind::Rule( @@ -400,7 +400,7 @@ fn lit_token(lexeme: &str, token: Token) -> Result> { .ok_or(Error(ErrorKind::Lit("integer", token.span)))?; Ok(Some(Lit::Int(value))) } - TokenKind::StringToken(StringToken::Normal) => { + TokenKind::String(StringToken::Normal) => { let lexeme = shorten(1, 1, lexeme); let string = unescape(lexeme).map_err(|index| { let ch = lexeme[index + 1..] diff --git a/compiler/qsc_parse/src/lex/cooked.rs b/compiler/qsc_parse/src/lex/cooked.rs index fb95fb955e..f76c21aaa0 100644 --- a/compiler/qsc_parse/src/lex/cooked.rs +++ b/compiler/qsc_parse/src/lex/cooked.rs @@ -148,7 +148,7 @@ pub enum TokenKind { /// `;` Semi, /// A string literal. - StringToken(StringToken), + String(StringToken), /// `~~~` TildeTildeTilde, /// `w/` @@ -197,7 +197,7 @@ impl Display for TokenKind { TokenKind::Question => f.write_str("`?`"), TokenKind::RArrow => f.write_str("`->`"), TokenKind::Semi => f.write_str("`;`"), - TokenKind::StringToken(_) => f.write_str("string"), + TokenKind::String(_) => f.write_str("string"), TokenKind::TildeTildeTilde => f.write_str("`~~~`"), TokenKind::WSlash => f.write_str("`w/`"), TokenKind::WSlashEq => f.write_str("`w/=`"), @@ -338,13 +338,11 @@ impl<'a> Lexer<'a> { raw::TokenKind::Number(number) => Ok(Some(number.into())), raw::TokenKind::Single(single) => self.single(single).map(Some), raw::TokenKind::String(raw::StringToken::Normal { terminated: true }) => { - Ok(Some(TokenKind::StringToken(StringToken::Normal))) - } - raw::TokenKind::String(raw::StringToken::Interpolated(start, Some(ending))) => { - Ok(Some(TokenKind::StringToken(StringToken::Interpolated( - start, ending, - )))) + Ok(Some(TokenKind::String(StringToken::Normal))) } + raw::TokenKind::String(raw::StringToken::Interpolated(start, Some(ending))) => Ok( + Some(TokenKind::String(StringToken::Interpolated(start, ending))), + ), raw::TokenKind::String( raw::StringToken::Normal { terminated: false } | raw::StringToken::Interpolated(_, None), diff --git a/compiler/qsc_parse/src/lex/cooked/tests.rs b/compiler/qsc_parse/src/lex/cooked/tests.rs index f0169c0886..92dd664bd5 100644 --- a/compiler/qsc_parse/src/lex/cooked/tests.rs +++ b/compiler/qsc_parse/src/lex/cooked/tests.rs @@ -53,7 +53,7 @@ fn op_string(kind: TokenKind) -> Option { | TokenKind::Ident | TokenKind::Int(_) | TokenKind::Keyword(_) - | TokenKind::StringToken(_) => None, + | TokenKind::String(_) => None, } } From 9cdc6b30a4fec9f9e0c2853b8129019110489ff0 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 4 Mar 2024 14:25:58 -0800 Subject: [PATCH 39/74] correct tests after reverting rename of StringToken --- compiler/qsc_parse/src/lex/cooked/tests.rs | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/qsc_parse/src/lex/cooked/tests.rs b/compiler/qsc_parse/src/lex/cooked/tests.rs index 92dd664bd5..3ffe487da1 100644 --- a/compiler/qsc_parse/src/lex/cooked/tests.rs +++ b/compiler/qsc_parse/src/lex/cooked/tests.rs @@ -929,7 +929,7 @@ fn string() { [ Ok( Token { - kind: StringToken( + kind: String( Normal, ), span: Span { @@ -951,7 +951,7 @@ fn string_empty() { [ Ok( Token { - kind: StringToken( + kind: String( Normal, ), span: Span { @@ -1011,7 +1011,7 @@ fn interpolated_string() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, Quote, @@ -1036,7 +1036,7 @@ fn interpolated_string_braced() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1059,7 +1059,7 @@ fn interpolated_string_braced() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1084,7 +1084,7 @@ fn interpolated_string_escape_brace() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, Quote, @@ -1109,7 +1109,7 @@ fn interpolated_string_unclosed_brace() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1134,7 +1134,7 @@ fn interpolated_string_unclosed_brace_quote() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1186,7 +1186,7 @@ fn interpolated_string_unopened_brace_quote() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, Quote, @@ -1211,7 +1211,7 @@ fn interpolated_string_braced_index() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1267,7 +1267,7 @@ fn interpolated_string_braced_index() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1292,7 +1292,7 @@ fn interpolated_string_two_braced() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1315,7 +1315,7 @@ fn interpolated_string_two_braced() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, LBrace, @@ -1338,7 +1338,7 @@ fn interpolated_string_two_braced() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1363,7 +1363,7 @@ fn interpolated_string_braced_normal_string() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1377,7 +1377,7 @@ fn interpolated_string_braced_normal_string() { ), Ok( Token { - kind: StringToken( + kind: String( Normal, ), span: Span { @@ -1388,7 +1388,7 @@ fn interpolated_string_braced_normal_string() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1413,7 +1413,7 @@ fn nested_interpolated_string() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1427,7 +1427,7 @@ fn nested_interpolated_string() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1450,7 +1450,7 @@ fn nested_interpolated_string() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1464,7 +1464,7 @@ fn nested_interpolated_string() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1489,7 +1489,7 @@ fn nested_interpolated_string_with_exprs() { [ Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1523,7 +1523,7 @@ fn nested_interpolated_string_with_exprs() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( DollarQuote, LBrace, @@ -1546,7 +1546,7 @@ fn nested_interpolated_string_with_exprs() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, @@ -1560,7 +1560,7 @@ fn nested_interpolated_string_with_exprs() { ), Ok( Token { - kind: StringToken( + kind: String( Interpolated( RBrace, Quote, From 9c511ad8fa2769a1883e3a058c4ff15dc612afc7 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 5 Mar 2024 09:46:05 -0800 Subject: [PATCH 40/74] format_str and calculate_format_edits --- compiler/qsc_formatter/src/formatter.rs | 23 +- compiler/qsc_formatter/src/formatter/tests.rs | 220 +++--------------- language_service/src/format.rs | 4 +- 3 files changed, 52 insertions(+), 195 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 4217c1e6ac..9b7fac922b 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -30,9 +30,25 @@ fn make_indent_string(level: usize) -> String { " ".repeat(level) } +/// Applies formatting rules to the give code str and returns +/// the formatted string. +pub fn format_str(code: &str) -> String { + let mut edits = calculate_format_edits(code); + edits.sort_by_key(|edit| edit.span.hi); // sort edits by their span's hi value from lowest to highest + edits.reverse(); // sort from highest to lowest so that that as edits are applied they don't invalidate later applications of edits + let mut new_code = String::from(code); + + for edit in edits { + let range = (edit.span.lo as usize)..(edit.span.hi as usize); + new_code.replace_range(range, &edit.new_text); + } + + new_code +} + /// Applies formatting rules to the given code str, generating edits where /// the source code needs to be changed to comply with the format rules. -pub fn format(code: &str) -> Vec { +pub fn calculate_format_edits(code: &str) -> Vec { let tokens = concrete::ConcreteTokenIterator::new(code); let mut edits = vec![]; @@ -171,11 +187,6 @@ fn apply_rules( }, _ => {} } - - println!( - "edits for `{}` : {edits:?}", - &code[left.span.lo as usize..right.span.hi as usize] - ); edits } diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 7eac7c6085..162f8e478f 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -5,33 +5,8 @@ use expect_test::{expect, Expect}; use indoc::indoc; fn check(input: &str, expect: &Expect) { - let actual = super::format(input); - expect.assert_debug_eq(&actual); -} - -#[test] -fn test_formatting() { - check( - "operation Foo ()", - &expect![[r#" - [ - Edit { - span: Span { - lo: 9, - hi: 12, - }, - new_text: " ", - }, - Edit { - span: Span { - lo: 15, - hi: 18, - }, - new_text: "", - }, - ] -"#]], - ); + let actual = super::format_str(input); + expect.assert_eq(&actual); } #[test] @@ -50,36 +25,12 @@ operation Foo() : Unit {{ check( input.as_str(), &expect![[r#" - [ - Edit { - span: Span { - lo: 0, - hi: 40, - }, - new_text: "/// Doc Comment with trailing spaces", - }, - Edit { - span: Span { - lo: 70, - hi: 105, - }, - new_text: "// Comment with trailing spaces", - }, - Edit { - span: Span { - lo: 123, - hi: 166, - }, - new_text: "// In-line comment with trailing spaces", - }, - Edit { - span: Span { - lo: 181, - hi: 186, - }, - new_text: "\n", - }, - ] + /// Doc Comment with trailing spaces + operation Foo() : Unit { + // Comment with trailing spaces + let x = 3; // In-line comment with trailing spaces + let y = 4; + } "#]], ); } @@ -105,92 +56,21 @@ fn correct_indentation() { } "#, &expect![[r#" - [ - Edit { - span: Span { - lo: 0, - hi: 5, - }, - new_text: "", - }, - Edit { - span: Span { - lo: 25, - hi: 30, - }, - new_text: "\n", - }, - Edit { - span: Span { - lo: 39, - hi: 48, - }, - new_text: "\n", - }, - Edit { - span: Span { - lo: 76, - hi: 85, - }, - new_text: "\n ", - }, - Edit { - span: Span { - lo: 120, - hi: 130, - }, - new_text: "\n\n ", - }, - Edit { - span: Span { - lo: 143, - hi: 152, - }, - new_text: "\n ", - }, - Edit { - span: Span { - lo: 176, - hi: 189, - }, - new_text: "\n ", - }, - Edit { - span: Span { - lo: 199, - hi: 212, - }, - new_text: "\n ", - }, - Edit { - span: Span { - lo: 222, - hi: 236, - }, - new_text: "\n\n ", - }, - Edit { - span: Span { - lo: 246, - hi: 259, - }, - new_text: "\n ", - }, - Edit { - span: Span { - lo: 268, - hi: 277, - }, - new_text: "\n ", - }, - Edit { - span: Span { - lo: 278, - hi: 291, - }, - new_text: "\n", - }, - ] + /// First + /// Second + /// Third + namespace MyQuantumProgram { + open Microsoft.Quantum.Diagnostics; + + @EntryPoint() + operation Main() : Int { + let x = 3; + let y = 4; + + // Comment + return 5; + } + } "#]], ); } @@ -213,51 +93,20 @@ fn correct_empty_delimiters() { } "#}, &expect![[r#" - [ - Edit { - span: Span { - lo: 24, - hi: 25, - }, - new_text: "", - }, - Edit { - span: Span { - lo: 80, - hi: 83, - }, - new_text: "", - }, - Edit { - span: Span { - lo: 98, - hi: 104, - }, - new_text: "", - }, - Edit { - span: Span { - lo: 128, - hi: 129, - }, - new_text: "", - }, - Edit { - span: Span { - lo: 145, - hi: 152, - }, - new_text: "", - }, - ] + operation Foo() : Unit {} + operation Bar() : Unit { + operation Baz() : Unit {} + let x = {}; + let y : Int[] = []; + let z = (); + } "#]], ); } #[test] fn test_sample() { - check( - indoc! {r#" + let input = indoc! {r#" /// # Sample /// Joint Measurement /// @@ -299,9 +148,6 @@ fn test_sample() { return (parityResult, [firstQubitResult, secondQubitResult]); } } - "#}, - &expect![[r#" - [] - "#]], - ); + "#}; + assert!(super::calculate_format_edits(input).is_empty()); } diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 3469fae9e5..6f036dfc22 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -3,7 +3,7 @@ use crate::{compilation::Compilation, protocol::TextEdit}; -use qsc::formatter::format; +use qsc::formatter::calculate_format_edits; use qsc::line_column::{Encoding, Position, Range}; pub(crate) fn get_format_changes( @@ -20,7 +20,7 @@ pub(crate) fn get_format_changes( .contents .clone(); - format(&contents) + calculate_format_edits(&contents) .iter() .map(|edit| TextEdit { contents: edit.new_text.clone(), From 12e374d517e17e55bd80cb5289394e4d76788db0 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 5 Mar 2024 10:25:38 -0800 Subject: [PATCH 41/74] update TextEdit structs --- compiler/qsc_formatter/src/formatter.rs | 38 ++++++++++++++----------- language_service/src/format.rs | 4 +-- language_service/src/protocol.rs | 4 +-- wasm/src/language_service.rs | 10 +++---- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 9b7fac922b..8433e1ecbe 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -12,16 +12,16 @@ use qsc_frontend::lex::{ mod tests; #[derive(Debug)] -pub struct Edit { - pub span: Span, +pub struct TextEdit { pub new_text: String, + pub span: Span, } -impl Edit { - fn new(lo: u32, hi: u32, new_text: &str) -> Self { +impl TextEdit { + fn new(new_text: &str, lo: u32, hi: u32) -> Self { Self { - span: Span { lo, hi }, new_text: new_text.to_string(), + span: Span { lo, hi }, } } } @@ -48,7 +48,7 @@ pub fn format_str(code: &str) -> String { /// Applies formatting rules to the given code str, generating edits where /// the source code needs to be changed to comply with the format rules. -pub fn calculate_format_edits(code: &str) -> Vec { +pub fn calculate_format_edits(code: &str) -> Vec { let tokens = concrete::ConcreteTokenIterator::new(code); let mut edits = vec![]; @@ -97,7 +97,7 @@ pub fn calculate_format_edits(code: &str) -> Vec { (None, None, Some(three)) => { // Remove any whitespace at the start of a file if three.span.lo != 0 { - vec![Edit::new(0, three.span.lo, "")] + vec![TextEdit::new("", 0, three.span.lo)] } else { vec![] } @@ -120,7 +120,7 @@ fn apply_rules( right: &ConcreteToken, code: &str, indent_level: usize, -) -> Vec { +) -> Vec { let mut edits = vec![]; // when we get here, neither left nor right should be whitespace @@ -194,10 +194,10 @@ fn effect_no_space( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, - edits: &mut Vec, + edits: &mut Vec, ) { if !whitespace.is_empty() { - edits.push(Edit::new(left.span.hi, right.span.lo, "")); + edits.push(TextEdit::new("", left.span.hi, right.span.lo)); } } @@ -205,18 +205,22 @@ fn effect_single_space( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, - edits: &mut Vec, + edits: &mut Vec, ) { if whitespace != " " { - edits.push(Edit::new(left.span.hi, right.span.lo, " ")); + edits.push(TextEdit::new(" ", left.span.hi, right.span.lo)); } } -fn effect_trim_comment(left: &ConcreteToken, edits: &mut Vec, code: &str) { +fn effect_trim_comment(left: &ConcreteToken, edits: &mut Vec, code: &str) { let comment_contents = get_token_contents(code, left); let new_comment_contents = comment_contents.trim_end(); if comment_contents != new_comment_contents { - edits.push(Edit::new(left.span.lo, left.span.hi, new_comment_contents)); + edits.push(TextEdit::new( + new_comment_contents, + left.span.lo, + left.span.hi, + )); } } @@ -224,7 +228,7 @@ fn effect_correct_indentation( left: &ConcreteToken, whitespace: &str, right: &ConcreteToken, - edits: &mut Vec, + edits: &mut Vec, indent_level: usize, ) { let mut count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); @@ -237,10 +241,10 @@ fn effect_correct_indentation( let mut new_whitespace = "\n".repeat(count_newlines); new_whitespace.push_str(&make_indent_string(indent_level)); if whitespace != new_whitespace { - edits.push(Edit::new( + edits.push(TextEdit::new( + new_whitespace.as_str(), left.span.hi, right.span.lo, - new_whitespace.as_str(), )); } } diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 6f036dfc22..789f663ed4 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -23,8 +23,8 @@ pub(crate) fn get_format_changes( calculate_format_edits(&contents) .iter() .map(|edit| TextEdit { - contents: edit.new_text.clone(), - span: Range::from_span(encoding, &contents, &edit.span), + new_text: edit.new_text.clone(), + range: Range::from_span(encoding, &contents, &edit.span), }) .collect() } diff --git a/language_service/src/protocol.rs b/language_service/src/protocol.rs index 0d8535a513..2403fe832a 100644 --- a/language_service/src/protocol.rs +++ b/language_service/src/protocol.rs @@ -94,8 +94,8 @@ pub struct Hover { #[derive(Debug, PartialEq)] pub struct TextEdit { - pub contents: String, - pub span: Range, + pub new_text: String, + pub range: Range, } #[derive(Debug, PartialEq)] diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs index e76c1564d6..eb2bfc2f71 100644 --- a/wasm/src/language_service.rs +++ b/wasm/src/language_service.rs @@ -205,15 +205,15 @@ impl LanguageService { TextEdit { range: Range { start: Position { - line: edit.span.start.line, - character: edit.span.start.column, + line: edit.range.start.line, + character: edit.range.start.column, }, end: Position { - line: edit.span.end.line, - character: edit.span.end.column, + line: edit.range.end.line, + character: edit.range.end.column, }, }, - newText: edit.contents, + newText: edit.new_text, } .into() }) From b1997798564db988c1c066bd86401e2335df0393 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 5 Mar 2024 11:07:21 -0800 Subject: [PATCH 42/74] clippy --- compiler/qsc_parse/src/lex/concrete.rs | 3 ++- compiler/qsc_parse/src/lex/raw.rs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index cb6f4165fb..b6dc435c6a 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -25,7 +25,7 @@ pub enum ConcreteTokenKind { Comment, } -/// This is an iterator over ConcreteTokens, creating the tokens from a source str. +/// This is an iterator over `ConcreteTokens`, creating the tokens from a source str. /// It works by running the cooked lexer on the source str, and iterating over /// those cooked tokens. Whenever adjacent cooked tokens are found to have a gap /// between their spans, the raw lexer is run on that slice of the source str to @@ -39,6 +39,7 @@ pub struct ConcreteTokenIterator<'a> { } impl<'a> ConcreteTokenIterator<'a> { + #[must_use] pub fn new(code: &'a str) -> Self { Self { code, diff --git a/compiler/qsc_parse/src/lex/raw.rs b/compiler/qsc_parse/src/lex/raw.rs index a9610649bc..7663b86ab8 100644 --- a/compiler/qsc_parse/src/lex/raw.rs +++ b/compiler/qsc_parse/src/lex/raw.rs @@ -175,6 +175,7 @@ pub struct Lexer<'a> { } impl<'a> Lexer<'a> { + #[must_use] pub fn new(input: &'a str) -> Self { Self { chars: input.char_indices().peekable(), @@ -183,6 +184,7 @@ impl<'a> Lexer<'a> { } } + #[must_use] pub fn new_with_starting_offset(input: &'a str, starting_offset: u32) -> Self { Self { chars: input.char_indices().peekable(), From c218b46687389305275e1dbc3b9394ac6a51f58d Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 5 Mar 2024 13:27:30 -0800 Subject: [PATCH 43/74] little more clarity on tests names --- compiler/qsc_formatter/src/formatter/tests.rs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 162f8e478f..89a692ff0c 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -36,7 +36,32 @@ operation Foo() : Unit {{ } #[test] -fn correct_indentation() { +fn preserve_string_trailing_spaces() { + let extra_spaces = " "; + let input = format!( + "operation Foo() : Unit {{ + let x = \"Hello{extra_spaces} + World\"; +}} +" + ); + + assert!(super::calculate_format_edits(input.as_str()).is_empty()); +} + +#[test] +fn preserve_string_indentation() { + let input = r#"operation Foo() : Unit { + let x = "Hello + World"; +} +"#; + + assert!(super::calculate_format_edits(input).is_empty()); +} + +#[test] +fn formatting_corrects_indentation() { check( r#" /// First @@ -76,7 +101,7 @@ fn correct_indentation() { } #[test] -fn correct_empty_delimiters() { +fn remove_spaces_between_empty_delimiters() { check( indoc! {r#" operation Foo() : Unit { @@ -105,7 +130,7 @@ fn correct_empty_delimiters() { } #[test] -fn test_sample() { +fn sample_has_no_edits() { let input = indoc! {r#" /// # Sample /// Joint Measurement From 2af16d66c659bd011aa3e5e2babd3819d2cd7f7a Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 5 Mar 2024 13:29:19 -0800 Subject: [PATCH 44/74] quick rename --- compiler/qsc_formatter/src/formatter/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 89a692ff0c..70f436fc3f 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -130,7 +130,7 @@ fn remove_spaces_between_empty_delimiters() { } #[test] -fn sample_has_no_edits() { +fn sample_has_no_formatting_changes() { let input = indoc! {r#" /// # Sample /// Joint Measurement From 79f9da05b2c80721b56f05fa215b88ede7257e78 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 6 Mar 2024 14:41:48 -0800 Subject: [PATCH 45/74] more complete functionality, includes operators --- compiler/qsc_formatter/src/formatter.rs | 160 +++++++++++++++++++----- 1 file changed, 127 insertions(+), 33 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 8433e1ecbe..9054c3522b 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -4,7 +4,7 @@ use qsc_data_structures::span::Span; use qsc_frontend::lex::{ concrete::{self, ConcreteToken, ConcreteTokenKind}, - cooked::TokenKind, + cooked::{self, TokenKind}, Delim, }; @@ -136,10 +136,6 @@ fn apply_rules( use ConcreteTokenKind::*; use TokenKind::*; match (&left.kind, &right.kind) { - (Syntax(Open(l)), Syntax(Close(r))) if l == r => { - // close empty delimiter blocks, i.e. (), [], {} - effect_no_space(left, whitespace, right, &mut edits); - } (Comment | Syntax(DocComment), _) => { // remove whitespace at the ends of comments effect_trim_comment(left, &mut edits, code); @@ -150,39 +146,75 @@ fn apply_rules( effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } } - (Syntax(Semi), _) => { - effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); - } - (_, Syntax(Close(Delim::Brace))) - | (_, Syntax(Keyword(Keyword::Operation))) - | (_, Syntax(Keyword(Keyword::Function))) - | (_, Syntax(Keyword(Keyword::Newtype))) - | (_, Syntax(Keyword(Keyword::Namespace))) - | (Syntax(Open(Delim::Brace)), _) => { - effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); - } - (Syntax(Close(Delim::Brace)), Syntax(Semi)) - | (Syntax(Close(Delim::Brace)), Syntax(Comma)) => { - // remove any space between a close brace and a semicolon or comma - effect_no_space(left, whitespace, right, &mut edits); - } - (Syntax(Close(Delim::Brace)), _) => { - effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); - } (Syntax(cooked_left), Syntax(cooked_right)) => match (cooked_left, cooked_right) { - (Ident, Ident) | (Keyword(_), Ident) // single spaces around identifiers - | (_, Colon) | (Colon, _) // single spaces around type-annotating colons - | (Comma, _) // single space after a comma - => { + (Semi, _) => { + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); + } + (_, Semi) => { + effect_no_space(left, whitespace, right, &mut edits); + } + (Open(Delim::Brace), Close(Delim::Brace)) => { + // close empty brace blocks, i.e. {} + effect_no_space(left, whitespace, right, &mut edits); + } + (At, Ident) => { + effect_no_space(left, whitespace, right, &mut edits); + } + (Keyword(Keyword::Internal), _) => { effect_single_space(left, whitespace, right, &mut edits); } - (Ident, Open(Delim::Paren)) // no space between callable name and argument tuple, i.e. foo() - | (Ident, Open(Delim::Bracket)) // no space between array name and brackets, i.e. foo[2] - | (Ident, Comma) // no space between identifier and following comma in a sequence - | (Open(_), _) // no space after an open delimiter - | (_, Close(_)) => { // no space before a close delimiter + (Open(Delim::Brace), _) + | (_, Close(Delim::Brace)) + | (_, Keyword(Keyword::Internal)) + | (_, Keyword(Keyword::Operation)) + | (_, Keyword(Keyword::Function)) + | (_, Keyword(Keyword::Newtype)) + | (_, Keyword(Keyword::Namespace)) + | (_, At) => { + effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); + } + (Open(Delim::Bracket | Delim::Paren), _) + | (_, Close(Delim::Bracket | Delim::Paren)) => { effect_no_space(left, whitespace, right, &mut edits); } + (_, Open(Delim::Bracket | Delim::Paren)) => { + if is_value_token_left(cooked_left) { + // i.e. foo() or { foo }[3] + effect_no_space(left, whitespace, right, &mut edits); + } else { + // i.e. let x = (1, 2, 3); + effect_single_space(left, whitespace, right, &mut edits); + } + } + (_, TokenKind::DotDotDot) => { + if is_value_token_left(cooked_left) { + effect_no_space(left, whitespace, right, &mut edits); + } else { + effect_single_space(left, whitespace, right, &mut edits); + } + } + (_, _) if is_value_token_right(cooked_right) => { + if is_prefix_with_space(cooked_left) + || is_prefix_without_space(cooked_left) + || matches!(cooked_left, TokenKind::DotDotDot) + { + effect_no_space(left, whitespace, right, &mut edits); + } else { + effect_single_space(left, whitespace, right, &mut edits); + } + } + (_, _) if is_suffix(cooked_right) => { + effect_no_space(left, whitespace, right, &mut edits); + } + (_, _) if is_prefix_with_space(cooked_right) => { + effect_single_space(left, whitespace, right, &mut edits); + } + (_, _) if is_prefix_without_space(cooked_right) => { + effect_no_space(left, whitespace, right, &mut edits); + } + (_, _) if is_bin_op(cooked_right) => { + effect_single_space(left, whitespace, right, &mut edits); + } _ => {} }, _ => {} @@ -190,6 +222,68 @@ fn apply_rules( edits } +fn is_bin_op(cooked: &TokenKind) -> bool { + matches!( + cooked, + TokenKind::Bar + | TokenKind::BinOpEq(_) + | TokenKind::ClosedBinOp(_) + | TokenKind::Colon + | TokenKind::Eq + | TokenKind::EqEq + | TokenKind::FatArrow + | TokenKind::Gt + | TokenKind::Gte + | TokenKind::LArrow + | TokenKind::Lt + | TokenKind::Lte + | TokenKind::Ne + | TokenKind::Question + | TokenKind::RArrow + | TokenKind::WSlash + | TokenKind::WSlashEq + ) +} + +fn is_prefix_with_space(cooked: &TokenKind) -> bool { + matches!(cooked, TokenKind::AposIdent | TokenKind::TildeTildeTilde) +} + +fn is_prefix_without_space(cooked: &TokenKind) -> bool { + matches!( + cooked, + TokenKind::ColonColon | TokenKind::Dot | TokenKind::DotDot + ) +} + +fn is_suffix(cooked: &TokenKind) -> bool { + matches!(cooked, TokenKind::Bang | TokenKind::Comma) +} + +fn is_value_token_left(cooked: &TokenKind) -> bool { + matches!( + cooked, + TokenKind::BigInt(_) + | TokenKind::Float + | TokenKind::Ident + | TokenKind::Int(_) + | TokenKind::String(_) + | TokenKind::Close(_) + ) +} + +fn is_value_token_right(cooked: &TokenKind) -> bool { + matches!( + cooked, + TokenKind::BigInt(_) + | TokenKind::Float + | TokenKind::Ident + | TokenKind::Int(_) + | TokenKind::String(_) + | TokenKind::Open(_) + ) +} + fn effect_no_space( left: &ConcreteToken, whitespace: &str, From c42cf65ae08c82f51b003dc377080872f0e8bd48 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 6 Mar 2024 15:21:09 -0800 Subject: [PATCH 46/74] added rules for lots of keywords --- compiler/qsc_formatter/src/formatter.rs | 56 ++++++++++++++++++------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 9054c3522b..cd02dd9508 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -2,10 +2,13 @@ // Licensed under the MIT License. use qsc_data_structures::span::Span; -use qsc_frontend::lex::{ - concrete::{self, ConcreteToken, ConcreteTokenKind}, - cooked::{self, TokenKind}, - Delim, +use qsc_frontend::{ + keyword::Keyword, + lex::{ + concrete::{self, ConcreteToken, ConcreteTokenKind}, + cooked::TokenKind, + Delim, + }, }; #[cfg(test)] @@ -170,6 +173,7 @@ fn apply_rules( | (_, Keyword(Keyword::Function)) | (_, Keyword(Keyword::Newtype)) | (_, Keyword(Keyword::Namespace)) + | (_, Keyword(Keyword::Open)) | (_, At) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -242,6 +246,15 @@ fn is_bin_op(cooked: &TokenKind) -> bool { | TokenKind::RArrow | TokenKind::WSlash | TokenKind::WSlashEq + | TokenKind::Keyword(Keyword::And) + | TokenKind::Keyword(Keyword::Or) + // Technically the rest are not binary ops, but has the same spacing as one + | TokenKind::Keyword(Keyword::Not) + | TokenKind::Keyword(Keyword::As) + | TokenKind::Keyword(Keyword::In) + | TokenKind::Keyword(Keyword::Is) + | TokenKind::Keyword(Keyword::AdjointUpper) + | TokenKind::Keyword(Keyword::ControlledUpper) ) } @@ -260,19 +273,17 @@ fn is_suffix(cooked: &TokenKind) -> bool { matches!(cooked, TokenKind::Bang | TokenKind::Comma) } -fn is_value_token_left(cooked: &TokenKind) -> bool { +fn is_keyword_value(keyword: &Keyword) -> bool { + use Keyword::*; matches!( - cooked, - TokenKind::BigInt(_) - | TokenKind::Float - | TokenKind::Ident - | TokenKind::Int(_) - | TokenKind::String(_) - | TokenKind::Close(_) + keyword, + True | False | Zero | One | PauliI | PauliX | PauliY | PauliZ | Underscore + // Adj and Ctl are not really values, but have the same spacing as values + | Adj | Ctl ) } -fn is_value_token_right(cooked: &TokenKind) -> bool { +fn is_value_lit(cooked: &TokenKind) -> bool { matches!( cooked, TokenKind::BigInt(_) @@ -280,10 +291,27 @@ fn is_value_token_right(cooked: &TokenKind) -> bool { | TokenKind::Ident | TokenKind::Int(_) | TokenKind::String(_) - | TokenKind::Open(_) ) } +fn is_value_token_left(cooked: &TokenKind) -> bool { + match cooked { + _ if is_value_lit(cooked) => true, + TokenKind::Keyword(keyword) if is_keyword_value(keyword) => true, + TokenKind::Close(_) => true, // a closed delim represents a value on the left + _ => false, + } +} + +fn is_value_token_right(cooked: &TokenKind) -> bool { + match cooked { + _ if is_value_lit(cooked) => true, + TokenKind::Keyword(keyword) if is_keyword_value(keyword) => true, + TokenKind::Open(_) => true, // an open delim represents a value on the right + _ => false, + } +} + fn effect_no_space( left: &ConcreteToken, whitespace: &str, From 0f5abec7ea2f99fb70640f14d1c9b5c051d44a49 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 6 Mar 2024 16:05:42 -0800 Subject: [PATCH 47/74] functor keywords --- compiler/qsc_formatter/src/formatter.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index cd02dd9508..66b24dcf0e 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -166,6 +166,10 @@ fn apply_rules( (Keyword(Keyword::Internal), _) => { effect_single_space(left, whitespace, right, &mut edits); } + (Keyword(Keyword::Adjoint), Keyword(Keyword::Controlled)) + | (Keyword(Keyword::Controlled), Keyword(Keyword::Adjoint)) => { + effect_single_space(left, whitespace, right, &mut edits); + } (Open(Delim::Brace), _) | (_, Close(Delim::Brace)) | (_, Keyword(Keyword::Internal)) @@ -174,6 +178,9 @@ fn apply_rules( | (_, Keyword(Keyword::Newtype)) | (_, Keyword(Keyword::Namespace)) | (_, Keyword(Keyword::Open)) + | (_, Keyword(Keyword::Body)) + | (_, Keyword(Keyword::Adjoint)) + | (_, Keyword(Keyword::Controlled)) | (_, At) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -197,6 +204,12 @@ fn apply_rules( effect_single_space(left, whitespace, right, &mut edits); } } + (_, TokenKind::Keyword(Keyword::Auto)) + | (_, TokenKind::Keyword(Keyword::Distribute)) + | (_, TokenKind::Keyword(Keyword::Intrinsic)) + | (_, TokenKind::Keyword(Keyword::Invert)) => { + effect_single_space(left, whitespace, right, &mut edits); + } (_, _) if is_value_token_right(cooked_right) => { if is_prefix_with_space(cooked_left) || is_prefix_without_space(cooked_left) From 18cc087dce692c1039d86620513bfff04540c561 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 6 Mar 2024 16:24:20 -0800 Subject: [PATCH 48/74] Ignore `-` case --- compiler/qsc_formatter/src/formatter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 66b24dcf0e..3d5ef5cd65 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -136,6 +136,7 @@ fn apply_rules( }; use qsc_frontend::keyword::Keyword; + use qsc_frontend::lex::cooked::ClosedBinOp; use ConcreteTokenKind::*; use TokenKind::*; match (&left.kind, &right.kind) { @@ -145,11 +146,18 @@ fn apply_rules( effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (Syntax(Semi), Comment) => { + // ToDo: this needs to be broader than just off of semicolons if whitespace.contains('\n') { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } } (Syntax(cooked_left), Syntax(cooked_right)) => match (cooked_left, cooked_right) { + (ClosedBinOp(ClosedBinOp::Minus), _) => { + // This case is used to ignore the spacing after a `-`. + // This is done because we currently don't have the architecture + // to be able to differentiate between the unary `-` and the binary `-` + // which would have different spacing after. + } (Semi, _) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } From d458ac870b4af24167a5954a2f283a2f3015d514 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 7 Mar 2024 11:28:38 -0800 Subject: [PATCH 49/74] added ignorance cases for new-lines and tweaked rules for prefixes --- compiler/qsc_formatter/src/formatter.rs | 58 +++++++++++++++++++++---- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 3d5ef5cd65..f47d366053 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -135,6 +135,8 @@ fn apply_rules( indent_level }; + let new_line_in_spaces = whitespace.contains('\n'); + use qsc_frontend::keyword::Keyword; use qsc_frontend::lex::cooked::ClosedBinOp; use ConcreteTokenKind::*; @@ -152,11 +154,11 @@ fn apply_rules( } } (Syntax(cooked_left), Syntax(cooked_right)) => match (cooked_left, cooked_right) { - (ClosedBinOp(ClosedBinOp::Minus), _) => { - // This case is used to ignore the spacing after a `-`. + (ClosedBinOp(ClosedBinOp::Minus), _) | (_, ClosedBinOp(ClosedBinOp::Minus)) => { + // This case is used to ignore the spacing around a `-`. // This is done because we currently don't have the architecture // to be able to differentiate between the unary `-` and the binary `-` - // which would have different spacing after. + // which would have different spacing rules. } (Semi, _) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); @@ -192,12 +194,20 @@ fn apply_rules( | (_, At) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } + (_, _) if new_line_in_spaces => { + effect_trim_whitespace(left, whitespace, right, &mut edits); + // Ignore the rest of the cases if the user has a newline in the whitespace. + // This is done because we don't currently have logic for determining when + // lines are too long and require new-lines, and we don't have logic + // for determining what the correct indentation should be in these cases, + // so we put this do-nothing case in to leave user code unchanged. + } (Open(Delim::Bracket | Delim::Paren), _) | (_, Close(Delim::Bracket | Delim::Paren)) => { effect_no_space(left, whitespace, right, &mut edits); } (_, Open(Delim::Bracket | Delim::Paren)) => { - if is_value_token_left(cooked_left) { + if is_value_token_left(cooked_left) || is_prefix(cooked_left) { // i.e. foo() or { foo }[3] effect_no_space(left, whitespace, right, &mut edits); } else { @@ -219,10 +229,7 @@ fn apply_rules( effect_single_space(left, whitespace, right, &mut edits); } (_, _) if is_value_token_right(cooked_right) => { - if is_prefix_with_space(cooked_left) - || is_prefix_without_space(cooked_left) - || matches!(cooked_left, TokenKind::DotDotDot) - { + if is_prefix(cooked_left) { effect_no_space(left, whitespace, right, &mut edits); } else { effect_single_space(left, whitespace, right, &mut edits); @@ -232,7 +239,11 @@ fn apply_rules( effect_no_space(left, whitespace, right, &mut edits); } (_, _) if is_prefix_with_space(cooked_right) => { - effect_single_space(left, whitespace, right, &mut edits); + if is_prefix(cooked_left) { + effect_no_space(left, whitespace, right, &mut edits); + } else { + effect_single_space(left, whitespace, right, &mut edits); + } } (_, _) if is_prefix_without_space(cooked_right) => { effect_no_space(left, whitespace, right, &mut edits); @@ -290,6 +301,12 @@ fn is_prefix_without_space(cooked: &TokenKind) -> bool { ) } +fn is_prefix(cooked: &TokenKind) -> bool { + is_prefix_with_space(cooked) + || is_prefix_without_space(cooked) + || matches!(cooked, TokenKind::DotDotDot) +} + fn is_suffix(cooked: &TokenKind) -> bool { matches!(cooked, TokenKind::Bang | TokenKind::Comma) } @@ -367,6 +384,29 @@ fn effect_trim_comment(left: &ConcreteToken, edits: &mut Vec, code: &s } } +fn effect_trim_whitespace( + left: &ConcreteToken, + whitespace: &str, + right: &ConcreteToken, + edits: &mut Vec, +) { + let count_newlines = whitespace.chars().filter(|c| *c == '\n').count(); + let suffix = match whitespace.rsplit_once('\n') { + Some((_, suffix)) => suffix, + None => "", + }; + + let mut new_whitespace = "\n".repeat(count_newlines); + new_whitespace.push_str(suffix); + if whitespace != new_whitespace { + edits.push(TextEdit::new( + new_whitespace.as_str(), + left.span.hi, + right.span.lo, + )); + } +} + fn effect_correct_indentation( left: &ConcreteToken, whitespace: &str, From a6ad814aaefe44a094c1be09a83a08c6286bf869 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 7 Mar 2024 11:44:39 -0800 Subject: [PATCH 50/74] string interpolation blocks --- compiler/qsc_formatter/src/formatter.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index f47d366053..cfd3de418c 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -6,8 +6,8 @@ use qsc_frontend::{ keyword::Keyword, lex::{ concrete::{self, ConcreteToken, ConcreteTokenKind}, - cooked::TokenKind, - Delim, + cooked::{StringToken, TokenKind}, + Delim, InterpolatedEnding, InterpolatedStart, }, }; @@ -202,6 +202,10 @@ fn apply_rules( // for determining what the correct indentation should be in these cases, // so we put this do-nothing case in to leave user code unchanged. } + (String(StringToken::Interpolated(_, InterpolatedEnding::LBrace)), _) + | (_, String(StringToken::Interpolated(InterpolatedStart::RBrace, _))) => { + effect_no_space(left, whitespace, right, &mut edits); + } (Open(Delim::Bracket | Delim::Paren), _) | (_, Close(Delim::Bracket | Delim::Paren)) => { effect_no_space(left, whitespace, right, &mut edits); @@ -321,6 +325,7 @@ fn is_keyword_value(keyword: &Keyword) -> bool { ) } +/// Note that this does not include interpolated string literals fn is_value_lit(cooked: &TokenKind) -> bool { matches!( cooked, @@ -328,13 +333,14 @@ fn is_value_lit(cooked: &TokenKind) -> bool { | TokenKind::Float | TokenKind::Ident | TokenKind::Int(_) - | TokenKind::String(_) + | TokenKind::String(StringToken::Normal) ) } fn is_value_token_left(cooked: &TokenKind) -> bool { match cooked { _ if is_value_lit(cooked) => true, + TokenKind::String(StringToken::Interpolated(_, InterpolatedEnding::Quote)) => true, TokenKind::Keyword(keyword) if is_keyword_value(keyword) => true, TokenKind::Close(_) => true, // a closed delim represents a value on the left _ => false, @@ -344,6 +350,7 @@ fn is_value_token_left(cooked: &TokenKind) -> bool { fn is_value_token_right(cooked: &TokenKind) -> bool { match cooked { _ if is_value_lit(cooked) => true, + TokenKind::String(StringToken::Interpolated(InterpolatedStart::DollarQuote, _)) => true, TokenKind::Keyword(keyword) if is_keyword_value(keyword) => true, TokenKind::Open(_) => true, // an open delim represents a value on the right _ => false, From d9c886d595f552806c5b20d567943c3932160c6c Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 7 Mar 2024 11:49:01 -0800 Subject: [PATCH 51/74] adjusted logic for eol comments --- compiler/qsc_formatter/src/formatter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index cfd3de418c..4d0d8cd80a 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -147,8 +147,7 @@ fn apply_rules( effect_trim_comment(left, &mut edits, code); effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } - (Syntax(Semi), Comment) => { - // ToDo: this needs to be broader than just off of semicolons + (_, Comment) => { if whitespace.contains('\n') { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } From 251d5e08713bac53b1f0620bf170734958e5a553 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 7 Mar 2024 12:57:46 -0800 Subject: [PATCH 52/74] respect carriage returns --- compiler/qsc_formatter/src/formatter.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 4d0d8cd80a..f535b98bf2 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -148,7 +148,7 @@ fn apply_rules( effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } (_, Comment) => { - if whitespace.contains('\n') { + if new_line_in_spaces { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } } @@ -402,7 +402,11 @@ fn effect_trim_whitespace( None => "", }; - let mut new_whitespace = "\n".repeat(count_newlines); + let mut new_whitespace = if whitespace.contains("\r\n") { + "\r\n".repeat(count_newlines) + } else { + "\n".repeat(count_newlines) + }; new_whitespace.push_str(suffix); if whitespace != new_whitespace { edits.push(TextEdit::new( @@ -427,7 +431,11 @@ fn effect_correct_indentation( count_newlines = 1; } - let mut new_whitespace = "\n".repeat(count_newlines); + let mut new_whitespace = if whitespace.contains("\r\n") { + "\r\n".repeat(count_newlines) + } else { + "\n".repeat(count_newlines) + }; new_whitespace.push_str(&make_indent_string(indent_level)); if whitespace != new_whitespace { edits.push(TextEdit::new( From 5ac621faa0e7eda021a5b7a2f8f874c46475768a Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 7 Mar 2024 13:18:28 -0800 Subject: [PATCH 53/74] close any empty block --- compiler/qsc_formatter/src/formatter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index f535b98bf2..968e7956fb 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -165,8 +165,8 @@ fn apply_rules( (_, Semi) => { effect_no_space(left, whitespace, right, &mut edits); } - (Open(Delim::Brace), Close(Delim::Brace)) => { - // close empty brace blocks, i.e. {} + (Open(l), Close(r)) if l == r => { + // close empty delimiter blocks, i.e. (), [], {} effect_no_space(left, whitespace, right, &mut edits); } (At, Ident) => { From e4731c9084062ed22ffa0650358b6f651cc4e1c5 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 7 Mar 2024 15:52:44 -0800 Subject: [PATCH 54/74] telemetry --- vscode/src/format.ts | 18 ++++++++++++++++++ vscode/src/telemetry.ts | 10 ++++++++++ 2 files changed, 28 insertions(+) diff --git a/vscode/src/format.ts b/vscode/src/format.ts index 3390ae1ffc..d8c31855f1 100644 --- a/vscode/src/format.ts +++ b/vscode/src/format.ts @@ -4,6 +4,8 @@ import { ILanguageService } from "qsharp-lang"; import * as vscode from "vscode"; import { toVscodeRange } from "./common"; +import { EventType, sendTelemetryEvent } from "./telemetry"; +import { getRandomGuid } from "./utils"; export function createFormatProvider(languageService: ILanguageService) { return new QSharpFormatProvider(languageService); @@ -13,6 +15,11 @@ class QSharpFormatProvider implements vscode.DocumentFormattingEditProvider { constructor(public languageService: ILanguageService) {} async provideDocumentFormattingEdits(document: vscode.TextDocument) { + // telemetry start format + const associationId = getRandomGuid(); + sendTelemetryEvent(EventType.FormatStart, { associationId }, {}); + const start = performance.now(); + const lsEdits = await this.languageService.getFormatChanges( document.uri.toString(), ); @@ -23,6 +30,17 @@ class QSharpFormatProvider implements vscode.DocumentFormattingEditProvider { const referenceRange = toVscodeRange(edit.range); edits.push(new vscode.TextEdit(referenceRange, edit.newText)); } + + // telemetry end format + sendTelemetryEvent( + EventType.FormatEnd, + { associationId }, + { + timeToCompleteMs: performance.now() - start, + numberOfEdits: edits.length, + }, + ); + return edits; } } diff --git a/vscode/src/telemetry.ts b/vscode/src/telemetry.ts index 71720a8f47..10fc9ed87a 100644 --- a/vscode/src/telemetry.ts +++ b/vscode/src/telemetry.ts @@ -40,6 +40,8 @@ export enum EventType { TriggerHistogram = "Qsharp.TriggerHistogram", HistogramStart = "Qsharp.HistogramStart", HistogramEnd = "Qsharp.HistogramEnd", + FormatStart = "Qsharp.FormatStart", + FormatEnd = "Qsharp.FormatEnd", } type Empty = { [K in any]: never }; @@ -206,6 +208,14 @@ type EventTypes = { properties: { associationId: string }; measurements: { timeToCompleteMs: number }; }; + [EventType.FormatStart]: { + properties: { associationId: string }; + measurements: Empty; + }; + [EventType.FormatEnd]: { + properties: { associationId: string }; + measurements: { timeToCompleteMs: number; numberOfEdits: number }; + }; }; export enum QsharpDocumentType { From 0fbc84828663a65553ec672f9117e3bc49cdf724 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 11 Mar 2024 11:22:54 -0700 Subject: [PATCH 55/74] Added many tests --- compiler/qsc_formatter/src/formatter.rs | 10 +- compiler/qsc_formatter/src/formatter/tests.rs | 434 ++++++++++++++++-- compiler/qsc_parse/src/lex/concrete.rs | 7 +- 3 files changed, 402 insertions(+), 49 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 968e7956fb..b2758f3891 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -159,6 +159,13 @@ fn apply_rules( // to be able to differentiate between the unary `-` and the binary `-` // which would have different spacing rules. } + (Gt, _) | (_, Gt) | (Lt, _) | (_, Lt) => { + // This case is used to ignore the spacing around a `<` and `>`. + // This is done because we currently don't have the architecture + // to be able to differentiate between the comparison operators + // and the type-parameter delimiters which would have different + // spacing rules. + } (Semi, _) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } @@ -294,7 +301,7 @@ fn is_bin_op(cooked: &TokenKind) -> bool { } fn is_prefix_with_space(cooked: &TokenKind) -> bool { - matches!(cooked, TokenKind::AposIdent | TokenKind::TildeTildeTilde) + matches!(cooked, TokenKind::TildeTildeTilde) } fn is_prefix_without_space(cooked: &TokenKind) -> bool { @@ -331,6 +338,7 @@ fn is_value_lit(cooked: &TokenKind) -> bool { TokenKind::BigInt(_) | TokenKind::Float | TokenKind::Ident + | TokenKind::AposIdent | TokenKind::Int(_) | TokenKind::String(StringToken::Normal) ) diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 70f436fc3f..521dda3cd9 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -9,28 +9,30 @@ fn check(input: &str, expect: &Expect) { expect.assert_eq(&actual); } +// Removing trailing whitespace from lines + #[test] fn remove_trailing_spaces() { let extra_spaces = " "; let input = format!( "/// Doc Comment with trailing spaces{extra_spaces} -operation Foo() : Unit {{ - // Comment with trailing spaces{extra_spaces} - let x = 3; // In-line comment with trailing spaces{extra_spaces} - let y = 4;{extra_spaces} -}} + operation Foo() : Unit {{ + // Comment with trailing spaces{extra_spaces} + let x = 3; // In-line comment with trailing spaces{extra_spaces} + let y = 4;{extra_spaces} + }} " ); check( input.as_str(), &expect![[r#" - /// Doc Comment with trailing spaces - operation Foo() : Unit { - // Comment with trailing spaces - let x = 3; // In-line comment with trailing spaces - let y = 4; - } + /// Doc Comment with trailing spaces + operation Foo() : Unit { + // Comment with trailing spaces + let x = 3; // In-line comment with trailing spaces + let y = 4; + } "#]], ); } @@ -39,27 +41,368 @@ operation Foo() : Unit {{ fn preserve_string_trailing_spaces() { let extra_spaces = " "; let input = format!( - "operation Foo() : Unit {{ - let x = \"Hello{extra_spaces} - World\"; -}} -" + "\"Hello{extra_spaces} +World\"" ); assert!(super::calculate_format_edits(input.as_str()).is_empty()); } +// Namespace items begin on their own lines + #[test] -fn preserve_string_indentation() { - let input = r#"operation Foo() : Unit { - let x = "Hello - World"; +fn namespace_items_begin_on_their_own_lines() { + check( + "operation Foo() : Unit {} operation Bar() : Unit {}", + &expect![[r#" + operation Foo() : Unit {} + operation Bar() : Unit {}"#]], + ); +} + +// Single spaces around most binary operators + +#[test] +fn singe_space_around_arithmetic_bin_ops() { + // Note that `-` is missing at this time due to it being unsupported for formatting. + check( + indoc! {" + 1+2; + 1 * 2; + 4 /2; + 3% 2; + 2 ^ 3; + "}, + &expect![[r#" + 1 + 2; + 1 * 2; + 4 / 2; + 3 % 2; + 2 ^ 3; + "#]], + ); +} + +#[test] +fn singe_space_around_bit_wise_bin_ops() { + check( + indoc! {" + 1&&&2; + 1 ||| 2; + 4 ^^^2; + 3<<< 2; + 2 >>> 3; + "}, + &expect![[r#" + 1 &&& 2; + 1 ||| 2; + 4 ^^^ 2; + 3 <<< 2; + 2 >>> 3; + "#]], + ); +} + +#[test] +fn singe_space_around_boolean_bin_ops() { + check( + indoc! {" + true and false; + true or false; + "}, + &expect![[r#" + true and false; + true or false; + "#]], + ); +} + +#[test] +fn singe_space_around_bin_op_equals() { + check( + indoc! {" + let x += y; + let x -=y; + let x*= y; + let x /= y; + let x %= y; + "}, + &expect![[r#" + let x += y; + let x -= y; + let x *= y; + let x /= y; + let x %= y; + "#]], + ); +} + +#[test] +fn singe_space_around_equals() { + check("let x = 3;", &expect!["let x = 3;"]); +} + +#[test] +fn singe_space_around_colon() { + check("let x : Int = 3;", &expect!["let x : Int = 3;"]); +} + +#[test] +fn singe_space_around_comp_ops() { + // Note that `<` and `>` are missing at this time due to them being unsupported for formatting. + check( + indoc! {" + x <=y; + x >= y; + x == y; + x != y; + "}, + &expect![[r#" + x <= y; + x >= y; + x == y; + x != y; + "#]], + ); +} + +#[test] +fn singe_space_around_ternary() { + check("x? 3| 4", &expect!["x ? 3 | 4"]); +} + +#[test] +fn singe_space_around_copy() { + check("x w/3 <- 4", &expect!["x w/ 3 <- 4"]); +} + +#[test] +fn singe_space_around_copy_and_update() { + check("x w/=3 <- 4", &expect!["x w/= 3 <- 4"]); +} + +#[test] +fn singe_space_around_lambda_ops() { + check( + indoc! {" + let x = () -> (); + let y = ()=>(); + "}, + &expect![[r#" + let x = () -> (); + let y = () => (); + "#]], + ); +} + +#[test] +fn singe_space_around_characteristic_expr() { + check( + "operation Foo() : Unit is Adj+Ctl {}", + &expect!["operation Foo() : Unit is Adj + Ctl {}"], + ); +} + +#[test] +fn singe_space_around_functors() { + check( + "Controlled Adjoint Foo()", + &expect!["Controlled Adjoint Foo()"], + ); +} + +#[test] +fn singe_space_around_as() { + check( + "open thing as other;", + &expect!["open thing as other;"], + ); +} + +// No space between unary operators and their operand + +#[test] +fn no_space_before_unwrap() { + check("let x = foo !;", &expect!["let x = foo!;"]); +} + +#[test] +fn no_space_after_bit_negation() { + check("let x = ~~~ 3;", &expect!["let x = ~~~3;"]); +} + +#[test] +fn single_space_around_boolean_negation() { + check("let x = not 3;", &expect!["let x = not 3;"]); +} + +// No space after open parentheses and brackets and before close parentheses and brackets + +#[test] +fn no_space_for_parentheses() { + check("( 12, 13, 14 )", &expect!["(12, 13, 14)"]); +} + +#[test] +fn no_space_for_brackets() { + check("[ 12 + 13 + 14 ]", &expect!["[12 + 13 + 14]"]); +} + +// No space after open string-interpolation argument braces and before close string-interpolation argument braces + +#[test] +fn no_space_for_string_interpolation_argument_braces() { + check( + r#"let x = $"First { 1 + 1 } Third";"#, + &expect![[r#"let x = $"First {1 + 1} Third";"#]], + ); +} + +// No space before commas or semicolons + +#[test] +fn no_space_before_comma() { + check("(12 , 13 , 14)", &expect!["(12, 13, 14)"]); +} + +#[test] +fn no_space_before_semicolons() { + check("let x = 3 ;", &expect!["let x = 3;"]); +} + +// New line after semicolons + +#[test] +fn new_line_after_semicolon() { + check( + "let x = 3; let y = 2;", + &expect![[r#" + let x = 3; + let y = 2;"#]], + ); } -"#; +#[test] +fn preserve_eol_comment() { + let input = indoc! {"let x = 3; // End-of-line Comment + let y = 2; + "}; assert!(super::calculate_format_edits(input).is_empty()); } +// No space between caller expressions and argument tuple + +#[test] +fn no_space_in_front_of_argument_tuple() { + check("Foo (1, 2, 3)", &expect!["Foo(1, 2, 3)"]); +} + +#[test] +fn no_space_in_front_of_parameter_tuple() { + check( + "operation Foo (x : Int, y : Int) : Unit {}", + &expect!["operation Foo(x : Int, y : Int) : Unit {}"], + ); +} + +// No space between array expressions and indexing brackets + +#[test] +fn no_space_in_front_of_array_indexing() { + check("arr [4]", &expect!["arr[4]"]); +} + +// No space around `.`, `..`, and `::` operators + +#[test] +fn no_space_around_dot_operator() { + check("let x = thing . other;", &expect!["let x = thing.other;"]); +} + +#[test] +fn no_space_around_range_operator() { + check("let x = 1 .. 4;", &expect!["let x = 1..4;"]); +} + +#[test] +fn no_space_around_field_operator() { + check("let x = thing :: other;", &expect!["let x = thing::other;"]); +} + +// No space between the `…` operator and any possible operands on either side + +#[test] +fn no_space_around_full_range_in_slice() { + check("let x = y[ ... ];", &expect!["let x = y[...];"]); +} + +#[test] +fn no_space_between_open_end_range_and_operand() { + check("let x = 15 ...;", &expect!["let x = 15...;"]); +} + +#[test] +fn no_space_between_open_start_range_and_operand() { + check("let x = ... 15;", &expect!["let x = ...15;"]); +} + +// Single space before open brace and new line after, except empty blocks have no space + +#[test] +fn single_space_before_open_brace_and_new_line_after() { + check( + indoc! {r#" + operation Foo() : Unit{ let x = 3; } + operation Bar() : Unit + { { let x = 3; }{ let x = 4; } } + "#}, + &expect![[r#" + operation Foo() : Unit { + let x = 3; + } + operation Bar() : Unit + { + { + let x = 3; + } { + let x = 4; + } + } + "#]], + ); +} + +#[test] +fn remove_spaces_between_empty_delimiters() { + check( + indoc! {r#" + operation Foo() : Unit { + } + operation Bar() : Unit { + operation Baz() : Unit { } + let x = { + + }; + let y : Int[] = [ ]; + let z = ( + + ); + } + "#}, + &expect![[r#" + operation Foo() : Unit {} + operation Bar() : Unit { + operation Baz() : Unit {} + let x = {}; + let y : Int[] = []; + let z = (); + } + "#]], + ); +} + +// Correct indentation, which increases by four spaces when a brace-delimited block is opened and decreases when block is closed + #[test] fn formatting_corrects_indentation() { check( @@ -72,10 +415,10 @@ fn formatting_corrects_indentation() { @EntryPoint() operation Main() : Int { - let x = 3; + let x = 3; let y = 4; - // Comment + // Comment return 5; } } @@ -101,34 +444,31 @@ fn formatting_corrects_indentation() { } #[test] -fn remove_spaces_between_empty_delimiters() { - check( - indoc! {r#" - operation Foo() : Unit { - } - operation Bar() : Unit { - operation Baz() : Unit { } - let x = { +fn preserve_string_indentation() { + let input = r#""Hello + World""#; - }; - let y : Int[] = [ ]; - let z = ( + assert!(super::calculate_format_edits(input).is_empty()); +} - ); - } - "#}, - &expect![[r#" - operation Foo() : Unit {} - operation Bar() : Unit { - operation Baz() : Unit {} - let x = {}; - let y : Int[] = []; - let z = (); - } - "#]], - ); +// Will respect user new-lines and indentation added into expressions + +#[test] +fn preserve_user_new_lines_in_expressions() { + let input = indoc! {r#" + let x = [ + thing1, + thing2, + thing3, + ]; + let y = 1 + 2 + 3 + 4 + 5 + + 6 + 7 + 8 + 9 + 10; + "#}; + assert!(super::calculate_format_edits(input).is_empty()); } +// Extra test case for sanity + #[test] fn sample_has_no_formatting_changes() { let input = indoc! {r#" diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index b6dc435c6a..50993d00dd 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -96,8 +96,13 @@ impl Iterator for ConcreteTokenIterator<'_> { kind: ConcreteTokenKind::WhiteSpace, span, }, + // ToDo: investigate this case further + raw::TokenKind::Single(raw::Single::Apos) => ConcreteToken { + kind: ConcreteTokenKind::Syntax(super::TokenKind::AposIdent), + span, + }, // This will panic if any content other than whitespace or comments are ignored when "cooking" the raw tokens - _ => panic!("only comments and whitespace should be non-compilable tokens"), + _ => panic!("Raw Token couldn't be converted: {raw_token:?}"), }; Some(concrete) } From 21b52ff4e78f59431f42f943d192b97faf8adff6 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 11 Mar 2024 13:05:15 -0700 Subject: [PATCH 56/74] account for apostrophe --- compiler/qsc_parse/src/lex/concrete.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 50993d00dd..75e47b8330 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -96,11 +96,11 @@ impl Iterator for ConcreteTokenIterator<'_> { kind: ConcreteTokenKind::WhiteSpace, span, }, - // ToDo: investigate this case further - raw::TokenKind::Single(raw::Single::Apos) => ConcreteToken { - kind: ConcreteTokenKind::Syntax(super::TokenKind::AposIdent), - span, - }, + raw::TokenKind::Single(raw::Single::Apos) => { + // Apostrophes are handled a bit strangely. + // Their full information is contained in the following token. + return self.next(); + } // This will panic if any content other than whitespace or comments are ignored when "cooking" the raw tokens _ => panic!("Raw Token couldn't be converted: {raw_token:?}"), }; @@ -110,19 +110,21 @@ impl Iterator for ConcreteTokenIterator<'_> { Ok(token) => { let next_lo = self.get_next_lo(); self.get_tokens_from_span(token.span.hi, next_lo); - Some(ConcreteToken { + let syntax = ConcreteToken { kind: ConcreteTokenKind::Syntax(token.kind), span: token.span, - }) + }; + Some(syntax) } Err(err) => { let next_lo = self.get_next_lo(); let span = err.get_span(); self.get_tokens_from_span(span.hi, next_lo); - Some(ConcreteToken { + let error = ConcreteToken { kind: ConcreteTokenKind::Error(err), span, - }) + }; + Some(error) } }, } From db65af8c48e64631f64e5ec32985d8ddb5c0cee3 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 13 Mar 2024 11:05:56 -0700 Subject: [PATCH 57/74] control-flow-helper keywords --- compiler/qsc_formatter/src/formatter.rs | 30 ++++-- compiler/qsc_formatter/src/formatter/tests.rs | 97 ++++++++++++++++++- 2 files changed, 114 insertions(+), 13 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index b2758f3891..8cd2b88e4b 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -197,14 +197,34 @@ fn apply_rules( | (_, Keyword(Keyword::Body)) | (_, Keyword(Keyword::Adjoint)) | (_, Keyword(Keyword::Controlled)) + | (_, Keyword(Keyword::Let)) + | (_, Keyword(Keyword::Mutable)) + | (_, Keyword(Keyword::Set)) + | (_, Keyword(Keyword::Use)) + | (_, Keyword(Keyword::Borrow)) + | (_, Keyword(Keyword::Fixup)) | (_, At) => { effect_correct_indentation(left, whitespace, right, &mut edits, indent_level); } + (_, TokenKind::Keyword(Keyword::Until)) + | (_, TokenKind::Keyword(Keyword::In)) + | (_, TokenKind::Keyword(Keyword::As)) + | (_, TokenKind::Keyword(Keyword::Elif)) + | (_, TokenKind::Keyword(Keyword::Else)) + | (_, TokenKind::Keyword(Keyword::Apply)) => { + effect_single_space(left, whitespace, right, &mut edits); + } + (_, TokenKind::Keyword(Keyword::Auto)) + | (_, TokenKind::Keyword(Keyword::Distribute)) + | (_, TokenKind::Keyword(Keyword::Intrinsic)) + | (_, TokenKind::Keyword(Keyword::Invert)) => { + effect_single_space(left, whitespace, right, &mut edits); + } (_, _) if new_line_in_spaces => { effect_trim_whitespace(left, whitespace, right, &mut edits); // Ignore the rest of the cases if the user has a newline in the whitespace. // This is done because we don't currently have logic for determining when - // lines are too long and require new-lines, and we don't have logic + // lines are too long and require newlines, and we don't have logic // for determining what the correct indentation should be in these cases, // so we put this do-nothing case in to leave user code unchanged. } @@ -232,10 +252,7 @@ fn apply_rules( effect_single_space(left, whitespace, right, &mut edits); } } - (_, TokenKind::Keyword(Keyword::Auto)) - | (_, TokenKind::Keyword(Keyword::Distribute)) - | (_, TokenKind::Keyword(Keyword::Intrinsic)) - | (_, TokenKind::Keyword(Keyword::Invert)) => { + (_, TokenKind::Keyword(Keyword::Is)) => { effect_single_space(left, whitespace, right, &mut edits); } (_, _) if is_value_token_right(cooked_right) => { @@ -292,9 +309,6 @@ fn is_bin_op(cooked: &TokenKind) -> bool { | TokenKind::Keyword(Keyword::Or) // Technically the rest are not binary ops, but has the same spacing as one | TokenKind::Keyword(Keyword::Not) - | TokenKind::Keyword(Keyword::As) - | TokenKind::Keyword(Keyword::In) - | TokenKind::Keyword(Keyword::Is) | TokenKind::Keyword(Keyword::AdjointUpper) | TokenKind::Keyword(Keyword::ControlledUpper) ) diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 521dda3cd9..ce95109bd0 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -270,10 +270,10 @@ fn no_space_before_semicolons() { check("let x = 3 ;", &expect!["let x = 3;"]); } -// New line after semicolons +// Newline after semicolons #[test] -fn new_line_after_semicolon() { +fn newline_after_semicolon() { check( "let x = 3; let y = 2;", &expect![[r#" @@ -290,6 +290,93 @@ fn preserve_eol_comment() { assert!(super::calculate_format_edits(input).is_empty()); } +// Newline before declaration keywords + +#[test] +fn newline_before_let() { + check( + "let x = 3; {} let y = 2;", + &expect![[r#" + let x = 3; + {} + let y = 2;"#]], + ); +} + +#[test] +fn newline_before_mutable() { + check( + "mutable x = 3; {} mutable y = 2;", + &expect![[r#" + mutable x = 3; + {} + mutable y = 2;"#]], + ); +} + +#[test] +fn newline_before_set() { + check( + "set x = 3; {} set y = 2;", + &expect![[r#" + set x = 3; + {} + set y = 2;"#]], + ); +} + +#[test] +fn newline_before_use() { + check( + "use q = Qubit(); {} use w = Qubit();", + &expect![[r#" + use q = Qubit(); + {} + use w = Qubit();"#]], + ); +} + +#[test] +fn newline_before_borrow() { + check( + "borrow q = Qubit(); {} borrow w = Qubit();", + &expect![[r#" + borrow q = Qubit(); + {} + borrow w = Qubit();"#]], + ); +} + +// Single space before control-flow-helper keywords + +#[test] +fn single_space_before_in() { + check("for x in 0..2 {}", &expect![[r#"for x in 0..2 {}"#]]); +} + +#[test] +fn single_space_before_until() { + check( + "repeat {} until x fixup {}", + &expect![[r#" + repeat {} until x + fixup {}"#]], + ); +} + +#[test] +fn single_space_before_elif_and_else() { + check( + "if x {} elif y {} else {}", + &expect!["if x {} elif y {} else {}"], + ); +} + +#[test] +fn single_space_before_apply() { + check("within {} apply {}", &expect!["within {} apply {}"]); +} + // No space between caller expressions and argument tuple #[test] @@ -346,10 +433,10 @@ fn no_space_between_open_start_range_and_operand() { check("let x = ... 15;", &expect!["let x = ...15;"]); } -// Single space before open brace and new line after, except empty blocks have no space +// Single space before open brace and newline after, except empty blocks have no space #[test] -fn single_space_before_open_brace_and_new_line_after() { +fn single_space_before_open_brace_and_newline_after() { check( indoc! {r#" operation Foo() : Unit{ let x = 3; } @@ -454,7 +541,7 @@ fn preserve_string_indentation() { // Will respect user new-lines and indentation added into expressions #[test] -fn preserve_user_new_lines_in_expressions() { +fn preserve_user_newlines_in_expressions() { let input = indoc! {r#" let x = [ thing1, From 55c8a686d10caefe4368ad017e99b69b270135ce Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 13 Mar 2024 11:13:07 -0700 Subject: [PATCH 58/74] other keyword rules --- compiler/qsc_formatter/src/formatter.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index 8cd2b88e4b..c35f30220e 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -252,7 +252,14 @@ fn apply_rules( effect_single_space(left, whitespace, right, &mut edits); } } - (_, TokenKind::Keyword(Keyword::Is)) => { + (_, TokenKind::Keyword(Keyword::Is)) + | (_, TokenKind::Keyword(Keyword::For)) + | (_, TokenKind::Keyword(Keyword::While)) + | (_, TokenKind::Keyword(Keyword::Repeat)) + | (_, TokenKind::Keyword(Keyword::If)) + | (_, TokenKind::Keyword(Keyword::Within)) + | (_, TokenKind::Keyword(Keyword::Return)) + | (_, TokenKind::Keyword(Keyword::Fail)) => { effect_single_space(left, whitespace, right, &mut edits); } (_, _) if is_value_token_right(cooked_right) => { From 449af2558b0c1b4f0f3735e3e2a95266e1f3c4af Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 13 Mar 2024 13:36:04 -0700 Subject: [PATCH 59/74] lots of small syntax improvements --- compiler/qsc_parse/src/lex/concrete.rs | 4 ++-- compiler/qsc_parse/src/lex/cooked.rs | 2 +- language_service/src/completion.rs | 10 +++++----- language_service/src/format.rs | 16 +++++++--------- language_service/src/lib.rs | 6 ++++-- language_service/src/protocol.rs | 2 +- vscode/src/format.ts | 8 +++----- wasm/src/language_service.rs | 12 +----------- 8 files changed, 24 insertions(+), 36 deletions(-) diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 75e47b8330..51bd9ddc04 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -64,7 +64,7 @@ impl<'a> ConcreteTokenIterator<'a> { None => match self.cooked_tokens.peek() { Some(next) => match next { Ok(next) => next.span.lo, - Err(err) => err.get_span().lo, + Err(err) => err.span().lo, }, None => self .code @@ -118,7 +118,7 @@ impl Iterator for ConcreteTokenIterator<'_> { } Err(err) => { let next_lo = self.get_next_lo(); - let span = err.get_span(); + let span = err.span(); self.get_tokens_from_span(span.hi, next_lo); let error = ConcreteToken { kind: ConcreteTokenKind::Error(err), diff --git a/compiler/qsc_parse/src/lex/cooked.rs b/compiler/qsc_parse/src/lex/cooked.rs index f76c21aaa0..e273d483c3 100644 --- a/compiler/qsc_parse/src/lex/cooked.rs +++ b/compiler/qsc_parse/src/lex/cooked.rs @@ -67,7 +67,7 @@ impl Error { } } - pub(crate) fn get_span(self) -> Span { + pub(crate) fn span(self) -> Span { match self { Error::Incomplete(_, _, _, s) | Error::IncompleteEof(_, _, s) diff --git a/language_service/src/completion.rs b/language_service/src/completion.rs index 13107e528d..01390d3068 100644 --- a/language_service/src/completion.rs +++ b/language_service/src/completion.rs @@ -5,7 +5,7 @@ mod tests; use crate::compilation::{Compilation, CompilationKind}; -use crate::protocol::{CompletionItem, CompletionItemKind, CompletionList}; +use crate::protocol::{CompletionItem, CompletionItemKind, CompletionList, TextEdit}; use crate::qsc_utils::{into_range, span_contains}; use qsc::ast::visit::{self, Visitor}; use qsc::display::{CodeDisplay, Lookup}; @@ -449,14 +449,14 @@ impl CompletionListBuilder { Some(alias) => alias.as_ref().cloned(), None => match insert_open_at { Some(start) => { - additional_edits.push(( - start, - format!( + additional_edits.push(TextEdit { + new_text: format!( "open {};{}", namespace.name.clone(), indent, ), - )); + range: start, + }); None } None => Some(namespace.name.clone()), diff --git a/language_service/src/format.rs b/language_service/src/format.rs index 789f663ed4..0adf0443a2 100644 --- a/language_service/src/format.rs +++ b/language_service/src/format.rs @@ -4,27 +4,25 @@ use crate::{compilation::Compilation, protocol::TextEdit}; use qsc::formatter::calculate_format_edits; -use qsc::line_column::{Encoding, Position, Range}; +use qsc::line_column::{Encoding, Range}; pub(crate) fn get_format_changes( compilation: &Compilation, source_name: &str, - _position: Position, encoding: Encoding, ) -> Vec { - let contents = compilation + let contents = &compilation .user_unit() .sources .find_by_name(source_name) .expect("can't find source by name") - .contents - .clone(); + .contents; - calculate_format_edits(&contents) - .iter() + calculate_format_edits(contents) + .into_iter() .map(|edit| TextEdit { - new_text: edit.new_text.clone(), - range: Range::from_span(encoding, &contents, &edit.span), + new_text: edit.new_text, + range: Range::from_span(encoding, contents, &edit.span), }) .collect() } diff --git a/language_service/src/lib.rs b/language_service/src/lib.rs index c5f6326fb8..c8ae936589 100644 --- a/language_service/src/lib.rs +++ b/language_service/src/lib.rs @@ -223,10 +223,12 @@ impl LanguageService { #[must_use] pub fn get_format_changes(&self, uri: &str) -> Vec { self.document_op( - format::get_format_changes, + |compilation, uri, (), position_encoding| { + format::get_format_changes(compilation, uri, position_encoding) + }, "get_format_changes", uri, - Position { line: 0, column: 0 }, + (), ) } diff --git a/language_service/src/protocol.rs b/language_service/src/protocol.rs index 0cc9aba15d..d19ab3cbab 100644 --- a/language_service/src/protocol.rs +++ b/language_service/src/protocol.rs @@ -43,7 +43,7 @@ pub struct CompletionItem { pub kind: CompletionItemKind, pub sort_text: Option, pub detail: Option, - pub additional_text_edits: Option>, + pub additional_text_edits: Option>, } impl CompletionItem { diff --git a/vscode/src/format.ts b/vscode/src/format.ts index d8c31855f1..12beba8682 100644 --- a/vscode/src/format.ts +++ b/vscode/src/format.ts @@ -25,11 +25,9 @@ class QSharpFormatProvider implements vscode.DocumentFormattingEditProvider { ); if (!lsEdits) return []; - const edits = []; - for (const edit of lsEdits) { - const referenceRange = toVscodeRange(edit.range); - edits.push(new vscode.TextEdit(referenceRange, edit.newText)); - } + const edits = lsEdits.map( + (edit) => new vscode.TextEdit(toVscodeRange(edit.range), edit.newText), + ); // telemetry end format sendTelemetryEvent( diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs index 9327d76713..c1c01f5a0b 100644 --- a/wasm/src/language_service.rs +++ b/wasm/src/language_service.rs @@ -201,18 +201,8 @@ impl LanguageService { edits .into_iter() .map(|edit| { - // ToDo: is there an easier way to convert data types? TextEdit { - range: Range { - start: Position { - line: edit.range.start.line, - character: edit.range.start.column, - }, - end: Position { - line: edit.range.end.line, - character: edit.range.end.column, - }, - }, + range: edit.range.into(), newText: edit.new_text, } .into() From 04f5f0d1545d8323adb3fdc78bb6791db8f90d9f Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 13 Mar 2024 15:04:47 -0700 Subject: [PATCH 60/74] added some more tests --- compiler/qsc_formatter/src/formatter.rs | 7 +- compiler/qsc_formatter/src/formatter/tests.rs | 133 +++++++++++++++++- compiler/qsc_parse/src/lex/concrete.rs | 2 +- wasm/src/language_service.rs | 6 +- 4 files changed, 141 insertions(+), 7 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index c35f30220e..ea133b4f24 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -217,7 +217,8 @@ fn apply_rules( (_, TokenKind::Keyword(Keyword::Auto)) | (_, TokenKind::Keyword(Keyword::Distribute)) | (_, TokenKind::Keyword(Keyword::Intrinsic)) - | (_, TokenKind::Keyword(Keyword::Invert)) => { + | (_, TokenKind::Keyword(Keyword::Invert)) + | (_, TokenKind::Keyword(Keyword::Slf)) => { effect_single_space(left, whitespace, right, &mut edits); } (_, _) if new_line_in_spaces => { @@ -252,6 +253,10 @@ fn apply_rules( effect_single_space(left, whitespace, right, &mut edits); } } + (TokenKind::DotDotDot, TokenKind::Open(Delim::Brace)) => { + // Special case: `... {}` + effect_single_space(left, whitespace, right, &mut edits); + } (_, TokenKind::Keyword(Keyword::Is)) | (_, TokenKind::Keyword(Keyword::For)) | (_, TokenKind::Keyword(Keyword::While)) diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index ce95109bd0..420069e648 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -53,10 +53,82 @@ World\"" #[test] fn namespace_items_begin_on_their_own_lines() { check( - "operation Foo() : Unit {} operation Bar() : Unit {}", + "operation Foo() : Unit {} function Bar() : Unit {}", &expect![[r#" operation Foo() : Unit {} - operation Bar() : Unit {}"#]], + function Bar() : Unit {}"#]], + ); +} + +// Functor specializations begin on their own lines + +#[test] +fn functor_specs_begin_on_their_own_lines() { + check( + "operation Foo() : Unit { body ... {} adjoint ... {} controlled (c, ...) {} controlled adjoint (c, ...) {} }", + &expect![[r#" + operation Foo() : Unit { + body ... {} + adjoint ... {} + controlled (c, ...) {} + controlled adjoint (c, ...) {} + }"#]], + ); +} + +#[test] +fn single_space_between_adjoint_controlled_func_spec_keywords() { + check( + indoc! {" + operation Foo() : Unit { + body ... {} + adjoint ... {} + controlled (c, ...) {} + controlled adjoint (c, ...) {} + } + operation Bar() : Unit { + body ... {} + adjoint ... {} + controlled (c, ...) {} + adjoint controlled (c, ...) {} + }"}, + &expect![[r#" + operation Foo() : Unit { + body ... {} + adjoint ... {} + controlled (c, ...) {} + controlled adjoint (c, ...) {} + } + operation Bar() : Unit { + body ... {} + adjoint ... {} + controlled (c, ...) {} + adjoint controlled (c, ...) {} + }"#]], + ); +} + +// Single spaces before generator keywords + +#[test] +fn single_spaces_before_generator_keywords() { + check( + indoc! {" + operation Foo() : Unit { + body ... intrinsic + adjoint ... invert + controlled (c, ...) distribute + controlled adjoint (c, ...) auto + adjoint ... self + }"}, + &expect![[r#" + operation Foo() : Unit { + body ... intrinsic + adjoint ... invert + controlled (c, ...) distribute + controlled adjoint (c, ...) auto + adjoint ... self + }"#]], ); } @@ -488,6 +560,63 @@ fn remove_spaces_between_empty_delimiters() { ); } +// Single space before literals + +#[test] +fn single_space_before_literals() { + check( + indoc! {" + let x = 15; + let x = 0xF; + let x = 15.0; + let x = 15L; + let x = \"Fifteen\"; + let x = $\"Fifteen\"; + let x = PauliI; + let x = PauliX; + let x = PauliY; + let x = PauliZ; + let x = true; + let x = false; + let x = One; + let x = Zero; + "}, + &expect![[r#" + let x = 15; + let x = 0xF; + let x = 15.0; + let x = 15L; + let x = "Fifteen"; + let x = $"Fifteen"; + let x = PauliI; + let x = PauliX; + let x = PauliY; + let x = PauliZ; + let x = true; + let x = false; + let x = One; + let x = Zero; + "#]], + ); +} + +// Single space before types + +#[test] +fn single_space_before_types() { + check( + "let x : (Int, Double, String[], (BigInt, Unit), ('T,)) => 'T = foo;", + &expect![[r#"let x : (Int, Double, String[], (BigInt, Unit), ('T,)) => 'T = foo;"#]], + ); +} + +// Single space before variables + +#[test] +fn single_space_before_idents() { + check("let x = foo;", &expect!["let x = foo;"]); +} + // Correct indentation, which increases by four spaces when a brace-delimited block is opened and decreases when block is closed #[test] diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 51bd9ddc04..107453079c 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -101,7 +101,7 @@ impl Iterator for ConcreteTokenIterator<'_> { // Their full information is contained in the following token. return self.next(); } - // This will panic if any content other than whitespace or comments are ignored when "cooking" the raw tokens + // This will panic if any other non-handled raw tokens didn't get cooked _ => panic!("Raw Token couldn't be converted: {raw_token:?}"), }; Some(concrete) diff --git a/wasm/src/language_service.rs b/wasm/src/language_service.rs index c1c01f5a0b..c8f27a9b1c 100644 --- a/wasm/src/language_service.rs +++ b/wasm/src/language_service.rs @@ -162,9 +162,9 @@ impl LanguageService { additionalTextEdits: i.additional_text_edits.map(|edits| { edits .into_iter() - .map(|(span, text)| TextEdit { - range: span.into(), - newText: text, + .map(|edit| TextEdit { + range: edit.range.into(), + newText: edit.new_text, }) .collect() }), From 2f792dc30f577e5e4c566978a0934789cb45b591 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 13 Mar 2024 15:18:27 -0700 Subject: [PATCH 61/74] update completions tests --- language_service/src/completion/tests.rs | 104 +++++++++++------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/language_service/src/completion/tests.rs b/language_service/src/completion/tests.rs index 51ffe7d6c5..34a6c24517 100644 --- a/language_service/src/completion/tests.rs +++ b/language_service/src/completion/tests.rs @@ -151,8 +151,9 @@ fn ignore_unstable_callable() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 2, column: 12, @@ -162,8 +163,7 @@ fn ignore_unstable_callable() { column: 12, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, @@ -203,8 +203,9 @@ fn ignore_internal_callable() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 2, column: 12, @@ -214,8 +215,7 @@ fn ignore_internal_callable() { column: 12, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, @@ -334,8 +334,9 @@ fn in_block_contains_std_functions() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 1, column: 4, @@ -345,8 +346,7 @@ fn in_block_contains_std_functions() { column: 4, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, @@ -363,8 +363,9 @@ fn in_block_contains_std_functions() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 1, column: 4, @@ -374,8 +375,7 @@ fn in_block_contains_std_functions() { column: 4, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, @@ -392,8 +392,9 @@ fn in_block_contains_std_functions() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 1, column: 4, @@ -403,8 +404,7 @@ fn in_block_contains_std_functions() { column: 4, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, @@ -566,8 +566,9 @@ fn in_block_from_other_namespace() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open Other;\n ", + range: Range { start: Position { line: 1, column: 4, @@ -577,8 +578,7 @@ fn in_block_from_other_namespace() { column: 4, }, }, - "open Other;\n ", - ), + }, ], ), }, @@ -618,8 +618,9 @@ fn auto_open_multiple_files() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open Foo;\n ", + range: Range { start: Position { line: 0, column: 16, @@ -629,8 +630,7 @@ fn auto_open_multiple_files() { column: 16, }, }, - "open Foo;\n ", - ), + }, ], ), }, @@ -797,8 +797,9 @@ fn stdlib_udt() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 1, column: 4, @@ -808,8 +809,7 @@ fn stdlib_udt() { column: 4, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, @@ -876,8 +876,9 @@ fn notebook_top_level() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n", + range: Range { start: Position { line: 0, column: 0, @@ -887,8 +888,7 @@ fn notebook_top_level() { column: 0, }, }, - "open FakeStdLib;\n", - ), + }, ], ), }, @@ -922,8 +922,9 @@ fn notebook_top_level_global() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n", + range: Range { start: Position { line: 0, column: 0, @@ -933,8 +934,7 @@ fn notebook_top_level_global() { column: 0, }, }, - "open FakeStdLib;\n", - ), + }, ], ), }, @@ -1001,8 +1001,9 @@ fn notebook_block() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n", + range: Range { start: Position { line: 0, column: 0, @@ -1012,8 +1013,7 @@ fn notebook_block() { column: 0, }, }, - "open FakeStdLib;\n", - ), + }, ], ), }, @@ -1056,8 +1056,9 @@ fn notebook_auto_open_start_of_cell_empty() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n", + range: Range { start: Position { line: 0, column: 0, @@ -1067,8 +1068,7 @@ fn notebook_auto_open_start_of_cell_empty() { column: 0, }, }, - "open FakeStdLib;\n", - ), + }, ], ), }, @@ -1100,8 +1100,9 @@ fn notebook_auto_open_start_of_cell() { ), additional_text_edits: Some( [ - ( - Range { + TextEdit { + new_text: "open FakeStdLib;\n ", + range: Range { start: Position { line: 0, column: 3, @@ -1111,8 +1112,7 @@ fn notebook_auto_open_start_of_cell() { column: 3, }, }, - "open FakeStdLib;\n ", - ), + }, ], ), }, From a8905aa3c99abcf4aeacf16d51ebd4d1d3f68d97 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 13 Mar 2024 17:03:11 -0700 Subject: [PATCH 62/74] handle error cases --- compiler/qsc_formatter/src/formatter/tests.rs | 27 +++++++++++++++++++ compiler/qsc_parse/src/lex/concrete.rs | 6 +---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 420069e648..a565d89f63 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -617,6 +617,33 @@ fn single_space_before_idents() { check("let x = foo;", &expect!["let x = foo;"]); } +// Formatter continues after error token + +#[test] +fn formatter_continues_after_error_token() { + check( + indoc! {" + let x : ' T = foo; + let x : ` T = foo; + let x : & T = foo; + let x : || T = foo; + let x : ^^ T = foo; + "}, + &expect![[r#" + let x : ' T = foo; + let x : ` T = foo; + let x : & T = foo; + let x : || T = foo; + let x : ^^ T = foo; + "#]], + ); +} + +#[test] +fn formatter_does_not_crash_on_non_terminating_string() { + super::calculate_format_edits("let x = \"Hello World"); +} + // Correct indentation, which increases by four spaces when a brace-delimited block is opened and decreases when block is closed #[test] diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index 107453079c..e4c7c12f37 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -96,13 +96,9 @@ impl Iterator for ConcreteTokenIterator<'_> { kind: ConcreteTokenKind::WhiteSpace, span, }, - raw::TokenKind::Single(raw::Single::Apos) => { - // Apostrophes are handled a bit strangely. - // Their full information is contained in the following token. + _ => { return self.next(); } - // This will panic if any other non-handled raw tokens didn't get cooked - _ => panic!("Raw Token couldn't be converted: {raw_token:?}"), }; Some(concrete) } From dd9b10fc7aedfb8703780a23f168bbc5fca306da Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Mar 2024 11:01:36 -0700 Subject: [PATCH 63/74] get raw tokens at start of content --- compiler/qsc_formatter/src/formatter.rs | 4 +- compiler/qsc_formatter/src/formatter/tests.rs | 25 +++++++++++- compiler/qsc_parse/src/lex/concrete.rs | 38 +++++++++++++++---- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/compiler/qsc_formatter/src/formatter.rs b/compiler/qsc_formatter/src/formatter.rs index ea133b4f24..df9572ed8d 100644 --- a/compiler/qsc_formatter/src/formatter.rs +++ b/compiler/qsc_formatter/src/formatter.rs @@ -99,8 +99,8 @@ pub fn calculate_format_edits(code: &str) -> Vec { } (None, None, Some(three)) => { // Remove any whitespace at the start of a file - if three.span.lo != 0 { - vec![TextEdit::new("", 0, three.span.lo)] + if matches!(three.kind, ConcreteTokenKind::WhiteSpace) { + vec![TextEdit::new("", three.span.lo, three.span.hi)] } else { vec![] } diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index a565d89f63..6847c80576 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -710,7 +710,30 @@ fn preserve_user_newlines_in_expressions() { assert!(super::calculate_format_edits(input).is_empty()); } -// Extra test case for sanity +// Remove extra whitespace from start of code + +#[test] +fn remove_extra_whitespace_from_start_of_code() { + let input = indoc! {r#" + + + + + namespace Foo {}"#}; + + check(input, &expect!["namespace Foo {}"]); +} + +// Extra test cases for sanity + +#[test] +fn preserve_comments_at_start_of_file() { + let input = indoc! {r#" + // Initial Comment + namespace Foo {}"#}; + + assert!(super::calculate_format_edits(input).is_empty()); +} #[test] fn sample_has_no_formatting_changes() { diff --git a/compiler/qsc_parse/src/lex/concrete.rs b/compiler/qsc_parse/src/lex/concrete.rs index e4c7c12f37..dee4f6c63c 100644 --- a/compiler/qsc_parse/src/lex/concrete.rs +++ b/compiler/qsc_parse/src/lex/concrete.rs @@ -41,20 +41,34 @@ pub struct ConcreteTokenIterator<'a> { impl<'a> ConcreteTokenIterator<'a> { #[must_use] pub fn new(code: &'a str) -> Self { + let mut cooked_tokens = cooked::Lexer::new(code).peekable(); + let non_compilation_tokens = match cooked_tokens.peek() { + Some(first) => { + let lo = match first { + Ok(okay) => okay.span.lo, + Err(err) => err.span().lo, + }; + if lo != 0 { + match get_tokens_from_span(code, 0, lo) { + Some(iter) => iter, + None => raw::Lexer::new("").peekable(), + } + } else { + raw::Lexer::new("").peekable() + } + } + None => raw::Lexer::new(code).peekable(), + }; Self { code, - cooked_tokens: cooked::Lexer::new(code).peekable(), - non_compilation_tokens: raw::Lexer::new("").peekable(), + cooked_tokens, + non_compilation_tokens, } } fn get_tokens_from_span(&mut self, lo: u32, hi: u32) { - let starting_offset = lo; - let lo = lo as usize; - let hi = hi as usize; - if let Some(slice) = self.code.get(lo..hi) { - self.non_compilation_tokens = - raw::Lexer::new_with_starting_offset(slice, starting_offset).peekable(); + if let Some(iter) = get_tokens_from_span(self.code, lo, hi) { + self.non_compilation_tokens = iter; } } @@ -76,6 +90,14 @@ impl<'a> ConcreteTokenIterator<'a> { } } +fn get_tokens_from_span(code: &str, lo: u32, hi: u32) -> Option>> { + let starting_offset = lo; + let lo = lo as usize; + let hi = hi as usize; + code.get(lo..hi) + .map(|slice| raw::Lexer::new_with_starting_offset(slice, starting_offset).peekable()) +} + impl Iterator for ConcreteTokenIterator<'_> { type Item = ConcreteToken; From 80ba9e7ed5280f1b0a88df5b0f2f31b270ecd905 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Mar 2024 13:27:34 -0700 Subject: [PATCH 64/74] samples formatted --- samples/algorithms/BernsteinVazirani.qs | 2 +- samples/algorithms/BitFlipCode.qs | 14 ++-- samples/algorithms/DeutschJozsa.qs | 8 +-- samples/algorithms/Entanglement.qs | 2 +- samples/algorithms/HiddenShift.qs | 4 +- samples/algorithms/HiddenShiftNISQ.qs | 4 +- samples/algorithms/Measurement.qs | 2 +- samples/algorithms/PhaseFlipCode.qs | 14 ++-- samples/algorithms/QRNG.qs | 2 +- samples/algorithms/RandomBit.qs | 2 +- samples/algorithms/Shor.qs | 12 ++-- samples/algorithms/Superposition.qs | 2 +- samples/algorithms/Teleportation.qs | 2 +- samples/estimation/Dynamics.qs | 35 +++++----- samples/estimation/EkeraHastadFactoring.qs | 18 +++-- samples/estimation/ShorRE.qs | 4 +- .../df-chemistry/src/df_chemistry.qs | 68 ++++++++++--------- .../estimation/df-chemistry/src/prepare.qs | 26 +++---- samples/language/Comments.qs | 4 +- samples/language/ConditionalBranching.qs | 14 +++- samples/language/EntryPoint.qs | 2 +- samples/language/ForLoops.qs | 6 +- samples/language/LambdaExpression.qs | 2 +- samples/language/MultiFileProject/src/Main.qs | 16 ++--- .../language/MultiFileProject/src/Particle.qs | 12 ++-- samples/language/Namespaces.qs | 2 +- samples/language/Operations.qs | 12 ++-- samples/language/Pauli.qs | 4 +- samples/language/QuantumMemory.qs | 2 +- samples/language/Qubit.qs | 4 +- samples/language/Range.qs | 2 +- samples/language/Result.qs | 2 +- samples/language/ReturnStatement.qs | 2 +- samples/language/Specializations.qs | 32 ++++----- samples/language/Unit.qs | 2 +- 35 files changed, 175 insertions(+), 166 deletions(-) diff --git a/samples/algorithms/BernsteinVazirani.qs b/samples/algorithms/BernsteinVazirani.qs index 70b983b996..88b81c2e47 100644 --- a/samples/algorithms/BernsteinVazirani.qs +++ b/samples/algorithms/BernsteinVazirani.qs @@ -148,7 +148,7 @@ namespace Sample { // Apply the quantum operations that encode the bit string. for index in IndexRange(xRegister) { - if ((bitStringAsInt &&& 2^index) != 0) { + if ((bitStringAsInt &&& 2 ^ index) != 0) { CNOT(xRegister[index], yQubit); } } diff --git a/samples/algorithms/BitFlipCode.qs b/samples/algorithms/BitFlipCode.qs index 19b2308661..1f3b39213e 100644 --- a/samples/algorithms/BitFlipCode.qs +++ b/samples/algorithms/BitFlipCode.qs @@ -119,14 +119,14 @@ namespace Sample { // parity measurements. let indexOfError = if (parity01, parity12) == (One, Zero) { - 0 - } elif (parity01, parity12) == (One, One) { - 1 - } elif (parity01, parity12) == (Zero, One) { - 2 - } else { + 0 + } elif (parity01, parity12) == (One, One) { + 1 + } elif (parity01, parity12) == (Zero, One) { + 2 + } else { -1 - }; + }; // If an error was detected, correct that qubit. if indexOfError > -1 { diff --git a/samples/algorithms/DeutschJozsa.qs b/samples/algorithms/DeutschJozsa.qs index 718a69b9bd..c60249eb01 100644 --- a/samples/algorithms/DeutschJozsa.qs +++ b/samples/algorithms/DeutschJozsa.qs @@ -40,7 +40,7 @@ namespace Sample { let isConstant = DeutschJozsa(fn, 5); if (isConstant != shouldBeConstant) { let shouldBeConstantStr = shouldBeConstant ? - "constant" | + "constant" | "balanced"; fail $"{name} should be detected as {shouldBeConstantStr}"; } @@ -104,7 +104,7 @@ namespace Sample { // state so that they can be safely deallocated at the end of the block. // The loop also sets `result` to `true` if all measurement results are // `Zero`, i.e. if the function is a constant function, and sets - // `result` to `false` if not, which according to the assumption on 𝑓 + // `result` to `false` if not, which according to the assumption on 𝑓 // means that it must be balanced. mutable result = true; for q in queryRegister { @@ -131,7 +131,7 @@ namespace Sample { // A more complex constant Boolean function. // It applies X to every input basis vector. operation ConstantBoolF(args : Qubit[], target : Qubit) : Unit { - for i in 0..(2^Length(args))-1 { + for i in 0..(2 ^ Length(args))-1 { ApplyControlledOnInt(i, X, args, target); } } @@ -139,7 +139,7 @@ namespace Sample { // A more complex balanced Boolean function. // It applies X to half of the input basis vectors. operation BalancedBoolF(args : Qubit[], target : Qubit) : Unit { - for i in 0..2..(2^Length(args))-1 { + for i in 0..2..(2 ^ Length(args))-1 { ApplyControlledOnInt(i, X, args, target); } } diff --git a/samples/algorithms/Entanglement.qs b/samples/algorithms/Entanglement.qs index de63ed8804..dca96c80f7 100644 --- a/samples/algorithms/Entanglement.qs +++ b/samples/algorithms/Entanglement.qs @@ -14,7 +14,7 @@ namespace Sample { // Allocate the two qubits that will be entangled. use (q1, q2) = (Qubit(), Qubit()); - // Set the first qubit in superposition by calling the `H` operation, + // Set the first qubit in superposition by calling the `H` operation, // which applies a Hadamard transformation to the qubit. // Then, entangle the two qubits using the `CNOT` operation. H(q1); diff --git a/samples/algorithms/HiddenShift.qs b/samples/algorithms/HiddenShift.qs index 32f9bf58b5..58fc6ee399 100644 --- a/samples/algorithms/HiddenShift.qs +++ b/samples/algorithms/HiddenShift.qs @@ -81,7 +81,7 @@ namespace Sample { /// - [*Martin Roetteler*, /// Proc. SODA 2010, ACM, pp. 448-457, 2010] /// (https://doi.org/10.1137/1.9781611973075.37) - operation FindHiddenShift ( + operation FindHiddenShift( Ufstar : (Qubit[] => Unit), Ug : (Qubit[] => Unit), n : Int) @@ -142,7 +142,7 @@ namespace Sample { operation BentFunction(register : Qubit[]) : Unit { Fact(Length(register) % 2 == 0, "Length of register must be even."); let u = Length(register) / 2; - let xs = register[0 .. u - 1]; + let xs = register[0..u - 1]; let ys = register[u...]; for index in 0..u-1 { CZ(xs[index], ys[index]); diff --git a/samples/algorithms/HiddenShiftNISQ.qs b/samples/algorithms/HiddenShiftNISQ.qs index 75d8cdd4ce..c063c4d3a2 100644 --- a/samples/algorithms/HiddenShiftNISQ.qs +++ b/samples/algorithms/HiddenShiftNISQ.qs @@ -72,7 +72,7 @@ namespace Sample { /// - [*Martin Roetteler*, /// Proc. SODA 2010, ACM, pp. 448-457, 2010] /// (https://doi.org/10.1137/1.9781611973075.37) - operation FindHiddenShift ( + operation FindHiddenShift( Ufstar : (Qubit[] => Unit), Ug : (Qubit[] => Unit), n : Int) @@ -133,7 +133,7 @@ namespace Sample { operation BentFunction(register : Qubit[]) : Unit { Fact(Length(register) % 2 == 0, "Length of register must be even."); let u = Length(register) / 2; - let xs = register[0 .. u - 1]; + let xs = register[0..u - 1]; let ys = register[u...]; for index in 0..u-1 { CZ(xs[index], ys[index]); diff --git a/samples/algorithms/Measurement.qs b/samples/algorithms/Measurement.qs index 8a0f1959de..4f0d9ad15e 100644 --- a/samples/algorithms/Measurement.qs +++ b/samples/algorithms/Measurement.qs @@ -14,7 +14,7 @@ namespace Sample { open Microsoft.Quantum.Measurement; @EntryPoint() - operation Main () : (Result, Result[]) { + operation Main() : (Result, Result[]) { // The `M` operation performs a measurement of a single qubit in the // computational basis, also known as the Pauli Z basis. use q = Qubit(); diff --git a/samples/algorithms/PhaseFlipCode.qs b/samples/algorithms/PhaseFlipCode.qs index b70ece981f..10788523ec 100644 --- a/samples/algorithms/PhaseFlipCode.qs +++ b/samples/algorithms/PhaseFlipCode.qs @@ -140,14 +140,14 @@ namespace Sample { // parity measurements. let indexOfError = if (parity01, parity12) == (One, Zero) { - 0 - } elif (parity01, parity12) == (One, One) { - 1 - } elif (parity01, parity12) == (Zero, One) { - 2 - } else { + 0 + } elif (parity01, parity12) == (One, One) { + 1 + } elif (parity01, parity12) == (Zero, One) { + 2 + } else { -1 - }; + }; // If an error was detected, correct that qubit. if indexOfError > -1 { diff --git a/samples/algorithms/QRNG.qs b/samples/algorithms/QRNG.qs index c04994e4cc..95b951a8e4 100644 --- a/samples/algorithms/QRNG.qs +++ b/samples/algorithms/QRNG.qs @@ -42,7 +42,7 @@ namespace Sample { // Allocate a qubit. use q = Qubit(); - // Set the qubit into superposition of 0 and 1 using the Hadamard + // Set the qubit into superposition of 0 and 1 using the Hadamard // operation `H`. H(q); diff --git a/samples/algorithms/RandomBit.qs b/samples/algorithms/RandomBit.qs index 66538329ee..4d4c119f2d 100644 --- a/samples/algorithms/RandomBit.qs +++ b/samples/algorithms/RandomBit.qs @@ -16,7 +16,7 @@ namespace Sample { // Set the qubit in superposition by applying a Hadamard transformation. H(qubit); - // Measure the qubit. There is a 50% probability of measuring either + // Measure the qubit. There is a 50% probability of measuring either // `Zero` or `One`. let result = M(qubit); diff --git a/samples/algorithms/Shor.qs b/samples/algorithms/Shor.qs index 787f168b7b..781b32f915 100644 --- a/samples/algorithms/Shor.qs +++ b/samples/algorithms/Shor.qs @@ -79,12 +79,11 @@ namespace Sample { set foundFactors = true; set factors = (gcd, number / gcd); } - set attempt = attempt+1; + set attempt = attempt + 1; if (attempt > 100) { fail "Failed to find factors: too many attempts!"; } - } - until foundFactors + } until foundFactors fixup { Message("The estimated period did not yield a valid factor. " + "Trying again."); @@ -235,8 +234,7 @@ namespace Sample { if frequencyEstimate != 0 { return PeriodFromFrequency( modulus, frequencyEstimate, bitsPrecision, 1); - } - else { + } else { Message("The estimated frequency was 0, trying again."); return 1; } @@ -258,10 +256,10 @@ namespace Sample { /// /// # Output /// The numerator k of dyadic fraction k/2^bitsPrecision approximating s/r. - operation EstimateFrequency(generator : Int,modulus : Int, bitsize : Int) + operation EstimateFrequency(generator : Int, modulus : Int, bitsize : Int) : Int { mutable frequencyEstimate = 0; - let bitsPrecision = 2 * bitsize + 1; + let bitsPrecision = 2 * bitsize + 1; Message($"Estimating frequency with bitsPrecision={bitsPrecision}."); // Allocate qubits for the superposition of eigenstates of the oracle diff --git a/samples/algorithms/Superposition.qs b/samples/algorithms/Superposition.qs index 5ed19e77b4..c00bb69255 100644 --- a/samples/algorithms/Superposition.qs +++ b/samples/algorithms/Superposition.qs @@ -15,7 +15,7 @@ namespace Sample { // Set the qubit in superposition by applying a Hadamard transformation. H(qubit); - // Measure the qubit. There is a 50% probability of measuring either + // Measure the qubit. There is a 50% probability of measuring either // `Zero` or `One`. let result = M(qubit); diff --git a/samples/algorithms/Teleportation.qs b/samples/algorithms/Teleportation.qs index 21c2e8e398..924c493ac0 100644 --- a/samples/algorithms/Teleportation.qs +++ b/samples/algorithms/Teleportation.qs @@ -15,7 +15,7 @@ namespace Sample { open Microsoft.Quantum.Measurement; @EntryPoint() - operation Main () : Result[] { + operation Main() : Result[] { // Allocate the message and target qubits. use (message, target) = (Qubit(), Qubit()); diff --git a/samples/estimation/Dynamics.qs b/samples/estimation/Dynamics.qs index 95d9832159..01aabc0534 100644 --- a/samples/estimation/Dynamics.qs +++ b/samples/estimation/Dynamics.qs @@ -50,39 +50,36 @@ namespace QuantumDynamics { let len1 = 3; let len2 = 3; - let valLength = 2*len1+len2+1; - mutable values = [0.0, size=valLength]; + let valLength = 2 * len1 + len2 + 1; + mutable values = [0.0, size = valLength]; - let val1 = J*p*dt; - let val2 = -g*p*dt; - let val3 = J*(1.0 - 3.0*p)*dt/2.0; - let val4 = g*(1.0 - 4.0*p)*dt/2.0; + let val1 = J * p * dt; + let val2 = -g * p * dt; + let val3 = J * (1.0 - 3.0 * p) * dt / 2.0; + let val4 = g * (1.0 - 4.0 * p) * dt / 2.0; for i in 0..len1 { if (i % 2 == 0) { set values w/= i <- val1; - } - else { + } else { set values w/= i <- val2; } } - for i in len1+1..len1+len2 { + for i in len1 + 1..len1 + len2 { if (i % 2 == 0) { set values w/= i <- val3; - } - else { + } else { set values w/= i <- val4; } } - for i in len1+len2+1..valLength-1 { + for i in len1 + len2 + 1..valLength-1 { if (i % 2 == 0) { set values w/= i <- val1; - } - else { + } else { set values w/= i <- val2; } } @@ -128,8 +125,8 @@ namespace QuantumDynamics { for row in 0..r_end { for col in start..2..c_end { // Iterate through even or odd columns based on `grp` - let row2 = dir ? row+1 | row; - let col2 = dir ? col | col+1; + let row2 = dir ? row + 1 | row; + let col2 = dir ? col | col + 1; Exp(P_op, theta, [qArr[row][col], qArr[row2][col2]]); } @@ -151,10 +148,10 @@ namespace QuantumDynamics { /// operation IsingModel2DSim(N1 : Int, N2 : Int, J : Double, g : Double, totTime : Double, dt : Double) : Unit { - use qs = Qubit[N1*N2]; + use qs = Qubit[N1 * N2]; let qubitArray = Chunks(N2, qs); // qubits are re-arranged to be in an N1 x N2 array - let p = 1.0 / (4.0 - 4.0^(1.0 / 3.0)); + let p = 1.0 / (4.0 - 4.0 ^ (1.0 / 3.0)); let t = Ceiling(totTime / dt); let seqLen = 10 * t + 1; @@ -162,7 +159,7 @@ namespace QuantumDynamics { let angSeq = SetAngleSequence(p, dt, J, g); for i in 0..seqLen - 1 { - let theta = (i==0 or i==seqLen-1) ? J*p*dt/2.0 | angSeq[i%10]; + let theta = (i == 0 or i == seqLen-1) ? J * p * dt / 2.0 | angSeq[i % 10]; // for even indexes if i % 2 == 0 { diff --git a/samples/estimation/EkeraHastadFactoring.qs b/samples/estimation/EkeraHastadFactoring.qs index 248c7529f8..adf63a4f36 100644 --- a/samples/estimation/EkeraHastadFactoring.qs +++ b/samples/estimation/EkeraHastadFactoring.qs @@ -71,10 +71,14 @@ namespace Microsoft.Quantum.Applications.Cryptography { // ------------------------------ // /// Window size for exponentiation (c_exp) - internal function ExponentWindowLength_() : Int { 5 } + internal function ExponentWindowLength_() : Int { + 5 + } /// Window size for multiplication (c_mul) - internal function MultiplicationWindowLength_() : Int { 5 } + internal function MultiplicationWindowLength_() : Int { + 5 + } // ------------------------------- // // Modular arithmetic (operations) // @@ -184,11 +188,11 @@ namespace Microsoft.Quantum.Applications.Cryptography { } internal function LookupData(factor : BigInt, expLength : Int, mulLength : Int, base : BigInt, mod : BigInt, sign : Int, numBits : Int) : Bool[][] { - mutable data = [[false, size = numBits], size = 2^(expLength + mulLength)]; - for b in 0..2^mulLength - 1 { - for a in 0..2^expLength - 1 { - let idx = b * 2^expLength + a; - let value = ModulusL(factor * IntAsBigInt(b) * IntAsBigInt(sign) * (base^a), mod); + mutable data = [[false, size = numBits], size = 2 ^ (expLength + mulLength)]; + for b in 0..2 ^ mulLength - 1 { + for a in 0..2 ^ expLength - 1 { + let idx = b * 2 ^ expLength + a; + let value = ModulusL(factor * IntAsBigInt(b) * IntAsBigInt(sign) * (base ^ a), mod); set data w/= idx <- BigIntAsBoolArray(value, numBits); } } diff --git a/samples/estimation/ShorRE.qs b/samples/estimation/ShorRE.qs index 4f3939ca69..3426539c5c 100644 --- a/samples/estimation/ShorRE.qs +++ b/samples/estimation/ShorRE.qs @@ -23,7 +23,7 @@ namespace Shors { // When chooseing parameters for `EstimateFrequency`, make sure that // generator and modules are not co-prime - let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize); + let _ = EstimateFrequency(11, 2 ^ bitsize - 1, bitsize); } /// # Summary @@ -50,7 +50,7 @@ namespace Shors { ) : Int { mutable frequencyEstimate = 0; - let bitsPrecision = 2 * bitsize + 1; + let bitsPrecision = 2 * bitsize + 1; // Allocate qubits for the superposition of eigenstates of // the oracle that is used in period finding. diff --git a/samples/estimation/df-chemistry/src/df_chemistry.qs b/samples/estimation/df-chemistry/src/df_chemistry.qs index 25e2e31220..d03fd1b9eb 100644 --- a/samples/estimation/df-chemistry/src/df_chemistry.qs +++ b/samples/estimation/df-chemistry/src/df_chemistry.qs @@ -20,28 +20,28 @@ namespace Microsoft.Quantum.Applications.Chemistry { /// # Reference /// arXiv:2007.14460, p. 9, eq. 9 newtype DoubleFactorizedChemistryProblem = ( - // Number of orbitals (N, p. 8) - NumOrbitals: Int, - // one-body norm (ǁL⁽⁻¹⁾ǁ, p. 8, eq. 16) - OneBodyNorm: Double, - // one-body norm (¼∑ǁL⁽ʳ⁾ǁ², p. 8, eq. 16) - TwoBodyNorm: Double, - // eigenvalues in the EVD of the one-electron Hamiltonian (λₖ, p. 54, eq. 67) - OneBodyEigenValues: Double[], - // eigenvectors in the EVD of the one-electron Hamiltonian (Rₖ, p. 54, eq. 67) - OneBodyEigenVectors: Double[][], - // norms inside Λ_SH (p. 56, eq. 77) - Lambdas: Double[], - // eigenvalues in the EVDs of the two-electron Hamiltonian for all r (λₖ⁽ʳ⁾, p. 56, eq. 77) - TwoBodyEigenValues: Double[][], - // eigenvectors in the EVDs of the two-electron Hamiltonian for all r (R⁽ʳ⁾ₖ, p. 56, eq. 77) - TwoBodyEigenVectors: Double[][][], + // Number of orbitals (N, p. 8) + NumOrbitals : Int, + // one-body norm (ǁL⁽⁻¹⁾ǁ, p. 8, eq. 16) + OneBodyNorm : Double, + // one-body norm (¼∑ǁL⁽ʳ⁾ǁ², p. 8, eq. 16) + TwoBodyNorm : Double, + // eigenvalues in the EVD of the one-electron Hamiltonian (λₖ, p. 54, eq. 67) + OneBodyEigenValues : Double[], + // eigenvectors in the EVD of the one-electron Hamiltonian (Rₖ, p. 54, eq. 67) + OneBodyEigenVectors : Double[][], + // norms inside Λ_SH (p. 56, eq. 77) + Lambdas : Double[], + // eigenvalues in the EVDs of the two-electron Hamiltonian for all r (λₖ⁽ʳ⁾, p. 56, eq. 77) + TwoBodyEigenValues : Double[][], + // eigenvectors in the EVDs of the two-electron Hamiltonian for all r (R⁽ʳ⁾ₖ, p. 56, eq. 77) + TwoBodyEigenVectors : Double[][][], ); newtype DoubleFactorizedChemistryParameters = ( - // Standard deviation (ΔE, p. 8, eq. 1) - // Typically set to 0.001 - StandardDeviation: Double, + // Standard deviation (ΔE, p. 8, eq. 1) + // Typically set to 0.001 + StandardDeviation : Double, ); /// # Summary @@ -50,7 +50,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { /// gradient technique (p. 55) operation DoubleFactorizedChemistry( problem : DoubleFactorizedChemistryProblem, - parameters: DoubleFactorizedChemistryParameters + parameters : DoubleFactorizedChemistryParameters ) : Unit { let constants = ComputeConstants(problem, parameters); @@ -86,9 +86,9 @@ namespace Microsoft.Quantum.Applications.Chemistry { /// electron operators, which are computed from the double factorized /// problem and parameters. internal newtype DoubleFactorizedChemistryConstants = ( - RotationAngleBitPrecision: Int, - StatePreparationBitPrecision: Int, - TargetError: Double + RotationAngleBitPrecision : Int, + StatePreparationBitPrecision : Int, + TargetError : Double ); internal function ComputeConstants( @@ -104,7 +104,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { + Lg(Sqrt((IntAsDouble((problem::NumOrbitals - 1) * 8) * PI() * norm) / parameters::StandardDeviation)) + 0.5 * Lg(1.0 / barEpsilon)); let StatePreparationBitPrecision = Ceiling(Lg(1.0 / epsilon) + 2.5); - let TargetError = 2.0^IntAsDouble(1 - StatePreparationBitPrecision); + let TargetError = 2.0 ^ IntAsDouble(1 - StatePreparationBitPrecision); DoubleFactorizedChemistryConstants( RotationAngleBitPrecision, @@ -114,8 +114,8 @@ namespace Microsoft.Quantum.Applications.Chemistry { } internal newtype WalkStep = ( - NGarbageQubits: Int, - StepOp: (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit + NGarbageQubits : Int, + StepOp : (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit ); /// # Summary @@ -150,7 +150,9 @@ namespace Microsoft.Quantum.Applications.Chemistry { within { PrepareSingleQubit(problem::OneBodyNorm, problem::TwoBodyNorm, ctl); } apply { - within { X(ctl); } apply { + within { + X(ctl); + } apply { Controlled oneElectronOperator::Apply([ctl], (register0, register1, phaseGradientRegister, [], helperParts[0])); } Controlled twoElectronOperator::Apply([ctl], (register0, register1, phaseGradientRegister, helperParts[1])); @@ -161,8 +163,8 @@ namespace Microsoft.Quantum.Applications.Chemistry { } internal newtype OneElectronOperator = ( - NGarbageQubits: Int, - Apply: (Qubit[], Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl + NGarbageQubits : Int, + Apply : (Qubit[], Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl ); /// # Summary @@ -235,8 +237,8 @@ namespace Microsoft.Quantum.Applications.Chemistry { } internal newtype TwoElectronOperator = ( - NGarbageQubits: Int, - Apply: (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Ctl + NGarbageQubits : Int, + Apply : (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Ctl ); /// # Summary @@ -330,7 +332,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { mutable bitstrings = []; let tau = 2.0 * PI(); - let preFactor = 2.0^IntAsDouble(precision); + let preFactor = 2.0 ^ IntAsDouble(precision); for eigenVector in eigenVectors { // Computes rotation angles for Majorana operator ($\vec u$ in p. 52, eq. 55) @@ -341,7 +343,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { // We apply MinD, such that rounding errors do not lead to // an argument for ArcCos which is larger than 1.0. (p. 52, eq. 56) let theta = sins == 0.0 ? 0.0 | 0.5 * ArcCos(MinD(eigenVector[index] / sins, 1.0)); - + // all angles as bit string let factor = theta / tau; set result += Reversed(IntAsBoolArray(IsNaN(factor) ? 0 | Floor(preFactor * factor), precision)); diff --git a/samples/estimation/df-chemistry/src/prepare.qs b/samples/estimation/df-chemistry/src/prepare.qs index f06edf9fd6..cec4aff024 100644 --- a/samples/estimation/df-chemistry/src/prepare.qs +++ b/samples/estimation/df-chemistry/src/prepare.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { operation PrepareUniformSuperposition(numStates : Int, qs : Qubit[]) : Unit is Adj + Ctl { Fact(numStates >= 1, "numStates must be positive"); - Fact(numStates <= 2^Length(qs), $"numStates must be smaller or equal to {2^Length(qs)}"); + Fact(numStates <= 2 ^ Length(qs), $"numStates must be smaller or equal to {2 ^ Length(qs)}"); let qsAdjusted = qs[...Ceiling(Lg(IntAsDouble(numStates))) - 1]; @@ -52,10 +52,10 @@ namespace Microsoft.Quantum.Applications.Chemistry { } newtype PrepareArbitrarySuperposition = ( - NIndexQubits: Int, - NGarbageQubits: Int, - Prepare: (Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl, - PrepareWithSelect: ((Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl + NIndexQubits : Int, + NGarbageQubits : Int, + Prepare : (Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl, + PrepareWithSelect : ((Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl ); function MakePrepareArbitrarySuperposition(targetError : Double, coefficients : Double[]) @@ -72,7 +72,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { return PrepareArbitrarySuperposition(nIndexQubits, nGarbageQubits, op, opWithSelect); } - function MakePrepareArbitrarySuperpositionWithData(targetError : Double, coefficients : Double[], data: Bool[][]) : PrepareArbitrarySuperposition { + function MakePrepareArbitrarySuperpositionWithData(targetError : Double, coefficients : Double[], data : Bool[][]) : PrepareArbitrarySuperposition { let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; let positiveCoefficients = Mapped(AbsD, coefficients); let (keepCoeff, altIndex) = DiscretizedProbabilityDistribution(nBitsPrecision, positiveCoefficients); @@ -106,7 +106,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { Fact(targetError > 0.0, "targetError must be positive"); Fact(nCoefficients > 0, "nCoefficients must be positive"); - let nBitsPrecision = -Ceiling(Lg(0.5*targetError)) + 1; + let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; let nIndexQubits = Ceiling(Lg(IntAsDouble(nCoefficients))); let nGarbageQubits = nIndexQubits + 2 * nBitsPrecision + 1; (nIndexQubits, nGarbageQubits) @@ -114,7 +114,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { // Computes discretized probability distribution as described in Section 3 // and Fig. 13 in [arXiv:1805.03662](https://arxiv.org/pdf/1805.03662.pdf) - internal function DiscretizedProbabilityDistribution(bitsPrecision: Int, coefficients: Double[]) + internal function DiscretizedProbabilityDistribution(bitsPrecision : Int, coefficients : Double[]) : (Int[], Int[]) { let oneNorm = PNorm(1.0, coefficients); let nCoefficients = Length(coefficients); @@ -135,7 +135,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { // Uniformly distribute excess bars across coefficients. for idx in 0..AbsI(bars) - 1 { - set keepCoeff w/= idx <- keepCoeff[idx] + (bars > 0 ? -1 | +1); + set keepCoeff w/= idx <- keepCoeff[idx] + (bars > 0 ? -1 | + 1); } mutable barSink = []; @@ -178,10 +178,10 @@ namespace Microsoft.Quantum.Applications.Chemistry { // Used in QuantumROM implementation. internal operation PrepareQuantumROMState( - nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, - keepCoeff: Int[], altIndex: Int[], data : Bool[][], - selectOperation: (Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, - indexRegister: Qubit[], dataQubits : Qubit[], garbageRegister: Qubit[] + nBitsPrecision : Int, nCoeffs : Int, nBitsIndices : Int, + keepCoeff : Int[], altIndex : Int[], data : Bool[][], + selectOperation : (Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, + indexRegister : Qubit[], dataQubits : Qubit[], garbageRegister : Qubit[] ) : Unit is Adj + Ctl { let garbageIdx0 = nBitsIndices; diff --git a/samples/language/Comments.qs b/samples/language/Comments.qs index 8ad7505fca..e8fe1d47d1 100644 --- a/samples/language/Comments.qs +++ b/samples/language/Comments.qs @@ -3,13 +3,13 @@ /// /// # Description /// Comments begin with two forward slashes (`//`) and continue until the -/// end of line. Comments may appear anywhere in the source code. +/// end of line. Comments may appear anywhere in the source code. /// Q# does not currently support block comments. /// Documentation comments, or doc comments, are denoted with three /// forward slashes (`///`) instead of two. namespace MyQuantumApp { open Microsoft.Quantum.Diagnostics; - + /// This is a doc-comment for the `Main` operation. @EntryPoint() operation Main() : Result[] { diff --git a/samples/language/ConditionalBranching.qs b/samples/language/ConditionalBranching.qs index dd63bb8f6e..10950223ba 100644 --- a/samples/language/ConditionalBranching.qs +++ b/samples/language/ConditionalBranching.qs @@ -13,11 +13,15 @@ namespace MyQuantumApp { let number = 5; // Conditionally messages "Fizz" if the `number`, in this case 5, is divisible by 3. // Since 5 is not divisible by 3, the message "Fizz" will not be printed. - if number % 3 == 0 { Message("Fizz"); } + if number % 3 == 0 { + Message("Fizz"); + } // Conditionally messages "Buzz" if the `number`, in this case 5, is divisible by 5. // Since 5 is divisible by 5, the message "Buzz" will be printed. - if number % 5 == 0 { Message("Buzz"); } + if number % 5 == 0 { + Message("Buzz"); + } let fahrenheit = 40; @@ -36,6 +40,10 @@ namespace MyQuantumApp { let fahrenheit = 40; // `if` can also be used as an expression, to conditionally return a value. - let absoluteValue = if fahrenheit > 0 { fahrenheit } else { fahrenheit * -1 }; + let absoluteValue = if fahrenheit > 0 { + fahrenheit + } else { + fahrenheit * -1 + }; } } \ No newline at end of file diff --git a/samples/language/EntryPoint.qs b/samples/language/EntryPoint.qs index 6aed799f25..4be7b7900f 100644 --- a/samples/language/EntryPoint.qs +++ b/samples/language/EntryPoint.qs @@ -3,7 +3,7 @@ /// /// # Description /// The `@EntryPoint()` attribute is used to designate a particular operation as -/// the entry point of a Q# program rather than requiring entry points to have +/// the entry point of a Q# program rather than requiring entry points to have // a particular name such as `main`, `Main`, or `__main__`. namespace MyQuantumApp { diff --git a/samples/language/ForLoops.qs b/samples/language/ForLoops.qs index 98c679ec3a..4c40d886d6 100644 --- a/samples/language/ForLoops.qs +++ b/samples/language/ForLoops.qs @@ -10,13 +10,13 @@ namespace MyQuantumApp { @EntryPoint() operation Main() : Unit { // For loop over `Range` - for i in 0..5 { } + for i in 0..5 {} // For loop over `Array` - for element in [10, 11, 12] { } + for element in [10, 11, 12] {} // For loop over array slice let array = [1.0, 2.0, 3.0, 4.0]; - for element in array[2...] { } + for element in array[2...] {} } } diff --git a/samples/language/LambdaExpression.qs b/samples/language/LambdaExpression.qs index a873e2d13b..26e9c64672 100644 --- a/samples/language/LambdaExpression.qs +++ b/samples/language/LambdaExpression.qs @@ -30,6 +30,6 @@ namespace MyQuantumApp { // `Map` takes a callable and applies it to all elements in // an array let incremented = Mapped(x -> x + 1, intArray); - + } } \ No newline at end of file diff --git a/samples/language/MultiFileProject/src/Main.qs b/samples/language/MultiFileProject/src/Main.qs index 0f30c50484..eaf598229c 100644 --- a/samples/language/MultiFileProject/src/Main.qs +++ b/samples/language/MultiFileProject/src/Main.qs @@ -2,18 +2,18 @@ /// Multi File Project /// /// # Description -/// Organizing code into multiple Q# source files is an important part of +/// Organizing code into multiple Q# source files is an important part of /// writing readable and maintainable code. In this project, we have `Main.qs`, /// and `Particle.qs`, which defines a new namespace for particle operations. /// The presence of a Q# manifest file (`qsharp.json`) tells the compiler /// to include all Q# files under `src/`. namespace MyQuantumApp { - open Particle; - @EntryPoint() - operation Main() : Unit { - let particleA = Particle(0, 0, 0); - let particleB = Particle(1, 1, 1); + open Particle; + @EntryPoint() + operation Main() : Unit { + let particleA = Particle(0, 0, 0); + let particleB = Particle(1, 1, 1); - let particleC = addParticles(particleA, particleB); - } + let particleC = addParticles(particleA, particleB); + } } diff --git a/samples/language/MultiFileProject/src/Particle.qs b/samples/language/MultiFileProject/src/Particle.qs index bbe73ef961..8f6947174b 100644 --- a/samples/language/MultiFileProject/src/Particle.qs +++ b/samples/language/MultiFileProject/src/Particle.qs @@ -1,9 +1,9 @@ namespace Particle { - newtype Particle = (x: Int, y: Int, z: Int); + newtype Particle = (x : Int, y : Int, z : Int); - function addParticles(a: Particle, b: Particle) : Particle { - let (x1, y1, z1) = a!; - let (x2, y2, z2) = b!; - return Particle(x1 + x2, y1 + y2, z1 + z2); - } + function addParticles(a : Particle, b : Particle) : Particle { + let (x1, y1, z1) = a!; + let (x2, y2, z2) = b!; + return Particle(x1 + x2, y1 + y2, z1 + z2); + } } diff --git a/samples/language/Namespaces.qs b/samples/language/Namespaces.qs index d80dcd66df..bdf0579d4c 100644 --- a/samples/language/Namespaces.qs +++ b/samples/language/Namespaces.qs @@ -10,7 +10,7 @@ namespace MyQuantumApp { // The following `open` directive is used to import all types and callables declared in the // Microsoft.Quantum.Diagnostics namespace. open Microsoft.Quantum.Diagnostics; - + @EntryPoint() operation Main() : Result[] { // `DumpMachine` is in the Microsoft.Quantum.Diagnostics namespace diff --git a/samples/language/Operations.qs b/samples/language/Operations.qs index 29840f8f9f..3a8b423e2a 100644 --- a/samples/language/Operations.qs +++ b/samples/language/Operations.qs @@ -1,19 +1,19 @@ /// # Sample -/// Operations +/// Operations /// /// # Description /// Operations are the basic building blocks of a Q# program. A Q# /// operation is a quantum subroutine. That is, it's a callable routine /// that contains quantum operations that modify the state of qubits. namespace MyQuantumApp { - + @EntryPoint() operation MeasureOneQubit() : Result { - // Allocate a qubit, by default it is in zero state - use q = Qubit(); + // Allocate a qubit, by default it is in zero state + use q = Qubit(); // We apply a Hadamard operation H to the state - // It now has a 50% chance of being measured 0 or 1 - H(q); + // It now has a 50% chance of being measured 0 or 1 + H(q); // Now we measure the qubit in Z-basis using the `M` operation. let result = M(q); // We reset the qubit before releasing it using the `Reset` operation. diff --git a/samples/language/Pauli.qs b/samples/language/Pauli.qs index 60a1c09d99..a7ee59fe12 100644 --- a/samples/language/Pauli.qs +++ b/samples/language/Pauli.qs @@ -8,10 +8,10 @@ namespace MyQuantumApp { @EntryPoint() operation Main() : Result { use q = Qubit(); - + // A `Pauli` can be declared as a literal. let pauliDimension = PauliX; - + // Measuring along a dimension returns a `Result`: let result = Measure([pauliDimension], [q]); diff --git a/samples/language/QuantumMemory.qs b/samples/language/QuantumMemory.qs index 044b273160..163d907ebc 100644 --- a/samples/language/QuantumMemory.qs +++ b/samples/language/QuantumMemory.qs @@ -4,7 +4,7 @@ /// # Description /// The primary quantum feature of Q# is its representation of qubits and qubit /// memory. Q# supports allocation of qubits, and differentiates between allocating -/// "clean" qubits and "dirty" qubits with the `use` and `borrow` keywords. +/// "clean" qubits and "dirty" qubits with the `use` and `borrow` keywords. /// Clean qubits are unentangled, whereas dirty qubits are in an unknown state /// and can potentially be entangled. namespace MyQuantumApp { diff --git a/samples/language/Qubit.qs b/samples/language/Qubit.qs index 854ac60349..db3afcb2ce 100644 --- a/samples/language/Qubit.qs +++ b/samples/language/Qubit.qs @@ -2,13 +2,13 @@ /// Qubit /// /// # Description -/// Q# uses the `Qubit` primitive type to represent quantum state. A qubit represents +/// Q# uses the `Qubit` primitive type to represent quantum state. A qubit represents /// the smallest addressable physical unit in a quantum computer. Qubits are long-lived, /// and accumulates transformations to quantum states. A Q# program has no ability to /// introspect into the state of a qubit, and thus is entirely agnostic about what a /// quantum state is or on how it is realized. Rather, a program can call operations /// such as Measure to learn information about the quantum state of the computation. -namespace MyQuantumApp { +namespace MyQuantumApp { open Microsoft.Quantum.Diagnostics; /// In the below code, all varibles have type annotations to showcase their type. @EntryPoint() diff --git a/samples/language/Range.qs b/samples/language/Range.qs index edf568f9bb..086b1d646a 100644 --- a/samples/language/Range.qs +++ b/samples/language/Range.qs @@ -38,7 +38,7 @@ namespace MyQuantumApp { // The array [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]. mutable array = []; for i in 0..10 { - set array += [i^2]; + set array += [i ^ 2]; } // Ranges can be used to create array slices. diff --git a/samples/language/Result.qs b/samples/language/Result.qs index 97435f8637..bc31df74cb 100644 --- a/samples/language/Result.qs +++ b/samples/language/Result.qs @@ -22,7 +22,7 @@ namespace MyQuantumApp { // Measure the qubit. let measurement = M(q); - + // Reset the qubit. Reset(q); diff --git a/samples/language/ReturnStatement.qs b/samples/language/ReturnStatement.qs index 07505706d5..1ae6d924c3 100644 --- a/samples/language/ReturnStatement.qs +++ b/samples/language/ReturnStatement.qs @@ -3,7 +3,7 @@ /// /// # Description /// Return statements are a form of control flow statement that abort the current callable and -/// return control flow to the callee's scope with a given value. +/// return control flow to the callee's scope with a given value. namespace MyQuantumApp { @EntryPoint() operation Main() : Unit { diff --git a/samples/language/Specializations.qs b/samples/language/Specializations.qs index 6fd2016cc8..811be920fa 100644 --- a/samples/language/Specializations.qs +++ b/samples/language/Specializations.qs @@ -5,7 +5,7 @@ /// Q# allows specialized implementations. Operations in Q# can implicitly /// or explicitly define adjoint and/or controlled versions. /// Q# employs symbolic computation that can automatically generate the -/// corresponding adjoint and controlled implementations for a particular +/// corresponding adjoint and controlled implementations for a particular /// body implementation. namespace MyQuantumApp { @@ -13,19 +13,19 @@ namespace MyQuantumApp { /// generated for the `DoNothing` operation that declares supports for these /// specializations using the `is` keyword followed by the union of the supported /// specializations (`Adj + Ctl`). - operation DoNothing() : Unit - is Adj + Ctl { } + operation DoNothing() : Unit + is Adj + Ctl {} - /// Here, the specializations hvae been explicitly defined. + /// Here, the specializations hvae been explicitly defined. /// In the following example, the declaration for an operation SWAP, /// which exchanges the state of two qubits q1 and q2, declares an /// explicit specialization for its adjoint version and its controlled /// version. While the implementations for Adjoint SWAP and Controlled - /// SWAP are thus user-defined, the compiler still needs to generate + /// SWAP are thus user-defined, the compiler still needs to generate /// the implementation for the combination of both functors (Controlled /// Adjoint SWAP, which is the same as Adjoint Controlled SWAP). - operation SWAP (q1 : Qubit, q2 : Qubit) : Unit - is Adj + Ctl { + operation SWAP(q1 : Qubit, q2 : Qubit) : Unit + is Adj + Ctl { body (...) { CNOT(q1, q2); @@ -33,22 +33,22 @@ namespace MyQuantumApp { CNOT(q1, q2); } - adjoint (...) { + adjoint (...) { SWAP(q1, q2); } - controlled (cs, ...) { + controlled (cs, ...) { CNOT(q1, q2); Controlled CNOT(cs, (q2, q1)); - CNOT(q1, q2); - } + CNOT(q1, q2); + } } - /// The main function cannot be Adj or Ctl. + /// The main function cannot be Adj or Ctl. @EntryPoint() operation Main() : Unit { - // We invoke specializations using functors at the call site. + // We invoke specializations using functors at the call site. // In order to call these operations and their specializations, we need // to allocate some qubits. use (q1, q2) = (Qubit(), Qubit()); @@ -60,12 +60,12 @@ namespace MyQuantumApp { // We use the functor `Adjoint` on the operation `SWAP` to invoke the // adjoint specialization of `SWAP`. Adjoint SWAP(q1, q2); - + // Now,we will use the `Controlled` functor. To use this functor, we - // need some control qubits. + // need some control qubits. // The `Controlled` functor invokes the control specialization of the - // operation. Note that the control specialization has a different + // operation. Note that the control specialization has a different // signature than the regular operation: first, the control qubits; // second, the parameters for the regular operation. // For a singly controlled invocation, only pass one control qubit diff --git a/samples/language/Unit.qs b/samples/language/Unit.qs index 3a144aebfa..80b2b22a8b 100644 --- a/samples/language/Unit.qs +++ b/samples/language/Unit.qs @@ -4,7 +4,7 @@ /// # Description /// The `Unit` type is the singleton type whose only value is (). /// Functions implicitly return `Unit` if no explicit or implicit -/// return is specified. +/// return is specified. namespace MyQuantumApp { @EntryPoint() From de61ac9ef8e1e90af0515624fd9fb005f0f7f300 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Mar 2024 13:53:58 -0700 Subject: [PATCH 65/74] format libraries --- library/core/core.qs | 2 +- library/src/tests/resources/add_le.qs | 4 +- library/src/tests/resources/compare.qs | 16 +- library/src/tests/resources/inc_by_le.qs | 6 +- library/src/tests/resources/qft_le.qs | 18 +- library/src/tests/resources/select.qs | 4 +- .../src/tests/resources/state_preparation.qs | 40 ++-- library/std/arrays.qs | 57 ++--- library/std/canon.qs | 24 +- library/std/convert.qs | 26 +- library/std/core.qs | 12 +- library/std/diagnostics.qs | 4 +- library/std/internal.qs | 81 +++---- library/std/intrinsic.qs | 224 ++++++------------ library/std/math.qs | 112 +++++---- library/std/measurement.qs | 12 +- library/std/re.qs | 8 +- library/std/unstable_arithmetic.qs | 41 ++-- library/std/unstable_arithmetic_internal.qs | 63 +++-- library/std/unstable_state_preparation.qs | 16 +- library/std/unstable_table_lookup.qs | 18 +- 21 files changed, 362 insertions(+), 426 deletions(-) diff --git a/library/core/core.qs b/library/core/core.qs index 9e30481278..b8abde5509 100644 --- a/library/core/core.qs +++ b/library/core/core.qs @@ -38,7 +38,7 @@ namespace Microsoft.Quantum.Core { } mutable output = []; - for _ in 1 .. length { + for _ in 1..length { set output += [value]; } diff --git a/library/src/tests/resources/add_le.qs b/library/src/tests/resources/add_le.qs index b4cb2c85e5..be6c728370 100644 --- a/library/src/tests/resources/add_le.qs +++ b/library/src/tests/resources/add_le.qs @@ -46,8 +46,8 @@ namespace Test { bitwidth : Int) : Unit { TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth); - TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth+1); - TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth+2); + TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth + 1); + TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth + 2); } diff --git a/library/src/tests/resources/compare.qs b/library/src/tests/resources/compare.qs index 1f00db6986..274ed51d56 100644 --- a/library/src/tests/resources/compare.qs +++ b/library/src/tests/resources/compare.qs @@ -5,17 +5,17 @@ namespace Test { open Microsoft.Quantum.Diagnostics; internal operation CompareWithBigInt( - name: String, + name : String, bitwidth : Int, quantumComparator : (BigInt, Qubit[], Qubit) => Unit, classicalComparator : (Int, Int) -> Bool) : Unit { - + for n in 1..bitwidth { use qs = Qubit[n]; use t = Qubit(); - for a in 0 .. 2^n+1 { // We want b to have more bits sometimes... - for b in 0 .. 2^n-1 { + for a in 0..2 ^ n + 1 { // We want b to have more bits sometimes... + for b in 0..2 ^ n-1 { ApplyXorInPlace(b, qs); quantumComparator(IntAsBigInt(a), qs, t); let actual = MResetZ(t) == One; @@ -29,18 +29,18 @@ namespace Test { } internal operation CompareWithLE( - name: String, + name : String, bitwidth : Int, quantumComparator : (Qubit[], Qubit[], Qubit) => Unit, classicalComparator : (Int, Int) -> Bool) : Unit { - + for n in 1..bitwidth { use x = Qubit[n]; use y = Qubit[n]; use t = Qubit(); - for a in 0 .. 2^n-1 { - for b in 0 .. 2^n-1 { + for a in 0..2 ^ n-1 { + for b in 0..2 ^ n-1 { ApplyXorInPlace(a, x); ApplyXorInPlace(b, y); quantumComparator(x, y, t); diff --git a/library/src/tests/resources/inc_by_le.qs b/library/src/tests/resources/inc_by_le.qs index d0797a5436..7d343fa8e1 100644 --- a/library/src/tests/resources/inc_by_le.qs +++ b/library/src/tests/resources/inc_by_le.qs @@ -62,7 +62,7 @@ namespace Test { $"{name}: Incorrect sum={yActual}, expected={yExpected}. ctl={isCtl}, |x|={xLen}, |y|={yLen}, x={xValue}, y={yValue}."); Fact(xActual == xValue, $"{name}: Incorrect x={xActual}, expected={xValue}. ctl={isCtl}, |x|={xLen}, |y|={yLen}, x={xValue}, y={yValue}."); - + ResetAll(x); ResetAll(y); Reset(ctl); @@ -77,8 +77,8 @@ namespace Test { bitwidth : Int) : Unit { TestIncByLE2(name, adder, bitwidth, bitwidth); - TestIncByLE2(name, adder, bitwidth, bitwidth+1); - TestIncByLE2(name, adder, bitwidth, bitwidth+2); + TestIncByLE2(name, adder, bitwidth, bitwidth + 1); + TestIncByLE2(name, adder, bitwidth, bitwidth + 2); } internal operation TestIncByLECtl( diff --git a/library/src/tests/resources/qft_le.qs b/library/src/tests/resources/qft_le.qs index 9c1341e687..f99d3860c9 100644 --- a/library/src/tests/resources/qft_le.qs +++ b/library/src/tests/resources/qft_le.qs @@ -2,18 +2,18 @@ namespace Test { open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Arrays; - operation PrepareEntangledState ( + operation PrepareEntangledState( left : Qubit[], right : Qubit[]) : Unit is Adj + Ctl { - for idxQubit in 0 .. Length(left) - 1 + for idxQubit in 0..Length(left) - 1 { H(left[idxQubit]); Controlled X([left[idxQubit]], right[idxQubit]); } } - operation AssertOperationsEqualReferenced ( + operation AssertOperationsEqualReferenced( nQubits : Int, actual : (Qubit[] => Unit), expected : (Qubit[] => Unit is Adj)) : Unit { @@ -33,14 +33,14 @@ namespace Test { /// # Summary /// Hard-code 1 qubit QFT - operation QFT1 (target : Qubit[]) : Unit is Adj { + operation QFT1(target : Qubit[]) : Unit is Adj { Fact(Length(target) == 1, $"`Length(target!)` must be 1"); H((target)[0]); } /// # Summary /// Hard-code 2 qubit QFT - operation QFT2 (target : Qubit[]) : Unit is Adj { + operation QFT2(target : Qubit[]) : Unit is Adj { Fact(Length(target) == 2, $"`Length(target!)` must be 2"); let (q1, q2) = ((target)[0], (target)[1]); H(q1); @@ -50,7 +50,7 @@ namespace Test { /// # Summary /// Hard-code 3 qubit QFT - operation QFT3 (target : Qubit[]) : Unit is Adj { + operation QFT3(target : Qubit[]) : Unit is Adj { Fact(Length(target) == 3, $"`Length(target)` must be 3"); let (q1, q2, q3) = ((target)[0], (target)[1], (target)[2]); H(q1); @@ -63,7 +63,7 @@ namespace Test { /// # Summary /// Hard-code 4 qubit QFT - operation QFT4 (target : Qubit[]) : Unit is Adj { + operation QFT4(target : Qubit[]) : Unit is Adj { Fact(Length(target) == 4, $"`Length(target!)` must be 4"); let (q1, q2, q3, q4) = ((target)[0], (target)[1], (target)[2], (target)[3]); H(q1); @@ -80,8 +80,8 @@ namespace Test { /// # Summary /// Compares QFT to the hard-coded implementations - operation TestQFT(n: Int) : Unit { - Fact(n>=1 and n<=4, "Only have four tests for QFT."); + operation TestQFT(n : Int) : Unit { + Fact(n >= 1 and n <= 4, "Only have four tests for QFT."); let testOperations = [QFT1, QFT2, QFT3, QFT4]; AssertOperationsEqualReferenced(n, testOperations[n-1], q => ApplyQFT(Reversed(q))); } diff --git a/library/src/tests/resources/select.qs b/library/src/tests/resources/select.qs index 4848006a75..9aa8539eb9 100644 --- a/library/src/tests/resources/select.qs +++ b/library/src/tests/resources/select.qs @@ -11,7 +11,7 @@ namespace Test { use temporaryRegister = Qubit[dataBits]; use dataRegister = Qubit[dataBits]; - let data = DrawMany(_ => DrawMany(_ => (DrawRandomInt(0, 1) == 1), dataBits, 0), 2^addressBits, 0); + let data = DrawMany(_ => DrawMany(_ => (DrawRandomInt(0, 1) == 1), dataBits, 0), 2 ^ addressBits, 0); for (index, expected) in Enumerated(data) { ApplyXorInPlace(index, addressRegister); @@ -33,7 +33,7 @@ namespace Test { for _ in 1..rounds { let addressBits = DrawRandomInt(2, 6); let dataBits = 10; - let numData = DrawRandomInt(2^(addressBits - 1) + 1, 2^addressBits - 1); + let numData = DrawRandomInt(2 ^ (addressBits - 1) + 1, 2 ^ addressBits - 1); let data = DrawMany(_ => DrawMany(_ => (DrawRandomInt(0, 1) == 1), dataBits, 0), numData, 0); diff --git a/library/src/tests/resources/state_preparation.qs b/library/src/tests/resources/state_preparation.qs index 7e762ac903..260bc583bd 100644 --- a/library/src/tests/resources/state_preparation.qs +++ b/library/src/tests/resources/state_preparation.qs @@ -7,7 +7,7 @@ namespace Test { open Microsoft.Quantum.Unstable.StatePreparation; - operation TestPlusState(): Unit { + operation TestPlusState() : Unit { use q = Qubit(); PreparePureStateD([Sqrt(0.5), Sqrt(0.5)], [q]); DumpMachine(); @@ -15,7 +15,7 @@ namespace Test { H(q); } - operation TestMinusState(): Unit { + operation TestMinusState() : Unit { use q = Qubit(); PreparePureStateD([Sqrt(0.5), -Sqrt(0.5)], [q]); DumpMachine(); @@ -24,7 +24,7 @@ namespace Test { X(q); } - operation TestBellState(): Unit { + operation TestBellState() : Unit { use q = Qubit[2]; PreparePureStateD([Sqrt(0.5), 0.0, 0.0, Sqrt(0.5)], q); DumpMachine(); @@ -33,7 +33,7 @@ namespace Test { H(q[0]); } - operation TestCat3State(): Unit { + operation TestCat3State() : Unit { use q = Qubit[3]; PreparePureStateD([Sqrt(0.5), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Sqrt(0.5)], q); DumpMachine(); @@ -50,41 +50,41 @@ namespace Test { T(qs[1]); } - operation TestPrepareComplex(): Unit { + operation TestPrepareComplex() : Unit { use q = Qubit[2]; let c00 = ComplexPolar(0.5, 0.0); - let c01 = ComplexPolar(0.5, PI()/4.0); - let c10 = ComplexPolar(0.5, PI()/2.0); - let c11 = ComplexPolar(0.5, 3.0*PI()/4.0); + let c01 = ComplexPolar(0.5, PI() / 4.0); + let c10 = ComplexPolar(0.5, PI() / 2.0); + let c11 = ComplexPolar(0.5, 3.0 * PI() / 4.0); ApproximatelyPreparePureStateCP(0.0, [c00, c01, c10, c11], q); DumpMachine(); Adjoint PrepareComplex(q); } - operation TestPreparationCompletion(): Unit { + operation TestPreparationCompletion() : Unit { let testCases = [ - // Test positive coefficients - [0.773761, 0.633478], + // Test positive coefficients + [0.773761, 0.633478], [0.183017, 0.406973, 0.604925, 0.659502], [0.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.461883, 0.149609], [0.271471, 0.0583654, 0.11639, 0.36112, 0.307383, 0.193371, 0.274151, 0.332542, 0.130172, 0.222546, 0.314879, 0.210704, 0.212429, 0.245518, 0.30666, 0.22773], - // Test negative coefficients; should give same probabilities as positive coefficients - [-0.773761, 0.633478], + // Test negative coefficients; should give same probabilities as positive coefficients + [-0.773761, 0.633478], [0.183017, -0.406973, 0.604925, 0.659502], [0.0986553, -0.359005, 0.465689, -0.467395, 0.419893, 0.118445, -0.461883, 0.149609], [-0.271471, 0.0583654, 0.11639, 0.36112, -0.307383, 0.193371, -0.274151, 0.332542, 0.130172, 0.222546, 0.314879, -0.210704, 0.212429, 0.245518, -0.30666, -0.22773], - // Test unnormalized coefficients - [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], + // Test unnormalized coefficients + [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], - // Test missing coefficients - [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445] + // Test missing coefficients + [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445] ]; for coefficients in testCases { let L = Length(coefficients); - let N = Ceiling(Log(IntAsDouble(L))/LogOf2() - 0.001); + let N = Ceiling(Log(IntAsDouble(L)) / LogOf2() - 0.001); use q = Qubit[N]; PreparePureStateD(coefficients, q); DumpMachine(); @@ -92,10 +92,10 @@ namespace Test { } } - operation TestEndianness(): Unit { + operation TestEndianness() : Unit { let n = 4; use qs = Qubit[n]; - let bitsize = 2^n; + let bitsize = 2 ^ n; for i in 0..bitsize-1 { mutable c = Repeated(0.0, bitsize); set c w/= i <- 1.0; diff --git a/library/std/arrays.qs b/library/std/arrays.qs index 0b7b08ce2a..5265685912 100644 --- a/library/std/arrays.qs +++ b/library/std/arrays.qs @@ -246,7 +246,7 @@ namespace Microsoft.Quantum.Arrays { let columns = rows == 0 ? 0 | Length(Head(matrix)); let rangeLimit = MinI(rows, columns) - 1; mutable diagonal = []; - for index in 0 .. rangeLimit { + for index in 0..rangeLimit { set diagonal += [matrix[index][index]]; } @@ -280,7 +280,7 @@ namespace Microsoft.Quantum.Arrays { operation DrawMany<'TInput, 'TOutput>(op : ('TInput => 'TOutput), nSamples : Int, input : 'TInput) : 'TOutput[] { mutable outputs = []; - for _ in 1 .. nSamples { + for _ in 1..nSamples { set outputs += [op(input)]; } outputs @@ -349,7 +349,7 @@ namespace Microsoft.Quantum.Arrays { set toKeep w/= indexToRemove <- false; } mutable output = []; - for index in 0 .. arrayLength - 1 { + for index in 0..arrayLength - 1 { if toKeep[index] { set output += [array[index]]; } @@ -572,7 +572,7 @@ namespace Microsoft.Quantum.Arrays { /// // `indexOfFirstEven` is 3. /// ``` function IndexOf<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { - for index in 0 .. Length(array) - 1 { + for index in 0..Length(array) - 1 { if predicate(array[index]) { return index; } @@ -602,7 +602,7 @@ namespace Microsoft.Quantum.Arrays { /// for idx in 0 .. Length(array) - 1 { ... } /// ``` function IndexRange<'TElement>(array : 'TElement[]) : Range { - 0 .. Length(array) - 1 + 0..Length(array) - 1 } /// # Summary @@ -647,8 +647,11 @@ namespace Microsoft.Quantum.Arrays { for index in 0..interleavedLength - 1 { let originalIndex = index / 2; let value = - if index % 2 == 0 {first[originalIndex]} - else {second[originalIndex]}; + if index % 2 == 0 { + first[originalIndex] + } else { + second[originalIndex] + }; set interleaved += [value]; } interleaved @@ -693,7 +696,7 @@ namespace Microsoft.Quantum.Arrays { function IsRectangularArray<'T>(array : 'T[][]) : Bool { if (Length(array) > 0) { let columnCount = Length(Head(array)); - for index in 1 .. Length(array) - 1 { + for index in 1..Length(array) - 1 { if Length(array[index]) != columnCount { return false; } @@ -727,7 +730,7 @@ namespace Microsoft.Quantum.Arrays { /// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` /// is assumed. function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { - for index in 1 .. Length(array) - 1 { + for index in 1..Length(array) - 1 { if not comparison(array[index - 1], array[index]) { return false; } @@ -827,8 +830,8 @@ namespace Microsoft.Quantum.Arrays { /// ```qsharp /// let array = MappedByIndex(f, [x0, x1, x2]); /// ``` - /// and - /// ```qsharp + /// and + /// ```qsharp /// let array = [f(0, x0), f(1, x1), f(2, x2)]; /// ``` /// @@ -836,7 +839,7 @@ namespace Microsoft.Quantum.Arrays { /// - Microsoft.Quantum.Arrays.Mapped function MappedByIndex<'T, 'U> (mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[] { mutable mapped = []; - for index in 0 .. Length(array) - 1 { + for index in 0..Length(array) - 1 { set mapped += [mapper(index, array[index])]; } mapped @@ -892,7 +895,7 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// An array containing the elements `array[0..Length(array) - 2]`. function Most<'T> (array : 'T[]) : 'T[] { - array[... Length(array) - 2] + array[...Length(array) - 2] } /// # Summary @@ -990,10 +993,10 @@ namespace Microsoft.Quantum.Arrays { if partitionEndIndex >= Length(array) { fail "Partitioned argument out of bounds."; } - set output w/= index <- array[partitionStartIndex .. partitionEndIndex]; + set output w/= index <- array[partitionStartIndex..partitionEndIndex]; set partitionStartIndex = partitionEndIndex + 1; } - set output w/= Length(partitionSizes) <- array[partitionStartIndex .. Length(array) - 1]; + set output w/= Length(partitionSizes) <- array[partitionStartIndex..Length(array) - 1]; output } @@ -1012,7 +1015,7 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// An array containing the elements `array[1..Length(array) - 1]`. function Rest<'T> (array : 'T[]) : 'T[] { - array[1 ...] + array[1...] } /// # Summary @@ -1030,7 +1033,7 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// An array containing the elements `array[Length(array) - 1]` .. `array[0]`. function Reversed<'T>(array : 'T[]) : 'T[] { - array[... -1 ...] + array[...-1...] } /// # Summary @@ -1055,10 +1058,10 @@ namespace Microsoft.Quantum.Arrays { /// let numbers = SequenceI(0, _); // function to create sequence from 0 to `to` /// let naturals = SequenceI(1, _); // function to create sequence from 1 to `to` /// ``` - function SequenceI (from : Int, to : Int) : Int[] { + function SequenceI(from : Int, to : Int) : Int[] { Fact(to >= from, $"`to` must be larger than `from`."); mutable array = []; - for index in from .. to { + for index in from..to { set array += [index]; } array @@ -1086,7 +1089,7 @@ namespace Microsoft.Quantum.Arrays { /// let arr2 = SequenceL(23L, 29L); // [23L, 24L, 25L, 26L, 27L, 28L, 29L] /// let arr3 = SequenceL(-5L, -2L); // [-5L, -4L, -3L, -2L] /// ``` - function SequenceL (from : BigInt, to : BigInt) : BigInt[] { + function SequenceL(from : BigInt, to : BigInt) : BigInt[] { Fact(to >= from, "`to` must be larger than `from`"); mutable array = []; mutable current = from; @@ -1269,9 +1272,9 @@ namespace Microsoft.Quantum.Arrays { Fact(columnCount > 0, "Matrix must have at least 1 column"); Fact(IsRectangularArray(matrix), "Matrix is not a rectangular array"); mutable transposed = []; - for columnIndex in 0 .. columnCount - 1 { + for columnIndex in 0..columnCount - 1 { mutable newRow = []; - for rowIndex in 0 .. rowCount - 1 { + for rowIndex in 0..rowCount - 1 { set newRow += [matrix[rowIndex][columnIndex]]; } set transposed += [newRow]; @@ -1327,7 +1330,7 @@ namespace Microsoft.Quantum.Arrays { function Unzipped<'T, 'U>(array : ('T, 'U)[]) : ('T[], 'U[]) { mutable first = []; mutable second = []; - for index in 0 .. Length(array) - 1 { + for index in 0..Length(array) - 1 { let (left, right) = array[index]; set first += [left]; set second += [right]; @@ -1353,7 +1356,7 @@ namespace Microsoft.Quantum.Arrays { /// An array of indices where `predicate` is true. function Where<'T>(predicate : ('T -> Bool), array : 'T[]) : Int[] { mutable indexes = []; - for index in 0 .. Length(array) - 1 { + for index in 0..Length(array) - 1 { if predicate(array[index]) { set indexes += [index]; } @@ -1396,8 +1399,8 @@ namespace Microsoft.Quantum.Arrays { "The size of the window must be a positive integer no greater than the size of the array"); mutable windows = []; - for index in 0 .. arrayLength - size { - set windows += [array[index .. index + size - 1]]; + for index in 0..arrayLength - size { + set windows += [array[index..index + size - 1]]; } windows } @@ -1435,7 +1438,7 @@ namespace Microsoft.Quantum.Arrays { function Zipped<'T, 'U>(left : 'T[], right : 'U[]) : ('T, 'U)[] { let arrayLength = MinI(Length(left), Length(right)); mutable zipped = []; - for index in 0 .. arrayLength - 1 { + for index in 0..arrayLength - 1 { set zipped += [(left[index], right[index])]; } zipped diff --git a/library/std/canon.qs b/library/std/canon.qs index 244b914d63..6171a98605 100644 --- a/library/std/canon.qs +++ b/library/std/canon.qs @@ -153,7 +153,7 @@ namespace Microsoft.Quantum.Canon { /// ```qsharp /// CNOT(control, target); /// ``` - operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl{ + operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl { body ... { __quantum__qis__cx__body(control, target); } @@ -188,7 +188,7 @@ namespace Microsoft.Quantum.Canon { /// ```qsharp /// Controlled Y([control], target); /// ``` - operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl{ + operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl { body ... { __quantum__qis__cy__body(control, target); } @@ -263,7 +263,7 @@ namespace Microsoft.Quantum.Canon { /// $$ operation ApplyCNOTChain(qubits : Qubit[]) : Unit is Adj + Ctl { for i in 0..Length(qubits)-2 { - CNOT(qubits[i], qubits[i+1]); + CNOT(qubits[i], qubits[i + 1]); } } @@ -287,9 +287,13 @@ namespace Microsoft.Quantum.Canon { /// X(q); /// ``` operation ApplyP(pauli : Pauli, target : Qubit) : Unit is Adj + Ctl { - if pauli == PauliX { X(target); } - elif pauli == PauliY { Y(target); } - elif pauli == PauliZ { Z(target); } + if pauli == PauliX { + X(target); + } elif pauli == PauliY { + Y(target); + } elif pauli == PauliZ { + Z(target); + } } /// # Summary @@ -491,13 +495,13 @@ namespace Microsoft.Quantum.Canon { /// /// # Reference /// - [Quantum Fourier transform](https://en.wikipedia.org/wiki/Quantum_Fourier_transform) - operation ApplyQFT (qs : Qubit[]) : Unit is Adj + Ctl { + operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl { let length = Length(qs); Fact(length >= 1, "ApplyQFT: Length(qs) must be at least 1."); for i in length-1..-1..0 { H(qs[i]); for j in 0..i-1 { - Controlled R1Frac([qs[i]], (1, j+1, qs[i-j-1])); + Controlled R1Frac([qs[i]], (1, j + 1, qs[i-j-1])); } } } @@ -508,9 +512,9 @@ namespace Microsoft.Quantum.Canon { /// # Input /// ## register /// The qubits order of which should be reversed using SWAP gates - operation SwapReverseRegister (register : Qubit[]) : Unit is Adj + Ctl { + operation SwapReverseRegister(register : Qubit[]) : Unit is Adj + Ctl { let length = Length(register); - for i in 0 .. length/2 - 1 { + for i in 0..length / 2 - 1 { SWAP(register[i], register[(length - i) - 1]); } } diff --git a/library/std/convert.qs b/library/std/convert.qs index 0f75aeb1f6..00ef9139e6 100644 --- a/library/std/convert.qs +++ b/library/std/convert.qs @@ -44,7 +44,11 @@ namespace Microsoft.Quantum.Convert { /// A `Result` representing the `input`. @Config(Unrestricted) function BoolAsResult(input : Bool) : Result { - if input {One} else {Zero} + if input { + One + } else { + Zero + } } /// # Summary @@ -58,7 +62,7 @@ namespace Microsoft.Quantum.Convert { Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); mutable number = 0; - for i in 0 .. nBits - 1 { + for i in 0..nBits - 1 { if (bits[i]) { set number |||= 1 <<< i; } @@ -89,7 +93,7 @@ namespace Microsoft.Quantum.Convert { mutable runningValue = number; mutable result = []; for _ in 1..bits { - set result += [ (runningValue &&& 1) != 0 ]; + set result += [(runningValue &&& 1) != 0]; set runningValue >>>= 1; } Fact(runningValue == 0, $"`number`={number} is too large to fit into {bits} bits."); @@ -119,7 +123,7 @@ namespace Microsoft.Quantum.Convert { set result += 1L <<< i; } } - + result } @@ -145,7 +149,7 @@ namespace Microsoft.Quantum.Convert { mutable runningValue = number; mutable result = []; for _ in 1..bits { - set result += [ (runningValue &&& 1L) != 0L ]; + set result += [(runningValue &&& 1L) != 0L]; set runningValue >>>= 1; } Fact(runningValue == 0L, $"`number`={number} is too large to fit into {bits} bits."); @@ -174,7 +178,7 @@ namespace Microsoft.Quantum.Convert { Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); mutable number = 0; - for idxBit in 0 .. nBits - 1 { + for idxBit in 0..nBits - 1 { if (results[idxBit] == One) { set number |||= 1 <<< idxBit; } @@ -217,7 +221,11 @@ namespace Microsoft.Quantum.Convert { function BoolArrayAsResultArray(input : Bool[]) : Result[] { mutable output = []; for b in input { - set output += [if b {One} else {Zero}]; + set output += [if b { + One + } else { + Zero + }]; } output @@ -233,7 +241,7 @@ namespace Microsoft.Quantum.Convert { /// /// # Output /// Complex number c = r⋅e^(t𝑖). - function ComplexAsComplexPolar (input : Complex) : ComplexPolar { + function ComplexAsComplexPolar(input : Complex) : ComplexPolar { return ComplexPolar(AbsComplex(input), ArgComplex(input)); } @@ -247,7 +255,7 @@ namespace Microsoft.Quantum.Convert { /// /// # Output /// Complex number c = x + y𝑖. - function ComplexPolarAsComplex (input : ComplexPolar) : Complex { + function ComplexPolarAsComplex(input : ComplexPolar) : Complex { return Complex( input::Magnitude * Cos(input::Argument), input::Magnitude * Sin(input::Argument) diff --git a/library/std/core.qs b/library/std/core.qs index 1c1b458a93..8442c91202 100644 --- a/library/std/core.qs +++ b/library/std/core.qs @@ -16,14 +16,14 @@ namespace Microsoft.Quantum.Core { /// A range expression's first element is `start`, /// its second element is `start+step`, third element is `start+step+step`, etc., /// until `end` is passed. - /// + /// /// Note that the defined start value of a range is the same as the first element of the sequence, /// unless the range specifies an empty sequence (for example, 2 .. 1). function RangeStart(r : Range) : Int { r::Start } - - + + /// # Summary /// Returns the defined end value of the given range, /// which is not necessarily the last element in the sequence. @@ -39,14 +39,14 @@ namespace Microsoft.Quantum.Core { /// A range expression's first element is `start`, /// its second element is `start+step`, third element is `start+step+step`, etc., /// until `end` is passed. - /// + /// /// Note that the defined end value of a range can differ from the last element in the sequence specified by the range; /// for example, in a range 0 .. 2 .. 5 the last element is 4 but the end value is 5. function RangeEnd(r : Range) : Int { r::End } - - + + /// # Summary /// Returns the integer that specifies how the next value of a range is calculated. /// diff --git a/library/std/diagnostics.qs b/library/std/diagnostics.qs index 1a976b0a19..d6d50ee9de 100644 --- a/library/std/diagnostics.qs +++ b/library/std/diagnostics.qs @@ -121,7 +121,7 @@ namespace Microsoft.Quantum.Diagnostics { /// # Output /// True if operations are equal, false otherwise. @Config(Unrestricted) - operation CheckOperationsAreEqual ( + operation CheckOperationsAreEqual( nQubits : Int, actual : (Qubit[] => Unit), expected : (Qubit[] => Unit is Adj)) : Bool { @@ -132,7 +132,7 @@ namespace Microsoft.Quantum.Diagnostics { // Apply operations. within { - for i in 0 .. nQubits - 1 { + for i in 0..nQubits - 1 { H(reference[i]); CNOT(reference[i], target[i]); } diff --git a/library/std/internal.qs b/library/std/internal.qs index 5c8c27f47b..9595f8bb8e 100644 --- a/library/std/internal.qs +++ b/library/std/internal.qs @@ -12,8 +12,7 @@ namespace Microsoft.Quantum.Intrinsic { S(target); H(target); T(target); - } - apply { + } apply { CNOT(control, target); } } @@ -23,8 +22,7 @@ namespace Microsoft.Quantum.Intrinsic { S(target); H(target); T(target); - } - apply { + } apply { CCNOT(control1, control2, target); } } @@ -34,22 +32,20 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { // Noop - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { Rz(theta, ctls[0]); - } - else { + } else { Controlled R1(ctls[1..(Length(ctls) - 1)], (theta, ctls[0])); } } } internal operation CR1(theta : Double, control : Qubit, target : Qubit) : Unit is Adj { - Rz(theta/2.0, target); - Rz(theta/2.0, control); - CNOT(control,target); - Rz(-theta/2.0, target); - CNOT(control,target); + Rz(theta / 2.0, target); + Rz(theta / 2.0, control); + CNOT(control, target); + Rz(-theta / 2.0, target); + CNOT(control, target); } internal operation CRz(control : Qubit, theta : Double, target : Qubit) : Unit is Adj { @@ -77,28 +73,21 @@ namespace Microsoft.Quantum.Intrinsic { } internal operation MapPauli(qubit : Qubit, from : Pauli, to : Pauli) : Unit is Adj { - if from == to { - } - elif (from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ) { + if from == to {} elif (from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ) { H(qubit); - } - elif from == PauliZ and to == PauliY { + } elif from == PauliZ and to == PauliY { H(qubit); S(qubit); H(qubit); - } - elif from == PauliY and to == PauliZ { + } elif from == PauliY and to == PauliZ { H(qubit); Adjoint S(qubit); H(qubit); - } - elif from == PauliY and to == PauliX { + } elif from == PauliY and to == PauliX { S(qubit); - } - elif from == PauliX and to == PauliY { + } elif from == PauliX and to == PauliY { Adjoint S(qubit); - } - else { + } else { fail "Unsupported input"; } } @@ -106,11 +95,9 @@ namespace Microsoft.Quantum.Intrinsic { internal operation EntangleForJointMeasure(basis : Pauli, aux : Qubit, qubit : Qubit) : Unit { if basis == PauliX { Controlled X([aux], qubit); - } - elif basis == PauliZ { + } elif basis == PauliZ { Controlled Z([aux], qubit); - } - elif basis == PauliY { + } elif basis == PauliY { Controlled Y([aux], qubit); } } @@ -165,15 +152,15 @@ namespace Microsoft.Quantum.Intrinsic { internal operation PhaseCCX(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { // https://arxiv.org/pdf/1210.0974.pdf#page=2 H(target); - CNOT(target,control1); - CNOT(control1,control2); + CNOT(target, control1); + CNOT(control1, control2); T(control2); Adjoint T(control1); T(target); - CNOT(target,control1); - CNOT(control1,control2); + CNOT(target, control1); + CNOT(control1, control2); Adjoint T(control2); - CNOT(target,control2); + CNOT(target, control2); H(target); } @@ -188,8 +175,7 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CCY(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { within { MapPauli(target, PauliX, PauliY); - } - apply { + } apply { CCNOT(control1, control2, target); } } @@ -197,8 +183,7 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CRxx(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { within { CNOT(qubit1, qubit0); - } - apply { + } apply { Controlled Rx([control], (theta, qubit0)); } } @@ -206,8 +191,7 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CRyy(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { within { CNOT(qubit1, qubit0); - } - apply { + } apply { Controlled Ry([control], (theta, qubit0)); } } @@ -215,15 +199,14 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CRzz(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { within { CNOT(qubit1, qubit0); - } - apply { + } apply { Controlled Rz([control], (theta, qubit0)); } } - internal function IndicesOfNonIdentity (paulies : Pauli[]) : Int[] { + internal function IndicesOfNonIdentity(paulies : Pauli[]) : Int[] { mutable indices = []; - for i in 0 .. Length(paulies) - 1 { + for i in 0..Length(paulies) - 1 { if (paulies[i] != PauliI) { set indices += [i]; } @@ -231,19 +214,19 @@ namespace Microsoft.Quantum.Intrinsic { indices } - internal function RemovePauliI (paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) { + internal function RemovePauliI(paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) { let indices = IndicesOfNonIdentity(paulis); let newPaulis = Subarray(indices, paulis); let newQubits = Subarray(indices, qubits); return (newPaulis, newQubits); } - internal operation SpreadZ (from : Qubit, to : Qubit[]) : Unit is Adj { + internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj { if (Length(to) > 0) { if (Length(to) > 1) { let half = Length(to) / 2; - SpreadZ(to[0], to[half + 1 .. Length(to) - 1]); - SpreadZ(from, to[1 .. half]); + SpreadZ(to[0], to[half + 1..Length(to) - 1]); + SpreadZ(from, to[1..half]); } CNOT(to[0], from); } diff --git a/library/std/intrinsic.qs b/library/std/intrinsic.qs index c1d5c01e7d..270c817c47 100644 --- a/library/std/intrinsic.qs +++ b/library/std/intrinsic.qs @@ -93,7 +93,7 @@ namespace Microsoft.Quantum.Intrinsic { /// $$ /// where $P_i$ is the $i$th element of `paulis`, and where /// $N = $`Length(paulis)`. - operation Exp (paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { + operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { body ... { Fact(Length(paulis) == Length(qubits), "Arrays 'pauli' and 'qubits' must have the same length"); @@ -103,35 +103,29 @@ namespace Microsoft.Quantum.Intrinsic { if len == 0 { ApplyGlobalPhase(theta); - } - elif len == 1 { + } elif len == 1 { R(newPaulis[0], angle, qubits[0]); - } - elif len == 2 { + } elif len == 2 { within { MapPauli(qubits[1], paulis[0], paulis[1]); - } - apply { + } apply { if (paulis[0] == PauliX) { - Rxx(angle , qubits[0], qubits[1]); + Rxx(angle, qubits[0], qubits[1]); } elif (paulis[0] == PauliY) { Ryy(angle, qubits[0], qubits[1]); } elif (paulis[0] == PauliZ) { Rzz(angle, qubits[0], qubits[1]); } } - } - else { // len > 2 + } else { // len > 2 within { - for i in 0 .. Length(paulis) - 1 { + for i in 0..Length(paulis) - 1 { MapPauli(qubits[i], PauliZ, paulis[i]); } - } - apply { + } apply { within { - SpreadZ(qubits[1], qubits[2 .. Length(qubits) - 1]); - } - apply { + SpreadZ(qubits[1], qubits[2..Length(qubits) - 1]); + } apply { Rzz(angle, qubits[0], qubits[1]); } } @@ -167,23 +161,18 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__h__body(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CH(ctls[0], qubit); - } - elif Length(ctls) == 2 { + } elif Length(ctls) == 2 { CCH(ctls[0], ctls[1], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 1 - (Length(ctls) % 2)]; within { CollectControls(ctls, aux, 0); - } - apply { + } apply { if Length(ctls) % 2 != 0 { CCH(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } - else { + } else { CCH(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -199,7 +188,7 @@ namespace Microsoft.Quantum.Intrinsic { /// This is a no-op. It is provided for completeness and because /// sometimes it is useful to call the identity in an algorithm or to pass it as a parameter. operation I(target : Qubit) : Unit is Adj + Ctl { - body ... { } + body ... {} adjoint self; } @@ -309,17 +298,14 @@ namespace Microsoft.Quantum.Intrinsic { if Length(bases) == 1 { within { MapPauli(qubits[0], PauliZ, bases[0]); - } - apply { + } apply { __quantum__qis__m__body(qubits[0]) } - } - else { + } else { use aux = Qubit(); within { H(aux); - } - apply { + } apply { for i in 0..Length(bases)-1 { EntangleForJointMeasure(bases[i], aux, qubits[i]); } @@ -375,8 +361,7 @@ namespace Microsoft.Quantum.Intrinsic { use aux = Qubit(); within { H(aux); - } - apply { + } apply { for i in 0..Length(bases)-1 { EntangleForJointMeasure(bases[i], aux, qubits[i]); } @@ -410,15 +395,12 @@ namespace Microsoft.Quantum.Intrinsic { operation R(pauli : Pauli, theta : Double, qubit : Qubit) : Unit is Adj + Ctl { if (pauli == PauliX) { Rx(theta, qubit); - } - elif (pauli == PauliY) { + } elif (pauli == PauliY) { Ry(theta, qubit); - } - elif (pauli == PauliZ) { + } elif (pauli == PauliZ) { Rz(theta, qubit); - } - else { // PauliI - ApplyGlobalPhase( - theta / 2.0 ); + } else { // PauliI + ApplyGlobalPhase( - theta / 2.0); } } @@ -451,17 +433,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { Rz(theta, qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CR1(theta, ctls[0], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { CR1(theta, aux[Length(ctls) - 2], qubit); } } @@ -602,12 +581,10 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rx__body(theta, qubit); - } - else { + } else { within { MapPauli(qubit, PauliZ, PauliX); - } - apply { + } apply { Controlled Rz(ctls, (theta, qubit)); } } @@ -647,17 +624,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rxx__body(theta, qubit0, qubit1); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CRxx(ctls[0], theta, qubit0, qubit1); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { CRxx(aux[Length(ctls) - 2], theta, qubit0, qubit1); } } @@ -699,12 +673,10 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__ry__body(theta, qubit); - } - else { + } else { within { MapPauli(qubit, PauliZ, PauliY); - } - apply { + } apply { Controlled Rz(ctls, (theta, qubit)); } } @@ -744,17 +716,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__ryy__body(theta, qubit0, qubit1); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CRyy(ctls[0], theta, qubit0, qubit1); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { CRyy(aux[Length(ctls) - 2], theta, qubit0, qubit1); } } @@ -796,17 +765,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rz__body(theta, qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CRz(ctls[0], theta, qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { CRz(aux[Length(ctls) - 2], theta, qubit); } } @@ -846,17 +812,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rzz__body(theta, qubit0, qubit1); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CRzz(ctls[0], theta, qubit0, qubit1); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { CRzz(aux[Length(ctls) - 2], theta, qubit0, qubit1); } } @@ -893,23 +856,18 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__s__body(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CS(ctls[0], qubit); - } - elif Length(ctls) == 2 { + } elif Length(ctls) == 2 { Controlled CS([ctls[0]], (ctls[1], qubit)); - } - else { + } else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } - apply { + } apply { if Length(ctls) % 2 != 0 { Controlled CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); - } - else { + } else { Controlled CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); } } @@ -918,23 +876,18 @@ namespace Microsoft.Quantum.Intrinsic { controlled adjoint (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__s__adj(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { Adjoint CS(ctls[0], qubit); - } - elif Length(ctls) == 2 { + } elif Length(ctls) == 2 { Controlled Adjoint CS([ctls[0]], (ctls[1], qubit)); - } - else { + } else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } - apply { + } apply { if Length(ctls) % 2 != 0 { Controlled Adjoint CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); - } - else { + } else { Controlled Adjoint CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); } } @@ -980,12 +933,10 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if (Length(ctls) == 0) { __quantum__qis__swap__body(qubit1, qubit2); - } - else { + } else { within { CNOT(qubit1, qubit2); - } - apply { + } apply { Controlled CNOT(ctls, (qubit2, qubit1)); } } @@ -1019,17 +970,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__t__body(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { CT(ctls[0], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { CT(aux[Length(ctls) - 2], qubit); } } @@ -1037,17 +985,14 @@ namespace Microsoft.Quantum.Intrinsic { controlled adjoint (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__t__adj(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { Adjoint CT(ctls[0], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } - apply { + } apply { Adjoint CT(aux[Length(ctls) - 2], qubit); } } @@ -1078,23 +1023,18 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__x__body(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { __quantum__qis__cx__body(ctls[0], qubit); - } - elif Length(ctls) == 2 { + } elif Length(ctls) == 2 { __quantum__qis__ccx__body(ctls[0], ctls[1], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } - apply { + } apply { if Length(ctls) % 2 != 0 { __quantum__qis__ccx__body(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } - else { + } else { __quantum__qis__ccx__body(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -1127,23 +1067,18 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if (Length(ctls) == 0) { __quantum__qis__y__body(qubit); - } - elif (Length(ctls) == 1) { + } elif (Length(ctls) == 1) { __quantum__qis__cy__body(ctls[0], qubit); - } - elif (Length(ctls) == 2) { + } elif (Length(ctls) == 2) { CCY(ctls[0], ctls[1], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } - apply { + } apply { if Length(ctls) % 2 != 0 { CCY(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } - else { + } else { CCY(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -1176,23 +1111,18 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__z__body(qubit); - } - elif Length(ctls) == 1 { + } elif Length(ctls) == 1 { __quantum__qis__cz__body(ctls[0], qubit); - } - elif Length(ctls) == 2 { + } elif Length(ctls) == 2 { CCZ(ctls[0], ctls[1], qubit); - } - else { + } else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } - apply { + } apply { if Length(ctls) % 2 != 0 { CCZ(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } - else { + } else { CCZ(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -1212,7 +1142,7 @@ namespace Microsoft.Quantum.Intrinsic { /// The specific behavior of this function is simulator-dependent, /// but in most cases the given message will be written to the console. /// ``` - function Message (msg : String) : Unit { + function Message(msg : String) : Unit { body intrinsic; } diff --git a/library/std/math.qs b/library/std/math.qs index 7d37628f2e..4db0942355 100644 --- a/library/std/math.qs +++ b/library/std/math.qs @@ -40,7 +40,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// Returns a `Double` equal to 0.6931471805599453. - function LogOf2 () : Double + function LogOf2() : Double { 0.6931471805599453 } @@ -102,42 +102,54 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignI (a : Int) : Int { - if (a < 0) { -1 } - elif (a > 0) { +1 } - else { 0 } + function SignI(a : Int) : Int { + if (a < 0) { + -1 + } elif (a > 0) { + 1 + } else { + 0 + } } /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignD (a : Double) : Int { - if (a < 0.0) { -1 } - elif (a > 0.0) { +1 } - else { 0 } + function SignD(a : Double) : Int { + if (a < 0.0) { + -1 + } elif (a > 0.0) { + 1 + } else { + 0 + } } /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignL (a : BigInt) : Int { - if (a < 0L) { -1 } - elif (a > 0L) { +1 } - else { 0 } + function SignL(a : BigInt) : Int { + if (a < 0L) { + -1 + } elif (a > 0L) { + 1 + } else { + 0 + } } /// # Summary /// Returns the absolute value of an integer. - function AbsI (a : Int) : Int { + function AbsI(a : Int) : Int { a < 0 ? -a | a } /// # Summary /// Returns the absolute value of a double-precision floating-point number. - function AbsD (a : Double) : Double { + function AbsD(a : Double) : Double { a < 0.0 ? -a | a } /// # Summary - function AbsL (a : BigInt) : BigInt { + function AbsL(a : BigInt) : BigInt { a < 0L ? -a | a } @@ -155,19 +167,19 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns the larger of two specified numbers. - function MaxL (a : BigInt, b : BigInt) : BigInt { + function MaxL(a : BigInt, b : BigInt) : BigInt { a > b ? a | b } /// # Summary /// Returns the smaller of two specified numbers. - function MinI (a : Int, b : Int) : Int { + function MinI(a : Int, b : Int) : Int { a < b ? a | b } /// # Summary /// Returns the smaller of two specified numbers. - function MinD (a : Double, b : Double) : Double { + function MinD(a : Double, b : Double) : Double { a < b ? a | b } @@ -186,7 +198,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The largest element of `values`. - function Max (values : Int[]) : Int { + function Max(values : Int[]) : Int { Fact(Length(values) > 0, "Array must contain at least one element."); mutable max = values[0]; for element in values[1...] { @@ -207,7 +219,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The smallest element of `values`. - function Min (values : Int[]) : Int { + function Min(values : Int[]) : Int { Fact(Length(values) > 0, "Array must contain at least one element."); mutable min = values[0]; for element in values[1...] { @@ -225,80 +237,80 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns the angle whose cosine is the specified number. - function ArcCos (x : Double) : Double { + function ArcCos(x : Double) : Double { body intrinsic; } /// # Summary /// Returns the angle whose sine is the specified number. - function ArcSin (y : Double) : Double { + function ArcSin(y : Double) : Double { body intrinsic; } /// # Summary /// Returns the angle whose tangent is the specified number. - function ArcTan (d : Double) : Double { + function ArcTan(d : Double) : Double { body intrinsic; } /// # Summary /// Returns the angle whose tangent is the quotient of two specified numbers. - function ArcTan2 (y : Double, x : Double) : Double { + function ArcTan2(y : Double, x : Double) : Double { body intrinsic; } /// # Summary /// Returns the cosine of the specified angle. - function Cos (theta : Double) : Double { + function Cos(theta : Double) : Double { body intrinsic; } /// # Summary /// Returns the hyperbolic cosine of the specified angle. - function Cosh (d : Double) : Double { + function Cosh(d : Double) : Double { body intrinsic; } /// # Summary /// Returns the sine of the specified angle. - function Sin (theta : Double) : Double { + function Sin(theta : Double) : Double { body intrinsic; } /// # Summary /// Returns the hyperbolic sine of the specified angle. - function Sinh (d : Double) : Double { + function Sinh(d : Double) : Double { body intrinsic; } /// # Summary /// Returns the tangent of the specified angle. - function Tan (d : Double) : Double { + function Tan(d : Double) : Double { body intrinsic; } /// # Summary /// Returns the hyperbolic tangent of the specified angle. - function Tanh (d : Double) : Double { + function Tanh(d : Double) : Double { body intrinsic; } /// # Summary /// Computes the inverse hyperbolic cosine of a number. - function ArcCosh (x : Double) : Double { + function ArcCosh(x : Double) : Double { Log(x + Sqrt(x * x - 1.0)) } /// # Summary /// Computes the inverse hyperbolic sine of a number. - function ArcSinh (x : Double) : Double { + function ArcSinh(x : Double) : Double { Log(x + Sqrt(x * x + 1.0)) } /// # Summary /// Computes the inverse hyperbolic tangent of a number. - function ArcTanh (x : Double) : Double { + function ArcTanh(x : Double) : Double { Log((1.0 + x) / (1.0 - x)) * 0.5 } @@ -738,7 +750,7 @@ namespace Microsoft.Quantum.Math { /// # Summary /// For a non-zero integer `a`, returns the number of trailing zero bits /// in the binary representation of `a`. - function TrailingZeroCountI (a : Int) : Int { + function TrailingZeroCountI(a : Int) : Int { Fact(a != 0, "TrailingZeroCountI: `a` cannot be 0."); mutable count = 0; @@ -754,7 +766,7 @@ namespace Microsoft.Quantum.Math { /// # Summary /// For a non-zero integer `a`, returns the number of trailing zero bits /// in the binary representation of `a`. - function TrailingZeroCountL (a : BigInt) : Int { + function TrailingZeroCountL(a : BigInt) : Int { Fact(a != 0L, "TrailingZeroCountL: `a` cannot be 0."); mutable count = 0; @@ -769,7 +781,7 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns the number of 1 bits in the binary representation of integer `n`. - function HammingWeightI (n : Int) : Int { + function HammingWeightI(n : Int) : Int { let i1 = n - ((n >>> 1) &&& 0x5555555555555555); let i2 = (i1 &&& 0x3333333333333333) + ((i1 >>> 2) &&& 0x3333333333333333); // Multiplication may overflow. See https://github.com/microsoft/qsharp/issues/828 @@ -826,7 +838,7 @@ namespace Microsoft.Quantum.Math { Fact(n >= 0, "The factorial is not defined for negative inputs."); mutable result = 1L; - for i in 1 .. n { + for i in 1..n { set result *= IntAsBigInt(i); } result @@ -952,7 +964,7 @@ namespace Microsoft.Quantum.Math { if n < 171 { Floor(0.5 + ApproximateFactorial(n) / (ApproximateFactorial(k) * ApproximateFactorial(n - k))) } else { - Floor(0.5 + E()^(LogFactorialD(n) - LogFactorialD(k) - LogFactorialD(n - k))) + Floor(0.5 + E() ^ (LogFactorialD(n) - LogFactorialD(k) - LogFactorialD(n - k))) } } @@ -973,7 +985,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The squared 2-norm of `array`. - function SquaredNorm (array : Double[]) : Double { + function SquaredNorm(array : Double[]) : Double { mutable sum = 0.0; for element in array { set sum += element * element; @@ -994,17 +1006,17 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The p-norm |x̄|ₚ. - function PNorm (p : Double, array : Double[]) : Double { + function PNorm(p : Double, array : Double[]) : Double { if p < 1.0 { fail "p must be >= 1.0"; } mutable sum = 0.0; for element in array { - set sum += AbsD(element)^p; + set sum += AbsD(element) ^ p; } - sum^(1.0 / p) + sum ^ (1.0 / p) } /// # Summary @@ -1023,7 +1035,7 @@ namespace Microsoft.Quantum.Math { /// /// # See Also /// - PNorm - function PNormalized (p : Double, array : Double[]) : Double[] { + function PNormalized(p : Double, array : Double[]) : Double[] { let norm = PNorm(p, array); if (norm == 0.0) { return array; @@ -1051,7 +1063,7 @@ namespace Microsoft.Quantum.Math { /// ```qsharp /// let imagUnit = Complex(0.0, 1.0); /// ``` - newtype Complex = (Real: Double, Imag: Double); + newtype Complex = (Real : Double, Imag : Double); /// # Summary /// Represents a complex number in polar form. @@ -1062,7 +1074,7 @@ namespace Microsoft.Quantum.Math { /// The absolute value r>0 of c. /// ## Argument /// The phase t ∈ ℝ of c. - newtype ComplexPolar = (Magnitude: Double, Argument: Double); + newtype ComplexPolar = (Magnitude : Double, Argument : Double); /// # Summary /// Returns the squared absolute value of a complex number of type @@ -1281,7 +1293,7 @@ namespace Microsoft.Quantum.Math { /// Note that this is a multi-valued function, but only one value is returned. internal function PowCAsCP(base : Complex, power : Complex) : ComplexPolar { let ((a, b), (c, d)) = (base!, power!); - let baseSqNorm = a*a + b*b; + let baseSqNorm = a * a + b * b; let baseNorm = Sqrt(baseSqNorm); let baseArg = ArgComplex(base); @@ -1294,7 +1306,7 @@ namespace Microsoft.Quantum.Math { // magnitude = 𝑒^((c⋅ln(baseNorm) - d⋅baseArg)) = baseNorm^c / 𝑒^(d⋅baseArg) // angle = d⋅ln(baseNorm) + c⋅baseArg - let magnitude = baseNorm^c / E()^(d * baseArg); + let magnitude = baseNorm ^ c / E() ^ (d * baseArg); let angle = d * Log(baseNorm) + c * baseArg; ComplexPolar(magnitude, angle) @@ -1382,7 +1394,7 @@ namespace Microsoft.Quantum.Math { /// # Remark /// The value can be computed as -2^(p-1), where p is the number of integer bits. function SmallestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { - -(2.0^IntAsDouble(integerBits - 1)) + -(2.0 ^ IntAsDouble(integerBits - 1)) } /// # Summary @@ -1398,7 +1410,7 @@ namespace Microsoft.Quantum.Math { /// The value can be computed as 2^(p-1) - 2^(-q), where p /// is the number of integer bits and q is the number of fractional bits. function LargestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { - 2.0^IntAsDouble(integerBits - 1) - 2.0^(-IntAsDouble(fractionalBits)) + 2.0 ^ IntAsDouble(integerBits - 1) - 2.0 ^ (-IntAsDouble(fractionalBits)) } } diff --git a/library/std/measurement.qs b/library/std/measurement.qs index d24dfbcec2..fc4e05326a 100644 --- a/library/std/measurement.qs +++ b/library/std/measurement.qs @@ -24,7 +24,7 @@ namespace Microsoft.Quantum.Measurement { /// # Remarks /// This operation does not reset the measured qubits to the |0⟩ state, /// leaving them in the state that corresponds to the measurement result. - operation MeasureAllZ (register : Qubit[]) : Result { + operation MeasureAllZ(register : Qubit[]) : Result { Measure(Repeated(PauliZ, Length(register)), register) } @@ -39,7 +39,7 @@ namespace Microsoft.Quantum.Measurement { /// # Remarks /// This operation does not reset the measured qubits to the |0⟩ state, /// leaving them in the state that corresponds to the measurement results. - operation MeasureEachZ (register : Qubit[]) : Result[] { + operation MeasureEachZ(register : Qubit[]) : Result[] { mutable results = []; for qubit in register { set results += [M(qubit)]; @@ -55,7 +55,7 @@ namespace Microsoft.Quantum.Measurement { /// An array of qubits to be measured. /// # Output /// An array of measurement results. - operation MResetEachZ (register : Qubit[]) : Result[] { + operation MResetEachZ(register : Qubit[]) : Result[] { mutable results = []; for qubit in register { set results += [MResetZ(qubit)]; @@ -79,7 +79,7 @@ namespace Microsoft.Quantum.Measurement { /// /// # Output /// The result of measuring `target` in the Pauli X basis. - operation MResetX (target : Qubit) : Result { + operation MResetX(target : Qubit) : Result { // Map the qubit's state from the Z-basis to the X-basis. // Then measure and reset the qubit. H(target); @@ -102,7 +102,7 @@ namespace Microsoft.Quantum.Measurement { /// /// # Output /// The result of measuring `target` in the Pauli Y basis. - operation MResetY (target : Qubit) : Result { + operation MResetY(target : Qubit) : Result { // Map the qubit's state from the Z-basis to the Y-basis. // Then measure and reset the qubit. // Note: this use HSadj instead of HSH since that is sufficient for measurement. @@ -127,7 +127,7 @@ namespace Microsoft.Quantum.Measurement { /// /// # Output /// The result of measuring `target` in the Pauli Z basis. - operation MResetZ (target : Qubit) : Result { + operation MResetZ(target : Qubit) : Result { __quantum__qis__mresetz__body(target) } diff --git a/library/std/re.qs b/library/std/re.qs index 09e05d0359..29b71bf13d 100644 --- a/library/std/re.qs +++ b/library/std/re.qs @@ -34,7 +34,7 @@ namespace Microsoft.Quantum.ResourceEstimation { /// `false` indicates if cached estimates have been incorporated into the overall costs /// and the code fragment should be skipped. @Config(Unrestricted) - function BeginEstimateCaching(name: String, variant: Int): Bool { + function BeginEstimateCaching(name : String, variant : Int) : Bool { body intrinsic; } @@ -42,7 +42,7 @@ namespace Microsoft.Quantum.ResourceEstimation { /// Instructs the resource estimator to stop estimates caching /// because the code fragment in consideration is over. This function /// is only available when using resource estimator execution target. - function EndEstimateCaching(): Unit { + function EndEstimateCaching() : Unit { body intrinsic; } @@ -116,14 +116,14 @@ namespace Microsoft.Quantum.ResourceEstimation { /// to physical resource estimates. Only PSSPCLayout() is supported at this time. /// ## arguments /// Operation takes these qubits as its arguments. - operation AccountForEstimates(estimates: (Int, Int)[], layout: Int, arguments: Qubit[]): Unit is Adj { + operation AccountForEstimates(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit is Adj { body ... { AccountForEstimatesInternal(estimates, layout, arguments); } adjoint self; } - internal operation AccountForEstimatesInternal(estimates: (Int, Int)[], layout: Int, arguments: Qubit[]): Unit { + internal operation AccountForEstimatesInternal(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit { body intrinsic; } diff --git a/library/std/unstable_arithmetic.qs b/library/std/unstable_arithmetic.qs index 0c6b045339..b4970a92b3 100644 --- a/library/std/unstable_arithmetic.qs +++ b/library/std/unstable_arithmetic.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// The second input qubit. /// ## z /// A qubit onto which the majority function will be applied. - operation MAJ (x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { + operation MAJ(x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { CNOT(z, y); CNOT(z, x); CCNOT(y, x, z); @@ -46,7 +46,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Remarks /// This operation is implemented in-place, without explicit allocation of /// additional auxiliary qubits. - operation ReflectAboutInteger (index : Int, reg : Qubit[]) : Unit is Adj + Ctl { + operation ReflectAboutInteger(index : Int, reg : Qubit[]) : Unit is Adj + Ctl { within { // Evaluation optimization for case index == 0 if index == 0 { @@ -94,7 +94,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Length(ys) = n > 0, c is a Int number, 0 ≤ c < 2ⁿ. /// NOTE: Use IncByIUsingIncByLE directly if the choice of implementation /// is important. - operation IncByI (c : Int, ys : Qubit[]) : Unit is Adj + Ctl { + operation IncByI(c : Int, ys : Qubit[]) : Unit is Adj + Ctl { IncByIUsingIncByLE(RippleCarryTTKIncByLE, c, ys); } @@ -106,7 +106,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. /// NOTE: Use IncByLUsingIncByLE directly if the choice of implementation /// is important. - operation IncByL (c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { + operation IncByL(c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { IncByLUsingIncByLE(RippleCarryTTKIncByLE, c, ys); } @@ -118,7 +118,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// and Length(xs) ≤ Length(ys) = n. /// NOTE: Use operations like RippleCarryCGIncByLE directly if /// the choice of implementation is important. - operation IncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation IncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { RippleCarryTTKIncByLE(xs, ys); } @@ -131,7 +131,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Length(xs) = Length(ys) ≤ Length(zs) = n, assuming zs is 0-initialized. /// NOTE: Use operations like RippleCarryCGAddLE directly if /// the choice of implementation is important. - operation AddLE (xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + operation AddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { RippleCarryCGAddLE(xs, ys, zs); } @@ -151,7 +151,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// "Quantum Addition Circuits and Unbounded Fan-Out" /// by Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro /// - operation RippleCarryTTKIncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation RippleCarryTTKIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { let xsLen = Length(xs); let ysLen = Length(ys); @@ -166,9 +166,8 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { ApplyInnerTTKAdderNoCarry(xs, ys); } } - CNOT (xs[0], ys[0]); - } - elif xsLen + 1 == ysLen { + CNOT(xs[0], ys[0]); + } elif xsLen + 1 == ysLen { if xsLen > 1 { CNOT(xs[xsLen-1], ys[ysLen-1]); within { @@ -176,13 +175,11 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { } apply { ApplyInnerTTKAdderWithCarry(xs, ys); } - } - else { + } else { CCNOT(xs[0], ys[0], ys[1]); } CNOT(xs[0], ys[0]); - } - elif xsLen + 2 <= ysLen { + } elif xsLen + 2 <= ysLen { // Pad xs so that its length is one qubit shorter than ys. use padding = Qubit[ysLen - xsLen - 1]; RippleCarryTTKIncByLE(xs + padding, ys); @@ -203,7 +200,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Reference /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) /// "Halving the cost of quantum addition" by Craig Gidney. - operation RippleCarryCGIncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { let xsLen = Length(xs); let ysLen = Length(ys); @@ -260,7 +257,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Reference /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) /// "Halving the cost of quantum addition" by Craig Gidney. - operation RippleCarryCGAddLE (xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + operation RippleCarryCGAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { let xsLen = Length(xs); let zsLen = Length(zs); Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); @@ -269,7 +266,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { // Since zs is zero-initialized, its bits at indexes higher than // xsLen remain unused as there will be no carry into them. let top = MinI(zsLen-2, xsLen-1); - for k in 0 .. top { + for k in 0..top { FullAdder(zs[k], xs[k], ys[k], zs[k + 1]); } @@ -341,7 +338,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Reference /// - [arXiv:quant-ph/0008033](https://arxiv.org/abs/quant-ph/0008033) /// "Addition on a Quantum Computer" by Thomas G. Draper - operation FourierTDIncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation FourierTDIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { within { ApplyQFT(ys); } apply { @@ -358,7 +355,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Description /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. - operation IncByLUsingIncByLE ( + operation IncByLUsingIncByLE( adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { @@ -366,7 +363,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let ysLen = Length(ys); Fact(ysLen > 0, "Length of `ys` must be at least 1."); Fact(c >= 0L, "Constant `c` must be non-negative."); - Fact(c < 2L^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + Fact(c < 2L ^ ysLen, "Constant `c` must be smaller than 2^Length(ys)."); if c != 0L { // If c has j trailing zeros, then the j least significant @@ -390,7 +387,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Description /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register /// Length(ys) = n > 0, c is an Int number, 0 ≤ c < 2ⁿ. - operation IncByIUsingIncByLE ( + operation IncByIUsingIncByLE( adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, c : Int, ys : Qubit[]) : Unit is Adj + Ctl { @@ -398,7 +395,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let ysLen = Length(ys); Fact(ysLen > 0, "Length of `ys` must be at least 1."); Fact(c >= 0, "Constant `c` must be non-negative."); - Fact(c < 2^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + Fact(c < 2 ^ ysLen, "Constant `c` must be smaller than 2^Length(ys)."); if c != 0 { // If c has j trailing zeros than the j least significant diff --git a/library/std/unstable_arithmetic_internal.qs b/library/std/unstable_arithmetic_internal.qs index 5a0fa365a2..44785d4d4a 100644 --- a/library/std/unstable_arithmetic_internal.qs +++ b/library/std/unstable_arithmetic_internal.qs @@ -28,12 +28,12 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { internal operation ApplyOuterTTKAdder(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { Fact(Length(xs) <= Length(ys), - "Input register ys must be at lease as long as xs." ); + "Input register ys must be at lease as long as xs."); for i in 1..Length(xs)-1 { CNOT(xs[i], ys[i]); } for i in Length(xs)-2..-1..1 { - CNOT(xs[i], xs[i+1]); + CNOT(xs[i], xs[i + 1]); } } @@ -63,14 +63,14 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { internal operation ApplyInnerTTKAdderNoCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { body (...) { - (Controlled ApplyInnerTTKAdderNoCarry) ([], (xs, ys)); + (Controlled ApplyInnerTTKAdderNoCarry)([], (xs, ys)); } - controlled ( controls, ... ) { + controlled (controls, ...) { Fact(Length(xs) == Length(ys), - "Input registers must have the same number of qubits." ); + "Input registers must have the same number of qubits."); for idx in 0..Length(xs) - 2 { - CCNOT (xs[idx], ys[idx], xs[idx + 1]); + CCNOT(xs[idx], ys[idx], xs[idx + 1]); } for idx in Length(xs)-1..-1..1 { Controlled CNOT(controls, (xs[idx], ys[idx])); @@ -107,15 +107,15 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { body (...) { (Controlled ApplyInnerTTKAdderWithCarry)([], (xs, ys)); } - controlled ( controls, ... ) { - Fact(Length(xs)+1 == Length(ys), - "ys must be one qubit longer then xs." ); + controlled (controls, ...) { + Fact(Length(xs) + 1 == Length(ys), + "ys must be one qubit longer then xs."); Fact(Length(xs) > 0, "Array should not be empty."); let nQubits = Length(xs); for idx in 0..nQubits - 2 { - CCNOT(xs[idx], ys[idx], xs[idx+1]); + CCNOT(xs[idx], ys[idx], xs[idx + 1]); } (Controlled CCNOT)(controls, (xs[nQubits-1], ys[nQubits-1], ys[nQubits])); for idx in nQubits - 1..-1..1 { @@ -255,7 +255,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) /// doi:10.1103/PhysRevA.87.022328 @Config(Unrestricted) - internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target: Qubit) + internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { // NOTE: Eventually this operation will be public and intrinsic. body (...) { if not CheckZero(target) { @@ -300,7 +300,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) /// doi:10.1103/PhysRevA.87.022328 @Config(Base) - internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target: Qubit) + internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { H(target); T(target); @@ -309,8 +309,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { within { CNOT(target, control1); CNOT(target, control2); - } - apply { + } apply { Adjoint T(control1); Adjoint T(control2); T(target); @@ -323,12 +322,12 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Computes carries for the look-ahead adder internal operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj { let n = Length(gs); - Fact(Length(ps)+1 == n, "Register gs must be one qubit longer than register gs."); + Fact(Length(ps) + 1 == n, "Register gs must be one qubit longer than register gs."); let T = Floor(Lg(IntAsDouble(n))); use qs = Qubit[n - HammingWeightI(n) - T]; - let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1); + let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2 ^ t)) - 1, 1..T - 1); let pWorkspace = [ps] + Partitioned(registerPartition, qs); within { @@ -383,11 +382,11 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let n = Length(gs); for t in 1..T { - let length = Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1; + let length = Floor(IntAsDouble(n) / IntAsDouble(2 ^ t)) - 1; let ps = pWorkspace[t - 1][0..2...]; for m in 0..length { - CCNOT(gs[2^t * m + 2^(t - 1) - 1], ps[m], gs[2^t * m + 2^t - 1]); + CCNOT(gs[2 ^ t * m + 2 ^ (t - 1) - 1], ps[m], gs[2 ^ t * m + 2 ^ t - 1]); } } } @@ -399,16 +398,16 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let start = Floor(Lg(IntAsDouble(2 * n) / 3.0)); for t in start..-1..1 { - let length = Floor(IntAsDouble(n - 2^(t - 1)) / IntAsDouble(2^t)); + let length = Floor(IntAsDouble(n - 2 ^ (t - 1)) / IntAsDouble(2 ^ t)); let ps = pWorkspace[t - 1][1..2...]; for m in 1..length { - CCNOT(gs[2^t * m - 1], ps[m - 1], gs[2^t * m + 2^(t - 1) - 1]); + CCNOT(gs[2 ^ t * m - 1], ps[m - 1], gs[2 ^ t * m + 2 ^ (t - 1) - 1]); } } } - internal operation PhaseGradient (qs : Qubit[]) : Unit is Adj + Ctl { + internal operation PhaseGradient(qs : Qubit[]) : Unit is Adj + Ctl { for i in IndexRange(qs) { R1Frac(1, i, qs[i]); } @@ -423,18 +422,18 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// (if `invertControl` is false). If `invertControl` is true, the `action` /// is applied in the opposite situation. internal operation ApplyActionIfGreaterThanOrEqualConstant<'T>( - invertControl: Bool, - action: 'T => Unit is Adj + Ctl, - c: BigInt, - x: Qubit[], - target: 'T) : Unit is Adj + Ctl { + invertControl : Bool, + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T) : Unit is Adj + Ctl { let bitWidth = Length(x); if c == 0L { if not invertControl { action(target); } - } elif c >= (2L^bitWidth) { + } elif c >= (2L ^ bitWidth) { if invertControl { action(target); } @@ -459,9 +458,9 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { within { for i in 0..Length(cs1)-1 { let op = - cNormalized &&& (1L <<< (i+1)) != 0L ? + cNormalized &&& (1L <<< (i + 1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target; - op(cs1[i], xNormalized[i+1], qs[i]); + op(cs1[i], xNormalized[i + 1], qs[i]); } } apply { let control = IsEmpty(qs) ? Tail(x) | Tail(qs); @@ -541,8 +540,8 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// controlled version that collects controls into one qubit /// by applying AND chain using auxiliary qubit array. internal operation ApplyAsSinglyControlled<'TIn> ( - op : ( 'TIn => Unit is Adj + Ctl ), - input : 'TIn ) : Unit is Adj + Ctl { + op : ('TIn => Unit is Adj + Ctl), + input : 'TIn) : Unit is Adj + Ctl { body (...) { op(input); @@ -559,7 +558,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { within { ApplyAndAssuming0Target(ctls[0], ctls[1], aux[0]); for i in 1..n-2 { - ApplyAndAssuming0Target(aux[i-1], ctls[i+1], aux[i]); + ApplyAndAssuming0Target(aux[i-1], ctls[i + 1], aux[i]); } } apply { Controlled op(aux[n-2..n-2], input); diff --git a/library/std/unstable_state_preparation.qs b/library/std/unstable_state_preparation.qs index f04688add3..cbedb2e36d 100644 --- a/library/std/unstable_state_preparation.qs +++ b/library/std/unstable_state_preparation.qs @@ -115,7 +115,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { let coefficientsPadded = Padded(-2 ^ nQubits, ComplexPolar(0.0, 0.0), coefficients); let idxTarget = 0; // Determine what controls to apply - let rngControl = nQubits > 1 ? (1 .. (nQubits - 1)) | (1..0); + let rngControl = nQubits > 1 ? (1..(nQubits - 1)) | (1..0); // Note we use the reversed qubits array to get the endianness ordering that we expect // when corresponding qubit state to state vector index. Adjoint ApproximatelyUnprepareArbitraryState( @@ -130,7 +130,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { coefficients : ComplexPolar[], rngControl : Range, idxTarget : Int, - register: Qubit[] + register : Qubit[] ) : Unit is Adj + Ctl { // For each 2D block, compute disentangling single-qubit rotation parameters @@ -231,7 +231,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { mutable disentanglingY = []; mutable newCoefficients = []; - for idxCoeff in 0 .. 2 .. Length(coefficients) - 1 { + for idxCoeff in 0..2..Length(coefficients) - 1 { let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); set disentanglingZ += [0.5 * phi]; set disentanglingY += [0.5 * theta]; @@ -256,7 +256,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { /// /// # Output /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. - internal function BlochSphereCoordinates ( + internal function BlochSphereCoordinates( a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) { @@ -343,12 +343,12 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { // pad coefficients length to a power of 2. let coefficientsPadded = Padded(2 ^ (Length(control) + 1), 0.0, Padded(-2 ^ Length(control), 0.0, coefficients)); let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance,coefficients0, control, target); - if AnyOutsideToleranceD(tolerance,coefficients1) { + ApproximatelyMultiplexZ(tolerance, coefficients0, control, target); + if AnyOutsideToleranceD(tolerance, coefficients1) { within { Controlled X(controlRegister, target); } apply { - ApproximatelyMultiplexZ(tolerance,coefficients1, control, target); + ApproximatelyMultiplexZ(tolerance, coefficients1, control, target); } } } @@ -361,7 +361,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { mutable coefficients0 = []; mutable coefficients1 = []; - for idxCoeff in 0 .. newCoefficientsLength - 1 { + for idxCoeff in 0..newCoefficientsLength - 1 { set coefficients0 += [0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength])]; set coefficients1 += [0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength])]; } diff --git a/library/std/unstable_table_lookup.qs b/library/std/unstable_table_lookup.qs index 74e5e6c62e..39191ec98e 100644 --- a/library/std/unstable_table_lookup.qs +++ b/library/std/unstable_table_lookup.qs @@ -57,7 +57,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup { WriteMemoryContents(Head(data), target); } else { let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2^(n - 1)], data); + let parts = Partitioned([2 ^ (n - 1)], data); within { X(tail); @@ -113,7 +113,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup { use helper = Qubit(); let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2^(n - 1)], data); + let parts = Partitioned([2 ^ (n - 1)], data); within { X(tail); @@ -180,13 +180,13 @@ namespace Microsoft.Quantum.Unstable.TableLookup { let res = Mapped(r -> r == One, ForEach(MResetX, target)); - let dataFixup = Chunks(2^l, Padded(-2^numAddressBits, false, + let dataFixup = Chunks(2 ^ l, Padded(-2 ^ numAddressBits, false, Mapped(MustBeFixed(res, _), data))); let numAddressBitsFixup = numAddressBits - l; let selectParts = Partitioned([l], select); - let targetFixup = target[...2^l - 1]; + let targetFixup = target[...2 ^ l - 1]; within { EncodeUnary(selectParts[0], targetFixup); @@ -220,8 +220,8 @@ namespace Microsoft.Quantum.Unstable.TableLookup { target : Qubit[] ) : Unit is Adj { Fact( - Length(target) == 2^Length(input), - $"target register should be of length {2^Length(input)}, but is {Length(target)}" + Length(target) == 2 ^ Length(input), + $"target register should be of length {2 ^ Length(input)}, but is {Length(target)}" ); X(Head(target)); @@ -232,7 +232,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup { CNOT(target[1], target[0]); } else { // targets are the first and second 2^i qubits of the target register - let split = Partitioned([2^i, 2^i], target); + let split = Partitioned([2 ^ i, 2 ^ i], target); for j in IndexRange(split[0]) { ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]); CNOT(split[1][j], split[0][j]); @@ -243,8 +243,8 @@ namespace Microsoft.Quantum.Unstable.TableLookup { } internal newtype AndChain = ( - NGarbageQubits: Int, - Apply: Qubit[] => Unit is Adj + NGarbageQubits : Int, + Apply : Qubit[] => Unit is Adj ); internal function MakeAndChain(ctls : Qubit[], target : Qubit) : AndChain { From 3e85e8ba2a553cdaee0d735f4c14b5181bf94a6c Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Mar 2024 15:23:12 -0700 Subject: [PATCH 66/74] try to fix integration test --- vscode/test/suites/debugger/debugger.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode/test/suites/debugger/debugger.test.ts b/vscode/test/suites/debugger/debugger.test.ts index 2a832845b6..a12c7ddb64 100644 --- a/vscode/test/suites/debugger/debugger.test.ts +++ b/vscode/test/suites/debugger/debugger.test.ts @@ -375,10 +375,10 @@ suite("Q# Debugger Tests", function suite() { sourceReference: 0, adapterData: "qsharp-adapter-data", }, - line: 165, + line: 159, column: 13, name: "H ", - endLine: 165, + endLine: 159, endColumn: 44, }, { From c577452cd058f01a5038b28cb33f8882bc031868 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Mar 2024 15:37:04 -0700 Subject: [PATCH 67/74] update expect on test --- compiler/qsc_eval/src/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs index 17fcf1a4cd..c98cbf45b1 100644 --- a/compiler/qsc_eval/src/tests.rs +++ b/compiler/qsc_eval/src/tests.rs @@ -348,16 +348,16 @@ fn block_qubit_use_array_invalid_count_expr() { 0, ), span: Span { - lo: 1568, - hi: 1625, + lo: 1566, + hi: 1623, }, }, ), [ Frame { span: Span { - lo: 1573, - hi: 1625, + lo: 1571, + hi: 1623, }, id: StoreItemId { package: PackageId( From 59042c604f9d4ec969b616577aecb81d886e9705 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 09:53:47 -0700 Subject: [PATCH 68/74] Added setting to enable/disable formatter --- vscode/package.json | 5 +++++ vscode/src/config.ts | 15 +++++++++++++ vscode/src/extension.ts | 48 ++++++++++++++++++++++++++++++++--------- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/vscode/package.json b/vscode/package.json index ab8caa74b8..aaadf137ba 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -108,6 +108,11 @@ "The minimal set of capabilities required to run a quantum program. This option maps to the Base Profile as defined by the QIR specification." ], "description": "Setting the target profile allows the Q# extension to generate programs that are compatible with a specific target. The target is the hardware or simulator which will be used to run the Q# program. The target profile is a description of a target's capabilities." + }, + "Q#.enableFormatting": { + "type": "boolean", + "default": "true", + "description": "Enables the Q# formatter to be used to format code." } } }, diff --git a/vscode/src/config.ts b/vscode/src/config.ts index 75e031ac8f..7990f99eed 100644 --- a/vscode/src/config.ts +++ b/vscode/src/config.ts @@ -26,3 +26,18 @@ export async function setTarget(target: TargetProfile) { vscode.ConfigurationTarget.Global, ); } + +export function getEnableFormating(): boolean { + return vscode.workspace + .getConfiguration("Q#") + .get("enableFormatting", true); +} + +export async function setEnableFormating(isEnabled: boolean) { + const config = vscode.workspace.getConfiguration("Q#"); + await config.update( + "enableFormatting", + isEnabled, + vscode.ConfigurationTarget.Global, + ); +} diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts index 6d2011349d..a73f20e4e9 100644 --- a/vscode/src/extension.ts +++ b/vscode/src/extension.ts @@ -18,7 +18,7 @@ import { qsharpLanguageId, } from "./common.js"; import { createCompletionItemProvider } from "./completion"; -import { getTarget } from "./config"; +import { getEnableFormating, getTarget } from "./config"; import { activateDebugger } from "./debugger/activate"; import { createDefinitionProvider } from "./definition"; import { startCheckingQSharp } from "./diagnostics"; @@ -182,8 +182,24 @@ async function activateLanguageService(extensionUri: vscode.Uri) { ...registerQSharpNotebookCellUpdateHandlers(languageService), ); + // format document + const isFormattingEnabled = getEnableFormating(); + const formatterEvent = { + event: undefined as vscode.Disposable | undefined, + }; + log.debug("Enable formatting set to: " + isFormattingEnabled); + if (isFormattingEnabled) { + formatterEvent.event = + vscode.languages.registerDocumentFormattingEditProvider( + qsharpLanguageId, + createFormatProvider(languageService), + ); + } + // synchronize configuration - subscriptions.push(registerConfigurationChangeHandlers(languageService)); + subscriptions.push( + registerConfigurationChangeHandlers(languageService, formatterEvent), + ); // completions subscriptions.push( @@ -194,14 +210,6 @@ async function activateLanguageService(extensionUri: vscode.Uri) { ), ); - // format document - subscriptions.push( - vscode.languages.registerDocumentFormattingEditProvider( - qsharpLanguageId, - createFormatProvider(languageService), - ), - ); - // hover subscriptions.push( vscode.languages.registerHoverProvider( @@ -275,6 +283,23 @@ async function updateLanguageServiceProfile(languageService: ILanguageService) { }); } +async function updateLanguageServiceEnableFormatting( + languageService: ILanguageService, + formatterEvent: any, +) { + const isFormattingEnabled = getEnableFormating(); + log.debug("Enable formatting set to: " + isFormattingEnabled); + if (isFormattingEnabled) { + formatterEvent.event = + vscode.languages.registerDocumentFormattingEditProvider( + qsharpLanguageId, + createFormatProvider(languageService), + ); + } else { + formatterEvent.event?.dispose(); + } +} + async function loadLanguageService(baseUri: vscode.Uri) { const start = performance.now(); const wasmUri = vscode.Uri.joinPath(baseUri, "./wasm/qsc_wasm_bg.wasm"); @@ -297,10 +322,13 @@ async function loadLanguageService(baseUri: vscode.Uri) { function registerConfigurationChangeHandlers( languageService: ILanguageService, + formatterEvent: any, ) { return vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration("Q#.targetProfile")) { updateLanguageServiceProfile(languageService); + } else if (event.affectsConfiguration("Q#.enableFormatting")) { + updateLanguageServiceEnableFormatting(languageService, formatterEvent); } }); } From e0445857c6d39e01f65581a55d1fe267f7d7ea91 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 11:10:19 -0700 Subject: [PATCH 69/74] Revert "format libraries" This reverts commit de61ac9ef8e1e90af0515624fd9fb005f0f7f300. --- library/core/core.qs | 2 +- library/src/tests/resources/add_le.qs | 4 +- library/src/tests/resources/compare.qs | 16 +- library/src/tests/resources/inc_by_le.qs | 6 +- library/src/tests/resources/qft_le.qs | 18 +- library/src/tests/resources/select.qs | 4 +- .../src/tests/resources/state_preparation.qs | 40 ++-- library/std/arrays.qs | 57 +++-- library/std/canon.qs | 24 +- library/std/convert.qs | 26 +- library/std/core.qs | 12 +- library/std/diagnostics.qs | 4 +- library/std/internal.qs | 81 ++++--- library/std/intrinsic.qs | 224 ++++++++++++------ library/std/math.qs | 112 ++++----- library/std/measurement.qs | 12 +- library/std/re.qs | 8 +- library/std/unstable_arithmetic.qs | 41 ++-- library/std/unstable_arithmetic_internal.qs | 63 ++--- library/std/unstable_state_preparation.qs | 16 +- library/std/unstable_table_lookup.qs | 18 +- 21 files changed, 426 insertions(+), 362 deletions(-) diff --git a/library/core/core.qs b/library/core/core.qs index b8abde5509..9e30481278 100644 --- a/library/core/core.qs +++ b/library/core/core.qs @@ -38,7 +38,7 @@ namespace Microsoft.Quantum.Core { } mutable output = []; - for _ in 1..length { + for _ in 1 .. length { set output += [value]; } diff --git a/library/src/tests/resources/add_le.qs b/library/src/tests/resources/add_le.qs index a53ba19d2a..948e57b5dc 100644 --- a/library/src/tests/resources/add_le.qs +++ b/library/src/tests/resources/add_le.qs @@ -45,8 +45,8 @@ namespace Test { bitwidth : Int) : Unit { TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth); - TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth + 1); - TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth + 2); + TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth+1); + TestAddLE3(name, adder, bitwidth, bitwidth, bitwidth+2); } diff --git a/library/src/tests/resources/compare.qs b/library/src/tests/resources/compare.qs index 417304572d..6b85f448b7 100644 --- a/library/src/tests/resources/compare.qs +++ b/library/src/tests/resources/compare.qs @@ -4,17 +4,17 @@ namespace Test { open Microsoft.Quantum.Diagnostics; internal operation CompareWithBigInt( - name : String, + name: String, bitwidth : Int, quantumComparator : (BigInt, Qubit[], Qubit) => Unit, classicalComparator : (Int, Int) -> Bool) : Unit { - + for n in 1..bitwidth { use qs = Qubit[n]; use t = Qubit(); - for a in 0..2 ^ n + 1 { // We want b to have more bits sometimes... - for b in 0..2 ^ n-1 { + for a in 0 .. 2^n+1 { // We want b to have more bits sometimes... + for b in 0 .. 2^n-1 { ApplyXorInPlace(b, qs); quantumComparator(IntAsBigInt(a), qs, t); let actual = MResetZ(t) == One; @@ -28,18 +28,18 @@ namespace Test { } internal operation CompareWithLE( - name : String, + name: String, bitwidth : Int, quantumComparator : (Qubit[], Qubit[], Qubit) => Unit, classicalComparator : (Int, Int) -> Bool) : Unit { - + for n in 1..bitwidth { use x = Qubit[n]; use y = Qubit[n]; use t = Qubit(); - for a in 0..2 ^ n-1 { - for b in 0..2 ^ n-1 { + for a in 0 .. 2^n-1 { + for b in 0 .. 2^n-1 { ApplyXorInPlace(a, x); ApplyXorInPlace(b, y); quantumComparator(x, y, t); diff --git a/library/src/tests/resources/inc_by_le.qs b/library/src/tests/resources/inc_by_le.qs index 283f7f819e..d8c54161a0 100644 --- a/library/src/tests/resources/inc_by_le.qs +++ b/library/src/tests/resources/inc_by_le.qs @@ -61,7 +61,7 @@ namespace Test { $"{name}: Incorrect sum={yActual}, expected={yExpected}. ctl={isCtl}, |x|={xLen}, |y|={yLen}, x={xValue}, y={yValue}."); Fact(xActual == xValue, $"{name}: Incorrect x={xActual}, expected={xValue}. ctl={isCtl}, |x|={xLen}, |y|={yLen}, x={xValue}, y={yValue}."); - + ResetAll(x); ResetAll(y); Reset(ctl); @@ -76,8 +76,8 @@ namespace Test { bitwidth : Int) : Unit { TestIncByLE2(name, adder, bitwidth, bitwidth); - TestIncByLE2(name, adder, bitwidth, bitwidth + 1); - TestIncByLE2(name, adder, bitwidth, bitwidth + 2); + TestIncByLE2(name, adder, bitwidth, bitwidth+1); + TestIncByLE2(name, adder, bitwidth, bitwidth+2); } internal operation TestIncByLECtl( diff --git a/library/src/tests/resources/qft_le.qs b/library/src/tests/resources/qft_le.qs index f99d3860c9..9c1341e687 100644 --- a/library/src/tests/resources/qft_le.qs +++ b/library/src/tests/resources/qft_le.qs @@ -2,18 +2,18 @@ namespace Test { open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Arrays; - operation PrepareEntangledState( + operation PrepareEntangledState ( left : Qubit[], right : Qubit[]) : Unit is Adj + Ctl { - for idxQubit in 0..Length(left) - 1 + for idxQubit in 0 .. Length(left) - 1 { H(left[idxQubit]); Controlled X([left[idxQubit]], right[idxQubit]); } } - operation AssertOperationsEqualReferenced( + operation AssertOperationsEqualReferenced ( nQubits : Int, actual : (Qubit[] => Unit), expected : (Qubit[] => Unit is Adj)) : Unit { @@ -33,14 +33,14 @@ namespace Test { /// # Summary /// Hard-code 1 qubit QFT - operation QFT1(target : Qubit[]) : Unit is Adj { + operation QFT1 (target : Qubit[]) : Unit is Adj { Fact(Length(target) == 1, $"`Length(target!)` must be 1"); H((target)[0]); } /// # Summary /// Hard-code 2 qubit QFT - operation QFT2(target : Qubit[]) : Unit is Adj { + operation QFT2 (target : Qubit[]) : Unit is Adj { Fact(Length(target) == 2, $"`Length(target!)` must be 2"); let (q1, q2) = ((target)[0], (target)[1]); H(q1); @@ -50,7 +50,7 @@ namespace Test { /// # Summary /// Hard-code 3 qubit QFT - operation QFT3(target : Qubit[]) : Unit is Adj { + operation QFT3 (target : Qubit[]) : Unit is Adj { Fact(Length(target) == 3, $"`Length(target)` must be 3"); let (q1, q2, q3) = ((target)[0], (target)[1], (target)[2]); H(q1); @@ -63,7 +63,7 @@ namespace Test { /// # Summary /// Hard-code 4 qubit QFT - operation QFT4(target : Qubit[]) : Unit is Adj { + operation QFT4 (target : Qubit[]) : Unit is Adj { Fact(Length(target) == 4, $"`Length(target!)` must be 4"); let (q1, q2, q3, q4) = ((target)[0], (target)[1], (target)[2], (target)[3]); H(q1); @@ -80,8 +80,8 @@ namespace Test { /// # Summary /// Compares QFT to the hard-coded implementations - operation TestQFT(n : Int) : Unit { - Fact(n >= 1 and n <= 4, "Only have four tests for QFT."); + operation TestQFT(n: Int) : Unit { + Fact(n>=1 and n<=4, "Only have four tests for QFT."); let testOperations = [QFT1, QFT2, QFT3, QFT4]; AssertOperationsEqualReferenced(n, testOperations[n-1], q => ApplyQFT(Reversed(q))); } diff --git a/library/src/tests/resources/select.qs b/library/src/tests/resources/select.qs index ceb035e149..08087539ad 100644 --- a/library/src/tests/resources/select.qs +++ b/library/src/tests/resources/select.qs @@ -10,7 +10,7 @@ namespace Test { use temporaryRegister = Qubit[dataBits]; use dataRegister = Qubit[dataBits]; - let data = DrawMany(_ => DrawMany(_ => (DrawRandomInt(0, 1) == 1), dataBits, 0), 2 ^ addressBits, 0); + let data = DrawMany(_ => DrawMany(_ => (DrawRandomInt(0, 1) == 1), dataBits, 0), 2^addressBits, 0); for (index, expected) in Enumerated(data) { ApplyXorInPlace(index, addressRegister); @@ -32,7 +32,7 @@ namespace Test { for _ in 1..rounds { let addressBits = DrawRandomInt(2, 6); let dataBits = 10; - let numData = DrawRandomInt(2 ^ (addressBits - 1) + 1, 2 ^ addressBits - 1); + let numData = DrawRandomInt(2^(addressBits - 1) + 1, 2^addressBits - 1); let data = DrawMany(_ => DrawMany(_ => (DrawRandomInt(0, 1) == 1), dataBits, 0), numData, 0); diff --git a/library/src/tests/resources/state_preparation.qs b/library/src/tests/resources/state_preparation.qs index 356a8e75c5..3c80bb6934 100644 --- a/library/src/tests/resources/state_preparation.qs +++ b/library/src/tests/resources/state_preparation.qs @@ -6,7 +6,7 @@ namespace Test { open Microsoft.Quantum.Unstable.StatePreparation; - operation TestPlusState() : Unit { + operation TestPlusState(): Unit { use q = Qubit(); PreparePureStateD([Sqrt(0.5), Sqrt(0.5)], [q]); DumpMachine(); @@ -14,7 +14,7 @@ namespace Test { H(q); } - operation TestMinusState() : Unit { + operation TestMinusState(): Unit { use q = Qubit(); PreparePureStateD([Sqrt(0.5), -Sqrt(0.5)], [q]); DumpMachine(); @@ -23,7 +23,7 @@ namespace Test { X(q); } - operation TestBellState() : Unit { + operation TestBellState(): Unit { use q = Qubit[2]; PreparePureStateD([Sqrt(0.5), 0.0, 0.0, Sqrt(0.5)], q); DumpMachine(); @@ -32,7 +32,7 @@ namespace Test { H(q[0]); } - operation TestCat3State() : Unit { + operation TestCat3State(): Unit { use q = Qubit[3]; PreparePureStateD([Sqrt(0.5), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Sqrt(0.5)], q); DumpMachine(); @@ -49,41 +49,41 @@ namespace Test { T(qs[1]); } - operation TestPrepareComplex() : Unit { + operation TestPrepareComplex(): Unit { use q = Qubit[2]; let c00 = ComplexPolar(0.5, 0.0); - let c01 = ComplexPolar(0.5, PI() / 4.0); - let c10 = ComplexPolar(0.5, PI() / 2.0); - let c11 = ComplexPolar(0.5, 3.0 * PI() / 4.0); + let c01 = ComplexPolar(0.5, PI()/4.0); + let c10 = ComplexPolar(0.5, PI()/2.0); + let c11 = ComplexPolar(0.5, 3.0*PI()/4.0); ApproximatelyPreparePureStateCP(0.0, [c00, c01, c10, c11], q); DumpMachine(); Adjoint PrepareComplex(q); } - operation TestPreparationCompletion() : Unit { + operation TestPreparationCompletion(): Unit { let testCases = [ - // Test positive coefficients - [0.773761, 0.633478], + // Test positive coefficients + [0.773761, 0.633478], [0.183017, 0.406973, 0.604925, 0.659502], [0.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.461883, 0.149609], [0.271471, 0.0583654, 0.11639, 0.36112, 0.307383, 0.193371, 0.274151, 0.332542, 0.130172, 0.222546, 0.314879, 0.210704, 0.212429, 0.245518, 0.30666, 0.22773], - // Test negative coefficients; should give same probabilities as positive coefficients - [-0.773761, 0.633478], + // Test negative coefficients; should give same probabilities as positive coefficients + [-0.773761, 0.633478], [0.183017, -0.406973, 0.604925, 0.659502], [0.0986553, -0.359005, 0.465689, -0.467395, 0.419893, 0.118445, -0.461883, 0.149609], [-0.271471, 0.0583654, 0.11639, 0.36112, -0.307383, 0.193371, -0.274151, 0.332542, 0.130172, 0.222546, 0.314879, -0.210704, 0.212429, 0.245518, -0.30666, -0.22773], - // Test unnormalized coefficients - [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], + // Test unnormalized coefficients + [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], - // Test missing coefficients - [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445] + // Test missing coefficients + [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445] ]; for coefficients in testCases { let L = Length(coefficients); - let N = Ceiling(Log(IntAsDouble(L)) / LogOf2() - 0.001); + let N = Ceiling(Log(IntAsDouble(L))/LogOf2() - 0.001); use q = Qubit[N]; PreparePureStateD(coefficients, q); DumpMachine(); @@ -91,10 +91,10 @@ namespace Test { } } - operation TestEndianness() : Unit { + operation TestEndianness(): Unit { let n = 4; use qs = Qubit[n]; - let bitsize = 2 ^ n; + let bitsize = 2^n; for i in 0..bitsize-1 { mutable c = Repeated(0.0, bitsize); set c w/= i <- 1.0; diff --git a/library/std/arrays.qs b/library/std/arrays.qs index 5265685912..0b7b08ce2a 100644 --- a/library/std/arrays.qs +++ b/library/std/arrays.qs @@ -246,7 +246,7 @@ namespace Microsoft.Quantum.Arrays { let columns = rows == 0 ? 0 | Length(Head(matrix)); let rangeLimit = MinI(rows, columns) - 1; mutable diagonal = []; - for index in 0..rangeLimit { + for index in 0 .. rangeLimit { set diagonal += [matrix[index][index]]; } @@ -280,7 +280,7 @@ namespace Microsoft.Quantum.Arrays { operation DrawMany<'TInput, 'TOutput>(op : ('TInput => 'TOutput), nSamples : Int, input : 'TInput) : 'TOutput[] { mutable outputs = []; - for _ in 1..nSamples { + for _ in 1 .. nSamples { set outputs += [op(input)]; } outputs @@ -349,7 +349,7 @@ namespace Microsoft.Quantum.Arrays { set toKeep w/= indexToRemove <- false; } mutable output = []; - for index in 0..arrayLength - 1 { + for index in 0 .. arrayLength - 1 { if toKeep[index] { set output += [array[index]]; } @@ -572,7 +572,7 @@ namespace Microsoft.Quantum.Arrays { /// // `indexOfFirstEven` is 3. /// ``` function IndexOf<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { - for index in 0..Length(array) - 1 { + for index in 0 .. Length(array) - 1 { if predicate(array[index]) { return index; } @@ -602,7 +602,7 @@ namespace Microsoft.Quantum.Arrays { /// for idx in 0 .. Length(array) - 1 { ... } /// ``` function IndexRange<'TElement>(array : 'TElement[]) : Range { - 0..Length(array) - 1 + 0 .. Length(array) - 1 } /// # Summary @@ -647,11 +647,8 @@ namespace Microsoft.Quantum.Arrays { for index in 0..interleavedLength - 1 { let originalIndex = index / 2; let value = - if index % 2 == 0 { - first[originalIndex] - } else { - second[originalIndex] - }; + if index % 2 == 0 {first[originalIndex]} + else {second[originalIndex]}; set interleaved += [value]; } interleaved @@ -696,7 +693,7 @@ namespace Microsoft.Quantum.Arrays { function IsRectangularArray<'T>(array : 'T[][]) : Bool { if (Length(array) > 0) { let columnCount = Length(Head(array)); - for index in 1..Length(array) - 1 { + for index in 1 .. Length(array) - 1 { if Length(array[index]) != columnCount { return false; } @@ -730,7 +727,7 @@ namespace Microsoft.Quantum.Arrays { /// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` /// is assumed. function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { - for index in 1..Length(array) - 1 { + for index in 1 .. Length(array) - 1 { if not comparison(array[index - 1], array[index]) { return false; } @@ -830,8 +827,8 @@ namespace Microsoft.Quantum.Arrays { /// ```qsharp /// let array = MappedByIndex(f, [x0, x1, x2]); /// ``` - /// and - /// ```qsharp + /// and + /// ```qsharp /// let array = [f(0, x0), f(1, x1), f(2, x2)]; /// ``` /// @@ -839,7 +836,7 @@ namespace Microsoft.Quantum.Arrays { /// - Microsoft.Quantum.Arrays.Mapped function MappedByIndex<'T, 'U> (mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[] { mutable mapped = []; - for index in 0..Length(array) - 1 { + for index in 0 .. Length(array) - 1 { set mapped += [mapper(index, array[index])]; } mapped @@ -895,7 +892,7 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// An array containing the elements `array[0..Length(array) - 2]`. function Most<'T> (array : 'T[]) : 'T[] { - array[...Length(array) - 2] + array[... Length(array) - 2] } /// # Summary @@ -993,10 +990,10 @@ namespace Microsoft.Quantum.Arrays { if partitionEndIndex >= Length(array) { fail "Partitioned argument out of bounds."; } - set output w/= index <- array[partitionStartIndex..partitionEndIndex]; + set output w/= index <- array[partitionStartIndex .. partitionEndIndex]; set partitionStartIndex = partitionEndIndex + 1; } - set output w/= Length(partitionSizes) <- array[partitionStartIndex..Length(array) - 1]; + set output w/= Length(partitionSizes) <- array[partitionStartIndex .. Length(array) - 1]; output } @@ -1015,7 +1012,7 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// An array containing the elements `array[1..Length(array) - 1]`. function Rest<'T> (array : 'T[]) : 'T[] { - array[1...] + array[1 ...] } /// # Summary @@ -1033,7 +1030,7 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// An array containing the elements `array[Length(array) - 1]` .. `array[0]`. function Reversed<'T>(array : 'T[]) : 'T[] { - array[...-1...] + array[... -1 ...] } /// # Summary @@ -1058,10 +1055,10 @@ namespace Microsoft.Quantum.Arrays { /// let numbers = SequenceI(0, _); // function to create sequence from 0 to `to` /// let naturals = SequenceI(1, _); // function to create sequence from 1 to `to` /// ``` - function SequenceI(from : Int, to : Int) : Int[] { + function SequenceI (from : Int, to : Int) : Int[] { Fact(to >= from, $"`to` must be larger than `from`."); mutable array = []; - for index in from..to { + for index in from .. to { set array += [index]; } array @@ -1089,7 +1086,7 @@ namespace Microsoft.Quantum.Arrays { /// let arr2 = SequenceL(23L, 29L); // [23L, 24L, 25L, 26L, 27L, 28L, 29L] /// let arr3 = SequenceL(-5L, -2L); // [-5L, -4L, -3L, -2L] /// ``` - function SequenceL(from : BigInt, to : BigInt) : BigInt[] { + function SequenceL (from : BigInt, to : BigInt) : BigInt[] { Fact(to >= from, "`to` must be larger than `from`"); mutable array = []; mutable current = from; @@ -1272,9 +1269,9 @@ namespace Microsoft.Quantum.Arrays { Fact(columnCount > 0, "Matrix must have at least 1 column"); Fact(IsRectangularArray(matrix), "Matrix is not a rectangular array"); mutable transposed = []; - for columnIndex in 0..columnCount - 1 { + for columnIndex in 0 .. columnCount - 1 { mutable newRow = []; - for rowIndex in 0..rowCount - 1 { + for rowIndex in 0 .. rowCount - 1 { set newRow += [matrix[rowIndex][columnIndex]]; } set transposed += [newRow]; @@ -1330,7 +1327,7 @@ namespace Microsoft.Quantum.Arrays { function Unzipped<'T, 'U>(array : ('T, 'U)[]) : ('T[], 'U[]) { mutable first = []; mutable second = []; - for index in 0..Length(array) - 1 { + for index in 0 .. Length(array) - 1 { let (left, right) = array[index]; set first += [left]; set second += [right]; @@ -1356,7 +1353,7 @@ namespace Microsoft.Quantum.Arrays { /// An array of indices where `predicate` is true. function Where<'T>(predicate : ('T -> Bool), array : 'T[]) : Int[] { mutable indexes = []; - for index in 0..Length(array) - 1 { + for index in 0 .. Length(array) - 1 { if predicate(array[index]) { set indexes += [index]; } @@ -1399,8 +1396,8 @@ namespace Microsoft.Quantum.Arrays { "The size of the window must be a positive integer no greater than the size of the array"); mutable windows = []; - for index in 0..arrayLength - size { - set windows += [array[index..index + size - 1]]; + for index in 0 .. arrayLength - size { + set windows += [array[index .. index + size - 1]]; } windows } @@ -1438,7 +1435,7 @@ namespace Microsoft.Quantum.Arrays { function Zipped<'T, 'U>(left : 'T[], right : 'U[]) : ('T, 'U)[] { let arrayLength = MinI(Length(left), Length(right)); mutable zipped = []; - for index in 0..arrayLength - 1 { + for index in 0 .. arrayLength - 1 { set zipped += [(left[index], right[index])]; } zipped diff --git a/library/std/canon.qs b/library/std/canon.qs index 6171a98605..244b914d63 100644 --- a/library/std/canon.qs +++ b/library/std/canon.qs @@ -153,7 +153,7 @@ namespace Microsoft.Quantum.Canon { /// ```qsharp /// CNOT(control, target); /// ``` - operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl{ body ... { __quantum__qis__cx__body(control, target); } @@ -188,7 +188,7 @@ namespace Microsoft.Quantum.Canon { /// ```qsharp /// Controlled Y([control], target); /// ``` - operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl{ body ... { __quantum__qis__cy__body(control, target); } @@ -263,7 +263,7 @@ namespace Microsoft.Quantum.Canon { /// $$ operation ApplyCNOTChain(qubits : Qubit[]) : Unit is Adj + Ctl { for i in 0..Length(qubits)-2 { - CNOT(qubits[i], qubits[i + 1]); + CNOT(qubits[i], qubits[i+1]); } } @@ -287,13 +287,9 @@ namespace Microsoft.Quantum.Canon { /// X(q); /// ``` operation ApplyP(pauli : Pauli, target : Qubit) : Unit is Adj + Ctl { - if pauli == PauliX { - X(target); - } elif pauli == PauliY { - Y(target); - } elif pauli == PauliZ { - Z(target); - } + if pauli == PauliX { X(target); } + elif pauli == PauliY { Y(target); } + elif pauli == PauliZ { Z(target); } } /// # Summary @@ -495,13 +491,13 @@ namespace Microsoft.Quantum.Canon { /// /// # Reference /// - [Quantum Fourier transform](https://en.wikipedia.org/wiki/Quantum_Fourier_transform) - operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl { + operation ApplyQFT (qs : Qubit[]) : Unit is Adj + Ctl { let length = Length(qs); Fact(length >= 1, "ApplyQFT: Length(qs) must be at least 1."); for i in length-1..-1..0 { H(qs[i]); for j in 0..i-1 { - Controlled R1Frac([qs[i]], (1, j + 1, qs[i-j-1])); + Controlled R1Frac([qs[i]], (1, j+1, qs[i-j-1])); } } } @@ -512,9 +508,9 @@ namespace Microsoft.Quantum.Canon { /// # Input /// ## register /// The qubits order of which should be reversed using SWAP gates - operation SwapReverseRegister(register : Qubit[]) : Unit is Adj + Ctl { + operation SwapReverseRegister (register : Qubit[]) : Unit is Adj + Ctl { let length = Length(register); - for i in 0..length / 2 - 1 { + for i in 0 .. length/2 - 1 { SWAP(register[i], register[(length - i) - 1]); } } diff --git a/library/std/convert.qs b/library/std/convert.qs index 00ef9139e6..0f75aeb1f6 100644 --- a/library/std/convert.qs +++ b/library/std/convert.qs @@ -44,11 +44,7 @@ namespace Microsoft.Quantum.Convert { /// A `Result` representing the `input`. @Config(Unrestricted) function BoolAsResult(input : Bool) : Result { - if input { - One - } else { - Zero - } + if input {One} else {Zero} } /// # Summary @@ -62,7 +58,7 @@ namespace Microsoft.Quantum.Convert { Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); mutable number = 0; - for i in 0..nBits - 1 { + for i in 0 .. nBits - 1 { if (bits[i]) { set number |||= 1 <<< i; } @@ -93,7 +89,7 @@ namespace Microsoft.Quantum.Convert { mutable runningValue = number; mutable result = []; for _ in 1..bits { - set result += [(runningValue &&& 1) != 0]; + set result += [ (runningValue &&& 1) != 0 ]; set runningValue >>>= 1; } Fact(runningValue == 0, $"`number`={number} is too large to fit into {bits} bits."); @@ -123,7 +119,7 @@ namespace Microsoft.Quantum.Convert { set result += 1L <<< i; } } - + result } @@ -149,7 +145,7 @@ namespace Microsoft.Quantum.Convert { mutable runningValue = number; mutable result = []; for _ in 1..bits { - set result += [(runningValue &&& 1L) != 0L]; + set result += [ (runningValue &&& 1L) != 0L ]; set runningValue >>>= 1; } Fact(runningValue == 0L, $"`number`={number} is too large to fit into {bits} bits."); @@ -178,7 +174,7 @@ namespace Microsoft.Quantum.Convert { Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); mutable number = 0; - for idxBit in 0..nBits - 1 { + for idxBit in 0 .. nBits - 1 { if (results[idxBit] == One) { set number |||= 1 <<< idxBit; } @@ -221,11 +217,7 @@ namespace Microsoft.Quantum.Convert { function BoolArrayAsResultArray(input : Bool[]) : Result[] { mutable output = []; for b in input { - set output += [if b { - One - } else { - Zero - }]; + set output += [if b {One} else {Zero}]; } output @@ -241,7 +233,7 @@ namespace Microsoft.Quantum.Convert { /// /// # Output /// Complex number c = r⋅e^(t𝑖). - function ComplexAsComplexPolar(input : Complex) : ComplexPolar { + function ComplexAsComplexPolar (input : Complex) : ComplexPolar { return ComplexPolar(AbsComplex(input), ArgComplex(input)); } @@ -255,7 +247,7 @@ namespace Microsoft.Quantum.Convert { /// /// # Output /// Complex number c = x + y𝑖. - function ComplexPolarAsComplex(input : ComplexPolar) : Complex { + function ComplexPolarAsComplex (input : ComplexPolar) : Complex { return Complex( input::Magnitude * Cos(input::Argument), input::Magnitude * Sin(input::Argument) diff --git a/library/std/core.qs b/library/std/core.qs index 8442c91202..1c1b458a93 100644 --- a/library/std/core.qs +++ b/library/std/core.qs @@ -16,14 +16,14 @@ namespace Microsoft.Quantum.Core { /// A range expression's first element is `start`, /// its second element is `start+step`, third element is `start+step+step`, etc., /// until `end` is passed. - /// + /// /// Note that the defined start value of a range is the same as the first element of the sequence, /// unless the range specifies an empty sequence (for example, 2 .. 1). function RangeStart(r : Range) : Int { r::Start } - - + + /// # Summary /// Returns the defined end value of the given range, /// which is not necessarily the last element in the sequence. @@ -39,14 +39,14 @@ namespace Microsoft.Quantum.Core { /// A range expression's first element is `start`, /// its second element is `start+step`, third element is `start+step+step`, etc., /// until `end` is passed. - /// + /// /// Note that the defined end value of a range can differ from the last element in the sequence specified by the range; /// for example, in a range 0 .. 2 .. 5 the last element is 4 but the end value is 5. function RangeEnd(r : Range) : Int { r::End } - - + + /// # Summary /// Returns the integer that specifies how the next value of a range is calculated. /// diff --git a/library/std/diagnostics.qs b/library/std/diagnostics.qs index d6d50ee9de..1a976b0a19 100644 --- a/library/std/diagnostics.qs +++ b/library/std/diagnostics.qs @@ -121,7 +121,7 @@ namespace Microsoft.Quantum.Diagnostics { /// # Output /// True if operations are equal, false otherwise. @Config(Unrestricted) - operation CheckOperationsAreEqual( + operation CheckOperationsAreEqual ( nQubits : Int, actual : (Qubit[] => Unit), expected : (Qubit[] => Unit is Adj)) : Bool { @@ -132,7 +132,7 @@ namespace Microsoft.Quantum.Diagnostics { // Apply operations. within { - for i in 0..nQubits - 1 { + for i in 0 .. nQubits - 1 { H(reference[i]); CNOT(reference[i], target[i]); } diff --git a/library/std/internal.qs b/library/std/internal.qs index 75d1559a5a..6a2f4dc4e4 100644 --- a/library/std/internal.qs +++ b/library/std/internal.qs @@ -11,7 +11,8 @@ namespace Microsoft.Quantum.Intrinsic { S(target); H(target); T(target); - } apply { + } + apply { CNOT(control, target); } } @@ -21,7 +22,8 @@ namespace Microsoft.Quantum.Intrinsic { S(target); H(target); T(target); - } apply { + } + apply { CCNOT(control1, control2, target); } } @@ -31,20 +33,22 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { // Noop - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { Rz(theta, ctls[0]); - } else { + } + else { Controlled R1(ctls[1..(Length(ctls) - 1)], (theta, ctls[0])); } } } internal operation CR1(theta : Double, control : Qubit, target : Qubit) : Unit is Adj { - Rz(theta / 2.0, target); - Rz(theta / 2.0, control); - CNOT(control, target); - Rz(-theta / 2.0, target); - CNOT(control, target); + Rz(theta/2.0, target); + Rz(theta/2.0, control); + CNOT(control,target); + Rz(-theta/2.0, target); + CNOT(control,target); } internal operation CRz(control : Qubit, theta : Double, target : Qubit) : Unit is Adj { @@ -72,21 +76,28 @@ namespace Microsoft.Quantum.Intrinsic { } internal operation MapPauli(qubit : Qubit, from : Pauli, to : Pauli) : Unit is Adj { - if from == to {} elif (from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ) { + if from == to { + } + elif (from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ) { H(qubit); - } elif from == PauliZ and to == PauliY { + } + elif from == PauliZ and to == PauliY { H(qubit); S(qubit); H(qubit); - } elif from == PauliY and to == PauliZ { + } + elif from == PauliY and to == PauliZ { H(qubit); Adjoint S(qubit); H(qubit); - } elif from == PauliY and to == PauliX { + } + elif from == PauliY and to == PauliX { S(qubit); - } elif from == PauliX and to == PauliY { + } + elif from == PauliX and to == PauliY { Adjoint S(qubit); - } else { + } + else { fail "Unsupported input"; } } @@ -94,9 +105,11 @@ namespace Microsoft.Quantum.Intrinsic { internal operation EntangleForJointMeasure(basis : Pauli, aux : Qubit, qubit : Qubit) : Unit { if basis == PauliX { Controlled X([aux], qubit); - } elif basis == PauliZ { + } + elif basis == PauliZ { Controlled Z([aux], qubit); - } elif basis == PauliY { + } + elif basis == PauliY { Controlled Y([aux], qubit); } } @@ -151,15 +164,15 @@ namespace Microsoft.Quantum.Intrinsic { internal operation PhaseCCX(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { // https://arxiv.org/pdf/1210.0974.pdf#page=2 H(target); - CNOT(target, control1); - CNOT(control1, control2); + CNOT(target,control1); + CNOT(control1,control2); T(control2); Adjoint T(control1); T(target); - CNOT(target, control1); - CNOT(control1, control2); + CNOT(target,control1); + CNOT(control1,control2); Adjoint T(control2); - CNOT(target, control2); + CNOT(target,control2); H(target); } @@ -174,7 +187,8 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CCY(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { within { MapPauli(target, PauliX, PauliY); - } apply { + } + apply { CCNOT(control1, control2, target); } } @@ -182,7 +196,8 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CRxx(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { within { CNOT(qubit1, qubit0); - } apply { + } + apply { Controlled Rx([control], (theta, qubit0)); } } @@ -190,7 +205,8 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CRyy(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { within { CNOT(qubit1, qubit0); - } apply { + } + apply { Controlled Ry([control], (theta, qubit0)); } } @@ -198,14 +214,15 @@ namespace Microsoft.Quantum.Intrinsic { internal operation CRzz(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { within { CNOT(qubit1, qubit0); - } apply { + } + apply { Controlled Rz([control], (theta, qubit0)); } } - internal function IndicesOfNonIdentity(paulies : Pauli[]) : Int[] { + internal function IndicesOfNonIdentity (paulies : Pauli[]) : Int[] { mutable indices = []; - for i in 0..Length(paulies) - 1 { + for i in 0 .. Length(paulies) - 1 { if (paulies[i] != PauliI) { set indices += [i]; } @@ -213,19 +230,19 @@ namespace Microsoft.Quantum.Intrinsic { indices } - internal function RemovePauliI(paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) { + internal function RemovePauliI (paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) { let indices = IndicesOfNonIdentity(paulis); let newPaulis = Subarray(indices, paulis); let newQubits = Subarray(indices, qubits); return (newPaulis, newQubits); } - internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj { + internal operation SpreadZ (from : Qubit, to : Qubit[]) : Unit is Adj { if (Length(to) > 0) { if (Length(to) > 1) { let half = Length(to) / 2; - SpreadZ(to[0], to[half + 1..Length(to) - 1]); - SpreadZ(from, to[1..half]); + SpreadZ(to[0], to[half + 1 .. Length(to) - 1]); + SpreadZ(from, to[1 .. half]); } CNOT(to[0], from); } diff --git a/library/std/intrinsic.qs b/library/std/intrinsic.qs index 270c817c47..c1d5c01e7d 100644 --- a/library/std/intrinsic.qs +++ b/library/std/intrinsic.qs @@ -93,7 +93,7 @@ namespace Microsoft.Quantum.Intrinsic { /// $$ /// where $P_i$ is the $i$th element of `paulis`, and where /// $N = $`Length(paulis)`. - operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { + operation Exp (paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { body ... { Fact(Length(paulis) == Length(qubits), "Arrays 'pauli' and 'qubits' must have the same length"); @@ -103,29 +103,35 @@ namespace Microsoft.Quantum.Intrinsic { if len == 0 { ApplyGlobalPhase(theta); - } elif len == 1 { + } + elif len == 1 { R(newPaulis[0], angle, qubits[0]); - } elif len == 2 { + } + elif len == 2 { within { MapPauli(qubits[1], paulis[0], paulis[1]); - } apply { + } + apply { if (paulis[0] == PauliX) { - Rxx(angle, qubits[0], qubits[1]); + Rxx(angle , qubits[0], qubits[1]); } elif (paulis[0] == PauliY) { Ryy(angle, qubits[0], qubits[1]); } elif (paulis[0] == PauliZ) { Rzz(angle, qubits[0], qubits[1]); } } - } else { // len > 2 + } + else { // len > 2 within { - for i in 0..Length(paulis) - 1 { + for i in 0 .. Length(paulis) - 1 { MapPauli(qubits[i], PauliZ, paulis[i]); } - } apply { + } + apply { within { - SpreadZ(qubits[1], qubits[2..Length(qubits) - 1]); - } apply { + SpreadZ(qubits[1], qubits[2 .. Length(qubits) - 1]); + } + apply { Rzz(angle, qubits[0], qubits[1]); } } @@ -161,18 +167,23 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__h__body(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CH(ctls[0], qubit); - } elif Length(ctls) == 2 { + } + elif Length(ctls) == 2 { CCH(ctls[0], ctls[1], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 1 - (Length(ctls) % 2)]; within { CollectControls(ctls, aux, 0); - } apply { + } + apply { if Length(ctls) % 2 != 0 { CCH(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { + } + else { CCH(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -188,7 +199,7 @@ namespace Microsoft.Quantum.Intrinsic { /// This is a no-op. It is provided for completeness and because /// sometimes it is useful to call the identity in an algorithm or to pass it as a parameter. operation I(target : Qubit) : Unit is Adj + Ctl { - body ... {} + body ... { } adjoint self; } @@ -298,14 +309,17 @@ namespace Microsoft.Quantum.Intrinsic { if Length(bases) == 1 { within { MapPauli(qubits[0], PauliZ, bases[0]); - } apply { + } + apply { __quantum__qis__m__body(qubits[0]) } - } else { + } + else { use aux = Qubit(); within { H(aux); - } apply { + } + apply { for i in 0..Length(bases)-1 { EntangleForJointMeasure(bases[i], aux, qubits[i]); } @@ -361,7 +375,8 @@ namespace Microsoft.Quantum.Intrinsic { use aux = Qubit(); within { H(aux); - } apply { + } + apply { for i in 0..Length(bases)-1 { EntangleForJointMeasure(bases[i], aux, qubits[i]); } @@ -395,12 +410,15 @@ namespace Microsoft.Quantum.Intrinsic { operation R(pauli : Pauli, theta : Double, qubit : Qubit) : Unit is Adj + Ctl { if (pauli == PauliX) { Rx(theta, qubit); - } elif (pauli == PauliY) { + } + elif (pauli == PauliY) { Ry(theta, qubit); - } elif (pauli == PauliZ) { + } + elif (pauli == PauliZ) { Rz(theta, qubit); - } else { // PauliI - ApplyGlobalPhase( - theta / 2.0); + } + else { // PauliI + ApplyGlobalPhase( - theta / 2.0 ); } } @@ -433,14 +451,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { Rz(theta, qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CR1(theta, ctls[0], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { CR1(theta, aux[Length(ctls) - 2], qubit); } } @@ -581,10 +602,12 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rx__body(theta, qubit); - } else { + } + else { within { MapPauli(qubit, PauliZ, PauliX); - } apply { + } + apply { Controlled Rz(ctls, (theta, qubit)); } } @@ -624,14 +647,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rxx__body(theta, qubit0, qubit1); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CRxx(ctls[0], theta, qubit0, qubit1); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { CRxx(aux[Length(ctls) - 2], theta, qubit0, qubit1); } } @@ -673,10 +699,12 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__ry__body(theta, qubit); - } else { + } + else { within { MapPauli(qubit, PauliZ, PauliY); - } apply { + } + apply { Controlled Rz(ctls, (theta, qubit)); } } @@ -716,14 +744,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__ryy__body(theta, qubit0, qubit1); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CRyy(ctls[0], theta, qubit0, qubit1); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { CRyy(aux[Length(ctls) - 2], theta, qubit0, qubit1); } } @@ -765,14 +796,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rz__body(theta, qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CRz(ctls[0], theta, qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { CRz(aux[Length(ctls) - 2], theta, qubit); } } @@ -812,14 +846,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__rzz__body(theta, qubit0, qubit1); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CRzz(ctls[0], theta, qubit0, qubit1); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { CRzz(aux[Length(ctls) - 2], theta, qubit0, qubit1); } } @@ -856,18 +893,23 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__s__body(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CS(ctls[0], qubit); - } elif Length(ctls) == 2 { + } + elif Length(ctls) == 2 { Controlled CS([ctls[0]], (ctls[1], qubit)); - } else { + } + else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { + } + apply { if Length(ctls) % 2 != 0 { Controlled CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); - } else { + } + else { Controlled CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); } } @@ -876,18 +918,23 @@ namespace Microsoft.Quantum.Intrinsic { controlled adjoint (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__s__adj(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { Adjoint CS(ctls[0], qubit); - } elif Length(ctls) == 2 { + } + elif Length(ctls) == 2 { Controlled Adjoint CS([ctls[0]], (ctls[1], qubit)); - } else { + } + else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { + } + apply { if Length(ctls) % 2 != 0 { Controlled Adjoint CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); - } else { + } + else { Controlled Adjoint CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); } } @@ -933,10 +980,12 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if (Length(ctls) == 0) { __quantum__qis__swap__body(qubit1, qubit2); - } else { + } + else { within { CNOT(qubit1, qubit2); - } apply { + } + apply { Controlled CNOT(ctls, (qubit2, qubit1)); } } @@ -970,14 +1019,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__t__body(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { CT(ctls[0], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { CT(aux[Length(ctls) - 2], qubit); } } @@ -985,14 +1037,17 @@ namespace Microsoft.Quantum.Intrinsic { controlled adjoint (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__t__adj(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { Adjoint CT(ctls[0], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 1]; within { CollectControls(ctls, aux, 0); AdjustForSingleControl(ctls, aux); - } apply { + } + apply { Adjoint CT(aux[Length(ctls) - 2], qubit); } } @@ -1023,18 +1078,23 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__x__body(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { __quantum__qis__cx__body(ctls[0], qubit); - } elif Length(ctls) == 2 { + } + elif Length(ctls) == 2 { __quantum__qis__ccx__body(ctls[0], ctls[1], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { + } + apply { if Length(ctls) % 2 != 0 { __quantum__qis__ccx__body(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { + } + else { __quantum__qis__ccx__body(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -1067,18 +1127,23 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if (Length(ctls) == 0) { __quantum__qis__y__body(qubit); - } elif (Length(ctls) == 1) { + } + elif (Length(ctls) == 1) { __quantum__qis__cy__body(ctls[0], qubit); - } elif (Length(ctls) == 2) { + } + elif (Length(ctls) == 2) { CCY(ctls[0], ctls[1], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { + } + apply { if Length(ctls) % 2 != 0 { CCY(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { + } + else { CCY(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -1111,18 +1176,23 @@ namespace Microsoft.Quantum.Intrinsic { controlled (ctls, ...) { if Length(ctls) == 0 { __quantum__qis__z__body(qubit); - } elif Length(ctls) == 1 { + } + elif Length(ctls) == 1 { __quantum__qis__cz__body(ctls[0], qubit); - } elif Length(ctls) == 2 { + } + elif Length(ctls) == 2 { CCZ(ctls[0], ctls[1], qubit); - } else { + } + else { use aux = Qubit[Length(ctls) - 2]; within { CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { + } + apply { if Length(ctls) % 2 != 0 { CCZ(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { + } + else { CCZ(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); } } @@ -1142,7 +1212,7 @@ namespace Microsoft.Quantum.Intrinsic { /// The specific behavior of this function is simulator-dependent, /// but in most cases the given message will be written to the console. /// ``` - function Message(msg : String) : Unit { + function Message (msg : String) : Unit { body intrinsic; } diff --git a/library/std/math.qs b/library/std/math.qs index 4db0942355..7d37628f2e 100644 --- a/library/std/math.qs +++ b/library/std/math.qs @@ -40,7 +40,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// Returns a `Double` equal to 0.6931471805599453. - function LogOf2() : Double + function LogOf2 () : Double { 0.6931471805599453 } @@ -102,54 +102,42 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignI(a : Int) : Int { - if (a < 0) { - -1 - } elif (a > 0) { - 1 - } else { - 0 - } + function SignI (a : Int) : Int { + if (a < 0) { -1 } + elif (a > 0) { +1 } + else { 0 } } /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignD(a : Double) : Int { - if (a < 0.0) { - -1 - } elif (a > 0.0) { - 1 - } else { - 0 - } + function SignD (a : Double) : Int { + if (a < 0.0) { -1 } + elif (a > 0.0) { +1 } + else { 0 } } /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignL(a : BigInt) : Int { - if (a < 0L) { - -1 - } elif (a > 0L) { - 1 - } else { - 0 - } + function SignL (a : BigInt) : Int { + if (a < 0L) { -1 } + elif (a > 0L) { +1 } + else { 0 } } /// # Summary /// Returns the absolute value of an integer. - function AbsI(a : Int) : Int { + function AbsI (a : Int) : Int { a < 0 ? -a | a } /// # Summary /// Returns the absolute value of a double-precision floating-point number. - function AbsD(a : Double) : Double { + function AbsD (a : Double) : Double { a < 0.0 ? -a | a } /// # Summary - function AbsL(a : BigInt) : BigInt { + function AbsL (a : BigInt) : BigInt { a < 0L ? -a | a } @@ -167,19 +155,19 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns the larger of two specified numbers. - function MaxL(a : BigInt, b : BigInt) : BigInt { + function MaxL (a : BigInt, b : BigInt) : BigInt { a > b ? a | b } /// # Summary /// Returns the smaller of two specified numbers. - function MinI(a : Int, b : Int) : Int { + function MinI (a : Int, b : Int) : Int { a < b ? a | b } /// # Summary /// Returns the smaller of two specified numbers. - function MinD(a : Double, b : Double) : Double { + function MinD (a : Double, b : Double) : Double { a < b ? a | b } @@ -198,7 +186,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The largest element of `values`. - function Max(values : Int[]) : Int { + function Max (values : Int[]) : Int { Fact(Length(values) > 0, "Array must contain at least one element."); mutable max = values[0]; for element in values[1...] { @@ -219,7 +207,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The smallest element of `values`. - function Min(values : Int[]) : Int { + function Min (values : Int[]) : Int { Fact(Length(values) > 0, "Array must contain at least one element."); mutable min = values[0]; for element in values[1...] { @@ -237,80 +225,80 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns the angle whose cosine is the specified number. - function ArcCos(x : Double) : Double { + function ArcCos (x : Double) : Double { body intrinsic; } /// # Summary /// Returns the angle whose sine is the specified number. - function ArcSin(y : Double) : Double { + function ArcSin (y : Double) : Double { body intrinsic; } /// # Summary /// Returns the angle whose tangent is the specified number. - function ArcTan(d : Double) : Double { + function ArcTan (d : Double) : Double { body intrinsic; } /// # Summary /// Returns the angle whose tangent is the quotient of two specified numbers. - function ArcTan2(y : Double, x : Double) : Double { + function ArcTan2 (y : Double, x : Double) : Double { body intrinsic; } /// # Summary /// Returns the cosine of the specified angle. - function Cos(theta : Double) : Double { + function Cos (theta : Double) : Double { body intrinsic; } /// # Summary /// Returns the hyperbolic cosine of the specified angle. - function Cosh(d : Double) : Double { + function Cosh (d : Double) : Double { body intrinsic; } /// # Summary /// Returns the sine of the specified angle. - function Sin(theta : Double) : Double { + function Sin (theta : Double) : Double { body intrinsic; } /// # Summary /// Returns the hyperbolic sine of the specified angle. - function Sinh(d : Double) : Double { + function Sinh (d : Double) : Double { body intrinsic; } /// # Summary /// Returns the tangent of the specified angle. - function Tan(d : Double) : Double { + function Tan (d : Double) : Double { body intrinsic; } /// # Summary /// Returns the hyperbolic tangent of the specified angle. - function Tanh(d : Double) : Double { + function Tanh (d : Double) : Double { body intrinsic; } /// # Summary /// Computes the inverse hyperbolic cosine of a number. - function ArcCosh(x : Double) : Double { + function ArcCosh (x : Double) : Double { Log(x + Sqrt(x * x - 1.0)) } /// # Summary /// Computes the inverse hyperbolic sine of a number. - function ArcSinh(x : Double) : Double { + function ArcSinh (x : Double) : Double { Log(x + Sqrt(x * x + 1.0)) } /// # Summary /// Computes the inverse hyperbolic tangent of a number. - function ArcTanh(x : Double) : Double { + function ArcTanh (x : Double) : Double { Log((1.0 + x) / (1.0 - x)) * 0.5 } @@ -750,7 +738,7 @@ namespace Microsoft.Quantum.Math { /// # Summary /// For a non-zero integer `a`, returns the number of trailing zero bits /// in the binary representation of `a`. - function TrailingZeroCountI(a : Int) : Int { + function TrailingZeroCountI (a : Int) : Int { Fact(a != 0, "TrailingZeroCountI: `a` cannot be 0."); mutable count = 0; @@ -766,7 +754,7 @@ namespace Microsoft.Quantum.Math { /// # Summary /// For a non-zero integer `a`, returns the number of trailing zero bits /// in the binary representation of `a`. - function TrailingZeroCountL(a : BigInt) : Int { + function TrailingZeroCountL (a : BigInt) : Int { Fact(a != 0L, "TrailingZeroCountL: `a` cannot be 0."); mutable count = 0; @@ -781,7 +769,7 @@ namespace Microsoft.Quantum.Math { /// # Summary /// Returns the number of 1 bits in the binary representation of integer `n`. - function HammingWeightI(n : Int) : Int { + function HammingWeightI (n : Int) : Int { let i1 = n - ((n >>> 1) &&& 0x5555555555555555); let i2 = (i1 &&& 0x3333333333333333) + ((i1 >>> 2) &&& 0x3333333333333333); // Multiplication may overflow. See https://github.com/microsoft/qsharp/issues/828 @@ -838,7 +826,7 @@ namespace Microsoft.Quantum.Math { Fact(n >= 0, "The factorial is not defined for negative inputs."); mutable result = 1L; - for i in 1..n { + for i in 1 .. n { set result *= IntAsBigInt(i); } result @@ -964,7 +952,7 @@ namespace Microsoft.Quantum.Math { if n < 171 { Floor(0.5 + ApproximateFactorial(n) / (ApproximateFactorial(k) * ApproximateFactorial(n - k))) } else { - Floor(0.5 + E() ^ (LogFactorialD(n) - LogFactorialD(k) - LogFactorialD(n - k))) + Floor(0.5 + E()^(LogFactorialD(n) - LogFactorialD(k) - LogFactorialD(n - k))) } } @@ -985,7 +973,7 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The squared 2-norm of `array`. - function SquaredNorm(array : Double[]) : Double { + function SquaredNorm (array : Double[]) : Double { mutable sum = 0.0; for element in array { set sum += element * element; @@ -1006,17 +994,17 @@ namespace Microsoft.Quantum.Math { /// /// # Output /// The p-norm |x̄|ₚ. - function PNorm(p : Double, array : Double[]) : Double { + function PNorm (p : Double, array : Double[]) : Double { if p < 1.0 { fail "p must be >= 1.0"; } mutable sum = 0.0; for element in array { - set sum += AbsD(element) ^ p; + set sum += AbsD(element)^p; } - sum ^ (1.0 / p) + sum^(1.0 / p) } /// # Summary @@ -1035,7 +1023,7 @@ namespace Microsoft.Quantum.Math { /// /// # See Also /// - PNorm - function PNormalized(p : Double, array : Double[]) : Double[] { + function PNormalized (p : Double, array : Double[]) : Double[] { let norm = PNorm(p, array); if (norm == 0.0) { return array; @@ -1063,7 +1051,7 @@ namespace Microsoft.Quantum.Math { /// ```qsharp /// let imagUnit = Complex(0.0, 1.0); /// ``` - newtype Complex = (Real : Double, Imag : Double); + newtype Complex = (Real: Double, Imag: Double); /// # Summary /// Represents a complex number in polar form. @@ -1074,7 +1062,7 @@ namespace Microsoft.Quantum.Math { /// The absolute value r>0 of c. /// ## Argument /// The phase t ∈ ℝ of c. - newtype ComplexPolar = (Magnitude : Double, Argument : Double); + newtype ComplexPolar = (Magnitude: Double, Argument: Double); /// # Summary /// Returns the squared absolute value of a complex number of type @@ -1293,7 +1281,7 @@ namespace Microsoft.Quantum.Math { /// Note that this is a multi-valued function, but only one value is returned. internal function PowCAsCP(base : Complex, power : Complex) : ComplexPolar { let ((a, b), (c, d)) = (base!, power!); - let baseSqNorm = a * a + b * b; + let baseSqNorm = a*a + b*b; let baseNorm = Sqrt(baseSqNorm); let baseArg = ArgComplex(base); @@ -1306,7 +1294,7 @@ namespace Microsoft.Quantum.Math { // magnitude = 𝑒^((c⋅ln(baseNorm) - d⋅baseArg)) = baseNorm^c / 𝑒^(d⋅baseArg) // angle = d⋅ln(baseNorm) + c⋅baseArg - let magnitude = baseNorm ^ c / E() ^ (d * baseArg); + let magnitude = baseNorm^c / E()^(d * baseArg); let angle = d * Log(baseNorm) + c * baseArg; ComplexPolar(magnitude, angle) @@ -1394,7 +1382,7 @@ namespace Microsoft.Quantum.Math { /// # Remark /// The value can be computed as -2^(p-1), where p is the number of integer bits. function SmallestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { - -(2.0 ^ IntAsDouble(integerBits - 1)) + -(2.0^IntAsDouble(integerBits - 1)) } /// # Summary @@ -1410,7 +1398,7 @@ namespace Microsoft.Quantum.Math { /// The value can be computed as 2^(p-1) - 2^(-q), where p /// is the number of integer bits and q is the number of fractional bits. function LargestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { - 2.0 ^ IntAsDouble(integerBits - 1) - 2.0 ^ (-IntAsDouble(fractionalBits)) + 2.0^IntAsDouble(integerBits - 1) - 2.0^(-IntAsDouble(fractionalBits)) } } diff --git a/library/std/measurement.qs b/library/std/measurement.qs index fc4e05326a..d24dfbcec2 100644 --- a/library/std/measurement.qs +++ b/library/std/measurement.qs @@ -24,7 +24,7 @@ namespace Microsoft.Quantum.Measurement { /// # Remarks /// This operation does not reset the measured qubits to the |0⟩ state, /// leaving them in the state that corresponds to the measurement result. - operation MeasureAllZ(register : Qubit[]) : Result { + operation MeasureAllZ (register : Qubit[]) : Result { Measure(Repeated(PauliZ, Length(register)), register) } @@ -39,7 +39,7 @@ namespace Microsoft.Quantum.Measurement { /// # Remarks /// This operation does not reset the measured qubits to the |0⟩ state, /// leaving them in the state that corresponds to the measurement results. - operation MeasureEachZ(register : Qubit[]) : Result[] { + operation MeasureEachZ (register : Qubit[]) : Result[] { mutable results = []; for qubit in register { set results += [M(qubit)]; @@ -55,7 +55,7 @@ namespace Microsoft.Quantum.Measurement { /// An array of qubits to be measured. /// # Output /// An array of measurement results. - operation MResetEachZ(register : Qubit[]) : Result[] { + operation MResetEachZ (register : Qubit[]) : Result[] { mutable results = []; for qubit in register { set results += [MResetZ(qubit)]; @@ -79,7 +79,7 @@ namespace Microsoft.Quantum.Measurement { /// /// # Output /// The result of measuring `target` in the Pauli X basis. - operation MResetX(target : Qubit) : Result { + operation MResetX (target : Qubit) : Result { // Map the qubit's state from the Z-basis to the X-basis. // Then measure and reset the qubit. H(target); @@ -102,7 +102,7 @@ namespace Microsoft.Quantum.Measurement { /// /// # Output /// The result of measuring `target` in the Pauli Y basis. - operation MResetY(target : Qubit) : Result { + operation MResetY (target : Qubit) : Result { // Map the qubit's state from the Z-basis to the Y-basis. // Then measure and reset the qubit. // Note: this use HSadj instead of HSH since that is sufficient for measurement. @@ -127,7 +127,7 @@ namespace Microsoft.Quantum.Measurement { /// /// # Output /// The result of measuring `target` in the Pauli Z basis. - operation MResetZ(target : Qubit) : Result { + operation MResetZ (target : Qubit) : Result { __quantum__qis__mresetz__body(target) } diff --git a/library/std/re.qs b/library/std/re.qs index 29b71bf13d..09e05d0359 100644 --- a/library/std/re.qs +++ b/library/std/re.qs @@ -34,7 +34,7 @@ namespace Microsoft.Quantum.ResourceEstimation { /// `false` indicates if cached estimates have been incorporated into the overall costs /// and the code fragment should be skipped. @Config(Unrestricted) - function BeginEstimateCaching(name : String, variant : Int) : Bool { + function BeginEstimateCaching(name: String, variant: Int): Bool { body intrinsic; } @@ -42,7 +42,7 @@ namespace Microsoft.Quantum.ResourceEstimation { /// Instructs the resource estimator to stop estimates caching /// because the code fragment in consideration is over. This function /// is only available when using resource estimator execution target. - function EndEstimateCaching() : Unit { + function EndEstimateCaching(): Unit { body intrinsic; } @@ -116,14 +116,14 @@ namespace Microsoft.Quantum.ResourceEstimation { /// to physical resource estimates. Only PSSPCLayout() is supported at this time. /// ## arguments /// Operation takes these qubits as its arguments. - operation AccountForEstimates(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit is Adj { + operation AccountForEstimates(estimates: (Int, Int)[], layout: Int, arguments: Qubit[]): Unit is Adj { body ... { AccountForEstimatesInternal(estimates, layout, arguments); } adjoint self; } - internal operation AccountForEstimatesInternal(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit { + internal operation AccountForEstimatesInternal(estimates: (Int, Int)[], layout: Int, arguments: Qubit[]): Unit { body intrinsic; } diff --git a/library/std/unstable_arithmetic.qs b/library/std/unstable_arithmetic.qs index b4970a92b3..0c6b045339 100644 --- a/library/std/unstable_arithmetic.qs +++ b/library/std/unstable_arithmetic.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// The second input qubit. /// ## z /// A qubit onto which the majority function will be applied. - operation MAJ(x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { + operation MAJ (x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { CNOT(z, y); CNOT(z, x); CCNOT(y, x, z); @@ -46,7 +46,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Remarks /// This operation is implemented in-place, without explicit allocation of /// additional auxiliary qubits. - operation ReflectAboutInteger(index : Int, reg : Qubit[]) : Unit is Adj + Ctl { + operation ReflectAboutInteger (index : Int, reg : Qubit[]) : Unit is Adj + Ctl { within { // Evaluation optimization for case index == 0 if index == 0 { @@ -94,7 +94,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Length(ys) = n > 0, c is a Int number, 0 ≤ c < 2ⁿ. /// NOTE: Use IncByIUsingIncByLE directly if the choice of implementation /// is important. - operation IncByI(c : Int, ys : Qubit[]) : Unit is Adj + Ctl { + operation IncByI (c : Int, ys : Qubit[]) : Unit is Adj + Ctl { IncByIUsingIncByLE(RippleCarryTTKIncByLE, c, ys); } @@ -106,7 +106,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. /// NOTE: Use IncByLUsingIncByLE directly if the choice of implementation /// is important. - operation IncByL(c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { + operation IncByL (c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { IncByLUsingIncByLE(RippleCarryTTKIncByLE, c, ys); } @@ -118,7 +118,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// and Length(xs) ≤ Length(ys) = n. /// NOTE: Use operations like RippleCarryCGIncByLE directly if /// the choice of implementation is important. - operation IncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation IncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { RippleCarryTTKIncByLE(xs, ys); } @@ -131,7 +131,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Length(xs) = Length(ys) ≤ Length(zs) = n, assuming zs is 0-initialized. /// NOTE: Use operations like RippleCarryCGAddLE directly if /// the choice of implementation is important. - operation AddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + operation AddLE (xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { RippleCarryCGAddLE(xs, ys, zs); } @@ -151,7 +151,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// "Quantum Addition Circuits and Unbounded Fan-Out" /// by Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro /// - operation RippleCarryTTKIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation RippleCarryTTKIncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { let xsLen = Length(xs); let ysLen = Length(ys); @@ -166,8 +166,9 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { ApplyInnerTTKAdderNoCarry(xs, ys); } } - CNOT(xs[0], ys[0]); - } elif xsLen + 1 == ysLen { + CNOT (xs[0], ys[0]); + } + elif xsLen + 1 == ysLen { if xsLen > 1 { CNOT(xs[xsLen-1], ys[ysLen-1]); within { @@ -175,11 +176,13 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { } apply { ApplyInnerTTKAdderWithCarry(xs, ys); } - } else { + } + else { CCNOT(xs[0], ys[0], ys[1]); } CNOT(xs[0], ys[0]); - } elif xsLen + 2 <= ysLen { + } + elif xsLen + 2 <= ysLen { // Pad xs so that its length is one qubit shorter than ys. use padding = Qubit[ysLen - xsLen - 1]; RippleCarryTTKIncByLE(xs + padding, ys); @@ -200,7 +203,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Reference /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) /// "Halving the cost of quantum addition" by Craig Gidney. - operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation RippleCarryCGIncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { let xsLen = Length(xs); let ysLen = Length(ys); @@ -257,7 +260,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Reference /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) /// "Halving the cost of quantum addition" by Craig Gidney. - operation RippleCarryCGAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + operation RippleCarryCGAddLE (xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { let xsLen = Length(xs); let zsLen = Length(zs); Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); @@ -266,7 +269,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { // Since zs is zero-initialized, its bits at indexes higher than // xsLen remain unused as there will be no carry into them. let top = MinI(zsLen-2, xsLen-1); - for k in 0..top { + for k in 0 .. top { FullAdder(zs[k], xs[k], ys[k], zs[k + 1]); } @@ -338,7 +341,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Reference /// - [arXiv:quant-ph/0008033](https://arxiv.org/abs/quant-ph/0008033) /// "Addition on a Quantum Computer" by Thomas G. Draper - operation FourierTDIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + operation FourierTDIncByLE (xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { within { ApplyQFT(ys); } apply { @@ -355,7 +358,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Description /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. - operation IncByLUsingIncByLE( + operation IncByLUsingIncByLE ( adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { @@ -363,7 +366,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let ysLen = Length(ys); Fact(ysLen > 0, "Length of `ys` must be at least 1."); Fact(c >= 0L, "Constant `c` must be non-negative."); - Fact(c < 2L ^ ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + Fact(c < 2L^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); if c != 0L { // If c has j trailing zeros, then the j least significant @@ -387,7 +390,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// # Description /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register /// Length(ys) = n > 0, c is an Int number, 0 ≤ c < 2ⁿ. - operation IncByIUsingIncByLE( + operation IncByIUsingIncByLE ( adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, c : Int, ys : Qubit[]) : Unit is Adj + Ctl { @@ -395,7 +398,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let ysLen = Length(ys); Fact(ysLen > 0, "Length of `ys` must be at least 1."); Fact(c >= 0, "Constant `c` must be non-negative."); - Fact(c < 2 ^ ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + Fact(c < 2^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); if c != 0 { // If c has j trailing zeros than the j least significant diff --git a/library/std/unstable_arithmetic_internal.qs b/library/std/unstable_arithmetic_internal.qs index 44785d4d4a..5a0fa365a2 100644 --- a/library/std/unstable_arithmetic_internal.qs +++ b/library/std/unstable_arithmetic_internal.qs @@ -28,12 +28,12 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { internal operation ApplyOuterTTKAdder(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { Fact(Length(xs) <= Length(ys), - "Input register ys must be at lease as long as xs."); + "Input register ys must be at lease as long as xs." ); for i in 1..Length(xs)-1 { CNOT(xs[i], ys[i]); } for i in Length(xs)-2..-1..1 { - CNOT(xs[i], xs[i + 1]); + CNOT(xs[i], xs[i+1]); } } @@ -63,14 +63,14 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { internal operation ApplyInnerTTKAdderNoCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { body (...) { - (Controlled ApplyInnerTTKAdderNoCarry)([], (xs, ys)); + (Controlled ApplyInnerTTKAdderNoCarry) ([], (xs, ys)); } - controlled (controls, ...) { + controlled ( controls, ... ) { Fact(Length(xs) == Length(ys), - "Input registers must have the same number of qubits."); + "Input registers must have the same number of qubits." ); for idx in 0..Length(xs) - 2 { - CCNOT(xs[idx], ys[idx], xs[idx + 1]); + CCNOT (xs[idx], ys[idx], xs[idx + 1]); } for idx in Length(xs)-1..-1..1 { Controlled CNOT(controls, (xs[idx], ys[idx])); @@ -107,15 +107,15 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { body (...) { (Controlled ApplyInnerTTKAdderWithCarry)([], (xs, ys)); } - controlled (controls, ...) { - Fact(Length(xs) + 1 == Length(ys), - "ys must be one qubit longer then xs."); + controlled ( controls, ... ) { + Fact(Length(xs)+1 == Length(ys), + "ys must be one qubit longer then xs." ); Fact(Length(xs) > 0, "Array should not be empty."); let nQubits = Length(xs); for idx in 0..nQubits - 2 { - CCNOT(xs[idx], ys[idx], xs[idx + 1]); + CCNOT(xs[idx], ys[idx], xs[idx+1]); } (Controlled CCNOT)(controls, (xs[nQubits-1], ys[nQubits-1], ys[nQubits])); for idx in nQubits - 1..-1..1 { @@ -255,7 +255,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) /// doi:10.1103/PhysRevA.87.022328 @Config(Unrestricted) - internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) + internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target: Qubit) : Unit is Adj { // NOTE: Eventually this operation will be public and intrinsic. body (...) { if not CheckZero(target) { @@ -300,7 +300,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) /// doi:10.1103/PhysRevA.87.022328 @Config(Base) - internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) + internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target: Qubit) : Unit is Adj { H(target); T(target); @@ -309,7 +309,8 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { within { CNOT(target, control1); CNOT(target, control2); - } apply { + } + apply { Adjoint T(control1); Adjoint T(control2); T(target); @@ -322,12 +323,12 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// Computes carries for the look-ahead adder internal operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj { let n = Length(gs); - Fact(Length(ps) + 1 == n, "Register gs must be one qubit longer than register gs."); + Fact(Length(ps)+1 == n, "Register gs must be one qubit longer than register gs."); let T = Floor(Lg(IntAsDouble(n))); use qs = Qubit[n - HammingWeightI(n) - T]; - let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2 ^ t)) - 1, 1..T - 1); + let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1); let pWorkspace = [ps] + Partitioned(registerPartition, qs); within { @@ -382,11 +383,11 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let n = Length(gs); for t in 1..T { - let length = Floor(IntAsDouble(n) / IntAsDouble(2 ^ t)) - 1; + let length = Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1; let ps = pWorkspace[t - 1][0..2...]; for m in 0..length { - CCNOT(gs[2 ^ t * m + 2 ^ (t - 1) - 1], ps[m], gs[2 ^ t * m + 2 ^ t - 1]); + CCNOT(gs[2^t * m + 2^(t - 1) - 1], ps[m], gs[2^t * m + 2^t - 1]); } } } @@ -398,16 +399,16 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { let start = Floor(Lg(IntAsDouble(2 * n) / 3.0)); for t in start..-1..1 { - let length = Floor(IntAsDouble(n - 2 ^ (t - 1)) / IntAsDouble(2 ^ t)); + let length = Floor(IntAsDouble(n - 2^(t - 1)) / IntAsDouble(2^t)); let ps = pWorkspace[t - 1][1..2...]; for m in 1..length { - CCNOT(gs[2 ^ t * m - 1], ps[m - 1], gs[2 ^ t * m + 2 ^ (t - 1) - 1]); + CCNOT(gs[2^t * m - 1], ps[m - 1], gs[2^t * m + 2^(t - 1) - 1]); } } } - internal operation PhaseGradient(qs : Qubit[]) : Unit is Adj + Ctl { + internal operation PhaseGradient (qs : Qubit[]) : Unit is Adj + Ctl { for i in IndexRange(qs) { R1Frac(1, i, qs[i]); } @@ -422,18 +423,18 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// (if `invertControl` is false). If `invertControl` is true, the `action` /// is applied in the opposite situation. internal operation ApplyActionIfGreaterThanOrEqualConstant<'T>( - invertControl : Bool, - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T) : Unit is Adj + Ctl { + invertControl: Bool, + action: 'T => Unit is Adj + Ctl, + c: BigInt, + x: Qubit[], + target: 'T) : Unit is Adj + Ctl { let bitWidth = Length(x); if c == 0L { if not invertControl { action(target); } - } elif c >= (2L ^ bitWidth) { + } elif c >= (2L^bitWidth) { if invertControl { action(target); } @@ -458,9 +459,9 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { within { for i in 0..Length(cs1)-1 { let op = - cNormalized &&& (1L <<< (i + 1)) != 0L ? + cNormalized &&& (1L <<< (i+1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target; - op(cs1[i], xNormalized[i + 1], qs[i]); + op(cs1[i], xNormalized[i+1], qs[i]); } } apply { let control = IsEmpty(qs) ? Tail(x) | Tail(qs); @@ -540,8 +541,8 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { /// controlled version that collects controls into one qubit /// by applying AND chain using auxiliary qubit array. internal operation ApplyAsSinglyControlled<'TIn> ( - op : ('TIn => Unit is Adj + Ctl), - input : 'TIn) : Unit is Adj + Ctl { + op : ( 'TIn => Unit is Adj + Ctl ), + input : 'TIn ) : Unit is Adj + Ctl { body (...) { op(input); @@ -558,7 +559,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { within { ApplyAndAssuming0Target(ctls[0], ctls[1], aux[0]); for i in 1..n-2 { - ApplyAndAssuming0Target(aux[i-1], ctls[i + 1], aux[i]); + ApplyAndAssuming0Target(aux[i-1], ctls[i+1], aux[i]); } } apply { Controlled op(aux[n-2..n-2], input); diff --git a/library/std/unstable_state_preparation.qs b/library/std/unstable_state_preparation.qs index cbedb2e36d..f04688add3 100644 --- a/library/std/unstable_state_preparation.qs +++ b/library/std/unstable_state_preparation.qs @@ -115,7 +115,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { let coefficientsPadded = Padded(-2 ^ nQubits, ComplexPolar(0.0, 0.0), coefficients); let idxTarget = 0; // Determine what controls to apply - let rngControl = nQubits > 1 ? (1..(nQubits - 1)) | (1..0); + let rngControl = nQubits > 1 ? (1 .. (nQubits - 1)) | (1..0); // Note we use the reversed qubits array to get the endianness ordering that we expect // when corresponding qubit state to state vector index. Adjoint ApproximatelyUnprepareArbitraryState( @@ -130,7 +130,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { coefficients : ComplexPolar[], rngControl : Range, idxTarget : Int, - register : Qubit[] + register: Qubit[] ) : Unit is Adj + Ctl { // For each 2D block, compute disentangling single-qubit rotation parameters @@ -231,7 +231,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { mutable disentanglingY = []; mutable newCoefficients = []; - for idxCoeff in 0..2..Length(coefficients) - 1 { + for idxCoeff in 0 .. 2 .. Length(coefficients) - 1 { let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); set disentanglingZ += [0.5 * phi]; set disentanglingY += [0.5 * theta]; @@ -256,7 +256,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { /// /// # Output /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. - internal function BlochSphereCoordinates( + internal function BlochSphereCoordinates ( a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) { @@ -343,12 +343,12 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { // pad coefficients length to a power of 2. let coefficientsPadded = Padded(2 ^ (Length(control) + 1), 0.0, Padded(-2 ^ Length(control), 0.0, coefficients)); let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance, coefficients0, control, target); - if AnyOutsideToleranceD(tolerance, coefficients1) { + ApproximatelyMultiplexZ(tolerance,coefficients0, control, target); + if AnyOutsideToleranceD(tolerance,coefficients1) { within { Controlled X(controlRegister, target); } apply { - ApproximatelyMultiplexZ(tolerance, coefficients1, control, target); + ApproximatelyMultiplexZ(tolerance,coefficients1, control, target); } } } @@ -361,7 +361,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { mutable coefficients0 = []; mutable coefficients1 = []; - for idxCoeff in 0..newCoefficientsLength - 1 { + for idxCoeff in 0 .. newCoefficientsLength - 1 { set coefficients0 += [0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength])]; set coefficients1 += [0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength])]; } diff --git a/library/std/unstable_table_lookup.qs b/library/std/unstable_table_lookup.qs index cb37a53c03..5cb064528c 100644 --- a/library/std/unstable_table_lookup.qs +++ b/library/std/unstable_table_lookup.qs @@ -56,7 +56,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup { WriteMemoryContents(Head(data), target); } else { let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2 ^ (n - 1)], data); + let parts = Partitioned([2^(n - 1)], data); within { X(tail); @@ -112,7 +112,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup { use helper = Qubit(); let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2 ^ (n - 1)], data); + let parts = Partitioned([2^(n - 1)], data); within { X(tail); @@ -179,13 +179,13 @@ namespace Microsoft.Quantum.Unstable.TableLookup { let res = Mapped(r -> r == One, ForEach(MResetX, target)); - let dataFixup = Chunks(2 ^ l, Padded(-2 ^ numAddressBits, false, + let dataFixup = Chunks(2^l, Padded(-2^numAddressBits, false, Mapped(MustBeFixed(res, _), data))); let numAddressBitsFixup = numAddressBits - l; let selectParts = Partitioned([l], select); - let targetFixup = target[...2 ^ l - 1]; + let targetFixup = target[...2^l - 1]; within { EncodeUnary(selectParts[0], targetFixup); @@ -219,8 +219,8 @@ namespace Microsoft.Quantum.Unstable.TableLookup { target : Qubit[] ) : Unit is Adj { Fact( - Length(target) == 2 ^ Length(input), - $"target register should be of length {2 ^ Length(input)}, but is {Length(target)}" + Length(target) == 2^Length(input), + $"target register should be of length {2^Length(input)}, but is {Length(target)}" ); X(Head(target)); @@ -231,7 +231,7 @@ namespace Microsoft.Quantum.Unstable.TableLookup { CNOT(target[1], target[0]); } else { // targets are the first and second 2^i qubits of the target register - let split = Partitioned([2 ^ i, 2 ^ i], target); + let split = Partitioned([2^i, 2^i], target); for j in IndexRange(split[0]) { ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]); CNOT(split[1][j], split[0][j]); @@ -242,8 +242,8 @@ namespace Microsoft.Quantum.Unstable.TableLookup { } internal newtype AndChain = ( - NGarbageQubits : Int, - Apply : Qubit[] => Unit is Adj + NGarbageQubits: Int, + Apply: Qubit[] => Unit is Adj ); internal function MakeAndChain(ctls : Qubit[], target : Qubit) : AndChain { From 1ebac90a8f92ea5baaa30994a8eaa010942932a2 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 11:10:56 -0700 Subject: [PATCH 70/74] Revert "samples formatted" This reverts commit 80ba9e7ed5280f1b0a88df5b0f2f31b270ecd905. --- samples/algorithms/BernsteinVazirani.qs | 2 +- samples/algorithms/BitFlipCode.qs | 14 ++-- samples/algorithms/DeutschJozsa.qs | 8 +-- samples/algorithms/Entanglement.qs | 2 +- samples/algorithms/HiddenShift.qs | 4 +- samples/algorithms/HiddenShiftNISQ.qs | 4 +- samples/algorithms/Measurement.qs | 2 +- samples/algorithms/PhaseFlipCode.qs | 14 ++-- samples/algorithms/QRNG.qs | 2 +- samples/algorithms/RandomBit.qs | 2 +- samples/algorithms/Shor.qs | 12 ++-- samples/algorithms/Superposition.qs | 2 +- samples/algorithms/Teleportation.qs | 2 +- samples/estimation/Dynamics.qs | 35 +++++----- samples/estimation/EkeraHastadFactoring.qs | 18 ++--- samples/estimation/ShorRE.qs | 4 +- .../df-chemistry/src/df_chemistry.qs | 68 +++++++++---------- .../estimation/df-chemistry/src/prepare.qs | 26 +++---- samples/language/Comments.qs | 4 +- samples/language/ConditionalBranching.qs | 14 +--- samples/language/EntryPoint.qs | 2 +- samples/language/ForLoops.qs | 6 +- samples/language/LambdaExpression.qs | 2 +- samples/language/MultiFileProject/src/Main.qs | 16 ++--- .../language/MultiFileProject/src/Particle.qs | 12 ++-- samples/language/Namespaces.qs | 2 +- samples/language/Operations.qs | 12 ++-- samples/language/Pauli.qs | 4 +- samples/language/QuantumMemory.qs | 2 +- samples/language/Qubit.qs | 4 +- samples/language/Range.qs | 2 +- samples/language/Result.qs | 2 +- samples/language/ReturnStatement.qs | 2 +- samples/language/Specializations.qs | 32 ++++----- samples/language/Unit.qs | 2 +- 35 files changed, 166 insertions(+), 175 deletions(-) diff --git a/samples/algorithms/BernsteinVazirani.qs b/samples/algorithms/BernsteinVazirani.qs index 88b81c2e47..70b983b996 100644 --- a/samples/algorithms/BernsteinVazirani.qs +++ b/samples/algorithms/BernsteinVazirani.qs @@ -148,7 +148,7 @@ namespace Sample { // Apply the quantum operations that encode the bit string. for index in IndexRange(xRegister) { - if ((bitStringAsInt &&& 2 ^ index) != 0) { + if ((bitStringAsInt &&& 2^index) != 0) { CNOT(xRegister[index], yQubit); } } diff --git a/samples/algorithms/BitFlipCode.qs b/samples/algorithms/BitFlipCode.qs index 1f3b39213e..19b2308661 100644 --- a/samples/algorithms/BitFlipCode.qs +++ b/samples/algorithms/BitFlipCode.qs @@ -119,14 +119,14 @@ namespace Sample { // parity measurements. let indexOfError = if (parity01, parity12) == (One, Zero) { - 0 - } elif (parity01, parity12) == (One, One) { - 1 - } elif (parity01, parity12) == (Zero, One) { - 2 - } else { + 0 + } elif (parity01, parity12) == (One, One) { + 1 + } elif (parity01, parity12) == (Zero, One) { + 2 + } else { -1 - }; + }; // If an error was detected, correct that qubit. if indexOfError > -1 { diff --git a/samples/algorithms/DeutschJozsa.qs b/samples/algorithms/DeutschJozsa.qs index c60249eb01..718a69b9bd 100644 --- a/samples/algorithms/DeutschJozsa.qs +++ b/samples/algorithms/DeutschJozsa.qs @@ -40,7 +40,7 @@ namespace Sample { let isConstant = DeutschJozsa(fn, 5); if (isConstant != shouldBeConstant) { let shouldBeConstantStr = shouldBeConstant ? - "constant" | + "constant" | "balanced"; fail $"{name} should be detected as {shouldBeConstantStr}"; } @@ -104,7 +104,7 @@ namespace Sample { // state so that they can be safely deallocated at the end of the block. // The loop also sets `result` to `true` if all measurement results are // `Zero`, i.e. if the function is a constant function, and sets - // `result` to `false` if not, which according to the assumption on 𝑓 + // `result` to `false` if not, which according to the assumption on 𝑓 // means that it must be balanced. mutable result = true; for q in queryRegister { @@ -131,7 +131,7 @@ namespace Sample { // A more complex constant Boolean function. // It applies X to every input basis vector. operation ConstantBoolF(args : Qubit[], target : Qubit) : Unit { - for i in 0..(2 ^ Length(args))-1 { + for i in 0..(2^Length(args))-1 { ApplyControlledOnInt(i, X, args, target); } } @@ -139,7 +139,7 @@ namespace Sample { // A more complex balanced Boolean function. // It applies X to half of the input basis vectors. operation BalancedBoolF(args : Qubit[], target : Qubit) : Unit { - for i in 0..2..(2 ^ Length(args))-1 { + for i in 0..2..(2^Length(args))-1 { ApplyControlledOnInt(i, X, args, target); } } diff --git a/samples/algorithms/Entanglement.qs b/samples/algorithms/Entanglement.qs index dca96c80f7..de63ed8804 100644 --- a/samples/algorithms/Entanglement.qs +++ b/samples/algorithms/Entanglement.qs @@ -14,7 +14,7 @@ namespace Sample { // Allocate the two qubits that will be entangled. use (q1, q2) = (Qubit(), Qubit()); - // Set the first qubit in superposition by calling the `H` operation, + // Set the first qubit in superposition by calling the `H` operation, // which applies a Hadamard transformation to the qubit. // Then, entangle the two qubits using the `CNOT` operation. H(q1); diff --git a/samples/algorithms/HiddenShift.qs b/samples/algorithms/HiddenShift.qs index 58fc6ee399..32f9bf58b5 100644 --- a/samples/algorithms/HiddenShift.qs +++ b/samples/algorithms/HiddenShift.qs @@ -81,7 +81,7 @@ namespace Sample { /// - [*Martin Roetteler*, /// Proc. SODA 2010, ACM, pp. 448-457, 2010] /// (https://doi.org/10.1137/1.9781611973075.37) - operation FindHiddenShift( + operation FindHiddenShift ( Ufstar : (Qubit[] => Unit), Ug : (Qubit[] => Unit), n : Int) @@ -142,7 +142,7 @@ namespace Sample { operation BentFunction(register : Qubit[]) : Unit { Fact(Length(register) % 2 == 0, "Length of register must be even."); let u = Length(register) / 2; - let xs = register[0..u - 1]; + let xs = register[0 .. u - 1]; let ys = register[u...]; for index in 0..u-1 { CZ(xs[index], ys[index]); diff --git a/samples/algorithms/HiddenShiftNISQ.qs b/samples/algorithms/HiddenShiftNISQ.qs index c063c4d3a2..75d8cdd4ce 100644 --- a/samples/algorithms/HiddenShiftNISQ.qs +++ b/samples/algorithms/HiddenShiftNISQ.qs @@ -72,7 +72,7 @@ namespace Sample { /// - [*Martin Roetteler*, /// Proc. SODA 2010, ACM, pp. 448-457, 2010] /// (https://doi.org/10.1137/1.9781611973075.37) - operation FindHiddenShift( + operation FindHiddenShift ( Ufstar : (Qubit[] => Unit), Ug : (Qubit[] => Unit), n : Int) @@ -133,7 +133,7 @@ namespace Sample { operation BentFunction(register : Qubit[]) : Unit { Fact(Length(register) % 2 == 0, "Length of register must be even."); let u = Length(register) / 2; - let xs = register[0..u - 1]; + let xs = register[0 .. u - 1]; let ys = register[u...]; for index in 0..u-1 { CZ(xs[index], ys[index]); diff --git a/samples/algorithms/Measurement.qs b/samples/algorithms/Measurement.qs index 4f0d9ad15e..8a0f1959de 100644 --- a/samples/algorithms/Measurement.qs +++ b/samples/algorithms/Measurement.qs @@ -14,7 +14,7 @@ namespace Sample { open Microsoft.Quantum.Measurement; @EntryPoint() - operation Main() : (Result, Result[]) { + operation Main () : (Result, Result[]) { // The `M` operation performs a measurement of a single qubit in the // computational basis, also known as the Pauli Z basis. use q = Qubit(); diff --git a/samples/algorithms/PhaseFlipCode.qs b/samples/algorithms/PhaseFlipCode.qs index 10788523ec..b70ece981f 100644 --- a/samples/algorithms/PhaseFlipCode.qs +++ b/samples/algorithms/PhaseFlipCode.qs @@ -140,14 +140,14 @@ namespace Sample { // parity measurements. let indexOfError = if (parity01, parity12) == (One, Zero) { - 0 - } elif (parity01, parity12) == (One, One) { - 1 - } elif (parity01, parity12) == (Zero, One) { - 2 - } else { + 0 + } elif (parity01, parity12) == (One, One) { + 1 + } elif (parity01, parity12) == (Zero, One) { + 2 + } else { -1 - }; + }; // If an error was detected, correct that qubit. if indexOfError > -1 { diff --git a/samples/algorithms/QRNG.qs b/samples/algorithms/QRNG.qs index 95b951a8e4..c04994e4cc 100644 --- a/samples/algorithms/QRNG.qs +++ b/samples/algorithms/QRNG.qs @@ -42,7 +42,7 @@ namespace Sample { // Allocate a qubit. use q = Qubit(); - // Set the qubit into superposition of 0 and 1 using the Hadamard + // Set the qubit into superposition of 0 and 1 using the Hadamard // operation `H`. H(q); diff --git a/samples/algorithms/RandomBit.qs b/samples/algorithms/RandomBit.qs index 4d4c119f2d..66538329ee 100644 --- a/samples/algorithms/RandomBit.qs +++ b/samples/algorithms/RandomBit.qs @@ -16,7 +16,7 @@ namespace Sample { // Set the qubit in superposition by applying a Hadamard transformation. H(qubit); - // Measure the qubit. There is a 50% probability of measuring either + // Measure the qubit. There is a 50% probability of measuring either // `Zero` or `One`. let result = M(qubit); diff --git a/samples/algorithms/Shor.qs b/samples/algorithms/Shor.qs index 781b32f915..787f168b7b 100644 --- a/samples/algorithms/Shor.qs +++ b/samples/algorithms/Shor.qs @@ -79,11 +79,12 @@ namespace Sample { set foundFactors = true; set factors = (gcd, number / gcd); } - set attempt = attempt + 1; + set attempt = attempt+1; if (attempt > 100) { fail "Failed to find factors: too many attempts!"; } - } until foundFactors + } + until foundFactors fixup { Message("The estimated period did not yield a valid factor. " + "Trying again."); @@ -234,7 +235,8 @@ namespace Sample { if frequencyEstimate != 0 { return PeriodFromFrequency( modulus, frequencyEstimate, bitsPrecision, 1); - } else { + } + else { Message("The estimated frequency was 0, trying again."); return 1; } @@ -256,10 +258,10 @@ namespace Sample { /// /// # Output /// The numerator k of dyadic fraction k/2^bitsPrecision approximating s/r. - operation EstimateFrequency(generator : Int, modulus : Int, bitsize : Int) + operation EstimateFrequency(generator : Int,modulus : Int, bitsize : Int) : Int { mutable frequencyEstimate = 0; - let bitsPrecision = 2 * bitsize + 1; + let bitsPrecision = 2 * bitsize + 1; Message($"Estimating frequency with bitsPrecision={bitsPrecision}."); // Allocate qubits for the superposition of eigenstates of the oracle diff --git a/samples/algorithms/Superposition.qs b/samples/algorithms/Superposition.qs index c00bb69255..5ed19e77b4 100644 --- a/samples/algorithms/Superposition.qs +++ b/samples/algorithms/Superposition.qs @@ -15,7 +15,7 @@ namespace Sample { // Set the qubit in superposition by applying a Hadamard transformation. H(qubit); - // Measure the qubit. There is a 50% probability of measuring either + // Measure the qubit. There is a 50% probability of measuring either // `Zero` or `One`. let result = M(qubit); diff --git a/samples/algorithms/Teleportation.qs b/samples/algorithms/Teleportation.qs index 924c493ac0..21c2e8e398 100644 --- a/samples/algorithms/Teleportation.qs +++ b/samples/algorithms/Teleportation.qs @@ -15,7 +15,7 @@ namespace Sample { open Microsoft.Quantum.Measurement; @EntryPoint() - operation Main() : Result[] { + operation Main () : Result[] { // Allocate the message and target qubits. use (message, target) = (Qubit(), Qubit()); diff --git a/samples/estimation/Dynamics.qs b/samples/estimation/Dynamics.qs index 01aabc0534..95d9832159 100644 --- a/samples/estimation/Dynamics.qs +++ b/samples/estimation/Dynamics.qs @@ -50,36 +50,39 @@ namespace QuantumDynamics { let len1 = 3; let len2 = 3; - let valLength = 2 * len1 + len2 + 1; - mutable values = [0.0, size = valLength]; + let valLength = 2*len1+len2+1; + mutable values = [0.0, size=valLength]; - let val1 = J * p * dt; - let val2 = -g * p * dt; - let val3 = J * (1.0 - 3.0 * p) * dt / 2.0; - let val4 = g * (1.0 - 4.0 * p) * dt / 2.0; + let val1 = J*p*dt; + let val2 = -g*p*dt; + let val3 = J*(1.0 - 3.0*p)*dt/2.0; + let val4 = g*(1.0 - 4.0*p)*dt/2.0; for i in 0..len1 { if (i % 2 == 0) { set values w/= i <- val1; - } else { + } + else { set values w/= i <- val2; } } - for i in len1 + 1..len1 + len2 { + for i in len1+1..len1+len2 { if (i % 2 == 0) { set values w/= i <- val3; - } else { + } + else { set values w/= i <- val4; } } - for i in len1 + len2 + 1..valLength-1 { + for i in len1+len2+1..valLength-1 { if (i % 2 == 0) { set values w/= i <- val1; - } else { + } + else { set values w/= i <- val2; } } @@ -125,8 +128,8 @@ namespace QuantumDynamics { for row in 0..r_end { for col in start..2..c_end { // Iterate through even or odd columns based on `grp` - let row2 = dir ? row + 1 | row; - let col2 = dir ? col | col + 1; + let row2 = dir ? row+1 | row; + let col2 = dir ? col | col+1; Exp(P_op, theta, [qArr[row][col], qArr[row2][col2]]); } @@ -148,10 +151,10 @@ namespace QuantumDynamics { /// operation IsingModel2DSim(N1 : Int, N2 : Int, J : Double, g : Double, totTime : Double, dt : Double) : Unit { - use qs = Qubit[N1 * N2]; + use qs = Qubit[N1*N2]; let qubitArray = Chunks(N2, qs); // qubits are re-arranged to be in an N1 x N2 array - let p = 1.0 / (4.0 - 4.0 ^ (1.0 / 3.0)); + let p = 1.0 / (4.0 - 4.0^(1.0 / 3.0)); let t = Ceiling(totTime / dt); let seqLen = 10 * t + 1; @@ -159,7 +162,7 @@ namespace QuantumDynamics { let angSeq = SetAngleSequence(p, dt, J, g); for i in 0..seqLen - 1 { - let theta = (i == 0 or i == seqLen-1) ? J * p * dt / 2.0 | angSeq[i % 10]; + let theta = (i==0 or i==seqLen-1) ? J*p*dt/2.0 | angSeq[i%10]; // for even indexes if i % 2 == 0 { diff --git a/samples/estimation/EkeraHastadFactoring.qs b/samples/estimation/EkeraHastadFactoring.qs index adf63a4f36..248c7529f8 100644 --- a/samples/estimation/EkeraHastadFactoring.qs +++ b/samples/estimation/EkeraHastadFactoring.qs @@ -71,14 +71,10 @@ namespace Microsoft.Quantum.Applications.Cryptography { // ------------------------------ // /// Window size for exponentiation (c_exp) - internal function ExponentWindowLength_() : Int { - 5 - } + internal function ExponentWindowLength_() : Int { 5 } /// Window size for multiplication (c_mul) - internal function MultiplicationWindowLength_() : Int { - 5 - } + internal function MultiplicationWindowLength_() : Int { 5 } // ------------------------------- // // Modular arithmetic (operations) // @@ -188,11 +184,11 @@ namespace Microsoft.Quantum.Applications.Cryptography { } internal function LookupData(factor : BigInt, expLength : Int, mulLength : Int, base : BigInt, mod : BigInt, sign : Int, numBits : Int) : Bool[][] { - mutable data = [[false, size = numBits], size = 2 ^ (expLength + mulLength)]; - for b in 0..2 ^ mulLength - 1 { - for a in 0..2 ^ expLength - 1 { - let idx = b * 2 ^ expLength + a; - let value = ModulusL(factor * IntAsBigInt(b) * IntAsBigInt(sign) * (base ^ a), mod); + mutable data = [[false, size = numBits], size = 2^(expLength + mulLength)]; + for b in 0..2^mulLength - 1 { + for a in 0..2^expLength - 1 { + let idx = b * 2^expLength + a; + let value = ModulusL(factor * IntAsBigInt(b) * IntAsBigInt(sign) * (base^a), mod); set data w/= idx <- BigIntAsBoolArray(value, numBits); } } diff --git a/samples/estimation/ShorRE.qs b/samples/estimation/ShorRE.qs index 3426539c5c..4f3939ca69 100644 --- a/samples/estimation/ShorRE.qs +++ b/samples/estimation/ShorRE.qs @@ -23,7 +23,7 @@ namespace Shors { // When chooseing parameters for `EstimateFrequency`, make sure that // generator and modules are not co-prime - let _ = EstimateFrequency(11, 2 ^ bitsize - 1, bitsize); + let _ = EstimateFrequency(11, 2^bitsize - 1, bitsize); } /// # Summary @@ -50,7 +50,7 @@ namespace Shors { ) : Int { mutable frequencyEstimate = 0; - let bitsPrecision = 2 * bitsize + 1; + let bitsPrecision = 2 * bitsize + 1; // Allocate qubits for the superposition of eigenstates of // the oracle that is used in period finding. diff --git a/samples/estimation/df-chemistry/src/df_chemistry.qs b/samples/estimation/df-chemistry/src/df_chemistry.qs index d03fd1b9eb..25e2e31220 100644 --- a/samples/estimation/df-chemistry/src/df_chemistry.qs +++ b/samples/estimation/df-chemistry/src/df_chemistry.qs @@ -20,28 +20,28 @@ namespace Microsoft.Quantum.Applications.Chemistry { /// # Reference /// arXiv:2007.14460, p. 9, eq. 9 newtype DoubleFactorizedChemistryProblem = ( - // Number of orbitals (N, p. 8) - NumOrbitals : Int, - // one-body norm (ǁL⁽⁻¹⁾ǁ, p. 8, eq. 16) - OneBodyNorm : Double, - // one-body norm (¼∑ǁL⁽ʳ⁾ǁ², p. 8, eq. 16) - TwoBodyNorm : Double, - // eigenvalues in the EVD of the one-electron Hamiltonian (λₖ, p. 54, eq. 67) - OneBodyEigenValues : Double[], - // eigenvectors in the EVD of the one-electron Hamiltonian (Rₖ, p. 54, eq. 67) - OneBodyEigenVectors : Double[][], - // norms inside Λ_SH (p. 56, eq. 77) - Lambdas : Double[], - // eigenvalues in the EVDs of the two-electron Hamiltonian for all r (λₖ⁽ʳ⁾, p. 56, eq. 77) - TwoBodyEigenValues : Double[][], - // eigenvectors in the EVDs of the two-electron Hamiltonian for all r (R⁽ʳ⁾ₖ, p. 56, eq. 77) - TwoBodyEigenVectors : Double[][][], + // Number of orbitals (N, p. 8) + NumOrbitals: Int, + // one-body norm (ǁL⁽⁻¹⁾ǁ, p. 8, eq. 16) + OneBodyNorm: Double, + // one-body norm (¼∑ǁL⁽ʳ⁾ǁ², p. 8, eq. 16) + TwoBodyNorm: Double, + // eigenvalues in the EVD of the one-electron Hamiltonian (λₖ, p. 54, eq. 67) + OneBodyEigenValues: Double[], + // eigenvectors in the EVD of the one-electron Hamiltonian (Rₖ, p. 54, eq. 67) + OneBodyEigenVectors: Double[][], + // norms inside Λ_SH (p. 56, eq. 77) + Lambdas: Double[], + // eigenvalues in the EVDs of the two-electron Hamiltonian for all r (λₖ⁽ʳ⁾, p. 56, eq. 77) + TwoBodyEigenValues: Double[][], + // eigenvectors in the EVDs of the two-electron Hamiltonian for all r (R⁽ʳ⁾ₖ, p. 56, eq. 77) + TwoBodyEigenVectors: Double[][][], ); newtype DoubleFactorizedChemistryParameters = ( - // Standard deviation (ΔE, p. 8, eq. 1) - // Typically set to 0.001 - StandardDeviation : Double, + // Standard deviation (ΔE, p. 8, eq. 1) + // Typically set to 0.001 + StandardDeviation: Double, ); /// # Summary @@ -50,7 +50,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { /// gradient technique (p. 55) operation DoubleFactorizedChemistry( problem : DoubleFactorizedChemistryProblem, - parameters : DoubleFactorizedChemistryParameters + parameters: DoubleFactorizedChemistryParameters ) : Unit { let constants = ComputeConstants(problem, parameters); @@ -86,9 +86,9 @@ namespace Microsoft.Quantum.Applications.Chemistry { /// electron operators, which are computed from the double factorized /// problem and parameters. internal newtype DoubleFactorizedChemistryConstants = ( - RotationAngleBitPrecision : Int, - StatePreparationBitPrecision : Int, - TargetError : Double + RotationAngleBitPrecision: Int, + StatePreparationBitPrecision: Int, + TargetError: Double ); internal function ComputeConstants( @@ -104,7 +104,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { + Lg(Sqrt((IntAsDouble((problem::NumOrbitals - 1) * 8) * PI() * norm) / parameters::StandardDeviation)) + 0.5 * Lg(1.0 / barEpsilon)); let StatePreparationBitPrecision = Ceiling(Lg(1.0 / epsilon) + 2.5); - let TargetError = 2.0 ^ IntAsDouble(1 - StatePreparationBitPrecision); + let TargetError = 2.0^IntAsDouble(1 - StatePreparationBitPrecision); DoubleFactorizedChemistryConstants( RotationAngleBitPrecision, @@ -114,8 +114,8 @@ namespace Microsoft.Quantum.Applications.Chemistry { } internal newtype WalkStep = ( - NGarbageQubits : Int, - StepOp : (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit + NGarbageQubits: Int, + StepOp: (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit ); /// # Summary @@ -150,9 +150,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { within { PrepareSingleQubit(problem::OneBodyNorm, problem::TwoBodyNorm, ctl); } apply { - within { - X(ctl); - } apply { + within { X(ctl); } apply { Controlled oneElectronOperator::Apply([ctl], (register0, register1, phaseGradientRegister, [], helperParts[0])); } Controlled twoElectronOperator::Apply([ctl], (register0, register1, phaseGradientRegister, helperParts[1])); @@ -163,8 +161,8 @@ namespace Microsoft.Quantum.Applications.Chemistry { } internal newtype OneElectronOperator = ( - NGarbageQubits : Int, - Apply : (Qubit[], Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl + NGarbageQubits: Int, + Apply: (Qubit[], Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl ); /// # Summary @@ -237,8 +235,8 @@ namespace Microsoft.Quantum.Applications.Chemistry { } internal newtype TwoElectronOperator = ( - NGarbageQubits : Int, - Apply : (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Ctl + NGarbageQubits: Int, + Apply: (Qubit[], Qubit[], Qubit[], Qubit[]) => Unit is Ctl ); /// # Summary @@ -332,7 +330,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { mutable bitstrings = []; let tau = 2.0 * PI(); - let preFactor = 2.0 ^ IntAsDouble(precision); + let preFactor = 2.0^IntAsDouble(precision); for eigenVector in eigenVectors { // Computes rotation angles for Majorana operator ($\vec u$ in p. 52, eq. 55) @@ -343,7 +341,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { // We apply MinD, such that rounding errors do not lead to // an argument for ArcCos which is larger than 1.0. (p. 52, eq. 56) let theta = sins == 0.0 ? 0.0 | 0.5 * ArcCos(MinD(eigenVector[index] / sins, 1.0)); - + // all angles as bit string let factor = theta / tau; set result += Reversed(IntAsBoolArray(IsNaN(factor) ? 0 | Floor(preFactor * factor), precision)); diff --git a/samples/estimation/df-chemistry/src/prepare.qs b/samples/estimation/df-chemistry/src/prepare.qs index cec4aff024..f06edf9fd6 100644 --- a/samples/estimation/df-chemistry/src/prepare.qs +++ b/samples/estimation/df-chemistry/src/prepare.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { operation PrepareUniformSuperposition(numStates : Int, qs : Qubit[]) : Unit is Adj + Ctl { Fact(numStates >= 1, "numStates must be positive"); - Fact(numStates <= 2 ^ Length(qs), $"numStates must be smaller or equal to {2 ^ Length(qs)}"); + Fact(numStates <= 2^Length(qs), $"numStates must be smaller or equal to {2^Length(qs)}"); let qsAdjusted = qs[...Ceiling(Lg(IntAsDouble(numStates))) - 1]; @@ -52,10 +52,10 @@ namespace Microsoft.Quantum.Applications.Chemistry { } newtype PrepareArbitrarySuperposition = ( - NIndexQubits : Int, - NGarbageQubits : Int, - Prepare : (Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl, - PrepareWithSelect : ((Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl + NIndexQubits: Int, + NGarbageQubits: Int, + Prepare: (Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl, + PrepareWithSelect: ((Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl ); function MakePrepareArbitrarySuperposition(targetError : Double, coefficients : Double[]) @@ -72,7 +72,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { return PrepareArbitrarySuperposition(nIndexQubits, nGarbageQubits, op, opWithSelect); } - function MakePrepareArbitrarySuperpositionWithData(targetError : Double, coefficients : Double[], data : Bool[][]) : PrepareArbitrarySuperposition { + function MakePrepareArbitrarySuperpositionWithData(targetError : Double, coefficients : Double[], data: Bool[][]) : PrepareArbitrarySuperposition { let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; let positiveCoefficients = Mapped(AbsD, coefficients); let (keepCoeff, altIndex) = DiscretizedProbabilityDistribution(nBitsPrecision, positiveCoefficients); @@ -106,7 +106,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { Fact(targetError > 0.0, "targetError must be positive"); Fact(nCoefficients > 0, "nCoefficients must be positive"); - let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; + let nBitsPrecision = -Ceiling(Lg(0.5*targetError)) + 1; let nIndexQubits = Ceiling(Lg(IntAsDouble(nCoefficients))); let nGarbageQubits = nIndexQubits + 2 * nBitsPrecision + 1; (nIndexQubits, nGarbageQubits) @@ -114,7 +114,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { // Computes discretized probability distribution as described in Section 3 // and Fig. 13 in [arXiv:1805.03662](https://arxiv.org/pdf/1805.03662.pdf) - internal function DiscretizedProbabilityDistribution(bitsPrecision : Int, coefficients : Double[]) + internal function DiscretizedProbabilityDistribution(bitsPrecision: Int, coefficients: Double[]) : (Int[], Int[]) { let oneNorm = PNorm(1.0, coefficients); let nCoefficients = Length(coefficients); @@ -135,7 +135,7 @@ namespace Microsoft.Quantum.Applications.Chemistry { // Uniformly distribute excess bars across coefficients. for idx in 0..AbsI(bars) - 1 { - set keepCoeff w/= idx <- keepCoeff[idx] + (bars > 0 ? -1 | + 1); + set keepCoeff w/= idx <- keepCoeff[idx] + (bars > 0 ? -1 | +1); } mutable barSink = []; @@ -178,10 +178,10 @@ namespace Microsoft.Quantum.Applications.Chemistry { // Used in QuantumROM implementation. internal operation PrepareQuantumROMState( - nBitsPrecision : Int, nCoeffs : Int, nBitsIndices : Int, - keepCoeff : Int[], altIndex : Int[], data : Bool[][], - selectOperation : (Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, - indexRegister : Qubit[], dataQubits : Qubit[], garbageRegister : Qubit[] + nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, + keepCoeff: Int[], altIndex: Int[], data : Bool[][], + selectOperation: (Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, + indexRegister: Qubit[], dataQubits : Qubit[], garbageRegister: Qubit[] ) : Unit is Adj + Ctl { let garbageIdx0 = nBitsIndices; diff --git a/samples/language/Comments.qs b/samples/language/Comments.qs index e8fe1d47d1..8ad7505fca 100644 --- a/samples/language/Comments.qs +++ b/samples/language/Comments.qs @@ -3,13 +3,13 @@ /// /// # Description /// Comments begin with two forward slashes (`//`) and continue until the -/// end of line. Comments may appear anywhere in the source code. +/// end of line. Comments may appear anywhere in the source code. /// Q# does not currently support block comments. /// Documentation comments, or doc comments, are denoted with three /// forward slashes (`///`) instead of two. namespace MyQuantumApp { open Microsoft.Quantum.Diagnostics; - + /// This is a doc-comment for the `Main` operation. @EntryPoint() operation Main() : Result[] { diff --git a/samples/language/ConditionalBranching.qs b/samples/language/ConditionalBranching.qs index 10950223ba..dd63bb8f6e 100644 --- a/samples/language/ConditionalBranching.qs +++ b/samples/language/ConditionalBranching.qs @@ -13,15 +13,11 @@ namespace MyQuantumApp { let number = 5; // Conditionally messages "Fizz" if the `number`, in this case 5, is divisible by 3. // Since 5 is not divisible by 3, the message "Fizz" will not be printed. - if number % 3 == 0 { - Message("Fizz"); - } + if number % 3 == 0 { Message("Fizz"); } // Conditionally messages "Buzz" if the `number`, in this case 5, is divisible by 5. // Since 5 is divisible by 5, the message "Buzz" will be printed. - if number % 5 == 0 { - Message("Buzz"); - } + if number % 5 == 0 { Message("Buzz"); } let fahrenheit = 40; @@ -40,10 +36,6 @@ namespace MyQuantumApp { let fahrenheit = 40; // `if` can also be used as an expression, to conditionally return a value. - let absoluteValue = if fahrenheit > 0 { - fahrenheit - } else { - fahrenheit * -1 - }; + let absoluteValue = if fahrenheit > 0 { fahrenheit } else { fahrenheit * -1 }; } } \ No newline at end of file diff --git a/samples/language/EntryPoint.qs b/samples/language/EntryPoint.qs index 4be7b7900f..6aed799f25 100644 --- a/samples/language/EntryPoint.qs +++ b/samples/language/EntryPoint.qs @@ -3,7 +3,7 @@ /// /// # Description /// The `@EntryPoint()` attribute is used to designate a particular operation as -/// the entry point of a Q# program rather than requiring entry points to have +/// the entry point of a Q# program rather than requiring entry points to have // a particular name such as `main`, `Main`, or `__main__`. namespace MyQuantumApp { diff --git a/samples/language/ForLoops.qs b/samples/language/ForLoops.qs index 4c40d886d6..98c679ec3a 100644 --- a/samples/language/ForLoops.qs +++ b/samples/language/ForLoops.qs @@ -10,13 +10,13 @@ namespace MyQuantumApp { @EntryPoint() operation Main() : Unit { // For loop over `Range` - for i in 0..5 {} + for i in 0..5 { } // For loop over `Array` - for element in [10, 11, 12] {} + for element in [10, 11, 12] { } // For loop over array slice let array = [1.0, 2.0, 3.0, 4.0]; - for element in array[2...] {} + for element in array[2...] { } } } diff --git a/samples/language/LambdaExpression.qs b/samples/language/LambdaExpression.qs index 26e9c64672..a873e2d13b 100644 --- a/samples/language/LambdaExpression.qs +++ b/samples/language/LambdaExpression.qs @@ -30,6 +30,6 @@ namespace MyQuantumApp { // `Map` takes a callable and applies it to all elements in // an array let incremented = Mapped(x -> x + 1, intArray); - + } } \ No newline at end of file diff --git a/samples/language/MultiFileProject/src/Main.qs b/samples/language/MultiFileProject/src/Main.qs index eaf598229c..0f30c50484 100644 --- a/samples/language/MultiFileProject/src/Main.qs +++ b/samples/language/MultiFileProject/src/Main.qs @@ -2,18 +2,18 @@ /// Multi File Project /// /// # Description -/// Organizing code into multiple Q# source files is an important part of +/// Organizing code into multiple Q# source files is an important part of /// writing readable and maintainable code. In this project, we have `Main.qs`, /// and `Particle.qs`, which defines a new namespace for particle operations. /// The presence of a Q# manifest file (`qsharp.json`) tells the compiler /// to include all Q# files under `src/`. namespace MyQuantumApp { - open Particle; - @EntryPoint() - operation Main() : Unit { - let particleA = Particle(0, 0, 0); - let particleB = Particle(1, 1, 1); + open Particle; + @EntryPoint() + operation Main() : Unit { + let particleA = Particle(0, 0, 0); + let particleB = Particle(1, 1, 1); - let particleC = addParticles(particleA, particleB); - } + let particleC = addParticles(particleA, particleB); + } } diff --git a/samples/language/MultiFileProject/src/Particle.qs b/samples/language/MultiFileProject/src/Particle.qs index 8f6947174b..bbe73ef961 100644 --- a/samples/language/MultiFileProject/src/Particle.qs +++ b/samples/language/MultiFileProject/src/Particle.qs @@ -1,9 +1,9 @@ namespace Particle { - newtype Particle = (x : Int, y : Int, z : Int); + newtype Particle = (x: Int, y: Int, z: Int); - function addParticles(a : Particle, b : Particle) : Particle { - let (x1, y1, z1) = a!; - let (x2, y2, z2) = b!; - return Particle(x1 + x2, y1 + y2, z1 + z2); - } + function addParticles(a: Particle, b: Particle) : Particle { + let (x1, y1, z1) = a!; + let (x2, y2, z2) = b!; + return Particle(x1 + x2, y1 + y2, z1 + z2); + } } diff --git a/samples/language/Namespaces.qs b/samples/language/Namespaces.qs index bdf0579d4c..d80dcd66df 100644 --- a/samples/language/Namespaces.qs +++ b/samples/language/Namespaces.qs @@ -10,7 +10,7 @@ namespace MyQuantumApp { // The following `open` directive is used to import all types and callables declared in the // Microsoft.Quantum.Diagnostics namespace. open Microsoft.Quantum.Diagnostics; - + @EntryPoint() operation Main() : Result[] { // `DumpMachine` is in the Microsoft.Quantum.Diagnostics namespace diff --git a/samples/language/Operations.qs b/samples/language/Operations.qs index 3a8b423e2a..29840f8f9f 100644 --- a/samples/language/Operations.qs +++ b/samples/language/Operations.qs @@ -1,19 +1,19 @@ /// # Sample -/// Operations +/// Operations /// /// # Description /// Operations are the basic building blocks of a Q# program. A Q# /// operation is a quantum subroutine. That is, it's a callable routine /// that contains quantum operations that modify the state of qubits. namespace MyQuantumApp { - + @EntryPoint() operation MeasureOneQubit() : Result { - // Allocate a qubit, by default it is in zero state - use q = Qubit(); + // Allocate a qubit, by default it is in zero state + use q = Qubit(); // We apply a Hadamard operation H to the state - // It now has a 50% chance of being measured 0 or 1 - H(q); + // It now has a 50% chance of being measured 0 or 1 + H(q); // Now we measure the qubit in Z-basis using the `M` operation. let result = M(q); // We reset the qubit before releasing it using the `Reset` operation. diff --git a/samples/language/Pauli.qs b/samples/language/Pauli.qs index a7ee59fe12..60a1c09d99 100644 --- a/samples/language/Pauli.qs +++ b/samples/language/Pauli.qs @@ -8,10 +8,10 @@ namespace MyQuantumApp { @EntryPoint() operation Main() : Result { use q = Qubit(); - + // A `Pauli` can be declared as a literal. let pauliDimension = PauliX; - + // Measuring along a dimension returns a `Result`: let result = Measure([pauliDimension], [q]); diff --git a/samples/language/QuantumMemory.qs b/samples/language/QuantumMemory.qs index 163d907ebc..044b273160 100644 --- a/samples/language/QuantumMemory.qs +++ b/samples/language/QuantumMemory.qs @@ -4,7 +4,7 @@ /// # Description /// The primary quantum feature of Q# is its representation of qubits and qubit /// memory. Q# supports allocation of qubits, and differentiates between allocating -/// "clean" qubits and "dirty" qubits with the `use` and `borrow` keywords. +/// "clean" qubits and "dirty" qubits with the `use` and `borrow` keywords. /// Clean qubits are unentangled, whereas dirty qubits are in an unknown state /// and can potentially be entangled. namespace MyQuantumApp { diff --git a/samples/language/Qubit.qs b/samples/language/Qubit.qs index db3afcb2ce..854ac60349 100644 --- a/samples/language/Qubit.qs +++ b/samples/language/Qubit.qs @@ -2,13 +2,13 @@ /// Qubit /// /// # Description -/// Q# uses the `Qubit` primitive type to represent quantum state. A qubit represents +/// Q# uses the `Qubit` primitive type to represent quantum state. A qubit represents /// the smallest addressable physical unit in a quantum computer. Qubits are long-lived, /// and accumulates transformations to quantum states. A Q# program has no ability to /// introspect into the state of a qubit, and thus is entirely agnostic about what a /// quantum state is or on how it is realized. Rather, a program can call operations /// such as Measure to learn information about the quantum state of the computation. -namespace MyQuantumApp { +namespace MyQuantumApp { open Microsoft.Quantum.Diagnostics; /// In the below code, all varibles have type annotations to showcase their type. @EntryPoint() diff --git a/samples/language/Range.qs b/samples/language/Range.qs index 086b1d646a..edf568f9bb 100644 --- a/samples/language/Range.qs +++ b/samples/language/Range.qs @@ -38,7 +38,7 @@ namespace MyQuantumApp { // The array [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]. mutable array = []; for i in 0..10 { - set array += [i ^ 2]; + set array += [i^2]; } // Ranges can be used to create array slices. diff --git a/samples/language/Result.qs b/samples/language/Result.qs index bc31df74cb..97435f8637 100644 --- a/samples/language/Result.qs +++ b/samples/language/Result.qs @@ -22,7 +22,7 @@ namespace MyQuantumApp { // Measure the qubit. let measurement = M(q); - + // Reset the qubit. Reset(q); diff --git a/samples/language/ReturnStatement.qs b/samples/language/ReturnStatement.qs index 1ae6d924c3..07505706d5 100644 --- a/samples/language/ReturnStatement.qs +++ b/samples/language/ReturnStatement.qs @@ -3,7 +3,7 @@ /// /// # Description /// Return statements are a form of control flow statement that abort the current callable and -/// return control flow to the callee's scope with a given value. +/// return control flow to the callee's scope with a given value. namespace MyQuantumApp { @EntryPoint() operation Main() : Unit { diff --git a/samples/language/Specializations.qs b/samples/language/Specializations.qs index 811be920fa..6fd2016cc8 100644 --- a/samples/language/Specializations.qs +++ b/samples/language/Specializations.qs @@ -5,7 +5,7 @@ /// Q# allows specialized implementations. Operations in Q# can implicitly /// or explicitly define adjoint and/or controlled versions. /// Q# employs symbolic computation that can automatically generate the -/// corresponding adjoint and controlled implementations for a particular +/// corresponding adjoint and controlled implementations for a particular /// body implementation. namespace MyQuantumApp { @@ -13,19 +13,19 @@ namespace MyQuantumApp { /// generated for the `DoNothing` operation that declares supports for these /// specializations using the `is` keyword followed by the union of the supported /// specializations (`Adj + Ctl`). - operation DoNothing() : Unit - is Adj + Ctl {} + operation DoNothing() : Unit + is Adj + Ctl { } - /// Here, the specializations hvae been explicitly defined. + /// Here, the specializations hvae been explicitly defined. /// In the following example, the declaration for an operation SWAP, /// which exchanges the state of two qubits q1 and q2, declares an /// explicit specialization for its adjoint version and its controlled /// version. While the implementations for Adjoint SWAP and Controlled - /// SWAP are thus user-defined, the compiler still needs to generate + /// SWAP are thus user-defined, the compiler still needs to generate /// the implementation for the combination of both functors (Controlled /// Adjoint SWAP, which is the same as Adjoint Controlled SWAP). - operation SWAP(q1 : Qubit, q2 : Qubit) : Unit - is Adj + Ctl { + operation SWAP (q1 : Qubit, q2 : Qubit) : Unit + is Adj + Ctl { body (...) { CNOT(q1, q2); @@ -33,22 +33,22 @@ namespace MyQuantumApp { CNOT(q1, q2); } - adjoint (...) { + adjoint (...) { SWAP(q1, q2); } - controlled (cs, ...) { + controlled (cs, ...) { CNOT(q1, q2); Controlled CNOT(cs, (q2, q1)); - CNOT(q1, q2); - } + CNOT(q1, q2); + } } - /// The main function cannot be Adj or Ctl. + /// The main function cannot be Adj or Ctl. @EntryPoint() operation Main() : Unit { - // We invoke specializations using functors at the call site. + // We invoke specializations using functors at the call site. // In order to call these operations and their specializations, we need // to allocate some qubits. use (q1, q2) = (Qubit(), Qubit()); @@ -60,12 +60,12 @@ namespace MyQuantumApp { // We use the functor `Adjoint` on the operation `SWAP` to invoke the // adjoint specialization of `SWAP`. Adjoint SWAP(q1, q2); - + // Now,we will use the `Controlled` functor. To use this functor, we - // need some control qubits. + // need some control qubits. // The `Controlled` functor invokes the control specialization of the - // operation. Note that the control specialization has a different + // operation. Note that the control specialization has a different // signature than the regular operation: first, the control qubits; // second, the parameters for the regular operation. // For a singly controlled invocation, only pass one control qubit diff --git a/samples/language/Unit.qs b/samples/language/Unit.qs index 80b2b22a8b..3a144aebfa 100644 --- a/samples/language/Unit.qs +++ b/samples/language/Unit.qs @@ -4,7 +4,7 @@ /// # Description /// The `Unit` type is the singleton type whose only value is (). /// Functions implicitly return `Unit` if no explicit or implicit -/// return is specified. +/// return is specified. namespace MyQuantumApp { @EntryPoint() From 9bdb9503d4f88c573b27ad7c14d107296ef20ec2 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 13:16:47 -0700 Subject: [PATCH 71/74] fixed eval test --- compiler/qsc_eval/src/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/qsc_eval/src/tests.rs b/compiler/qsc_eval/src/tests.rs index c98cbf45b1..17fcf1a4cd 100644 --- a/compiler/qsc_eval/src/tests.rs +++ b/compiler/qsc_eval/src/tests.rs @@ -348,16 +348,16 @@ fn block_qubit_use_array_invalid_count_expr() { 0, ), span: Span { - lo: 1566, - hi: 1623, + lo: 1568, + hi: 1625, }, }, ), [ Frame { span: Span { - lo: 1571, - hi: 1623, + lo: 1573, + hi: 1625, }, id: StoreItemId { package: PackageId( From 57aff3a2d71a69bc09c19a84b4061f92a17740ac Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 13:20:22 -0700 Subject: [PATCH 72/74] Q# settings tweaks. --- vscode/package.json | 2 +- vscode/src/config.ts | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/vscode/package.json b/vscode/package.json index aaadf137ba..1793877251 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -112,7 +112,7 @@ "Q#.enableFormatting": { "type": "boolean", "default": "true", - "description": "Enables the Q# formatter to be used to format code." + "description": "Enables the Q# formatter." } } }, diff --git a/vscode/src/config.ts b/vscode/src/config.ts index 7990f99eed..5bfcd9f398 100644 --- a/vscode/src/config.ts +++ b/vscode/src/config.ts @@ -32,12 +32,3 @@ export function getEnableFormating(): boolean { .getConfiguration("Q#") .get("enableFormatting", true); } - -export async function setEnableFormating(isEnabled: boolean) { - const config = vscode.workspace.getConfiguration("Q#"); - await config.update( - "enableFormatting", - isEnabled, - vscode.ConfigurationTarget.Global, - ); -} From decba41fc2ba92a03b4326c17303e4fe5c91652b Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 13:33:10 -0700 Subject: [PATCH 73/74] revert change to debug test --- vscode/test/suites/debugger/debugger.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode/test/suites/debugger/debugger.test.ts b/vscode/test/suites/debugger/debugger.test.ts index a12c7ddb64..2a832845b6 100644 --- a/vscode/test/suites/debugger/debugger.test.ts +++ b/vscode/test/suites/debugger/debugger.test.ts @@ -375,10 +375,10 @@ suite("Q# Debugger Tests", function suite() { sourceReference: 0, adapterData: "qsharp-adapter-data", }, - line: 159, + line: 165, column: 13, name: "H ", - endLine: 159, + endLine: 165, endColumn: 44, }, { From af8d6d4acd97013fbf1d74ca40a40f8fc0225c07 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 18 Mar 2024 23:06:02 -0700 Subject: [PATCH 74/74] telemetry in no-edits format --- vscode/src/extension.ts | 18 +++++++++--------- vscode/src/format.ts | 14 +++++++++++++- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts index a73f20e4e9..5b02432a40 100644 --- a/vscode/src/extension.ts +++ b/vscode/src/extension.ts @@ -184,12 +184,12 @@ async function activateLanguageService(extensionUri: vscode.Uri) { // format document const isFormattingEnabled = getEnableFormating(); - const formatterEvent = { - event: undefined as vscode.Disposable | undefined, + const formatterHandle = { + handle: undefined as vscode.Disposable | undefined, }; log.debug("Enable formatting set to: " + isFormattingEnabled); if (isFormattingEnabled) { - formatterEvent.event = + formatterHandle.handle = vscode.languages.registerDocumentFormattingEditProvider( qsharpLanguageId, createFormatProvider(languageService), @@ -198,7 +198,7 @@ async function activateLanguageService(extensionUri: vscode.Uri) { // synchronize configuration subscriptions.push( - registerConfigurationChangeHandlers(languageService, formatterEvent), + registerConfigurationChangeHandlers(languageService, formatterHandle), ); // completions @@ -285,18 +285,18 @@ async function updateLanguageServiceProfile(languageService: ILanguageService) { async function updateLanguageServiceEnableFormatting( languageService: ILanguageService, - formatterEvent: any, + formatterHandle: any, ) { const isFormattingEnabled = getEnableFormating(); log.debug("Enable formatting set to: " + isFormattingEnabled); if (isFormattingEnabled) { - formatterEvent.event = + formatterHandle.handle = vscode.languages.registerDocumentFormattingEditProvider( qsharpLanguageId, createFormatProvider(languageService), ); } else { - formatterEvent.event?.dispose(); + formatterHandle.handle?.dispose(); } } @@ -322,13 +322,13 @@ async function loadLanguageService(baseUri: vscode.Uri) { function registerConfigurationChangeHandlers( languageService: ILanguageService, - formatterEvent: any, + formatterHandle: any, ) { return vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration("Q#.targetProfile")) { updateLanguageServiceProfile(languageService); } else if (event.affectsConfiguration("Q#.enableFormatting")) { - updateLanguageServiceEnableFormatting(languageService, formatterEvent); + updateLanguageServiceEnableFormatting(languageService, formatterHandle); } }); } diff --git a/vscode/src/format.ts b/vscode/src/format.ts index 12beba8682..c6b7935382 100644 --- a/vscode/src/format.ts +++ b/vscode/src/format.ts @@ -24,7 +24,19 @@ class QSharpFormatProvider implements vscode.DocumentFormattingEditProvider { document.uri.toString(), ); - if (!lsEdits) return []; + if (!lsEdits) { + // telemetry end format + sendTelemetryEvent( + EventType.FormatEnd, + { associationId }, + { + timeToCompleteMs: performance.now() - start, + numberOfEdits: 0, + }, + ); + return []; + } + const edits = lsEdits.map( (edit) => new vscode.TextEdit(toVscodeRange(edit.range), edit.newText), );