Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Conversation

@theRoughCode
Copy link

This PR implements the skeleton for the VS Code formatter. We have 2 basic rules for now:

  1. Strip away any whitespace to the left of namespace. For example,
    namespace Microsoft.Quantum {} -> namespace Microsoft.Quantum {}.
  2. Format operation definitions. For example:
    operation Foo(q:Qubit, n :Int) : Bool -> operation Foo (q : Qubit, n : Int) : Bool

@theRoughCode theRoughCode requested a review from swernli July 27, 2020 21:31
@theRoughCode theRoughCode self-assigned this Jul 27, 2020
@theRoughCode
Copy link
Author

cc: @amrondonp, @swosti99

Copy link
Contributor

@swernli swernli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments and questions, but overall I think this is a great start! Exciting to see the progress!

* `operation Foo (q : Qubit, n : Int) : Bool`
*/
const argsRule = (code: string): string => {
const operationMatcher: RegExp = /operation\s*(\w+)\s*\((.*)\)\s*:\s*(\w+)/g;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Turns out that functions follow the same spacing rules, so you could have the same argsRule implementation for them. Maybe that means later all of this except the literal operation could be moved to a standard utility and both operation-rules.ts and a future function-rules.ts could refer to it? Alternatively, operation-rules.ts could be renamed to be more general and have both operation and function related rules in them, since they are almost identical.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's a generic umbrella term for operations and functions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question, and I don't think there really is one. But if the intent of the file is for checking operation and function declarations, maybe a decent name would be declaration-rules.ts? Then it could also handle user-defined type declarations (newtype as documented here). That file name change can be made in following PRs, no need to gate this PR on the name change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, we've generally used "callable" to mean "function or operation."

@swernli
Copy link
Contributor

swernli commented Jul 28, 2020

Apologies for the delay on the review; I thought I had hit submit but had it sitting open in a browser instead. Great work so far!

@swernli
Copy link
Contributor

swernli commented Jul 28, 2020

Looks like there was a failure in the testing of the VSCode extension. Is it possible something in these changes is showing up as a unit test when it shouldn't?
https://dev.azure.com/ms-quantum-public/Microsoft%20Quantum%20(public)/_build/results?buildId=12399&view=logs&j=aa540828-7369-5cca-9a86-6547727f16ff&t=5c10f11e-357e-5f9b-e70d-e2e6470f089e&l=1055

@swernli swernli self-requested a review July 28, 2020 02:00
@swernli
Copy link
Contributor

swernli commented Jul 28, 2020

Actually, looks like quite a few commits were added between my original review and now. I'm going to take a look back through the files again. Thanks for adding testing!

describe("space after if rule", () => {
it("adds space after if statement", () => {
const code = "if(1 == 1){H(qs[0]);}";
const expectedCode = "if (1 == 1){H(qs[0]);}";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these test cases will need to be updated once other rules are implemented (such as requiring a space before and after open curly brace, ie if (1 == 1) { H(qs[0]); }. But that's ok to leave this as-is for now and expect those updates to be done by later rule authors.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

@amrondonp amrondonp Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention of this rule is only to handle the space after the if statement, We obviously need integration tests that test several rules at once but this specific rule only is concerned about the spacing after the if

Copy link
Contributor

@swernli swernli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to make some build script changes to ensure these tests run as expected (and only when expected) in the pipeline.

@theRoughCode theRoughCode requested a review from swernli July 28, 2020 15:28
@swernli swernli merged commit cbbd929 into feature/qslint-hackathon Jul 28, 2020
const formattedLines: vscode.TextEdit[] = lines
.map((line) => {
const formattedLine: string = formatter(line.text, rules);
return formattedLine !== line.text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this constrain all formatting rules to work one line at a time?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. I'm not sure how to match the whole document at once. Will definitely have to change this to handle multi-line matching.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could just go lines.join(""); counldn't we?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be a bit more involved than that. We need to return vscode.TextEdit[] instead of just the final formatted string.

* more examples in the unit tests
*/
export const spaceAfterIf: FormatRule = (code: string): string => {
return code.replace(/(^| +|;|})if[ \n]*/, "$1if ");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the * operator could make the regex match on zero instances of [ \n], such that variable names starting with if could be affected. Do you want + here to match [1, ∞) copies of [ \n]?

Suggested change
return code.replace(/(^| +|;|})if[ \n]*/, "$1if ");
return code.replace(/(^| +|;|})if[ \n]+/, "$1if ");

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also want to match none in the case of if(...) -> if (...). I would suggest the following

Suggested change
return code.replace(/(^| +|;|})if[ \n]*/, "$1if ");
return code.replace(/(^| +|;|})if[ |\n]*\(/, "$1if ");

cc: @amrondonp who wrote this

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, @theRoughCode thanks!

* `namespace Foo {}`
*/
export const namespaceRule: FormatRule = (code: string) => {
const namespaceMatcher: RegExp = /^\s*namespace\s*(\w+)\s*(\S|\S.*\S)\s*$/g;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does \w+ catch dotted names like Microsoft.Quantum.Arrays?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. What do you think of this:

/^\s*namespace\s+(\w+(?:\.\w+)*)\s*({|{.*})\s*/$

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make a test for every edge case you encounter

@@ -0,0 +1,98 @@
import "mocha";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest a unit test to ensure that if occuring in the beginning, middle, or end of an identifier name doesn't get replaced.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, Will do

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants