Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
4 changes: 2 additions & 2 deletions src/QsCompiler/CommandLineTool/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ private static NonNullable<string> SNIPPET_FILE_ID
/// <summary>
/// name of the namespace within which code snippets are compiled
/// </summary>
private const string SNIPPET_NAMESPACE = "_CODE_SNIPPET_NS_";
private const string SNIPPET_NAMESPACE = "CODE_SNIPPET_NS";

/// <summary>
/// name of the callable within which code snippets are compiled
/// </summary>
private const string SNIPPET_CALLABLE = "_CODE_SNIPPET_CALLABLE_";
private const string SNIPPET_CALLABLE = "CODE_SNIPPET_CALLABLE";

/// <summary>
/// wraps the given content into a namespace and callable that maps Unit to Unit
Expand Down
10 changes: 8 additions & 2 deletions src/QsCompiler/DataStructures/Diagnostics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ type ErrorCode =
| InvalidConstructorExpression = 3030
| InvalidKeywordWithinExpression = 3032
| InvalidUseOfReservedKeyword = 3033
| ExcessContinuation = 3034
| NonCallExprAsStatement = 3035
| InvalidUseOfUnderscorePattern = 3034
| ExcessContinuation = 3035
| NonCallExprAsStatement = 3036

| InvalidExpression = 3101
| MissingExpression = 3102
Expand Down Expand Up @@ -320,6 +321,8 @@ type WarningCode =
| DeprecatedNOToperator = 3301
| DeprecatedANDoperator = 3302
| DeprecatedORoperator = 3303
| UseOfFutureReservedKeyword = 3304
| UseOfUnderscorePattern = 3305
| DeprecatedRUSloopInFunction = 4001

| DiscardingItemInAssignment = 5001
Expand Down Expand Up @@ -428,6 +431,7 @@ type DiagnosticItem =
| ErrorCode.InvalidConstructorExpression -> "Syntax error in constructor expression."
| ErrorCode.InvalidKeywordWithinExpression -> "Invalid use of a reserved keyword within an expression."
| ErrorCode.InvalidUseOfReservedKeyword -> "The symbol is reserved for internal use only."
| ErrorCode.InvalidUseOfUnderscorePattern -> "Double underscores as well as underscores before a dot or at the end of a namespace name are reserved for internal use only."
| ErrorCode.ExcessContinuation -> "Unexpected code fragment."
| ErrorCode.NonCallExprAsStatement -> "An expression used as a statement must be a call expression."

Expand Down Expand Up @@ -712,6 +716,8 @@ type DiagnosticItem =
| WarningCode.DeprecatedNOToperator -> "Deprecated syntax. Use \"not\" to denote the logical NOT operator."
| WarningCode.DeprecatedANDoperator -> "Deprecated syntax. Use \"and\" to denote the logical AND operator."
| WarningCode.DeprecatedORoperator -> "Deprecated syntax. Use \"or\" to denote the logical OR operator."
| WarningCode.UseOfFutureReservedKeyword -> "The symbol will be reserved for internal use in the future."
| WarningCode.UseOfUnderscorePattern -> "Double underscores as well as underscores before a dot or at the end of a namespace name will be reserved for internal use in the future."
| WarningCode.DeprecatedRUSloopInFunction -> "The use of repeat-until-success-loops within functions may not be supported in the future. Please use a while-loop instead."

| WarningCode.DiscardingItemInAssignment -> "The expression on the right hand side is discarded on assignment and can be omitted."
Expand Down
4 changes: 2 additions & 2 deletions src/QsCompiler/DataStructures/ReservedKeywords.fs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ module InternalUse =
"Borrow"
"Return"

"Data"
"Item"
"Data" // REL0920: can be removed once we give errors for underscore patterns
Comment thread
bettinaheim marked this conversation as resolved.
"Item" // REL0920: can be removed once we give errors for underscore patterns

"QVoid"
"Int64"
Expand Down
24 changes: 12 additions & 12 deletions src/QsCompiler/Tests.Compiler/CommandLineTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ let ``generate docs`` () =
let ``find path relative`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha","beta","c","test-path.qs")
let options = new BuildCompilation.BuildOptions()
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (Path.GetFullPath "alpha","beta","c","test-path.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -252,7 +252,7 @@ let ``find path relative to outputfolder`` () =
let fullPath = Path.Combine(Path.GetFullPath "alpha","beta","c","test-path.qs")
let options = new BuildCompilation.BuildOptions()
options.OutputFolder <- Path.Combine (pathRoot,"foo","bar")
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (pathRoot, "foo", "bar", "alpha", "beta", "c", "test-path.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -262,7 +262,7 @@ let ``find path relative to relative outputfolder`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha","beta","c","test-path.qs")
let options = new BuildCompilation.BuildOptions()
options.OutputFolder <- Path.Combine("..","foo","bar")
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (parentDir,"foo","bar","alpha","beta","c","test-path.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -272,7 +272,7 @@ let ``find path absolute`` () =
let fileName = Path.Combine (pathRoot,"alpha","beta","c","test-path.qs")
let fullPath = Path.GetFullPath fileName
let options = new BuildCompilation.BuildOptions()
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.GetFullPath "test-path.g.cs"
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -282,7 +282,7 @@ let ``find path absolute to outputfolder`` () =
let fullPath = Path.Combine (pathRoot, "alpha","beta","c","test-path.qs")
let options = new BuildCompilation.BuildOptions()
options.OutputFolder <- Path.Combine (pathRoot, "foo","bar")
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (pathRoot, "foo","bar", "test-path.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -291,7 +291,7 @@ let ``find path absolute to outputfolder`` () =
let ``find path relative to here`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha","beta","c","test-path.qs")
let options = new BuildCompilation.BuildOptions()
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (Path.GetFullPath "alpha","beta","c","test-path.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -300,7 +300,7 @@ let ``find path relative to here`` () =
let ``find path relative with spaces`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha", "some beta", "c", "test 00.qs")
let options = new BuildCompilation.BuildOptions()
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (Path.GetFullPath "alpha","some beta","c","test 00.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -310,7 +310,7 @@ let ``find path relative to outputfolder with spaces`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha","some beta","c","test 00.qs")
let options = new BuildCompilation.BuildOptions()
options.OutputFolder <- Path.Combine (pathRoot, "foo", "some bar")
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.GetFullPath (Path.Combine (pathRoot, "foo","some bar","alpha","some beta","c","test 00.g.cs"))
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -320,7 +320,7 @@ let ``find path relative to relative outputfolder with spaces`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha","some beta","c","test 00.qs")
let options = new BuildCompilation.BuildOptions()
options.OutputFolder <- Path.Combine ("..","some foo","bar")
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (parentDir,"some foo","bar","alpha","some beta","c","test 00.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -329,7 +329,7 @@ let ``find path relative to relative outputfolder with spaces`` () =
let ``find path absolute with spaces`` () =
let fullPath = Path.Combine (pathRoot, "alpha","some beta","c","test 02.qs")
let options = new BuildCompilation.BuildOptions()
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.GetFullPath "test 02.g.cs"
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -339,7 +339,7 @@ let ``find path absolute to outputfolder with spaces`` () =
let fullPath = Path.Combine (pathRoot, "alpha", "some beta", "c", "test 02.qs")
let options = new BuildCompilation.BuildOptions()
options.OutputFolder <- Path.Combine(pathRoot, "foo", "some bar")
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
let expected = Path.Combine (pathRoot, "foo", "some bar", "test 02.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
Expand All @@ -348,7 +348,7 @@ let ``find path absolute to outputfolder with spaces`` () =
let ``find path relative to here with spaces`` () =
let fullPath = Path.Combine (Path.GetFullPath "alpha","some beta","c","test 03.qs")
let options = new BuildCompilation.BuildOptions()
let id = CompilationUnitManager.TryGetFileId (new Uri(fullPath)) |> snd
let id = CompilationUnitManager.GetFileId (new Uri(fullPath))
Comment thread
bettinaheim marked this conversation as resolved.
let expected = Path.Combine (Path.GetFullPath "alpha","some beta","c","test 03.g.cs")
let actual = CompilationLoader.GeneratedFile(id, options.OutputFolder, ".g.cs")
Assert.Equal(expected, actual)
54 changes: 52 additions & 2 deletions src/QsCompiler/Tests.Compiler/SyntaxTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open Microsoft.Quantum.QsCompiler.DataTypes
open Microsoft.Quantum.QsCompiler.Diagnostics
open Microsoft.Quantum.QsCompiler.SyntaxTokens
open Microsoft.Quantum.QsCompiler.TextProcessing.ExpressionParsing
open Microsoft.Quantum.QsCompiler.TextProcessing.CodeFragments
open Microsoft.Quantum.QsCompiler.TextProcessing.SyntaxBuilder
open System
open System.Collections.Immutable
Expand All @@ -17,7 +18,57 @@ open Xunit

let private rawString = getStringContent (manyChars anyChar) |>> fst

// Component parsers

[<Fact>]
let ``Reserved patterns`` () =
[
("_mySymbol" , true , Some "_mySymbol" , [])
("mySymbol_" , true , Some "mySymbol_" , [])
("my_symbol" , true , Some "my_symbol" , [])
("my__symbol", true , Some "my__symbol", [Warning WarningCode.UseOfUnderscorePattern])
("__mySymbol", true , Some "__mySymbol", [Warning WarningCode.UseOfUnderscorePattern])
("mySymbol__", true , Some "mySymbol__", [Warning WarningCode.UseOfUnderscorePattern])
("__my__sym" , true , Some "__my__sym" , [Warning WarningCode.UseOfUnderscorePattern])
("my__sym__" , true , Some "my__sym__" , [Warning WarningCode.UseOfUnderscorePattern])
("__mysym__" , true , None , [Error ErrorCode.InvalidUseOfReservedKeyword])
]
|> List.iter (testOne (symbolNameLike ErrorCode.InvalidIdentifierName))
[
("a.b" , true , ([Some "a" ], Some "b" ), [])
("_a.b" , true , ([Some "_a" ], Some "b" ), [])
("a_.b" , true , ([Some "a_" ], Some "b" ), [Warning WarningCode.UseOfUnderscorePattern])
("a._b" , true , ([Some "a" ], Some "_b" ), [])
("a.b_" , true , ([Some "a" ], Some "b_" ), [])
("_a.b_" , true , ([Some "_a" ], Some "b_" ), [])
("a_._b" , true , ([Some "a_" ], Some "_b" ), [Warning WarningCode.UseOfUnderscorePattern])
("__a.b" , true , ([Some "__a" ], Some "b" ), [Warning WarningCode.UseOfUnderscorePattern])
("a__a.b" , true , ([Some "a__a"], Some "b" ), [Warning WarningCode.UseOfUnderscorePattern])
("a__.b" , true , ([Some "a__" ], Some "b" ), [Warning WarningCode.UseOfUnderscorePattern])
("a.__b" , true , ([Some "a" ], Some "__b" ), [Warning WarningCode.UseOfUnderscorePattern])
("a.b__b" , true , ([Some "a" ], Some "b__b"), [Warning WarningCode.UseOfUnderscorePattern])
("a.b__" , true , ([Some "a" ], Some "b__" ), [Warning WarningCode.UseOfUnderscorePattern])
("__a.b__", true , ([Some "__a" ], Some "b__" ), [Warning WarningCode.UseOfUnderscorePattern; Warning WarningCode.UseOfUnderscorePattern])
]
|> List.iter (testOne (multiSegmentSymbol ErrorCode.InvalidIdentifierName |>> fst))
[
("a.b" , true , Some "a.b" , [])
("_a.b" , true , Some "_a.b" , [])
("a_.b" , true , Some "a_.b" , [Warning WarningCode.UseOfUnderscorePattern])
("a._b" , true , Some "a._b" , [])
("a.b_" , true , Some "a.b_" , [Warning WarningCode.UseOfUnderscorePattern])
("_a.b_" , true , Some "_a.b_" , [Warning WarningCode.UseOfUnderscorePattern])
("a_._b" , true , Some "a_._b" , [Warning WarningCode.UseOfUnderscorePattern])
("__a.b" , true , Some "__a.b" , [Warning WarningCode.UseOfUnderscorePattern])
("a__a.b" , true , Some "a__a.b" , [Warning WarningCode.UseOfUnderscorePattern])
("a__.b" , true , Some "a__.b" , [Warning WarningCode.UseOfUnderscorePattern])
("a.__b" , true , Some "a.__b" , [Warning WarningCode.UseOfUnderscorePattern])
("a.b__b" , true , Some "a.b__b" , [Warning WarningCode.UseOfUnderscorePattern])
("a.b__" , true , Some "a.b__" , [Warning WarningCode.UseOfUnderscorePattern])
("__a.b__", true , Some "__a.b__", [Warning WarningCode.UseOfUnderscorePattern; Warning WarningCode.UseOfUnderscorePattern])
]
|> List.iter (testOne (namespaceName |>> fst))


[<Fact>]
let ``String parser tests`` () =
[
Expand Down Expand Up @@ -141,7 +192,6 @@ let ``Symbol name tests`` () =
("_a", true, "_a", []);
("_", false, "", []);
("__", false, "", []);
("__a", true, "__a", []);
("функция25", true, "функция25", []); // Russian word 'function' followed by '25'
("λ", true, "λ", []); // Greek small letter Lambda
("ℵ", true, "ℵ", []); // Hebrew capital letter Aleph
Expand Down
22 changes: 19 additions & 3 deletions src/QsCompiler/TextProcessor/QsFragmentParsing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,31 @@ let private buildSymbolTuple (items, range : Position * Position) =
let private expectedIdentifierDeclaration continuation =
expected localIdentifier ErrorCode.InvalidIdentifierDeclaration ErrorCode.MissingIdentifierDeclaration invalidSymbol continuation

/// Uses multiSegmentSymbol to parse the name of a namespace,
/// concatenates all path segments and the symbol with a dot, and returns a the concatenated string as Some.
/// Returns None if the path contains segments that are None (i.e. invalid).
/// Generates a suitable diagnostic if the namespace name ends in an underscore.
let internal namespaceName = // internal for testing purposes
let asNamespaceName ((path, sym : string option), range : Position * Position) =
let names = path @ [sym]
let namespaceStr = names |> List.choose id |> String.concat "."
if names |> List.contains None then (None, range) |> preturn
elif sym.Value.EndsWith "_" && not (namespaceStr.Contains "__" || namespaceStr.Contains "_.") then // REL0920: remove the second half and return None for pattern errors
buildWarning (preturn range) WarningCode.UseOfUnderscorePattern >>% (Some namespaceStr, range)
else (Some namespaceStr, range) |> preturn
multiSegmentSymbol ErrorCode.InvalidPathSegment >>= asNamespaceName

/// Given a continuation (parser), attempts to parse a qualified QsSymbol
/// using multiSegmentSymbol to generate suitable errors for invalid symbol and/or path names,
/// and returns the parsed symbol, or a QsSymbol representing an invalid symbol (parsing failure) if the parsing fails.
/// On failure, either raises an MissingQualifiedSymbol if the given continuation succeeds at the current position,
/// or raises an InvalidQualifiedSymbol and advances until the given continuation succeeds otherwise.
/// Does not apply the given continuation.
let private expectedNamespaceName continuation =
let path = multiSegmentSymbol ErrorCode.InvalidPathSegment |>> asSymbol
expected path ErrorCode.InvalidQualifiedSymbol ErrorCode.MissingQualifiedSymbol invalidSymbol continuation
let private expectedNamespaceName continuation =
let namespaceName = namespaceName |>> function
| None, _ -> (InvalidSymbol, Null) |> QsSymbol.New
| Some name, range -> (name |> NonNullable<string>.New |> Symbol, range) |> QsSymbol.New
expected namespaceName ErrorCode.InvalidQualifiedSymbol ErrorCode.MissingQualifiedSymbol invalidSymbol continuation

/// Parses the condition e.g. for if, elif and until clauses.
/// Uses optTupleBrackets to raise the corresponding missing bracket errors if the condition is not within tuple brackets.
Expand Down
Loading