diff --git a/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenNodeAttribute.g.cs b/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenNodeAttribute.cs similarity index 77% rename from Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenNodeAttribute.g.cs rename to Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenNodeAttribute.cs index 456165f..64915cc 100644 --- a/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenNodeAttribute.g.cs +++ b/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenNodeAttribute.cs @@ -7,8 +7,8 @@ /// The kinds this node could have. /// This should be the value on the enum (e.g.: SyntaxKind.ClassDeclarationSyntax) /// -[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] -internal sealed class GreenNodeAttribute(params object[] kinds) : Attribute +[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +internal sealed class GreenNodeAttribute(params object[] kinds) : global::System.Attribute { /// /// This node's Kind. diff --git a/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenTreeRootAttribute.g.cs b/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenTreeRootAttribute.cs similarity index 70% rename from Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenTreeRootAttribute.g.cs rename to Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenTreeRootAttribute.cs index a6452c8..18e0608 100644 --- a/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenTreeRootAttribute.g.cs +++ b/Tsu.Trees.RedGreen/sample/Generated/Tsu.Trees.RedGreen/Tsu.Trees.RedGreen.SourceGenerator.Generator/GreenTreeRootAttribute.cs @@ -3,8 +3,8 @@ /// /// An attribute that marks the given class as the base class for all nodes in a green node tree. /// -[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] -internal sealed class GreenTreeRootAttribute(Type redBase, string suffix, Type kindEnum) : Attribute +[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +internal sealed class GreenTreeRootAttribute(Type redBase, string suffix, Type kindEnum) : global::System.Attribute { /// /// The suffix for nodes in this tree. @@ -14,12 +14,12 @@ internal sealed class GreenTreeRootAttribute(Type redBase, string suffix, Type k /// /// The base node type for all nodes in the red tree. /// - public Type RedBase { get; } = redBase; + public global::System.Type RedBase { get; } = redBase; /// /// The enum type that contains the definitions for the node kinds. /// - public Type KindEnum { get; } = kindEnum; + public global::System.Type KindEnum { get; } = kindEnum; /// /// Whether to create base visitor implementations for this tree. @@ -36,6 +36,12 @@ internal sealed class GreenTreeRootAttribute(Type redBase, string suffix, Type k /// public bool CreateRewriter { get; set; } + /// + /// Whether to generate list types and infrastructure for this tree. + /// This implies in having roslyn MIT-licensed code being added to your project. + /// + public bool CreateLists { get; set; } + /// /// Whether to generate a file with only comments dumping the entire tree structure. /// diff --git a/Tsu.Trees.RedGreen/src/Code.cs b/Tsu.Trees.RedGreen/src/Code.cs deleted file mode 100644 index 223c7f3..0000000 --- a/Tsu.Trees.RedGreen/src/Code.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright © 2024 GGG KILLER -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software -// and associated documentation files (the “Software”), to deal in the Software without -// restriction, including without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -// the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -namespace Tsu.Trees.RedGreen.SourceGenerator; - -internal static class Code -{ - public const string GreenNodeAttributeName = "Tsu.Trees.RedGreen.GreenNodeAttribute"; - - public const string GreenNodeAttributeCode = """ - namespace Tsu.Trees.RedGreen; - - /// - /// Marks this class as a green node. - /// - /// - /// The kinds this node could have. - /// This should be the value on the enum (e.g.: SyntaxKind.ClassDeclarationSyntax) - /// - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - internal sealed class GreenNodeAttribute(params object[] kinds) : Attribute - { - /// - /// This node's Kind. - /// - public object[] Kinds { get; } = kinds; - } - """; - - public const string GreenTreeRootAttributeName = "Tsu.Trees.RedGreen.GreenTreeRootAttribute"; - - public const string GreenTreeRootAttributeCode = """ - namespace Tsu.Trees.RedGreen; - - /// - /// An attribute that marks the given class as the base class for all nodes in a green node tree. - /// - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - internal sealed class GreenTreeRootAttribute(Type redBase, string suffix, Type kindEnum) : Attribute - { - /// - /// The suffix for nodes in this tree. - /// - public string Suffix { get; } = suffix; - - /// - /// The base node type for all nodes in the red tree. - /// - public Type RedBase { get; } = redBase; - - /// - /// The enum type that contains the definitions for the node kinds. - /// - public Type KindEnum { get; } = kindEnum; - - /// - /// Whether to create base visitor implementations for this tree. - /// - public bool CreateVisitors { get; set; } - - /// - /// Whether to create a base walker implementation for this tree. - /// - public bool CreateWalker { get; set; } - - /// - /// Whether to generate a base rewriter implementation for this tree. - /// - public bool CreateRewriter { get; set; } - - /// - /// Whether to generate list types and infrastructure for this tree. - /// This implies in having roslyn MIT-licensed code being added to your project. - /// - public bool CreateLists { get; set; } - - /// - /// Whether to generate a file with only comments dumping the entire tree structure. - /// - public bool DebugDump { get; set; } - } - """; -} \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Generator.cs b/Tsu.Trees.RedGreen/src/Generator.cs index 9332c48..56868dc 100644 --- a/Tsu.Trees.RedGreen/src/Generator.cs +++ b/Tsu.Trees.RedGreen/src/Generator.cs @@ -27,17 +27,16 @@ public sealed class Generator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { + context.RegisterResourcesToCopy([ + "GreenTreeRootAttribute.cs", + "GreenNodeAttribute.cs", + ]); + var roots = context.GetTreeInfos(); var nodes = context.GetNodeInfos(); var trees = TreeCreator.BuildTree(roots, nodes); - context.RegisterPostInitializationOutput(ctx => - { - ctx.AddSource("GreenNodeAttribute.g.cs", Code.GreenNodeAttributeCode); - ctx.AddSource("GreenTreeRootAttribute.g.cs", Code.GreenTreeRootAttributeCode); - }); - context.RegisterSourceOutput(trees, (ctx, tree) => { if (!tree.DebugDump) diff --git a/Tsu.Trees.RedGreen/src/ResourceCopier.cs b/Tsu.Trees.RedGreen/src/ResourceCopier.cs new file mode 100644 index 0000000..15533fa --- /dev/null +++ b/Tsu.Trees.RedGreen/src/ResourceCopier.cs @@ -0,0 +1,30 @@ +using System.Reflection; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace Tsu.Trees.RedGreen.SourceGenerator; + +internal static class ResourceCopier +{ + private static readonly Assembly _assembly = typeof(TemplateGenerator).Assembly; + + public static void RegisterResourcesToCopy(this IncrementalGeneratorInitializationContext context, IEnumerable paths) + { + context.RegisterPostInitializationOutput(ctx => + { + foreach (var path in paths) + { + SourceText sourceText; + + using (var stream = _assembly.GetManifestResourceStream(path)) + using (var reader = new StreamReader(stream)) + { + sourceText = SourceText.From(reader, (int) stream.Length, Encoding.UTF8); + } + + ctx.AddSource(path, sourceText); + } + }); + } +} \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Templates/GreenListAttribute.cs b/Tsu.Trees.RedGreen/src/Templates/GreenListAttribute.cs new file mode 100644 index 0000000..74e0c0c --- /dev/null +++ b/Tsu.Trees.RedGreen/src/Templates/GreenListAttribute.cs @@ -0,0 +1,17 @@ +namespace Tsu.Trees.RedGreen; + +/// +/// Marks this struct as a green list base. +/// +/// +/// The kind that all lists will have. +/// This should be the value on the enum (e.g.: SyntaxKind.List) +/// +[global::System.AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] +internal sealed class GreenListAttribute(object kind) : global::System.Attribute +{ + /// + /// The List Kind. + /// + public object Kind { get; } = kind; +} \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Templates/GreenNodeAttribute.cs b/Tsu.Trees.RedGreen/src/Templates/GreenNodeAttribute.cs new file mode 100644 index 0000000..5975e60 --- /dev/null +++ b/Tsu.Trees.RedGreen/src/Templates/GreenNodeAttribute.cs @@ -0,0 +1,17 @@ +namespace Tsu.Trees.RedGreen; + +/// +/// Marks this class as a green node. +/// +/// +/// The kinds this node could have. +/// This should be the value on the enum (e.g.: SyntaxKind.ClassDeclarationSyntax) +/// +[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +internal sealed class GreenNodeAttribute(params object[] kinds) : global::System.Attribute +{ + /// + /// This node's Kind. + /// + public object[] Kinds { get; } = kinds; +} \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Templates/GreenTreeRootAttribute.cs b/Tsu.Trees.RedGreen/src/Templates/GreenTreeRootAttribute.cs new file mode 100644 index 0000000..fb594aa --- /dev/null +++ b/Tsu.Trees.RedGreen/src/Templates/GreenTreeRootAttribute.cs @@ -0,0 +1,49 @@ +namespace Tsu.Trees.RedGreen; + +/// +/// An attribute that marks the given class as the base class for all nodes in a green node tree. +/// +[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +internal sealed class GreenTreeRootAttribute(Type redBase, string suffix, Type kindEnum) : global::System.Attribute +{ + /// + /// The suffix for nodes in this tree. + /// + public string Suffix { get; } = suffix; + + /// + /// The base node type for all nodes in the red tree. + /// + public global::System.Type RedBase { get; } = redBase; + + /// + /// The enum type that contains the definitions for the node kinds. + /// + public global::System.Type KindEnum { get; } = kindEnum; + + /// + /// Whether to create base visitor implementations for this tree. + /// + public bool CreateVisitors { get; set; } + + /// + /// Whether to create a base walker implementation for this tree. + /// + public bool CreateWalker { get; set; } + + /// + /// Whether to generate a base rewriter implementation for this tree. + /// + public bool CreateRewriter { get; set; } + + /// + /// Whether to generate list types and infrastructure for this tree. + /// This implies in having roslyn MIT-licensed code being added to your project. + /// + public bool CreateLists { get; set; } + + /// + /// Whether to generate a file with only comments dumping the entire tree structure. + /// + public bool DebugDump { get; set; } +} \ No newline at end of file diff --git a/Tsu.Trees.RedGreen/src/Tsu.Trees.RedGreen.csproj b/Tsu.Trees.RedGreen/src/Tsu.Trees.RedGreen.csproj index 3338e97..343f8c7 100644 --- a/Tsu.Trees.RedGreen/src/Tsu.Trees.RedGreen.csproj +++ b/Tsu.Trees.RedGreen/src/Tsu.Trees.RedGreen.csproj @@ -27,6 +27,11 @@ + + + + + diff --git a/Tsu.Trees.RedGreen/src/Utils.cs b/Tsu.Trees.RedGreen/src/Utils.cs index 37f6a15..11d6a18 100644 --- a/Tsu.Trees.RedGreen/src/Utils.cs +++ b/Tsu.Trees.RedGreen/src/Utils.cs @@ -78,74 +78,6 @@ public static string ToCSharpString(this INamespaceSymbol symbol, bool noGlobal return noGlobal ? str.Substring("global::".Length) : str; } - public static void WriteLines(this IndentedTextWriter writer, string text) - { - var initialIndent = writer.Indent; - var lines = text.Split('\n'); - foreach (var l in lines) - { - var line = l.TrimEnd(); - if (line.Length == 0) - { - writer.WriteLineNoTabs(""); - } - else - { - var indents = countIndents(line, 4); - if (writer.Indent != initialIndent + indents) - writer.Indent = initialIndent + indents; - writer.WriteLine(line.TrimStart()); - } - } - - static int countIndents(string str, int spaces) - { - var n = 0; - for (var idx = 0; idx < str.Length; idx++) - { - if (str[idx] == ' ') - n++; - else - break; - } - return n / spaces; - } - } - - public static void WriteLines(this IndentedTextWriter writer, string text, params object[] args) - { - var initialIndent = writer.Indent; - var lines = text.Split('\n'); - foreach (var l in lines) - { - var line = l.TrimEnd(); - if (line.Length == 0) - { - writer.WriteLineNoTabs(""); - } - else - { - var indents = countIndents(line, 4); - if (writer.Indent != initialIndent + indents) - writer.Indent = initialIndent + indents; - writer.WriteLine(line.TrimStart(), args); - } - } - - static int countIndents(string str, int spaces) - { - var n = 0; - for (var idx = 0; idx < str.Length; idx++) - { - if (str[idx] == ' ') - n++; - else - break; - } - return n / spaces; - } - } - public static SourceText ToSourceText(this StringBuilder builder) => SourceText.From(new StringBuilderReader(builder), builder.Length, Encoding.UTF8); } \ No newline at end of file