From f6bf80291b8e8921caf21a3fc79c947923415f1e Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 28 May 2020 16:32:08 -0700 Subject: [PATCH] Remove RazorSyntaxGenerator --- .../AbstractFileWriter.cs | 358 --- .../Model/AbstractNode.cs | 14 - .../RazorSyntaxGenerator/Model/Comment.cs | 14 - .../tools/RazorSyntaxGenerator/Model/Field.cs | 32 - .../tools/RazorSyntaxGenerator/Model/Kind.cs | 13 - .../tools/RazorSyntaxGenerator/Model/Node.cs | 23 - .../Model/PredefinedNode.cs | 9 - .../tools/RazorSyntaxGenerator/Model/Tree.cs | 20 - .../RazorSyntaxGenerator/Model/TreeType.cs | 22 - .../tools/RazorSyntaxGenerator/Program.cs | 112 - .../tools/RazorSyntaxGenerator/README.md | 7 - .../RazorSyntaxGenerator.csproj | 12 - .../RazorSyntaxGenerator/SignatureWriter.cs | 130 - .../RazorSyntaxGenerator/SourceWriter.cs | 2262 ----------------- 14 files changed, 3028 deletions(-) delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/AbstractFileWriter.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/AbstractNode.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/Comment.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/Field.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/Kind.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/Node.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/PredefinedNode.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/Tree.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Model/TreeType.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/Program.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/README.md delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/RazorSyntaxGenerator.csproj delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/SignatureWriter.cs delete mode 100644 src/Razor/tools/RazorSyntaxGenerator/SourceWriter.cs diff --git a/src/Razor/tools/RazorSyntaxGenerator/AbstractFileWriter.cs b/src/Razor/tools/RazorSyntaxGenerator/AbstractFileWriter.cs deleted file mode 100644 index bae61b5e74a..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/AbstractFileWriter.cs +++ /dev/null @@ -1,358 +0,0 @@ -// 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 _parentMap; - private readonly ILookup _childMap; - private readonly IDictionary _nodeMap; - private readonly IDictionary _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().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 ParentMap { get { return _parentMap; } } - protected ILookup 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 - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/AbstractNode.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/AbstractNode.cs deleted file mode 100644 index bc120f8095c..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/AbstractNode.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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 Fields; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/Comment.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/Comment.cs deleted file mode 100644 index 7b26ed940b2..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/Comment.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/Field.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/Field.cs deleted file mode 100644 index fe900160b0f..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/Field.cs +++ /dev/null @@ -1,32 +0,0 @@ -// 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 Kinds; - - [XmlElement] - public Comment PropertyComment; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/Kind.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/Kind.cs deleted file mode 100644 index fb1254d500f..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/Kind.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/Node.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/Node.cs deleted file mode 100644 index 365bc4d3934..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/Node.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 Kinds; - - [XmlElement(ElementName = "Field", Type = typeof(Field))] - public List Fields; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/PredefinedNode.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/PredefinedNode.cs deleted file mode 100644 index 8fb09e6ca8d..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/PredefinedNode.cs +++ /dev/null @@ -1,9 +0,0 @@ -// 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 - { - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/Tree.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/Tree.cs deleted file mode 100644 index 000b5aaf19e..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/Tree.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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 Types; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Model/TreeType.cs b/src/Razor/tools/RazorSyntaxGenerator/Model/TreeType.cs deleted file mode 100644 index 8900c786f44..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Model/TreeType.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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; - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/Program.cs b/src/Razor/tools/RazorSyntaxGenerator/Program.cs deleted file mode 100644 index 63989d26e64..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/Program.cs +++ /dev/null @@ -1,112 +0,0 @@ -// 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 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); - } - } - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/README.md b/src/Razor/tools/RazorSyntaxGenerator/README.md deleted file mode 100644 index c19e1d681b5..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# 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` \ No newline at end of file diff --git a/src/Razor/tools/RazorSyntaxGenerator/RazorSyntaxGenerator.csproj b/src/Razor/tools/RazorSyntaxGenerator/RazorSyntaxGenerator.csproj deleted file mode 100644 index 93665f7d14d..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/RazorSyntaxGenerator.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Generates Razor syntax nodes from xml. For internal use only. - netcoreapp2.1 - dotnet-razorsyntaxgenerator - RazorSyntaxGenerator - Exe - false - - - diff --git a/src/Razor/tools/RazorSyntaxGenerator/SignatureWriter.cs b/src/Razor/tools/RazorSyntaxGenerator/SignatureWriter.cs deleted file mode 100644 index e7aefb38b9b..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/SignatureWriter.cs +++ /dev/null @@ -1,130 +0,0 @@ -// 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 _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 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); - } - } -} diff --git a/src/Razor/tools/RazorSyntaxGenerator/SourceWriter.cs b/src/Razor/tools/RazorSyntaxGenerator/SourceWriter.cs deleted file mode 100644 index 5a9a7112bbd..00000000000 --- a/src/Razor/tools/RazorSyntaxGenerator/SourceWriter.cs +++ /dev/null @@ -1,2262 +0,0 @@ -// 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; -using System.Xml; - -namespace RazorSyntaxGenerator -{ - internal class SourceWriter : AbstractFileWriter - { - private SourceWriter(TextWriter writer, Tree tree) - : base(writer, tree) - { - } - - public static void WriteMain(TextWriter writer, Tree tree) => new SourceWriter(writer, tree).WriteMain(); - - public static void WriteInternal(TextWriter writer, Tree tree) => new SourceWriter(writer, tree).WriteInternal(); - - public static void WriteSyntax(TextWriter writer, Tree tree) => new SourceWriter(writer, tree).WriteSyntax(); - - private void WriteFileHeader() - { - WriteLine("// "); - WriteLine(); - WriteLine("using System;"); - WriteLine("using System.Collections;"); - WriteLine("using System.Collections.Generic;"); - WriteLine("using System.Linq;"); - WriteLine("using System.Threading;"); - WriteLine(); - } - - private void WriteInternal() - { - WriteFileHeader(); - - WriteLine("namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax"); - WriteLine("{"); - WriteLine(); - WriteGreenTypes(); - WriteGreenVisitors(); - WriteGreenRewriter(); - WriteStaticGreenFactories(); - WriteLine("}"); - } - - private void WriteSyntax() - { - WriteFileHeader(); - - WriteLine(); - WriteLine("namespace Microsoft.AspNetCore.Razor.Language.Syntax"); - WriteLine("{"); - WriteLine(); - WriteRedTypes(); - WriteLine("}"); - } - - private void WriteMain() - { - WriteFileHeader(); - - WriteLine(); - WriteLine("namespace Microsoft.AspNetCore.Razor.Language.Syntax"); - WriteLine("{"); - //WriteLine(" using Microsoft.AspNetCore.Razor.Language.Syntax;"); - //WriteLine(); - WriteRedVisitors(); - WriteRedRewriter(); - WriteRedFactories(); - WriteLine("}"); - } - - private void WriteGreenTypes() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode)).ToList(); - for (int i = 0, n = nodes.Count; i < n; i++) - { - var node = nodes[i]; - WriteLine(); - WriteGreenType(node); - } - } - - private void WriteGreenType(TreeType node) - { - WriteComment(node.TypeComment, " "); - - if (node is AbstractNode) - { - AbstractNode nd = (AbstractNode)node; - WriteLine(" internal abstract partial class {0} : {1}", node.Name, node.Base == "SyntaxNode" ? "GreenNode" : node.Base); - WriteLine(" {"); - - // ctor with diagnostics and annotations - WriteLine(" internal {0}(SyntaxKind kind, RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)", node.Name); - WriteLine(" : base(kind, diagnostics, annotations)"); - WriteLine(" {"); - if (node.Name == "DirectiveTriviaSyntax") - { - WriteLine(" _flags |= NodeFlags.ContainsDirectives;"); - } - WriteLine(" }"); - - // ctor without diagnostics and annotations - WriteLine(" internal {0}(SyntaxKind kind)", node.Name); - WriteLine(" : base(kind)"); - WriteLine(" {"); - if (node.Name == "DirectiveTriviaSyntax") - { - WriteLine(" _flags |= NodeFlags.ContainsDirectives;"); - } - WriteLine(" }"); - - /* Remove - // object reader constructor - WriteLine(); - WriteLine(" protected {0}(ObjectReader reader)", node.Name); - WriteLine(" : base(reader)"); - WriteLine(" {"); - if (node.Name == "DirectiveTriviaSyntax") - { - WriteLine(" _flags |= NodeFlags.ContainsDirectives;"); - } - WriteLine(" }"); */ - - 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]; - if (IsNodeOrNodeList(field.Type)) - { - WriteLine(); - WriteComment(field.PropertyComment, " "); - - if (IsSeparatedNodeList(field.Type) || - IsNodeList(field.Type)) - { - WriteLine(" public abstract {0}{1} {2} {{ get; }}", - (IsNew(field) ? "new " : ""), field.Type, field.Name); - } - else - { - WriteLine(" public abstract {0}{1} {2} {{ get; }}", - (IsNew(field) ? "new " : ""), field.Type, field.Name); - } - } - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - WriteLine(); - WriteComment(field.PropertyComment, " "); - - WriteLine(" public abstract {0}{1} {2} {{ get; }}", - (IsNew(field) ? "new " : ""), field.Type, field.Name); - } - - WriteLine(" }"); - } - else if (node is Node) - { - Node nd = (Node)node; - - WriteLine(" internal sealed partial class {0} : {1}", node.Name, node.Base); - WriteLine(" {"); - - 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]; - var type = GetFieldType(field, green: true); - WriteLine(" private readonly {0} {1};", type, UnderscoreCamelCase(field.Name)); - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - WriteLine(" private readonly {0} {1};", field.Type, UnderscoreCamelCase(field.Name)); - } - - // write constructor with diagnostics and annotations - WriteLine(); - Write(" internal {0}(SyntaxKind kind", node.Name); - - WriteGreenNodeConstructorArgs(nodeFields, valueFields); - - WriteLine(", RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)"); - WriteLine(" : base(kind, diagnostics, annotations)"); - WriteLine(" {"); - WriteCtorBody(valueFields, nodeFields); - WriteLine(" }"); - WriteLine(); - - /* Remove - // write constructor with async - WriteLine(); - Write(" internal {0}(SyntaxKind kind", node.Name); - - WriteGreenNodeConstructorArgs(nodeFields, valueFields); - - WriteLine(", SyntaxFactoryContext context)"); - WriteLine(" : base(kind)"); - WriteLine(" {"); - WriteLine(" this.SetFactoryContext(context);"); - WriteCtorBody(valueFields, nodeFields); - WriteLine(" }"); - WriteLine(); */ - - // write constructor without diagnostics and annotations - WriteLine(); - Write(" internal {0}(SyntaxKind kind", node.Name); - - WriteGreenNodeConstructorArgs(nodeFields, valueFields); - - WriteLine(")"); - WriteLine(" : base(kind)"); - WriteLine(" {"); - WriteCtorBody(valueFields, nodeFields); - WriteLine(" }"); - WriteLine(); - - // property accessors - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - WriteComment(field.PropertyComment, " "); - if (IsNodeList(field.Type)) - { - WriteLine(" public {0}{1} {2} {{ get {{ return new {1}({3}); }} }}", - OverrideOrNewModifier(field), field.Type, field.Name, UnderscoreCamelCase(field.Name) - ); - } - else if (IsSeparatedNodeList(field.Type)) - { - WriteLine(" public {0}{1} {2} {{ get {{ return new {1}(new SyntaxList({3})); }} }}", - OverrideOrNewModifier(field), field.Type, field.Name, UnderscoreCamelCase(field.Name), i - ); - } - else if (field.Type == "SyntaxNodeOrTokenList") - { - WriteLine(" public {0}SyntaxList {1} {{ get {{ return new SyntaxList({2}); }} }}", - OverrideOrNewModifier(field), field.Name, UnderscoreCamelCase(field.Name) - ); - } - else - { - WriteLine(" public {0}{1} {2} {{ get {{ return {3}; }} }}", - OverrideOrNewModifier(field), field.Type, field.Name, UnderscoreCamelCase(field.Name) - ); - } - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - WriteComment(field.PropertyComment, " "); - WriteLine(" public {0}{1} {2} {{ get {{ return {3}; }} }}", - OverrideOrNewModifier(field), field.Type, field.Name, UnderscoreCamelCase(field.Name) - ); - } - - // GetSlot - WriteLine(); - WriteLine(" internal override GreenNode GetSlot(int index)"); - WriteLine(" {"); - WriteLine(" switch (index)"); - WriteLine(" {"); - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - WriteLine(" case {0}: return {1};", i, UnderscoreCamelCase(field.Name)); - } - WriteLine(" default: return null;"); - WriteLine(" }"); - WriteLine(" }"); - - WriteLine(); - WriteLine(" internal override SyntaxNode CreateRed(SyntaxNode parent, int position)"); - WriteLine(" {"); - WriteLine(" return new Syntax.{0}(this, parent, position);", node.Name); - WriteLine(" }"); - - WriteGreenAcceptMethods(nd); - WriteGreenUpdateMethod(nd); - WriteSetDiagnostics(nd); - WriteSetAnnotations(nd); - - WriteLine(" }"); - } - } - - private void WriteGreenNodeConstructorArgs(List nodeFields, List valueFields) - { - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - string type = GetFieldType(field, green: true); - - Write(", {0} {1}", type, CamelCase(field.Name)); - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - Write(", {0} {1}", field.Type, CamelCase(field.Name)); - } - } - - private void WriteGreenSerialization(Node node) - { - var valueFields = node.Fields.Where(n => !IsNodeOrNodeList(n.Type)).ToList(); - var nodeFields = node.Fields.Where(n => IsNodeOrNodeList(n.Type)).ToList(); - - // object reader constructor - WriteLine(); - WriteLine(" internal {0}(ObjectReader reader)", node.Name); - WriteLine(" : base(reader)"); - WriteLine(" {"); - - WriteLine(" this.SlotCount = {0};", nodeFields.Count); - - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - string type = GetFieldType(field, green: true); - WriteLine(" var {0} = ({1})reader.ReadValue();", CamelCase(field.Name), type); - WriteLine(" if ({0} != null)", CamelCase(field.Name)); - WriteLine(" {"); - WriteLine(" AdjustFlagsAndWidth({0});", CamelCase(field.Name)); - WriteLine(" this.{0} = {0};", CamelCase(field.Name), type); - WriteLine(" }"); - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - string type = GetFieldType(field, green: true); - WriteLine(" this.{0} = ({1})reader.{2}();", CamelCase(field.Name), type, GetReaderMethod(type)); - } - - WriteLine(" }"); - - // IWritable - WriteLine(); - WriteLine(" internal override void WriteTo(ObjectWriter writer)"); - WriteLine(" {"); - WriteLine(" base.WriteTo(writer);"); - - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - string type = GetFieldType(field, green: true); - WriteLine(" writer.WriteValue(this.{0});", CamelCase(field.Name)); - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - var type = GetFieldType(field, green: true); - WriteLine(" writer.{0}(this.{1});", GetWriterMethod(type), CamelCase(field.Name)); - } - - WriteLine(" }"); - - // IReadable - WriteLine(); - WriteLine(" static {0}()", node.Name); - WriteLine(" {"); - WriteLine(" ObjectBinder.RegisterTypeReader(typeof({0}), r => new {0}(r));", node.Name); - WriteLine(" }"); - } - - private string GetWriterMethod(string type) - { - switch (type) - { - case "bool": - return "WriteBoolean"; - default: - throw new InvalidOperationException(string.Format("Type '{0}' not supported for object reader serialization.", type)); - } - } - - private string GetReaderMethod(string type) - { - switch (type) - { - case "bool": - return "ReadBoolean"; - default: - throw new InvalidOperationException(string.Format("Type '{0}' not supported for object reader serialization.", type)); - } - } - - private void WriteCtorBody(List valueFields, List nodeFields) - { - // constructor body - WriteLine(" SlotCount = {0};", nodeFields.Count); - - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - if (IsAnyList(field.Type) || IsOptional(field)) - { - WriteLine(" if ({0} != null)", CamelCase(field.Name)); - WriteLine(" {"); - WriteLine(" AdjustFlagsAndWidth({0});", CamelCase(field.Name)); - WriteLine(" {0} = {1};", UnderscoreCamelCase(field.Name), CamelCase(field.Name)); - WriteLine(" }"); - } - else - { - WriteLine(" AdjustFlagsAndWidth({0});", CamelCase(field.Name)); - WriteLine(" {0} = {1};", UnderscoreCamelCase(field.Name), CamelCase(field.Name)); - } - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - WriteLine(" {0} = {1};", UnderscoreCamelCase(field.Name), CamelCase(field.Name)); - } - } - - private void WriteSetAnnotations(Node node) - { - WriteLine(); - WriteLine(" internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations)"); - WriteLine(" {"); - - Write(" return new {0}(", node.Name); - Write("Kind, "); - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - Write("{0}", UnderscoreCamelCase(field.Name)); - } - WriteLine(", GetDiagnostics(), annotations);"); - WriteLine(" }"); - } - - private void WriteSetDiagnostics(Node node) - { - WriteLine(); - WriteLine(" internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics)"); - WriteLine(" {"); - - Write(" return new {0}(", node.Name); - Write("Kind, "); - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - Write("{0}", UnderscoreCamelCase(field.Name)); - } - WriteLine(", diagnostics, GetAnnotations());"); - WriteLine(" }"); - } - - private void WriteGreenAcceptMethods(Node node) - { - //WriteLine(); - //WriteLine(" public override TResult Accept(SyntaxVisitor visitor, TArgument argument)"); - //WriteLine(" {"); - //WriteLine(" return visitor.Visit{0}(this, argument);", StripPost(node.Name, "Syntax")); - //WriteLine(" }"); - WriteLine(); - WriteLine(" public override TResult Accept(SyntaxVisitor visitor)"); - WriteLine(" {"); - WriteLine(" return visitor.Visit{0}(this);", StripPost(node.Name, "Syntax")); - WriteLine(" }"); - WriteLine(); - WriteLine(" public override void Accept(SyntaxVisitor visitor)"); - WriteLine(" {"); - WriteLine(" visitor.Visit{0}(this);", StripPost(node.Name, "Syntax")); - WriteLine(" }"); - } - - private void WriteGreenVisitors() - { - //WriteGreenVisitor(true, true); - //WriteLine(); - WriteGreenVisitor(false, true); - WriteLine(); - WriteGreenVisitor(false, false); - } - - private void WriteGreenVisitor(bool withArgument, bool withResult) - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode)).ToList(); - - WriteLine(); - WriteLine(" internal partial class SyntaxVisitor" + (withResult ? "<" + (withArgument ? "TArgument, " : "") + "TResult>" : "")); - WriteLine(" {"); - int nWritten = 0; - for (int i = 0, n = nodes.Count; i < n; i++) - { - if (nodes[i] is Node node) - { - if (nWritten > 0) - WriteLine(); - nWritten++; - WriteLine(" public virtual " + (withResult ? "TResult" : "void") + " Visit{0}({1} node{2})", StripPost(node.Name, "Syntax"), node.Name, withArgument ? ", TArgument argument" : ""); - WriteLine(" {"); - WriteLine(" " + (withResult ? "return " : "") + "DefaultVisit(node{0});", withArgument ? ", argument" : ""); - WriteLine(" }"); - } - } - WriteLine(" }"); - } - - private void WriteGreenUpdateMethod(Node node) - { - WriteLine(); - Write(" public {0} Update(", node.Name); - - // parameters - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - - var type = - field.Type == "SyntaxNodeOrTokenList" ? "Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList" : - field.Type == "SyntaxTokenList" ? "Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList" : - IsNodeList(field.Type) ? "Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax." + field.Type : - IsSeparatedNodeList(field.Type) ? "Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax." + field.Type : - field.Type; - - Write("{0} {1}", type, CamelCase(field.Name)); - } - WriteLine(")"); - WriteLine(" {"); - - Write(" if ("); - int nCompared = 0; - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (IsDerivedOrListOfDerived("SyntaxNode", field.Type) || IsDerivedOrListOfDerived("SyntaxToken", field.Type) || field.Type == "SyntaxNodeOrTokenList") - { - if (nCompared > 0) - Write(" || "); - Write("{0} != {1}", CamelCase(field.Name), field.Name); - nCompared++; - } - } - if (nCompared > 0) - { - WriteLine(")"); - WriteLine(" {"); - Write(" var newNode = SyntaxFactory.{0}(", StripPost(node.Name, "Syntax")); - if (node.Kinds.Count > 1) - { - Write("Kind, "); - } - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - Write(CamelCase(field.Name)); - } - WriteLine(");"); - WriteLine(" var diags = GetDiagnostics();"); - WriteLine(" if (diags != null && diags.Length > 0)"); - WriteLine(" newNode = newNode.WithDiagnosticsGreen(diags);"); - WriteLine(" var annotations = GetAnnotations();"); - WriteLine(" if (annotations != null && annotations.Length > 0)"); - WriteLine(" newNode = newNode.WithAnnotationsGreen(annotations);"); - WriteLine(" return newNode;"); - WriteLine(" }"); - } - - WriteLine(); - WriteLine(" return this;"); - WriteLine(" }"); - } - - private void WriteGreenRewriter() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode)).ToList(); - - WriteLine(); - WriteLine(" internal partial class SyntaxRewriter : SyntaxVisitor"); - WriteLine(" {"); - int nWritten = 0; - for (int i = 0, n = nodes.Count; i < n; i++) - { - if (nodes[i] is Node node) - { - var nodeFields = node.Fields.Where(nd => IsNodeOrNodeList(nd.Type)).ToList(); - - if (nWritten > 0) - WriteLine(); - nWritten++; - WriteLine(" public override GreenNode Visit{0}({1} node)", StripPost(node.Name, "Syntax"), node.Name); - WriteLine(" {"); - for (int f = 0; f < nodeFields.Count; f++) - { - var field = nodeFields[f]; - if (IsAnyList(field.Type)) - { - WriteLine(" var {0} = VisitList(node.{1});", CamelCase(field.Name), field.Name); - } - else - { - WriteLine(" var {0} = ({1})Visit(node.{2});", CamelCase(field.Name), field.Type, field.Name); - } - } - if (nodeFields.Count > 0) - { - Write(" return node.Update("); - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - if (IsNodeOrNodeList(field.Type)) - { - Write(CamelCase(field.Name)); - } - else - { - Write("node.{0}", field.Name); - } - } - WriteLine(");"); - } - else - { - WriteLine(" return node;"); - } - WriteLine(" }"); - } - } - WriteLine(" }"); - } - - private void WriteContextualGreenFactories() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode) && !(n is AbstractNode)).ToList(); - WriteLine(); - WriteLine(" internal partial class ContextAwareSyntax"); - WriteLine(" {"); - - WriteLine(); - WriteLine(" private SyntaxFactoryContext context;"); - WriteLine(); - - WriteLine(); - WriteLine(" public ContextAwareSyntax(SyntaxFactoryContext context)"); - WriteLine(" {"); - WriteLine(" this.context = context;"); - WriteLine(" }"); - - WriteGreenFactories(nodes, withSyntaxFactoryContext: true); - - WriteLine(" }"); - } - - private void WriteStaticGreenFactories() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode) && !(n is AbstractNode)).ToList(); - WriteLine(); - WriteLine(" internal static partial class SyntaxFactory"); - WriteLine(" {"); - - WriteGreenFactories(nodes); - - WriteGreenTypeList(); - - WriteLine(" }"); - } - - private void WriteGreenFactories(List nodes, bool withSyntaxFactoryContext = false) - { - for (int i = 0, n = nodes.Count; i < n; i++) - { - var node = nodes[i]; - WriteGreenFactory((Node)node, withSyntaxFactoryContext); - if (i < n - 1) - WriteLine(); - } - } - - private void WriteGreenTypeList() - { - WriteLine(); - WriteLine(" internal static IEnumerable GetNodeTypes()"); - WriteLine(" {"); - WriteLine(" return new Type[] {"); - - var nodes = Tree.Types.Where(n => !(n is PredefinedNode) && !(n is AbstractNode)).ToList(); - for (int i = 0, n = nodes.Count; i < n; i++) - { - var node = nodes[i]; - Write(" typeof({0})", node.Name); - if (i < n - 1) - Write(","); - WriteLine(); - } - - WriteLine(" };"); - WriteLine(" }"); - } - - - private void WriteGreenFactory(Node nd, bool withSyntaxFactoryContext = false) - { - var valueFields = nd.Fields.Where(n => !IsNodeOrNodeList(n.Type)).ToList(); - var nodeFields = nd.Fields.Where(n => IsNodeOrNodeList(n.Type)).ToList(); - - Write(" public {0}{1} {2}(", withSyntaxFactoryContext ? "" : "static ", nd.Name, StripPost(nd.Name, "Syntax")); - WriteGreenFactoryParameters(nd); - WriteLine(")"); - WriteLine(" {"); - - // validate kind - if (nd.Kinds.Count > 1) - { - WriteLine(" switch (kind)"); - WriteLine(" {"); - foreach (var k in nd.Kinds) - { - WriteLine(" case SyntaxKind.{0}:", k.Name); - } - WriteLine(" break;"); - WriteLine(" default:"); - WriteLine(" throw new ArgumentException(\"kind\");"); - WriteLine(" }"); - } - - // validate parameters - //WriteLine("#if DEBUG"); - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - var pname = CamelCase(field.Name); - - if (!IsAnyList(field.Type) && !IsOptional(field)) - { - WriteLine(" if ({0} == null)", CamelCase(field.Name)); - WriteLine(" throw new ArgumentNullException(nameof({0}));", CamelCase(field.Name)); - } - if (field.Type == "SyntaxToken" && field.Kinds != null && field.Kinds.Count > 0) - { - if (IsOptional(field)) - { - WriteLine(" if ({0} != null)", CamelCase(field.Name)); - WriteLine(" {"); - } - WriteLine(" switch ({0}.Kind)", pname); - WriteLine(" {"); - foreach (var kind in field.Kinds) - { - WriteLine(" case SyntaxKind.{0}:", kind.Name); - } - //we need to check for Kind=None as well as node == null because that's what the red factory will pass - if (IsOptional(field)) - { - WriteLine(" case SyntaxKind.None:"); - } - WriteLine(" break;"); - WriteLine(" default:"); - WriteLine(" throw new ArgumentException(\"{0}\");", pname); - WriteLine(" }"); - if (IsOptional(field)) - { - WriteLine(" }"); - } - } - } - - //WriteLine("#endif"); - - if (nd.Name != "SkippedTokensTriviaSyntax" && - nd.Name != "DocumentationCommentTriviaSyntax" && - nd.Name != "IncompleteMemberSyntax" && - valueFields.Count + nodeFields.Count <= 3) - { - //int hash; - //var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.IdentifierName, identifier, this.context, out hash); - //if (cached != null) return (IdentifierNameSyntax)cached; - - //var result = new IdentifierNameSyntax(SyntaxKind.IdentifierName, identifier, this.context); - //if (hash >= 0) - //{ - // SyntaxNodeCache.AddNode(result, hash); - //} - - //return result; - - WriteLine(); - - /* Remove - //int hash; - WriteLine(" int hash;"); - //SyntaxNode cached = SyntaxNodeCache.TryGetNode(SyntaxKind.IdentifierName, identifier, this.context, out hash); - if (withSyntaxFactoryContext) - { - Write(" var cached = CSharpSyntaxNodeCache.TryGetNode((int)"); - } - else - { - Write(" var cached = SyntaxNodeCache.TryGetNode((int)"); - } - - WriteCtorArgList(nd, withSyntaxFactoryContext, valueFields, nodeFields); - WriteLine(", out hash);"); - // if (cached != null) return (IdentifierNameSyntax)cached; - WriteLine(" if (cached != null) return ({0})cached;", nd.Name); - WriteLine(); */ - - //var result = new IdentifierNameSyntax(SyntaxKind.IdentifierName, identifier); - Write(" var result = new {0}(", nd.Name); - WriteCtorArgList(nd, withSyntaxFactoryContext, valueFields, nodeFields); - WriteLine(");"); - - /* Remove - //if (hash >= 0) - WriteLine(" if (hash >= 0)"); - //{ - WriteLine(" {"); - // SyntaxNodeCache.AddNode(result, hash); - WriteLine(" SyntaxNodeCache.AddNode(result, hash);"); - //} - WriteLine(" }"); */ - WriteLine(); - - //return result; - WriteLine(" return result;"); - } - else - { - WriteLine(); - Write(" return new {0}(", nd.Name); - WriteCtorArgList(nd, withSyntaxFactoryContext, valueFields, nodeFields); - WriteLine(");"); - } - - WriteLine(" }"); - } - - private void WriteGreenFactoryParameters(Node nd) - { - if (nd.Kinds.Count > 1) - { - Write("SyntaxKind kind, "); - } - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - if (i > 0) - Write(", "); - var type = field.Type; - if (type == "SyntaxNodeOrTokenList") - { - type = "SyntaxList"; - } - else if (IsSeparatedNodeList(field.Type) || - IsNodeList(field.Type)) - { - type = "Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax." + type; - } - Write("{0} {1}", type, CamelCase(field.Name)); - } - } - - private void WriteCtorArgList(Node nd, bool withSyntaxFactoryContext, List valueFields, List nodeFields) - { - if (nd.Kinds.Count == 1) - { - Write("SyntaxKind."); - Write(nd.Kinds[0].Name); - } - else - { - Write("kind"); - } - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - Write(", "); - if (field.Type == "SyntaxList" || IsAnyList(field.Type)) - { - Write("{0}.Node", CamelCase(field.Name)); - } - else - { - Write(CamelCase(field.Name)); - } - } - // values are at end - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - Write(", "); - Write(UnderscoreCamelCase(field.Name)); - } - if (withSyntaxFactoryContext) - { - Write(", this.context"); - } - } - - private void WriteRedTypes() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode)).ToList(); - for (int i = 0, n = nodes.Count; i < n; i++) - { - var node = nodes[i]; - WriteLine(); - WriteRedType(node); - } - } - - private List GetNodeOrNodeListFields(TreeType node) - => node is AbstractNode an - ? an.Fields.Where(n => IsNodeOrNodeList(n.Type)).ToList() - : node is Node nd - ? nd.Fields.Where(n => IsNodeOrNodeList(n.Type)).ToList() - : new List(); - - private void WriteRedType(TreeType node) - { - WriteComment(node.TypeComment, " "); - - if (node is AbstractNode) - { - AbstractNode nd = (AbstractNode)node; - WriteLine(" internal abstract partial class {0} : {1}", node.Name, node.Base); - WriteLine(" {"); - WriteLine(" internal {0}(GreenNode green, SyntaxNode parent, int position)", node.Name); - WriteLine(" : base(green, parent, position)"); - WriteLine(" {"); - WriteLine(" }"); - - var valueFields = nd.Fields.Where(n => !IsNodeOrNodeList(n.Type)).ToList(); - var nodeFields = GetNodeOrNodeListFields(nd); - - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - if (IsNodeOrNodeList(field.Type)) - { - //red SyntaxLists can't contain tokens, so we switch to SyntaxTokenList - var fieldType = GetRedFieldType(field); - WriteLine(); - WriteComment(field.PropertyComment, " "); - WriteLine(" {0} abstract {1}{2} {3} {{ get; }}", "public", (IsNew(field) ? "new " : ""), fieldType, field.Name); - WriteLine($" public {node.Name} With{field.Name}({fieldType} {CamelCase(field.Name)}) => With{field.Name}Core({CamelCase(field.Name)});"); - WriteLine($" internal abstract {node.Name} With{field.Name}Core({fieldType} {CamelCase(field.Name)});"); - - if (IsAnyList(field.Type)) - { - var argType = GetElementType(field.Type); - WriteLine(); - WriteLine(" public {0} Add{1}(params {2}[] items) => Add{1}Core(items);", node.Name, field.Name, argType); - WriteLine(" internal abstract {0} Add{1}Core(params {2}[] items);", node.Name, field.Name, argType); - } - else - { - var referencedNode = TryGetNodeForNestedList(field); - if (referencedNode != null) - { - for (int rf = 0; rf < referencedNode.Fields.Count; rf++) - { - var referencedNodeField = referencedNode.Fields[rf]; - if (IsAnyList(referencedNodeField.Type)) - { - var argType = GetElementType(referencedNodeField.Type); - - WriteLine(); - WriteLine(" public {0} Add{1}{2}(params {3}[] items) => Add{1}{2}Core(items);", node.Name, StripPost(field.Name, "Opt"), referencedNodeField.Name, argType); - WriteLine(" internal abstract {0} Add{1}{2}Core(params {3}[] items);", node.Name, StripPost(field.Name, "Opt"), referencedNodeField.Name, argType); - } - } - } - } - } - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - WriteLine(); - WriteComment(field.PropertyComment, " "); - WriteLine(" {0} abstract {1}{2} {3} {{ get; }}", "public", (IsNew(field) ? "new " : ""), field.Type, field.Name); - } - - var baseType = GetTreeType(node.Base); - if (baseType != null) - { - var baseNodeFields = GetNodeOrNodeListFields(baseType); - if (baseNodeFields.Count > 0) - { - WriteLine(); - } - - foreach (var baseField in baseNodeFields) - { - WriteLine($" public new {node.Name} With{baseField.Name}({GetRedFieldType(baseField)} {CamelCase(baseField.Name)}) => ({node.Name})With{baseField.Name}Core({CamelCase(baseField.Name)});"); - } - - foreach (var baseField in baseNodeFields) - { - if (IsAnyList(baseField.Type)) - { - var argType = GetElementType(baseField.Type); - WriteLine(); - WriteLine(" public new {0} Add{1}(params {2}[] items) => ({0})Add{1}Core(items);", node.Name, baseField.Name, argType); - } - else - { - var referencedNode = TryGetNodeForNestedList(baseField); - if (referencedNode != null) - { - // look for list members... - for (int rf = 0; rf < referencedNode.Fields.Count; rf++) - { - var referencedNodeField = referencedNode.Fields[rf]; - if (IsAnyList(referencedNodeField.Type)) - { - var argType = GetElementType(referencedNodeField.Type); - - WriteLine(); - WriteLine(" public new {0} Add{1}{2}(params {3}[] items) => Add{1}{2}Core(items);", baseType.Name, StripPost(baseField.Name, "Opt"), referencedNodeField.Name, argType); - } - } - } - } - } - } - - WriteLine(" }"); - } - else if (node is Node) - { - Node nd = (Node)node; - WriteLine(" internal sealed partial class {0} : {1}", node.Name, node.Base); - WriteLine(" {"); - - 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]; - //if (field.Type != "SyntaxToken" - // && field.Type != "SyntaxList" - // ) - //{ - if (IsSeparatedNodeList(field.Type) || field.Type == "SyntaxNodeOrTokenList") - { - WriteLine(" private SyntaxNode {0};", UnderscoreCamelCase(field.Name)); - } - else - { - var type = GetFieldType(field, green: false); - WriteLine(" private {0} {1};", type, UnderscoreCamelCase(field.Name)); - } - //} - } - - // write constructor - WriteLine(); - WriteLine(" internal {0}(GreenNode green, SyntaxNode parent, int position)", node.Name); - WriteLine(" : base(green, parent, position)"); - WriteLine(" {"); - WriteLine(" }"); - WriteLine(); - - // property accessors - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - //if (field.Type == "SyntaxToken") - //{ - // WriteComment(field.PropertyComment, " "); - // WriteLine(" {0} {1}{2} {3} ", "public", OverrideOrNewModifier(field), field.Type, field.Name); - // WriteLine(" {"); - // if (IsOptional(field)) - // { - // WriteLine(" get"); - // WriteLine(" {"); - // WriteLine(" var slot = ((InternalSyntax.{0})Green).{1};", node.Name, field.Name); - // WriteLine(" if (slot != null)"); - // WriteLine(" return new SyntaxToken(slot, this, {0});", GetChildPosition(i)/*, GetChildIndex(i)*/); - // WriteLine(); - // WriteLine(" return default(SyntaxToken);"); - // WriteLine(" }"); - // } - // else - // { - // WriteLine(" get {{ return new SyntaxToken(((InternalSyntax.{0})Green).{1}, this, {2}); }}", node.Name, field.Name, GetChildPosition(i)/*, GetChildIndex(i)*/); - // } - // WriteLine(" }"); - //} - /* Remove - else if (field.Type == "SyntaxList") - { - WriteComment(field.PropertyComment, " "); - WriteLine(" {0} {1}SyntaxTokenList {2} ", "public", OverrideOrNewModifier(field), field.Name); - WriteLine(" {"); - WriteLine(" get"); - WriteLine(" {"); - WriteLine(" var slot = Green.GetSlot({0});", i); - WriteLine(" if (slot != null)"); - WriteLine(" return new SyntaxTokenList(this, slot, {0}, {1});", GetChildPosition(i), GetChildIndex(i)); - WriteLine(); - WriteLine(" return default(SyntaxTokenList);"); - WriteLine(" }"); - WriteLine(" }"); - } */ - //else - //{ - WriteComment(field.PropertyComment, " "); - WriteLine(" {0} {1}{2} {3} ", "public", OverrideOrNewModifier(field), field.Type, field.Name); - WriteLine(" {"); - WriteLine(" get"); - WriteLine(" {"); - - if (IsNodeList(field.Type)) - { - WriteLine(" return new {0}(GetRed(ref {1}, {2}));", field.Type, UnderscoreCamelCase(field.Name), i); - } - else if (IsSeparatedNodeList(field.Type)) - { - WriteLine(" var red = GetRed(ref {0}, {1});", UnderscoreCamelCase(field.Name), i); - WriteLine(" if (red != null)", i); - WriteLine(" return new {0}(red, {1});", field.Type, GetChildIndex(i)); - WriteLine(); - WriteLine(" return default({0});", field.Type); - } - else if (field.Type == "SyntaxNodeOrTokenList") - { - throw new InvalidOperationException("field cannot be a random SyntaxNodeOrTokenList"); - } - else - { - if (i == 0) - { - WriteLine(" return GetRedAtZero(ref {0});", UnderscoreCamelCase(field.Name)); - } - else - { - WriteLine(" return GetRed(ref {0}, {1});", UnderscoreCamelCase(field.Name), i); - } - } - WriteLine(" }"); - WriteLine(" }"); - //} - WriteLine(); - } - - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - WriteComment(field.PropertyComment, " "); - WriteLine(" {0} {1}{2} {3} {{ get {{ return ((InternalSyntax.{4})Green).{3}; }} }}", - "public", OverrideOrNewModifier(field), field.Type, field.Name, node.Name - ); - WriteLine(); - } - - //GetNodeSlot forces creation of a red node. - WriteLine(" internal override SyntaxNode GetNodeSlot(int index)"); - WriteLine(" {"); - WriteLine(" switch (index)"); - WriteLine(" {"); - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - - //if (field.Type != "SyntaxToken" && field.Type != "SyntaxList") - if (true) - { - if (i == 0) - { - WriteLine(" case {0}: return GetRedAtZero(ref {1});", i, UnderscoreCamelCase(field.Name)); - } - else - { - WriteLine(" case {0}: return GetRed(ref {1}, {0});", i, UnderscoreCamelCase(field.Name)); - } - } - } - WriteLine(" default: return null;"); - WriteLine(" }"); - WriteLine(" }"); - - //GetCachedSlot returns a red node if we have it. - WriteLine(" internal override SyntaxNode GetCachedSlot(int index)"); - WriteLine(" {"); - WriteLine(" switch (index)"); - WriteLine(" {"); - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - //if (field.Type != "SyntaxToken" && field.Type != "SyntaxList") - if (true) - { - WriteLine(" case {0}: return {1};", i, UnderscoreCamelCase(field.Name)); - } - } - WriteLine(" default: return null;"); - WriteLine(" }"); - WriteLine(" }"); - - - WriteRedAcceptMethods(nd); - WriteRedUpdateMethod(nd); - WriteRedWithMethods(nd); - WriteRedListHelperMethods(nd); - - WriteLine(" }"); - } - } - - private static string GetRedFieldType(Field field) - { - //return field.Type == "SyntaxList" ? "SyntaxTokenList" : field.Type; - return field.Type; - } - - private string GetChildPosition(int i) - { - if (i == 0) - { - return "Position"; - } - else - { - return "GetChildPosition(" + i + ")"; - } - } - - private string GetChildIndex(int i) - { - if (i == 0) - { - return "0"; - } - else - { - return "GetChildIndex(" + i + ")"; - } - } - - private void WriteRedAcceptMethods(Node node) - { - //WriteRedAcceptMethod(node, true, true); - WriteRedAcceptMethod(node, false, true); - WriteRedAcceptMethod(node, false, false); - } - - private void WriteRedAcceptMethod(Node node, bool genericArgument, bool genericResult) - { - string genericArgs = - (genericResult && genericArgument) ? "" : - genericResult ? "" : ""; - WriteLine(); - WriteLine(" public override " + (genericResult ? "TResult" : "void") + " Accept" + genericArgs + "(SyntaxVisitor" + genericArgs + " visitor{0})", genericArgument ? ", TArgument argument" : ""); - WriteLine(" {"); - WriteLine(" " + (genericResult ? "return " : "") + "visitor.Visit{0}(this{1});", StripPost(node.Name, "Syntax"), genericArgument ? ", argument" : ""); - WriteLine(" }"); - } - - private void WriteRedVisitors() - { - //WriteRedVisitor(true, true); - WriteRedVisitor(false, true); - WriteRedVisitor(false, false); - } - - private void WriteRedVisitor(bool genericArgument, bool genericResult) - { - string genericArgs = - (genericResult && genericArgument) ? "" : - genericResult ? "" : ""; - var nodes = Tree.Types.Where(n => !(n is PredefinedNode)).ToList(); - - WriteLine(); - WriteLine(" internal partial class SyntaxVisitor" + genericArgs); - WriteLine(" {"); - int nWritten = 0; - for (int i = 0, n = nodes.Count; i < n; i++) - { - if (nodes[i] is Node node) - { - if (nWritten > 0) - WriteLine(); - nWritten++; - WriteComment(string.Format("Called when the visitor visits a {0} node.", node.Name), " "); - WriteLine(" public virtual " + (genericResult ? "TResult" : "void") + " Visit{0}({1} node{2})", StripPost(node.Name, "Syntax"), node.Name, genericArgument ? ", TArgument argument" : ""); - WriteLine(" {"); - WriteLine(" " + (genericResult ? "return " : "") + "DefaultVisit(node{0});", genericArgument ? ", argument" : ""); - WriteLine(" }"); - } - } - WriteLine(" }"); - } - - private void WriteRedUpdateMethod(Node node) - { - WriteLine(); - Write(" {0} {1} Update(", "public", node.Name); - - // parameters - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - //var type = field.Type == "SyntaxList" ? "SyntaxTokenList" : field.Type; - var type = field.Type; - Write("{0} {1}", type, CamelCase(field.Name)); - } - WriteLine(")"); - WriteLine(" {"); - - Write(" if ("); - int nCompared = 0; - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (IsDerivedOrListOfDerived("SyntaxNode", field.Type) || IsDerivedOrListOfDerived("SyntaxToken", field.Type) || field.Type == "SyntaxNodeOrTokenList") - { - if (nCompared > 0) - Write(" || "); - Write("{0} != {1}", CamelCase(field.Name), field.Name); - nCompared++; - } - } - if (nCompared > 0) - { - WriteLine(")"); - WriteLine(" {"); - Write(" var newNode = SyntaxFactory.{0}(", StripPost(node.Name, "Syntax")); - if (node.Kinds.Count > 1) - { - Write("Kind(), "); - } - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - Write(CamelCase(field.Name)); - } - WriteLine(");"); - WriteLine(" var diagnostics = GetDiagnostics();"); - WriteLine(" if (diagnostics != null && diagnostics.Length > 0)"); - WriteLine(" newNode = newNode.WithDiagnostics(diagnostics);"); - WriteLine(" var annotations = GetAnnotations();"); - WriteLine(" if (annotations != null && annotations.Length > 0)"); - WriteLine(" return newNode.WithAnnotations(annotations);"); - WriteLine(" return newNode;"); - WriteLine(" }"); - } - - WriteLine(); - WriteLine(" return this;"); - WriteLine(" }"); - } - - private void WriteRedWithMethod(Node node) - { - WriteLine(); - Write(" public {0} With(", node.Name); - - // parameters - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - var type = GetRedPropertyType(field); - Write("Optional<{0}> {1} = default(Optional<{0}>)", type, UnderscoreCamelCase(field.Name)); - if (f < node.Fields.Count - 1) - Write(", "); - } - WriteLine(")"); - WriteLine(" {"); - - Write(" return Update("); - - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - var parameterName = UnderscoreCamelCase(field.Name); - WriteLine(); - Write(" {0}.HasValue ? {0}.Value : {1}", parameterName, field.Name); - if (f < node.Fields.Count - 1) - Write(","); - } - - WriteLine(); - WriteLine(" );"); - - WriteLine(" }"); - } - - private void WriteRedWithMethods(Node node) - { - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - var type = GetRedPropertyType(field); - - WriteLine(); - - var isNew = false; - if (IsOverride(field)) - { - var baseType = GetHighestBaseTypeWithField(node, field.Name); - if (baseType != null) - { - WriteLine($" internal override {baseType.Name} With{field.Name}Core({type} {CamelCase(field.Name)}) => With{field.Name}({CamelCase(field.Name)});"); - isNew = true; - } - } - - WriteLine($" public{(isNew ? " new " : " ")}{node.Name} With{StripPost(field.Name, "Opt")}({type} {CamelCase(field.Name)})"); - WriteLine(" {"); - - // call update inside each setter - Write(" return Update("); - for (int f2 = 0; f2 < node.Fields.Count; f2++) - { - var field2 = node.Fields[f2]; - if (f2 > 0) - Write(", "); - - if (field2 == field) - { - Write("{0}", CamelCase(field2.Name)); - } - else - { - Write("{0}", field2.Name); - } - } - WriteLine(");"); - - WriteLine(" }"); - } - } - - private TreeType GetHighestBaseTypeWithField(TreeType node, string name) - { - TreeType bestType = null; - for (var current = node; current != null; current = TryGetBaseType(current)) - { - var fields = GetNodeOrNodeListFields(current); - var field = fields.FirstOrDefault(f => f.Name == name); - if (field != null) - { - bestType = current; - } - } - - return bestType; - } - - private TreeType TryGetBaseType(TreeType node) - => node is AbstractNode an - ? GetTreeType(an.Base) - : node is Node n - ? GetTreeType(n.Base) - : null; - - private void WriteRedListHelperMethods(Node node) - { - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - - if (IsAnyList(field.Type)) - { - // write list helper methods for list properties - WriteRedListHelperMethods(node, field); - } - else - { - var referencedNode = TryGetNodeForNestedList(field); - if (referencedNode != null) - { - // look for list members... - for (int rf = 0; rf < referencedNode.Fields.Count; rf++) - { - var referencedNodeField = referencedNode.Fields[rf]; - if (IsAnyList(referencedNodeField.Type)) - { - WriteRedNestedListHelperMethods(node, field, referencedNode, referencedNodeField); - } - } - } - } - } - } - - private Node TryGetNodeForNestedList(Field field) - { - Node referencedNode = GetNode(field.Type); - if (referencedNode != null && (!IsOptional(field) || RequiredFactoryArgumentCount(referencedNode) == 0)) - { - return referencedNode; - } - - return null; - } - - private void WriteRedListHelperMethods(Node node, Field field) - { - var argType = GetElementType(field.Type); - - var isNew = false; - if (IsOverride(field)) - { - var baseType = GetHighestBaseTypeWithField(node, field.Name); - if (baseType != null) - { - WriteLine(" internal override {0} Add{1}Core(params {2}[] items) => Add{1}(items);", baseType.Name, field.Name, argType); - isNew = true; - } - } - - WriteLine(); - WriteLine($" public{(isNew ? " new " : " ")}{node.Name} Add{field.Name}(params {argType}[] items)"); - WriteLine(" {"); - WriteLine(" return With{0}(this.{1}.AddRange(items));", StripPost(field.Name, "Opt"), field.Name); - WriteLine(" }"); - } - - private void WriteRedNestedListHelperMethods(Node node, Field field, Node referencedNode, Field referencedNodeField) - { - var argType = GetElementType(referencedNodeField.Type); - - var isNew = false; - if (IsOverride(field)) - { - var baseType = GetHighestBaseTypeWithField(node, field.Name); - if (baseType != null) - { - WriteLine(" internal override {0} Add{1}{2}Core(params {3}[] items) => Add{1}{2}(items);", baseType.Name, StripPost(field.Name, "Opt"), referencedNodeField.Name, argType); - isNew = true; - } - } - - // AddBaseListTypes - WriteLine(); - WriteLine($" public{(isNew ? " new " : " ")}{node.Name} Add{StripPost(field.Name, "Opt")}{referencedNodeField.Name}(params {argType}[] items)"); - WriteLine(" {"); - - if (IsOptional(field)) - { - var factoryName = StripPost(referencedNode.Name, "Syntax"); - var varName = StripPost(UnderscoreCamelCase(field.Name), "Opt"); - WriteLine(" var {0} = this.{1} ?? SyntaxFactory.{2}();", varName, field.Name, factoryName); - WriteLine(" return this.With{0}({1}.With{2}({1}.{3}.AddRange(items)));", StripPost(field.Name, "Opt"), varName, StripPost(referencedNodeField.Name, "Opt"), referencedNodeField.Name); - } - else - { - WriteLine(" return this.With{0}(this.{1}.With{2}(this.{1}.{3}.AddRange(items)));", StripPost(field.Name, "Opt"), field.Name, StripPost(referencedNodeField.Name, "Opt"), referencedNodeField.Name); - } - - WriteLine(" }"); - } - - private void WriteRedRewriter() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode)).ToList(); - - WriteLine(); - WriteLine(" internal partial class SyntaxRewriter : SyntaxVisitor"); - WriteLine(" {"); - int nWritten = 0; - for (int i = 0, n = nodes.Count; i < n; i++) - { - if (nodes[i] is Node node) - { - var nodeFields = node.Fields.Where(nd => IsNodeOrNodeList(nd.Type)).ToList(); - - if (nWritten > 0) - WriteLine(); - nWritten++; - WriteLine(" public override SyntaxNode Visit{0}({1} node)", StripPost(node.Name, "Syntax"), node.Name); - WriteLine(" {"); - for (int f = 0; f < nodeFields.Count; f++) - { - var field = nodeFields[f]; - if (IsAnyList(field.Type)) - { - WriteLine(" var {0} = VisitList(node.{1});", CamelCase(field.Name), field.Name); - } - else if (field.Type == "SyntaxToken") - { - WriteLine(" var {0} = ({1})VisitToken(node.{2});", CamelCase(field.Name), field.Type, field.Name); - } - else - { - WriteLine(" var {0} = ({1})Visit(node.{2});", CamelCase(field.Name), field.Type, field.Name); - } - } - if (nodeFields.Count > 0) - { - Write(" return node.Update("); - for (int f = 0; f < node.Fields.Count; f++) - { - var field = node.Fields[f]; - if (f > 0) - Write(", "); - if (IsNodeOrNodeList(field.Type)) - { - Write(CamelCase(field.Name)); - } - else - { - Write("node.{0}", field.Name); - } - } - WriteLine(");"); - } - else - { - WriteLine(" return node;"); - } - WriteLine(" }"); - } - } - WriteLine(" }"); - } - - private void WriteRedFactories() - { - var nodes = Tree.Types.Where(n => !(n is PredefinedNode) && !(n is AbstractNode)).OfType().ToList(); - WriteLine(); - WriteLine(" internal static partial class SyntaxFactory"); - WriteLine(" {"); - - for (int i = 0, n = nodes.Count; i < n; i++) - { - var node = nodes[i]; - WriteRedFactory(node); - WriteRedFactoryWithNoAutoCreatableTokens(node); - WriteRedMinimalFactory(node); - WriteRedMinimalFactory(node, withStringNames: true); - WriteKindConverters(node); - } - - WriteLine(" }"); - } - - protected bool CanBeAutoCreated(Node node, Field field) - { - return IsAutoCreatableToken(node, field) || IsAutoCreatableNode(node, field); - } - - private bool IsAutoCreatableToken(Node node, Field field) - { - return field.Type == "SyntaxToken" - && field.Kinds != null - && ((field.Kinds.Count == 1 && field.Kinds[0].Name != "IdentifierToken" && !field.Kinds[0].Name.EndsWith("LiteralToken", StringComparison.Ordinal)) || (field.Kinds.Count > 1 && field.Kinds.Count == node.Kinds.Count)); - } - - private bool IsAutoCreatableNode(Node node, Field field) - { - var referencedNode = GetNode(field.Type); - return (referencedNode != null && RequiredFactoryArgumentCount(referencedNode) == 0); - } - - private bool IsRequiredFactoryField(Node node, Field field) - { - return (!IsOptional(field) && !IsAnyList(field.Type) && !CanBeAutoCreated(node, field)) || IsValueField(field); - } - - private bool IsValueField(Field field) - { - return !IsNodeOrNodeList(field.Type); - } - - private int RequiredFactoryArgumentCount(Node nd, bool includeKind = true) - { - int count = 0; - - // kind must be specified in factory - if (nd.Kinds.Count > 1 && includeKind) - { - count++; - } - - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - if (IsRequiredFactoryField(nd, field)) - { - count++; - } - } - - return count; - } - - private int OptionalFactoryArgumentCount(Node nd) - { - int count = 0; - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - if (IsOptional(field) || CanBeAutoCreated(nd, field) || IsAnyList(field.Type)) - { - count++; - } - } - - return count; - } - - // full factory signature with nothing optional - private void WriteRedFactory(Node nd) - { - WriteLine(); - - var valueFields = nd.Fields.Where(n => IsValueField(n)).ToList(); - var nodeFields = nd.Fields.Where(n => !IsValueField(n)).ToList(); - - WriteComment(string.Format("Creates a new {0} instance.", nd.Name), " "); - - Write(" {0} static {1} {2}(", "public", nd.Name, StripPost(nd.Name, "Syntax")); - WriteRedFactoryParameters(nd); - - WriteLine(")"); - WriteLine(" {"); - - // validate kinds - if (nd.Kinds.Count > 1) - { - WriteLine(" switch (kind)"); - WriteLine(" {"); - foreach (var kind in nd.Kinds) - { - WriteLine(" case SyntaxKind.{0}:", kind.Name); - } - WriteLine(" break;"); - WriteLine(" default:"); - WriteLine(" throw new ArgumentException(\"kind\");"); - WriteLine(" }"); - } - - // validate parameters - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - var pname = CamelCase(field.Name); - - if (field.Type == "SyntaxToken") - { - if (field.Kinds != null && field.Kinds.Count > 0) - { - if (IsOptional(field)) - { - WriteLine(" if ({0} != null)", CamelCase(field.Name)); - WriteLine(" {"); - } - WriteLine(" switch ({0}.Kind)", pname); - WriteLine(" {"); - foreach (var kind in field.Kinds) - { - WriteLine(" case SyntaxKind.{0}:", kind.Name); - } - if (IsOptional(field)) - { - WriteLine(" case SyntaxKind.None:"); - } - WriteLine(" break;"); - WriteLine(" default:"); - WriteLine(" throw new ArgumentException(\"{0}\");", pname); - WriteLine(" }"); - if (IsOptional(field)) - { - WriteLine(" }"); - } - } - } - else if (!IsAnyList(field.Type) && !IsOptional(field)) - { - WriteLine(" if ({0} == null)", CamelCase(field.Name)); - WriteLine(" throw new ArgumentNullException(nameof({0}));", CamelCase(field.Name)); - } - } - - Write(" return ({0})InternalSyntax.SyntaxFactory.{1}(", nd.Name, StripPost(nd.Name, "Syntax")); - if (nd.Kinds.Count > 1) - { - Write("kind, "); - } - for (int i = 0, n = nodeFields.Count; i < n; i++) - { - var field = nodeFields[i]; - if (i > 0) - Write(", "); - if (field.Type == "SyntaxToken") - { - if (IsOptional(field)) - { - Write("(Syntax.InternalSyntax.SyntaxToken){0}?.Green", CamelCase(field.Name)); - } - else - { - Write("(Syntax.InternalSyntax.SyntaxToken){0}.Green", CamelCase(field.Name)); - } - } - else if (field.Type == "SyntaxList") - { - Write("{0}.Node.ToGreenList()", CamelCase(field.Name)); - } - else if (IsNodeList(field.Type)) - { - Write("{0}.Node.ToGreenList()", CamelCase(field.Name), GetElementType(field.Type)); - } - else if (IsSeparatedNodeList(field.Type)) - { - Write("{0}.Node.ToGreenSeparatedList()", CamelCase(field.Name), GetElementType(field.Type)); - } - else if (field.Type == "SyntaxNodeOrTokenList") - { - Write("{0}.Node.ToGreenList()", CamelCase(field.Name)); - } - else - { - Write("{0} == null ? null : (InternalSyntax.{1}){0}.Green", CamelCase(field.Name), field.Type); - } - } - - // values are at end - for (int i = 0, n = valueFields.Count; i < n; i++) - { - var field = valueFields[i]; - Write(", "); - Write(CamelCase(field.Name)); - } - - WriteLine(").CreateRed();"); - WriteLine(" }"); - - //WriteLine(); - } - - private void WriteRedFactoryParameters(Node nd) - { - if (nd.Kinds.Count > 1) - { - Write("SyntaxKind kind, "); - } - - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - if (i > 0) - Write(", "); - var type = GetRedPropertyType(field); - - Write("{0} {1}", type, CamelCase(field.Name)); - } - } - - private string GetRedPropertyType(Field field) - { - //if (field.Type == "SyntaxList") - // return "SyntaxTokenList"; - return field.Type; - } - - private string GetDefaultValue(Node nd, Field field) - { - if (IsRequiredFactoryField(nd, field)) - { - Console.WriteLine(nd.Name); - Console.WriteLine(field.Name); - } - System.Diagnostics.Debug.Assert(!IsRequiredFactoryField(nd, field)); - - if (IsOptional(field) || IsAnyList(field.Type)) - { - return string.Format("default({0})", GetRedPropertyType(field)); - } - else if (field.Type == "SyntaxToken") - { - // auto construct token? - if (field.Kinds.Count == 1) - { - return string.Format("SyntaxFactory.Token(SyntaxKind.{0})", field.Kinds[0].Name); - } - else - { - return string.Format("SyntaxFactory.Token(Get{0}{1}Kind(kind))", StripPost(nd.Name, "Syntax"), StripPost(field.Name, "Opt")); - } - } - else - { - var referencedNode = GetNode(field.Type); - return string.Format("SyntaxFactory.{0}()", StripPost(referencedNode.Name, "Syntax")); - } - } - - // Writes GetKind() methods for converting between node kind and member token kinds... - private void WriteKindConverters(Node nd) - { - for (int f = 0; f < nd.Fields.Count; f++) - { - var field = nd.Fields[f]; - - if (field.Type == "SyntaxToken" && CanBeAutoCreated(nd, field) && field.Kinds.Count > 1) - { - WriteLine(); - WriteLine(" private static SyntaxKind Get{0}{1}Kind(SyntaxKind kind)", StripPost(nd.Name, "Syntax"), StripPost(field.Name, "Opt")); - WriteLine(" {"); - - WriteLine(" switch (kind)"); - WriteLine(" {"); - - for (int k = 0; k < field.Kinds.Count; k++) - { - var nKind = nd.Kinds[k]; - var pKind = field.Kinds[k]; - WriteLine(" case SyntaxKind.{0}:", nKind.Name); - WriteLine(" return SyntaxKind.{0};", pKind.Name); - } - - WriteLine(" default:"); - WriteLine(" throw new ArgumentOutOfRangeException();"); - WriteLine(" }"); - WriteLine(" }"); - } - } - } - - private IEnumerable DetermineRedFactoryWithNoAutoCreatableTokenFields(Node nd) - { - return nd.Fields.Where(f => !IsAutoCreatableToken(nd, f)); - } - - // creates a factory without auto-creatable token arguments - private void WriteRedFactoryWithNoAutoCreatableTokens(Node nd) - { - var nAutoCreatableTokens = nd.Fields.Count(f => IsAutoCreatableToken(nd, f)); - if (nAutoCreatableTokens == 0) - return; // already handled by general factory - - var factoryWithNoAutoCreatableTokenFields = new HashSet(DetermineRedFactoryWithNoAutoCreatableTokenFields(nd)); - var minimalFactoryFields = DetermineMinimalFactoryFields(nd); - if (minimalFactoryFields != null && factoryWithNoAutoCreatableTokenFields.SetEquals(minimalFactoryFields)) - { - return; // will be handled in minimal factory case - } - - WriteLine(); - - WriteComment(string.Format("Creates a new {0} instance.", nd.Name), " "); - Write(" {0} static {1} {2}(", "public", nd.Name, StripPost(nd.Name, "Syntax")); - - bool hasPreviousParameter = false; - if (nd.Kinds.Count > 1) - { - Write("SyntaxKind kind"); - hasPreviousParameter = true; - } - - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - - if (factoryWithNoAutoCreatableTokenFields.Contains(field)) - { - if (hasPreviousParameter) - Write(", "); - - Write("{0} {1}", GetRedPropertyType(field), CamelCase(field.Name)); - - hasPreviousParameter = true; - } - } - WriteLine(")"); - - WriteLine(" {"); - - Write(" return SyntaxFactory.{0}(", StripPost(nd.Name, "Syntax")); - - bool hasPreviousArgument = false; - if (nd.Kinds.Count > 1) - { - Write("kind"); - hasPreviousArgument = true; - } - - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - - if (hasPreviousArgument) - Write(", "); - - if (factoryWithNoAutoCreatableTokenFields.Contains(field)) - { - // pass supplied parameter on to general factory - Write("{0}", CamelCase(field.Name)); - } - else - { - // pass an auto-created token to the general factory - Write("{0}", GetDefaultValue(nd, field)); - } - - hasPreviousArgument = true; - } - - WriteLine(");"); - - WriteLine(" }"); - } - - private Field DetermineMinimalOptionalField(Node nd) - { - // first if there is a single list, then choose the list because it would not have been optional - int listCount = nd.Fields.Count(f => IsAnyNodeList(f.Type)); - if (listCount == 1) - { - return nd.Fields.First(f => IsAnyNodeList(f.Type)); - } - else - { - // otherwise, if there is a single optional node, use that.. - int nodeCount = nd.Fields.Count(f => IsNode(f.Type) && f.Type != "SyntaxToken"); - if (nodeCount == 1) - { - return nd.Fields.First(f => IsNode(f.Type) && f.Type != "SyntaxToken"); - } - else - { - return null; - } - } - } - - private IEnumerable DetermineMinimalFactoryFields(Node nd) - { - // special case to allow a single optional argument if there would have been no arguments - // and we can determine a best single argument. - Field allowOptionalField = null; - - var optionalCount = OptionalFactoryArgumentCount(nd); - if (optionalCount == 0) - { - return null; // no fields... - } - - var requiredCount = RequiredFactoryArgumentCount(nd, includeKind: false); - if (requiredCount == 0 && optionalCount > 1) - { - allowOptionalField = DetermineMinimalOptionalField(nd); - } - - return nd.Fields.Where(f => IsRequiredFactoryField(nd, f) || allowOptionalField == f); - } - - // creates a factory with only the required arguments (everything else is defaulted) - private void WriteRedMinimalFactory(Node nd, bool withStringNames = false) - { - var optionalCount = OptionalFactoryArgumentCount(nd); - if (optionalCount == 0) - return; // already handled w/ general factory method - - var minimalFactoryfields = new HashSet(DetermineMinimalFactoryFields(nd)); - - if (withStringNames && minimalFactoryfields.Count(f => IsRequiredFactoryField(nd, f) && CanAutoConvertFromString(f)) == 0) - return; // no string-name overload necessary - - WriteLine(); - - WriteComment(string.Format("Creates a new {0} instance.", nd.Name), " "); - Write(" {0} static {1} {2}(", "public", nd.Name, StripPost(nd.Name, "Syntax")); - - bool hasPreviousParameter = false; - if (nd.Kinds.Count > 1) - { - Write("SyntaxKind kind"); - hasPreviousParameter = true; - } - - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - - if (minimalFactoryfields.Contains(field)) - { - var type = GetRedPropertyType(field); - - if (IsRequiredFactoryField(nd, field)) - { - if (hasPreviousParameter) - Write(", "); - - if (withStringNames && CanAutoConvertFromString(field)) - { - type = "string"; - } - - Write("{0} {1}", type, CamelCase(field.Name)); - - hasPreviousParameter = true; - } - else - { - if (hasPreviousParameter) - Write(", "); - - Write("{0} {1} = default({0})", type, CamelCase(field.Name)); - - hasPreviousParameter = true; - } - } - } - WriteLine(")"); - - WriteLine(" {"); - - Write(" return SyntaxFactory.{0}(", StripPost(nd.Name, "Syntax")); - - bool hasPreviousArgument = false; - if (nd.Kinds.Count > 1) - { - Write("kind"); - hasPreviousArgument = true; - } - - for (int i = 0, n = nd.Fields.Count; i < n; i++) - { - var field = nd.Fields[i]; - - if (hasPreviousArgument) - Write(", "); - - if (minimalFactoryfields.Contains(field)) - { - if (IsRequiredFactoryField(nd, field)) - { - if (withStringNames && CanAutoConvertFromString(field)) - { - Write("{0}({1})", GetStringConverterMethod(field), CamelCase(field.Name)); - } - else - { - Write("{0}", CamelCase(field.Name)); - } - } - else - { - if (IsOptional(field) || IsAnyList(field.Type)) - { - Write("{0}", CamelCase(field.Name)); - } - else - { - Write("{0} ?? {1}", CamelCase(field.Name), GetDefaultValue(nd, field)); - } - } - } - else - { - var defaultValue = GetDefaultValue(nd, field); - Write(defaultValue); - } - - hasPreviousArgument = true; - } - - WriteLine(");"); - - WriteLine(" }"); - } - - private bool CanAutoConvertFromString(Field field) - { - return IsIdentifierToken(field) || IsIdentifierNameSyntax(field); - } - - private bool IsIdentifierToken(Field field) - { - return field.Type == "SyntaxToken" && field.Kinds != null && field.Kinds.Count == 1 && field.Kinds[0].Name == "IdentifierToken"; - } - - private bool IsIdentifierNameSyntax(Field field) - { - return field.Type == "IdentifierNameSyntax"; - } - - private string GetStringConverterMethod(Field field) - { - if (IsIdentifierToken(field)) - { - return "SyntaxFactory.Identifier"; - } - else if (IsIdentifierNameSyntax(field)) - { - return "SyntaxFactory.IdentifierName"; - } - else - { - throw new NotSupportedException(); - } - } - - /// - /// Anything inside a <Comment> tag gets written out (escaping untouched) as the - /// XML doc comment. Line breaks will be preserved. - /// - private void WriteComment(string comment, string indent) - { - if (comment != null) - { - var lines = comment.Split(new string[] { "\r", "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); - foreach (var line in lines.Where(l => !string.IsNullOrWhiteSpace(l))) - { - WriteLine("{0}/// {1}", indent, line.TrimStart()); - } - } - } - - /// - /// Anything inside a <Comment> tag gets written out (escaping untouched) as the - /// XML doc comment. Line breaks will be preserved. - /// - private void WriteComment(Comment comment, string indent) - { - if (comment != null) - { - foreach (XmlElement element in comment.Body) - { - string[] lines = element.OuterXml.Split(new string[] { "\r", "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); - foreach (string line in lines.Where(l => !string.IsNullOrWhiteSpace(l))) - { - WriteLine("{0}/// {1}", indent, line.TrimStart()); - } - } - } - } - } -}