Merge pull request #22294 from dotnet/johluo/migrate-more-tooling

Johluo/migrate more tooling
This commit is contained in:
John Luo 2020-05-27 23:41:33 -07:00 committed by GitHub
commit 278715734e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 7182 additions and 9 deletions

View File

@ -149,7 +149,7 @@ stages:
$(_InternalRuntimeDownloadArgs)
displayName: Build x86
# This is in a separate build step with to workaround MAX_PATH limitations - https://github.com/Microsoft/msbuild/issues/53
# This is in a separate build step with -forceCoreMsbuild to workaround MAX_PATH limitations - https://github.com/Microsoft/msbuild/issues/53
- script: .\src\SiteExtensions\build.cmd
-ci
-nobl

View File

@ -0,0 +1 @@
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]

View File

@ -0,0 +1,58 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class CodeGenerationBenchmark
{
public CodeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
MSN = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"), FileKinds.Legacy);
}
public RazorProjectEngine ProjectEngine { get; }
public RazorProjectItem MSN { get; }
[Benchmark(Description = "Razor Design Time Code Generation of MSN.com")]
public void CodeGeneration_DesignTime_LargeStaticFile()
{
var codeDocument = ProjectEngine.ProcessDesignTime(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Code Generation of MSN.com")]
public void CodeGeneration_Runtime_LargeStaticFile()
{
var codeDocument = ProjectEngine.Process(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
<ExcludeFromSourceBuild>true</ExcludeFromSourceBuild>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Mvc.Razor.Extensions" />
<Reference Include="BenchmarkDotNet" />
<Reference Include="Newtonsoft.Json" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,77 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class SyntaxTreeGenerationBenchmark
{
public SyntaxTreeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
var projectItem = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"), FileKinds.Legacy);
MSN = RazorSourceDocument.ReadFrom(projectItem);
var directiveFeature = ProjectEngine.EngineFeatures.OfType<IRazorDirectiveFeature>().FirstOrDefault();
Directives = directiveFeature?.Directives.ToArray() ?? Array.Empty<DirectiveDescriptor>();
}
public RazorProjectEngine ProjectEngine { get; }
public RazorSourceDocument MSN { get; }
public DirectiveDescriptor[] Directives { get; }
[Benchmark(Description = "Razor Design Time Syntax Tree Generation of MSN.com")]
public void SyntaxTreeGeneration_DesignTime_LargeStaticFile()
{
var options = RazorParserOptions.CreateDesignTime(o =>
{
foreach (var directive in Directives)
{
o.Directives.Add(directive);
}
});
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
if (syntaxTree.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Syntax Tree Generation of MSN.com")]
public void SyntaxTreeGeneration_Runtime_LargeStaticFile()
{
var options = RazorParserOptions.Create(o =>
{
foreach (var directive in Directives)
{
o.Directives.Add(directive);
}
});
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
if (syntaxTree.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
}
}
}
}

View File

@ -0,0 +1,11 @@
Compile the solution in Release mode (so binaries are available in release)
To run a specific benchmark add it as parameter.
```
dotnet run -c Release <benchmark_name>
```
If you run without any parameters, you'll be offered the list of all benchmarks and get to choose.
```
dotnet run -c Release
```

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
<Project>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
<PropertyGroup>
<DisablePubternalApiCheck>true</DisablePubternalApiCheck>
</PropertyGroup>
</Project>

View File

@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<DisablePubternalApiCheck>true</DisablePubternalApiCheck>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,358 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace RazorSyntaxGenerator
{
internal abstract class AbstractFileWriter
{
private readonly TextWriter _writer;
private readonly Tree _tree;
private readonly IDictionary<string, string> _parentMap;
private readonly ILookup<string, string> _childMap;
private readonly IDictionary<string, Node> _nodeMap;
private readonly IDictionary<string, TreeType> _typeMap;
private const int INDENT_SIZE = 4;
private int _indentLevel;
private bool _needIndent = true;
protected AbstractFileWriter(TextWriter writer, Tree tree)
{
_writer = writer;
_tree = tree;
_nodeMap = tree.Types.OfType<Node>().ToDictionary(n => n.Name);
_typeMap = tree.Types.ToDictionary(n => n.Name);
_parentMap = tree.Types.ToDictionary(n => n.Name, n => n.Base);
_parentMap.Add(tree.Root, null);
_childMap = tree.Types.ToLookup(n => n.Base, n => n.Name);
}
protected IDictionary<string, string> ParentMap { get { return _parentMap; } }
protected ILookup<string, string> ChildMap { get { return _childMap; } }
protected Tree Tree { get { return _tree; } }
#region Output helpers
protected void Indent()
{
_indentLevel++;
}
protected void Unindent()
{
if (_indentLevel <= 0)
{
throw new InvalidOperationException("Cannot unindent from base level");
}
_indentLevel--;
}
protected void Write(string msg)
{
WriteIndentIfNeeded();
_writer.Write(msg);
}
protected void Write(string msg, params object[] args)
{
WriteIndentIfNeeded();
_writer.Write(msg, args);
}
protected void WriteLine()
{
WriteLine("");
}
protected void WriteLine(string msg)
{
WriteIndentIfNeeded();
_writer.WriteLine(msg);
_needIndent = true; //need an indent after each line break
}
protected void WriteLine(string msg, params object[] args)
{
WriteIndentIfNeeded();
_writer.WriteLine(msg, args);
_needIndent = true; //need an indent after each line break
}
private void WriteIndentIfNeeded()
{
if (_needIndent)
{
_writer.Write(new string(' ', _indentLevel * INDENT_SIZE));
_needIndent = false;
}
}
protected void OpenBlock()
{
WriteLine("{");
Indent();
}
protected void CloseBlock()
{
Unindent();
WriteLine("}");
}
#endregion Output helpers
#region Node helpers
protected static string OverrideOrNewModifier(Field field)
{
return IsOverride(field) ? "override " : IsNew(field) ? "new " : "";
}
protected static bool CanBeField(Field field)
{
return field.Type != "SyntaxToken" && !IsAnyList(field.Type) && !IsOverride(field) && !IsNew(field);
}
protected static string GetFieldType(Field field, bool green)
{
if (IsAnyList(field.Type))
{
return green
? "GreenNode"
: "SyntaxNode";
}
return field.Type;
}
protected bool IsDerivedOrListOfDerived(string baseType, string derivedType)
{
return IsDerivedType(baseType, derivedType)
|| ((IsNodeList(derivedType) || IsSeparatedNodeList(derivedType))
&& IsDerivedType(baseType, GetElementType(derivedType)));
}
protected static bool IsSeparatedNodeList(string typeName)
{
return typeName.StartsWith("SeparatedSyntaxList<", StringComparison.Ordinal);
}
protected static bool IsNodeList(string typeName)
{
return typeName.StartsWith("SyntaxList<", StringComparison.Ordinal);
}
protected static bool IsAnyNodeList(string typeName)
{
return IsNodeList(typeName) || IsSeparatedNodeList(typeName);
}
protected bool IsNodeOrNodeList(string typeName)
{
return IsNode(typeName) || IsNodeList(typeName) || IsSeparatedNodeList(typeName) || typeName == "SyntaxNodeOrTokenList";
}
protected static string GetElementType(string typeName)
{
if (!typeName.Contains("<"))
return string.Empty;
var iStart = typeName.IndexOf('<');
var iEnd = typeName.IndexOf('>', iStart + 1);
if (iEnd < iStart)
return string.Empty;
var sub = typeName.Substring(iStart + 1, iEnd - iStart - 1);
return sub;
}
protected static bool IsAnyList(string typeName)
{
return IsNodeList(typeName) || IsSeparatedNodeList(typeName) || typeName == "SyntaxNodeOrTokenList";
}
protected bool IsDerivedType(string typeName, string derivedTypeName)
{
if (typeName == derivedTypeName)
return true;
if (derivedTypeName != null && _parentMap.TryGetValue(derivedTypeName, out var baseType))
{
return IsDerivedType(typeName, baseType);
}
return false;
}
protected static bool IsRoot(Node n)
{
return n.Root != null && string.Compare(n.Root, "true", true) == 0;
}
protected bool IsNode(string typeName)
{
return _parentMap.ContainsKey(typeName);
}
protected Node GetNode(string typeName)
=> _nodeMap.TryGetValue(typeName, out var node) ? node : null;
protected TreeType GetTreeType(string typeName)
=> _typeMap.TryGetValue(typeName, out var node) ? node : null;
protected static bool IsOptional(Field f)
{
return f.Optional != null && string.Compare(f.Optional, "true", true) == 0;
}
protected static bool IsOverride(Field f)
{
return f.Override != null && string.Compare(f.Override, "true", true) == 0;
}
protected static bool IsNew(Field f)
{
return f.New != null && string.Compare(f.New, "true", true) == 0;
}
protected static bool HasErrors(Node n)
{
return n.Errors == null || string.Compare(n.Errors, "true", true) == 0;
}
protected static string CamelCase(string name)
{
if (char.IsUpper(name[0]))
{
name = char.ToLowerInvariant(name[0]) + name.Substring(1);
}
return FixKeyword(name);
}
protected static string FixKeyword(string name)
{
if (IsKeyword(name))
{
return "@" + name;
}
return name;
}
protected static string UnderscoreCamelCase(string name)
{
return "_" + CamelCase(name);
}
protected string StripNode(string name)
{
return (_tree.Root.EndsWith("Node", StringComparison.Ordinal)) ? _tree.Root.Substring(0, _tree.Root.Length - 4) : _tree.Root;
}
protected string StripRoot(string name)
{
var root = StripNode(_tree.Root);
if (name.EndsWith(root, StringComparison.Ordinal))
{
return name.Substring(0, name.Length - root.Length);
}
return name;
}
protected static string StripPost(string name, string post)
{
return name.EndsWith(post, StringComparison.Ordinal)
? name.Substring(0, name.Length - post.Length)
: name;
}
protected static bool IsKeyword(string name)
{
switch (name)
{
case "bool":
case "byte":
case "sbyte":
case "short":
case "ushort":
case "int":
case "uint":
case "long":
case "ulong":
case "double":
case "float":
case "decimal":
case "string":
case "char":
case "object":
case "typeof":
case "sizeof":
case "null":
case "true":
case "false":
case "if":
case "else":
case "while":
case "for":
case "foreach":
case "do":
case "switch":
case "case":
case "default":
case "lock":
case "try":
case "throw":
case "catch":
case "finally":
case "goto":
case "break":
case "continue":
case "return":
case "public":
case "private":
case "internal":
case "protected":
case "static":
case "readonly":
case "sealed":
case "const":
case "new":
case "override":
case "abstract":
case "virtual":
case "partial":
case "ref":
case "out":
case "in":
case "where":
case "params":
case "this":
case "base":
case "namespace":
case "using":
case "class":
case "struct":
case "interface":
case "delegate":
case "checked":
case "get":
case "set":
case "add":
case "remove":
case "operator":
case "implicit":
case "explicit":
case "fixed":
case "extern":
case "event":
case "enum":
case "unsafe":
return true;
default:
return false;
}
}
#endregion Node helpers
}
}

View File

@ -0,0 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class AbstractNode : TreeType
{
[XmlElement(ElementName = "Field", Type = typeof(Field))]
public List<Field> Fields;
}
}

View File

@ -0,0 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Xml;
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class Comment
{
[XmlAnyElement]
public XmlElement[] Body;
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class Field
{
[XmlAttribute]
public string Name;
[XmlAttribute]
public string Type;
[XmlAttribute]
public string Optional;
[XmlAttribute]
public string Override;
[XmlAttribute]
public string New;
[XmlElement(ElementName = "Kind", Type = typeof(Kind))]
public List<Kind> Kinds;
[XmlElement]
public Comment PropertyComment;
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class Kind
{
[XmlAttribute]
public string Name;
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class Node : TreeType
{
[XmlAttribute]
public string Root;
[XmlAttribute]
public string Errors;
[XmlElement(ElementName = "Kind", Type = typeof(Kind))]
public List<Kind> Kinds;
[XmlElement(ElementName = "Field", Type = typeof(Field))]
public List<Field> Fields;
}
}

View File

@ -0,0 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace RazorSyntaxGenerator
{
public class PredefinedNode : TreeType
{
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
[XmlRoot]
public class Tree
{
[XmlAttribute]
public string Root;
[XmlElement(ElementName = "Node", Type = typeof(Node))]
[XmlElement(ElementName = "AbstractNode", Type = typeof(AbstractNode))]
[XmlElement(ElementName = "PredefinedNode", Type = typeof(PredefinedNode))]
public List<TreeType> Types;
}
}

View File

@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class TreeType
{
[XmlAttribute]
public string Name;
[XmlAttribute]
public string Base;
[XmlElement]
public Comment TypeComment;
[XmlElement]
public Comment FactoryComment;
}
}

View File

@ -0,0 +1,112 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace RazorSyntaxGenerator
{
public class Program
{
public static int Main(string[] args)
{
if (args.Length < 2 || args.Length > 2)
{
WriteUsage();
return 1;
}
var inputFile = args[0];
if (!File.Exists(inputFile))
{
Console.WriteLine(Directory.GetCurrentDirectory());
Console.WriteLine(inputFile + " not found.");
return 1;
}
var writeSource = true;
var writeSignatures = false;
string outputFile = null;
if (args.Length == 2)
{
if (args[1] == "/sig")
{
writeSignatures = true;
}
else
{
outputFile = args[1];
}
}
var reader = XmlReader.Create(inputFile, new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit });
var serializer = new XmlSerializer(typeof(Tree));
var tree = (Tree)serializer.Deserialize(reader);
if (writeSignatures)
{
SignatureWriter.Write(Console.Out, tree);
}
else
{
if (writeSource)
{
var outputPath = outputFile.Trim('"');
var prefix = Path.GetFileName(inputFile);
var outputMainFile = Path.Combine(outputPath, $"{prefix}.Main.Generated.cs");
var outputInternalFile = Path.Combine(outputPath, $"{prefix}.Internal.Generated.cs");
var outputSyntaxFile = Path.Combine(outputPath, $"{prefix}.Syntax.Generated.cs");
WriteToFile(tree, SourceWriter.WriteMain, outputMainFile);
WriteToFile(tree, SourceWriter.WriteInternal, outputInternalFile);
WriteToFile(tree, SourceWriter.WriteSyntax, outputSyntaxFile);
}
//if (writeTests)
//{
// WriteToFile(tree, TestWriter.Write, outputFile);
//}
}
return 0;
}
private static void WriteUsage()
{
Console.WriteLine("Invalid usage");
Console.WriteLine(typeof(Program).GetTypeInfo().Assembly.ManifestModule.Name + " input-file output-file [/write-test]");
}
private static void WriteToFile(Tree tree, Action<TextWriter, Tree> writeAction, string outputFile)
{
var stringBuilder = new StringBuilder();
var writer = new StringWriter(stringBuilder);
writeAction(writer, tree);
var text = stringBuilder.ToString();
int length;
do
{
length = text.Length;
text = text.Replace("{\r\n\r\n", "{\r\n");
} while (text.Length != length);
try
{
using (var outFile = new StreamWriter(File.Open(outputFile, FileMode.Create), Encoding.UTF8))
{
outFile.Write(text);
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Unable to access {0}. Is it checked out?", outputFile);
}
}
}
}

View File

@ -0,0 +1,7 @@
# Razor syntax generator
Syntax generator tool for the Razor syntax tree. This is a modified version of Roslyn's [CSharpSyntaxGenerator](https://github.com/dotnet/roslyn/tree/master/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator). For internal use only.
## Usage
dotnet run `full/path/to/Syntax.xml` `full/path/to/generated/output`

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Generates Razor syntax nodes from xml. For internal use only.</Description>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>dotnet-razorsyntaxgenerator</AssemblyName>
<PackageId>RazorSyntaxGenerator</PackageId>
<OutputType>Exe</OutputType>
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,130 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace RazorSyntaxGenerator
{
internal class SignatureWriter
{
private readonly TextWriter _writer;
private readonly Tree _tree;
private readonly Dictionary<string, string> _typeMap;
private SignatureWriter(TextWriter writer, Tree tree)
{
_writer = writer;
_tree = tree;
_typeMap = tree.Types.ToDictionary(n => n.Name, n => n.Base);
_typeMap.Add(tree.Root, null);
}
public static void Write(TextWriter writer, Tree tree)
{
new SignatureWriter(writer, tree).WriteFile();
}
private void WriteFile()
{
_writer.WriteLine("using System;");
_writer.WriteLine("using System.Collections;");
_writer.WriteLine("using System.Collections.Generic;");
_writer.WriteLine("using System.Linq;");
_writer.WriteLine("using System.Threading;");
_writer.WriteLine();
_writer.WriteLine("namespace Microsoft.AspNetCore.Razor.Language.Syntax");
_writer.WriteLine("{");
this.WriteTypes();
_writer.WriteLine("}");
}
private void WriteTypes()
{
var nodes = _tree.Types.Where(n => !(n is PredefinedNode)).ToList();
for (int i = 0, n = nodes.Count; i < n; i++)
{
var node = nodes[i];
_writer.WriteLine();
WriteType(node);
}
}
private void WriteType(TreeType node)
{
if (node is AbstractNode abstractNode)
{
_writer.WriteLine(" public abstract partial class {0} : {1}", node.Name, node.Base);
_writer.WriteLine(" {");
for (int i = 0, n = abstractNode.Fields.Count; i < n; i++)
{
var field = abstractNode.Fields[i];
if (IsNodeOrNodeList(field.Type))
{
_writer.WriteLine(" public abstract {0}{1} {2} {{ get; }}", "", field.Type, field.Name);
}
}
_writer.WriteLine(" }");
}
else if (node is Node nd)
{
_writer.WriteLine(" public partial class {0} : {1}", node.Name, node.Base);
_writer.WriteLine(" {");
WriteKinds(nd.Kinds);
var valueFields = nd.Fields.Where(n => !IsNodeOrNodeList(n.Type)).ToList();
var nodeFields = nd.Fields.Where(n => IsNodeOrNodeList(n.Type)).ToList();
for (int i = 0, n = nodeFields.Count; i < n; i++)
{
var field = nodeFields[i];
_writer.WriteLine(" public {0}{1}{2} {3} {{ get; }}", "", "", field.Type, field.Name);
}
for (int i = 0, n = valueFields.Count; i < n; i++)
{
var field = valueFields[i];
_writer.WriteLine(" public {0}{1}{2} {3} {{ get; }}", "", "", field.Type, field.Name);
}
_writer.WriteLine(" }");
}
}
private void WriteKinds(List<Kind> kinds)
{
if (kinds.Count > 1)
{
foreach (var kind in kinds)
{
_writer.WriteLine(" // {0}", kind.Name);
}
}
}
private bool IsSeparatedNodeList(string typeName)
{
return typeName.StartsWith("SeparatedSyntaxList<", StringComparison.Ordinal);
}
private bool IsNodeList(string typeName)
{
return typeName.StartsWith("SyntaxList<", StringComparison.Ordinal);
}
public bool IsNodeOrNodeList(string typeName)
{
return IsNode(typeName) || IsNodeList(typeName) || IsSeparatedNodeList(typeName);
}
private bool IsNode(string typeName)
{
return _typeMap.ContainsKey(typeName);
}
}
}

File diff suppressed because it is too large Load Diff