diff --git a/Tsu.Trees.RedGreen/src/DebugGenerator.cs b/Tsu.Trees.RedGreen/src/DebugGenerator.cs index 4fbc178..e3dfb9d 100644 --- a/Tsu.Trees.RedGreen/src/DebugGenerator.cs +++ b/Tsu.Trees.RedGreen/src/DebugGenerator.cs @@ -39,14 +39,16 @@ public static void RegisterDebugOutput(this IncrementalGeneratorInitializationCo builder.AppendLine($"// {indent} Children:"); foreach (var child in node.Item2.Children) - builder.AppendLine($"// {indent} {child.Type.ToCSharpString()} (IsList = {child.IsList}, Name = {child.FieldName}, IsOptional = {child.IsOptional}, PassToBase = {child.PassToBase})"); + builder.AppendLine($"// {indent} {child.Type.ToCSharpString()} (IsList = {child.IsList}, Name = {child.FieldName}, IsOptional = {child.IsOptional}, PassToBase = {child.PassToBase}, Order = {child.Order})"); builder.AppendLine($"// {indent} ExtraData:"); foreach (var child in node.Item2.ExtraData) - builder.AppendLine($"// {indent} {child.Type.ToCSharpString()} (IsList = {child.IsList}, Name = {child.FieldName}, IsOptional = {child.IsOptional}, PassToBase = {child.PassToBase})"); + builder.AppendLine($"// {indent} {child.Type.ToCSharpString()} (IsList = {child.IsList}, Name = {child.FieldName}, IsOptional = {child.IsOptional}, PassToBase = {child.PassToBase}, Order = {child.Order})"); + + builder.AppendLine($"// {indent} Descendants:"); foreach (var derived in node.Item2.Descendants) - queue.Push((node.Item1 + 1, derived)); + queue.Push((node.Item1 + 2, derived)); } ctx.AddSource($"{tree.Suffix}/Debug.g.cs", builder.ToSourceText()); diff --git a/Tsu.Trees.RedGreen/src/Model/Component.cs b/Tsu.Trees.RedGreen/src/Model/Component.cs index cca8e26..9f63807 100644 --- a/Tsu.Trees.RedGreen/src/Model/Component.cs +++ b/Tsu.Trees.RedGreen/src/Model/Component.cs @@ -24,9 +24,11 @@ public sealed record Component( ITypeSymbol Type, string FieldName, bool IsOptional, - bool PassToBase + bool PassToBase, + int Order ) { + public int SortOrder => Order < 0 ? int.MaxValue + Order : Order; public string ParameterName { get; } = FieldName.TrimStart('_').ToCamelCase(); public string PropertyName { get; } = FieldName.TrimStart('_').ToPascalCase(); } \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Model/Node.cs b/Tsu.Trees.RedGreen/src/Model/Node.cs index 0529f92..fe752ff 100644 --- a/Tsu.Trees.RedGreen/src/Model/Node.cs +++ b/Tsu.Trees.RedGreen/src/Model/Node.cs @@ -29,7 +29,7 @@ internal sealed record Node( ImmutableArray ExtraData ) { - public IEnumerable Components => ExtraData.Concat(Children); + public IEnumerable Components => ExtraData.Concat(Children).OrderBy(x => x.SortOrder); public IEnumerable ParentComponents => Components.Where(x => x.PassToBase); diff --git a/Tsu.Trees.RedGreen/src/Model/Script/ScriptComponent.cs b/Tsu.Trees.RedGreen/src/Model/Script/ScriptComponent.cs index b483a4b..5b1dfb8 100644 --- a/Tsu.Trees.RedGreen/src/Model/Script/ScriptComponent.cs +++ b/Tsu.Trees.RedGreen/src/Model/Script/ScriptComponent.cs @@ -26,4 +26,6 @@ internal sealed class ScriptComponent(Component component) public string PropertyName => component.PropertyName; public bool IsOptional => component.IsOptional; public bool PassToBase => component.PassToBase; + public int Order => component.Order; + public int SortOrder => component.SortOrder; } \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Model/Script/ScriptNode.cs b/Tsu.Trees.RedGreen/src/Model/Script/ScriptNode.cs index ca823d3..2dcb7c2 100644 --- a/Tsu.Trees.RedGreen/src/Model/Script/ScriptNode.cs +++ b/Tsu.Trees.RedGreen/src/Model/Script/ScriptNode.cs @@ -30,7 +30,7 @@ internal sealed class ScriptNode(Node node) public ImmutableArray Children { get; } = node.Children.Select(x => new ScriptComponent(x)).ToImmutableArray(); public ImmutableArray ExtraData { get; } = node.ExtraData.Select(x => new ScriptComponent(x)).ToImmutableArray(); - public IEnumerable Components => ExtraData.Concat(Children); + public IEnumerable Components => ExtraData.Concat(Children).OrderBy(x => x.SortOrder); public IEnumerable ParentComponents => Components.Where(x => x.PassToBase); diff --git a/Tsu.Trees.RedGreen/src/TreeCreator.cs b/Tsu.Trees.RedGreen/src/TreeCreator.cs index fa1da56..741f192 100644 --- a/Tsu.Trees.RedGreen/src/TreeCreator.cs +++ b/Tsu.Trees.RedGreen/src/TreeCreator.cs @@ -119,19 +119,45 @@ private static Node ProcessNode( IEnumerable parentExtraData) { var fields = node.NodeType.GetMembers().OfType().Where(f => f.IsReadOnly); - var nodeChildren = fields.Where(x => x.Type.DerivesFrom(tree.GreenBase)).Select(toComponent); - var nodeExtraData = fields.Where(x => !x.Type.DerivesFrom(tree.GreenBase)).Select(toComponent); + + // Starting order for this node + var order = 1; + if (parentNodes.Any()) + order = Math.Max(order, parentNodes.Select(x => x.Order).Max() + 1); + if (parentExtraData.Any()) + order = Math.Max(order, parentExtraData.Select(x => x.Order).Max() + 1); + + var nodeChildren = fields.Where(x => x.Type.DerivesFrom(tree.GreenBase)) + .Select(x => + { + var ret = toComponent(x, order); + if (ret.Order == order) + order++; + return ret; + }) + .ToArray(); + var nodeExtraData = fields.Where(x => !x.Type.DerivesFrom(tree.GreenBase)) + .Select(x => + { + var ret = toComponent(x, order); + if (ret.Order == order) + order++; + return ret; + }) + .ToArray(); var children = parentNodes.Select(x => x with { PassToBase = true }) .Concat(nodeChildren) + .OrderBy(x => x.SortOrder) .ToImmutableArray(); var extraData = parentExtraData.Select(x => x with { PassToBase = true }) .Concat(nodeExtraData) + .OrderBy(x => x.SortOrder) .ToImmutableArray(); if (SymbolEqualityComparer.Default.Equals(node.NodeType, tree.GreenBase)) - extraData = extraData.Add(new Component(false, tree.KindEnum, "_kind", false, false)); + extraData = extraData.Add(new Component(false, tree.KindEnum, "_kind", false, false, 0)); return new Node( node.BaseType, @@ -142,15 +168,22 @@ private static Node ProcessNode( children, extraData); - static Component toComponent(IFieldSymbol fieldSymbol) + static Component toComponent(IFieldSymbol fieldSymbol, int order) { var isList = false; var type = fieldSymbol.Type; - if (fieldSymbol.GetAttributes().SingleOrDefault(x => x.AttributeClass?.ToCSharpString(false) == "global::Tsu.Trees.RedGreen.GreenListAttribute") is AttributeData attr) + if (fieldSymbol.GetAttributes().SingleOrDefault(x => x.AttributeClass?.ToCSharpString(false) == "global::Tsu.Trees.RedGreen.GreenListAttribute") is AttributeData listAttr) { isList = true; - type = (INamedTypeSymbol) attr.ConstructorArguments.Single().Value!; + type = (INamedTypeSymbol) listAttr.ConstructorArguments.Single().Value!; + } + + if (fieldSymbol.GetAttributes().SingleOrDefault(x => x.AttributeClass?.ToCSharpString(false) == "global::Tsu.Trees.RedGreen.NodeComponentAttribute") is AttributeData custAttr) + { + var val = custAttr.NamedArguments.SingleOrDefault(x => x.Key == "Order").Value; + if (val.Value is int num) + order = num; } return new( @@ -158,7 +191,8 @@ static Component toComponent(IFieldSymbol fieldSymbol) type, fieldSymbol.Name, fieldSymbol.Type.NullableAnnotation == NullableAnnotation.Annotated, - false); + false, + order); } }