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
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [20.x, 22.x]

steps:
- uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm

- name: Install dependencies
run: npm ci

- name: Build grammar
run: npm run build

- name: Verify committed grammars are in sync with the source
run: |
if ! git diff --exit-code -- grammars/; then
echo "::error::grammars/ is out of date. Run 'npm run build' and commit the result."
exit 1
fi

- name: Run tests
run: npm test
36 changes: 36 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: npm

- name: Install dependencies
run: npm ci

- name: Build grammar
run: npm run build

- name: Run tests
run: npm test

- name: Attach grammar to the release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.release.tag_name }}
run: gh release upload "$TAG" grammars/qsharp.tmLanguage.json --clobber
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,6 @@ dist
# TernJS port file
.tern-port
out/

# macOS
.DS_Store
5 changes: 5 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require": "ts-node/register",
"spec": "test/**/*.tests.ts",
"timeout": 10000
}
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,32 @@ This repository contains the TextMate grammar for Q#. The grammar provides token

[![CoC](https://img.shields.io/badge/code%20of%20conduct-contributor%20covenant-yellow)](CODE_OF_CONDUCT.md)

## Language coverage

The grammar tracks modern Q# (QDK 1.x) and covers, among other things:

* File-scoped namespaces, `import` / `export` directives (with `*` wildcards and `as` aliases), and the legacy `namespace { }` / `open` forms
* `struct` declarations, `new` struct instantiation, copy-and-update (`...spread`) and member access (`point.X`)
* Attributes (`@EntryPoint()`, `@Test()`, `@Config(...)`, ...)
* Operation/function declarations with type parameters and class constraints (`<'T : Eq + Add>`, `Exp['T]`), plus the functors `is Adj + Ctl`
* Lambdas (`->`, `=>`), partial application, ternary (`cond ? a | b`), and the full operator set (arithmetic, comparison, logical, bitwise `&&& ||| ^^^ ~~~ <<< >>>`, ranges `..`/`...`, copy-update `w/ ... <-`)
* Numeric literals in decimal, hex (`0xFF`), binary (`0b1010`), octal (`0o52`), `BigInt` (`42L`), exponent (`1.0e-3`) and digit-separator (`1_000`) forms
* Interpolated strings (`$"...{expr}..."`) with tokenized expression holes
* Intrinsic quantum operations highlighted as quantum operations while still tokenizing their arguments

The behaviour is pinned by an extensive unit-test suite; the tests can additionally be run against a checkout of the official [`microsoft/qdk`](https://github.com/microsoft/qdk) samples by pointing the `QDK_SAMPLES` environment variable at its `samples/` directory.

## Build and Development

To contribute, clone the repo and run (requires Node.js and `npm` to be installed on the dev machine)

* `npm install` to install all dependencies
* Run `npm run compile` to build and run tests
* Run `npm run test` to run only tests
* Run `npm run build` to regenerate the grammar outputs from the YAML source
* Run `npm test` to build the grammar and run the unit tests

The source grammar is located at `src/qsharp.tmLanguage.yml` and is the core file to be maintained.
The build (`build.js`) converts it into the two output files below; the tests tokenize
Q# snippets with `vscode-textmate` and assert on the resulting scopes.

## Output

Expand Down
36 changes: 36 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Builds the Q# TextMate grammar outputs from the YAML source.
//
// src/qsharp.tmLanguage.yml -> grammars/qsharp.tmLanguage (plist)
// -> grammars/qsharp.tmLanguage.json (JSON)
//
// The YAML file is the single source of truth and the only file that should be
// edited by hand. Run with `npm run build`.

const fs = require("fs");
const path = require("path");
const jsYaml = require("js-yaml");
const plist = require("plist");

const srcFile = path.join(__dirname, "src", "qsharp.tmLanguage.yml");
const grammarsDir = path.join(__dirname, "grammars");

function build() {
const text = fs.readFileSync(srcFile, "utf8");
const grammar = jsYaml.load(text);

fs.mkdirSync(grammarsDir, { recursive: true });

fs.writeFileSync(
path.join(grammarsDir, "qsharp.tmLanguage.json"),
JSON.stringify(grammar, null, "\t") + "\n"
);

fs.writeFileSync(
path.join(grammarsDir, "qsharp.tmLanguage"),
plist.build(grammar)
);

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

build();
Loading
Loading