From 09992284461f2797db91f2301574978d30f9141a Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Mon, 13 Aug 2018 23:54:03 +0300 Subject: [PATCH 1/9] Fix lexing of preprocessor directive --- src/fsharp/LexFilter.fs | 7 +++++++ src/fsharp/lex.fsl | 8 ++++++++ src/fsharp/pars.fsy | 1 + src/fsharp/service/ServiceLexing.fs | 0 4 files changed, 16 insertions(+) mode change 100755 => 100644 src/fsharp/service/ServiceLexing.fs diff --git a/src/fsharp/LexFilter.fs b/src/fsharp/LexFilter.fs index 956b351e9dc..d72a3dae663 100644 --- a/src/fsharp/LexFilter.fs +++ b/src/fsharp/LexFilter.fs @@ -2215,6 +2215,13 @@ type LexFilterImpl (lightStatus: LightSyntaxStatus, compilingFsLib, lexer, lexbu and rulesForBothSoftWhiteAndHardWhite(tokenTup: TokenTup) = match tokenTup.Token with + | HASH_IDENT (ident) -> + let hashPos = new LexbufState(tokenTup.StartPos, tokenTup.StartPos.ShiftColumnBy(1), false) + let identPos = new LexbufState(tokenTup.StartPos.ShiftColumnBy(1), tokenTup.EndPos, false) + delayToken(new TokenTup(IDENT(ident), identPos, tokenTup.LastTokenPos)) + delayToken(new TokenTup(HASH, hashPos, tokenTup.LastTokenPos)) + true + // Insert HIGH_PRECEDENCE_PAREN_APP if needed | IDENT _ when (nextTokenIsAdjacentLParenOrLBrack tokenTup).IsSome -> let dotTokenTup = peekNextTokenTup() diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index f5679b2f585..2de82839f5e 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -956,6 +956,14 @@ rule token args skip = parse let tok = fail args lexbuf (FSComp.SR.lexHashIfMustHaveIdent()) tok if not skip then tok else token args skip lexbuf } + | anywhite* "#if" ident_char+ + | anywhite* "#else" ident_char+ + | anywhite* "#endif" ident_char+ + | anywhite* "#light" ident_char+ + { let n = Array.IndexOf(lexbuf.Lexeme, '#') + lexbuf.StartPos <- lexbuf.StartPos.ShiftColumnBy(n) + HASH_IDENT(lexemeTrimLeft lexbuf (n+1)) } + | surrogateChar surrogateChar | _ diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index 1d757e4789d..86f48e74481 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -201,6 +201,7 @@ let rangeOfLongIdent(lid:LongIdent) = %token KEYWORD_STRING // Like __SOURCE_DIRECTORY__ %token IDENT +%token HASH_IDENT %token INFIX_STAR_STAR_OP %token INFIX_COMPARE_OP %token INFIX_AT_HAT_OP diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs old mode 100755 new mode 100644 From 4b795295fafc3d3d15ed016af5bdc89495044de7 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sat, 25 Jul 2020 20:41:04 +0200 Subject: [PATCH 2/9] Fix error msg for single use of #indent/#light --- src/fsharp/lex.fsl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl index 2de82839f5e..e1bc80085c2 100644 --- a/src/fsharp/lex.fsl +++ b/src/fsharp/lex.fsl @@ -895,8 +895,10 @@ rule token args skip = parse | "#light" anywhite* | ("#indent" | "#light") anywhite+ "\"on\"" { if args.lightStatus.ExplicitlySet && args.lightStatus.WarnOnMultipleTokens then - warning(Error((0,"#light should only occur as the first non-comment text in an F# source file"), lexbuf.LexemeRange)) - // TODO unreachable error above, I think? - brianmcn + let s = lexeme lexbuf + warning(Error((0, sprintf "%s should only be set once in an F# source file." s), lexbuf.LexemeRange)) + // TODO: where should this go? (abelb) + //warning(Error((0,"#light should only occur as the first non-comment text in an F# source file."), lexbuf.LexemeRange)) args.lightStatus.Status <- true if not skip then HASH_LIGHT (LexCont.Token(args.ifdefStack, args.stringNest)) else token args skip lexbuf } From 6cbcfcd5cebf9844b9cc94e9d1361a5f40417472 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sat, 25 Jul 2020 20:41:31 +0200 Subject: [PATCH 3/9] Add more info-output to failing test --- .../Tests.ProjectSystem.Miscellaneous.fs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs b/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs index 1f5dfff2054..3a67280a1b5 100644 --- a/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs +++ b/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs @@ -278,6 +278,7 @@ type Miscellaneous() = let buildableCfg = vsBuildableCfg :?> BuildableProjectConfig AssertEqual VSConstants.S_OK hr + let mutable isCleaning = false let success = ref false use event = new System.Threading.ManualResetEvent(false) let (hr, cookie) = @@ -286,6 +287,8 @@ type Miscellaneous() = member this.BuildBegin pfContinue = pfContinue <- 1; VSConstants.S_OK member this.BuildEnd fSuccess = success := fSuccess <> 0 + printfn "Build %s, code %i, phase: %s." (if !success then "succeeded" else "failed") fSuccess (if isCleaning then "Cleaning" else "Build") + event.Set() |> Assert.IsTrue VSConstants.S_OK member this.Tick pfContinue = pfContinue <- 1; VSConstants.S_OK @@ -301,14 +304,19 @@ type Miscellaneous() = buildableCfg.Build(0u, output, target) event.WaitOne() |> Assert.IsTrue buildMgrAccessor.EndDesignTimeBuild() |> ValidateOK // this is not a design-time build, but our mock does all the right initialization of the build manager for us, similar to what the system would do in VS for real - AssertEqual true !success - printfn "building..." - doBuild "Build" + AssertEqual true !success + + printfn "Building..." + doBuild "Build" AssertEqual true (File.Exists (Path.Combine(project.ProjectFolder, "bin\\Debug\\Blah.dll"))) + printfn "Output files present." - printfn "cleaning..." + isCleaning <- true + printfn "Cleaning..." doBuild "Clean" + printfn "Finished build-then-clean." AssertEqual false (File.Exists (Path.Combine(project.ProjectFolder, "bin\\Debug\\Blah.dll"))) + printfn "Files were cleaned." finally buildableCfg.UnadviseBuildStatusCallback(cookie) |> AssertEqual VSConstants.S_OK )) From 02d7b1899cecfea8e229ef6b5e071bdf2e2d7ab0 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Wed, 29 Jul 2020 18:33:22 +0200 Subject: [PATCH 4/9] Fix test BuildAndClean (was always wrong!) --- .../LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs b/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs index 3a67280a1b5..b390100ded5 100644 --- a/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs +++ b/vsintegration/tests/UnitTests/LegacyProjectSystem/Tests.ProjectSystem.Miscellaneous.fs @@ -266,8 +266,7 @@ type Miscellaneous() = this.MSBuildProjectBoilerplate "Library", (fun project ccn projFileName -> let fooPath = Path.Combine(project.ProjectFolder, "foo.fs") - File.AppendAllText(fooPath, "#light") - File.AppendAllText(fooPath, "module Foo") + File.AppendAllLines(fooPath, ["#light"; "module Foo"]) //ccn((project :> IVsHierarchy), "Debug|Any CPU") let configName = "Debug" From bfb1e0011149a7429b00b3df2ca3b70d75d37089 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Thu, 30 Jul 2020 01:21:35 +0200 Subject: [PATCH 5/9] Attempted fix for untestable test --- .../ConditionalCompilation/E_MustBeIdent02.fs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs index 8e204947133..9adefc41718 100644 --- a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs +++ b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs @@ -1,10 +1,9 @@ -// #Regression #Conformance #LexicalAnalysis +// #Regression #Conformance #LexicalAnalysis // Regression test for FSHARP1.0:1419 -//#if directive should be immediately followed by an identifier -//#endif has no matching #if in pattern -//Unmatched '\(' +//The type 'if_' is not defined. +//The type 'endif_' is not defined. #light let t8 (x : #if_) = () let t7 (x : #endif_) = () -exit 1 +exit 1 \ No newline at end of file From e6d4c22f8bc9fc8ec2a167e8a3ecc395c072bcad Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Mon, 3 Aug 2020 20:21:02 +0200 Subject: [PATCH 6/9] Fix ranges in test E_MustBeIdent02.fs --- .../LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs index 9adefc41718..c245d773d49 100644 --- a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs +++ b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #LexicalAnalysis // Regression test for FSHARP1.0:1419 -//The type 'if_' is not defined. -//The type 'endif_' is not defined. +//The type 'if_' is not defined. +//The type 'endif_' is not defined. #light let t8 (x : #if_) = () let t7 (x : #endif_) = () From a02b53fc18cb56d0041582965e3819c8c9505e90 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Tue, 4 Aug 2020 18:27:19 +0200 Subject: [PATCH 7/9] Fix line-no in E_MustBeIdent02.fs fsharpqa test --- .../LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs index c245d773d49..09dee4fbf57 100644 --- a/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs +++ b/tests/fsharpqa/Source/Conformance/LexicalAnalysis/ConditionalCompilation/E_MustBeIdent02.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #LexicalAnalysis // Regression test for FSHARP1.0:1419 -//The type 'if_' is not defined. -//The type 'endif_' is not defined. +//The type 'if_' is not defined. +//The type 'endif_' is not defined. #light let t8 (x : #if_) = () let t7 (x : #endif_) = () From 01e700fdcaf44e284016051c416ca0f29dee6e97 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Tue, 4 Aug 2020 20:09:34 +0200 Subject: [PATCH 8/9] Fix HashConstraint02.fs, now a type error --- .../TypeParameterDefinitions/HashConstraint02.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/TypesAndTypeConstraints/TypeParameterDefinitions/HashConstraint02.fs b/tests/fsharpqa/Source/Conformance/TypesAndTypeConstraints/TypeParameterDefinitions/HashConstraint02.fs index 24f94f08d3e..fe215d60f9e 100644 --- a/tests/fsharpqa/Source/Conformance/TypesAndTypeConstraints/TypeParameterDefinitions/HashConstraint02.fs +++ b/tests/fsharpqa/Source/Conformance/TypesAndTypeConstraints/TypeParameterDefinitions/HashConstraint02.fs @@ -1,8 +1,7 @@ // #Regression #Conformance #TypeConstraints // Regression test for FSHARP1.0:1419 // Tokens beginning with # should not match greedily with directives -// The only case where we are still a bit confused is #light: for this reason the code -// below compiles just fine (it would not work if I replace #light with #r for example) +//The type 'float' is not compatible with the type 'light_' #light type light_() = class From 5a882a88d16e8e7cefb20dc2d47b9b13f8704a27 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 9 Aug 2020 23:32:07 +0200 Subject: [PATCH 9/9] Merge ServiceLexing.fs from fix-lexing-hash-directives --- src/fsharp/service/ServiceLexing.fs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs index 20f05760f33..d98da168ef1 100644 --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -32,6 +32,7 @@ module FSharpTokenTag = let String = tagOfToken (STRING ("a", LexCont.Default)) let IDENT = tagOfToken (IDENT "a") + let HASH_IDENT = tagOfToken (HASH_IDENT "a") let STRING = String let INTERP_STRING_BEGIN_END = tagOfToken (INTERP_STRING_BEGIN_END ("a", LexCont.Default)) let INTERP_STRING_BEGIN_PART = tagOfToken (INTERP_STRING_BEGIN_PART ("a", LexCont.Default)) @@ -172,6 +173,7 @@ module internal TokenClassifications = let tokenInfo token = match token with + | HASH_IDENT s | IDENT s -> if s.Length <= 0 then System.Diagnostics.Debug.Assert(false, "BUG: Received zero length IDENT token.") @@ -773,6 +775,9 @@ type FSharpLineTokenizer(lexbuf: UnicodeLexing.Lexbuf, false, processHashEndElse m.StartColumn lineStr 4 cont | HASH_ENDIF (m, lineStr, cont) when lineStr <> "" -> false, processHashEndElse m.StartColumn lineStr 5 cont + | HASH_IDENT(ident) -> + delayToken(IDENT (ident), leftc + 1, rightc) + false, (HASH, leftc, leftc) | RQUOTE_DOT (s, raw) -> delayToken(DOT, rightc, rightc) false, (RQUOTE (s, raw), leftc, rightc - 1)