diff --git a/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen.SourceGenerator/Tsu.Trees.RedGreen.SourceGenerator.Generator/Sample.Internal.g.cs b/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen.SourceGenerator/Tsu.Trees.RedGreen.SourceGenerator.Generator/Sample.Internal.g.cs index 556c284..e1f2c31 100644 --- a/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen.SourceGenerator/Tsu.Trees.RedGreen.SourceGenerator.Generator/Sample.Internal.g.cs +++ b/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen.SourceGenerator/Tsu.Trees.RedGreen.SourceGenerator.Generator/Sample.Internal.g.cs @@ -38,7 +38,7 @@ public int SlotCount { var node = this.GetSlot(index); Debug.Assert((object)node != null) - return node; + return node!; } protected virtual int GetSlotCount() => _slotCount; @@ -177,6 +177,16 @@ internal BinaryOperationExpressionSample(global::Tsu.Trees.RedGreen.Sample.Sampl public override global::Tsu.Trees.RedGreen.Sample.SampleNode CreateRed(global::Tsu.Trees.RedGreen.Sample.SampleNode? parent) => new global::Tsu.Trees.RedGreen.Sample.BinaryOperationExpressionSample(this, parent); + + public global::Tsu.Trees.RedGreen.Sample.Internal.BinaryOperationExpressionSample Update(global::Tsu.Trees.RedGreen.Sample.SampleKind kind, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample left, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample right) + { + if (kind != this.Kind && left != this.Left && right != this.Right) + { + return global::Tsu.Trees.RedGreen.Sample.Internal.SampleFactory.BinaryOperationExpression(kind, left, right); + } + + return this; + } } partial class FunctionCallExpressionSample : global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample @@ -215,5 +225,71 @@ internal FunctionCallExpressionSample(global::Tsu.Trees.RedGreen.Sample.SampleKi return this; } } + + internal static class SampleFactory + { + public static global::Tsu.Trees.RedGreen.Sample.Internal.IdentifierExpressionSample IdentifierExpression(string name) + { +#if DEBUG + if ((object)name == null) throw new global::System.ArgumentNullException(nameof(name)) +#endif // DEBUG + + return new global::Tsu.Trees.RedGreen.Sample.Internal.IdentifierExpressionSample( + global::Tsu.Trees.RedGreen.Sample.SampleKind.IdentifierExpression, name); + } + + public static global::Tsu.Trees.RedGreen.Sample.Internal.NumericalLiteralExpressionSample NumericalLiteralExpression(double value) + { +#if DEBUG +#endif // DEBUG + + return new global::Tsu.Trees.RedGreen.Sample.Internal.NumericalLiteralExpressionSample( + global::Tsu.Trees.RedGreen.Sample.SampleKind.NumericalLiteralExpression, value); + } + + public static global::Tsu.Trees.RedGreen.Sample.Internal.BinaryOperationExpressionSample BinaryOperationExpression(global::Tsu.Trees.RedGreen.Sample.SampleKind kind, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample left, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample right) + { +#if DEBUG + if ((object)left == null) throw new global::System.ArgumentNullException(nameof(left)) + if ((object)right == null) throw new global::System.ArgumentNullException(nameof(right)) + switch (kind) + { + case Tsu.Trees.RedGreen.Sample.SampleKind.AdditionExpression: + case Tsu.Trees.RedGreen.Sample.SampleKind.DivisionExpression: + case Tsu.Trees.RedGreen.Sample.SampleKind.MultiplicationExpression: + case Tsu.Trees.RedGreen.Sample.SampleKind.SubtractionExpression: + break; + default: + throw new global::System.ArgumentException("Kind not accepted for this node.", nameof(kind)); + } +#endif // DEBUG + + return new global::Tsu.Trees.RedGreen.Sample.Internal.BinaryOperationExpressionSample( + kind, left, right); + } + + public static global::Tsu.Trees.RedGreen.Sample.Internal.FunctionCallExpressionSample FunctionCallExpression(global::Tsu.Trees.RedGreen.Sample.Internal.IdentifierExpressionSample identifier, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample firstArg) + { +#if DEBUG + if ((object)identifier == null) throw new global::System.ArgumentNullException(nameof(identifier)) + if ((object)firstArg == null) throw new global::System.ArgumentNullException(nameof(firstArg)) +#endif // DEBUG + + return new global::Tsu.Trees.RedGreen.Sample.Internal.FunctionCallExpressionSample( + global::Tsu.Trees.RedGreen.Sample.SampleKind.FunctionCallExpression, identifier, firstArg); + } + + public static global::Tsu.Trees.RedGreen.Sample.Internal.FunctionCallExpressionSample FunctionCallExpression(global::Tsu.Trees.RedGreen.Sample.Internal.IdentifierExpressionSample identifier, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample firstArg, global::Tsu.Trees.RedGreen.Sample.Internal.ExpressionSample secondArg) + { +#if DEBUG + if ((object)identifier == null) throw new global::System.ArgumentNullException(nameof(identifier)) + if ((object)firstArg == null) throw new global::System.ArgumentNullException(nameof(firstArg)) + if ((object)secondArg == null) throw new global::System.ArgumentNullException(nameof(secondArg)) +#endif // DEBUG + + return new global::Tsu.Trees.RedGreen.Sample.Internal.FunctionCallExpressionSample( + global::Tsu.Trees.RedGreen.Sample.SampleKind.FunctionCallExpression, identifier, firstArg, secondArg); + } + } } diff --git a/Tsu.Trees.RedGreen/sourcegen/GreenTreeWriter.cs b/Tsu.Trees.RedGreen/sourcegen/GreenTreeWriter.cs index 760eb94..86625a3 100644 --- a/Tsu.Trees.RedGreen/sourcegen/GreenTreeWriter.cs +++ b/Tsu.Trees.RedGreen/sourcegen/GreenTreeWriter.cs @@ -1,6 +1,7 @@ using System.CodeDom.Compiler; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Tsu.Trees.RedGreen.SourceGenerator.Model; namespace Tsu.Trees.RedGreen.SourceGenerator; @@ -51,6 +52,9 @@ public static void RegisterGreenOutput(this IncrementalGeneratorInitializationCo writer.WriteGreenNode(tree, node); } + writer.WriteLineNoTabs(""); + writer.WriteGreenFactory(tree); + writer.Indent--; writer.WriteLine('}'); writer.WriteLineNoTabs(""); @@ -395,8 +399,104 @@ private static void WriteGreenConstructor(this IndentedTextWriter writer, Node n writer.WriteLine('}'); } - public static void WriteGreenFactory(this IncrementalGeneratorInitializationContext context, IncrementalValuesProvider trees) + public static void WriteGreenFactory(this IndentedTextWriter writer, Tree tree) + { + writer.WriteLine("{0} static class {1}Factory", tree.GreenBase.DeclaredAccessibility.ToCSharpString(), tree.Suffix); + writer.WriteLine('{'); + writer.Indent++; + { + var queue = new Queue(); + foreach (var desc in tree.Root.Descendants) + queue.Enqueue(desc); + + var first = true; + while (queue.Count > 0) + { + var node = queue.Dequeue(); + if (node.Descendants.Any()) + { + foreach (var desc in node.Descendants) + queue.Enqueue(desc); + } + else + { + if (!first) writer.WriteLineNoTabs(""); + first = false; + writer.WriteGreenFactoryMethods(tree, node); + } + } + } + writer.Indent--; + writer.WriteLine('}'); + } + + private static void WriteGreenFactoryMethods(this IndentedTextWriter writer, Tree tree, Node node) { + if (node.RequiredComponents.Any(x => x.IsOptional)) + { + var nonOptionalRequired = node.RequiredComponents.Where(x => !x.IsOptional); + writeMethod(writer, tree, node, nonOptionalRequired); + writer.WriteLineNoTabs(""); + } + writeMethod(writer, tree, node, node.RequiredComponents); + + static void writeMethod(IndentedTextWriter writer, Tree tree, Node node, IEnumerable components) + { + writer.Write("public static {0} {1}(", node.TypeSymbol.ToCSharpString(), node.TypeSymbol.Name.WithoutSuffix(tree.Suffix)); + var first = true; + foreach (var component in components) + { + if (!first) writer.Write(", "); + first = false; + writer.Write("{0} {1}", component.Type.ToCSharpString(), component.ParameterName); + } + writer.WriteLine(')'); + writer.WriteLine('{'); + writer.Indent++; + { + writer.WriteLineNoTabs("#if DEBUG"); + foreach (var component in components.Where(x => !x.Type.IsValueType)) + writer.WriteLine("if ((object){0} == null) throw new global::System.ArgumentNullException(nameof({0}))", component.ParameterName); + if (node.Kinds.Length != 1) + { + writer.WriteLine("switch (kind)"); + writer.WriteLine('{'); + writer.Indent++; + { + foreach (var kind in node.Kinds) + writer.WriteLine("case {0}:", kind.ToCSharpString()); + writer.Indent++; + writer.WriteLine("break;"); + writer.Indent--; + writer.WriteLine("default:"); + writer.Indent++; + writer.WriteLine("throw new global::System.ArgumentException(\"Kind not accepted for this node.\", nameof(kind));"); + writer.Indent--; + } + writer.Indent--; + writer.WriteLine('}'); + } + writer.WriteLineNoTabs("#endif // DEBUG"); + writer.WriteLineNoTabs(""); + + writer.WriteLine("return new {0}(", node.TypeSymbol.ToCSharpString()); + first = true; + if (node.Kinds.Length == 1) + { + first = false; + writer.Write("global::{0}", node.Kinds[0].ToCSharpString()); + } + foreach (var component in components) + { + if (!first) writer.Write(", "); + first = false; + writer.Write(component.ParameterName); + } + writer.WriteLine(");"); + } + writer.Indent--; + writer.WriteLine('}'); + } } private static string WithoutSuffix(this string name, string suffix)