From 617d5658da140205698287fff4b2bfaf96ef5ab8 Mon Sep 17 00:00:00 2001 From: filipw Date: Sat, 25 Jul 2026 17:53:14 +0200 Subject: [PATCH] 1. #comments added to type-parameter-list, parameter-list, parameter, both udt-declaration initializer branches, struct-field, import-export-directive, open-directive, tuple-pattern. 2. #keywords added to #expression. end widened to (?=;|\)|}) for local-declaration, array-assignment, local-assignment, quantum-declaration --- grammars/qsharp.tmLanguage | 52 ++++++- grammars/qsharp.tmLanguage.json | 19 ++- src/qsharp.tmLanguage.yml | 19 ++- test/comment.contexts.tests.ts | 183 ++++++++++++++++++++++++ test/keywords.expression.tests.ts | 222 ++++++++++++++++++++++++++++++ 5 files changed, 483 insertions(+), 12 deletions(-) create mode 100644 test/comment.contexts.tests.ts create mode 100644 test/keywords.expression.tests.ts diff --git a/grammars/qsharp.tmLanguage b/grammars/qsharp.tmLanguage index d6637e2..872ab0b 100644 --- a/grammars/qsharp.tmLanguage +++ b/grammars/qsharp.tmLanguage @@ -740,6 +740,10 @@ patterns + + include + #comments + match ('[_[:alpha:]][_[:alnum:]]*)\b @@ -846,6 +850,10 @@ patterns + + include + #comments + include #parameter @@ -906,6 +914,10 @@ (?=(,|\)|\])) patterns + + include + #comments + include #literals @@ -1010,6 +1022,10 @@ patterns + + include + #comments + include #literals @@ -1035,6 +1051,10 @@ (?=;) patterns + + include + #comments + include #literals @@ -1150,6 +1170,10 @@ (?=(,|\})) patterns + + include + #comments + include #type-parameter @@ -1403,6 +1427,10 @@ include #new-expression + + include + #keywords + include #strings @@ -1535,6 +1563,10 @@ (?=;)|$ patterns + + include + #comments + begin \b(as)\b\s* @@ -1550,6 +1582,10 @@ (?=(,|;)|$) patterns + + include + #comments + name entity.name.type.alias.qsharp @@ -1654,6 +1690,10 @@ (?=;) patterns + + include + #comments + begin \b(as)\s+(?<alias>[_[:alpha:]][_[:alnum:]]*) @@ -1801,7 +1841,7 @@ end - (?=;|\)) + (?=;|\)|}) patterns @@ -1886,6 +1926,10 @@ patterns + + include + #comments + include #tuple-pattern @@ -1943,7 +1987,7 @@ end - (?=;|\)) + (?=;|\)|}) patterns @@ -1979,7 +2023,7 @@ end - (?=;|\)) + (?=;|\)|}) patterns @@ -2169,7 +2213,7 @@ end - (?=;|\)) + (?=;|\)|}) patterns diff --git a/grammars/qsharp.tmLanguage.json b/grammars/qsharp.tmLanguage.json index 4bd2973..a0f00a3 100644 --- a/grammars/qsharp.tmLanguage.json +++ b/grammars/qsharp.tmLanguage.json @@ -270,6 +270,7 @@ "0": { "name": "punctuation.definition.typeparameters.end.qsharp" } }, "patterns": [ + { "include": "#comments" }, { "match": "('[_[:alpha:]][_[:alnum:]]*)\\b", "captures": { @@ -311,6 +312,7 @@ "0": { "name": "punctuation.parenthesis.close.qsharp" } }, "patterns": [ + { "include": "#comments" }, { "include": "#parameter" }, { "include": "#punctuation-comma" } ] @@ -336,6 +338,7 @@ }, "end": "(?=(,|\\)|\\]))", "patterns": [ + { "include": "#comments" }, { "include": "#literals" }, { "include": "#types" }, { "include": "#library" }, @@ -378,6 +381,7 @@ "0": { "name": "punctuation.parenthesis.close.qsharp" } }, "patterns": [ + { "include": "#comments" }, { "include": "#literals" }, { "include": "#punctuation-comma" }, { "include": "#types" }, @@ -388,6 +392,7 @@ "begin": "(?:\\s*=\\s*)", "end": "(?=;)", "patterns": [ + { "include": "#comments" }, { "include": "#literals" }, { "include": "#punctuation-comma" }, { "include": "#types" }, @@ -432,6 +437,7 @@ }, "end": "(?=(,|\\}))", "patterns": [ + { "include": "#comments" }, { "include": "#type-parameter" }, { "include": "#types" }, { "include": "#library" } @@ -514,6 +520,7 @@ { "include": "#comments" }, { "include": "#if-statement" }, { "include": "#new-expression" }, + { "include": "#keywords" }, { "include": "#strings" }, { "include": "#member-access" }, { "include": "#library-invocation" }, @@ -559,11 +566,13 @@ "beginCaptures": { "1": { "name": "keyword.other.import.qsharp" } }, "end": "(?=;)|$", "patterns": [ + { "include": "#comments" }, { "begin": "\\b(as)\\b\\s*", "beginCaptures": { "1": { "name": "keyword.other.qsharp" } }, "end": "(?=(,|;)|$)", "patterns": [ + { "include": "#comments" }, { "name": "entity.name.type.alias.qsharp", "match": "[_[:alpha:]][_[:alnum:]]*" @@ -622,6 +631,7 @@ "beginCaptures": { "1": { "name": "keyword.other.open.qsharp" } }, "end": "(?=;)", "patterns": [ + { "include": "#comments" }, { "begin": "\\b(as)\\s+(?[_[:alpha:]][_[:alnum:]]*)", "beginCaptures": { @@ -686,7 +696,7 @@ "2": { "name": "keyword.other.mutable.qsharp" }, "3": { "name": "entity.name.variable.local.qsharp" } }, - "end": "(?=;|\\))", + "end": "(?=;|\\)|})", "patterns": [{ "include": "#variable-initializer" }] }, "tuple-binding": { @@ -715,6 +725,7 @@ "0": { "name": "punctuation.parenthesis.close.qsharp" } }, "patterns": [ + { "include": "#comments" }, { "include": "#tuple-pattern" }, { "name": "entity.name.variable.local.qsharp", @@ -733,7 +744,7 @@ "5": { "name": "keyword.operator.assignment.qsharp" }, "6": { "name": "keyword.operator.assignment.qsharp" } }, - "end": "(?=;|\\))", + "end": "(?=;|\\)|})", "patterns": [ { "name": "keyword.operator.assignment.qsharp", "match": "<-" }, { "include": "#expression" } @@ -745,7 +756,7 @@ "1": { "name": "keyword.other.set.qsharp" }, "2": { "name": "entity.name.variable.local.qsharp" } }, - "end": "(?=;|\\))", + "end": "(?=;|\\)|})", "patterns": [{ "include": "#variable-initializer" }] }, "variable-initializer": { @@ -828,7 +839,7 @@ "2": { "name": "keyword.other.borrow.qsharp" }, "3": { "name": "entity.name.variable.local.qsharp" } }, - "end": "(?=;|\\))", + "end": "(?=;|\\)|})", "patterns": [{ "include": "#quantum-initializer" }] }, "quantum-initializer": { diff --git a/src/qsharp.tmLanguage.yml b/src/qsharp.tmLanguage.yml index 3176f08..555c0fd 100644 --- a/src/qsharp.tmLanguage.yml +++ b/src/qsharp.tmLanguage.yml @@ -270,6 +270,7 @@ repository: '0': name: punctuation.definition.typeparameters.end.qsharp patterns: + - include: '#comments' - match: ('[_[:alpha:]][_[:alnum:]]*)\b captures: '1': @@ -310,6 +311,7 @@ repository: '0': name: punctuation.parenthesis.close.qsharp patterns: + - include: '#comments' - include: '#parameter' - include: '#punctuation-comma' @@ -335,6 +337,7 @@ repository: name: punctuation.separator.colon.qsharp end: (?=(,|\)|\])) patterns: + - include: '#comments' - include: '#literals' - include: '#types' - include: '#library' @@ -378,6 +381,7 @@ repository: '0': name: punctuation.parenthesis.close.qsharp patterns: + - include: '#comments' - include: '#literals' - include: '#punctuation-comma' - include: '#types' @@ -385,6 +389,7 @@ repository: - begin: (?:\s*=\s*) end: (?=;) patterns: + - include: '#comments' - include: '#literals' - include: '#punctuation-comma' - include: '#types' @@ -428,6 +433,7 @@ repository: name: punctuation.separator.colon.qsharp end: (?=(,|\})) patterns: + - include: '#comments' - include: '#type-parameter' - include: '#types' - include: '#library' @@ -515,6 +521,7 @@ repository: - include: '#comments' - include: '#if-statement' - include: '#new-expression' + - include: '#keywords' - include: '#strings' - include: '#member-access' - include: '#library-invocation' @@ -567,12 +574,14 @@ repository: name: keyword.other.import.qsharp end: (?=;)|$ patterns: + - include: '#comments' - begin: \b(as)\b\s* beginCaptures: '1': name: keyword.other.qsharp end: (?=(,|;)|$) patterns: + - include: '#comments' - name: entity.name.type.alias.qsharp match: '[_[:alpha:]][_[:alnum:]]*' - name: keyword.operator.wildcard.qsharp @@ -613,6 +622,7 @@ repository: name: keyword.other.open.qsharp end: (?=;) patterns: + - include: '#comments' - begin: \b(as)\s+(?[_[:alpha:]][_[:alnum:]]*) beginCaptures: '1': @@ -669,7 +679,7 @@ repository: '1': { name: keyword.other.let.qsharp } '2': { name: keyword.other.mutable.qsharp } '3': { name: entity.name.variable.local.qsharp } - end: (?=;|\)) + end: (?=;|\)|}) patterns: - include: '#variable-initializer' @@ -707,6 +717,7 @@ repository: '0': name: punctuation.parenthesis.close.qsharp patterns: + - include: '#comments' - include: '#tuple-pattern' - name: entity.name.variable.local.qsharp match: \b[_[:alpha:]][_[:alnum:]]*\b @@ -733,7 +744,7 @@ repository: '4': { name: entity.name.variable.local.qsharp } '5': { name: keyword.operator.assignment.qsharp } '6': { name: keyword.operator.assignment.qsharp } - end: (?=;|\)) + end: (?=;|\)|}) patterns: - name: keyword.operator.assignment.qsharp match: <- @@ -748,7 +759,7 @@ repository: beginCaptures: '1': { name: keyword.other.set.qsharp } '2': { name: entity.name.variable.local.qsharp } - end: (?=;|\)) + end: (?=;|\)|}) patterns: - include: '#variable-initializer' @@ -818,7 +829,7 @@ repository: '1': { name: keyword.other.use.qsharp } '2': { name: keyword.other.borrow.qsharp } '3': { name: entity.name.variable.local.qsharp } - end: (?=;|\)) + end: (?=;|\)|}) patterns: - include: '#quantum-initializer' diff --git a/test/comment.contexts.tests.ts b/test/comment.contexts.tests.ts new file mode 100644 index 0000000..b4429fd --- /dev/null +++ b/test/comment.contexts.tests.ts @@ -0,0 +1,183 @@ +import { should } from 'chai'; +import { tokenize, createToken, Token } from './utils/tokenize'; + +// comments should be recognized in (almost) every context, not just where a +// statement is expected +describe("Comments in nested contexts", () => { + before(() => { should(); }); + + it("Comment inside a parameter list", async () => { + const tokens = await tokenize(`function Foo( + // the input + x : Int) : Unit {}`); + tokens.should.deep.equal([ + createToken("function", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Foo", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(" ", "punctuation.whitespace.comment.leading.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" the input", "comment.line.double-slash.qsharp"), + createToken(" ", "source.qsharp"), + createToken("x", "entity.name.variable.parameter.qsharp"), + createToken(" ", "source.qsharp"), + createToken(":", "punctuation.separator.colon.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Int", "storage.type.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + ]); + }); + + it("Comment between a parameter name and its type", async () => { + const tokens = await tokenize(`function Foo(x : // c + Int) : Unit {}`); + tokens.should.deep.equal([ + createToken("function", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Foo", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken("x", "entity.name.variable.parameter.qsharp"), + createToken(" ", "source.qsharp"), + createToken(":", "punctuation.separator.colon.qsharp"), + createToken(" ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Int", "storage.type.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + ]); + }); + + it("Comment inside a newtype tuple", async () => { + const tokens = await tokenize(`newtype Pair = ( + // first + Int, Int);`); + tokens.should.deep.equal([ + createToken("newtype", "keyword.other.udt.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Pair", "entity.name.type.udt.qsharp"), + createToken(" = ", "source.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(" ", "punctuation.whitespace.comment.leading.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" first", "comment.line.double-slash.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Int", "storage.type.qsharp"), + createToken(",", "punctuation.separator.comma.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Int", "storage.type.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + ]); + }); + + it("Comment inside a newtype alias", async () => { + const tokens = await tokenize(`newtype Alias = // c + Int;`); + tokens.should.deep.equal([ + createToken("newtype", "keyword.other.udt.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Alias", "entity.name.type.udt.qsharp"), + createToken(" = ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Int", "storage.type.qsharp"), + createToken(";", "source.qsharp"), + ]); + }); + + it("Comment between a struct field name and its type", async () => { + const tokens = await tokenize(`struct S { Field : // c + Int }`); + tokens.should.deep.equal([ + createToken("struct", "keyword.other.struct.qsharp"), + createToken(" ", "source.qsharp"), + createToken("S", "entity.name.type.struct.qsharp"), + createToken(" ", "source.qsharp"), + createToken("{", "punctuation.curlybrace.open.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Field", "variable.other.property.qsharp"), + createToken(" ", "source.qsharp"), + createToken(":", "punctuation.separator.colon.qsharp"), + createToken(" ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Int", "storage.type.qsharp"), + createToken(" ", "source.qsharp"), + createToken("}", "punctuation.curlybrace.close.qsharp"), + ]); + }); + + it("Comment inside an import directive", async () => { + const tokens = await tokenize(`import Foo // c`); + tokens.should.deep.equal([ + createToken("import", "keyword.other.import.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Foo", "entity.name.namespace.qsharp"), + createToken(" ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + ]); + }); + + it("Comment after an import alias keyword", async () => { + const tokens = await tokenize(`import Std.Math as // c`); + tokens.should.deep.equal([ + createToken("import", "keyword.other.import.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Std", "entity.name.namespace.qsharp"), + createToken(".", "punctuation.accessor.qsharp"), + createToken("Math", "entity.name.namespace.qsharp"), + createToken(" ", "source.qsharp"), + createToken("as", "keyword.other.qsharp"), + createToken(" ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + ]); + }); + + it("Comment inside an open directive", async () => { + const tokens = await tokenize(`namespace A { + open // c +}`); + tokens.should.deep.equal([ + createToken("namespace", "keyword.other.namespace.qsharp"), + createToken(" ", "source.qsharp"), + createToken("A", "entity.name.type.namespace.qsharp"), + createToken(" ", "source.qsharp"), + createToken("{", "punctuation.curlybrace.open.qsharp"), + createToken(" ", "source.qsharp"), + createToken("open", "keyword.other.open.qsharp"), + createToken(" ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + ]); + }); + + it("Comment inside a tuple binding pattern", async () => { + const tokens = await tokenize(`let (a, // c + b) = pair;`); + tokens.should.deep.equal([ + createToken("let", "keyword.other.let.qsharp"), + createToken(" ", "source.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken("a", "entity.name.variable.local.qsharp"), + createToken(",", "punctuation.separator.comma.qsharp"), + createToken(" ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" c", "comment.line.double-slash.qsharp"), + createToken(" ", "source.qsharp"), + createToken("b", "entity.name.variable.local.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("pair", "variable.other.readwrite.qsharp"), + ]); + }); +}); diff --git a/test/keywords.expression.tests.ts b/test/keywords.expression.tests.ts new file mode 100644 index 0000000..c356a1f --- /dev/null +++ b/test/keywords.expression.tests.ts @@ -0,0 +1,222 @@ +import { should } from 'chai'; +import { tokenize, createToken, Token } from './utils/tokenize'; + +// keywords should be recognized inside expression contexts too, not only where +// a statement is expected +describe("Keywords in expression contexts", () => { + before(() => { should(); }); + + it("within/apply in a lambda body", async () => { + const tokens = await tokenize(`let op = q => within { H(q); } apply { X(q); };`); + tokens.should.deep.equal([ + createToken("let", "keyword.other.let.qsharp"), + createToken(" ", "source.qsharp"), + createToken("op", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("q", "variable.other.readwrite.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=>", "keyword.operator.lambda.qsharp"), + createToken(" ", "source.qsharp"), + createToken("within", "keyword.control.qsharp"), + createToken(" { ", "source.qsharp"), + createToken("H", "support.function.quantum.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken("q", "variable.other.readwrite.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken("; } ", "source.qsharp"), + createToken("apply", "keyword.control.qsharp"), + createToken(" { ", "source.qsharp"), + createToken("X", "support.function.quantum.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken("q", "variable.other.readwrite.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + ]); + }); + + it("Keyword inside an argument list", async () => { + const tokens = await tokenize(`Foo(for);`); + tokens.should.deep.equal([ + createToken("Foo", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken("for", "keyword.control.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + ]); + }); + + it("Keyword-looking text inside a string is not a keyword", async () => { + const tokens = await tokenize(`let s = "return within apply";`); + tokens.should.deep.equal([ + createToken("let", "keyword.other.let.qsharp"), + createToken(" ", "source.qsharp"), + createToken("s", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken(`"`, "string.quoted.double.qsharp"), + createToken("return within apply", "string.quoted.double.qsharp"), + createToken(`"`, "string.quoted.double.qsharp"), + ]); + }); + + it("Keyword-looking text inside a comment is not a keyword", async () => { + const tokens = await tokenize(`let x = 1; // return within apply`); + tokens.should.deep.equal([ + createToken("let", "keyword.other.let.qsharp"), + createToken(" ", "source.qsharp"), + createToken("x", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("1", "constant.numeric.decimal.qsharp"), + createToken("; ", "source.qsharp"), + createToken("//", "punctuation.definition.comment.qsharp"), + createToken(" return within apply", "comment.line.double-slash.qsharp"), + ]); + }); +}); + +// An unterminated statement must not swallow the rest of the file: a closing +// curly brace ends the statement just like `;` or `)` do. +describe("Unterminated statements stop at a closing brace", () => { + before(() => { should(); }); + + it("let without a semicolon", async () => { + const tokens = await tokenize(`operation Main() : Unit { + let x = 1 +} +function Bar() : Unit {}`); + tokens.should.deep.equal([ + createToken("operation", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Main", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + createToken(" {", "source.qsharp"), + createToken(" ", "source.qsharp"), + createToken("let", "keyword.other.let.qsharp"), + createToken(" ", "source.qsharp"), + createToken("x", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("1", "constant.numeric.decimal.qsharp"), + createToken("}", "source.qsharp"), + createToken("function", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Bar", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + ]); + }); + + it("set without a semicolon", async () => { + const tokens = await tokenize(`operation Main() : Unit { + set x = 1 +} +function Bar() : Unit {}`); + tokens.should.deep.equal([ + createToken("operation", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Main", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + createToken(" {", "source.qsharp"), + createToken(" ", "source.qsharp"), + createToken("set", "keyword.other.set.qsharp"), + createToken(" ", "source.qsharp"), + createToken("x", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("1", "constant.numeric.decimal.qsharp"), + createToken("}", "source.qsharp"), + createToken("function", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Bar", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + ]); + }); + + it("use without a semicolon", async () => { + const tokens = await tokenize(`operation Main() : Unit { + use q = Qubit() +} +function Bar() : Unit {}`); + tokens.should.deep.equal([ + createToken("operation", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Main", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + createToken(" {", "source.qsharp"), + createToken(" ", "source.qsharp"), + createToken("use", "keyword.other.use.qsharp"), + createToken(" ", "source.qsharp"), + createToken("q", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Qubit", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken("}", "source.qsharp"), + createToken("function", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Bar", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + ]); + }); + + it("copy-and-update assignment without a semicolon", async () => { + const tokens = await tokenize(`operation Main() : Unit { + set ary w/= 0 <- 10 +} +function Bar() : Unit {}`); + tokens.should.deep.equal([ + createToken("operation", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Main", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + createToken(" {", "source.qsharp"), + createToken(" ", "source.qsharp"), + createToken("set", "keyword.other.set.qsharp"), + createToken(" ", "source.qsharp"), + createToken("ary", "entity.name.variable.local.qsharp"), + createToken(" ", "source.qsharp"), + createToken("w/=", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("0", "constant.numeric.decimal.qsharp"), + createToken(" ", "source.qsharp"), + createToken("<-", "keyword.operator.assignment.qsharp"), + createToken(" ", "source.qsharp"), + createToken("10", "constant.numeric.decimal.qsharp"), + createToken("}", "source.qsharp"), + createToken("function", "keyword.other.callable.qsharp"), + createToken(" ", "source.qsharp"), + createToken("Bar", "entity.name.function.qsharp"), + createToken("(", "punctuation.parenthesis.open.qsharp"), + createToken(")", "punctuation.parenthesis.close.qsharp"), + createToken(" : ", "source.qsharp"), + createToken("Unit", "storage.type.qsharp"), + ]); + }); +});