public void Build(CodeFragmentBuilder builder) { builder.AppendLine("if ({0} != null)", Name); builder.Indent(); builder.AppendLine("yield return {0};", Name); builder.Unindent(); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("public enum {0}", Name); builder.AppendLine("{"); builder.Indent(); var names = new List <string>(FieldNames); names.Sort(); int none = names.IndexOf("None"); if (none != -1) { names.RemoveAt(none); names.Insert(0, "None"); } for (int i = 0; i < names.Count; i++) { builder.Append(names[i]); if (i != names.Count - 1) { builder.Append(","); } builder.AppendLine(); } builder.Unindent(); builder.AppendLine("}"); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("public enum {0}", Name); builder.AppendLine("{"); builder.Indent(); var names = new List<string>(FieldNames); names.Sort(); int none = names.IndexOf("None"); if (none != -1) { names.RemoveAt(none); names.Insert(0, "None"); } for (int i = 0; i < names.Count; i++) { builder.Append(names[i]); if (i != names.Count - 1) builder.Append(","); builder.AppendLine(); } builder.Unindent(); builder.AppendLine("}"); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("if ({0} != null)", Name); builder.Indent(); builder.AppendLine("yield return {0};", Name); builder.Unindent(); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("foreach (var item in {0})", Name); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("yield return item;"); builder.Unindent(); builder.AppendLine("}"); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("foreach (var item in {0})", Name); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("yield return item;"); builder.Unindent(); builder.AppendLine("}"); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("[Flags]"); builder.AppendLine("public enum {0}", Name); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("None = 0,"); for (int i = 0; i < FieldNames.Length; i++) { builder.Append(FieldNames[i]); builder.Append(" = 1 << "); builder.Append(i.ToString(CultureInfo.InvariantCulture)); if (i != FieldNames.Length - 1 || AddAll) builder.Append(","); builder.AppendLine(); } if (AddAll) { builder.Append("All = (1 << "); builder.Append(FieldNames.Length.ToString(CultureInfo.InvariantCulture)); builder.AppendLine(") - 1"); } builder.Unindent(); builder.AppendLine("}"); }
public void Build(CodeFragmentBuilder builder) { builder.AppendLine("[Flags]"); builder.AppendLine("public enum {0}", Name); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("None = 0,"); for (int i = 0; i < FieldNames.Length; i++) { builder.Append(FieldNames[i]); builder.Append(" = 1 << "); builder.Append(i.ToString(CultureInfo.InvariantCulture)); if (i != FieldNames.Length - 1 || AddAll) { builder.Append(","); } builder.AppendLine(); } if (AddAll) { builder.Append("All = (1 << "); builder.Append(FieldNames.Length.ToString(CultureInfo.InvariantCulture)); builder.AppendLine(") - 1"); } builder.Unindent(); builder.AppendLine("}"); }
private void BuildFactories(string target, Dictionary<SyntaxType, List<Factory>> factories, HashSet<SyntaxType> writtenTypes) { var builder = new CodeFragmentBuilder(); builder.AppendLine("using System;"); builder.AppendLine("using System.Collections.Generic;"); builder.AppendLine("using System.Linq;"); builder.AppendLine("using System.Text;"); builder.AppendLine(); builder.AppendLine("namespace CSharpSyntax"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("public static partial class Syntax"); builder.AppendLine("{"); builder.Indent(); bool hadOne = false; foreach (var item in factories.Where(p => writtenTypes.Contains(p.Key)).OrderBy(p => p.Key.Name)) { foreach (var factory in item.Value) { factory.Parameters.RemoveAll(p => p.Type == "SyntaxKind"); } } SeedParamsFactories(factories); SeedParseNameFactories(factories); foreach (var item in factories.Where(p => writtenTypes.Contains(p.Key)).OrderBy(p => p.Key.Name)) { for (int i = 0; i < item.Value.Count; i++) { var factory = item.Value[i]; bool duplicate = false; for (int j = i + 1; j < item.Value.Count; j++) { if (factory.Equals(item.Value[j])) { duplicate = true; break; } } if (duplicate) continue; if (factory.Parameters.Count == 0 && item.Value.Any(p => p.Parameters.Count > 0)) continue; if (FactoryWithMoreParametersExists(factory, item.Value)) continue; if (hadOne) builder.AppendLine(); else hadOne = true; builder.Append( "public static {0} {1}(", item.Key.Name, factory.Name ); bool hadOneChild = false; foreach (var parameter in factory.Parameters) { if (hadOneChild) builder.Append(", "); else hadOneChild = true; if (parameter.IsParams) builder.Append("params "); string type = parameter.Type; switch (type) { case "String": type = "string"; break; case "Object": type = "object"; break; } if (parameter.IsParams && !type.EndsWith("[]")) type += "[]"; if (parameter.IsList) builder.Append("IEnumerable<{0}> {1}", type, EscapeParameterName(parameter)); else builder.Append("{0} {1}", type, EscapeParameterName(parameter)); if ( (parameter.IsOptional || true) && // All parameters are currently generated as default !parameter.IsParams ) { if ( parameter.OriginalType.IsValueType || parameter.OriginalType == typeof(AttributeTargetSpecifierSyntax) ) builder.Append(" = default({0})", parameter.Type); else builder.Append(" = null"); } } builder.AppendLine(")"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("var result = new {0}();", item.Key.Name); builder.AppendLine(); foreach (var parameter in factory.Parameters) { if (parameter.Type == "SyntaxKind") continue; string propertyName = parameter.Name.Substring(0, 1).ToUpperInvariant() + parameter.Name.Substring(1); string parameterName = EscapeParameterName(parameter); string parseName = parameter.ParseNameType; if (item.Key.Name == "AliasQualifiedNameSyntax") { if (parameter.Name == "alias" && parameter.Type == "String") parseName = "IdentifierNameSyntax"; } else if (item.Key.Name == "IdentifierNameSyntax") { if (parameter.Name == "name") propertyName = "Identifier"; } else if (new[] { "NameColonSyntax", "NameEqualsSyntax", "TypeParameterConstraintClauseSyntax" }.Contains(item.Key.Name)) { if (parameter.Name == "name" && parameter.Type == "String") parseName = "IdentifierNameSyntax"; } if (parseName != null) { builder.AppendLine("if ({0} != null)", parameterName); builder.Indent(); if (parseName == "TypeSyntax") { if (parameter.IsList || parameter.IsParams) { builder.AppendLine( "result.{0}.AddRange(ParseNames<TypeSyntax>({1}));", propertyName, parameterName ); } else { builder.AppendLine( "result.{0} = ParseName({1});", propertyName, parameterName ); } } else { if (parameter.IsList || parameter.IsParams) { builder.AppendLine( "result.{0}.AddRange(ParseNames<{2}>({1}));", propertyName, parameterName, parseName ); } else { builder.AppendLine( "result.{0} = ({2})ParseName({1});", propertyName, parameterName, parseName ); } } builder.Unindent(); } else if (parameter.IsList || parameter.IsParams) { builder.AppendLine("if ({0} != null)", parameterName); builder.Indent(); builder.AppendLine("result.{0}.AddRange({1});", propertyName, parameterName); builder.Unindent(); } else { builder.AppendLine( "result.{0} = {1};", propertyName, parameterName ); } } builder.AppendLine(); builder.AppendLine("return result;"); builder.Unindent(); builder.AppendLine("}"); } } builder.Unindent(); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); WriteFile(target, "Syntax", builder); }
private void BuildBaseVisitor(string target, HashSet<string> visitors) { var builder = new CodeFragmentBuilder(); builder.AppendLine("using System;"); builder.AppendLine("using System.Collections.Generic;"); builder.AppendLine("using System.Linq;"); builder.AppendLine("using System.Text;"); builder.AppendLine("using System.Diagnostics;"); builder.AppendLine(); builder.AppendLine("namespace CSharpSyntax"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("public class SyntaxVisitorBase : ISyntaxVisitor"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("public bool Done { get; protected set; }"); foreach (string name in visitors.OrderBy(p => p)) { builder.AppendLine(); builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public virtual void Visit{1}({0} node)", name, StripPostfix(name, "Syntax")); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("DefaultVisit(node);"); builder.Unindent(); builder.AppendLine("}"); } builder.AppendLine(); builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public virtual void Visit(SyntaxNode node)"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("if (node != null)"); builder.Indent(); builder.AppendLine("node.Accept(this);"); builder.Unindent(); builder.Unindent(); builder.AppendLine("}"); builder.AppendLine(); builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public virtual void DefaultVisit(SyntaxNode node)"); builder.AppendLine("{"); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); builder.AppendLine(); builder.AppendLine("public class SyntaxVisitorBase<T> : ISyntaxVisitor<T>"); builder.AppendLine("{"); builder.Indent(); foreach (string name in visitors.OrderBy(p => p)) { builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public virtual T Visit{1}({0} node)", name, StripPostfix(name, "Syntax")); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("return DefaultVisit(node);"); builder.Unindent(); builder.AppendLine("}"); builder.AppendLine(); } builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public virtual T Visit(SyntaxNode node)"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("if (node == null)"); builder.Indent(); builder.AppendLine("return default(T);"); builder.Unindent(); builder.AppendLine(); builder.AppendLine("return node.Accept(this);"); builder.Unindent(); builder.AppendLine("}"); builder.AppendLine(); builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public virtual T DefaultVisit(SyntaxNode node)"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("return default(T);"); builder.Unindent(); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); WriteFile(target, "SyntaxVisitorBase", builder); }
public void Generate(string target) { var enums = new EnumDeclarationCollection(); var nonAbstractTypes = new HashSet<string>(); var factories = GetFactories(); var writtenTypes = new HashSet<SyntaxType>(); foreach (var type in GetTypes()) { if (!type.IsAbstract) nonAbstractTypes.Add(type.Name); var builder = new CodeFragmentBuilder(); var initializeLists = new Dictionary<string, string>(); var getChildrenGenerators = new List<IGetChildrenGenerator>(); builder.AppendLine("using System;"); builder.AppendLine("using System.Collections.Generic;"); builder.AppendLine("using System.Linq;"); builder.AppendLine("using System.Text;"); // We only need this when we're implementing an Accept. if (!type.IsAbstract) builder.AppendLine("using System.Diagnostics;"); builder.AppendLine(); builder.AppendLine("namespace CSharpSyntax"); builder.AppendLine("{"); builder.Indent(); string baseType = type.BaseType.Name; if (_allowTriviaTypes.Any(p => p.Name == type.Name)) { Debug.Assert(baseType == "SyntaxNode"); baseType = "SyntaxTriviaNode"; } builder.AppendLine("public {0} partial class {1} : {2}", type.IsAbstract ? "abstract" : "sealed", type.Name, baseType); builder.AppendLine("{"); builder.Indent(); foreach (var property in from property in type.Properties where property.DeclaringType == type orderby property.Name select property) { if ( type.BaseType.Properties.Contains(property.Name) || property.Name == "ParentTrivia" || property.Name == "AllowsAnyExpression" || property.Name == "IsConst" || property.Name == "IsFixed" ) continue; // These are not supported because they are associated with errors. //if (typeof(BracketedArgumentListSyntax).IsAssignableFrom(property.PropertyType)) // continue; string propertyType = CodeUtil.Encode(property.PropertyType); string propertyName = property.Name; // These are hand coded to keep the complexity of the generator down. if (new[] { "Arity", "IsVar", "Rank" }.Contains(property.Name)) continue; if (property.Name == "Target") { propertyType = "AttributeTarget"; enums.Add(new EnumDeclaration( propertyType, new[] { "None", "Assembly", "Field", "Event", "Method", "Module", "Param", "Property", "Return", "Type" } )); } else if ( property.PropertyType == typeof(SyntaxTrivia) || property.PropertyType == typeof(SyntaxToken) || property.PropertyType == typeof(SyntaxTokenList) ) { if (property.Name == "TextTokens") { propertyName = "Text"; propertyType = "string"; } else if (property.Name == "Modifiers") { if (type.Name == "ParameterSyntax") { propertyType = "ParameterModifier"; propertyName = "Modifier"; } else { propertyType = "Modifiers"; if (!enums.Contains(propertyType)) { enums.Add(new FlagsEnumDeclaration( propertyType, new[] { "Async", "Abstract", "Const", "Extern", "Internal", "New", "Override", "Partial", "Private", "Protected", "Public", "ReadOnly", "Sealed", "Static", "Virtual", "Volatile" }, true )); } } } else if (property.Name == "Keyword") { propertyType = null; var items = new List<string>(); switch (type.Name) { case "PredefinedTypeSyntax": propertyName = "Type"; propertyType = "PredefinedType"; items.AddRange(new[] { "Bool", "Byte", "SByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Double", "Float", "Decimal", "String", "Char", "Void", "Object" }); break; case "TypeDeclarationSyntax": case "MakeRefExpressionSyntax": case "RefTypeExpressionSyntax": case "RefValueExpressionSyntax": case "DefaultExpressionSyntax": case "TypeOfExpressionSyntax": case "SizeOfExpressionSyntax": break; case "CheckedExpressionSyntax": case "CheckedStatementSyntax": propertyName = "Kind"; propertyType = "CheckedOrUnchecked"; items.AddRange(new[] { "Checked", "Unchecked" }); break; case "AccessorDeclarationSyntax": propertyName = "Kind"; propertyType = "AccessorDeclarationKind"; items.AddRange(new[] { "Get", "Set", "Add", "Remove" }); break; default: throw new NotSupportedException(); } if (propertyType == null) continue; else if (!enums.Contains(propertyType)) enums.Add(new EnumDeclaration(propertyType, items.ToArray())); } else if (property.Name == "OperatorToken") { propertyType = null; propertyName = "Operator"; var items = new List<string>(); if (type.Name == "OperatorDeclarationSyntax") { propertyType = "Operator"; items.AddRange(new[] { "Plus", "Minus", "Exclamation", "Tilde", "PlusPlus", "MinusMinus", "Asterisk", "Slash", "Percent", "LessThanLessThan", "GreaterThanGreaterThan", "Bar", "Ampersand", "Caret", "EqualsEquals", "ExclamationEquals", "LessThan", "LessThanEquals", "GreaterThan", "GreaterThanEquals", "False", "True" }); } else { switch (type.Name) { case "BinaryExpressionSyntax": propertyType = "BinaryOperator"; items.AddRange(new[] { "Percent", "Caret", "Ampersand", "Asterisk", "Minus", "Plus", "Equals", "Bar", "LessThan", "GreaterThan", "Slash", "BarBar", "AmpersandAmpersand", "QuestionQuestion", "ExclamationEquals", "EqualsEquals", "LessThanEquals", "LessThanLessThan", "LessThanLessThanEquals", "GreaterThanEquals", "GreaterThanGreaterThan", "GreaterThanGreaterThanEquals", "SlashEquals", "AsteriskEquals", "BarEquals", "AmpersandEquals", "PlusEquals", "MinusEquals", "CaretEquals", "PercentEquals", "IsKeyword", "AsKeyword" }); break; case "PrefixUnaryExpressionSyntax": propertyType = "PrefixUnaryOperator"; items.AddRange(new[] { "Tilde", "Exclamation", "Ampersand", "Asterisk", "Minus", "Plus", "MinusMinus", "PlusPlus" }); break; case "PostfixUnaryExpressionSyntax": propertyType = "PostfixUnaryOperator"; items.AddRange(new[] { "MinusMinus", "PlusPlus" }); break; case "MemberAccessExpressionSyntax": // The operator token on this is ignored. break; default: throw new InvalidOperationException(); } } if (propertyType == null) continue; else if (!enums.Contains(propertyType)) enums.Add(new EnumDeclaration(propertyType, items.ToArray())); } else if ( type.Name == "LiteralExpressionSyntax" && property.Name == "Token" ) { propertyType = "object"; propertyName = "Value"; } else if ( property.Name.EndsWith("Token") || property.Name == "EndOfComment" || // DocumentationComment property.Name == "Comma" // RefValueExpression ) { continue; } else if (property.Name.EndsWith("Keyword")) { string trimmedName = StripPostfix(property.Name, "Keyword"); string[] items; if (trimmedName == "Variance") { propertyName = trimmedName; items = new[] { "None", "In", "Out" }; } else if (SplitNames(trimmedName).Contains("Or")) { if (trimmedName == "RefOrOut") { propertyName = "Modifier"; trimmedName = "ParameterModifier"; items = new[] { "None", "Ref", "Out" }; } else { propertyName = "Kind"; items = trimmedName.Split(new[] { "Or" }, StringSplitOptions.None); } } else { continue; } propertyType = trimmedName; if (!enums.Contains(propertyType)) enums.Add(new EnumDeclaration(propertyType, items.ToArray())); } else { propertyType = null; switch (property.Name) { case "Guid": case "File": case "Line": case "Bytes": case "Identifier": case "LocalName": case "Name": case "Prefix": propertyType = "string"; break; case "Commas": propertyType = "int?"; break; } if (propertyType == null) throw new InvalidOperationException(); } } if ( type.Name == "GotoStatementSyntax" && propertyType == "CaseOrDefault" ) propertyType += "?"; if ( property.PropertyType.Name.StartsWith("SyntaxList`") || property.PropertyType.Name.StartsWith("SeparatedSyntaxList`") ) { if (propertyType.StartsWith("Separated")) propertyType = propertyType.Substring("Separated".Length); getChildrenGenerators.Add(new ListGetChildrenGenerator(propertyName)); builder.AppendLine("public {0} {1} {{ get; private set; }}", propertyType, propertyName); initializeLists.Add(propertyName, propertyType); } else if ( typeof(SyntaxNode).IsAssignableFrom(property.PropertyType) && propertyType == property.PropertyType.Name ) { getChildrenGenerators.Add(new SimpleGetChildrenGenerator(propertyName)); string fieldName = MakeFieldName(propertyName); builder.AppendLine("private {0} {1};", propertyType, fieldName); builder.AppendLine("public {0} {1}", propertyType, propertyName); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("get {{ return {0}; }}", fieldName); builder.AppendLine("set"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("if ({0} != null)", fieldName); builder.Indent(); builder.AppendLine("RemoveChild({0});", fieldName); builder.Unindent(); builder.AppendLine(); builder.AppendLine("{0} = value;", fieldName); builder.AppendLine(); builder.AppendLine("if ({0} != null)", fieldName); builder.Indent(); builder.AppendLine("AddChild({0});", fieldName); builder.Unindent(); builder.Unindent(); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); } else { builder.AppendLine("public {0} {1} {{ get; set; }}", propertyType, propertyName); } foreach (var item in factories.Where(p => type.IsAssignableFrom(p.Key))) { FixupFactories(item.Value, property, propertyName, propertyType); } builder.AppendLine(); } if (type.IsAbstract) { builder.AppendLine("internal {0}(SyntaxKind syntaxKind)", type.Name); builder.Indent(); builder.AppendLine(": base(syntaxKind)"); builder.Unindent(); } else { builder.AppendLine("public {0}()", type.Name); builder.Indent(); builder.AppendLine(": base(SyntaxKind.{0})", StripPostfix(type.Name, "Syntax")); builder.Unindent(); } builder.AppendLine("{"); builder.Indent(); foreach (var item in initializeLists.OrderBy(p => p.Key)) { builder.AppendLine("{0} = new {1}(this);", item.Key, item.Value); } builder.Unindent(); builder.AppendLine("}"); if (getChildrenGenerators.Count > 0) { builder.AppendLine(); builder.AppendLine("public override IEnumerable<SyntaxNode> ChildNodes()"); builder.AppendLine("{"); builder.Indent(); bool hadOneChild = false; if (baseType != "SyntaxNode" && baseType != "SyntaxTriviaNode") { builder.AppendLine("foreach (var child in base.ChildNodes())"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("yield return child;"); builder.Unindent(); builder.AppendLine("}"); hadOneChild = true; } foreach (var generator in getChildrenGenerators) { if (hadOneChild) builder.AppendLine(); else hadOneChild = true; generator.Build(builder); } builder.Unindent(); builder.AppendLine("}"); } if (!type.IsAbstract) { builder.AppendLine(); builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public override void Accept(ISyntaxVisitor visitor)"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("if (!visitor.Done)"); builder.Indent(); builder.AppendLine("visitor.Visit{0}(this);", StripPostfix(type.Name, "Syntax")); builder.Unindent(); builder.Unindent(); builder.AppendLine("}"); builder.AppendLine(); builder.AppendLine("[DebuggerStepThrough]"); builder.AppendLine("public override T Accept<T>(ISyntaxVisitor<T> visitor)"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("return visitor.Visit{0}(this);", StripPostfix(type.Name, "Syntax")); builder.Unindent(); builder.AppendLine("}"); } builder.Unindent(); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); writtenTypes.Add(type); WriteFile(target, type.Name, builder); } var syntaxKinds = new List<string>(); syntaxKinds.Add("UserDefined"); syntaxKinds.AddRange(nonAbstractTypes.OrderBy(p => p).Select(p => StripPostfix(p, "Syntax"))); enums.Add(new EnumDeclaration("SyntaxKind", syntaxKinds.ToArray())); foreach (var enumType in enums.OrderBy(p => p.Name)) { var builder = new CodeFragmentBuilder(); builder.AppendLine("using System;"); builder.AppendLine("using System.Collections.Generic;"); builder.AppendLine("using System.Linq;"); builder.AppendLine("using System.Text;"); builder.AppendLine(); builder.AppendLine("namespace CSharpSyntax"); builder.AppendLine("{"); builder.Indent(); enumType.Build(builder); builder.Unindent(); builder.AppendLine("}"); WriteFile(target, enumType.Name, builder); } BuildVisitor(target, nonAbstractTypes); BuildBaseVisitor(target, nonAbstractTypes); BuildFactories(target, factories, writtenTypes); }
private void BuildVisitor(string target, HashSet<string> visitors) { var builder = new CodeFragmentBuilder(); builder.AppendLine("using System;"); builder.AppendLine("using System.Collections.Generic;"); builder.AppendLine("using System.Linq;"); builder.AppendLine("using System.Text;"); builder.AppendLine(); builder.AppendLine("namespace CSharpSyntax"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("public interface ISyntaxVisitor"); builder.AppendLine("{"); builder.Indent(); builder.AppendLine("bool Done { get; }"); foreach (string name in visitors.OrderBy(p => p)) { builder.AppendLine(); builder.AppendLine("void Visit{1}({0} node);", name, StripPostfix(name, "Syntax")); } builder.Unindent(); builder.AppendLine("}"); builder.AppendLine(); builder.AppendLine("public interface ISyntaxVisitor<T>"); builder.AppendLine("{"); builder.Indent(); bool hadOne = false; foreach (string name in visitors.OrderBy(p => p)) { if (hadOne) builder.AppendLine(); else hadOne = true; builder.AppendLine("T Visit{1}({0} node);", name, StripPostfix(name, "Syntax")); } builder.Unindent(); builder.AppendLine("}"); builder.Unindent(); builder.AppendLine("}"); WriteFile(target, "ISyntaxVisitor", builder); }