From f4c6b4b6204d73607e36a0870fc994507e5ae7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Jank=C3=B3?= Date: Tue, 17 May 2016 16:40:31 +0200 Subject: [PATCH] initial experiments and refactoring for C# analyzer --- .gitignore | 1 + WebSharper.Compiler.sln | 46 +- WebSharper.sln | 9 + msbuild/FSharp.targets | 10 +- msbuild/WebSharper.CSharp.Internal.targets | 2 +- msbuild/WebSharper.CSharp.targets | 7 +- msbuild/Zafir.CSharp.targets | 5 +- src/build/Bootstrap/Main.fs | 2 +- .../WebSharper.CSharp.Analyzer/Analyzer.fs | 129 +++ .../WebSharper.CSharp.Analyzer.fsproj | 47 ++ src/compiler/WebSharper.CSharp/Program.fs | 3 + .../WebSharper.CSharp.fsproj | 4 + .../WebSharper.Compiler.CSharp/CodeReader.fs | 788 +++++++++--------- .../WebSharper.Compiler.CSharp/Main.fs | 58 +- .../ProjectReader.fs | 85 +- .../WebSharper.Compiler.CSharp/Syntax.xml | 9 +- .../WebSharperTask.fs | 23 +- .../WebSharperTask.fsi | 15 +- tests/WebSharper.CSharp.Tests/Linq.cs | 2 +- tests/WebSharper.CSharp.Tests/Macro.cs | 18 +- tests/WebSharper.CSharp.Tests/String.cs | 4 + tests/WebSharper.CSharp.Tests/Syntax.cs | 4 +- tests/WebSharper.CSharp.Tests/Tests.cs | 73 +- .../WebSharper.CSharp.Tests.csproj | 12 + 24 files changed, 820 insertions(+), 536 deletions(-) create mode 100644 src/compiler/WebSharper.CSharp.Analyzer/Analyzer.fs create mode 100644 src/compiler/WebSharper.CSharp.Analyzer/WebSharper.CSharp.Analyzer.fsproj diff --git a/.gitignore b/.gitignore index f028c407d..cdba40ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ IntelliFactory.WebSharper.JQuery/*.js /msbuild/AssemblyInfo.extra.fs /.hg /.vs/config +/msbuild.log diff --git a/WebSharper.Compiler.sln b/WebSharper.Compiler.sln index 42616b69e..fcbbfbec9 100644 --- a/WebSharper.Compiler.sln +++ b/WebSharper.Compiler.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E8624E6F-F8E9-4295-B9E0-6D1A79BAD0D5}" EndProject @@ -26,10 +26,6 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.Core", "src\comp EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.InterfaceGenerator", "src\compiler\WebSharper.InterfaceGenerator\WebSharper.InterfaceGenerator.fsproj", "{A05B0B61-A2EF-4C88-B9A3-00E888777798}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.MSBuild", "src\compiler\WebSharper.MSBuild\WebSharper.MSBuild.fsproj", "{C713BE60-B53C-44BB-A1EB-1696894996F5}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper", "src\compiler\WebSharper\WebSharper.fsproj", "{DF5F2614-44E8-4C7D-A6E2-019D220D38C9}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{EED59312-2E8D-4332-8BA5-671F85D8E25E}" ProjectSection(SolutionItems) = preProject tools\minify.fsx = tools\minify.fsx @@ -59,12 +55,14 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.Compiler.FSharp" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.Compiler.CSharp", "src\compiler\WebSharper.Compiler.CSharp\WebSharper.Compiler.CSharp.fsproj", "{8F188E8B-547E-4A8E-BD3B-257A13AF9ACD}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.MSBuild.FSharp", "src\compiler\WebSharper.MSBuild.FSharp\WebSharper.MSBuild.FSharp.fsproj", "{3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}" -EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.FSharp", "src\compiler\WebSharper.FSharp\WebSharper.FSharp.fsproj", "{615AEA64-16EC-49BC-AFB4-36211F6354CC}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.MSBuild.CSharp", "src\compiler\WebSharper.MSBuild.CSharp\WebSharper.MSBuild.CSharp.fsproj", "{B5503FD3-638E-4E54-96FC-1AFFD780E9E9}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.CSharp.Analyzer", "src\compiler\WebSharper.CSharp.Analyzer\WebSharper.CSharp.Analyzer.fsproj", "{055CF3AD-BDAF-4441-989B-D764B80FBDEE}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.CSharp", "src\compiler\WebSharper.CSharp\WebSharper.CSharp.fsproj", "{46D8C7C3-43CA-465C-9714-20B22CF3E459}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -96,17 +94,6 @@ Global {A05B0B61-A2EF-4C88-B9A3-00E888777798}.DebugTests|Any CPU.Build.0 = Release|Any CPU {A05B0B61-A2EF-4C88-B9A3-00E888777798}.Release|Any CPU.ActiveCfg = Release|Any CPU {A05B0B61-A2EF-4C88-B9A3-00E888777798}.Release|Any CPU.Build.0 = Release|Any CPU - {C713BE60-B53C-44BB-A1EB-1696894996F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C713BE60-B53C-44BB-A1EB-1696894996F5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C713BE60-B53C-44BB-A1EB-1696894996F5}.DebugTests|Any CPU.ActiveCfg = Release|Any CPU - {C713BE60-B53C-44BB-A1EB-1696894996F5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C713BE60-B53C-44BB-A1EB-1696894996F5}.Release|Any CPU.Build.0 = Release|Any CPU - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9}.DebugTests|Any CPU.ActiveCfg = Release|Any CPU - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9}.DebugTests|Any CPU.Build.0 = Release|Any CPU - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9}.Release|Any CPU.Build.0 = Release|Any CPU {15DD08E0-9E5E-49B1-9738-D73ACA630FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {15DD08E0-9E5E-49B1-9738-D73ACA630FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU {15DD08E0-9E5E-49B1-9738-D73ACA630FF5}.DebugTests|Any CPU.ActiveCfg = Release|Any CPU @@ -131,12 +118,6 @@ Global {8F188E8B-547E-4A8E-BD3B-257A13AF9ACD}.DebugTests|Any CPU.Build.0 = Debug|Any CPU {8F188E8B-547E-4A8E-BD3B-257A13AF9ACD}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F188E8B-547E-4A8E-BD3B-257A13AF9ACD}.Release|Any CPU.Build.0 = Release|Any CPU - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}.DebugTests|Any CPU.ActiveCfg = Debug|Any CPU - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}.DebugTests|Any CPU.Build.0 = Debug|Any CPU - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA}.Release|Any CPU.Build.0 = Release|Any CPU {615AEA64-16EC-49BC-AFB4-36211F6354CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {615AEA64-16EC-49BC-AFB4-36211F6354CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {615AEA64-16EC-49BC-AFB4-36211F6354CC}.DebugTests|Any CPU.ActiveCfg = Debug|Any CPU @@ -149,6 +130,18 @@ Global {B5503FD3-638E-4E54-96FC-1AFFD780E9E9}.DebugTests|Any CPU.Build.0 = Debug|Any CPU {B5503FD3-638E-4E54-96FC-1AFFD780E9E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {B5503FD3-638E-4E54-96FC-1AFFD780E9E9}.Release|Any CPU.Build.0 = Release|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.DebugTests|Any CPU.ActiveCfg = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.DebugTests|Any CPU.Build.0 = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Release|Any CPU.Build.0 = Release|Any CPU + {46D8C7C3-43CA-465C-9714-20B22CF3E459}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46D8C7C3-43CA-465C-9714-20B22CF3E459}.Debug|Any CPU.Build.0 = Debug|Any CPU + {46D8C7C3-43CA-465C-9714-20B22CF3E459}.DebugTests|Any CPU.ActiveCfg = Debug|Any CPU + {46D8C7C3-43CA-465C-9714-20B22CF3E459}.DebugTests|Any CPU.Build.0 = Debug|Any CPU + {46D8C7C3-43CA-465C-9714-20B22CF3E459}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46D8C7C3-43CA-465C-9714-20B22CF3E459}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -159,16 +152,15 @@ Global {BFB21B61-FDA9-4814-A728-7D43038E0B57} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {52741881-8D64-4639-8B5C-19C060958C35} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {A05B0B61-A2EF-4C88-B9A3-00E888777798} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} - {C713BE60-B53C-44BB-A1EB-1696894996F5} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} - {DF5F2614-44E8-4C7D-A6E2-019D220D38C9} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {B38B1480-30AC-4F48-8AA3-C406889EC6CF} = {EED59312-2E8D-4332-8BA5-671F85D8E25E} {1ACAFCBC-6FE9-4CD6-91DF-AAE1902C9B1F} = {E8624E6F-F8E9-4295-B9E0-6D1A79BAD0D5} {15DD08E0-9E5E-49B1-9738-D73ACA630FF5} = {1ACAFCBC-6FE9-4CD6-91DF-AAE1902C9B1F} {5FB61954-9230-4408-A349-7F1EFC6E0A66} = {1ACAFCBC-6FE9-4CD6-91DF-AAE1902C9B1F} {D54EA1FD-F52F-4F07-921F-7B3D1B412CD0} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {8F188E8B-547E-4A8E-BD3B-257A13AF9ACD} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} - {3A0893DD-291A-4ACF-AADC-BC2AF7D098EA} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {615AEA64-16EC-49BC-AFB4-36211F6354CC} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {B5503FD3-638E-4E54-96FC-1AFFD780E9E9} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} + {055CF3AD-BDAF-4441-989B-D764B80FBDEE} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} + {46D8C7C3-43CA-465C-9714-20B22CF3E459} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} EndGlobalSection EndGlobal diff --git a/WebSharper.sln b/WebSharper.sln index 4b963d7a9..132ab40ba 100644 --- a/WebSharper.sln +++ b/WebSharper.sln @@ -142,6 +142,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.Sitelets.Offline EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSharper.CSharp.Sitelets.Tests", "tests\WebSharper.CSharp.Sitelets.Tests\WebSharper.CSharp.Sitelets.Tests.csproj", "{91E8E3CC-B1F5-4D27-8DAF-639CA5C76F63}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebSharper.CSharp.Analyzer", "src\compiler\WebSharper.CSharp.Analyzer\WebSharper.CSharp.Analyzer.fsproj", "{055CF3AD-BDAF-4441-989B-D764B80FBDEE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -341,6 +343,12 @@ Global {91E8E3CC-B1F5-4D27-8DAF-639CA5C76F63}.DebugTests|Any CPU.Build.0 = DebugTests|Any CPU {91E8E3CC-B1F5-4D27-8DAF-639CA5C76F63}.Release|Any CPU.ActiveCfg = Release|Any CPU {91E8E3CC-B1F5-4D27-8DAF-639CA5C76F63}.Release|Any CPU.Build.0 = Release|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.DebugTests|Any CPU.ActiveCfg = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.DebugTests|Any CPU.Build.0 = Debug|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {055CF3AD-BDAF-4441-989B-D764B80FBDEE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -383,5 +391,6 @@ Global {46D8C7C3-43CA-465C-9714-20B22CF3E459} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} {24B3FBDF-E7C2-4A54-8877-CBC05DBF2ABC} = {70FEE852-57E6-4910-B4A8-E1B6D0F159E3} {91E8E3CC-B1F5-4D27-8DAF-639CA5C76F63} = {7C8FF043-B608-42BD-930B-2249675BA666} + {055CF3AD-BDAF-4441-989B-D764B80FBDEE} = {EC03CB1D-151F-4469-A6DD-D5854A340F1D} EndGlobalSection EndGlobal diff --git a/msbuild/FSharp.targets b/msbuild/FSharp.targets index a7cc7f2fd..5f0147b11 100644 --- a/msbuild/FSharp.targets +++ b/msbuild/FSharp.targets @@ -36,11 +36,7 @@ - - ..\packages\FSharp.Core.3.0.2\lib\net40\FSharp.Core.dll - False - - + ..\packages\FSharp.Core.4.0.0.1\lib\net40\FSharp.Core.dll True @@ -87,12 +83,12 @@ - + $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets - + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets diff --git a/msbuild/WebSharper.CSharp.Internal.targets b/msbuild/WebSharper.CSharp.Internal.targets index 4c9c14c07..7cbc1617d 100644 --- a/msbuild/WebSharper.CSharp.Internal.targets +++ b/msbuild/WebSharper.CSharp.Internal.targets @@ -54,5 +54,5 @@ 3 $(Root)\build\Release\$(Name).xml - + diff --git a/msbuild/WebSharper.CSharp.targets b/msbuild/WebSharper.CSharp.targets index 9800c8e7b..576077c80 100644 --- a/msbuild/WebSharper.CSharp.targets +++ b/msbuild/WebSharper.CSharp.targets @@ -29,8 +29,7 @@ diff --git a/msbuild/Zafir.CSharp.targets b/msbuild/Zafir.CSharp.targets index 2c8a22d60..06f8a8537 100644 --- a/msbuild/Zafir.CSharp.targets +++ b/msbuild/Zafir.CSharp.targets @@ -30,7 +30,6 @@ DefineConstants="$(DefineConstants)" NoStandardLib="$(NoCompilerStandardLib)" Sources="@(Compile)" - CscCommandLineArgs="@(CscCommandLineArgs)" OutputAssembly="@(IntermediateAssembly)" References="@(ReferencePath)" Configuration="$(Configuration)" @@ -49,6 +48,10 @@ WebSharperProject="$(WebSharperProject)" WebSharperErrorsAsWarnings="$(WebSharperErrorsAsWarnings)" ZafirToolPath="$(MSBuildThisFileDirectory)/../tools/net45/zafircs.exe" + TargetType="$(OutputType)" + NoConfig="true" + DebugType="$(DebugType)" + SubsystemVersion="$(SubsystemVersion)" /> diff --git a/src/build/Bootstrap/Main.fs b/src/build/Bootstrap/Main.fs index 8de48d13f..546deb858 100644 --- a/src/build/Bootstrap/Main.fs +++ b/src/build/Bootstrap/Main.fs @@ -80,7 +80,7 @@ let RestorePackages () = nuget "install FSharp.Core -version 3.0.2 -o packages" nuget "install FSharp.Core -version 4.0.0.1 -o packages" nuget "install sharpcompress -version 0.11.5 -o packages -excludeVersion" - nuget "install Mono.Cecil -version 0.9.5.4 -o packages -excludeVersion" // newer: 0.9.6.1 + nuget "install Mono.Cecil -version 0.9.6.1 -o packages -excludeVersion" // newer: 0.9.6.1 nuget "install AjaxMin -version 5.14.5506.26202 -o packages -excludeVersion" nuget "install FsNuGet -o packages -excludeVersion -nocache" nuget "install Microsoft.CodeAnalysis.CSharp -version 1.2.1 -o packages -excludeVersion" diff --git a/src/compiler/WebSharper.CSharp.Analyzer/Analyzer.fs b/src/compiler/WebSharper.CSharp.Analyzer/Analyzer.fs new file mode 100644 index 000000000..4453c2bd8 --- /dev/null +++ b/src/compiler/WebSharper.CSharp.Analyzer/Analyzer.fs @@ -0,0 +1,129 @@ +namespace WebSharper.CSharp.Analyzer + +open System +open System.Collections.Generic +open System.Collections.Immutable +open System.Linq +open System.Threading +open System.Reflection +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CSharp +open Microsoft.CodeAnalysis.CSharp.Syntax +open Microsoft.CodeAnalysis.Diagnostics +open System.IO +open WebSharper.Compiler + +[] +type WebSharperCSharpAnalyzer () = + inherit DiagnosticAnalyzer() + + static let wsWarning = + new DiagnosticDescriptor ("WebSharperWarning", "WebSharper warnings", "{0}", "WebSharper", DiagnosticSeverity.Warning, true, null, null) + + static let wsError = + new DiagnosticDescriptor ("WebSharperError", "WebSharper errors", "{0}", "WebSharper", DiagnosticSeverity.Error, true, null, null) + + let mutable cachedRefMeta = None + + override this.SupportedDiagnostics = + ImmutableArray.Create(wsWarning, wsError) + + override this.Initialize(initCtx) = + let mutable count = 0 + +// initCtx.RegisterCompilationStartAction(fun startCtx -> +// startCtx.RegisterCompilationEndAction(fun endCtx -> +// ) +// ) + + initCtx.RegisterCompilationAction(fun compCtx -> + + try + let compilation = compCtx.Compilation :?> CSharpCompilation + + let refMeta = + match cachedRefMeta with + | Some res -> res + | _ -> + let refPaths = + compilation.ExternalReferences |> Seq.choose (fun r -> + match r with + | :? PortableExecutableReference as cr -> Some cr.FilePath + | _ -> None + ) + let aR = + AssemblyResolver.Create() + .SearchPaths(refPaths) + let loader = WebSharper.Compiler.FrontEnd.Loader.Create aR ignore + let refs = [ for r in refPaths -> loader.LoadFile(r) ] + let metas = refs |> List.choose (fun r -> WebSharper.Compiler.FrontEnd.ReadFromAssembly r) + let referencedAsmNames = + refPaths + |> Seq.map (fun i -> + let n = Path.GetFileNameWithoutExtension(i) + n, i + ) + |> Map.ofSeq + + let assemblyResolveHandler = ResolveEventHandler(fun _ e -> + let assemblyName = AssemblyName(e.Name).Name + match Map.tryFind assemblyName referencedAsmNames with + | None -> null + | Some p -> + if assemblyName = "FSharp.Core" then + typeof>.Assembly + else + Assembly.LoadFrom(p) + ) + + System.AppDomain.CurrentDomain.add_AssemblyResolve(assemblyResolveHandler) + + let res = + if List.isEmpty metas then None + else Some (WebSharper.Core.DependencyGraph.Graph.UnionOfMetadata metas) + + cachedRefMeta <- Some res + res + + if compCtx.CancellationToken.IsCancellationRequested then () else + + let compiler = WebSharper.Compiler.CSharp.WebSharperCSharpCompiler(ignore) + + let comp = + compiler.Compile(refMeta, compilation) + + if compCtx.CancellationToken.IsCancellationRequested then () else + + let loc (pos: WebSharper.Core.AST.SourcePos option) = + match pos with + | None -> Location.None + | Some p -> +// Text.TextSpan(snd p.Start - 1, snd p.End - 1) +// let lp (line, col) = Text.LinePosition(line - 1, col - 1) +// let lineSpan = Text.LinePositionSpan(lp p.Start, lp p.End) + match WebSharper.Compiler.CSharp.ProjectReader.textSpans.TryGetValue(p) with + | true, textSpan -> + let syntaxTree = + compilation.SyntaxTrees |> Seq.find (fun t -> t.FilePath = p.FileName) + Location.Create(syntaxTree, !textSpan) + | _ -> + Location.None + + for pos, wrn in comp.Warnings do + compCtx.ReportDiagnostic(Diagnostic.Create(wsWarning, loc pos, string wrn)) + + for pos, err in comp.Errors do + compCtx.ReportDiagnostic(Diagnostic.Create(wsError, loc pos, string err)) + +// let files = +// compilation.SyntaxTrees |> Seq.map (fun t -> System.IO.Path.GetFileNameWithoutExtension t.FilePath) +// |> String.concat " " + + count <- count + 1 + compCtx.ReportDiagnostic(Diagnostic.Create(wsWarning, Location.None, sprintf "WebSharper analyzer finished (%d): %d errors, %d warnings" count comp.Errors.Length comp.Warnings.Length)) + compCtx.ReportDiagnostic(Diagnostic.Create(wsWarning, Location.None, sprintf "Another diagnostic")) + with e -> + count <- count + 1 + compCtx.ReportDiagnostic(Diagnostic.Create(wsWarning, Location.None, sprintf "WebSharper analyzer failed (%d): %s at %s" count e.Message e.StackTrace)) + ) + diff --git a/src/compiler/WebSharper.CSharp.Analyzer/WebSharper.CSharp.Analyzer.fsproj b/src/compiler/WebSharper.CSharp.Analyzer/WebSharper.CSharp.Analyzer.fsproj new file mode 100644 index 000000000..ced084916 --- /dev/null +++ b/src/compiler/WebSharper.CSharp.Analyzer/WebSharper.CSharp.Analyzer.fsproj @@ -0,0 +1,47 @@ + + + + 055CF3AD-BDAF-4441-989B-D764B80FBDEE + Library + WebSharper.CSharp.Analyzer + v4.5 + + True + + + + + + WebSharper.Compiler.CSharp + {8f188e8b-547e-4a8e-bd3b-257a13af9acd} + True + + + WebSharper.Compiler + {bfb21b61-fda9-4814-a728-7d43038e0b57} + True + + + WebSharper.Core + {52741881-8d64-4639-8b5c-19c060958c35} + True + + + + + ..\..\..\packages\Microsoft.CodeAnalysis.Common\lib\net45\Microsoft.CodeAnalysis.dll + + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp\lib\net45\Microsoft.CodeAnalysis.CSharp.dll + + + ..\..\..\packages\System.Collections.Immutable\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + ..\..\..\packages\System.Reflection.Metadata\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + + + + \ No newline at end of file diff --git a/src/compiler/WebSharper.CSharp/Program.fs b/src/compiler/WebSharper.CSharp/Program.fs index 4be972884..fa1c13212 100644 --- a/src/compiler/WebSharper.CSharp/Program.fs +++ b/src/compiler/WebSharper.CSharp/Program.fs @@ -233,6 +233,9 @@ let compileMain argv = | StartsWith "/reference:" r -> refs.Add r cscArgs.Add a + | StartsWith "/resource:" r -> + resources.Add r + cscArgs.Add a | StartsWith "/keyfile:" k -> wsArgs := { !wsArgs with KeyFile = Some k } | _ -> diff --git a/src/compiler/WebSharper.CSharp/WebSharper.CSharp.fsproj b/src/compiler/WebSharper.CSharp/WebSharper.CSharp.fsproj index 53ef3107b..fcb4405ac 100644 --- a/src/compiler/WebSharper.CSharp/WebSharper.CSharp.fsproj +++ b/src/compiler/WebSharper.CSharp/WebSharper.CSharp.fsproj @@ -42,4 +42,8 @@ True + + + + \ No newline at end of file diff --git a/src/compiler/WebSharper.Compiler.CSharp/CodeReader.fs b/src/compiler/WebSharper.Compiler.CSharp/CodeReader.fs index 4f7991499..60f0a0c8f 100644 --- a/src/compiler/WebSharper.Compiler.CSharp/CodeReader.fs +++ b/src/compiler/WebSharper.Compiler.CSharp/CodeReader.fs @@ -28,56 +28,13 @@ open WebSharper.Core open WebSharper.Core.AST open WebSharper.Compiler.CompilationHelpers open WebSharper.Compiler.Breaker + +module A = WebSharper.Compiler.AttributeReader open WebSharper.Compiler.CSharp.RoslynHelpers open System.Collections.Generic -type Environment = - { - SemanticModel : SemanticModel - Vars : IDictionary - Parameters : IDictionary - Labels : IDictionary - Caught : option - Conditional : option - Initializing : option - Compilation : WebSharper.Compiler.Compilation - RangeVars : IDictionary> - } - static member New(model, comp) = - { - SemanticModel = model - Vars = Dictionary() - Parameters = Dictionary() - Labels = Dictionary() - Caught = None - Conditional = None - Initializing = None - Compilation = comp - RangeVars = Dictionary() - } - - member this.GetLabelId(symbol) = - match this.Labels.TryGetValue(symbol) with - | true, id -> id - | _ -> - let id = Id.New(symbol.Name) - this.Labels.Add(symbol, id) - id - - member this.WithCaught(c) = - { this with Caught = Some c } - - member this.WithConditional(c) = - { this with Conditional = Some c } - - member this.WithInitializing(i) = - { this with Initializing = Some i } - - member this.WithNotInitializing() = - { this with Initializing = None } - type CSharpParameter = { ParameterId : Id @@ -112,26 +69,30 @@ type CSharpConstructor = Initializer : option } -let getConstantValueOfExpression (env: Environment) x = - env.SemanticModel.GetConstantValue(x).Value - |> ReadLiteral |> Value - -let getSourcePosOfSpan (span: FileLinePositionSpan) = - { - FileName = span.Path - Start = - let pos = span.StartLinePosition - pos.Line + 1, pos.Character + 1 - End = - let pos = span.EndLinePosition - pos.Line + 1, pos.Character + 1 - } +let textSpans = + System.Runtime.CompilerServices.ConditionalWeakTable() + +let getSourcePosOfSpan (ts: Text.TextSpan) (span: FileLinePositionSpan) = + let res = + { + FileName = span.Path + Start = + let pos = span.StartLinePosition + pos.Line + 1, pos.Character + 1 + End = + let pos = span.EndLinePosition + pos.Line + 1, pos.Character + 1 + } + textSpans.Add(res, ref ts) + res let getSourcePos (x: CSharpSyntaxNode) = - getSourcePosOfSpan (x.SyntaxTree.GetLineSpan(x.Span)) + let ts = x.Span + getSourcePosOfSpan ts (x.SyntaxTree.GetLineSpan ts) let getSourcePosOfSyntaxReference (x: SyntaxReference) = - getSourcePosOfSpan (x.SyntaxTree.GetLineSpan(x.Span)) + let ts = x.Span + getSourcePosOfSpan ts (x.SyntaxTree.GetLineSpan ts) let withExprSourcePos (x: CSharpSyntaxNode) expr = ExprSourcePos (getSourcePos x, IgnoreExprSourcePos expr) @@ -152,247 +113,340 @@ let inline TODO x = let inline NotSupported x = failwithf "Syntax not supported for JavaScript: %s" x -let rec getNamedTypeDefinition (x: INamedTypeSymbol) = - let arity (symbol: INamedTypeSymbol) = - match symbol.Arity with 0 -> "" | a -> "`" + string a +module M = Metadata - let rec getNamespaceOrTypeAddress acc (symbol: INamespaceOrTypeSymbol) = - match symbol.ContainingNamespace with - | null -> acc |> String.concat "." - | ns -> getNamespaceOrTypeAddress (symbol.Name :: acc) ns - - let rec getTypeAddress acc (symbol: INamedTypeSymbol) = - match symbol.ContainingType with - | null -> - let ns = getNamespaceOrTypeAddress [] symbol + arity symbol - if List.isEmpty acc then ns else - ns :: acc |> String.concat "+" - | t -> getTypeAddress (symbol.Name + arity symbol :: acc) t - - Hashed { - Assembly = x.ContainingAssembly.Identity.Name - FullName = getTypeAddress [] x //) + arity x - } +type SymbolReader(comp : WebSharper.Compiler.Compilation) as self = -and getNamedType (x: INamedTypeSymbol) = - if isNull x then - // TODO: handle dynamic by cheking symbol.ContainingSymbol before calling getNamedType - NonGeneric Definitions.Dynamic - else - let ta = x.TypeArguments |> Seq.map getType |> List.ofSeq - let td = getNamedTypeDefinition x - Generic td ta - -and recognizeNamedType (x: INamedTypeSymbol) = - let ta = x.TypeArguments |> Seq.map getType |> List.ofSeq - let td = getNamedTypeDefinition x - let tName = td.Value.FullName - if tName.StartsWith "System.Tuple" then - if tName.EndsWith "8" then - match ta.[7] with - | TupleType rest -> TupleType (ta.[.. 6] @ rest) - | _ -> failwith "invalid big tuple type" - else TupleType ta - elif tName = "Microsoft.FSharp.Core.FSharpFunc`2" then - match ta with - | [a; r] -> FSharpFuncType(a, r) - | _ -> failwith "impossible" - elif tName = "Microsoft.FSharp.Core.Unit" || tName = "System.Void" then - VoidType - else - GenericType td ta - -and getType (x: ITypeSymbol) : Type = - match x.TypeKind with - | TypeKind.Array -> - let t = x :?> IArrayTypeSymbol - ArrayType (getType t.ElementType, t.Rank) - | TypeKind.Class - | TypeKind.Struct - | TypeKind.Error - | TypeKind.Enum - | TypeKind.Delegate - | TypeKind.Interface -> - let t = x :?> INamedTypeSymbol - recognizeNamedType t - | TypeKind.Dynamic -> - ConcreteType (NonGeneric Definitions.Obj) - | TypeKind.TypeParameter -> - let t = x :?> ITypeParameterSymbol - if t.TypeParameterKind = TypeParameterKind.Method then - TypeParameter (t.Ordinal + t.DeclaringMethod.ContainingType.TypeParameters.Length) - else - TypeParameter t.Ordinal - | _ -> - errf x "transformType: typekind %O not suppported" x.TypeKind - -let getAsyncReturnKind (x: IMethodSymbol) = - if x.ReturnsVoid then - Continuation.ReturnsVoid - elif (x.ReturnType :?> INamedTypeSymbol).IsGenericType then - Continuation.ReturnsResultTask - else Continuation.ReturnsTask - -let getMethod (x: IMethodSymbol) = - let x = x.OriginalDefinition - Hashed { - MethodName = x.Name - Parameters = x.Parameters |> Seq.map (fun p -> getType p.Type) |> List.ofSeq - ReturnType = x.ReturnType |> getType - Generics = x.Arity - } + let attrReader = + { new A.AttributeReader() with + override this.GetAssemblyName attr = attr.AttributeClass.ContainingAssembly.Name + override this.GetName attr = attr.AttributeClass.Name + override this.GetCtorArgs attr = attr.ConstructorArguments |> Seq.map (fun a -> a.Value) |> Array.ofSeq + override this.GetTypeDef o = self.ReadNamedTypeDefinition (o :?> INamedTypeSymbol) + } -let setterOf (getter : Concrete) = - let m = getter.Entity.Value - if not (m.MethodName.StartsWith "get_") then - failwithf "Invalid getter method: %s" m.MethodName - { getter with - Entity = - Method { - MethodName = "set" + m.MethodName.[3 ..] - ReturnType = VoidType - Parameters = m.Parameters @ [ m.ReturnType ] - Generics = m.Generics + member this.RegisterCustomType def (td: INamedTypeSymbol) = + if not (comp.HasCustomTypeInfo def) then + let inv = td.DelegateInvokeMethod + if not (isNull inv) then + let info = + M.DelegateInfo { + DelegateArgs = + inv.Parameters |> Seq.map (fun p -> this.ReadType p.Type) |> List.ofSeq + ReturnType = this.ReadType inv.ReturnType + } + comp.AddCustomType(def, info) + + member this.ReadNamedTypeDefinition (x: INamedTypeSymbol) = + let arity (symbol: INamedTypeSymbol) = + match symbol.Arity with 0 -> "" | a -> "`" + string a + + let rec getNamespaceOrTypeAddress acc (symbol: INamespaceOrTypeSymbol) = + match symbol.ContainingNamespace with + | null -> acc |> String.concat "." + | ns -> getNamespaceOrTypeAddress (symbol.Name :: acc) ns + + let rec getTypeAddress acc (symbol: INamedTypeSymbol) = + match symbol.ContainingType with + | null -> + let ns = getNamespaceOrTypeAddress [] symbol + arity symbol + if List.isEmpty acc then ns else + ns :: acc |> String.concat "+" + | t -> getTypeAddress (symbol.Name + arity symbol :: acc) t + + let res = + Hashed { + Assembly = x.ContainingAssembly.Identity.Name + FullName = getTypeAddress [] x //) + arity x } - } -let getConstructor (x: IMethodSymbol) = - Hashed { - CtorParameters = x.Parameters |> Seq.map (fun p -> getType p.Type) |> List.ofSeq - } + this.RegisterCustomType res x -let getMember (x: IMethodSymbol) = - let name = x.Name - match name with - | ".ctor" -> - Member.Constructor <| Hashed { - CtorParameters = x.Parameters |> Seq.map (fun p -> getType p.Type) |> List.ofSeq + res + + member this.ReadNamedType (x: INamedTypeSymbol) = + if isNull x then + // TODO: handle dynamic by cheking symbol.ContainingSymbol before calling sr.ReadNamedType + NonGeneric Definitions.Dynamic + else + let ta = x.TypeArguments |> Seq.map this.ReadType |> List.ofSeq + let td = this.ReadNamedTypeDefinition x + Generic td ta + + member this.RecognizeNamedType (x: INamedTypeSymbol) = + let ta = x.TypeArguments |> Seq.map this.ReadType |> List.ofSeq + let td = this.ReadNamedTypeDefinition x + let tName = td.Value.FullName + if tName.StartsWith "System.Tuple" then + if tName.EndsWith "8" then + match ta.[7] with + | TupleType rest -> TupleType (ta.[.. 6] @ rest) + | _ -> failwith "invalid big tuple type" + else TupleType ta + elif tName = "Microsoft.FSharp.Core.FSharpFunc`2" then + match ta with + | [a; r] -> FSharpFuncType(a, r) + | _ -> failwith "impossible" + elif tName = "Microsoft.FSharp.Core.Unit" || tName = "System.Void" then + VoidType + else + GenericType td ta + + member this.ReadType (x: ITypeSymbol) : Type = + match x.TypeKind with + | TypeKind.Array -> + let t = x :?> IArrayTypeSymbol + ArrayType (this.ReadType t.ElementType, t.Rank) + | TypeKind.Class + | TypeKind.Struct + | TypeKind.Error + | TypeKind.Enum + | TypeKind.Delegate + | TypeKind.Interface -> + let t = x :?> INamedTypeSymbol + this.RecognizeNamedType t + | TypeKind.Dynamic -> + ConcreteType (NonGeneric Definitions.Obj) + | TypeKind.TypeParameter -> + let t = x :?> ITypeParameterSymbol + if t.TypeParameterKind = TypeParameterKind.Method then + TypeParameter (t.Ordinal + t.DeclaringMethod.ContainingType.TypeParameters.Length) + else + TypeParameter t.Ordinal + | _ -> + errf x "transformType: typekind %O not suppported" x.TypeKind + + member this.ReadAsyncReturnKind (x: IMethodSymbol) = + if x.ReturnsVoid then + Continuation.ReturnsVoid + elif (x.ReturnType :?> INamedTypeSymbol).IsGenericType then + Continuation.ReturnsResultTask + else Continuation.ReturnsTask + + member this.ReadMethod (x: IMethodSymbol) = + let x = x.OriginalDefinition + Hashed { + MethodName = x.Name + Parameters = x.Parameters |> Seq.map (fun p -> this.ReadType p.Type) |> List.ofSeq + ReturnType = x.ReturnType |> this.ReadType + Generics = x.Arity } - | ".cctor" -> Member.StaticConstructor - | _ -> - let getMeth (x: IMethodSymbol) = - Hashed { - MethodName = x.Name - Parameters = x.Parameters |> Seq.map (fun p -> getType p.Type) |> List.ofSeq - ReturnType = x.ReturnType |> getType - Generics = x.Arity + + member this.ReadConstructor (x: IMethodSymbol) = + Hashed { + CtorParameters = x.Parameters |> Seq.map (fun p -> this.ReadType p.Type) |> List.ofSeq + } + + member this.ReadMember (x: IMethodSymbol) = + let name = x.Name + match name with + | ".ctor" -> + Member.Constructor <| Hashed { + CtorParameters = x.Parameters |> Seq.map (fun p -> this.ReadType p.Type) |> List.ofSeq } - if x.IsOverride then - let o = x.OverriddenMethod.OriginalDefinition - Member.Override(getNamedTypeDefinition o.ContainingType, getMeth o) - elif x.ExplicitInterfaceImplementations.Length > 0 then - let o = x.ExplicitInterfaceImplementations.[0].OriginalDefinition - Member.Implementation(getNamedTypeDefinition o.ContainingType, getMeth o) - else - let o = x.OriginalDefinition - Member.Method (not o.IsStatic, getMeth o) - -let getParameter (x: IParameterSymbol) : CSharpParameter = - let typ = getType x.Type - let defValue = - if x.HasExplicitDefaultValue then - Some (ReadLiteral x.ExplicitDefaultValue |> Value) - elif x.IsOptional then - Some (DefaultValueOf typ) - elif x.IsParams then - Some (NewArray []) - else None - - let id = Id.New x.Name + | ".cctor" -> Member.StaticConstructor + | _ -> + let getMeth (x: IMethodSymbol) = + Hashed { + MethodName = x.Name + Parameters = x.Parameters |> Seq.map (fun p -> this.ReadType p.Type) |> List.ofSeq + ReturnType = x.ReturnType |> this.ReadType + Generics = x.Arity + } + if x.IsOverride then + let o = x.OverriddenMethod.OriginalDefinition + Member.Override(this.ReadNamedTypeDefinition o.ContainingType, getMeth o) + elif x.ExplicitInterfaceImplementations.Length > 0 then + let o = x.ExplicitInterfaceImplementations.[0].OriginalDefinition + Member.Implementation(this.ReadNamedTypeDefinition o.ContainingType, getMeth o) + else + let o = x.OriginalDefinition + Member.Method (not o.IsStatic, getMeth o) + + member this.ReadParameter (x: IParameterSymbol) : CSharpParameter = + let typ = this.ReadType x.Type + let defValue = + if x.HasExplicitDefaultValue then + Some (ReadLiteral x.ExplicitDefaultValue |> Value) + elif x.IsOptional then + Some (DefaultValueOf typ) + elif x.IsParams then + Some (NewArray []) + else None + + let id = Id.New x.Name + { + ParameterId = id + Symbol = x + DefaultValue = defValue + Type = typ + RefOrOut = x.RefKind <> RefKind.None + } + + member this.ReadParameters (x: IMethodSymbol) = + x.Parameters |> Seq.map this.ReadParameter |> List.ofSeq + + //let hasSignature (comp: WebSharper.Compiler.Compilation) (s: Method) (x: IMethodSymbol) = + // let s = s.Value + // x.Arity = s.Generics + // && (x.ReturnType |> sr.ReadType) = s.ReturnType + // && x.Parameters |> Seq.map (fun p -> sr.ReadType p.Type) |> Seq.equals s.Parameters + + member this.AttributeReader = attrReader + +type Environment = { - ParameterId = id - Symbol = x - DefaultValue = defValue - Type = typ - RefOrOut = x.RefKind <> RefKind.None + SemanticModel : SemanticModel + Vars : IDictionary + Parameters : IDictionary + Labels : IDictionary + Caught : option + Conditional : option + Initializing : option + Compilation : WebSharper.Compiler.Compilation + SymbolReader : SymbolReader + RangeVars : IDictionary> } + static member New(model, comp, sr) = + { + SemanticModel = model + Vars = Dictionary() + Parameters = Dictionary() + Labels = Dictionary() + Caught = None + Conditional = None + Initializing = None + Compilation = comp + SymbolReader = sr + RangeVars = Dictionary() + } -let getParameters (x: IMethodSymbol) = - x.Parameters |> Seq.map getParameter |> List.ofSeq - -let fixParamArray (symbol: IMethodSymbol) (env: Environment) (args: ArgumentListData) argumentList = - let ps = symbol.Parameters - let paramCount = ps.Length - let fixSingleArg pa = - let rec arrayDepth (t: ITypeSymbol) = - if t.TypeKind = TypeKind.Array then - let t = t :?> IArrayTypeSymbol - 1 + arrayDepth t.ElementType - else 0 - let paTy = - env.SemanticModel.GetTypeInfo((args.Arguments |> Seq.last).Expression.Node).Type - let paTyArrayDepth = - if paTy = null then 0 else arrayDepth paTy - if arrayDepth (ps.[paramCount - 1].Type) = paTyArrayDepth then pa else NewArray [ pa ] - - if paramCount > 0 && ps.[paramCount - 1].IsParams then - if List.length argumentList >= paramCount - 1 - && argumentList |> Seq.forall (fst >> Option.isNone) then - let normal, toArr = argumentList |> List.map snd |> List.splitAt (paramCount - 1) - match toArr with - | [ pa ] -> normal @ [ fixSingleArg pa ] - | _ -> - normal @ [ NewArray toArr ] - |> List.map (fun a -> None, a) - else - let psInd = Some (paramCount - 1) - if argumentList |> Seq.map fst |> Seq.contains psInd then - argumentList |> List.map (fun (i, v) -> - i, if i = psInd then fixSingleArg v else v - ) - else argumentList - else argumentList - -let getReorderedParams args = - if args |> List.forall (fst >> Option.isNone) then [], args |> List.map snd else - let needsParamReorder = - args |> List.fold (fun bo (i, _) -> - bo |> Option.bind (fun b -> - match i with - | None -> Some 0 - | Some i -> if i < b then None else Some i - ) - ) (Some 0) - |> Option.isNone - let lastIndex = args |> Seq.choose fst |> Seq.max - let argsWithIndexes = - args |> List.mapi (fun i (j, e) -> i, defaultArg j i, e, Id.New()) - if needsParamReorder then - let byOrdinal = argsWithIndexes |> Seq.map (fun (_, i, _, v) -> i, v) |> Map.ofSeq - let inOrder = argsWithIndexes |> List.sortBy (fun (_, i, _, _) -> i) |> List.map (fun (_, _, e, v) -> v, e) - let fargs = - List.init (lastIndex + 1) (fun i -> - match byOrdinal |> Map.tryFind i with - | Some v -> Var v - | _ -> Undefined - ) - inOrder, fargs - else - let byOrdinal = argsWithIndexes |> Seq.map (fun (_, i, e, _) -> i, e) |> Map.ofSeq - let fargs = - List.init (lastIndex + 1) (fun i -> - match byOrdinal |> Map.tryFind i with - | Some e -> e - | _ -> Undefined - ) - [], fargs - -let hasSignature (s: Method) (x: IMethodSymbol) = - let s = s.Value - x.Arity = s.Generics - && (x.ReturnType |> getType) = s.ReturnType - && x.Parameters |> Seq.map (fun p -> getType p.Type) |> Seq.equals s.Parameters - -let jsCall expr item args = - Application(ItemGet(expr, Value (String item)), args) + member this.GetLabelId(symbol) = + match this.Labels.TryGetValue(symbol) with + | true, id -> id + | _ -> + let id = Id.New(symbol.Name) + this.Labels.Add(symbol, id) + id + + member this.WithCaught(c) = + { this with Caught = Some c } -let queryCall (symbol: IMethodSymbol) args = - let qtyp = getNamedType symbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod symbol.ReducedFrom) ma - Call (None, qtyp, meth, args) + member this.WithConditional(c) = + { this with Conditional = Some c } + + member this.WithInitializing(i) = + { this with Initializing = Some i } + + member this.WithNotInitializing() = + { this with Initializing = None } type RoslynTransformer(env: Environment) = + let getConstantValueOfExpression x = + env.SemanticModel.GetConstantValue(x).Value + |> ReadLiteral |> Value + + let sr = env.SymbolReader + + let fixParamArray (symbol: IMethodSymbol) (args: ArgumentListData) argumentList = + let ps = symbol.Parameters + let paramCount = ps.Length + let fixSingleArg pa = + let rec arrayDepth (t: ITypeSymbol) = + if t.TypeKind = TypeKind.Array then + let t = t :?> IArrayTypeSymbol + 1 + arrayDepth t.ElementType + else 0 + let paTy = + env.SemanticModel.GetTypeInfo((args.Arguments |> Seq.last).Expression.Node).Type + let paTyArrayDepth = + if paTy = null then 0 else arrayDepth paTy + if arrayDepth (ps.[paramCount - 1].Type) = paTyArrayDepth then pa else NewArray [ pa ] + + if paramCount > 0 && ps.[paramCount - 1].IsParams then + if List.length argumentList >= paramCount - 1 + && argumentList |> Seq.forall (fst >> Option.isNone) then + let normal, toArr = argumentList |> List.map snd |> List.splitAt (paramCount - 1) + match toArr with + | [ pa ] -> normal @ [ fixSingleArg pa ] + | _ -> + normal @ [ NewArray toArr ] + |> List.map (fun a -> None, a) + else + let psInd = Some (paramCount - 1) + if argumentList |> Seq.map fst |> Seq.contains psInd then + argumentList |> List.map (fun (i, v) -> + i, if i = psInd then fixSingleArg v else v + ) + else argumentList + else argumentList + + let readReorderedParams args = + if args |> List.forall (fst >> Option.isNone) then [], args |> List.map snd else + let needsParamReorder = + args |> List.fold (fun bo (i, _) -> + bo |> Option.bind (fun b -> + match i with + | None -> Some 0 + | Some i -> if i < b then None else Some i + ) + ) (Some 0) + |> Option.isNone + let lastIndex = args |> Seq.choose fst |> Seq.max + let argsWithIndexes = + args |> List.mapi (fun i (j, e) -> i, defaultArg j i, e, Id.New()) + if needsParamReorder then + let byOrdinal = argsWithIndexes |> Seq.map (fun (_, i, _, v) -> i, v) |> Map.ofSeq + let inOrder = argsWithIndexes |> List.sortBy (fun (_, i, _, _) -> i) |> List.map (fun (_, _, e, v) -> v, e) + let fargs = + List.init (lastIndex + 1) (fun i -> + match byOrdinal |> Map.tryFind i with + | Some v -> Var v + | _ -> Undefined + ) + inOrder, fargs + else + let byOrdinal = argsWithIndexes |> Seq.map (fun (_, i, e, _) -> i, e) |> Map.ofSeq + let fargs = + List.init (lastIndex + 1) (fun i -> + match byOrdinal |> Map.tryFind i with + | Some e -> e + | _ -> Undefined + ) + [], fargs + + let setterOf (getter : Concrete) = + let m = getter.Entity.Value + if not (m.MethodName.StartsWith "get_") then + failwithf "Invalid getter method: %s" m.MethodName + { getter with + Entity = + Method { + MethodName = "set" + m.MethodName.[3 ..] + ReturnType = VoidType + Parameters = m.Parameters @ [ m.ReturnType ] + Generics = m.Generics + } + } + + let jsCall expr item args = + Application(ItemGet(expr, Value (String item)), args) + + let queryCall (symbol: IMethodSymbol) args = + let qtyp = sr.ReadNamedType symbol.ContainingType + let ma = symbol.TypeArguments |> Seq.map (sr.ReadType) |> List.ofSeq + let meth = Generic (sr.ReadMethod symbol.ReducedFrom) ma + Call (None, qtyp, meth, args) + + let getTypeAndMethod (symbol: IMethodSymbol) = + let typ = sr.ReadNamedType symbol.ContainingType + let ma = symbol.TypeArguments |> Seq.map (sr.ReadType) |> List.ofSeq + let meth = Generic (sr.ReadMethod symbol) ma + typ, meth + + let call (symbol: IMethodSymbol) thisOpt args = + let typ, meth = getTypeAndMethod symbol + Call(thisOpt, typ, meth, args) member this.TransformIdentifierName (x: IdentifierNameData) : Expression = let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol @@ -411,19 +465,15 @@ type RoslynTransformer(env: Environment) = match env.RangeVars.[v] with | v, None -> Var v | v, Some i -> ItemGet(Var v, Value (Int i)) - | :? IFieldSymbol as f -> FieldGet((getTarget()), getNamedType f.ContainingType, f.Name) - | :? IEventSymbol as e -> FieldGet((getTarget()), getNamedType e.ContainingType, e.Name) + | :? IFieldSymbol as f -> FieldGet((getTarget()), sr.ReadNamedType f.ContainingType, f.Name) + | :? IEventSymbol as e -> FieldGet((getTarget()), sr.ReadNamedType e.ContainingType, e.Name) | :? IPropertySymbol as p -> - let ma = p.GetMethod.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod p.GetMethod) ma - Call(getTarget(), getNamedType p.ContainingType, meth, []) // TODO: indexed properties + call p.GetMethod (getTarget()) [] // TODO: indexed properties? | :? IMethodSymbol as m -> let conv = env.SemanticModel.GetConversion(x.Node) if not conv.Exists || conv.IsIdentity then This elif conv.IsMethodGroup then - let typ = getNamedType symbol.ContainingType - let ma = m.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod m) ma + let typ, meth = getTypeAndMethod m NewDelegate(Some This, typ, meth) else failwithf "transformIdentifierName: unhandled IMethodSymbol conversion: %A" conv | _ -> @@ -472,9 +522,9 @@ type RoslynTransformer(env: Environment) = let conversion = env.SemanticModel.GetConversion(x.Node) if conversion.IsUserDefined then let symbol = conversion.MethodSymbol - let typ = getNamedType symbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod symbol) ma + let typ = sr.ReadNamedType symbol.ContainingType + let ma = symbol.TypeArguments |> Seq.map (sr.ReadType) |> List.ofSeq + let meth = Generic (sr.ReadMethod symbol) ma Call(None, typ, meth, [ expr ]) else expr with e -> @@ -503,22 +553,30 @@ type RoslynTransformer(env: Environment) = member this.TransformInvocationExpression (x: InvocationExpressionData) : Expression = let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol +// let symbol = +// if isNull symbol then +// env.SemanticModel.GetSymbolInfo(x.Expression.Node).Symbol :?> IMethodSymbol +// else symbol +// if isNull symbol then +// env.SemanticModel.GetSyntaxDiagnostics(System.Nullable x.Node.Parent.Span) +// |> Seq.map (fun d -> d.GetMessage()) |> String.concat " / " +// |> failwithf "Parent errors: %s" let eSymbol, isExtensionMethod = match symbol.ReducedFrom with | null -> symbol, false | symbol -> symbol, true - let typ = getNamedType eSymbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod eSymbol) ma + let typ = sr.ReadNamedType eSymbol.ContainingType + let ma = symbol.TypeArguments |> Seq.map sr.ReadType |> List.ofSeq + let meth = Generic (sr.ReadMethod eSymbol) ma let argumentList = x.ArgumentList |> this.TransformArgumentList - let argumentListWithParamsFix = fixParamArray eSymbol env x.ArgumentList argumentList + let argumentListWithParamsFix = fixParamArray eSymbol x.ArgumentList argumentList let argumentListWithThis = if isExtensionMethod || not symbol.IsStatic then (None, (x.Expression |> this.TransformExpression)) :: (argumentListWithParamsFix |> List.map (fun (i, e) -> i |> Option.map ((+) 1), e)) else argumentListWithParamsFix - let tempVars, args = getReorderedParams argumentListWithThis + let tempVars, args = readReorderedParams argumentListWithThis if isExtensionMethod || symbol.IsStatic then Call(None, typ, meth, args) @@ -543,12 +601,7 @@ type RoslynTransformer(env: Environment) = // TODO: make setter possible for 2-dim arrays List.fold (fun e a -> ItemGet(e, a)) expression argumentList else - let symbol = symbol - let typ = getNamedType symbol.ContainingType - let getM = symbol.GetMethod - let ma = getM.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod getM) ma - Call (Some expression, typ, meth, argumentList) + call symbol.GetMethod (Some expression) argumentList member this.TransformElementAccessExpression (x: ElementAccessExpressionData) : _ = this.TransformElementAccess(x.Node, Some x.Expression, x.ArgumentList) @@ -597,7 +650,7 @@ type RoslynTransformer(env: Environment) = x.Arguments |> Seq.map this.TransformArgument |> Seq.map snd |> List.ofSeq member this.TransformLiteralExpression (x: LiteralExpressionData) = - getConstantValueOfExpression env x.Node + getConstantValueOfExpression x.Node member this.TransformStatement (x: StatementData) : Statement = try @@ -738,10 +791,7 @@ type RoslynTransformer(env: Environment) = else this match leftSymbol with | :? IPropertySymbol as leftSymbol -> - let typ = getNamedType leftSymbol.ContainingType - let setM = leftSymbol.SetMethod - let ma = setM.TypeArguments |> Seq.map getType |> List.ofSeq - let setter = Generic (getMethod setM) ma + let typ, setter = getTypeAndMethod leftSymbol.SetMethod //if leftSymbol.IsIndexer // TODO property indexers match x.Kind with @@ -760,9 +810,7 @@ type RoslynTransformer(env: Environment) = let left = x.Left |> this.TransformExpression let right = x.Right |> trR.TransformExpression let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol - let opTyp = getNamedType symbol.ContainingType - let oa = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let operator = Generic (getMethod symbol) oa + let opTyp, operator = getTypeAndMethod symbol if leftSymbol.IsStatic then Call(None, typ, setter, [Call(None, opTyp, operator, [left; right])]) else @@ -790,9 +838,7 @@ type RoslynTransformer(env: Environment) = | _ -> TODO x | _ -> let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol - let opTyp = getNamedType symbol.ContainingType - let oa = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let operator = Generic (getMethod symbol) oa + let opTyp, operator = getTypeAndMethod symbol match IgnoreExprSourcePos left with | Var id -> VarSet(id, Call(None, opTyp, operator, [left; right])) | FieldGet (obj, ty, f) -> @@ -826,10 +872,10 @@ type RoslynTransformer(env: Environment) = let left = x.Left |> this.TransformExpression match x.Kind with | BinaryExpressionKind.IsExpression -> - let rightType = env.SemanticModel.GetTypeInfo(x.Right.Node).ConvertedType |> getType + let rightType = env.SemanticModel.GetTypeInfo(x.Right.Node).ConvertedType |> sr.ReadType TypeCheck (left, rightType) | BinaryExpressionKind.AsExpression -> - let rightType = env.SemanticModel.GetTypeInfo(x.Right.Node).ConvertedType |> getType + let rightType = env.SemanticModel.GetTypeInfo(x.Right.Node).ConvertedType |> sr.ReadType let asVar = Id.New () Let (asVar, left, Conditional (TypeCheck (Var asVar, rightType), Var asVar, Value Null)) | _ -> @@ -840,14 +886,11 @@ type RoslynTransformer(env: Environment) = | BinaryExpressionKind.LogicalAndExpression -> Conditional(left, right, Value (Bool false)) | BinaryExpressionKind.CoalesceExpression -> - let leftType = env.SemanticModel.GetTypeInfo(x.Left.Node).ConvertedType |> getType + let leftType = env.SemanticModel.GetTypeInfo(x.Left.Node).ConvertedType |> sr.ReadType Coalesce(left, leftType, right) | _ -> let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol - let typ = getNamedType symbol.ContainingType - let oa = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let operator = Generic (getMethod symbol) oa - Call(None, typ, operator, [left; right]) + call symbol None [left; right] |> withExprSourcePos x.Node member this.TransformConditionalExpression (x: ConditionalExpressionData) : Expression = @@ -858,7 +901,7 @@ type RoslynTransformer(env: Environment) = |> withExprSourcePos x.Node member this.TransformMethodDeclarationBase (symbol: IMethodSymbol, parameterList, stBody, exprBody) : CSharpMethod = - let returnType = getType symbol.ReturnType + let returnType = sr.ReadType symbol.ReturnType for p in parameterList do env.Parameters.Add(p.Symbol, (p.ParameterId, p.RefOrOut)) let body = @@ -897,7 +940,7 @@ type RoslynTransformer(env: Environment) = member this.TransformParameter (x: ParameterData) : CSharpParameter = let symbol = env.SemanticModel.GetDeclaredSymbol(x.Node) - let typ = getType symbol.Type + let typ = sr.ReadType symbol.Type let defValue = match x.Default with | Some defExpr -> Some (this.TransformEqualsValueClause defExpr) @@ -934,15 +977,15 @@ type RoslynTransformer(env: Environment) = | _ -> failwith "Delegate constructor must have a single argument" else let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol - let typ = getNamedType symbol.ContainingType + let typ = sr.ReadNamedType symbol.ContainingType let argumentList = defaultArg (x.ArgumentList |> Option.map (this.TransformArgumentList)) [] let argumentListWithParamsFix = match x.ArgumentList with - | Some a -> fixParamArray symbol env a argumentList + | Some a -> fixParamArray symbol a argumentList | _-> argumentList - let tempVars, args = getReorderedParams argumentListWithParamsFix + let tempVars, args = readReorderedParams argumentListWithParamsFix let ctor = - Ctor (typ, getConstructor symbol, args) + Ctor (typ, sr.ReadConstructor symbol, args) |> List.foldBack (fun (v, e) b -> Let (v, e, b)) tempVars match x.Initializer with | Some init -> @@ -958,26 +1001,14 @@ type RoslynTransformer(env: Environment) = | InitializerExpressionKind.ObjectInitializerExpression -> Sequential expressions | InitializerExpressionKind.CollectionInitializerExpression -> - let cSymbol = env.SemanticModel.GetSymbolInfo(x.Node.Parent).Symbol :?> IMethodSymbol - let cTyp = getNamedType cSymbol.ContainingType - let addMethods = - cSymbol.ContainingType.GetMembers("Add").OfType() - let addM i = - let candidates = - addMethods - |> Seq.filter (fun m -> m.Parameters.Length = i) - |> Array.ofSeq - if candidates.Length > 1 then - failwith "TODO: overloaded Add method on collection initialization" - elif candidates.Length = 0 then - failwithf "Add method with %d parameters not found for collection initialization" i - else - candidates.[0] |> getMethod |> NonGeneric + let addSymbol = + env.SemanticModel.GetCollectionInitializerSymbolInfo(x.Node).Symbol :?> IMethodSymbol + let cTyp, addM = getTypeAndMethod addSymbol expressions |> List.map (fun item -> match IgnoreExprSourcePos item with | ComplexElement cItem -> - Call(Some (Var env.Initializing.Value), cTyp, addM (List.length cItem), cItem) - | _ -> Call(Some (Var env.Initializing.Value), cTyp, addM 1, [item]) + Call(Some (Var env.Initializing.Value), cTyp, addM, cItem) + | _ -> Call(Some (Var env.Initializing.Value), cTyp, addM, [item]) ) |> Sequential | InitializerExpressionKind.ArrayInitializerExpression -> // TODO: 2-dimensional @@ -1013,19 +1044,19 @@ type RoslynTransformer(env: Environment) = member this.TransformConstructorInitializer (x: ConstructorInitializerData) : _ = let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol let argumentList = x.ArgumentList |> this.TransformArgumentList - let argumentListWithParamsFix = fixParamArray symbol env x.ArgumentList argumentList - let tempVars, args = getReorderedParams argumentListWithParamsFix + let argumentListWithParamsFix = fixParamArray symbol x.ArgumentList argumentList + let tempVars, args = readReorderedParams argumentListWithParamsFix let initTempVars = List.foldBack (fun (v, e) b -> Let (v, e, b)) tempVars match x.Kind with | ConstructorInitializerKind.BaseConstructorInitializer -> - BaseInitializer (getNamedType symbol.ContainingType, getConstructor symbol, args, initTempVars) + BaseInitializer (sr.ReadNamedType symbol.ContainingType, sr.ReadConstructor symbol, args, initTempVars) | ConstructorInitializerKind.ThisConstructorInitializer -> - ThisInitializer (getConstructor symbol, args, initTempVars) + ThisInitializer (sr.ReadConstructor symbol, args, initTempVars) member this.TransformAccessorDeclaration (x: AccessorDeclarationData) : _ = let symbol = env.SemanticModel.GetDeclaredSymbol(x.Node) - let returnType = getType symbol.ReturnType - let parameterList = getParameters symbol + let returnType = sr.ReadType symbol.ReturnType + let parameterList = sr.ReadParameters symbol for p in parameterList do env.Parameters.Add(p.Symbol, (p.ParameterId, p.RefOrOut)) let body = x.Body |> Option.map (this.TransformBlock) @@ -1110,10 +1141,8 @@ type RoslynTransformer(env: Environment) = member this.TransformIncrOrDecr (node : ExpressionSyntax, operand) = let symbol = env.SemanticModel.GetSymbolInfo(node).Symbol :?> IMethodSymbol - let typ = getNamedType symbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod symbol) ma - + let typ, meth = getTypeAndMethod symbol + let e = IgnoreExprSourcePos operand let callOp v = Call(None, typ, meth, [ v ]) match e with @@ -1149,9 +1178,9 @@ type RoslynTransformer(env: Environment) = this.TransformIncrOrDecr(x.Node, operand) | _ -> let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol - let typ = getNamedType symbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod symbol) ma + let typ = sr.ReadNamedType symbol.ContainingType + let ma = symbol.TypeArguments |> Seq.map (sr.ReadType) |> List.ofSeq + let meth = Generic (sr.ReadMethod symbol) ma Call(None, typ, meth, [ operand ]) |> withExprSourcePos x.Node @@ -1230,7 +1259,7 @@ type RoslynTransformer(env: Environment) = member this.TransformCatchDeclaration (x: CatchDeclarationData) : _ = let symbol = env.SemanticModel.GetDeclaredSymbol(x.Node) - let typ = getType symbol.Type + let typ = sr.ReadType symbol.Type symbol, typ member this.TransformCatchFilterClause (x: CatchFilterClauseData) : _ = @@ -1242,7 +1271,7 @@ type RoslynTransformer(env: Environment) = member this.TransformForEachStatement (x: ForEachStatementData) : _ = let expression = x.Expression |> this.TransformExpression let symbol = env.SemanticModel.GetDeclaredSymbol(x.Node) - let typ = getType symbol.Type + let typ = sr.ReadType symbol.Type let v = Id.New symbol.Name env.Vars.Add(symbol, v) let statement = x.Statement |> this.TransformStatement @@ -1323,7 +1352,7 @@ type RoslynTransformer(env: Environment) = |> BreakStatement |> Continuation.FreeNestedGotos().TransformStatement let labels = Continuation.CollectLabels.Collect b - Function([id], Continuation.AsyncTransformer(labels, getAsyncReturnKind symbol).TransformMethodBody(b)) + Function([id], Continuation.AsyncTransformer(labels, sr.ReadAsyncReturnKind symbol).TransformMethodBody(b)) else Function([id], body) @@ -1344,7 +1373,7 @@ type RoslynTransformer(env: Environment) = |> BreakStatement |> Continuation.FreeNestedGotos().TransformStatement let labels = Continuation.CollectLabels.Collect b - Function(ids, Continuation.AsyncTransformer(labels, getAsyncReturnKind symbol).TransformMethodBody(b)) + Function(ids, Continuation.AsyncTransformer(labels, sr.ReadAsyncReturnKind symbol).TransformMethodBody(b)) else Function(ids, body) @@ -1431,11 +1460,7 @@ type RoslynTransformer(env: Environment) = if symbol.ContainingType.IsAnonymousType then ItemGet(getExpression().Value, Value (String (symbol.Name))) else - let typ = getNamedType symbol.ContainingType - let getM = symbol.GetMethod - let ma = getM.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod getM) ma - Call(getExpression(), typ, meth, []) // TODO property indexers + call symbol.GetMethod (getExpression()) [] // TODO property indexers | :? IMethodSymbol as symbol -> // TODO: this works for invocations but not always let expression = getExpression() @@ -1444,19 +1469,17 @@ type RoslynTransformer(env: Environment) = // if its static, left side has no real expression information defaultArg expression Undefined elif conv.IsMethodGroup then - let typ = getNamedType symbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod symbol) ma + let typ, meth = getTypeAndMethod symbol NewDelegate(expression, typ, meth) else failwithf "this.TransformIdentifierName: unhandled IMethodSymbol conversion: %A" conv | :? IFieldSymbol as symbol -> let expression = getExpression() - let typ = getNamedType symbol.ContainingType + let typ = sr.ReadNamedType symbol.ContainingType let f = symbol.Name FieldGet(expression, typ, f) | :? IEventSymbol as symbol -> let expression = getExpression() - let typ = getNamedType symbol.ContainingType + let typ = sr.ReadNamedType symbol.ContainingType let f = symbol.Name FieldGet(expression, typ, f) | _ -> @@ -1521,21 +1544,18 @@ type RoslynTransformer(env: Environment) = TODO x member this.TransformDefaultExpression (x: DefaultExpressionData) : _ = - let typ = env.SemanticModel.GetTypeInfo(x.Type.Node).Type |> getType + let typ = env.SemanticModel.GetTypeInfo(x.Type.Node).Type |> sr.ReadType DefaultValueOf typ member this.TransformCastExpression (x: CastExpressionData) : _ = // TODO type check -// let typ = env.SemanticModel.GetTypeInfo(x.Type.Node).Type |> getType +// let typ = env.SemanticModel.GetTypeInfo(x.Type.Node).Type |> sr.ReadType let expression = x.Expression |> this.TransformExpression let symbol = env.SemanticModel.GetSymbolInfo(x.Node).Symbol :?> IMethodSymbol if isNull symbol then expression else - let typ = getNamedType symbol.ContainingType - let ma = symbol.TypeArguments |> Seq.map getType |> List.ofSeq - let meth = Generic (getMethod symbol) ma - Call(None, typ, meth, [ expression ]) + call symbol None [ expression ] member this.TransformQueryExpression (x: QueryExpressionData) : _ = let expression = x.FromClause.Expression |> this.TransformExpression diff --git a/src/compiler/WebSharper.Compiler.CSharp/Main.fs b/src/compiler/WebSharper.Compiler.CSharp/Main.fs index 166ff4f0a..eeb2ee3d8 100644 --- a/src/compiler/WebSharper.Compiler.CSharp/Main.fs +++ b/src/compiler/WebSharper.Compiler.CSharp/Main.fs @@ -40,7 +40,11 @@ type WebSharperCSharpCompiler(logger) = | :? System.IO.PathTooLongException | :? System.Security.SecurityException -> p - member this.Compile (prevMeta, argv, path: string, warnOnly) = + member this.Compile (prevMeta, argv: seq, path: string, warnOnly) = + +// let argv = +// """/noconfig /nowarn:1701,1702 /nostdlib+ /warn:3 /doc:C:\repo\websharper.csharp\msbuild\\..\build\Release\WebSharper.CSharp.Tests.xml /define:TRACE /highentropyva+ /reference:C:\repo\websharper.csharp\build\Release\FSharp.Core.dll /reference:'C:\Program_Files_(x86)\Reference_Assemblies\Microsoft\Framework\.NETFramework\v4.5\Microsoft.CSharp.dll' /reference:'C:\Program_Files_(x86)\Reference_Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll' /reference:'C:\Program_Files_(x86)\Reference_Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll' /reference:'C:\Program_Files_(x86)\Reference_Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.dll' /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Collections.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Collections.Tests.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Control.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Core.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Core.JavaScript.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.InterfaceGenerator.Tests.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.JavaScript.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Main.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Testing.dll /reference:C:\repo\websharper.csharp\build\Release\WebSharper.Web.dll /debug:pdbonly /filealign:512 /optimize+ /out:obj\Release\WebSharper.CSharp.Tests.dll /ruleset:'C:\Program_Files_(x86)\Microsoft_Visual_Studio_14.0\Team_Tools\Static_Analysis_Tools\\Rule_Sets\MinimumRecommendedRules.ruleset' /subsystemversion:6.00 /target:library /utf8output Arithmetic.cs Delegate.cs Macro.cs Object.cs Remoting.cs Interop.cs Linq.cs Properties\AssemblyInfo.cs String.cs Syntax.cs Tests.cs 'C:\Users\András\AppData\Local\Temp\.NETFramework,Version=v4.5.AssemblyAttributes.cs'""" +// .Split([|' '|]) |> Array.map (fun s -> s.Replace('_', ' ').Replace(''', '"')) let started = System.DateTime.Now @@ -56,12 +60,14 @@ type WebSharperCSharpCompiler(logger) = |> Seq.map (fun s -> CSharpSyntaxTree.ParseText(File.ReadAllText s.Path, path = s.Path) ) - + let references = argv |> Seq.choose (fun a -> + //if a.StartsWith "/reference:\"" then Some a.[12 .. a.Length - 2] if a.StartsWith "/reference:" then Some a.[11 ..] else None - ) |> Seq.map (fun r -> + ) + |> Seq.map (fun r -> MetadataReference.CreateFromFile(r, MetadataReferenceProperties.Assembly) :> MetadataReference ) @@ -73,6 +79,14 @@ type WebSharperCSharpCompiler(logger) = parsedArgs.CompilationOptions ) + let firstError = + compilation.GetDiagnostics() |> Seq.tryFind (fun d -> d.Severity = DiagnosticSeverity.Error) + + match firstError with + | Some err -> + failwithf "C# compilation resulted in errors: %s" (err.GetMessage()) + | _ -> () + let ended = System.DateTime.Now logger <| sprintf "Creating compilation: %A" (ended - started) let started = ended @@ -120,3 +134,41 @@ type WebSharperCSharpCompiler(logger) = logger <| sprintf "Transforming: %A" (ended - started) comp + + member this.Compile (prevMeta, compilation: CSharpCompilation) = + let refMeta = + match prevMeta with + | None -> M.Info.Empty + | Some dep -> dep + + let comp = + WebSharper.Compiler.CSharp.ProjectReader.transformAssembly refMeta + compilation + + WebSharper.Compiler.Translator.DotNetToJavaScript.CompileFull comp + +// comp.VerifyRPCs() + +// let projDir = Path.GetDirectoryName path + +// let winfo = "WebSharper warning: " +// for posOpt, err in comp.Warnings do +// let pos = +// match posOpt with +// | Some p -> +// let file = (fullpath projDir p.FileName).Replace("/","\\") +// sprintf "%s(%d,%d,%d,%d): " file (fst p.Start) (snd p.Start) (fst p.End) (snd p.End) +// | None -> "" +// eprintfn "%s%s%s" pos winfo (NormalizeErrorString (err.ToString())) +// +// let einfo = if warnOnly then "WebSharper warning: ERROR " else "WebSharper error: " +// for posOpt, err in comp.Errors do +// let pos = +// match posOpt with +// | Some p -> +// let file = (fullpath projDir p.FileName).Replace("/","\\") +// sprintf "%s(%d,%d,%d,%d): " file (fst p.Start) (snd p.Start) (fst p.End) (snd p.End) +// | None -> "" +// eprintfn "%s%s%s" pos einfo (NormalizeErrorString (err.ToString())) + + comp diff --git a/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs b/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs index a74f4455d..d2e34c4d9 100644 --- a/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs +++ b/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs @@ -33,23 +33,16 @@ open WebSharper.Compiler open WebSharper.Compiler.NotResolved module A = WebSharper.Compiler.AttributeReader -type private N = NotResolvedMemberKind - -type CSharpAttributeReader() = - inherit A.AttributeReader() - override this.GetAssemblyName attr = attr.AttributeClass.ContainingAssembly.Name - override this.GetName attr = attr.AttributeClass.Name - override this.GetCtorArgs attr = attr.ConstructorArguments |> Seq.map (fun a -> a.Value) |> Array.ofSeq - override this.GetTypeDef o = CodeReader.getNamedTypeDefinition (o :?> INamedTypeSymbol) +module R = CodeReader -let attrReader = CSharpAttributeReader() +type private N = NotResolvedMemberKind type TypeWithAnnotation = | TypeWithAnnotation of INamedTypeSymbol * A.TypeAnnotation -let rec getAllTypeMembers rootAnnot (n: INamespaceSymbol) = +let rec private getAllTypeMembers (sr: R.SymbolReader) rootAnnot (n: INamespaceSymbol) = let rec withNested a (t: INamedTypeSymbol) = - let annot = attrReader.GetTypeAnnot(a, t.GetAttributes()) + let annot = sr.AttributeReader.GetTypeAnnot(a, t.GetAttributes()) seq { yield TypeWithAnnotation (t, annot) for nt in t.GetTypeMembers() do @@ -57,26 +50,26 @@ let rec getAllTypeMembers rootAnnot (n: INamespaceSymbol) = } Seq.append (n.GetTypeMembers() |> Seq.collect (withNested rootAnnot)) - (n.GetNamespaceMembers() |> Seq.collect (getAllTypeMembers rootAnnot)) + (n.GetNamespaceMembers() |> Seq.collect (getAllTypeMembers sr rootAnnot)) -let transformInterface (annot: A.TypeAnnotation) (intf: INamedTypeSymbol) = +let private transformInterface (sr: R.SymbolReader) (annot: A.TypeAnnotation) (intf: INamedTypeSymbol) = if intf.TypeKind <> TypeKind.Interface then None else let methodNames = ResizeArray() let def = match annot.ProxyOf with | Some d -> d - | _ -> CodeReader.getNamedTypeDefinition intf + | _ -> sr.ReadNamedTypeDefinition intf for m in intf.GetMembers() do - let mAnnot = attrReader.GetMemberAnnot(annot, m.GetAttributes()) + let mAnnot = sr.AttributeReader.GetMemberAnnot(annot, m.GetAttributes()) let md = - match CodeReader.getMember (m :?> IMethodSymbol) with + match sr.ReadMember (m :?> IMethodSymbol) with | Member.Method (_, md) -> md | _ -> failwith "invalid interface member" methodNames.Add(md, mAnnot.Name) Some (def, { StrongName = annot.Name - Extends = intf.Interfaces |> Seq.map (fun i -> CodeReader.getNamedTypeDefinition i) |> List.ofSeq + Extends = intf.Interfaces |> Seq.map (fun i -> sr.ReadNamedTypeDefinition i) |> List.ofSeq NotResolvedMethods = List.ofSeq methodNames } ) @@ -110,9 +103,9 @@ let hasYield st = visitor.VisitStatement st visitor.Found -let isResourceType (c: INamedTypeSymbol) = +let private isResourceType (sr: R.SymbolReader) (c: INamedTypeSymbol) = c.AllInterfaces |> Seq.exists (fun i -> - CodeReader.getNamedTypeDefinition i = Definitions.IResource + sr.ReadNamedTypeDefinition i = Definitions.IResource ) let delegateTy, delRemove = @@ -122,12 +115,14 @@ let delegateTy, delRemove = Reflection.ReadMethod mi | _ -> failwith "Expecting a Call pattern" -let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.TypeAnnotation) (cls: INamedTypeSymbol) = +let textSpans = R.textSpans + +let private transformClass (rcomp: CSharpCompilation) (sr: R.SymbolReader) (comp: Compilation) (annot: A.TypeAnnotation) (cls: INamedTypeSymbol) = if cls.TypeKind <> TypeKind.Class then None else - let thisDef = CodeReader.getNamedTypeDefinition cls + let thisDef = sr.ReadNamedTypeDefinition cls - if isResourceType cls then + if isResourceType sr cls then let thisRes = comp.Graph.AddOrLookupNode(ResourceNode thisDef) for req in annot.Requires do comp.Graph.AddEdge(thisRes, ResourceNode req) @@ -135,7 +130,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type else let inline cs model = - CodeReader.RoslynTransformer(CodeReader.Environment.New(model, comp)) + CodeReader.RoslynTransformer(CodeReader.Environment.New(model, comp, sr)) let clsMembers = ResizeArray() @@ -183,7 +178,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type match mem with | :? IPropertySymbol as p -> if p.IsAbstract then () else - let pAnnot = attrReader.GetMemberAnnot(annot, p.GetMethod.GetAttributes()) + let pAnnot = sr.AttributeReader.GetMemberAnnot(annot, p.GetMethod.GetAttributes()) match pAnnot.Kind with | Some A.MemberKind.JavaScript -> let decls = p.DeclaringSyntaxReferences @@ -210,14 +205,14 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type else inits.Add <| ItemSet(This, Value (String ("$" + p.Name)), b ) | setMeth -> - let setter = CodeReader.getMethod setMeth + let setter = sr.ReadMethod setMeth if p.IsStatic then staticInits.Add <| Call(None, cdef, NonGeneric setter, [ b ]) else inits.Add <| Call(Some This, cdef, NonGeneric setter, [ b ]) | _ -> () | :? IFieldSymbol as f -> - let fAnnot = attrReader.GetMemberAnnot(annot, f.GetAttributes()) + let fAnnot = sr.AttributeReader.GetMemberAnnot(annot, f.GetAttributes()) // TODO: check multiple declarations on the same line match fAnnot.Kind with | Some A.MemberKind.JavaScript -> @@ -264,7 +259,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type | MethodKind.EventRemove -> Seq.append (meth.AssociatedSymbol.GetAttributes()) (meth.GetAttributes()) | _ -> meth.GetAttributes() :> _ - let mAnnot = attrReader.GetMemberAnnot(annot, attrs) + let mAnnot = sr.AttributeReader.GetMemberAnnot(annot, attrs) // let syntaxAndModel = // lazy @@ -294,7 +289,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type match mAnnot.Kind with | Some A.MemberKind.Stub -> () | Some (A.MemberKind.Remote rp) -> - let def = CodeReader.getMember meth + let def = sr.ReadMember meth match def with | Member.Method (isInstance, mdef) -> let remotingKind = @@ -308,7 +303,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type addMethod mAnnot mdef (N.Remote(remotingKind, comp.GetRemoteHandle(), rp)) true Undefined | _ -> error "Only methods can be defined Remote" | Some kind -> - let memdef = CodeReader.getMember meth + let memdef = sr.ReadMember meth let getParsed() = let decl = meth.DeclaringSyntaxReferences if decl.Length > 0 then @@ -349,7 +344,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type |> Scoping.fix |> Continuation.FreeNestedGotos().TransformStatement let labels = Continuation.CollectLabels.Collect b - Continuation.AsyncTransformer(labels, CodeReader.getAsyncReturnKind meth).TransformMethodBody(b) + Continuation.AsyncTransformer(labels, sr.ReadAsyncReturnKind meth).TransformMethodBody(b) else b1 |> Scoping.fix |> Continuation.eliminateGotos { m with Body = b2 |> FixThisScope().Fix } match syntax with @@ -373,7 +368,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type Parameters = [] Body = Return body IsAsync = meth.IsAsync - ReturnType = CodeReader.getType meth.ReturnType + ReturnType = sr.ReadType meth.ReturnType } : CodeReader.CSharpMethod |> fixMethod | :? ConstructorDeclarationSyntax as syntax -> @@ -440,7 +435,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type ReturnType = Unchecked.defaultof } : CodeReader.CSharpMethod elif meth.MethodKind = MethodKind.EventAdd then - let args = meth.Parameters |> Seq.map CodeReader.getParameter |> List.ofSeq + let args = meth.Parameters |> Seq.map sr.ReadParameter |> List.ofSeq let getEv, setEv = let on = if meth.IsStatic then None else Some This FieldGet(on, NonGeneric def, meth.AssociatedSymbol.Name) @@ -452,10 +447,10 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type Parameters = args Body = ExprStatement b IsAsync = false - ReturnType = CodeReader.getType meth.ReturnType + ReturnType = sr.ReadType meth.ReturnType } : CodeReader.CSharpMethod elif meth.MethodKind = MethodKind.EventRemove then - let args = meth.Parameters |> Seq.map CodeReader.getParameter |> List.ofSeq + let args = meth.Parameters |> Seq.map sr.ReadParameter |> List.ofSeq let getEv, setEv = let on = if meth.IsStatic then None else Some This FieldGet(on, NonGeneric def, meth.AssociatedSymbol.Name) @@ -467,7 +462,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type Parameters = args Body = ExprStatement b IsAsync = false - ReturnType = CodeReader.getType meth.ReturnType + ReturnType = sr.ReadType meth.ReturnType } : CodeReader.CSharpMethod else match meth.MethodKind with @@ -582,7 +577,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type match implicitImplementations.TryFind meth with | Some impls -> for impl in impls do - let idef = CodeReader.getNamedTypeDefinition impl + let idef = sr.ReadNamedTypeDefinition impl let vars = mdef.Value.Parameters |> List.map (fun _ -> Id.New()) // TODO : correct generics Lambda(vars, Call(Some This, NonGeneric def, NonGeneric mdef, vars |> List.map Var)) @@ -628,7 +623,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type clsMembers.Add (NotResolvedMember.StaticConstructor b) for f in members.OfType() do - let mAnnot = attrReader.GetMemberAnnot(annot, f.GetAttributes()) + let mAnnot = sr.AttributeReader.GetMemberAnnot(annot, f.GetAttributes()) let nr = { StrongName = mAnnot.Name @@ -638,7 +633,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type clsMembers.Add (NotResolvedMember.Field (f.Name, nr)) for f in members.OfType() do - let mAnnot = attrReader.GetMemberAnnot(annot, f.GetAttributes()) + let mAnnot = sr.AttributeReader.GetMemberAnnot(annot, f.GetAttributes()) let nr = { StrongName = mAnnot.Name @@ -660,7 +655,7 @@ let transformClass (rcomp: CSharpCompilation) (comp: Compilation) (annot: A.Type def, { StrongName = strongName - BaseClass = cls.BaseType |> CodeReader.getNamedTypeDefinition |> ignoreSystemObject + BaseClass = cls.BaseType |> sr.ReadNamedTypeDefinition |> ignoreSystemObject Requires = annot.Requires Members = List.ofSeq clsMembers IsModule = cls.IsStatic // TODO: static classes @@ -674,8 +669,10 @@ let transformAssembly (refMeta : Info) (rcomp: CSharpCompilation) = let assembly = rcomp.Assembly + let sr = CodeReader.SymbolReader(comp) + let asmAnnot = - attrReader.GetAssemblyAnnot(assembly.GetAttributes()) + sr.AttributeReader.GetAssemblyAnnot(assembly.GetAttributes()) let rootTypeAnnot = asmAnnot.RootTypeAnnot @@ -683,11 +680,11 @@ let transformAssembly (refMeta : Info) (rcomp: CSharpCompilation) = comp.AssemblyRequires <- asmAnnot.Requires comp.SiteletDefinition <- asmAnnot.SiteletDefinition - comp.CustomTypesReflector <- Some A.reflectCustomType + comp.CustomTypesReflector <- Some (fun _ -> CustomTypeInfo.NotCustomType) - for TypeWithAnnotation(t, a) in getAllTypeMembers rootTypeAnnot assembly.GlobalNamespace do - transformInterface a t |> Option.iter comp.AddInterface - transformClass rcomp comp a t |> Option.iter comp.AddClass + for TypeWithAnnotation(t, a) in getAllTypeMembers sr rootTypeAnnot assembly.GlobalNamespace do + transformInterface sr a t |> Option.iter comp.AddInterface + transformClass rcomp sr comp a t |> Option.iter comp.AddClass comp.Resolve() diff --git a/src/compiler/WebSharper.Compiler.CSharp/Syntax.xml b/src/compiler/WebSharper.Compiler.CSharp/Syntax.xml index 9903c9e2b..fb695090d 100644 --- a/src/compiler/WebSharper.Compiler.CSharp/Syntax.xml +++ b/src/compiler/WebSharper.Compiler.CSharp/Syntax.xml @@ -591,11 +591,10 @@ - - - SyntaxToken representing the colon. - - + + + SyntaxToken representing the colon. + diff --git a/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fs b/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fs index be16bebc4..8b564c15e 100644 --- a/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fs +++ b/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fs @@ -51,20 +51,14 @@ type WebSharperTask() = member val WebSharperTypeScriptDeclaration = "" with get, set member val WebSharperErrorsAsWarnings = "" with get, set member val DocumentationFile = "" with get, set - member val CscCommandLineArgs : string = null with get, set - member val ZafirToolPath = "zafircs.exe" with get, set - member val DefineConstants = "" with get, set member val NoStandardLib = "" with get, set member val Sources : ITaskItem [] = Array.empty with get, set - - - [] - member val ItemOutput : ITaskItem [] = Array.empty with get, set - - [] - member val ReferenceCopyLocalPaths : ITaskItem [] = Array.empty with get, set + member val TargetType = "" with get, set + member val NoConfig = "" with get, set + member val DebugType = "" with get, set + member val SubsystemVersion = "" with get, set override this.ToolName = "zafircs.exe" @@ -73,9 +67,18 @@ type WebSharperTask() = override this.GenerateCommandLineCommands() = let builder = CommandLineBuilder() + if bool.TryParse this.NoConfig ||> (&&) then + builder.AppendSwitch "/noconfig" + if bool.TryParse this.NoStandardLib ||> (&&) then builder.AppendSwitch "/nostdlib+" + builder.AppendSwitchIfNotNull("/target:", this.TargetType) + + builder.AppendSwitchIfNotNull("/debug:", this.DebugType) + + builder.AppendSwitchIfNotNull("/subsystemversion:", this.SubsystemVersion) + builder.AppendSwitchIfNotNull("/doc:", this.DocumentationFile) builder.AppendSwitchIfNotNull("/out:", this.OutputAssembly) diff --git a/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fsi b/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fsi index b98ac8a9f..620bc556e 100644 --- a/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fsi +++ b/src/compiler/WebSharper.MSBuild.CSharp/WebSharperTask.fsi @@ -46,13 +46,12 @@ type WebSharperTask = member DefineConstants : string with get, set member NoStandardLib : string with get, set member Sources : ITaskItem [] with get, set - member CscCommandLineArgs : string with get, set /// Item input for item commands. member References : ITaskItem [] with get, set - /// Item output for item commands. - member ItemOutput : ITaskItem [] with get, set +// /// Item output for item commands. +// member ItemOutput : ITaskItem [] with get, set /// Path to an `.snk` strong name key file, if any. member KeyOriginatorFile : string with get, set @@ -95,4 +94,12 @@ type WebSharperTask = /// Specifies if .d.ts files are unpacked along with the .js output. member WebSharperTypeScriptDeclaration : string with get, set - member ZafirToolPath : string with get, set \ No newline at end of file + member ZafirToolPath : string with get, set + + member TargetType : string with get, set + + member NoConfig : string with get, set + + member DebugType : string with get, set + + member SubsystemVersion : string with get, set \ No newline at end of file diff --git a/tests/WebSharper.CSharp.Tests/Linq.cs b/tests/WebSharper.CSharp.Tests/Linq.cs index 1df6aafc1..54773fef7 100644 --- a/tests/WebSharper.CSharp.Tests/Linq.cs +++ b/tests/WebSharper.CSharp.Tests/Linq.cs @@ -315,7 +315,7 @@ public void ThenBy() public void Range() { Equal(Enumerable.Range(1, 6).ToArray(), arr, "Non-empty"); - Equal(Enumerable.Range(1, 0).ToArray(), empty, "Empty"); + Equal(System.Linq.Enumerable.Range(1, 0).ToArray(), empty, "Empty"); Raises((() => Enumerable.Range(1, -1)), "Negative count raises"); } diff --git a/tests/WebSharper.CSharp.Tests/Macro.cs b/tests/WebSharper.CSharp.Tests/Macro.cs index 567c4e9b8..5d13a7c70 100644 --- a/tests/WebSharper.CSharp.Tests/Macro.cs +++ b/tests/WebSharper.CSharp.Tests/Macro.cs @@ -28,15 +28,15 @@ public override MacroResult TranslateCall(MacroCall call) [JavaScript] public class MacroTest : TestCategory { - [Macro(typeof(AddMacro))] - public static int Add(int a, int b) => a + b; + //[Macro(typeof(AddMacro))] + //public static int Add(int a, int b) => a + b; - [Test] - public void AddMacro() - { - Equal(MacroTest.Add(1, 2), 3, "transformed"); - var x = 1; - Equal(MacroTest.Add(x, 2), 3, "fallback"); - } + //[Test] + //public void AddMacro() + //{ + // Equal(MacroTest.Add(1, 2), 3, "transformed"); + // var x = 1; + // Equal(MacroTest.Add(x, 2), 3, "fallback"); + //} } } diff --git a/tests/WebSharper.CSharp.Tests/String.cs b/tests/WebSharper.CSharp.Tests/String.cs index 328aa37d3..a8f2d502a 100644 --- a/tests/WebSharper.CSharp.Tests/String.cs +++ b/tests/WebSharper.CSharp.Tests/String.cs @@ -21,6 +21,10 @@ public override string ToString() [Test] public void Format() { + Equal(String.Format("xyz"), "xyz"); + Equal(String.Format("{0}", (object)"xyz"), "xyz"); + var xyz = "xyz"; + Equal(String.Format(xyz), "xyz"); var pricePerOunce = 17.36m; Equal(String.Format("The current price is {0} per ounce.", pricePerOunce), "The current price is 17.36 per ounce."); diff --git a/tests/WebSharper.CSharp.Tests/Syntax.cs b/tests/WebSharper.CSharp.Tests/Syntax.cs index 191ea8025..be1e6a39b 100644 --- a/tests/WebSharper.CSharp.Tests/Syntax.cs +++ b/tests/WebSharper.CSharp.Tests/Syntax.cs @@ -371,6 +371,7 @@ class MyNumber [Test] public void Conversions() { + Console.WriteLine("Running Conversions test.."); int intFromChar = 'a'; Equal(intFromChar, 97, "char to int implicit"); Equal((int)'a', 97, "char to int explicit"); @@ -382,7 +383,8 @@ public void Conversions() Equal(val, 13.0, "Custom implicit conversion out"); Equal((double)custom, 13.0, "Custom explicit conversion out"); MyNumber addTest = custom + 1; - Equal(addTest.Value, 14.0, "Operator overloading"); + Equal(addTest.Value, 14.0, "Operator overloading"); + JavaScript.Console.Log("Conversions test", "finished"); } [Test] diff --git a/tests/WebSharper.CSharp.Tests/Tests.cs b/tests/WebSharper.CSharp.Tests/Tests.cs index d2eb0bd7f..06be0ac2a 100644 --- a/tests/WebSharper.CSharp.Tests/Tests.cs +++ b/tests/WebSharper.CSharp.Tests/Tests.cs @@ -13,8 +13,8 @@ namespace WebSharper.CSharp.Tests [JavaScript, Test("C# Basic tests")] public class Tests : TestCategory { - [Generated(typeof(TestGenerator))] - public static void RunTests() { } + //[Generated(typeof(TestGenerator))] + //public static void RunTests() { } public string GetHelloWorld() { return "Hello " + "world!"; } public string HelloWorldProp => "Hello " + "world!"; @@ -105,6 +105,7 @@ public void DisposingGenerator() IsTrue(SeqDisposed); } +// [JavaScript(false)] public async Task GetOneAsync() { var o = Task.FromResult(1); @@ -157,10 +158,10 @@ public void InlineTest() Equal(InlineWithReturn(false), 2); } - [Test] - public async Task VariableScopingAsync() - { - //var res = 0; + //[Test] + //public async Task VariableScopingAsync() + //{ + // //var res = 0; //var adders = new List(); //for (var i = 0; i <= 5; i++) //{ @@ -169,7 +170,7 @@ public async Task VariableScopingAsync() //} //foreach (var adder in adders) adder(); //Equal(res, 21, "variable inside loop"); - } + //} [Test] public void VariableScoping() @@ -196,34 +197,34 @@ public void VariableScoping() Equal(res, 15, "variable inside loop"); } - [Test] - public void VariableScopingGoto() - { - //var res = 0; - //var adders = new List(); - //for (var i = 0; i <= 10; i++) - //{ - // if (i == 6) goto outOfLoop; - // var b = i; - // adders.Add(() => res += b); - //} - //outOfLoop: foreach (var adder in adders) adder(); - //Equal(res, 15, "goto from inside loop"); - } - - [Test] - public void VariableScopingBreak() - { - //var res = 0; - //var adders = new List(); - //for (var i = 0; i <= 10; i++) - //{ - // if (i == 6) break; - // var b = i; - // adders.Add(() => res += b); - //} - //foreach (var adder in adders) adder(); - //Equal(res, 15, "break inside loop"); - } + //[Test] + //public void VariableScopingGoto() + //{ + // //var res = 0; + // //var adders = new List(); + // //for (var i = 0; i <= 10; i++) + // //{ + // // if (i == 6) goto outOfLoop; + // // var b = i; + // // adders.Add(() => res += b); + // //} + // //outOfLoop: foreach (var adder in adders) adder(); + // //Equal(res, 15, "goto from inside loop"); + //} + + //[Test] + //public void VariableScopingBreak() + //{ + // //var res = 0; + // //var adders = new List(); + // //for (var i = 0; i <= 10; i++) + // //{ + // // if (i == 6) break; + // // var b = i; + // // adders.Add(() => res += b); + // //} + // //foreach (var adder in adders) adder(); + // //Equal(res, 15, "break inside loop"); + //} } } diff --git a/tests/WebSharper.CSharp.Tests/WebSharper.CSharp.Tests.csproj b/tests/WebSharper.CSharp.Tests/WebSharper.CSharp.Tests.csproj index 1b0f5fce4..7044f5dca 100644 --- a/tests/WebSharper.CSharp.Tests/WebSharper.CSharp.Tests.csproj +++ b/tests/WebSharper.CSharp.Tests/WebSharper.CSharp.Tests.csproj @@ -96,6 +96,18 @@ + + + + + + + + + + + + \ No newline at end of file