├── .editorconfig ├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── Microsoft.Language.Xml.sln ├── NuGet.config ├── README.md ├── appveyor.yml ├── benchmark └── Microsoft.Language.Xml.Benchmarks │ ├── Microsoft.Language.Xml.Benchmarks.csproj │ ├── ParserBenchmarks.cs │ ├── Program.cs │ └── XmlSnippets.cs ├── key.snk ├── language_xml_logo.png ├── src ├── Microsoft.Language.Xml.Editor │ ├── Classification │ │ ├── ClassificationTypeDefinitions.cs │ │ ├── Classifier.cs │ │ └── ClassifierProvider.cs │ ├── Comments │ │ └── CommentingService.cs │ ├── ContentType.cs │ ├── Microsoft.Language.Xml.Editor.csproj │ ├── Outlining │ │ ├── OutliningTagger.cs │ │ └── OutliningTaggerProvider.cs │ ├── Parsing │ │ └── ParserService.cs │ ├── SmartIndent │ │ ├── SmartIndent.cs │ │ └── SmartIndentProvider.cs │ ├── Tagging │ │ └── AbstractSyntaxTreeTagger.cs │ └── TextSnapshotBuffer.cs └── Microsoft.Language.Xml │ ├── AssemblyInfo.cs │ ├── Blender.cs │ ├── Buffer.cs │ ├── Classification │ ├── ClassificationTypeNames.cs │ ├── ClassifierVisitor.cs │ └── XmlClassificationTypes.cs │ ├── Comments │ └── CommentUtilities.cs │ ├── DiagnosticInfo.cs │ ├── ErrorFactory.cs │ ├── Extensions.cs │ ├── InternalSyntax │ ├── GreenNode.cs │ ├── GreenNodeExtensions.cs │ ├── NodeFlags.cs │ ├── SeparatedSyntaxList.cs │ ├── SeparatedSyntaxListBuilder.cs │ ├── SyntaxFactory.cs │ ├── SyntaxList.cs │ ├── SyntaxListBuilder.cs │ ├── SyntaxListBuilder`1.cs │ ├── SyntaxList`1.cs │ ├── SyntaxRewriter.cs │ ├── SyntaxVisitor.cs │ └── TriviaInfo.cs │ ├── Microsoft.Language.Xml.csproj │ ├── Parser.cs │ ├── PooledStringBuilder.cs │ ├── Scanner.cs │ ├── ScannerState.cs │ ├── StringBuffer.cs │ ├── Structure │ ├── INamedXmlNode.cs │ └── IXmlElement.cs │ ├── Syntax │ ├── BadTokenSyntax.cs │ ├── ChildSyntaxList.cs │ ├── ERRID.cs │ ├── IXmlElementSyntax.cs │ ├── KeywordSyntax.cs │ ├── PunctuationSyntax.cs │ ├── SeparatedSyntaxListBuilder`1.cs │ ├── SeparatedSyntaxList`1.cs │ ├── SkippedTokensTriviaSyntax.cs │ ├── SkippedTriviaBuilder.cs │ ├── SyntaxAnnotation.cs │ ├── SyntaxDiffer.cs │ ├── SyntaxFactory.cs │ ├── SyntaxKind.cs │ ├── SyntaxList.cs │ ├── SyntaxListBuilder.cs │ ├── SyntaxListBuilderExtensions.cs │ ├── SyntaxListBuilder`1.cs │ ├── SyntaxListPool.cs │ ├── SyntaxList`1.cs │ ├── SyntaxNode.Enumerators.cs │ ├── SyntaxNode.cs │ ├── SyntaxNodeExtensions.cs │ ├── SyntaxNodeRemover.cs │ ├── SyntaxReplacer.cs │ ├── SyntaxRewriter.cs │ ├── SyntaxSubKind.cs │ ├── SyntaxToken.cs │ ├── SyntaxTrivia.cs │ ├── SyntaxTriviaList.cs │ ├── SyntaxTriviaListBuilder.cs │ ├── SyntaxVisitor.cs │ ├── XmlAttributeSyntax.cs │ ├── XmlCDataSectionSyntax.cs │ ├── XmlCommentSyntax.cs │ ├── XmlContentExtensions.cs │ ├── XmlContext.cs │ ├── XmlDeclarationOptionSyntax.cs │ ├── XmlDeclarationSyntax.cs │ ├── XmlDocumentSyntax.cs │ ├── XmlElementEndTagSyntax.cs │ ├── XmlElementStartTagSyntax.cs │ ├── XmlElementSyntax.cs │ ├── XmlEmptyElementSyntax.cs │ ├── XmlEntityTokenSyntax.cs │ ├── XmlNameSyntax.cs │ ├── XmlNameTokenSyntax.cs │ ├── XmlNodeSyntax.cs │ ├── XmlPrefixSyntax.cs │ ├── XmlProcessingInstructionSyntax.cs │ ├── XmlStringSyntax.cs │ ├── XmlTextSyntax.cs │ └── XmlTextTokenSyntax.cs │ ├── TextChange.cs │ ├── TextChangeRange.cs │ ├── TextSpan.cs │ ├── Utilities │ ├── ArrayBuilder.cs │ ├── ArrayElement.cs │ ├── FirstTokenReplacer.cs │ ├── HashFunctions.cs │ ├── LastTokenReplacer.cs │ ├── Normalization.cs │ ├── ObjectPool.cs │ ├── SpecializedCollections.cs │ ├── StringTable.cs │ ├── SyntaxLocator.cs │ ├── SyntaxNodeCache.cs │ └── TextKeyedCache.cs │ ├── XmlCharType.cs │ ├── XmlExtensions.cs │ ├── XmlResources.Designer.cs │ └── XmlResources.resx ├── test ├── Microsoft.Language.Xml.Editor.Tests │ ├── Microsoft.Language.Xml.Editor.Tests.csproj │ ├── SyntaxReplacerTests.cs │ └── TestSmartIndent.cs └── Microsoft.Language.Xml.Tests │ ├── Microsoft.Language.Xml.Tests.csproj │ ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx │ ├── TestAnnotations.cs │ ├── TestApi.cs │ ├── TestClassifier.cs │ ├── TestComments.cs │ ├── TestDiagnostic.cs │ ├── TestIncremental.cs │ ├── TestModification.cs │ ├── TestParser.cs │ ├── TestSyntaxLocator.cs │ ├── TestTrivia.cs │ └── TestXml.xml └── version.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Baseline 7 | [*] 8 | charset = utf-8 9 | indent_style = space 10 | trim_trailing_whitespace = true 11 | max_line_length = 120 12 | 13 | # MSBuild 14 | [*.{csproj,proj,projitems,shproj,fsproj,target,props}] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | # XML config files 19 | [*.{config,nuspec,resx}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | # JSON files 24 | [*.json] 25 | indent_style = space 26 | indent_size = 2 27 | 28 | # Dotnet code style settings: 29 | [*.{cs,vb}] 30 | 31 | # Sort using and Import directives with System.* appearing first 32 | dotnet_sort_system_directives_first = true 33 | 34 | # CSharp code style settings: 35 | [*.cs] 36 | 37 | # spaces before parens 38 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 39 | csharp_space_between_method_call_name_and_opening_parenthesis = false 40 | csharp_space_after_keywords_in_control_flow_statements = true 41 | 42 | # Newline settings 43 | csharp_new_line_before_open_brace = all 44 | csharp_new_line_before_else = true 45 | csharp_new_line_before_catch = true 46 | csharp_new_line_before_finally = true 47 | csharp_new_line_before_members_in_object_initializers = true 48 | csharp_new_line_before_members_in_anonymous_types = true 49 | 50 | # Switch indentation 51 | csharp_indent_switch_labels = true 52 | 53 | # Prefer "var" everywhere it's apparent 54 | csharp_style_var_for_built_in_types = true:suggestion 55 | csharp_style_var_when_type_is_apparent = true:suggestion 56 | csharp_style_var_elsewhere = false:suggestion 57 | 58 | # Prefer method-like constructs to have a block body 59 | csharp_style_expression_bodied_methods = false:none 60 | csharp_style_expression_bodied_constructors = false:none 61 | csharp_style_expression_bodied_operators = false:none 62 | 63 | # Prefer property-like constructs to have an expression-body 64 | csharp_style_expression_bodied_properties = true:none 65 | csharp_style_expression_bodied_indexers = true:none 66 | csharp_style_expression_bodied_accessors = true:none 67 | 68 | # Suggest more modern language features when available 69 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 70 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 71 | csharp_style_inlined_variable_declaration = true:suggestion 72 | csharp_style_throw_expression = false:suggestion 73 | csharp_style_conditional_delegate_call = true:suggestion 74 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Don't mess with my line endings. 3 | ############################################################################### 4 | * -text -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [KirillOsenkov] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | *.binlog 10 | 11 | # User-specific files (MonoDevelop/Xamarin Studio) 12 | *.userprefs 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | x64/ 20 | x86/ 21 | build/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | 26 | # Visual Studo 2015 cache/options directory 27 | .vs/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | *_i.c 43 | *_p.c 44 | *_i.h 45 | *.ilk 46 | *.meta 47 | *.obj 48 | *.pch 49 | *.pdb 50 | *.pgc 51 | *.pgd 52 | *.rsp 53 | *.sbr 54 | *.tlb 55 | *.tli 56 | *.tlh 57 | *.tmp 58 | *.tmp_proj 59 | *.log 60 | *.vspscc 61 | *.vssscc 62 | .builds 63 | *.pidb 64 | *.svclog 65 | *.scc 66 | 67 | # Chutzpah Test files 68 | _Chutzpah* 69 | 70 | # Visual C++ cache files 71 | ipch/ 72 | *.aps 73 | *.ncb 74 | *.opensdf 75 | *.sdf 76 | *.cachefile 77 | 78 | # Visual Studio profiler 79 | *.psess 80 | *.vsp 81 | *.vspx 82 | 83 | # TFS 2012 Local Workspace 84 | $tf/ 85 | 86 | # Guidance Automation Toolkit 87 | *.gpState 88 | 89 | # ReSharper is a .NET coding add-in 90 | _ReSharper*/ 91 | *.[Rr]e[Ss]harper 92 | *.DotSettings.user 93 | 94 | # JustCode is a .NET coding addin-in 95 | .JustCode 96 | 97 | # TeamCity is a build add-in 98 | _TeamCity* 99 | 100 | # DotCover is a Code Coverage Tool 101 | *.dotCover 102 | 103 | # NCrunch 104 | _NCrunch_* 105 | .*crunch*.local.xml 106 | 107 | # MightyMoose 108 | *.mm.* 109 | AutoTest.Net/ 110 | 111 | # Web workbench (sass) 112 | .sass-cache/ 113 | 114 | # Installshield output folder 115 | [Ee]xpress/ 116 | 117 | # DocProject is a documentation generator add-in 118 | DocProject/buildhelp/ 119 | DocProject/Help/*.HxT 120 | DocProject/Help/*.HxC 121 | DocProject/Help/*.hhc 122 | DocProject/Help/*.hhk 123 | DocProject/Help/*.hhp 124 | DocProject/Help/Html2 125 | DocProject/Help/html 126 | 127 | # Click-Once directory 128 | publish/ 129 | 130 | # Publish Web Output 131 | *.[Pp]ublish.xml 132 | *.azurePubxml 133 | # TODO: Comment the next line if you want to checkin your web deploy settings 134 | # but database connection strings (with potential passwords) will be unencrypted 135 | *.pubxml 136 | *.publishproj 137 | 138 | # NuGet Packages 139 | *.nupkg 140 | # The packages folder can be ignored because of Package Restore 141 | **/packages/* 142 | # except build/, which is used as an MSBuild target. 143 | !**/packages/build/ 144 | # Uncomment if necessary however generally it will be regenerated when needed 145 | #!**/packages/repositories.config 146 | 147 | # Windows Azure Build Output 148 | csx/ 149 | *.build.csdef 150 | 151 | # Windows Store app package directory 152 | AppPackages/ 153 | 154 | # Others 155 | *.[Cc]ache 156 | ClientBin/ 157 | [Ss]tyle[Cc]op.* 158 | ~$* 159 | *~ 160 | *.dbmdl 161 | *.dbproj.schemaview 162 | *.pfx 163 | *.publishsettings 164 | node_modules/ 165 | bower_components/ 166 | 167 | # RIA/Silverlight projects 168 | Generated_Code/ 169 | 170 | # Backup & report files from converting an old project file 171 | # to a newer Visual Studio version. Backup files are not needed, 172 | # because we have git ;-) 173 | _UpgradeReport_Files/ 174 | Backup*/ 175 | UpgradeLog*.XML 176 | UpgradeLog*.htm 177 | 178 | # SQL Server files 179 | *.mdf 180 | *.ldf 181 | 182 | # Business Intelligence projects 183 | *.rdl.data 184 | *.bim.layout 185 | *.bim_*.settings 186 | 187 | # Microsoft Fakes 188 | FakesAssemblies/ 189 | 190 | # Node.js Tools for Visual Studio 191 | .ntvs_analysis.dat 192 | 193 | # Visual Studio 6 build log 194 | *.plg 195 | 196 | # Visual Studio 6 workspace options file 197 | *.opt 198 | /NuGet.exe 199 | -------------------------------------------------------------------------------- /Microsoft.Language.Xml.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34321.82 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution items", "{9D11B9F6-7DFB-41A6-ACA9-E5DE89C02ED4}" 7 | ProjectSection(SolutionItems) = preProject 8 | .editorconfig = .editorconfig 9 | appveyor.yml = appveyor.yml 10 | NuGet.config = NuGet.config 11 | EndProjectSection 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79B2600B-6786-460B-85D7-1CB16DC9AE06}" 14 | EndProject 15 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Language.Xml", "src\Microsoft.Language.Xml\Microsoft.Language.Xml.csproj", "{2989FBE6-194F-46C9-8EF4-022F62519C9A}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Language.Xml.Editor", "src\Microsoft.Language.Xml.Editor\Microsoft.Language.Xml.Editor.csproj", "{C432B014-61DD-4F97-9D6F-966C1021F535}" 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{07F190D5-06B2-4F4C-B000-6EBE042AB43A}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Language.Xml.Tests", "test\Microsoft.Language.Xml.Tests\Microsoft.Language.Xml.Tests.csproj", "{20B89FC2-53BD-41AF-BFE9-A029362FE49C}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Language.Xml.Editor.Tests", "test\Microsoft.Language.Xml.Editor.Tests\Microsoft.Language.Xml.Editor.Tests.csproj", "{E3CEC50E-40AF-4E53-93AF-D7E2F2C9FF10}" 24 | EndProject 25 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmark", "benchmark", "{5D08C6A7-C10A-4CFD-8B6C-A278DC6C2701}" 26 | EndProject 27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Language.Xml.Benchmarks", "benchmark\Microsoft.Language.Xml.Benchmarks\Microsoft.Language.Xml.Benchmarks.csproj", "{7A2B7E87-9B54-437D-A7A1-B6F38BEA0819}" 28 | EndProject 29 | Global 30 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 31 | Debug|Any CPU = Debug|Any CPU 32 | Release|Any CPU = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 35 | {2989FBE6-194F-46C9-8EF4-022F62519C9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {2989FBE6-194F-46C9-8EF4-022F62519C9A}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {2989FBE6-194F-46C9-8EF4-022F62519C9A}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {2989FBE6-194F-46C9-8EF4-022F62519C9A}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {C432B014-61DD-4F97-9D6F-966C1021F535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {C432B014-61DD-4F97-9D6F-966C1021F535}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {C432B014-61DD-4F97-9D6F-966C1021F535}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {C432B014-61DD-4F97-9D6F-966C1021F535}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {20B89FC2-53BD-41AF-BFE9-A029362FE49C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {20B89FC2-53BD-41AF-BFE9-A029362FE49C}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {20B89FC2-53BD-41AF-BFE9-A029362FE49C}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {20B89FC2-53BD-41AF-BFE9-A029362FE49C}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {E3CEC50E-40AF-4E53-93AF-D7E2F2C9FF10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {E3CEC50E-40AF-4E53-93AF-D7E2F2C9FF10}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {E3CEC50E-40AF-4E53-93AF-D7E2F2C9FF10}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {E3CEC50E-40AF-4E53-93AF-D7E2F2C9FF10}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {7A2B7E87-9B54-437D-A7A1-B6F38BEA0819}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {7A2B7E87-9B54-437D-A7A1-B6F38BEA0819}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {7A2B7E87-9B54-437D-A7A1-B6F38BEA0819}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {7A2B7E87-9B54-437D-A7A1-B6F38BEA0819}.Release|Any CPU.Build.0 = Release|Any CPU 55 | EndGlobalSection 56 | GlobalSection(SolutionProperties) = preSolution 57 | HideSolutionNode = FALSE 58 | EndGlobalSection 59 | GlobalSection(NestedProjects) = preSolution 60 | {2989FBE6-194F-46C9-8EF4-022F62519C9A} = {79B2600B-6786-460B-85D7-1CB16DC9AE06} 61 | {C432B014-61DD-4F97-9D6F-966C1021F535} = {79B2600B-6786-460B-85D7-1CB16DC9AE06} 62 | {20B89FC2-53BD-41AF-BFE9-A029362FE49C} = {07F190D5-06B2-4F4C-B000-6EBE042AB43A} 63 | {E3CEC50E-40AF-4E53-93AF-D7E2F2C9FF10} = {07F190D5-06B2-4F4C-B000-6EBE042AB43A} 64 | {7A2B7E87-9B54-437D-A7A1-B6F38BEA0819} = {5D08C6A7-C10A-4CFD-8B6C-A278DC6C2701} 65 | EndGlobalSection 66 | EndGlobal 67 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XmlParser 2 | 3 | ![logo image](http://neteril.org/~jeremie/language_xml_logo.png) 4 | 5 | [![Build status](https://ci.appveyor.com/api/projects/status/5ur9sv9bp4nr7a3n?svg=true)](https://ci.appveyor.com/project/KirillOsenkov/xmlparser) 6 | [![NuGet package](https://img.shields.io/nuget/v/GuiLabs.Language.Xml.svg)](https://nuget.org/packages/GuiLabs.Language.Xml) 7 | [![NuGet package for VS Editor](https://img.shields.io/nuget/v/GuiLabs.Language.Xml.Editor.svg)](https://nuget.org/packages/GuiLabs.Language.Xml.Editor) 8 | 9 | A Roslyn-inspired full-fidelity XML parser with no dependencies and a simple Visual Studio XML language service. 10 | 11 | * The parser produces a **full-fidelity** syntax tree, meaning every character of the source text is represented in the tree. The tree covers the entire source text. 12 | * The parser has **no dependencies** and can easily be made portable. I would appreciate a high quality pull request making the parser portable. 13 | * The parser is based on the section of the Roslyn VB parser that parses XML literals. The Roslyn code is ported to C# and is made standalone. 14 | * The parser is **error-tolerant**. It will still produce a full tree even from invalid XML with missing tags, extra invalid text, etc. Missing and skipped tokens are still represented in the tree. 15 | * The resulting tree is **immutable** and follows Roslyn's [green/red separation](https://blogs.msdn.microsoft.com/ericlippert/2012/06/08/persistence-facades-and-roslyns-red-green-trees/) for maximum reusability of nodes. 16 | * The parser has basic support for **incrementality**. Given a previous constructed tree and a list of changes it will try to reuse existing nodes and only re-create what is necessary. 17 | * This library is more **low-level** than XLinq (for instance XLinq doesn't seem to represent whitespace around attributes). Also it has no idea about XML namespaces and just tells you what's in the source text (whereas in XLinq there's too much ceremony around XML namespaces). 18 | 19 | This is work in progress and by no means complete. Specifically: 20 | * XML DTD is not supported (Roslyn didn't support it either) 21 | * Code wasn't tuned for performance and allocations, I'm sure a lot can be done to reduce memory consumption by the resulting tree. It should be pretty efficient though. 22 | * We reserve the right to accept only very high quality pull requests. We have very limited time to work on this so I ask everybody to please respect that. 23 | 24 | ## Download from NuGet: 25 | * [GuiLabs.Language.Xml](https://www.nuget.org/packages/GuiLabs.Language.Xml) 26 | * [GuiLabs.Language.Xml.Editor](https://www.nuget.org/packages/GuiLabs.Language.Xml.Editor) 27 | 28 | ## Try it! 29 | 30 | https://xmlsyntaxvisualizer.azurewebsites.net/index.html 31 | 32 | The above app leverages the parser and can help you visualize the resulting syntax tree generated from an XML document. 33 | 34 | Code is available at https://github.com/garuma/XmlSyntaxVisualizer 35 | C# UWP example at https://github.com/michael-hawker/XmlSyntaxVisualizerUWP 36 | 37 | Also see the blog post: 38 | https://blog.neteril.org/blog/2018/03/21/xml-parsing-roslyn/ 39 | 40 | Resources about Immutable Syntax Trees: 41 | https://github.com/KirillOsenkov/Bliki/wiki/Roslyn-Immutable-Trees 42 | 43 | ## FAQ: 44 | 45 | ### How to find a node in the tree given a position in the source text? 46 | https://github.com/KirillOsenkov/XmlParser/blob/master/src/Microsoft.Language.Xml/Utilities/SyntaxLocator.cs#L24 47 | 48 | ``` 49 | SyntaxLocator.FindNode(SyntaxNode node, int position); 50 | ``` 51 | 52 | ### How to replace a node in the tree 53 | 54 | ```csharp 55 | var original = """ 56 | 57 | 58 | net8.0 59 | 60 | 61 | """; 62 | 63 | var expected = """ 64 | 65 | 66 | net9.0 67 | 68 | 69 | """; 70 | 71 | XmlDocumentSyntax root = Parser.ParseText(original); 72 | XmlElementSyntax syntaxToReplace = root 73 | .Descendants() 74 | .OfType() 75 | .Single(n => n.Name == "TargetFramework"); 76 | SyntaxNode textSyntaxToReplace = syntaxToReplace.Content.Single(); 77 | 78 | XmlTextSyntax content = SyntaxFactory.XmlText(SyntaxFactory.XmlTextLiteralToken("net9.0", null, null)); 79 | 80 | root = root.ReplaceNode(textSyntaxToReplace, content); 81 | 82 | Assert.Equal(expected, root.ToFullString()); 83 | ``` 84 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.2.{build} 2 | image: Visual Studio 2022 3 | before_build: 4 | - cmd: dotnet restore 5 | build: 6 | project: Microsoft.Language.Xml.sln 7 | parallel: true 8 | verbosity: minimal 9 | -------------------------------------------------------------------------------- /benchmark/Microsoft.Language.Xml.Benchmarks/Microsoft.Language.Xml.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | Microsoft.Language.Xml.Benchmarks 5 | net472;net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /benchmark/Microsoft.Language.Xml.Benchmarks/ParserBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Jobs; 3 | 4 | namespace Microsoft.Language.Xml.Benchmarks; 5 | 6 | [MemoryDiagnoser] 7 | [SimpleJob(RuntimeMoniker.Net472, id: ".NET Framework")] 8 | [SimpleJob(RuntimeMoniker.Net80, id: "Modern .NET")] 9 | public class ParserBenchmarks 10 | { 11 | private Buffer textBuffer; 12 | 13 | [GlobalSetup] 14 | public void Setup() 15 | { 16 | textBuffer = new StringBuffer(XmlSnippets.LongAndroidLayoutXml); 17 | } 18 | 19 | [Benchmark] 20 | public void ParseLongXml() => Parser.Parse(textBuffer); 21 | } 22 | -------------------------------------------------------------------------------- /benchmark/Microsoft.Language.Xml.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | using Microsoft.Language.Xml.Benchmarks; 3 | 4 | BenchmarkRunner.Run(); 5 | -------------------------------------------------------------------------------- /key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KirillOsenkov/XmlParser/57739b0cc45178eea0461a21386f73eb0695d1e2/key.snk -------------------------------------------------------------------------------- /language_xml_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KirillOsenkov/XmlParser/57739b0cc45178eea0461a21386f73eb0695d1e2/language_xml_logo.png -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Classification/Classifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Microsoft.VisualStudio.Text; 5 | using Microsoft.VisualStudio.Text.Classification; 6 | 7 | namespace Microsoft.Language.Xml.Editor 8 | { 9 | public class Classifier : AbstractSyntaxTreeTagger, IClassifier 10 | { 11 | private static readonly IList emptySpanList = new ClassificationSpan[0]; 12 | 13 | private readonly IClassificationType[] types; 14 | 15 | public event EventHandler ClassificationChanged; 16 | 17 | public Classifier(IClassificationType[] types, ParserService parserService) 18 | : base(parserService) 19 | { 20 | this.types = types; 21 | } 22 | 23 | public IList GetClassificationSpans(SnapshotSpan span) 24 | { 25 | // don't classify documents larger than 5 MB, arbitrary large number 26 | if (span.Snapshot.Length > 5000000) 27 | { 28 | return emptySpanList; 29 | } 30 | 31 | var task = parserService.GetSyntaxTree(span.Snapshot); 32 | 33 | // wait for 100 milliseconds to see if we're lucky and it finishes before that 34 | // this helps significantly reduce flicker since we're not going to clear and re-add all tags on every keystroke 35 | task.Wait(100); 36 | 37 | if (task.Status == TaskStatus.RanToCompletion) 38 | { 39 | var root = task.Result; 40 | var spans = new List(); 41 | ClassifierVisitor.Visit( 42 | root, 43 | span.Start, 44 | span.Length, 45 | (start, length, node, xmlClassification) => spans.Add( 46 | new ClassificationSpan( 47 | new SnapshotSpan( 48 | span.Snapshot, 49 | start, 50 | length), 51 | types[(int)xmlClassification]))); 52 | return spans; 53 | } 54 | 55 | task.ContinueWith(t => 56 | { 57 | RaiseClassificationChanged(span.Snapshot); 58 | }, TaskContinuationOptions.OnlyOnRanToCompletion); 59 | 60 | return emptySpanList; 61 | } 62 | 63 | private void RaiseClassificationChanged(ITextSnapshot snapshot) 64 | { 65 | var handler = ClassificationChanged; 66 | if (handler != null) 67 | { 68 | handler(this, new ClassificationChangedEventArgs(new SnapshotSpan(snapshot, 0, snapshot.Length))); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Classification/ClassifierProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Classification; 4 | using Microsoft.VisualStudio.Utilities; 5 | 6 | namespace Microsoft.Language.Xml.Editor 7 | { 8 | [Export(typeof(IClassifierProvider))] 9 | [ContentType("xml")] 10 | public class ClassifierProvider : IClassifierProvider 11 | { 12 | private readonly ParserService parserService; 13 | private IClassificationType[] types; 14 | 15 | [ImportingConstructor] 16 | public ClassifierProvider(IClassificationTypeRegistryService classificationTypeRegistryService, ParserService parserService) 17 | { 18 | types = new IClassificationType[] 19 | { 20 | classificationTypeRegistryService.GetClassificationType("text"), 21 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlAttributeName), 22 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlAttributeQuotes), 23 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlAttributeValue), 24 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlCDataSection), 25 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlComment), 26 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlDelimiter), 27 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlEntityReference), 28 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlName), 29 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlProcessingInstruction), 30 | classificationTypeRegistryService.GetClassificationType(ClassificationTypeNames.XmlText), 31 | }; 32 | this.parserService = parserService; 33 | } 34 | 35 | public IClassifier GetClassifier(ITextBuffer textBuffer) 36 | { 37 | return new Classifier(types, parserService); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/ContentType.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Utilities; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | public class ContentType 7 | { 8 | public const string Xml = "xml"; 9 | 10 | [Export] 11 | [Name(Xml)] 12 | [BaseDefinition("text")] 13 | public static readonly ContentTypeDefinition XmlContentTypeDefinition = null; 14 | 15 | [Export] 16 | [FileExtension(".xml")] 17 | [ContentType(Xml)] 18 | internal static readonly FileExtensionToContentTypeDefinition XmlFileExtension = null; 19 | 20 | [Export] 21 | [FileExtension(".csproj")] 22 | [ContentType(Xml)] 23 | internal static readonly FileExtensionToContentTypeDefinition CsprojFileExtension = null; 24 | 25 | [Export] 26 | [FileExtension(".vbproj")] 27 | [ContentType(Xml)] 28 | internal static readonly FileExtensionToContentTypeDefinition VbprojFileExtension = null; 29 | 30 | [Export] 31 | [FileExtension(".nuspec")] 32 | [ContentType(Xml)] 33 | internal static readonly FileExtensionToContentTypeDefinition NuspecFileExtension = null; 34 | 35 | [Export] 36 | [FileExtension(".props")] 37 | [ContentType(Xml)] 38 | internal static readonly FileExtensionToContentTypeDefinition PropsFileExtension = null; 39 | 40 | [Export] 41 | [FileExtension(".targets")] 42 | [ContentType(Xml)] 43 | internal static readonly FileExtensionToContentTypeDefinition TargetsFileExtension = null; 44 | 45 | [Export] 46 | [FileExtension(".settings")] 47 | [ContentType(Xml)] 48 | internal static readonly FileExtensionToContentTypeDefinition SettingsFileExtension = null; 49 | 50 | [Export] 51 | [FileExtension(".proj")] 52 | [ContentType(Xml)] 53 | internal static readonly FileExtensionToContentTypeDefinition ProjFileExtension = null; 54 | 55 | [Export] 56 | [FileExtension(".config")] 57 | [ContentType(Xml)] 58 | internal static readonly FileExtensionToContentTypeDefinition ConfigFileExtension = null; 59 | 60 | [Export] 61 | [FileExtension(".vsixmanifest")] 62 | [ContentType(Xml)] 63 | internal static readonly FileExtensionToContentTypeDefinition VsixmanifestFileExtension = null; 64 | 65 | [Export] 66 | [FileExtension(".dgml")] 67 | [ContentType(Xml)] 68 | internal static readonly FileExtensionToContentTypeDefinition DgmlFileExtension = null; 69 | 70 | [Export] 71 | [FileExtension(".xaml")] 72 | [ContentType(Xml)] 73 | internal static readonly FileExtensionToContentTypeDefinition XamlFileExtension = null; 74 | 75 | [Export] 76 | [FileExtension(".resx")] 77 | [ContentType(Xml)] 78 | internal static readonly FileExtensionToContentTypeDefinition ResxFileExtension = null; 79 | } 80 | } -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Microsoft.Language.Xml.Editor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Microsoft.Language.Xml.Editor 4 | net472 5 | true 6 | $([MSBuild]::IsOSPlatform('Windows')) 7 | embedded 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | True 26 | GuiLabs.Language.Xml.Editor 27 | Microsoft 28 | Microsoft 29 | A simple XML language service for the Visual Studio editor 30 | Currently includes a classifier, outlining and smart indent. 31 | Apache-2.0 32 | https://github.com/KirillOsenkov/XmlParser 33 | https://github.com/KirillOsenkov/XmlParser 34 | Xml Parser LanguageService Classifier VS VisualStudio Editor 35 | language_xml_logo.png 36 | true 37 | snupkg 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | True 48 | ..\..\key.snk 49 | False 50 | WPF;$(DefineConstants) 51 | 52 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Outlining/OutliningTagger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.VisualStudio.Text; 6 | using Microsoft.VisualStudio.Text.Tagging; 7 | 8 | namespace Microsoft.Language.Xml.Editor 9 | { 10 | public class OutliningTagger : AbstractSyntaxTreeTagger, ITagger 11 | { 12 | private static readonly IEnumerable> emptyTagList = Enumerable.Empty>(); 13 | 14 | private ITextBuffer buffer; 15 | private OutliningTaggerProvider outliningTaggerProvider; 16 | 17 | public OutliningTagger(OutliningTaggerProvider outliningTaggerProvider, ITextBuffer buffer) 18 | : base(outliningTaggerProvider.ParserService) 19 | { 20 | this.outliningTaggerProvider = outliningTaggerProvider; 21 | this.buffer = buffer; 22 | } 23 | 24 | public event EventHandler TagsChanged; 25 | 26 | public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) 27 | { 28 | if (spans.Count == 0) 29 | { 30 | return emptyTagList; 31 | } 32 | 33 | var snapshot = spans[0].Snapshot; 34 | 35 | var task = parserService.GetSyntaxTree(snapshot); 36 | 37 | // wait for 100 milliseconds to see if we're lucky and it finishes before that 38 | // this helps significantly reduce flicker since we're not going to clear and re-add all tags on every keystroke 39 | task.Wait(100); 40 | 41 | if (task.Status == TaskStatus.RanToCompletion) 42 | { 43 | var root = task.Result; 44 | var elementSpans = new List>(); 45 | CollectElementSpans(root, elementSpans, 0); 46 | var tagSpans = new List>(); 47 | foreach (var span in elementSpans) 48 | { 49 | if (snapshot.GetLineNumberFromPosition(span.Item1.Start) < snapshot.GetLineNumberFromPosition(span.Item1.End)) 50 | { 51 | tagSpans.Add(new TagSpan( 52 | new SnapshotSpan(snapshot, span.Item1), 53 | new OutliningRegionTag(span.Item2, span.Item2))); 54 | } 55 | } 56 | 57 | return tagSpans; 58 | } 59 | 60 | task.ContinueWith(t => 61 | { 62 | RaiseTagsChanged(snapshot); 63 | }, TaskContinuationOptions.OnlyOnRanToCompletion); 64 | 65 | return emptyTagList; 66 | } 67 | 68 | private void CollectElementSpans(SyntaxNode node, List> spans, int start) 69 | { 70 | if (node is IXmlElement) 71 | { 72 | var leading = node.GetLeadingTriviaWidth(); 73 | var trailing = node.GetTrailingTriviaWidth(); 74 | spans.Add(Tuple.Create( 75 | new Span(start + leading, node.FullWidth - leading - trailing), 76 | "<" + (node as IXmlElement).Name + ">")); 77 | } 78 | 79 | foreach (var child in node.ChildNodes) 80 | { 81 | CollectElementSpans(child, spans, start); 82 | start += child.FullWidth; 83 | } 84 | } 85 | 86 | private void RaiseTagsChanged(ITextSnapshot snapshot) 87 | { 88 | TagsChanged?.Invoke( 89 | this, 90 | new SnapshotSpanEventArgs( 91 | new SnapshotSpan(snapshot, 0, snapshot.Length))); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Outlining/OutliningTaggerProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Tagging; 5 | using Microsoft.VisualStudio.Utilities; 6 | 7 | namespace Microsoft.Language.Xml.Editor 8 | { 9 | [Export(typeof(ITaggerProvider))] 10 | [TagType(typeof(IOutliningRegionTag))] 11 | [ContentType(ContentType.Xml)] 12 | public class OutliningTaggerProvider : ITaggerProvider 13 | { 14 | [Import] 15 | public ParserService ParserService { get; set; } 16 | 17 | public ITagger CreateTagger(ITextBuffer buffer) where T : ITag 18 | { 19 | Func> factory = () => new OutliningTagger(this, buffer) as ITagger; 20 | return buffer.Properties.GetOrCreateSingletonProperty(factory); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Parsing/ParserService.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Runtime.CompilerServices; 3 | using System.Threading.Tasks; 4 | using Microsoft.VisualStudio.Text; 5 | 6 | namespace Microsoft.Language.Xml.Editor 7 | { 8 | [Export] 9 | public class ParserService 10 | { 11 | public Task GetSyntaxTree(ITextSnapshot textSnapshot) 12 | { 13 | var textBuffer = textSnapshot.TextBuffer; 14 | 15 | lock (textBuffer) 16 | { 17 | ConditionalWeakTable> textSnapshotToSyntaxRootMap; 18 | Task syntaxRootTask; 19 | 20 | if (!textBuffer.Properties.TryGetProperty(typeof(ParserService), out textSnapshotToSyntaxRootMap)) 21 | { 22 | textSnapshotToSyntaxRootMap = new ConditionalWeakTable>(); 23 | textBuffer.Properties.AddProperty(typeof(ParserService), textSnapshotToSyntaxRootMap); 24 | } 25 | else if (textSnapshotToSyntaxRootMap.TryGetValue(textSnapshot, out syntaxRootTask)) 26 | { 27 | return syntaxRootTask; 28 | } 29 | 30 | syntaxRootTask = Task.Run(() => Parse(textSnapshot)); 31 | textSnapshotToSyntaxRootMap.Add(textSnapshot, syntaxRootTask); 32 | 33 | return syntaxRootTask; 34 | } 35 | } 36 | 37 | public XmlNodeSyntax TryGetSyntaxTree(ITextSnapshot textSnapshot, int timeoutInMilliseconds = 100) 38 | { 39 | var task = GetSyntaxTree(textSnapshot); 40 | if (!task.Wait(timeoutInMilliseconds)) 41 | { 42 | return null; 43 | } 44 | 45 | return task.Result; 46 | } 47 | 48 | private static XmlNodeSyntax Parse(ITextSnapshot snapshot) 49 | { 50 | return Parser.Parse(new TextSnapshotBuffer(snapshot)); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/SmartIndent/SmartIndent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using Microsoft.VisualStudio.Text.Editor; 3 | 4 | namespace Microsoft.Language.Xml.Editor 5 | { 6 | public class SmartIndent : ISmartIndent 7 | { 8 | private ITextView textView; 9 | private readonly ParserService parserService; 10 | private int indentSize; 11 | 12 | public SmartIndent(ITextView textView, ParserService parserService) 13 | { 14 | this.textView = textView; 15 | this.parserService = parserService; 16 | } 17 | 18 | public int? GetDesiredIndentation(ITextSnapshotLine line) 19 | { 20 | var snapshot = line.Snapshot; 21 | var treeTask = parserService.GetSyntaxTree(snapshot); 22 | 23 | indentSize = textView.Options.GetOptionValue(DefaultOptions.IndentSizeOptionId); 24 | 25 | treeTask.Wait(100); 26 | 27 | if (!treeTask.IsCompleted) 28 | { 29 | return null; 30 | } 31 | 32 | var root = treeTask.Result; 33 | var lineStartPosition = line.Start.Position; 34 | var indent = FindTotalParentChainIndent( 35 | root, 36 | lineStartPosition, 37 | currentPosition: 0, 38 | indent: 0, 39 | indentSize: indentSize); 40 | return indent; 41 | } 42 | 43 | public static int FindTotalParentChainIndent(SyntaxNode node, int position, int currentPosition, int indent, int indentSize = 2) 44 | { 45 | var leading = node.GetLeadingTriviaWidth(); 46 | var trailing = node.GetTrailingTriviaWidth(); 47 | var fullWidth = node.FullWidth; 48 | 49 | if (position < currentPosition + leading || position >= currentPosition + fullWidth - trailing) 50 | { 51 | return indent; 52 | } 53 | 54 | bool isClosingTag = node is XmlElementEndTagSyntax; 55 | if (isClosingTag && indent >= indentSize) 56 | { 57 | return indent - indentSize; 58 | } 59 | 60 | bool isElementWithAName = node is IXmlElement && 61 | !(node is XmlDocumentSyntax) && 62 | !string.IsNullOrEmpty(((IXmlElement)node).Name); 63 | if (isElementWithAName) 64 | { 65 | indent += indentSize; 66 | } 67 | 68 | foreach (var child in node.ChildNodes) 69 | { 70 | int childWidth = child.FullWidth; 71 | if (position < currentPosition + childWidth) 72 | { 73 | int result = indent; 74 | result = FindTotalParentChainIndent(child, position, currentPosition, indent, indentSize); 75 | 76 | return result; 77 | } 78 | else 79 | { 80 | currentPosition += childWidth; 81 | } 82 | } 83 | 84 | return indent; 85 | } 86 | 87 | private static int GetLeadingWhitespaceLength(SyntaxNode node) 88 | { 89 | if (!(node is IXmlElement)) 90 | { 91 | return 0; 92 | } 93 | 94 | var leadingTrivia = node.GetLeadingTrivia(); 95 | if (leadingTrivia == null) 96 | { 97 | return 0; 98 | } 99 | 100 | int totalLength = 0; 101 | foreach (var child in leadingTrivia) 102 | { 103 | if (child.Kind == SyntaxKind.WhitespaceTrivia) 104 | { 105 | totalLength += child.FullWidth; 106 | } 107 | } 108 | 109 | return totalLength; 110 | } 111 | 112 | public void Dispose() 113 | { 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/SmartIndent/SmartIndentProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Text.Editor; 3 | using Microsoft.VisualStudio.Utilities; 4 | 5 | namespace Microsoft.Language.Xml.Editor 6 | { 7 | [Export(typeof(ISmartIndentProvider))] 8 | [ContentType(ContentType.Xml)] 9 | public class SmartIndentProvider : ISmartIndentProvider 10 | { 11 | [Import] 12 | private ParserService parserService = null; 13 | 14 | public ISmartIndent CreateSmartIndent(ITextView textView) 15 | { 16 | return new SmartIndent(textView, parserService); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/Tagging/AbstractSyntaxTreeTagger.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml.Editor 2 | { 3 | public abstract class AbstractSyntaxTreeTagger 4 | { 5 | protected readonly ParserService parserService; 6 | 7 | public AbstractSyntaxTreeTagger(ParserService parserService) 8 | { 9 | this.parserService = parserService; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml.Editor/TextSnapshotBuffer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | public class TextSnapshotBuffer : Buffer 6 | { 7 | private ITextSnapshot textSnapshot; 8 | 9 | public TextSnapshotBuffer(ITextSnapshot textSnapshot) 10 | { 11 | this.textSnapshot = textSnapshot; 12 | } 13 | 14 | public override int Length 15 | { 16 | get { return textSnapshot.Length; } 17 | } 18 | 19 | public override char this[int index] 20 | { 21 | get 22 | { 23 | return textSnapshot[index]; 24 | } 25 | } 26 | 27 | public override string GetText(int start, int length) 28 | { 29 | return textSnapshot.GetText(start, length); 30 | } 31 | 32 | public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) 33 | { 34 | textSnapshot.CopyTo(sourceIndex, destination, destinationIndex, count); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Microsoft.Language.Xml.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004d58e878a7c3f80f91e670fc8de4def82bc0ec6c5cfdf55b41976c470f568cf9eafd3262aed24e4e66bfac4edeb108ab8400263ee1bf1fc0a41eb22595cb847f5f74fc797d555d48112f854de4e01616e56ab583ad36a81627d962f96d10f9a12505fa2956346c48fd55de0351d331bb886490c01e0dd6048d102c3c47a1c8d0")] 4 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Buffer.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | /// 4 | /// Abstract text buffer 5 | /// 6 | public abstract class Buffer 7 | { 8 | public abstract int Length { get; } 9 | 10 | public abstract char this[int index] { get; } 11 | 12 | public abstract string GetText(int start, int length); 13 | 14 | public abstract void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Classification/ClassificationTypeNames.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | public class ClassificationTypeNames 4 | { 5 | public const string XmlAttributeName = "xml - attribute name"; 6 | public const string XmlAttributeQuotes = "xml - attribute quotes"; 7 | public const string XmlAttributeValue = "xml - attribute value"; 8 | public const string XmlCDataSection = "xml - cdata section"; 9 | public const string XmlComment = "xml - comment"; 10 | public const string XmlDelimiter = "xml - delimiter"; 11 | public const string XmlEntityReference = "xml - entity reference"; 12 | public const string XmlName = "xml - name"; 13 | public const string XmlProcessingInstruction = "xml - processing instruction"; 14 | public const string XmlText = "xml - text"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Classification/XmlClassificationTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | public enum XmlClassificationTypes : byte 4 | { 5 | None, 6 | XmlAttributeName, 7 | XmlAttributeQuotes, 8 | XmlAttributeValue, 9 | XmlCDataSection, 10 | XmlComment, 11 | XmlDelimiter, 12 | XmlEntityReference, 13 | XmlName, 14 | XmlProcessingInstruction, 15 | XmlText, 16 | Count, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/DiagnosticInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Immutable; 4 | using System.Diagnostics; 5 | using System.Globalization; 6 | using System.Resources; 7 | 8 | namespace Microsoft.Language.Xml 9 | { 10 | /// 11 | /// Describes how severe a diagnostic is. 12 | /// 13 | public enum DiagnosticSeverity 14 | { 15 | /// 16 | /// Something that is an issue, as determined by some authority, 17 | /// but is not surfaced through normal means. 18 | /// There may be different mechanisms that act on these issues. 19 | /// 20 | Hidden = 0, 21 | 22 | /// 23 | /// Information that does not indicate a problem (i.e. not prescriptive). 24 | /// 25 | Info = 1, 26 | 27 | /// 28 | /// Something suspicious but allowed. 29 | /// 30 | Warning = 2, 31 | 32 | /// 33 | /// Something not allowed by the rules of the language or other authority. 34 | /// 35 | Error = 3, 36 | } 37 | 38 | public class DiagnosticInfo 39 | { 40 | object[] parameters; 41 | 42 | public ERRID ErrorID { get; } 43 | public DiagnosticSeverity Severity => DiagnosticSeverity.Error; 44 | 45 | public DiagnosticInfo(ERRID errID) 46 | { 47 | ErrorID = errID; 48 | } 49 | 50 | public DiagnosticInfo(ERRID errID, object[] parameters) 51 | : this(errID) 52 | { 53 | this.parameters = parameters; 54 | } 55 | 56 | public string GetDescription() => GetDescription(XmlResources.ResourceManager); 57 | 58 | public string GetDescription(ResourceManager resourceManager) 59 | { 60 | var name = ErrorID.ToString(); 61 | var description = resourceManager.GetString(name); 62 | if (parameters != null) 63 | description = string.Format(description, parameters); 64 | return description; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/ErrorFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | internal static class ErrorFactory 4 | { 5 | public static DiagnosticInfo ErrorInfo(ERRID errID) 6 | { 7 | return new DiagnosticInfo(errID); 8 | } 9 | 10 | public static DiagnosticInfo ErrorInfo(ERRID errID, object[] arguments) 11 | { 12 | return new DiagnosticInfo(errID, arguments); 13 | } 14 | 15 | public static DiagnosticInfo ErrorInfo(ERRID errID, char xmlCh, string v) 16 | { 17 | return new DiagnosticInfo(errID, new object[] { xmlCh, v }); 18 | } 19 | 20 | public static DiagnosticInfo ErrorInfo(ERRID errID, string xmlCh, string v) 21 | { 22 | return new DiagnosticInfo(errID, new object[] { xmlCh, v }); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | internal static class Extensions 4 | { 5 | /// 6 | /// Search a sorted integer array for the target value in O(log N) time. 7 | /// 8 | /// The array of integers which must be sorted in ascending order. 9 | /// The target value. 10 | /// An index in the array pointing to the position where should be 11 | /// inserted in order to maintain the sorted order. All values to the right of this position will be 12 | /// strictly greater than . Note that this may return a position off the end 13 | /// of the array if all elements are less than or equal to . 14 | public static int BinarySearchUpperBound(this int[] array, int value) 15 | { 16 | int low = 0; 17 | int high = array.Length - 1; 18 | 19 | while (low <= high) 20 | { 21 | int middle = low + ((high - low) >> 1); 22 | if (array[middle] > value) 23 | { 24 | high = middle - 1; 25 | } 26 | else 27 | { 28 | low = middle + 1; 29 | } 30 | } 31 | 32 | return low; 33 | } 34 | 35 | public static bool OverlapsWithAny(this TextSpan span, TextSpan[] otherSpans) 36 | { 37 | foreach (var other in otherSpans) 38 | { 39 | // TextSpan.OverlapsWith does not handle empty spans so 40 | // empty spans need to be handled explicitly. 41 | if (other.Length == 0) 42 | { 43 | if (span.Contains(other.Start)) 44 | return false; 45 | } 46 | else 47 | { 48 | if (span.OverlapsWith(other)) 49 | return true; 50 | } 51 | } 52 | return false; 53 | } 54 | 55 | public static bool AnyContainsPosition(this TextSpan[] spans, int position) 56 | { 57 | foreach (var span in spans) 58 | { 59 | if (span.Contains(position) || (span.Length == 0 && span.Start == position)) 60 | return true; 61 | // Assume that spans are sorted 62 | if (span.Start > position) 63 | return false; 64 | } 65 | return false; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/NodeFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml.InternalSyntax 4 | { 5 | [Flags] 6 | internal enum NodeFlags : byte 7 | { 8 | None = 0, 9 | ContainsDiagnostics = 1 << 0, 10 | ContainsStructuredTrivia = 1 << 1, 11 | ContainsDirectives = 1 << 2, 12 | ContainsSkippedText = 1 << 3, 13 | ContainsAnnotations = 1 << 4, 14 | IsMissing = 1 << 5, 15 | 16 | InheritMask = ContainsDiagnostics | ContainsStructuredTrivia | ContainsDirectives | ContainsSkippedText | ContainsAnnotations | IsMissing, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/SeparatedSyntaxList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Microsoft.Language.Xml.InternalSyntax 5 | { 6 | internal readonly struct SeparatedSyntaxList : IEquatable> where TNode : GreenNode 7 | { 8 | private readonly SyntaxList _list; 9 | 10 | internal SeparatedSyntaxList(SyntaxList list) 11 | { 12 | Validate(list); 13 | _list = list; 14 | } 15 | 16 | [Conditional("DEBUG")] 17 | private static void Validate(SyntaxList list) 18 | { 19 | for (int i = 0; i < list.Count; i++) 20 | { 21 | var item = list[i]; 22 | if ((i & 1) == 0) 23 | { 24 | Debug.Assert(!item.IsToken, "even elements of a separated list must be nodes"); 25 | } 26 | else 27 | { 28 | Debug.Assert(item.IsToken, "odd elements of a separated list must be tokens"); 29 | } 30 | } 31 | } 32 | 33 | internal GreenNode Node => _list.Node; 34 | 35 | public int Count 36 | { 37 | get 38 | { 39 | return (_list.Count + 1) >> 1; 40 | } 41 | } 42 | 43 | public int SeparatorCount 44 | { 45 | get 46 | { 47 | return _list.Count >> 1; 48 | } 49 | } 50 | 51 | public TNode this[int index] 52 | { 53 | get 54 | { 55 | return (TNode)_list[index << 1]; 56 | } 57 | } 58 | 59 | /// 60 | /// Gets the separator at the given index in this list. 61 | /// 62 | /// The index. 63 | /// 64 | public GreenNode GetSeparator(int index) 65 | { 66 | return _list[(index << 1) + 1]; 67 | } 68 | 69 | public SyntaxList GetWithSeparators() 70 | { 71 | return _list; 72 | } 73 | 74 | public static bool operator ==(in SeparatedSyntaxList left, in SeparatedSyntaxList right) 75 | { 76 | return left.Equals(right); 77 | } 78 | 79 | public static bool operator !=(in SeparatedSyntaxList left, in SeparatedSyntaxList right) 80 | { 81 | return !left.Equals(right); 82 | } 83 | 84 | public bool Equals(SeparatedSyntaxList other) 85 | { 86 | return _list == other._list; 87 | } 88 | 89 | public override bool Equals(object obj) 90 | { 91 | return (obj is SeparatedSyntaxList) && Equals((SeparatedSyntaxList)obj); 92 | } 93 | 94 | public override int GetHashCode() 95 | { 96 | return _list.GetHashCode(); 97 | } 98 | 99 | public static implicit operator SeparatedSyntaxList(SeparatedSyntaxList list) 100 | { 101 | return new SeparatedSyntaxList(list.GetWithSeparators()); 102 | } 103 | 104 | #if DEBUG 105 | [Obsolete("For debugging only", true)] 106 | private TNode[] Nodes 107 | { 108 | get 109 | { 110 | int count = this.Count; 111 | TNode[] array = new TNode[count]; 112 | for (int i = 0; i < count; i++) 113 | { 114 | array[i] = this[i]; 115 | } 116 | return array; 117 | } 118 | } 119 | #endif 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/SeparatedSyntaxListBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml.InternalSyntax 4 | { 5 | internal readonly struct SeparatedSyntaxListBuilder where TNode : GreenNode 6 | { 7 | private readonly SyntaxListBuilder _builder; 8 | 9 | public SeparatedSyntaxListBuilder(int size) 10 | : this(new SyntaxListBuilder(size)) 11 | { 12 | } 13 | 14 | public static SeparatedSyntaxListBuilder Create() 15 | { 16 | return new SeparatedSyntaxListBuilder(8); 17 | } 18 | 19 | internal SeparatedSyntaxListBuilder(SyntaxListBuilder builder) 20 | { 21 | _builder = builder; 22 | } 23 | 24 | public bool IsNull 25 | { 26 | get 27 | { 28 | return _builder == null; 29 | } 30 | } 31 | 32 | public int Count 33 | { 34 | get 35 | { 36 | return _builder.Count; 37 | } 38 | } 39 | 40 | public GreenNode this[int index] 41 | { 42 | get 43 | { 44 | return _builder[index]; 45 | } 46 | 47 | set 48 | { 49 | _builder[index] = value; 50 | } 51 | } 52 | 53 | public void Clear() 54 | { 55 | _builder.Clear(); 56 | } 57 | 58 | public void RemoveLast() 59 | { 60 | this._builder.RemoveLast(); 61 | } 62 | 63 | public SeparatedSyntaxListBuilder Add(TNode node) 64 | { 65 | _builder.Add(node); 66 | return this; 67 | } 68 | 69 | public void AddSeparator(GreenNode separatorToken) 70 | { 71 | _builder.Add(separatorToken); 72 | } 73 | 74 | public void AddRange(TNode[] items, int offset, int length) 75 | { 76 | _builder.AddRange(items, offset, length); 77 | } 78 | 79 | public void AddRange(in SeparatedSyntaxList nodes) 80 | { 81 | _builder.AddRange(nodes.GetWithSeparators()); 82 | } 83 | 84 | public void AddRange(in SeparatedSyntaxList nodes, int count) 85 | { 86 | var list = nodes.GetWithSeparators(); 87 | this._builder.AddRange(list, this.Count, Math.Min(count * 2, list.Count)); 88 | } 89 | 90 | public bool Any(SyntaxKind kind) 91 | { 92 | return _builder.Any(kind); 93 | } 94 | 95 | public SeparatedSyntaxList ToList() 96 | { 97 | return _builder == null 98 | ? default(SeparatedSyntaxList) 99 | : new SeparatedSyntaxList(new SyntaxList(_builder.ToListNode())); 100 | } 101 | 102 | /// 103 | /// WARN WARN WARN: This should be used with extreme caution - the underlying builder does 104 | /// not give any indication that it is from a separated syntax list but the constraints 105 | /// (node, token, node, token, ...) should still be maintained. 106 | /// 107 | /// 108 | /// In order to avoid creating a separate pool of SeparatedSyntaxListBuilders, we expose 109 | /// our underlying SyntaxListBuilder to SyntaxListPool. 110 | /// 111 | internal SyntaxListBuilder UnderlyingBuilder 112 | { 113 | get { return _builder; } 114 | } 115 | 116 | public static implicit operator SeparatedSyntaxList(in SeparatedSyntaxListBuilder builder) 117 | { 118 | return builder.ToList(); 119 | } 120 | 121 | public static implicit operator SyntaxListBuilder(in SeparatedSyntaxListBuilder builder) 122 | { 123 | return builder._builder; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/SyntaxListBuilder`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml.InternalSyntax 4 | { 5 | internal readonly struct SyntaxListBuilder where TNode : GreenNode 6 | { 7 | private readonly SyntaxListBuilder _builder; 8 | 9 | public SyntaxListBuilder(int size) 10 | : this(new SyntaxListBuilder(size)) 11 | { 12 | } 13 | 14 | public static SyntaxListBuilder Create() 15 | { 16 | return new SyntaxListBuilder(8); 17 | } 18 | 19 | internal SyntaxListBuilder(SyntaxListBuilder builder) 20 | { 21 | _builder = builder; 22 | } 23 | 24 | public bool IsNull 25 | { 26 | get 27 | { 28 | return _builder == null; 29 | } 30 | } 31 | 32 | public int Count 33 | { 34 | get 35 | { 36 | return _builder.Count; 37 | } 38 | } 39 | 40 | public TNode this[int index] 41 | { 42 | get 43 | { 44 | return (TNode)_builder[index]; 45 | } 46 | 47 | set 48 | { 49 | _builder[index] = value; 50 | } 51 | } 52 | 53 | public void Clear() 54 | { 55 | _builder.Clear(); 56 | } 57 | 58 | public SyntaxListBuilder Add(TNode node) 59 | { 60 | _builder.Add(node); 61 | return this; 62 | } 63 | 64 | public void AddRange(TNode[] items, int offset, int length) 65 | { 66 | _builder.AddRange(items, offset, length); 67 | } 68 | 69 | public void AddRange(SyntaxList nodes) 70 | { 71 | _builder.AddRange(nodes); 72 | } 73 | 74 | public void AddRange(SyntaxList nodes, int offset, int length) 75 | { 76 | _builder.AddRange(nodes, offset, length); 77 | } 78 | 79 | public bool Any(SyntaxKind kind) 80 | { 81 | return _builder.Any(kind); 82 | } 83 | 84 | public SyntaxList ToList() 85 | { 86 | return _builder.ToList(); 87 | } 88 | 89 | public GreenNode ToListNode() 90 | { 91 | return _builder.ToListNode(); 92 | } 93 | 94 | public static implicit operator SyntaxListBuilder(SyntaxListBuilder builder) 95 | { 96 | return builder._builder; 97 | } 98 | 99 | public static implicit operator SyntaxList(SyntaxListBuilder builder) 100 | { 101 | if (builder._builder != null) 102 | { 103 | return builder.ToList(); 104 | } 105 | 106 | return default(SyntaxList); 107 | } 108 | 109 | public SyntaxList ToList() where TDerived : GreenNode 110 | { 111 | return new SyntaxList(ToListNode()); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/SyntaxList`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Microsoft.Language.Xml.InternalSyntax 8 | { 9 | internal readonly struct SyntaxList 10 | where TNode : GreenNode 11 | { 12 | private readonly GreenNode _node; 13 | 14 | public SyntaxList(GreenNode node) 15 | { 16 | this._node = node; 17 | } 18 | 19 | public GreenNode Node 20 | { 21 | get 22 | { 23 | return ((GreenNode)this._node); 24 | } 25 | } 26 | 27 | public int Count 28 | { 29 | get 30 | { 31 | return (this._node == null) ? 0 : this._node.IsList ? this._node.SlotCount : 1; 32 | } 33 | } 34 | 35 | public TNode Last 36 | { 37 | get 38 | { 39 | var node = this._node; 40 | if (node.IsList) 41 | { 42 | return ((TNode)node.GetSlot(node.SlotCount - 1)); 43 | } 44 | 45 | return ((TNode)node); 46 | } 47 | } 48 | 49 | /* Not Implemented: Default */ 50 | public TNode this[int index] 51 | { 52 | get 53 | { 54 | var node = this._node; 55 | if (node.IsList) 56 | { 57 | return ((TNode)node.GetSlot(index)); 58 | } 59 | 60 | Debug.Assert(index == 0); 61 | return ((TNode)node); 62 | } 63 | } 64 | 65 | public GreenNode ItemUntyped(int index) 66 | { 67 | var node = this._node; 68 | if (node.IsList) 69 | { 70 | return node.GetSlot(index); 71 | } 72 | 73 | Debug.Assert(index == 0); 74 | return node; 75 | } 76 | 77 | public bool Any() 78 | { 79 | return this._node != null; 80 | } 81 | 82 | public bool Any(SyntaxKind kind) 83 | { 84 | for (var i = 0; i < this.Count; i++) 85 | { 86 | var element = this.ItemUntyped(i); 87 | if ((element.Kind == kind)) 88 | { 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | 96 | public TNode[] Nodes 97 | { 98 | get 99 | { 100 | var arr = new TNode[this.Count]; 101 | for (var i = 0; i < this.Count; i++) 102 | { 103 | arr[i] = this[i]; 104 | } 105 | 106 | return arr; 107 | } 108 | } 109 | 110 | public static bool operator ==(SyntaxList left, SyntaxList right) 111 | { 112 | return (left._node == right._node); 113 | } 114 | 115 | public static bool operator !=(SyntaxList left, SyntaxList right) 116 | { 117 | return !(left._node == right._node); 118 | } 119 | 120 | public override bool Equals(object obj) 121 | { 122 | return (obj is SyntaxList && (this._node == ((SyntaxList)obj)._node)); 123 | } 124 | 125 | public override int GetHashCode() 126 | { 127 | return this._node != null ? this._node.GetHashCode() : 0; 128 | } 129 | 130 | /*public SeparatedSyntaxList AsSeparatedList() where TOther : GreenNode 131 | { 132 | return new SeparatedSyntaxList(new SyntaxList(this._node)); 133 | }*/ 134 | 135 | public static implicit operator SyntaxList(TNode node) 136 | { 137 | return new SyntaxList(node); 138 | } 139 | 140 | public static implicit operator SyntaxList(SyntaxList nodes) 141 | { 142 | return new SyntaxList(nodes._node); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/SyntaxVisitor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Microsoft.Language.Xml.InternalSyntax 4 | { 5 | internal abstract partial class SyntaxVisitor 6 | { 7 | public virtual GreenNode Visit(GreenNode node) 8 | { 9 | if (node != null) 10 | { 11 | return node.Accept(this); 12 | } 13 | 14 | return null; 15 | } 16 | 17 | public virtual GreenNode VisitSyntaxNode(GreenNode node) 18 | { 19 | return node; 20 | } 21 | 22 | public virtual GreenNode VisitXmlNode(XmlNodeSyntax.Green node) 23 | { 24 | return VisitSyntaxNode(node); 25 | } 26 | 27 | public virtual GreenNode VisitXmlDocument(XmlDocumentSyntax.Green node) 28 | { 29 | return VisitXmlNode(node); 30 | } 31 | 32 | public virtual GreenNode VisitXmlDeclaration(XmlDeclarationSyntax.Green node) 33 | { 34 | return VisitSyntaxNode(node); 35 | } 36 | 37 | public virtual GreenNode VisitXmlDeclarationOption(XmlDeclarationOptionSyntax.Green node) 38 | { 39 | return VisitSyntaxNode(node); 40 | } 41 | 42 | public virtual GreenNode VisitXmlElement(XmlElementSyntax.Green node) 43 | { 44 | return VisitXmlNode(node); 45 | } 46 | 47 | public virtual GreenNode VisitXmlText(XmlTextSyntax.Green node) 48 | { 49 | return VisitXmlNode(node); 50 | } 51 | 52 | public virtual GreenNode VisitXmlElementStartTag(XmlElementStartTagSyntax.Green node) 53 | { 54 | return VisitXmlNode(node); 55 | } 56 | 57 | public virtual GreenNode VisitXmlElementEndTag(XmlElementEndTagSyntax.Green node) 58 | { 59 | return VisitXmlNode(node); 60 | } 61 | 62 | public virtual GreenNode VisitXmlEmptyElement(XmlEmptyElementSyntax.Green node) 63 | { 64 | return VisitXmlNode(node); 65 | } 66 | 67 | public virtual GreenNode VisitXmlAttribute(XmlAttributeSyntax.Green node) 68 | { 69 | return VisitXmlNode(node); 70 | } 71 | 72 | public virtual GreenNode VisitXmlString(XmlStringSyntax.Green node) 73 | { 74 | return VisitXmlNode(node); 75 | } 76 | 77 | public virtual GreenNode VisitXmlName(XmlNameSyntax.Green node) 78 | { 79 | return VisitXmlNode(node); 80 | } 81 | 82 | public virtual GreenNode VisitXmlPrefix(XmlPrefixSyntax.Green node) 83 | { 84 | return VisitSyntaxNode(node); 85 | } 86 | 87 | public virtual GreenNode VisitXmlComment(XmlCommentSyntax.Green node) 88 | { 89 | return VisitXmlNode(node); 90 | } 91 | 92 | public virtual GreenNode VisitSkippedTokensTrivia(SkippedTokensTriviaSyntax.Green node) 93 | { 94 | return VisitSyntaxNode(node); 95 | } 96 | 97 | public virtual GreenNode VisitXmlProcessingInstruction(XmlProcessingInstructionSyntax.Green node) 98 | { 99 | return VisitXmlNode(node); 100 | } 101 | 102 | public virtual GreenNode VisitXmlCDataSection(XmlCDataSectionSyntax.Green node) 103 | { 104 | return VisitXmlNode(node); 105 | } 106 | 107 | public virtual GreenNode VisitList(SyntaxList list) 108 | { 109 | return list; 110 | } 111 | 112 | public virtual SyntaxToken.Green VisitSyntaxToken(SyntaxToken.Green token) 113 | { 114 | return token; 115 | } 116 | 117 | public virtual SyntaxTrivia.Green VisitSyntaxTrivia(SyntaxTrivia.Green trivia) 118 | { 119 | return trivia; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/InternalSyntax/TriviaInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Microsoft.Language.Xml.InternalSyntax 5 | { 6 | internal class TriviaInfo 7 | { 8 | private TriviaInfo(GreenNode leadingTrivia, GreenNode trailingTrivia) 9 | { 10 | this._leadingTrivia = leadingTrivia; 11 | this._trailingTrivia = trailingTrivia; 12 | } 13 | 14 | private const int maximumCachedTriviaWidth = 40; 15 | private const int triviaInfoCacheSize = 64; 16 | private static readonly Func triviaKeyHasher = (GreenNode key) => Hash.Combine(key.ToFullString(), ((short)key.Kind)); 17 | private static readonly Func triviaKeyEquality = (GreenNode key, TriviaInfo value) => (key == value._leadingTrivia) || ((key.Kind == value._leadingTrivia.Kind) && (key.FullWidth == value._leadingTrivia.FullWidth) && (key.ToFullString() == value._leadingTrivia.ToFullString())); 18 | 19 | private static bool ShouldCacheTriviaInfo(GreenNode leadingTrivia, GreenNode trailingTrivia) 20 | { 21 | Debug.Assert(leadingTrivia != null); 22 | if (trailingTrivia == null) 23 | { 24 | return false; 25 | } 26 | else 27 | { 28 | return leadingTrivia.Kind == SyntaxKind.WhitespaceTrivia && 29 | trailingTrivia.Kind == SyntaxKind.WhitespaceTrivia && 30 | trailingTrivia.FullWidth == 1 && 31 | trailingTrivia.ToFullString() == " " && 32 | leadingTrivia.FullWidth <= maximumCachedTriviaWidth; 33 | } 34 | } 35 | 36 | public static TriviaInfo Create(GreenNode leadingTrivia, GreenNode trailingTrivia) 37 | { 38 | Debug.Assert(leadingTrivia != null); 39 | return new TriviaInfo(leadingTrivia, trailingTrivia); 40 | } 41 | 42 | public GreenNode _leadingTrivia; 43 | public GreenNode _trailingTrivia; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Microsoft.Language.Xml.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Microsoft.Language.Xml 4 | netstandard2.0 5 | true 6 | latest 7 | embedded 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | True 22 | True 23 | XmlResources.resx 24 | 25 | 26 | 27 | 28 | ResXFileCodeGenerator 29 | XmlResources.Designer.cs 30 | 31 | 32 | 33 | 34 | 35 | 36 | True 37 | GuiLabs.Language.Xml 38 | Microsoft 39 | Microsoft 40 | A full-fidelity XML parser 41 | A full-fidelity XML parser. Produces a syntax tree from XML text, preserves all whitespace and provides low-level API to examine the exact structure of the source text. 42 | Apache-2.0 43 | https://github.com/KirillOsenkov/XmlParser 44 | https://github.com/KirillOsenkov/XmlParser 45 | language_xml_logo.png 46 | Xml Parser 47 | true 48 | snupkg 49 | 50 | 51 | True 52 | ..\..\key.snk 53 | False 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/PooledStringBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | /// 7 | /// The usage is: 8 | /// var inst = PooledStringBuilder.GetInstance(); 9 | /// var sb = inst.builder; 10 | /// ... Do Stuff... 11 | /// ... sb.ToString() ... 12 | /// inst.Free(); 13 | /// 14 | internal class PooledStringBuilder 15 | { 16 | public readonly StringBuilder Builder = new StringBuilder(); 17 | private readonly ObjectPool pool; 18 | 19 | private PooledStringBuilder(ObjectPool pool) 20 | { 21 | Debug.Assert(pool != null); 22 | this.pool = pool; 23 | } 24 | 25 | public int Length 26 | { 27 | get { return this.Builder.Length; } 28 | } 29 | 30 | public void Free() 31 | { 32 | var builder = this.Builder; 33 | 34 | // do not store builders that are too large. 35 | if (builder.Capacity <= 1024) 36 | { 37 | builder.Clear(); 38 | pool.Free(this); 39 | } 40 | else 41 | { 42 | pool.ForgetTrackedObject(this); 43 | } 44 | } 45 | 46 | [System.Obsolete("Consider calling ToStringAndFree instead.")] 47 | public new string ToString() 48 | { 49 | return this.Builder.ToString(); 50 | } 51 | 52 | public string ToStringAndFree() 53 | { 54 | string result = this.Builder.ToString(); 55 | this.Free(); 56 | 57 | return result; 58 | } 59 | 60 | public string ToStringAndFree(int startIndex, int length) 61 | { 62 | string result = this.Builder.ToString(startIndex, length); 63 | this.Free(); 64 | 65 | return result; 66 | } 67 | 68 | // global pool 69 | private static readonly ObjectPool PoolInstance = CreatePool(); 70 | 71 | // if someone needs to create a private pool; 72 | public static ObjectPool CreatePool() 73 | { 74 | ObjectPool pool = null; 75 | pool = new ObjectPool(() => new PooledStringBuilder(pool), 32); 76 | return pool; 77 | } 78 | 79 | public static PooledStringBuilder GetInstance() 80 | { 81 | var builder = PoolInstance.Allocate(); 82 | Debug.Assert(builder.Builder.Length == 0); 83 | return builder; 84 | } 85 | 86 | public static implicit operator StringBuilder(PooledStringBuilder obj) 87 | { 88 | return obj.Builder; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/ScannerState.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | public enum ScannerState 4 | { 5 | Content, // Scan text between markup 6 | Misc, // Scan tokens in Xml misc state, these are tokens between document declaration and the root element 7 | DocType, // Scan tokens inside of 8 | Element, // Scan tokens inside of < ... > 9 | EndElement, // Scan tokens inside of 10 | SingleQuotedString, // Scan a single quoted string 11 | SmartSingleQuotedString, // Scan a single quoted string DWCH_RSMART_Q 12 | QuotedString, // Scan a quoted string 13 | SmartQuotedString, // Scan a quoted string DWCH_RSMART_DQ 14 | UnQuotedString, // Scan a string that is missing quotes (error recovery) 15 | CData, // Scan text inside of 16 | StartProcessingInstruction, // Scan first text inside f , the first text can have leading trivia 17 | ProcessingInstruction, // Scan remaining text inside of 18 | Comment, // Scan text inside of 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/StringBuffer.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | /// 4 | /// Abstraction around text snapshot to decouple the parser from the editor 5 | /// 6 | public class StringBuffer : Buffer 7 | { 8 | private string text; 9 | 10 | public StringBuffer(string text) 11 | { 12 | this.text = text; 13 | } 14 | 15 | public override int Length 16 | { 17 | get { return text.Length; } 18 | } 19 | 20 | public override char this[int index] 21 | { 22 | get 23 | { 24 | return text[index]; 25 | } 26 | } 27 | 28 | public override string GetText(int start, int length) 29 | { 30 | return text.Substring(start, length); 31 | } 32 | 33 | public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) 34 | { 35 | text.CopyTo(sourceIndex, destination, destinationIndex, count); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Structure/INamedXmlNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | public interface INamedXmlNode 6 | { 7 | string Name { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Structure/IXmlElement.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | public interface IXmlElement 6 | { 7 | int Start { get; } 8 | int FullWidth { get; } 9 | string Name { get; } 10 | string Value { get; } 11 | IXmlElement Parent { get; } 12 | IEnumerable Elements { get; } 13 | IEnumerable> Attributes { get; } 14 | string this[string attributeName] { get; } 15 | IXmlElementSyntax AsSyntaxElement { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/BadTokenSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class BadTokenSyntax : PunctuationSyntax 8 | { 9 | internal new class Green : PunctuationSyntax.Green 10 | { 11 | public SyntaxSubKind SubKind { get; } 12 | 13 | internal Green(SyntaxSubKind subKind, string name, GreenNode leadingTrivia, GreenNode trailingTrivia) 14 | : base(SyntaxKind.BadToken, name, leadingTrivia, trailingTrivia) 15 | { 16 | SubKind = subKind; 17 | } 18 | 19 | internal Green(SyntaxSubKind subKind, string name, GreenNode leadingTrivia, GreenNode trailingTrivia, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 20 | : base(SyntaxKind.BadToken, name, leadingTrivia, trailingTrivia, diagnostics, annotations) 21 | { 22 | SubKind = subKind; 23 | } 24 | 25 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new BadTokenSyntax(this, parent, position); 26 | 27 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 28 | { 29 | return new Green(SubKind, Text, LeadingTrivia, TrailingTrivia, diagnostics, GetAnnotations()); 30 | } 31 | 32 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 33 | { 34 | return new Green(SubKind, Text, LeadingTrivia, TrailingTrivia, GetDiagnostics(), annotations); 35 | } 36 | } 37 | 38 | internal new Green GreenNode => (Green)base.GreenNode; 39 | 40 | public SyntaxSubKind SubKind => GreenNode.SubKind; 41 | 42 | internal BadTokenSyntax(Green green, SyntaxNode parent, int position) 43 | : base(green, parent, position) 44 | { 45 | 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/ERRID.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | public enum ERRID 4 | { 5 | //Void = InternalErrorCode.Void, 6 | //Unknown = InternalErrorCode.Unknown, 7 | ERR_None = 0, 8 | 9 | ERR_Syntax = 30035, 10 | ERR_IllegalChar = 30037, 11 | ERR_ExpectedGreater = 30636, 12 | ERR_ExpectedXmlName = 31146, 13 | ERR_DuplicateXmlAttribute = 31149, 14 | ERR_MismatchedXmlEndTag = 31150, 15 | ERR_MissingXmlEndTag = 31151, 16 | ERR_MissingVersionInXmlDecl = 31153, 17 | ERR_IllegalAttributeInXmlDecl = 31154, 18 | ERR_VersionMustBeFirstInXmlDecl = 31156, 19 | ERR_AttributeOrder = 31157, 20 | ERR_ExpectedSQuote = 31163, 21 | ERR_ExpectedQuote = 31164, 22 | ERR_ExpectedLT = 31165, 23 | ERR_StartAttributeValue = 31166, 24 | ERR_IllegalXmlStartNameChar = 31169, 25 | ERR_IllegalXmlNameChar = 31170, 26 | ERR_IllegalXmlCommentChar = 31171, 27 | ERR_ExpectedXmlWhiteSpace = 31173, 28 | ERR_IllegalProcessingInstructionName = 31174, 29 | ERR_DTDNotSupported = 31175, 30 | ERR_IllegalXmlWhiteSpace = 31177, 31 | ERR_ExpectedSColon = 31178, 32 | ERR_XmlEntityReference = 31180, 33 | ERR_InvalidAttributeValue1 = 31181, 34 | ERR_InvalidAttributeValue2 = 31182, 35 | ERR_XmlEndCDataNotAllowedInContent = 31198, 36 | ERR_XmlEndElementNoMatchingStart = 31207, 37 | 38 | ERR_LastPlusOne 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/IXmlElementSyntax.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | public interface IXmlElementSyntax 6 | { 7 | string Name { get; } 8 | XmlNameSyntax NameNode { get; } 9 | SyntaxList Content { get; } 10 | IXmlElementSyntax Parent { get; } 11 | IEnumerable Elements { get; } 12 | IEnumerable Attributes { get; } 13 | SyntaxList AttributesNode { get; } 14 | XmlAttributeSyntax GetAttribute(string localName, string prefix = null); 15 | string GetAttributeValue(string localName, string prefix = null); 16 | IXmlElement AsElement { get; } 17 | XmlNodeSyntax AsNode { get; } 18 | string ToFullString(); 19 | 20 | IXmlElementSyntax WithName(XmlNameSyntax newName); 21 | IXmlElementSyntax WithContent(SyntaxList newContent); 22 | IXmlElementSyntax WithAttributes(IEnumerable newAttributes); 23 | IXmlElementSyntax WithAttributes(SyntaxList newAttributes); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/KeywordSyntax.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | using InternalSyntax; 4 | 5 | public class KeywordSyntax : SyntaxToken 6 | { 7 | internal new class Green : SyntaxToken.Green 8 | { 9 | internal Green(string name, GreenNode leadingTrivia, GreenNode trailingTrivia) 10 | : base(SyntaxKind.XmlKeyword, name, leadingTrivia, trailingTrivia) 11 | { 12 | } 13 | 14 | internal Green(string name, GreenNode leadingTrivia, GreenNode trailingTrivia, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 15 | : base(SyntaxKind.XmlKeyword, name, leadingTrivia, trailingTrivia, diagnostics, annotations) 16 | { 17 | } 18 | 19 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new KeywordSyntax(this, parent, position); 20 | 21 | public override SyntaxToken.Green WithLeadingTrivia(GreenNode trivia) 22 | { 23 | return new Green(Text, trivia, TrailingTrivia); 24 | } 25 | 26 | public override SyntaxToken.Green WithTrailingTrivia(GreenNode trivia) 27 | { 28 | return new Green(Text, LeadingTrivia, trivia); 29 | } 30 | 31 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 32 | { 33 | return new Green(Text, LeadingTrivia, TrailingTrivia, diagnostics, GetAnnotations()); 34 | } 35 | 36 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 37 | { 38 | return new Green(Text, LeadingTrivia, TrailingTrivia, GetDiagnostics(), annotations); 39 | } 40 | } 41 | 42 | internal new Green GreenNode => (Green)base.GreenNode; 43 | 44 | public string Keyword => Text; 45 | 46 | internal KeywordSyntax(Green green, SyntaxNode parent, int position) 47 | : base(green, parent, position) 48 | { 49 | 50 | } 51 | 52 | internal override SyntaxToken WithLeadingTriviaCore(SyntaxNode trivia) 53 | { 54 | return (KeywordSyntax)new Green(Text, trivia?.GreenNode, GetTrailingTrivia().Node?.GreenNode).CreateRed(Parent, Start); 55 | } 56 | 57 | internal override SyntaxToken WithTrailingTriviaCore(SyntaxNode trivia) 58 | { 59 | return (KeywordSyntax)new Green(Text, GetLeadingTrivia().Node?.GreenNode, trivia?.GreenNode).CreateRed(Parent, Start); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/PunctuationSyntax.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | using InternalSyntax; 4 | 5 | public class PunctuationSyntax : SyntaxToken 6 | { 7 | internal new class Green : SyntaxToken.Green 8 | { 9 | internal Green(SyntaxKind kind, string name, GreenNode leadingTrivia, GreenNode trailingTrivia) 10 | : base(kind, name, leadingTrivia, trailingTrivia) 11 | { 12 | } 13 | 14 | internal Green(SyntaxKind kind, string name, GreenNode leadingTrivia, GreenNode trailingTrivia, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 15 | : base(kind, name, leadingTrivia, trailingTrivia, diagnostics, annotations) 16 | { 17 | } 18 | 19 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new PunctuationSyntax(this, parent, position); 20 | 21 | public override SyntaxToken.Green WithLeadingTrivia(GreenNode trivia) 22 | { 23 | return new Green(Kind, Text, trivia, TrailingTrivia); 24 | } 25 | 26 | public override SyntaxToken.Green WithTrailingTrivia(GreenNode trivia) 27 | { 28 | return new Green(Kind, Text, LeadingTrivia, trivia); 29 | } 30 | 31 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 32 | { 33 | return new Green(Kind, Text, LeadingTrivia, TrailingTrivia, diagnostics, GetAnnotations()); 34 | } 35 | 36 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 37 | { 38 | return new Green(Kind, Text, LeadingTrivia, TrailingTrivia, GetDiagnostics(), annotations); 39 | } 40 | } 41 | 42 | internal new Green GreenNode => (Green)base.GreenNode; 43 | 44 | public string Punctuation => Text; 45 | 46 | internal PunctuationSyntax(Green green, SyntaxNode parent, int position) 47 | : base(green, parent, position) 48 | { 49 | 50 | } 51 | 52 | internal override SyntaxToken WithLeadingTriviaCore(SyntaxNode trivia) 53 | { 54 | return (PunctuationSyntax)new Green(Kind, Text, trivia?.GreenNode, GetTrailingTrivia().Node?.GreenNode).CreateRed(Parent, Start); 55 | } 56 | 57 | internal override SyntaxToken WithTrailingTriviaCore(SyntaxNode trivia) 58 | { 59 | return (PunctuationSyntax)new Green(Kind, Text, GetLeadingTrivia().Node?.GreenNode, trivia?.GreenNode).CreateRed(Parent, Start); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SeparatedSyntaxListBuilder`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Language.Xml 8 | { 9 | internal readonly struct SeparatedSyntaxListBuilder 10 | where TNode : SyntaxNode 11 | { 12 | private readonly SyntaxListBuilder builder; 13 | 14 | public SeparatedSyntaxListBuilder(int size) : this(new SyntaxListBuilder(size)) 15 | { 16 | } 17 | 18 | public SeparatedSyntaxListBuilder(SyntaxListBuilder builder) 19 | { 20 | this.builder = builder; 21 | } 22 | 23 | public bool IsNull 24 | { 25 | get 26 | { 27 | return (this.builder == null); 28 | } 29 | } 30 | 31 | public int Count 32 | { 33 | get 34 | { 35 | return this.builder.Count; 36 | } 37 | } 38 | 39 | public void Clear() 40 | { 41 | this.builder.Clear(); 42 | } 43 | 44 | public void Add(TNode node) 45 | { 46 | this.builder.Add(node); 47 | } 48 | 49 | public void AddSeparator(SyntaxToken separatorToken) 50 | { 51 | this.builder.Add(separatorToken); 52 | } 53 | 54 | public void AddRange(SeparatedSyntaxList nodes, int count) 55 | { 56 | var list = nodes.GetWithSeparators(); 57 | this.builder.AddRange(list, this.Count, Math.Min(count * 2, list.Count)); 58 | } 59 | 60 | public void RemoveLast() 61 | { 62 | this.builder.RemoveLast(); 63 | } 64 | 65 | public bool Any(SyntaxKind kind) 66 | { 67 | return this.builder.Any(kind); 68 | } 69 | 70 | public SeparatedSyntaxList ToList() 71 | { 72 | return new SeparatedSyntaxList(this.builder.ToList()); 73 | } 74 | 75 | public SeparatedSyntaxList ToList() where TDerivedNode : TNode 76 | { 77 | return new SeparatedSyntaxList(this.builder.ToList()); 78 | } 79 | 80 | public static implicit operator SyntaxListBuilder(SeparatedSyntaxListBuilder builder) 81 | { 82 | return builder.builder; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SeparatedSyntaxList`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Language.Xml 8 | { 9 | public readonly struct SeparatedSyntaxList 10 | where TNode : SyntaxNode 11 | { 12 | private readonly SyntaxList _list; 13 | 14 | public SeparatedSyntaxList(SyntaxList list) 15 | { 16 | this._list = list; 17 | } 18 | 19 | public SyntaxNode Node 20 | { 21 | get 22 | { 23 | return this._list.Node; 24 | } 25 | } 26 | 27 | public int Count 28 | { 29 | get 30 | { 31 | return (this._list.Count + 1) >> 1; 32 | } 33 | } 34 | 35 | public TNode this[int index] 36 | { 37 | get 38 | { 39 | return (TNode)_list[index << 1]; 40 | } 41 | } 42 | 43 | public int SeparatorCount 44 | { 45 | get 46 | { 47 | return (this._list.Count) >> 1; 48 | } 49 | } 50 | 51 | /* 52 | ''' Gets the separator at the given index in this list. 53 | ''' 54 | ''' The index. 55 | */ 56 | public SyntaxToken GetSeparator(int index) 57 | { 58 | return ((SyntaxToken)this._list[(index << 1) + 1]); 59 | } 60 | 61 | public bool Any() 62 | { 63 | return (this.Count > 0); 64 | } 65 | 66 | public bool Any(SyntaxKind kind) 67 | { 68 | for (var i = 0; i < this.Count; i++) 69 | { 70 | var element = this[i]; 71 | if ((element.Kind == kind)) 72 | { 73 | return true; 74 | } 75 | } 76 | 77 | return false; 78 | } 79 | 80 | public SyntaxList GetWithSeparators() 81 | { 82 | return this._list; 83 | } 84 | 85 | public bool Contains(TNode node) 86 | { 87 | return this.IndexOf(node) >= 0; 88 | } 89 | 90 | public int IndexOf(TNode node) 91 | { 92 | for (int i = 0, n = this.Count; i < n; i++) 93 | { 94 | if (object.Equals(this[i], node)) 95 | { 96 | return i; 97 | } 98 | } 99 | 100 | return -1; 101 | } 102 | 103 | public int IndexOf(Func predicate) 104 | { 105 | for (int i = 0, n = this.Count; i < n; i++) 106 | { 107 | if (predicate(this[i])) 108 | { 109 | return i; 110 | } 111 | } 112 | 113 | return -1; 114 | } 115 | 116 | internal int IndexOf(SyntaxKind kind) 117 | { 118 | for (int i = 0, n = this.Count; i < n; i++) 119 | { 120 | if (this[i].Kind == kind) 121 | { 122 | return i; 123 | } 124 | } 125 | 126 | return -1; 127 | } 128 | 129 | public int LastIndexOf(TNode node) 130 | { 131 | for (int i = this.Count - 1; i >= 0; i--) 132 | { 133 | if (object.Equals(this[i], node)) 134 | { 135 | return i; 136 | } 137 | } 138 | 139 | return -1; 140 | } 141 | 142 | public int LastIndexOf(Func predicate) 143 | { 144 | for (int i = this.Count - 1; i >= 0; i--) 145 | { 146 | if (predicate(this[i])) 147 | { 148 | return i; 149 | } 150 | } 151 | 152 | return -1; 153 | } 154 | 155 | internal bool Any(Func predicate) 156 | { 157 | for (int i = 0; i < this.Count; i++) 158 | { 159 | if (predicate(this[i])) 160 | { 161 | return true; 162 | } 163 | } 164 | 165 | return false; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SkippedTokensTriviaSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class SkippedTokensTriviaSyntax : SyntaxNode 8 | { 9 | internal class Green : GreenNode 10 | { 11 | readonly GreenNode tokens; 12 | 13 | internal Green(GreenNode tokens) 14 | : base(SyntaxKind.SkippedTokensTrivia) 15 | { 16 | this.SlotCount = 1; 17 | this.tokens = tokens; 18 | AdjustWidth(tokens); 19 | } 20 | 21 | internal Green(GreenNode tokens, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 22 | : base(SyntaxKind.SkippedTokensTrivia, diagnostics, annotations) 23 | { 24 | this.SlotCount = 1; 25 | this.tokens = tokens; 26 | AdjustWidth(tokens); 27 | } 28 | 29 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new SkippedTokensTriviaSyntax(this, parent, position); 30 | 31 | internal override GreenNode GetSlot(int index) 32 | { 33 | switch (index) 34 | { 35 | case 0: return tokens; 36 | } 37 | throw new InvalidOperationException(); 38 | } 39 | 40 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 41 | { 42 | return visitor.VisitSkippedTokensTrivia(this); 43 | } 44 | 45 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 46 | { 47 | return new Green(tokens, diagnostics, GetAnnotations()); 48 | } 49 | 50 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 51 | { 52 | return new Green(tokens, GetDiagnostics(), annotations); 53 | } 54 | } 55 | 56 | internal new Green GreenNode => (Green)base.GreenNode; 57 | 58 | SyntaxNode textTokens; 59 | 60 | public SyntaxList Tokens => new SyntaxList(GetRed(ref textTokens, 0)); 61 | 62 | internal SkippedTokensTriviaSyntax(Green green, SyntaxNode parent, int position) 63 | : base(green, parent, position) 64 | { 65 | 66 | } 67 | 68 | public string Value => Tokens.Node?.ToFullString() ?? string.Empty; 69 | 70 | public override SyntaxNode Accept(SyntaxVisitor visitor) 71 | { 72 | return visitor.VisitSkippedTokensTrivia(this); 73 | } 74 | 75 | internal override SyntaxNode GetCachedSlot(int index) 76 | { 77 | switch (index) 78 | { 79 | case 0: return textTokens; 80 | default: return null; 81 | } 82 | } 83 | 84 | internal override SyntaxNode GetNodeSlot(int slot) 85 | { 86 | switch (slot) 87 | { 88 | case 0: return GetRed(ref textTokens, 0); 89 | default: return null; 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxAnnotation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | /// 7 | /// A SyntaxAnnotation is used to annotate syntax elements with additional information. 8 | /// 9 | /// Since syntax elements are immutable, annotating them requires creating new instances of them 10 | /// with the annotations attached. 11 | /// 12 | [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] 13 | public sealed class SyntaxAnnotation : IEquatable 14 | { 15 | // use a value identity instead of object identity so a deserialized instance matches the original instance. 16 | private readonly long _id; 17 | private static long s_nextId; 18 | 19 | // use a value identity instead of object identity so a deserialized instance matches the original instance. 20 | public string Kind { get; } 21 | public string Data { get; } 22 | 23 | public SyntaxAnnotation() 24 | { 25 | _id = System.Threading.Interlocked.Increment(ref s_nextId); 26 | } 27 | 28 | public SyntaxAnnotation(string kind) 29 | : this() 30 | { 31 | this.Kind = kind; 32 | } 33 | 34 | public SyntaxAnnotation(string kind, string data) 35 | : this(kind) 36 | { 37 | this.Data = data; 38 | } 39 | 40 | private string GetDebuggerDisplay() 41 | { 42 | return string.Format("Annotation: Kind='{0}' Data='{1}'", this.Kind ?? "", this.Data ?? ""); 43 | } 44 | 45 | public bool Equals(SyntaxAnnotation other) 46 | { 47 | return (object)other != null && _id == other._id; 48 | } 49 | 50 | public static bool operator ==(SyntaxAnnotation left, SyntaxAnnotation right) 51 | { 52 | if ((object)left == (object)right) 53 | { 54 | return true; 55 | } 56 | 57 | if ((object)left == null || (object)right == null) 58 | { 59 | return false; 60 | } 61 | 62 | return left.Equals(right); 63 | } 64 | 65 | public static bool operator !=(SyntaxAnnotation left, SyntaxAnnotation right) 66 | { 67 | if ((object)left == (object)right) 68 | { 69 | return false; 70 | } 71 | 72 | if ((object)left == null || (object)right == null) 73 | { 74 | return true; 75 | } 76 | 77 | return !left.Equals(right); 78 | } 79 | 80 | public override bool Equals(object obj) 81 | { 82 | return this.Equals(obj as SyntaxAnnotation); 83 | } 84 | 85 | public override int GetHashCode() 86 | { 87 | return _id.GetHashCode(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxKind.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | public enum SyntaxKind : byte 4 | { 5 | LessThanQuestionToken, 6 | XmlNameToken, 7 | XmlKeyword, 8 | LessThanToken, 9 | LessThanGreaterThanToken, 10 | LessThanSlashToken, 11 | BeginCDataToken, 12 | LessThanExclamationMinusMinusToken, 13 | LessThanPercentEqualsToken, 14 | XmlTextLiteralToken, 15 | BadToken, 16 | XmlEntityLiteralToken, 17 | DocumentationCommentLineBreakToken, 18 | SlashToken, 19 | XmlElementStartTag, 20 | GreaterThanToken, 21 | EndOfXmlToken, 22 | EndOfFileToken, 23 | EqualsToken, 24 | SingleQuoteToken, 25 | DoubleQuoteToken, 26 | QuestionGreaterThanToken, 27 | OpenParenToken, 28 | CloseParenToken, 29 | ColonToken, 30 | IdentifierToken, 31 | SlashGreaterThanToken, 32 | WhitespaceTrivia, 33 | EndOfLineTrivia, 34 | XmlString, 35 | XmlName, 36 | XmlProcessingInstruction, 37 | XmlElementEndTag, 38 | XmlDeclaration, 39 | XmlDeclarationOption, 40 | XmlPrefix, 41 | XmlElement, 42 | XmlText, 43 | List, 44 | XmlEmptyElement, 45 | XmlAttribute, 46 | EndCDataToken, 47 | XmlCDataSection, 48 | MinusMinusGreaterThanToken, 49 | XmlComment, 50 | XmlDocument, 51 | None, 52 | SkippedTokensTrivia 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace Microsoft.Language.Xml 6 | { 7 | public abstract class SyntaxList : SyntaxNode 8 | { 9 | internal SyntaxList(InternalSyntax.SyntaxList green, SyntaxNode parent, int position) 10 | : base(green, parent, position) 11 | { 12 | } 13 | 14 | public override SyntaxNode Accept(SyntaxVisitor visitor) 15 | { 16 | return visitor.Visit(this); 17 | } 18 | 19 | protected internal override SyntaxNode ReplaceCore(IEnumerable nodes = null, Func computeReplacementNode = null, IEnumerable tokens = null, Func computeReplacementToken = null, IEnumerable trivia = null, Func computeReplacementTrivia = null) 20 | { 21 | throw new InvalidOperationException(); 22 | } 23 | 24 | internal class WithTwoChildren : SyntaxList 25 | { 26 | private SyntaxNode _child0; 27 | private SyntaxNode _child1; 28 | 29 | internal WithTwoChildren(InternalSyntax.SyntaxList green, SyntaxNode parent, int position) 30 | : base(green, parent, position) 31 | { 32 | } 33 | 34 | internal override SyntaxNode GetNodeSlot(int index) 35 | { 36 | switch (index) 37 | { 38 | case 0: 39 | return this.GetRedElement(ref _child0, 0); 40 | case 1: 41 | return this.GetRedElement(ref _child1, 1); 42 | default: 43 | return null; 44 | } 45 | } 46 | 47 | internal override SyntaxNode GetCachedSlot(int index) 48 | { 49 | switch (index) 50 | { 51 | case 0: 52 | return _child0; 53 | case 1: 54 | return _child1; 55 | default: 56 | return null; 57 | } 58 | } 59 | } 60 | 61 | internal class WithThreeChildren : SyntaxList 62 | { 63 | private SyntaxNode _child0; 64 | private SyntaxNode _child1; 65 | private SyntaxNode _child2; 66 | 67 | internal WithThreeChildren(InternalSyntax.SyntaxList green, SyntaxNode parent, int position) 68 | : base(green, parent, position) 69 | { 70 | } 71 | 72 | internal override SyntaxNode GetNodeSlot(int index) 73 | { 74 | switch (index) 75 | { 76 | case 0: 77 | return this.GetRedElement(ref _child0, 0); 78 | case 1: 79 | return this.GetRedElement(ref _child1, 1); 80 | case 2: 81 | return this.GetRedElement(ref _child2, 2); 82 | default: 83 | return null; 84 | } 85 | } 86 | 87 | internal override SyntaxNode GetCachedSlot(int index) 88 | { 89 | switch (index) 90 | { 91 | case 0: 92 | return _child0; 93 | case 1: 94 | return _child1; 95 | case 2: 96 | return _child2; 97 | default: 98 | return null; 99 | } 100 | } 101 | } 102 | 103 | internal class WithManyChildren : SyntaxList 104 | { 105 | private readonly ArrayElement[] _children; 106 | 107 | internal WithManyChildren(InternalSyntax.SyntaxList green, SyntaxNode parent, int position) 108 | : base(green, parent, position) 109 | { 110 | _children = new ArrayElement[green.SlotCount]; 111 | } 112 | 113 | internal override SyntaxNode GetNodeSlot(int index) 114 | { 115 | return this.GetRedElement(ref _children[index].Value, index); 116 | } 117 | 118 | internal override SyntaxNode GetCachedSlot(int index) 119 | { 120 | return _children[index]; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxListBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | internal static class SyntaxListBuilderExtensions 6 | { 7 | public static SyntaxList ToList(this SyntaxListBuilder builder) 8 | { 9 | if (builder == null || builder.Count == 0) 10 | { 11 | return default(SyntaxList); 12 | } 13 | 14 | return new SyntaxList(builder.ToListNode().CreateRed()); 15 | } 16 | 17 | public static SyntaxList ToList(this SyntaxListBuilder builder) 18 | where TNode : SyntaxNode 19 | { 20 | if (builder == null || builder.Count == 0) 21 | { 22 | return new SyntaxList(); 23 | } 24 | 25 | return new SyntaxList(builder.ToListNode().CreateRed()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxListBuilder`1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Microsoft.Language.Xml 9 | { 10 | internal readonly struct SyntaxListBuilder 11 | where TNode : SyntaxNode 12 | { 13 | private readonly SyntaxListBuilder _builder; 14 | 15 | public SyntaxListBuilder(int size) 16 | : this(new SyntaxListBuilder(size)) 17 | { 18 | } 19 | 20 | public static SyntaxListBuilder Create() 21 | { 22 | return new SyntaxListBuilder(8); 23 | } 24 | 25 | internal SyntaxListBuilder(SyntaxListBuilder builder) 26 | { 27 | _builder = builder; 28 | } 29 | 30 | public bool IsNull 31 | { 32 | get 33 | { 34 | return _builder == null; 35 | } 36 | } 37 | 38 | public int Count 39 | { 40 | get 41 | { 42 | return _builder.Count; 43 | } 44 | } 45 | 46 | public void Clear() 47 | { 48 | _builder.Clear(); 49 | } 50 | 51 | public SyntaxListBuilder Add(TNode node) 52 | { 53 | _builder.Add(node); 54 | return this; 55 | } 56 | 57 | public void AddRange(TNode[] items, int offset, int length) 58 | { 59 | _builder.AddRange(items, offset, length); 60 | } 61 | 62 | public void AddRange(SyntaxList nodes) 63 | { 64 | _builder.AddRange(nodes); 65 | } 66 | 67 | public void AddRange(SyntaxList nodes, int offset, int length) 68 | { 69 | _builder.AddRange(nodes, offset, length); 70 | } 71 | 72 | public bool Any(SyntaxKind kind) 73 | { 74 | return _builder.Any(kind); 75 | } 76 | 77 | public SyntaxList ToList() 78 | { 79 | return _builder.ToList(); 80 | } 81 | 82 | public static implicit operator SyntaxListBuilder(SyntaxListBuilder builder) 83 | { 84 | return builder._builder; 85 | } 86 | 87 | public static implicit operator SyntaxList(SyntaxListBuilder builder) 88 | { 89 | if (builder._builder != null) 90 | { 91 | return builder.ToList(); 92 | } 93 | 94 | return default(SyntaxList); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxListPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | using InternalSyntax; 7 | 8 | internal class SyntaxListPool 9 | { 10 | private Stack _freeList = new Stack(); 11 | public InternalSyntax.SyntaxListBuilder Allocate() 12 | { 13 | if (_freeList.Count > 0) 14 | { 15 | return _freeList.Pop(); 16 | } 17 | 18 | return InternalSyntax.SyntaxListBuilder.Create(); 19 | } 20 | 21 | public InternalSyntax.SyntaxListBuilder Allocate() where TNode : GreenNode 22 | { 23 | return new InternalSyntax.SyntaxListBuilder(this.Allocate()); 24 | } 25 | 26 | /*public SeparatedSyntaxListBuilder AllocateSeparated() where TNode : GreenNode 27 | { 28 | return new SeparatedSyntaxListBuilder(this.Allocate()); 29 | }*/ 30 | 31 | public void Free(InternalSyntax.SyntaxListBuilder item) 32 | { 33 | if (item != null) 34 | { 35 | item.Clear(); 36 | _freeList.Push(item); 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxSubKind.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Microsoft.Language.Xml 7 | { 8 | public enum SyntaxSubKind 9 | { 10 | None, 11 | BeginDocTypeToken, 12 | LessThanExclamationToken, 13 | OpenBracketToken, 14 | CloseBracketToken, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxTrivia.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace Microsoft.Language.Xml 6 | { 7 | using InternalSyntax; 8 | 9 | public class SyntaxTrivia : SyntaxNode 10 | { 11 | internal class Green : GreenNode 12 | { 13 | public string Text { get; } 14 | 15 | internal Green(SyntaxKind kind, string text) 16 | : base(kind, text.Length) 17 | { 18 | Text = text; 19 | } 20 | 21 | internal Green(SyntaxKind kind, string text, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 22 | : base(kind, text.Length, diagnostics, annotations) 23 | { 24 | Text = text; 25 | } 26 | 27 | public override int Width => Text.Length; 28 | 29 | internal override void WriteToOrFlatten(TextWriter writer, Stack stack) 30 | { 31 | writer.Write(Text); 32 | } 33 | 34 | public sealed override string ToFullString() => Text; 35 | 36 | public sealed override int GetLeadingTriviaWidth() => 0; 37 | public sealed override int GetTrailingTriviaWidth() => 0; 38 | 39 | protected override sealed int GetSlotCount() => 0; 40 | 41 | internal override sealed GreenNode GetSlot(int index) 42 | { 43 | throw new InvalidOperationException(); 44 | } 45 | 46 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new SyntaxTrivia(this, parent, position); 47 | 48 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 49 | { 50 | return visitor.VisitSyntaxTrivia(this); 51 | } 52 | 53 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 54 | { 55 | return new Green(Kind, Text, diagnostics, GetAnnotations()); 56 | } 57 | 58 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 59 | { 60 | return new Green(Kind, Text, GetDiagnostics(), annotations); 61 | } 62 | } 63 | 64 | internal new Green GreenNode => (Green)base.GreenNode; 65 | 66 | public string Text => GreenNode.Text; 67 | 68 | internal SyntaxTrivia(Green green, SyntaxNode parent, int position) 69 | : base(green, parent, position) 70 | { 71 | } 72 | 73 | internal override sealed SyntaxNode GetCachedSlot(int index) 74 | { 75 | throw new InvalidOperationException(); 76 | } 77 | 78 | internal override sealed SyntaxNode GetNodeSlot(int slot) 79 | { 80 | throw new InvalidOperationException(); 81 | } 82 | 83 | public override SyntaxNode Accept(SyntaxVisitor visitor) 84 | { 85 | return visitor.VisitSyntaxTrivia(this); 86 | } 87 | 88 | protected override int GetTextWidth() 89 | { 90 | return Text.Length; 91 | } 92 | 93 | public sealed override SyntaxTriviaList GetTrailingTrivia() 94 | { 95 | return default(SyntaxTriviaList); 96 | } 97 | 98 | public sealed override SyntaxTriviaList GetLeadingTrivia() 99 | { 100 | return default(SyntaxTriviaList); 101 | } 102 | 103 | public override string ToString() => Text; 104 | public sealed override string ToFullString() => Text; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxTriviaListBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace Microsoft.Language.Xml 6 | { 7 | using InternalSyntax; 8 | 9 | internal class SyntaxTriviaListBuilder 10 | { 11 | private SyntaxTrivia[] _nodes; 12 | private int _count; 13 | 14 | public SyntaxTriviaListBuilder(int size) 15 | { 16 | _nodes = new SyntaxTrivia[size]; 17 | } 18 | 19 | public static SyntaxTriviaListBuilder Create() 20 | { 21 | return new SyntaxTriviaListBuilder(4); 22 | } 23 | 24 | public static SyntaxTriviaList Create(IEnumerable trivia) 25 | { 26 | if (trivia == null) 27 | { 28 | return new SyntaxTriviaList(); 29 | } 30 | 31 | var builder = SyntaxTriviaListBuilder.Create(); 32 | builder.AddRange(trivia); 33 | return builder.ToList(); 34 | } 35 | 36 | public int Count 37 | { 38 | get { return _count; } 39 | } 40 | 41 | public void Clear() 42 | { 43 | _count = 0; 44 | } 45 | 46 | public SyntaxTrivia this[int index] 47 | { 48 | get 49 | { 50 | if (index < 0 || index > _count) 51 | { 52 | throw new IndexOutOfRangeException(); 53 | } 54 | 55 | return _nodes[index]; 56 | } 57 | } 58 | 59 | public void AddRange(IEnumerable items) 60 | { 61 | if (items != null) 62 | { 63 | foreach (var item in items) 64 | { 65 | this.Add(item); 66 | } 67 | } 68 | } 69 | 70 | public SyntaxTriviaListBuilder Add(SyntaxTrivia item) 71 | { 72 | if (_nodes == null || _count >= _nodes.Length) 73 | { 74 | this.Grow(_count == 0 ? 8 : _nodes.Length * 2); 75 | } 76 | 77 | _nodes[_count++] = item; 78 | return this; 79 | } 80 | 81 | public void Add(SyntaxTrivia[] items) 82 | { 83 | this.Add(items, 0, items.Length); 84 | } 85 | 86 | public void Add(SyntaxTrivia[] items, int offset, int length) 87 | { 88 | if (_nodes == null || _count + length > _nodes.Length) 89 | { 90 | this.Grow(_count + length); 91 | } 92 | 93 | Array.Copy(items, offset, _nodes, _count, length); 94 | _count += length; 95 | } 96 | 97 | public void Add(in SyntaxTriviaList list) 98 | { 99 | this.Add(list, 0, list.Count); 100 | } 101 | 102 | public void Add(in SyntaxTriviaList list, int offset, int length) 103 | { 104 | if (_nodes == null || _count + length > _nodes.Length) 105 | { 106 | this.Grow(_count + length); 107 | } 108 | 109 | list.CopyTo(offset, _nodes, _count, length); 110 | _count += length; 111 | } 112 | 113 | private void Grow(int size) 114 | { 115 | var tmp = new SyntaxTrivia[size]; 116 | Array.Copy(_nodes, tmp, _nodes.Length); 117 | _nodes = tmp; 118 | } 119 | 120 | public static implicit operator SyntaxTriviaList(SyntaxTriviaListBuilder builder) 121 | { 122 | return builder.ToList(); 123 | } 124 | 125 | public SyntaxTriviaList ToList() 126 | { 127 | if (_count > 0) 128 | { 129 | var tmp = new ArrayElement[_count]; 130 | for (int i = 0; i < _count; i++) 131 | { 132 | tmp[i].Value = _nodes[i].GreenNode; 133 | } 134 | return new SyntaxTriviaList(InternalSyntax.SyntaxList.List(tmp).CreateRed (), position: 0, index: 0); 135 | } 136 | else 137 | { 138 | return default(SyntaxTriviaList); 139 | } 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/SyntaxVisitor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | public abstract class SyntaxVisitor 6 | { 7 | public virtual SyntaxNode Visit(SyntaxNode node) 8 | { 9 | if (node != null) 10 | { 11 | return node.Accept(this); 12 | } 13 | 14 | return null; 15 | } 16 | 17 | public virtual SyntaxNode VisitSyntaxNode(SyntaxNode node) 18 | { 19 | return node; 20 | } 21 | 22 | public virtual SyntaxNode VisitXmlNode(XmlNodeSyntax node) 23 | { 24 | return VisitSyntaxNode(node); 25 | } 26 | 27 | public virtual SyntaxNode VisitXmlDocument(XmlDocumentSyntax node) 28 | { 29 | return VisitXmlNode(node); 30 | } 31 | 32 | public virtual SyntaxNode VisitXmlDeclaration(XmlDeclarationSyntax node) 33 | { 34 | return VisitSyntaxNode(node); 35 | } 36 | 37 | public virtual SyntaxNode VisitXmlDeclarationOption(XmlDeclarationOptionSyntax node) 38 | { 39 | return VisitSyntaxNode(node); 40 | } 41 | 42 | public virtual SyntaxNode VisitXmlElement(XmlElementSyntax node) 43 | { 44 | return VisitXmlNode(node); 45 | } 46 | 47 | public virtual SyntaxNode VisitXmlText(XmlTextSyntax node) 48 | { 49 | return VisitXmlNode(node); 50 | } 51 | 52 | public virtual SyntaxNode VisitXmlElementStartTag(XmlElementStartTagSyntax node) 53 | { 54 | return VisitXmlNode(node); 55 | } 56 | 57 | public virtual SyntaxNode VisitXmlElementEndTag(XmlElementEndTagSyntax node) 58 | { 59 | return VisitXmlNode(node); 60 | } 61 | 62 | public virtual SyntaxNode VisitXmlEmptyElement(XmlEmptyElementSyntax node) 63 | { 64 | return VisitXmlNode(node); 65 | } 66 | 67 | public virtual SyntaxNode VisitXmlAttribute(XmlAttributeSyntax node) 68 | { 69 | return VisitXmlNode(node); 70 | } 71 | 72 | public virtual SyntaxNode VisitXmlString(XmlStringSyntax node) 73 | { 74 | return VisitXmlNode(node); 75 | } 76 | 77 | public virtual SyntaxNode VisitXmlName(XmlNameSyntax node) 78 | { 79 | return VisitXmlNode(node); 80 | } 81 | 82 | public virtual SyntaxNode VisitXmlPrefix(XmlPrefixSyntax node) 83 | { 84 | return VisitSyntaxNode(node); 85 | } 86 | 87 | public virtual SyntaxNode VisitXmlComment(XmlCommentSyntax node) 88 | { 89 | return VisitXmlNode(node); 90 | } 91 | 92 | public virtual SyntaxNode VisitSkippedTokensTrivia(SkippedTokensTriviaSyntax node) 93 | { 94 | return VisitSyntaxNode(node); 95 | } 96 | 97 | public virtual SyntaxNode VisitXmlProcessingInstruction(XmlProcessingInstructionSyntax node) 98 | { 99 | return VisitXmlNode(node); 100 | } 101 | 102 | public virtual SyntaxNode VisitXmlCDataSection(XmlCDataSectionSyntax node) 103 | { 104 | return VisitXmlNode(node); 105 | } 106 | 107 | public virtual SyntaxList VisitList (SyntaxList list) where TNode : SyntaxNode 108 | { 109 | return list; 110 | } 111 | 112 | public virtual SyntaxToken VisitSyntaxToken(SyntaxToken token) 113 | { 114 | return token; 115 | } 116 | 117 | public virtual SyntaxTrivia VisitSyntaxTrivia(SyntaxTrivia trivia) 118 | { 119 | return trivia; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlCDataSectionSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class XmlCDataSectionSyntax : XmlNodeSyntax 8 | { 9 | internal new class Green : XmlNodeSyntax.Green 10 | { 11 | readonly PunctuationSyntax.Green beginCData; 12 | readonly GreenNode value; 13 | readonly PunctuationSyntax.Green endCData; 14 | 15 | internal PunctuationSyntax.Green BeginCData => beginCData; 16 | internal InternalSyntax.SyntaxList TextTokens => value; 17 | internal PunctuationSyntax.Green EndCData => endCData; 18 | 19 | internal Green(PunctuationSyntax.Green beginCData, GreenNode value, PunctuationSyntax.Green endCData) 20 | : base(SyntaxKind.XmlCDataSection) 21 | { 22 | this.SlotCount = 3; 23 | this.beginCData = beginCData; 24 | AdjustWidth(beginCData); 25 | this.value = value; 26 | AdjustWidth(value); 27 | this.endCData = endCData; 28 | AdjustWidth(endCData); 29 | } 30 | 31 | internal Green(PunctuationSyntax.Green beginCData, GreenNode value, PunctuationSyntax.Green endCData, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 32 | : base(SyntaxKind.XmlCDataSection, diagnostics, annotations) 33 | { 34 | this.SlotCount = 3; 35 | this.beginCData = beginCData; 36 | AdjustWidth(beginCData); 37 | this.value = value; 38 | AdjustWidth(value); 39 | this.endCData = endCData; 40 | AdjustWidth(endCData); 41 | } 42 | 43 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlCDataSectionSyntax(this, parent, position); 44 | 45 | internal override GreenNode GetSlot(int index) 46 | { 47 | switch (index) 48 | { 49 | case 0: return beginCData; 50 | case 1: return value; 51 | case 2: return endCData; 52 | } 53 | throw new InvalidOperationException(); 54 | } 55 | 56 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 57 | { 58 | return visitor.VisitXmlCDataSection(this); 59 | } 60 | 61 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 62 | { 63 | return new Green(beginCData, value, endCData, diagnostics, GetAnnotations()); 64 | } 65 | 66 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 67 | { 68 | return new Green(beginCData, value, endCData, GetDiagnostics(), annotations); 69 | } 70 | } 71 | 72 | PunctuationSyntax beginCData; 73 | SyntaxNode textTokens; 74 | PunctuationSyntax endCData; 75 | 76 | public PunctuationSyntax BeginCData => GetRed(ref beginCData, 0); 77 | public SyntaxList TextTokens => new SyntaxList(GetRed(ref textTokens, 1)); 78 | public PunctuationSyntax EndCData => GetRed(ref endCData, 2); 79 | 80 | internal XmlCDataSectionSyntax(Green green, SyntaxNode parent, int position) 81 | : base(green, parent, position) 82 | { 83 | 84 | } 85 | 86 | public string Value => TextTokens.Node?.ToFullString() ?? string.Empty; 87 | 88 | public override SyntaxNode Accept(SyntaxVisitor visitor) 89 | { 90 | return visitor.VisitXmlCDataSection(this); 91 | } 92 | 93 | internal override SyntaxNode GetCachedSlot(int index) 94 | { 95 | switch (index) 96 | { 97 | case 0: return beginCData; 98 | case 1: return textTokens; 99 | case 2: return endCData; 100 | default: return null; 101 | } 102 | } 103 | 104 | internal override SyntaxNode GetNodeSlot(int slot) 105 | { 106 | switch (slot) 107 | { 108 | case 0: return BeginCData; 109 | case 1: return GetRed(ref textTokens, 1); 110 | case 2: return EndCData; 111 | default: return null; 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlCommentSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class XmlCommentSyntax : XmlNodeSyntax 8 | { 9 | internal new class Green : XmlNodeSyntax.Green 10 | { 11 | readonly PunctuationSyntax.Green beginComment; 12 | readonly GreenNode content; 13 | readonly PunctuationSyntax.Green endComment; 14 | 15 | internal PunctuationSyntax.Green BeginComment => beginComment; 16 | internal GreenNode Content => content; 17 | internal PunctuationSyntax.Green EndComment => endComment; 18 | 19 | internal Green(PunctuationSyntax.Green beginComment, GreenNode content, PunctuationSyntax.Green endComment) 20 | : base(SyntaxKind.XmlComment) 21 | { 22 | this.SlotCount = 3; 23 | this.beginComment = beginComment; 24 | AdjustWidth(beginComment); 25 | this.content = content; 26 | AdjustWidth(content); 27 | this.endComment = endComment; 28 | AdjustWidth(endComment); 29 | } 30 | 31 | internal Green(PunctuationSyntax.Green beginComment, GreenNode content, PunctuationSyntax.Green endComment, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 32 | : base(SyntaxKind.XmlComment, diagnostics, annotations) 33 | { 34 | this.SlotCount = 3; 35 | this.beginComment = beginComment; 36 | AdjustWidth(beginComment); 37 | this.content = content; 38 | AdjustWidth(content); 39 | this.endComment = endComment; 40 | AdjustWidth(endComment); 41 | } 42 | 43 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlCommentSyntax(this, parent, position); 44 | 45 | internal override GreenNode GetSlot(int index) 46 | { 47 | switch (index) 48 | { 49 | case 0: return beginComment; 50 | case 1: return content; 51 | case 2: return endComment; 52 | } 53 | throw new InvalidOperationException(); 54 | } 55 | 56 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 57 | { 58 | return visitor.VisitXmlNode(this); 59 | } 60 | 61 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 62 | { 63 | return new Green(beginComment, content, endComment, diagnostics, GetAnnotations()); 64 | } 65 | 66 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 67 | { 68 | return new Green(beginComment, content, endComment, GetDiagnostics(), annotations); 69 | } 70 | } 71 | 72 | PunctuationSyntax beginComment; 73 | SyntaxNode content; 74 | PunctuationSyntax endComment; 75 | 76 | public PunctuationSyntax BeginComment => GetRed(ref beginComment, 0); 77 | public SyntaxList Content => new SyntaxList(GetRed(ref content, 1)); 78 | public PunctuationSyntax EndComment => GetRed(ref endComment, 2); 79 | 80 | internal XmlCommentSyntax(Green green, SyntaxNode parent, int position) 81 | : base(green, parent, position) 82 | { 83 | 84 | } 85 | 86 | public string Value => Content.Node?.ToFullString() ?? string.Empty; 87 | 88 | public override SyntaxNode Accept(SyntaxVisitor visitor) 89 | { 90 | return visitor.VisitXmlComment(this); 91 | } 92 | 93 | internal override SyntaxNode GetCachedSlot(int index) 94 | { 95 | switch (index) 96 | { 97 | case 0: return beginComment; 98 | case 1: return content; 99 | case 2: return endComment; 100 | default: return null; 101 | } 102 | } 103 | 104 | internal override SyntaxNode GetNodeSlot(int slot) 105 | { 106 | switch (slot) 107 | { 108 | case 0: return BeginComment; 109 | case 1: return GetRed(ref content, 1); 110 | case 2: return EndComment; 111 | default: return null; 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlContentExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Microsoft.Language.Xml 9 | { 10 | public static class XmlContextExtensions 11 | { 12 | internal static void Push(this List @this, XmlContext context) 13 | { 14 | @this.Add(context); 15 | } 16 | 17 | internal static XmlContext Pop(this List @this) 18 | { 19 | var last = @this.Count - 1; 20 | var context = @this[last]; 21 | @this.RemoveAt(last); 22 | return context; 23 | } 24 | 25 | internal static XmlContext Peek(this List @this, int i = 0) 26 | { 27 | var last = @this.Count - 1; 28 | return @this[last - i]; 29 | } 30 | 31 | internal static int MatchEndElement(this List @this, XmlNameSyntax.Green name) 32 | { 33 | Debug.Assert(name == null || name.Kind == SyntaxKind.XmlName); 34 | var last = @this.Count - 1; 35 | if (name == null) 36 | { 37 | return last; 38 | } 39 | 40 | var i = last; 41 | while (i >= 0) 42 | { 43 | var context = @this[i]; 44 | var nameExpr = context.StartElement.NameNode; 45 | if (nameExpr.Kind == SyntaxKind.XmlName) 46 | { 47 | var startName = ((XmlNameSyntax.Green)nameExpr); 48 | if (startName.LocalName.Text == name.LocalName.Text) 49 | { 50 | var startPrefix = startName.Prefix; 51 | var endPrefix = name.Prefix; 52 | if (startPrefix == endPrefix) 53 | { 54 | break; 55 | } 56 | 57 | if (startPrefix != null && endPrefix != null) 58 | { 59 | if (startPrefix.Name.Text == endPrefix.Name.Text) 60 | { 61 | break; 62 | } 63 | } 64 | } 65 | } 66 | 67 | i -= 1; 68 | } 69 | 70 | return i; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Microsoft.Language.Xml 8 | { 9 | using InternalSyntax; 10 | using static InternalSyntax.SyntaxFactory; 11 | 12 | internal readonly struct XmlContext 13 | { 14 | private readonly XmlElementStartTagSyntax.Green _start; 15 | private readonly InternalSyntax.SyntaxListBuilder _content; 16 | private readonly SyntaxListPool _pool; 17 | 18 | public XmlContext(SyntaxListPool pool, XmlElementStartTagSyntax.Green start) 19 | { 20 | _pool = pool; 21 | _start = start; 22 | _content = _pool.Allocate(); 23 | } 24 | 25 | public void Add(XmlNodeSyntax.Green xml) 26 | { 27 | _content.Add(xml); 28 | } 29 | 30 | public XmlElementStartTagSyntax.Green StartElement 31 | { 32 | get 33 | { 34 | return _start; 35 | } 36 | } 37 | 38 | public XmlNodeSyntax.Green CreateElement(XmlElementEndTagSyntax.Green endElement) 39 | { 40 | Debug.Assert(endElement != null); 41 | var contentList = _content.ToList(); 42 | _pool.Free(_content); 43 | return XmlElement(_start, contentList.Node, endElement); 44 | } 45 | 46 | internal XmlNodeSyntax.Green CreateElement(XmlElementEndTagSyntax.Green missingEndElement, object v) 47 | { 48 | return CreateElement(missingEndElement); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlDeclarationOptionSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class XmlDeclarationOptionSyntax : XmlNodeSyntax, INamedXmlNode 8 | { 9 | internal new class Green : XmlNodeSyntax.Green 10 | { 11 | readonly XmlNameTokenSyntax.Green name; 12 | readonly PunctuationSyntax.Green equals; 13 | readonly XmlStringSyntax.Green value; 14 | 15 | internal XmlNameTokenSyntax.Green Name => name; 16 | internal new PunctuationSyntax.Green Equals => equals; 17 | internal XmlStringSyntax.Green Value => value; 18 | 19 | internal Green(XmlNameTokenSyntax.Green name, PunctuationSyntax.Green equals, XmlStringSyntax.Green value) 20 | : base(SyntaxKind.XmlDeclarationOption) 21 | { 22 | this.SlotCount = 3; 23 | this.name = name; 24 | AdjustWidth(name); 25 | this.equals = equals; 26 | AdjustWidth(equals); 27 | this.value = value; 28 | AdjustWidth(value); 29 | } 30 | 31 | internal Green(XmlNameTokenSyntax.Green name, PunctuationSyntax.Green equals, XmlStringSyntax.Green value, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 32 | : base(SyntaxKind.XmlDeclarationOption, diagnostics, annotations) 33 | { 34 | this.SlotCount = 3; 35 | this.name = name; 36 | AdjustWidth(name); 37 | this.equals = equals; 38 | AdjustWidth(equals); 39 | this.value = value; 40 | AdjustWidth(value); 41 | } 42 | 43 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlDeclarationOptionSyntax(this, parent, position); 44 | 45 | internal override GreenNode GetSlot(int index) 46 | { 47 | switch (index) 48 | { 49 | case 0: return name; 50 | case 1: return equals; 51 | case 2: return value; 52 | } 53 | throw new InvalidOperationException(); 54 | } 55 | 56 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 57 | { 58 | return visitor.VisitXmlDeclarationOption(this); 59 | } 60 | 61 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 62 | { 63 | return new Green(name, equals, value, diagnostics, GetAnnotations()); 64 | } 65 | 66 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 67 | { 68 | return new Green(name, equals, value, GetDiagnostics(), annotations); 69 | } 70 | } 71 | 72 | internal new Green GreenNode => (Green)GreenNode; 73 | 74 | XmlNameTokenSyntax nameNode; 75 | PunctuationSyntax equals; 76 | XmlStringSyntax value; 77 | 78 | public XmlNameTokenSyntax NameNode => GetRed(ref nameNode, 0); 79 | public new PunctuationSyntax Equals => GetRed(ref equals, 1); 80 | public XmlStringSyntax Value => GetRed(ref value, 2); 81 | 82 | public string Name => NameNode?.Name; 83 | 84 | internal XmlDeclarationOptionSyntax(Green green, SyntaxNode parent, int position) 85 | : base(green, parent, position) 86 | { 87 | 88 | } 89 | 90 | public override SyntaxNode Accept(SyntaxVisitor visitor) 91 | { 92 | return visitor.VisitXmlDeclarationOption(this); 93 | } 94 | 95 | internal override SyntaxNode GetCachedSlot(int index) 96 | { 97 | switch (index) 98 | { 99 | case 0: return nameNode; 100 | case 1: return equals; 101 | case 2: return value; 102 | default: return null; 103 | } 104 | } 105 | 106 | internal override SyntaxNode GetNodeSlot(int slot) 107 | { 108 | switch (slot) 109 | { 110 | case 0: return NameNode; 111 | case 1: return Equals; 112 | case 2: return Value; 113 | default: return null; 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlEntityTokenSyntax.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | using InternalSyntax; 4 | 5 | public class XmlEntityTokenSyntax : XmlTextTokenSyntax 6 | { 7 | internal new class Green : XmlTextTokenSyntax.Green 8 | { 9 | public string Value { get; } 10 | 11 | internal Green(string text, string value, GreenNode leadingTrivia, GreenNode trailingTrivia) 12 | : base(SyntaxKind.XmlEntityLiteralToken, text, leadingTrivia, trailingTrivia) 13 | { 14 | Value = value; 15 | } 16 | 17 | internal Green(string text, string value, GreenNode leadingTrivia, GreenNode trailingTrivia, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 18 | : base(SyntaxKind.XmlEntityLiteralToken, text, leadingTrivia, trailingTrivia, diagnostics, annotations) 19 | { 20 | Value = value; 21 | } 22 | 23 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlEntityTokenSyntax(this, parent, position); 24 | } 25 | 26 | internal new Green GreenNode => (Green)base.GreenNode; 27 | 28 | public string Entity => Text; 29 | public string EntityValue => GreenNode.Value; 30 | 31 | internal XmlEntityTokenSyntax(Green green, SyntaxNode parent, int position) 32 | : base(green, parent, position) 33 | { 34 | 35 | } 36 | 37 | internal override SyntaxToken WithLeadingTriviaCore(SyntaxNode trivia) 38 | { 39 | return (XmlEntityTokenSyntax)new Green(Entity, EntityValue, trivia?.GreenNode, GetTrailingTrivia().Node?.GreenNode).CreateRed(Parent, Start); 40 | } 41 | 42 | internal override SyntaxToken WithTrailingTriviaCore(SyntaxNode trivia) 43 | { 44 | return (XmlEntityTokenSyntax)new Green(Entity, EntityValue, GetLeadingTrivia().Node?.GreenNode, trivia?.GreenNode).CreateRed(Parent, Start); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlNameTokenSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class XmlNameTokenSyntax : SyntaxToken 8 | { 9 | internal new class Green : SyntaxToken.Green 10 | { 11 | internal Green(string name, GreenNode leadingTrivia, GreenNode trailingTrivia) 12 | : base(SyntaxKind.XmlNameToken, name, leadingTrivia, trailingTrivia) 13 | { 14 | } 15 | 16 | internal Green(string name, GreenNode leadingTrivia, GreenNode trailingTrivia, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 17 | : base(SyntaxKind.XmlNameToken, name, leadingTrivia, trailingTrivia, diagnostics, annotations) 18 | { 19 | } 20 | 21 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlNameTokenSyntax(this, parent, position); 22 | 23 | public override SyntaxToken.Green WithLeadingTrivia(GreenNode trivia) 24 | { 25 | return new Green(Text, trivia, TrailingTrivia); 26 | } 27 | 28 | public override SyntaxToken.Green WithTrailingTrivia(GreenNode trivia) 29 | { 30 | return new Green(Text, LeadingTrivia, trivia); 31 | } 32 | 33 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 34 | { 35 | return new Green(Text, LeadingTrivia, TrailingTrivia, diagnostics, GetAnnotations()); 36 | } 37 | 38 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 39 | { 40 | return new Green(Text, LeadingTrivia, TrailingTrivia, GetDiagnostics(), annotations); 41 | } 42 | } 43 | 44 | internal new Green GreenNode => (Green)base.GreenNode; 45 | 46 | public string Name => Text; 47 | 48 | internal XmlNameTokenSyntax(Green green, SyntaxNode parent, int position) 49 | : base(green, parent, position) 50 | { 51 | 52 | } 53 | 54 | internal override SyntaxToken WithLeadingTriviaCore(SyntaxNode trivia) 55 | { 56 | return (XmlNameTokenSyntax)new Green(Text, trivia?.GreenNode, GetTrailingTrivia().Node?.GreenNode).CreateRed(Parent, Start); 57 | } 58 | 59 | internal override SyntaxToken WithTrailingTriviaCore(SyntaxNode trivia) 60 | { 61 | return (XmlNameTokenSyntax)new Green(Text, GetLeadingTrivia().Node?.GreenNode, trivia?.GreenNode).CreateRed(Parent, Start); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlNodeSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | public abstract class XmlNodeSyntax : SyntaxNode 7 | { 8 | internal abstract class Green : InternalSyntax.GreenNode 9 | { 10 | protected Green(SyntaxKind kind) 11 | : base(kind) 12 | { 13 | } 14 | 15 | protected Green(SyntaxKind kind, int fullWidth) 16 | : base(kind, fullWidth) 17 | { 18 | } 19 | 20 | protected Green(SyntaxKind kind, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 21 | : base(kind, diagnostics, annotations) 22 | { 23 | } 24 | 25 | internal override InternalSyntax.GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 26 | { 27 | return visitor.VisitXmlNode(this); 28 | } 29 | } 30 | 31 | internal new Green GreenNode => (Green)base.GreenNode; 32 | 33 | internal XmlNodeSyntax(Green green, SyntaxNode parent, int position) : base(green, parent, position) 34 | { 35 | } 36 | 37 | public override SyntaxNode Accept(SyntaxVisitor visitor) 38 | { 39 | return visitor.VisitXmlNode(this); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlPrefixSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class XmlPrefixSyntax : SyntaxNode 8 | { 9 | internal class Green : GreenNode 10 | { 11 | readonly XmlNameTokenSyntax.Green name; 12 | readonly PunctuationSyntax.Green colonToken; 13 | 14 | internal XmlNameTokenSyntax.Green Name => name; 15 | 16 | internal Green(XmlNameTokenSyntax.Green name, PunctuationSyntax.Green colonToken) 17 | : base(SyntaxKind.XmlPrefix) 18 | { 19 | this.SlotCount = 2; 20 | this.name = name; 21 | AdjustWidth(name); 22 | this.colonToken = colonToken; 23 | AdjustWidth(colonToken); 24 | } 25 | 26 | internal Green(XmlNameTokenSyntax.Green name, PunctuationSyntax.Green colonToken, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 27 | : base(SyntaxKind.XmlPrefix, diagnostics, annotations) 28 | { 29 | this.SlotCount = 2; 30 | this.name = name; 31 | AdjustWidth(name); 32 | this.colonToken = colonToken; 33 | AdjustWidth(colonToken); 34 | } 35 | 36 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlPrefixSyntax(this, parent, position); 37 | 38 | internal override GreenNode GetSlot(int index) 39 | { 40 | switch (index) 41 | { 42 | case 0: return name; 43 | case 1: return colonToken; 44 | } 45 | 46 | throw new InvalidOperationException(); 47 | } 48 | 49 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 50 | { 51 | return visitor.VisitXmlPrefix(this); 52 | } 53 | 54 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 55 | { 56 | return new Green(name, colonToken, diagnostics, GetAnnotations()); 57 | } 58 | 59 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 60 | { 61 | return new Green(name, colonToken, GetDiagnostics(), annotations); 62 | } 63 | } 64 | 65 | internal new Green GreenNode => (Green)base.GreenNode; 66 | 67 | XmlNameTokenSyntax name; 68 | PunctuationSyntax colonToken; 69 | 70 | public XmlNameTokenSyntax Name => GetRed(ref name, 0); 71 | public PunctuationSyntax ColonToken => GetRed(ref colonToken, 1); 72 | 73 | internal XmlPrefixSyntax(Green green, SyntaxNode parent, int position) 74 | : base(green, parent, position) 75 | { 76 | } 77 | 78 | public override SyntaxNode Accept(SyntaxVisitor visitor) 79 | { 80 | return visitor.VisitXmlPrefix(this); 81 | } 82 | 83 | internal override SyntaxNode GetCachedSlot(int index) 84 | { 85 | switch (index) 86 | { 87 | case 0: return name; 88 | case 1: return colonToken; 89 | default: return null; 90 | } 91 | } 92 | 93 | internal override SyntaxNode GetNodeSlot(int slot) 94 | { 95 | switch (slot) 96 | { 97 | case 0: return Name; 98 | case 1: return ColonToken; 99 | default: return null; 100 | } 101 | } 102 | 103 | public XmlPrefixSyntax Update(XmlNameTokenSyntax name, PunctuationSyntax colonToken) 104 | { 105 | if (name != this.Name || colonToken != this.ColonToken) 106 | { 107 | var newNode = SyntaxFactory.XmlPrefix(name, colonToken); 108 | var annotations = this.GetAnnotations(); 109 | if (annotations != null && annotations.Length > 0) 110 | return newNode.WithAnnotations(annotations); 111 | return newNode; 112 | } 113 | 114 | return this; 115 | } 116 | 117 | public XmlPrefixSyntax WithName(XmlNameTokenSyntax name) 118 | { 119 | return Update(name, ColonToken); 120 | } 121 | 122 | public XmlPrefixSyntax WithColonToken(PunctuationSyntax colonToken) 123 | { 124 | return Update(Name, colonToken); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlTextSyntax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | public class XmlTextSyntax : XmlNodeSyntax 8 | { 9 | internal new class Green : XmlNodeSyntax.Green 10 | { 11 | readonly GreenNode value; 12 | 13 | internal InternalSyntax.SyntaxList TextTokens => new InternalSyntax.SyntaxList(value); 14 | 15 | internal Green(GreenNode value) 16 | : base(SyntaxKind.XmlText) 17 | { 18 | this.SlotCount = 1; 19 | this.value = value; 20 | AdjustWidth(value); 21 | } 22 | 23 | internal Green(GreenNode value, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 24 | : base(SyntaxKind.XmlText, diagnostics, annotations) 25 | { 26 | this.SlotCount = 1; 27 | this.value = value; 28 | AdjustWidth(value); 29 | } 30 | 31 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlTextSyntax(this, parent, position); 32 | 33 | internal override GreenNode GetSlot(int index) 34 | { 35 | switch (index) 36 | { 37 | case 0: return value; 38 | } 39 | throw new InvalidOperationException(); 40 | } 41 | 42 | internal override GreenNode Accept(InternalSyntax.SyntaxVisitor visitor) 43 | { 44 | return visitor.VisitXmlText(this); 45 | } 46 | 47 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 48 | { 49 | return new Green(value, diagnostics, GetAnnotations()); 50 | } 51 | 52 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 53 | { 54 | return new Green(value, GetDiagnostics(), annotations); 55 | } 56 | } 57 | 58 | SyntaxNode textTokens; 59 | 60 | public SyntaxList TextTokens => new SyntaxList(GetRed(ref textTokens, 0)); 61 | 62 | internal XmlTextSyntax(Green green, SyntaxNode parent, int position) 63 | : base(green, parent, position) 64 | { 65 | 66 | } 67 | 68 | public string Value => TextTokens.Node?.ToFullString() ?? string.Empty; 69 | 70 | public override SyntaxNode Accept(SyntaxVisitor visitor) 71 | { 72 | return visitor.VisitXmlText(this); 73 | } 74 | 75 | internal override SyntaxNode GetCachedSlot(int index) 76 | { 77 | switch (index) 78 | { 79 | case 0: return textTokens; 80 | default: return null; 81 | } 82 | } 83 | 84 | internal override SyntaxNode GetNodeSlot(int slot) 85 | { 86 | switch (slot) 87 | { 88 | case 0: return GetRed(ref textTokens, 0); 89 | default: return null; 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Syntax/XmlTextTokenSyntax.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Language.Xml 2 | { 3 | using InternalSyntax; 4 | 5 | public class XmlTextTokenSyntax : SyntaxToken 6 | { 7 | internal new class Green : SyntaxToken.Green 8 | { 9 | internal Green(string text, GreenNode leadingTrivia, GreenNode trailingTrivia) 10 | : base(SyntaxKind.XmlTextLiteralToken, text, leadingTrivia, trailingTrivia) 11 | { 12 | } 13 | 14 | protected Green(SyntaxKind kind, string name, GreenNode leadingTrivia, GreenNode trailingTrivia) 15 | : base(kind, name, leadingTrivia, trailingTrivia) 16 | { 17 | } 18 | 19 | protected Green(SyntaxKind kind, string name, GreenNode leadingTrivia, GreenNode trailingTrivia, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) 20 | : base(kind, name, leadingTrivia, trailingTrivia, diagnostics, annotations) 21 | { 22 | } 23 | 24 | internal override SyntaxNode CreateRed(SyntaxNode parent, int position) => new XmlTextTokenSyntax(this, parent, position); 25 | 26 | public override SyntaxToken.Green WithLeadingTrivia(GreenNode trivia) 27 | { 28 | return new Green(Kind, Text, trivia, TrailingTrivia); 29 | } 30 | 31 | public override SyntaxToken.Green WithTrailingTrivia(GreenNode trivia) 32 | { 33 | return new Green(Kind, Text, LeadingTrivia, trivia); 34 | } 35 | 36 | internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) 37 | { 38 | return new Green(Kind, Text, LeadingTrivia, TrailingTrivia, diagnostics, GetAnnotations()); 39 | } 40 | 41 | internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) 42 | { 43 | return new Green(Kind, Text, LeadingTrivia, TrailingTrivia, GetDiagnostics(), annotations); 44 | } 45 | } 46 | 47 | public string Value => Text; 48 | 49 | internal XmlTextTokenSyntax(Green green, SyntaxNode parent, int position) 50 | : base(green, parent, position) 51 | { 52 | 53 | } 54 | 55 | internal override SyntaxToken WithLeadingTriviaCore(SyntaxNode trivia) 56 | { 57 | return (XmlTextTokenSyntax)new Green(Text, trivia?.GreenNode, GetTrailingTrivia().Node?.GreenNode).CreateRed(Parent, Start); 58 | } 59 | 60 | internal override SyntaxToken WithTrailingTriviaCore(SyntaxNode trivia) 61 | { 62 | return (XmlTextTokenSyntax)new Green(Text, GetLeadingTrivia().Node?.GreenNode, trivia?.GreenNode).CreateRed(Parent, Start); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/TextChange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | public readonly struct TextChange : IEquatable 7 | { 8 | /// 9 | /// The original span of the changed text. 10 | /// 11 | public TextSpan Span { get; } 12 | 13 | /// 14 | /// The new text. 15 | /// 16 | public string NewText { get; } 17 | 18 | /// 19 | /// Initializes a new instance of 20 | /// 21 | /// The original span of the changed text. 22 | /// The new text. 23 | public TextChange(TextSpan span, string newText) 24 | : this() 25 | { 26 | if (newText == null) 27 | { 28 | throw new ArgumentNullException(nameof(newText)); 29 | } 30 | 31 | this.Span = span; 32 | this.NewText = newText; 33 | } 34 | 35 | /// 36 | /// Provides a string representation for . 37 | /// 38 | public override string ToString() 39 | { 40 | return string.Format("{0}: {{ {1}, \"{2}\" }}", this.GetType().Name, Span, NewText); 41 | } 42 | 43 | public override bool Equals(object obj) 44 | { 45 | return obj is TextChange && this.Equals((TextChange)obj); 46 | } 47 | 48 | public bool Equals(TextChange other) 49 | { 50 | return 51 | EqualityComparer.Default.Equals(this.Span, other.Span) && 52 | EqualityComparer.Default.Equals(this.NewText, other.NewText); 53 | } 54 | 55 | public override int GetHashCode() 56 | { 57 | return Hash.Combine(this.Span.GetHashCode(), this.NewText.GetHashCode()); 58 | } 59 | 60 | public static bool operator ==(TextChange left, TextChange right) 61 | { 62 | return left.Equals(right); 63 | } 64 | 65 | public static bool operator !=(TextChange left, TextChange right) 66 | { 67 | return !(left == right); 68 | } 69 | 70 | /// 71 | /// Converts a to a . 72 | /// 73 | /// 74 | public static implicit operator TextChangeRange(TextChange change) 75 | { 76 | return new TextChangeRange(change.Span, change.NewText.Length); 77 | } 78 | 79 | /// 80 | /// An empty set of changes. 81 | /// 82 | public static IReadOnlyList NoChanges => SpecializedCollections.EmptyReadOnlyList(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/TextChangeRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | /// 7 | /// Represents the change to a span of text. 8 | /// 9 | public readonly struct TextChangeRange : IEquatable 10 | { 11 | /// 12 | /// The span of text before the edit which is being changed 13 | /// 14 | public TextSpan Span { get; } 15 | 16 | /// 17 | /// Width of the span after the edit. A 0 here would represent a delete 18 | /// 19 | public int NewLength { get; } 20 | 21 | public TextSpan NewSpan => new TextSpan(Span.Start, NewLength); 22 | 23 | /// 24 | /// Initializes a new instance of . 25 | /// 26 | /// 27 | /// 28 | public TextChangeRange(TextSpan span, int newLength) 29 | : this() 30 | { 31 | if (newLength < 0) 32 | { 33 | throw new ArgumentOutOfRangeException(nameof(newLength)); 34 | } 35 | 36 | this.Span = span; 37 | this.NewLength = newLength; 38 | } 39 | 40 | /// 41 | /// Compares current instance of to another. 42 | /// 43 | public bool Equals(TextChangeRange other) 44 | { 45 | return 46 | other.Span == this.Span && 47 | other.NewLength == this.NewLength; 48 | } 49 | 50 | /// 51 | /// Compares current instance of to another. 52 | /// 53 | public override bool Equals(object obj) 54 | { 55 | return obj is TextChangeRange && Equals((TextChangeRange)obj); 56 | } 57 | 58 | /// 59 | /// Provides hash code for current instance of . 60 | /// 61 | /// 62 | public override int GetHashCode() 63 | { 64 | return Hash.Combine(this.NewLength, this.Span.GetHashCode()); 65 | } 66 | 67 | /// 68 | /// Determines if two instances of are same. 69 | /// 70 | public static bool operator ==(TextChangeRange left, TextChangeRange right) 71 | { 72 | return left.Equals(right); 73 | } 74 | 75 | /// 76 | /// Determines if two instances of are different. 77 | /// 78 | public static bool operator !=(TextChangeRange left, TextChangeRange right) 79 | { 80 | return !(left == right); 81 | } 82 | 83 | /// 84 | /// An empty set of changes. 85 | /// 86 | public static IReadOnlyList NoChanges { get; } = new List().AsReadOnly(); 87 | 88 | /// 89 | /// Collapse a set of s into a single encompassing range. If 90 | /// the set of ranges provided is empty, an empty range is returned. 91 | /// 92 | public static TextChangeRange Collapse(IEnumerable changes) 93 | { 94 | var diff = 0; 95 | var start = int.MaxValue; 96 | var end = 0; 97 | 98 | foreach (var change in changes) 99 | { 100 | diff += change.NewLength - change.Span.Length; 101 | 102 | if (change.Span.Start < start) 103 | { 104 | start = change.Span.Start; 105 | } 106 | 107 | if (change.Span.End > end) 108 | { 109 | end = change.Span.End; 110 | } 111 | } 112 | 113 | if (start > end) 114 | { 115 | // there were no changes. 116 | return default(TextChangeRange); 117 | } 118 | 119 | var combined = TextSpan.FromBounds(start, end); 120 | var newLen = combined.Length + diff; 121 | 122 | return new TextChangeRange(combined, newLen); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Utilities/ArrayElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Language.Xml 8 | { 9 | public struct ArrayElement 10 | { 11 | public T Value; 12 | 13 | public static implicit operator T(ArrayElement element) 14 | { 15 | return element.Value; 16 | } 17 | 18 | //NOTE: there is no opposite conversion operator T -> ArrayElement 19 | // 20 | // that is because it is preferred to update array elements in-place 21 | // "elements[i].Value = v" results in much better code than "elements[i] = (ArrayElement)v" 22 | // 23 | // The reason is that x86 ABI requires that structs must be returned in 24 | // a return buffer even if they can fit in a register like this one. 25 | // Also since struct contains a reference, the write to the buffer is done with a checked GC barrier 26 | // as JIT does not know if the write goes to a stack or a heap location. 27 | // Assigning to Value directly easily avoids all this redundancy. 28 | 29 | public static ArrayElement[] MakeElementArray(T[] items) 30 | { 31 | if (items == null) 32 | { 33 | return null; 34 | } 35 | 36 | var array = new ArrayElement[items.Length]; 37 | for (int i = 0; i < items.Length; i++) 38 | { 39 | array[i].Value = items[i]; 40 | } 41 | 42 | return array; 43 | } 44 | 45 | public static T[] MakeArray(ArrayElement[] items) 46 | { 47 | if (items == null) 48 | { 49 | return null; 50 | } 51 | 52 | var array = new T[items.Length]; 53 | for (int i = 0; i < items.Length; i++) 54 | { 55 | array[i] = items[i].Value; 56 | } 57 | 58 | return array; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Utilities/FirstTokenReplacer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | internal class FirstTokenReplacer : InternalSyntax.SyntaxRewriter 8 | { 9 | private readonly Func _newItem; 10 | private bool _isFirst = true; 11 | 12 | private FirstTokenReplacer(Func newItem) 13 | { 14 | _newItem = newItem; 15 | } 16 | 17 | internal static TTree Replace(TTree root, Func newItem) where TTree : GreenNode 18 | { 19 | return ((TTree)new FirstTokenReplacer(newItem).Visit(root)); 20 | } 21 | 22 | public override SyntaxToken.Green VisitSyntaxToken(SyntaxToken.Green token) 23 | { 24 | if (token == null) 25 | { 26 | return null; 27 | } 28 | 29 | if (_isFirst) 30 | { 31 | _isFirst = false; 32 | return _newItem(token); 33 | } 34 | 35 | return token; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Utilities/LastTokenReplacer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Language.Xml 4 | { 5 | using InternalSyntax; 6 | 7 | internal class LastTokenReplacer : InternalSyntax.SyntaxRewriter 8 | { 9 | private readonly Func _newItem; 10 | private int _skipCnt; 11 | private LastTokenReplacer(Func newItem) 12 | { 13 | _newItem = newItem; 14 | } 15 | 16 | internal static TTree Replace(TTree root, Func newItem) where TTree : GreenNode 17 | { 18 | return (TTree)new LastTokenReplacer(newItem).Visit(root); 19 | } 20 | 21 | public override GreenNode Visit(GreenNode node) 22 | { 23 | if (node == null) 24 | { 25 | return null; 26 | } 27 | 28 | // node is not interesting until skip count is 0 29 | if (_skipCnt != 0) 30 | { 31 | _skipCnt -= 1; 32 | return node; 33 | } // not interested in trivia 34 | 35 | if (!node.IsToken) 36 | { 37 | var allChildrenCnt = 0; 38 | for (int i = 0; i < node.SlotCount; i++) 39 | { 40 | var child = node.GetSlot(i); 41 | if (child == null) 42 | { 43 | continue; 44 | } 45 | 46 | if (child.IsList) 47 | { 48 | allChildrenCnt += child.SlotCount; 49 | } 50 | else 51 | { 52 | allChildrenCnt += 1; 53 | } 54 | } 55 | 56 | // no children 57 | if (allChildrenCnt == 0) 58 | { 59 | return node; 60 | } 61 | 62 | var prevIdx = _skipCnt; 63 | _skipCnt = allChildrenCnt - 1; 64 | GreenNode result; 65 | if (node.IsList) 66 | { 67 | result = VisitList(new InternalSyntax.SyntaxList(node)).Node; 68 | } 69 | else 70 | { 71 | result = base.Visit(node); 72 | } 73 | 74 | _skipCnt = prevIdx; 75 | return result; 76 | } 77 | else 78 | { 79 | return base.Visit(node); 80 | } 81 | } 82 | 83 | public override SyntaxToken.Green VisitSyntaxToken(SyntaxToken.Green token) 84 | { 85 | return _newItem(token); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/Utilities/Normalization.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Microsoft.Language.Xml.Utilities 4 | { 5 | public static class Normalization 6 | { 7 | /// 8 | /// Get normalized value 9 | /// 10 | /// to normalize. 11 | /// 12 | /// Normalization specs: 13 | /// 2.2.12 [XML] Section 3.3.3 14 | /// 2.11 [XML} End-of-Line Handling 15 | /// 16 | public static string GetNormalizedAttributeValue(this string value) => 17 | GetNormalizedAttributeValue(new StringBuilder(value)); 18 | 19 | internal static string GetNormalizedAttributeValue(StringBuilder inputBuffer) 20 | { 21 | var outputBuffer = PooledStringBuilder.GetInstance(); 22 | NormalizeAttributeValueTo(inputBuffer, outputBuffer); 23 | return outputBuffer.ToStringAndFree(); 24 | } 25 | 26 | internal static string GetNormalizedAttributeValue(this SyntaxNode node) 27 | { 28 | var inputBuffer = PooledStringBuilder.GetInstance(); 29 | var writer = new System.IO.StringWriter(inputBuffer.Builder, System.Globalization.CultureInfo.InvariantCulture); 30 | node.WriteTo(writer); 31 | var outputBuffer = PooledStringBuilder.GetInstance(); 32 | inputBuffer.Builder.NormalizeAttributeValueTo(outputBuffer); 33 | inputBuffer.Free(); 34 | return outputBuffer.ToStringAndFree(); 35 | } 36 | 37 | [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] 38 | private static void NormalizeAttributeValueTo(this StringBuilder inputBuffer, PooledStringBuilder outputBuffer) 39 | { 40 | var inputBufferLength = inputBuffer.Length; 41 | char lastChar = default; 42 | for (int charIndex = 0; charIndex < inputBufferLength; charIndex++) 43 | { 44 | var c = inputBuffer[charIndex]; 45 | switch (c) 46 | { 47 | // If there is a sequence of CR and LF or CR 0x85 or CR 0x2028 replace them with a space (0x32) 48 | case '\r' when (charIndex + 1 < inputBufferLength && (inputBuffer[charIndex + 1] is '\n' or '\x85' or '\x2028')): 49 | outputBuffer.Builder.Append(' '); 50 | charIndex++; // Skip next onece 51 | break; 52 | // If current char is single CR or 0x85 or 0x2028 replace with a space(0x32) 53 | case '\r': 54 | case '\x85': 55 | case '\x2000': 56 | outputBuffer.Builder.Append(' '); 57 | break; 58 | // if current char is LF and previus not is LF or CR 59 | case '\n' when lastChar != '\n' && lastChar != '\r': 60 | outputBuffer.Builder.Append(' '); 61 | break; 62 | case '\t': 63 | outputBuffer.Builder.Append(' '); 64 | break; 65 | default: 66 | outputBuffer.Builder.Append(c); 67 | break; 68 | } 69 | lastChar = c; 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/Microsoft.Language.Xml/XmlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Microsoft.Language.Xml 5 | { 6 | public static class XmlExtensions 7 | { 8 | /// 9 | /// Returns the text content of a element node 10 | /// 11 | /// 12 | /// In addition to the straightforward case 13 | /// of an element containing simple text tokens, this 14 | /// method also check for embedded CDATA sections 15 | /// 16 | public static string GetContentValue(this IXmlElementSyntax element) 17 | { 18 | if (element.Content.Count == 1 && element.Content.First() is XmlCDataSectionSyntax cdata) 19 | return cdata.TextTokens.ToFullString(); 20 | return element.AsElement.Value; 21 | } 22 | 23 | /// 24 | /// Return a new instance with 25 | /// the supplied string prefix. 26 | /// 27 | public static IXmlElementSyntax WithPrefixName(this IXmlElementSyntax element, string prefixName) 28 | { 29 | var existingName = element.NameNode; 30 | var existingPrefix = existingName.PrefixNode; 31 | var newName = SyntaxFactory.XmlNameToken(prefixName, null, null); 32 | 33 | return element.WithName(existingName.WithPrefix(existingPrefix.WithName(newName))); 34 | } 35 | 36 | /// 37 | /// Return a new instance with 38 | /// the supplied string attribute value 39 | /// 40 | public static XmlAttributeSyntax WithValue(this XmlAttributeSyntax attribute, string attributeValue) 41 | { 42 | var textTokens = SyntaxFactory.SingletonList(SyntaxFactory.XmlTextLiteralToken(attributeValue, null, null)); 43 | return attribute.WithValue(attribute.ValueNode.WithTextTokens(textTokens)); 44 | } 45 | 46 | public static XmlAttributeSyntax WithPrefixName(this XmlAttributeSyntax attribute, string prefixName) 47 | { 48 | var existingName = attribute.NameNode; 49 | var existingPrefix = existingName.PrefixNode; 50 | var newName = SyntaxFactory.XmlNameToken(prefixName, null, null); 51 | 52 | return attribute.WithName(existingName.WithPrefix(existingPrefix.WithName(newName))); 53 | } 54 | 55 | public static XmlAttributeSyntax WithLocalName(this XmlAttributeSyntax attribute, string localName) 56 | { 57 | var existingName = attribute.NameNode; 58 | var existingLocalName = existingName.LocalNameNode; 59 | var newName = SyntaxFactory.XmlNameToken(localName, null, null); 60 | 61 | return attribute.WithName(existingName.WithLocalName(newName)); 62 | } 63 | 64 | public static IXmlElementSyntax AddChild(this IXmlElementSyntax parent, IXmlElementSyntax child) 65 | { 66 | return parent.WithContent(parent.Content.Add(child.AsNode)); 67 | } 68 | 69 | public static IXmlElementSyntax InsertChild(this IXmlElementSyntax parent, IXmlElementSyntax child, int index) 70 | { 71 | if (index == -1) 72 | return AddChild(parent, child); 73 | return parent.WithContent(parent.Content.Insert(index, child.AsNode)); 74 | } 75 | 76 | public static IXmlElementSyntax RemoveChild(this IXmlElementSyntax parent, IXmlElementSyntax child) 77 | { 78 | return parent.WithContent(parent.Content.Remove(child.AsNode)); 79 | } 80 | 81 | internal static bool IsXmlNodeName(this XmlNameSyntax name) 82 | { 83 | var p = name.Parent; 84 | switch (p.Kind) 85 | { 86 | case SyntaxKind.XmlElement: 87 | case SyntaxKind.XmlEmptyElement: 88 | case SyntaxKind.XmlElementStartTag: 89 | case SyntaxKind.XmlElementEndTag: 90 | return true; 91 | default: return false; 92 | } 93 | } 94 | 95 | public static IXmlElementSyntax AddAttributes(this IXmlElementSyntax self, params XmlAttributeSyntax[] attributes) 96 | { 97 | return self.WithAttributes(self.AttributesNode.AddRange(attributes)); 98 | } 99 | 100 | public static IXmlElementSyntax AddAttributes(this IXmlElementSyntax self, IEnumerable attributes) 101 | { 102 | return self.WithAttributes(self.AttributesNode.AddRange(attributes)); 103 | } 104 | 105 | public static IXmlElementSyntax AddAttribute(this IXmlElementSyntax self, XmlAttributeSyntax attribute) 106 | { 107 | return self.WithAttributes(self.AttributesNode.Add(attribute)); 108 | } 109 | 110 | public static IXmlElementSyntax RemoveAttribute(this IXmlElementSyntax self, XmlAttributeSyntax attribute) 111 | { 112 | return self.WithAttributes(self.AttributesNode.Remove(attribute)); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Editor.Tests/Microsoft.Language.Xml.Editor.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Microsoft.Language.Xml.Editor.Tests 4 | net472 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Editor.Tests/SyntaxReplacerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Xunit; 3 | 4 | namespace Microsoft.Language.Xml.Test 5 | { 6 | public class SyntaxReplacerTests 7 | { 8 | [Fact] 9 | public void TestReplaceNode() 10 | { 11 | var original = @" 12 | 13 | 14 | net8.0 15 | 16 | 17 | "; 18 | 19 | var expected = @" 20 | 21 | 22 | net9.0 23 | 24 | 25 | "; 26 | 27 | XmlDocumentSyntax root = Parser.ParseText(original); 28 | XmlElementSyntax syntaxToReplace = root 29 | .Descendants() 30 | .OfType() 31 | .Single(n => n.Name == "TargetFramework"); 32 | SyntaxNode textSyntaxToReplace = syntaxToReplace.Content.Single(); 33 | 34 | XmlTextSyntax content = SyntaxFactory.XmlText(SyntaxFactory.XmlTextLiteralToken("net9.0", null, null)); 35 | 36 | root = root.ReplaceNode(textSyntaxToReplace, content); 37 | 38 | Assert.Equal(expected, root.ToFullString()); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Editor.Tests/TestSmartIndent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Language.Xml.Editor; 2 | using Xunit; 3 | 4 | namespace Microsoft.Language.Xml.Test 5 | { 6 | public class TestSmartIndent 7 | { 8 | [Fact] 9 | public void TestIndent1() 10 | { 11 | T(@" 12 | | 13 | "); 14 | T(@" 15 | | 16 | 17 | "); 18 | T(@" 19 | 20 | | 21 | 22 | "); 23 | T(@" 24 | 25 | 26 | | 27 | 28 | 29 | "); 30 | T(@" 31 | | 32 | 33 | 34 | "); 35 | T(@" 36 | 37 | | 38 | "); 39 | } 40 | 41 | [Fact] 42 | public void TestIndent2() 43 | { 44 | T(@" 45 | 46 | | 47 | "); 48 | } 49 | 50 | [Fact] 51 | public void TestIndent3() 52 | { 53 | T(@" 54 | |"); 55 | T(@" 56 | 57 | | 58 | "); 59 | T(@" 60 | 61 | 62 | |"); 63 | } 64 | 65 | private void T(string xmlWithCaret) 66 | { 67 | int caret = xmlWithCaret.IndexOf('|'); 68 | int expectedIndent = 0; 69 | while (caret - expectedIndent > 1 && xmlWithCaret[caret - expectedIndent - 1] == ' ') 70 | { 71 | expectedIndent++; 72 | } 73 | 74 | var xml = xmlWithCaret.Remove(caret, 1); 75 | var root = Parser.ParseText(xml); 76 | var actualIndent = SmartIndent.FindTotalParentChainIndent(root, caret, 0, 0); 77 | Assert.Equal(expectedIndent, actualIndent); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Tests/Microsoft.Language.Xml.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Microsoft.Language.Xml.Tests 4 | net472 5 | $([MSBuild]::IsOSPlatform('Windows')) 6 | 7 | 8 | True 9 | ..\..\key.snk 10 | False 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::GetDirectoryName('$(XunitConsolePath)')) 31 | 32 | 33 | 34 | Always 35 | False 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Tests/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Microsoft.Language.Xml.Tests.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Language.Xml.Tests.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> 65 | ///<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> 66 | /// <metadata> 67 | /// <id>Microsoft.Language.Xml.Editor</id> 68 | /// <summary>A simple XML language service for the Visual Studio editor</summary> 69 | /// <description> 70 | /// Currently includes a classifier, outlining and smart indent. 71 | /// </description> 72 | /// <dependencies> 73 | /// <!-- dependency --><!-- adjacent comment --> 74 | /// <dependency id="Microsoft.Language.Xml" version="$currentVersion$" / [rest of string was truncated]";. 75 | /// 76 | internal static string TestXml { 77 | get { 78 | return ResourceManager.GetString("TestXml", resourceCulture); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Tests/TestAnnotations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace Microsoft.Language.Xml.Tests 5 | { 6 | public class TestAnnotations 7 | { 8 | private static readonly SyntaxAnnotation annotation = new SyntaxAnnotation("test"); 9 | 10 | [Fact] 11 | public void AddingContentToElementPreservesAnnotations() 12 | { 13 | var root = GetRootElementSyntax(""); 14 | var child = Parser.ParseText("").RootSyntax; 15 | 16 | AssertAnnotation(root.AddChild(child)); 17 | } 18 | 19 | [Fact] 20 | public void AddingChildToEmptyElementPreservesAnnotations() 21 | { 22 | var root = GetRootEmptyElementSyntax(""); 23 | var child = Parser.ParseText("").RootSyntax; 24 | 25 | AssertAnnotation(root.AddChild(child)); 26 | } 27 | 28 | [Fact] 29 | public void AddingElementTriviaPreservesAnnotations() 30 | { 31 | var root = GetRootElementSyntax(""); 32 | var trivia = SyntaxFactory.WhitespaceTrivia(" "); 33 | 34 | AssertAnnotation(root.WithLeadingTrivia(trivia)); 35 | } 36 | 37 | [Fact] 38 | public void AddingEmptyElementTriviaPreservesAnnotations() 39 | { 40 | var root = GetRootEmptyElementSyntax(""); 41 | var trivia = SyntaxFactory.WhitespaceTrivia(" "); 42 | 43 | AssertAnnotation(root.WithLeadingTrivia(trivia)); 44 | } 45 | 46 | private static void AssertAnnotation(T element) where T : SyntaxNode 47 | { 48 | Assert.True(element.ContainsAnnotations); 49 | element.HasAnnotation(annotation); 50 | } 51 | 52 | private static void AssertAnnotation(IXmlElementSyntax element) 53 | { 54 | AssertAnnotation((SyntaxNode)element); 55 | } 56 | 57 | private static XmlElementSyntax GetRootElementSyntax(string xml) 58 | { 59 | return Assert.IsType(Parser.ParseText(xml).RootSyntax) 60 | .WithAdditionalAnnotations(annotation); 61 | } 62 | 63 | private static XmlEmptyElementSyntax GetRootEmptyElementSyntax(string xml) 64 | { 65 | return Assert.IsType(Parser.ParseText(xml).RootSyntax) 66 | .WithAdditionalAnnotations(annotation); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Tests/TestApi.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Xunit; 3 | 4 | namespace Microsoft.Language.Xml.Tests 5 | { 6 | public class TestApi 7 | { 8 | [Fact] 9 | public void TestAttributeValue() 10 | { 11 | var root = Parser.ParseText("")?.RootSyntax; 12 | var attributeValue = root.Attributes.First().Value; 13 | Assert.Equal("", attributeValue); 14 | } 15 | 16 | /// 17 | /// 2.2.12 [XML] Section 3.3.3, Attribute-Value Normalization 18 | /// 19 | /// 20 | [Fact] 21 | public void TestAttributeValueNormalization() 22 | { 23 | const string AllWhitespace = " \n\t"; 24 | var xml = $""; 25 | var root = Parser.ParseText(xml)?.RootSyntax; 26 | 27 | var attributeValue = root.Attributes.First().Value; 28 | Assert.Equal(" X ", attributeValue); 29 | } 30 | 31 | [Fact] 32 | public void TestContent() 33 | { 34 | var root = Parser.ParseText("Content")?.Root; 35 | var value = root.Value; 36 | Assert.Equal("Content", value); 37 | } 38 | 39 | [Fact] 40 | public void TestRootLevel() 41 | { 42 | var root = Parser.ParseText("")?.Root; 43 | Assert.Equal("Root", root.Name); 44 | } 45 | 46 | [Fact] 47 | public void TestRootLevelTrivia() 48 | { 49 | var root = Parser.ParseText("")?.Root; 50 | Assert.Equal("Root", root.Name); 51 | } 52 | 53 | [Fact] 54 | public void TestRootLevelTriviaWithDeclaration() 55 | { 56 | var root = Parser.ParseText("")?.Root; 57 | Assert.Equal("Root", root.Name); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/Microsoft.Language.Xml.Tests/TestComments.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.Language.Xml.Comments; 4 | using Microsoft.Language.Xml.Tests.Properties; 5 | using Xunit; 6 | 7 | namespace Microsoft.Language.Xml.Tests 8 | { 9 | public class TestComments 10 | { 11 | [Fact] 12 | public void CommentElementContent() 13 | { 14 | TC(Resources.TestXml, TextSpan.FromBounds(199, 209), 15 | TextSpan.FromBounds(199, 209)); 16 | 17 | // Test at edges xml element content 18 | TC(Resources.TestXml, TextSpan.FromBounds(276, 350), 19 | TextSpan.FromBounds(276, 350)); 20 | } 21 | 22 | [Fact] 23 | public void CommentSingleCharacter() 24 | { 25 | TC(Resources.TestXml, TextSpan.FromBounds(722, 723), 26 | TextSpan.FromBounds(722, 723)); 27 | } 28 | 29 | [Fact] 30 | public void CommentExpandsExcludingElementWhitespace() 31 | { 32 | TC(Resources.TestXml, TextSpan.FromBounds(451, 453), 33 | TextSpan.FromBounds(444, 513)); 34 | } 35 | 36 | [Fact] 37 | public void CommentMultipleElements() 38 | { 39 | TC(Resources.TestXml, TextSpan.FromBounds(753, 912), 40 | TextSpan.FromBounds(740, 919)); 41 | 42 | TC(Resources.TestXml, TextSpan.FromBounds(823, 911), 43 | TextSpan.FromBounds(818, 919)); 44 | } 45 | 46 | [Fact] 47 | public void CommentDeclaration() 48 | { 49 | TC(Resources.TestXml, TextSpan.FromBounds(22, 25), 50 | TextSpan.FromBounds(0, 39)); 51 | } 52 | 53 | [Fact] 54 | public void CommentedDeclaration() 55 | { 56 | TU(Resources.TestXml.Insert(39, "-->").Insert(0, " 11 | 12 | 13 | 14 | 15 | en-US 16 | false 17 | $currentVersion$ 18 | Microsoft 19 | http://www.apache.org/licenses/LICENSE-2.0.html 20 | http://github.com/KirillOsenkov/XmlParser 21 | 22 | 23 | 24 | Xml LanguageService Classifier VS VisualStudio Editor 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "1.2", 4 | "assemblyVersion": "1.0", 5 | "buildNumberOffset": 0, 6 | "publicReleaseRefSpec": [ 7 | "^refs/heads/main$", // we release out of master 8 | "^refs/heads/v\\d+(?:.\\d+)?$" // we also release out of vNN branches 9 | ], 10 | "cloudBuild": { 11 | "setVersionVariables": true, 12 | "buildNumber": { 13 | "enabled": true, 14 | "includeCommitId": { 15 | "when": "always", 16 | "where": "buildMetadata" 17 | } 18 | } 19 | } 20 | } 21 | --------------------------------------------------------------------------------