Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,6 @@ out/

# macOS
.DS_Store

# generated copy for the grammar test extension (see build.js)
test-extension/qsharp.tmLanguage.json
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Test grammar (Extension Development Host)",
"type": "extensionHost",
"request": "launch",
"args": [
"--disable-extension=quantum.qsharp-lang-vscode",
"--extensionDevelopmentPath=${workspaceFolder}/test-extension",
"${workspaceFolder}/test-extension/sample.qs"
]
}
]
}
11 changes: 11 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ function build() {
);

console.log("Built grammars/qsharp.tmLanguage and grammars/qsharp.tmLanguage.json");

// Keep a copy inside the test extension (gitignored) so its manifest can
// reference a grammar within its own folder — VS Code warns otherwise.
const testExtDir = path.join(__dirname, "test-extension");
if (fs.existsSync(testExtDir)) {
fs.writeFileSync(
path.join(testExtDir, "qsharp.tmLanguage.json"),
JSON.stringify(grammar, null, "\t") + "\n"
);
console.log("Refreshed test-extension/qsharp.tmLanguage.json");
}
}

build();
2 changes: 1 addition & 1 deletion grammars/qsharp.tmLanguage
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@
<key>name</key>
<string>support.type.constraint.qsharp</string>
<key>match</key>
<string>\b(Eq|Add|Sub|Mul|Div|Mod|Signed|Ord|Show|Integral|Exp)\b</string>
<string>\b(Eq|Add|Sub|Mul|Div|Mod|Signed|Ord|Show|Integral|Iterable|Exp)\b</string>
</dict>
<dict>
<key>name</key>
Expand Down
2 changes: 1 addition & 1 deletion grammars/qsharp.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@
},
{
"name": "support.type.constraint.qsharp",
"match": "\\b(Eq|Add|Sub|Mul|Div|Mod|Signed|Ord|Show|Integral|Exp)\\b"
"match": "\\b(Eq|Add|Sub|Mul|Div|Mod|Signed|Ord|Show|Integral|Iterable|Exp)\\b"
},
{
"name": "punctuation.squarebracket.open.qsharp",
Expand Down
2 changes: 1 addition & 1 deletion src/qsharp.tmLanguage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ repository:
- name: keyword.operator.qsharp
match: \+
- name: support.type.constraint.qsharp
match: \b(Eq|Add|Sub|Mul|Div|Mod|Signed|Ord|Show|Integral|Exp)\b
match: \b(Eq|Add|Sub|Mul|Div|Mod|Signed|Ord|Show|Integral|Iterable|Exp)\b
- name: punctuation.squarebracket.open.qsharp
match: \[
- name: punctuation.squarebracket.close.qsharp
Expand Down
38 changes: 38 additions & 0 deletions test-extension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Grammar test extension

A throwaway VS Code extension used to manually test the Q# TextMate grammar in a
real editor, isolated from the QDK extension (no language server, so no semantic
highlighting paints over the grammar).

It contributes the `qsharp` language for `.qs` files. Its grammar
(`qsharp.tmLanguage.json`) is generated into this folder by `npm run build`
(gitignored) so the manifest can reference a file inside its own folder — VS Code
warns about grammar paths that escape the extension directory.

## Usage

1. Build the grammar so `grammars/qsharp.tmLanguage.json` is current:

```bash
npm run build
```

2. Open the **repository root** in VS Code and press **F5** (the
`Test grammar (Extension Development Host)` launch config). This opens an
Extension Development Host with the official QDK extension disabled and
[`sample.qs`](./sample.qs) loaded.

3. Verify tokenization with **`Developer: Inspect Editor Tokens and Scopes`**
(Command Palette) — hover a token to see its `source.qsharp` scopes. This is
the authoritative check; colors are just the active theme's scope mapping.

4. After editing `src/qsharp.tmLanguage.yml`, re-run `npm run build` and reload
the host window (`Cmd/Ctrl+R`) to pick up the new grammar.

## Notes

- The launch config disables `quantum.qsharp-lang-vscode` only inside the
development host — your normal editor is untouched.
- If you prefer not to use F5, symlink this folder into your extensions dir
(`ln -s "$PWD/test-extension" ~/.vscode/extensions/qsharp-tmlanguage-test`),
disable the QDK extension, and reload.
22 changes: 22 additions & 0 deletions test-extension/language-configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"comments": {
"lineComment": "//"
},
"brackets": [
["[", "]"],
["(", ")"],
["{", "}"]
],
"autoClosingPairs": [
["[", "]"],
["(", ")"],
["{", "}"],
{ "open": "\"", "close": "\"", "notIn": ["string"] }
],
"surroundingPairs": [
["[", "]"],
["(", ")"],
["{", "}"],
["\"", "\""]
]
}
28 changes: 28 additions & 0 deletions test-extension/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "qsharp-tmlanguage-test-extension",
"displayName": "Q# TextMate grammar (dev)",
"description": "Loads the locally-built Q# grammar for manual testing in an Extension Development Host.",
"publisher": "local",
"version": "0.0.0",
"private": true,
"engines": {
"vscode": "^1.75.0"
},
"contributes": {
"languages": [
{
"id": "qsharp",
"aliases": ["Q#", "qsharp"],
"extensions": [".qs"],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "qsharp",
"scopeName": "source.qsharp",
"path": "./qsharp.tmLanguage.json"
}
]
}
}
63 changes: 63 additions & 0 deletions test-extension/sample.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Std.Diagnostics.*;
import Std.Math.PI as Pi;

/// A doc comment describing a struct.
struct Complex { Re : Double, Im : Double }

@EntryPoint()
operation Main() : Result[] {
// literals: decimal, hex, binary, octal, BigInt, float, separators
let ints = [42, 0xFF, 0b1010, 0o52, 1_000];
let big = 42L;
let approx = 1.0e-3;

// qubit allocation (single + tuple), gates, measurement, reset
use qs = Qubit[3];
use (control, target) = (Qubit(), Qubit());
for i in 0..Length(qs) - 1 {
H(qs[i]);
}
Controlled X([control], target);
Rx(Pi() / 4.0, target);

// structs: construction, copy-and-update, field access
let c = new Complex { Re = 1.0, Im = 0.0 };
let c2 = new Complex { ...c, Im = 2.0 };
let magnitudeSquared = c2.Re * c2.Re + c2.Im * c2.Im;

// operators: comparison, bitwise, ternary, ranges
let flags = (5 &&& 3) ||| (1 <<< 2);
let sign = magnitudeSquared > 0.0 ? One | Zero;
let slice = ints[1..2];

// lambdas, partial application, string interpolation
let addOne = x -> x + 1;
let applyX = q => X(q);
Message($"c2 = {c2.Re} + {c2.Im}i, sign = {sign}");

// control flow: if / elif / else, within-apply, mutation without `set`
mutable counter = 0;
counter += 1;
if counter == 1 {
Message("one");
} elif counter == 2 {
Message("two");
} else {
Message("many");
}

within {
H(qs[0]);
} apply {
Z(qs[0]);
}

ResetAll(qs);
return MeasureEachZ(qs);
}

function Sum2<'T : Add>(a : 'T, b : 'T) : 'T {
a + b
}

export Main, Sum2, Complex;
Loading