diff --git a/GlitchyEditor/BeefProj.toml b/GlitchyEditor/BeefProj.toml index 3f5d0f0..824a5be 100644 --- a/GlitchyEditor/BeefProj.toml +++ b/GlitchyEditor/BeefProj.toml @@ -7,5 +7,4 @@ TargetType = "BeefGUIApplication" StartupObject = "GlitchyEngine.Program" [Configs.Debug.Win64] -PreBuildCmds = ["dotnet build \"$(ProjectDir)/SandboxProject/Assets/Scripts/Sandbox.csproj\" -c Debug"] DebugCommandArguments = "\"content\\Scenes\\physics2D.scene\"" diff --git a/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs b/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs index 7897dd9..40cdd49 100644 --- a/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs +++ b/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs @@ -3,121 +3,134 @@ using GlitchyEngine; using GlitchyEngine.Editor; using GlitchyEngine.Math; -namespace Sandbox; +//using GlitchyEngine.Math; -public enum MyEnum +namespace Sandbox { - Yes, - No, - Maybe -} -public struct MyStruct -{ - public float TheFloat; - public Vector2 TheVector; - public MyEnum TheEnum; -} - -class MyTestEntity : Entity -{ - //[ShowInEditor] - RigidBody2D _rigidBody; - - public bool Bo; - - public byte By; - public ushort Us; - public uint Ui; - public ulong Ul; - - public sbyte Sb; - public short Sh; - public int In; - public long Lo; - - public float Fl; - public double Do; - public Vector2 V2; - public Vector3 V3; - public Vector4 V4; - - public Entity TheEntity; - - public float JumpForce = 2000; - [ShowInEditor] - float MoveForce = 1000; - [ShowInEditor] - private int MyNumber = 1337; - [ShowInEditor] - public double MyDouble = 1000.0f; - - public MyStruct AStruct; - - public Camera Camera; - - /// - /// Called after the script component was created. (The entity might not be fully created yet) - /// - void OnCreate() + public enum MyEnum { - Log.Info($"Create! {UUID}"); - - Log.Info($"Jump Force: {JumpForce}"); - - _rigidBody ??= GetComponent() ?? AddComponent(); - - Camera = FindEntityWithName("Camera").As(); - - if (Camera == null) - { - Log.Error("Camera not found."); - } - } - - /// - /// Called every frame. - /// - /// - void OnUpdate(float deltaTime) - { - Vector2 force = Vector2.Zero; - - if (Input.IsKeyPressed(Key.A)) - { - force.X -= MoveForce * deltaTime; - } - - if (Input.IsKeyPressed(Key.D)) - { - force.X += MoveForce * deltaTime; - } - - if (Input.IsKeyPressed(Key.Q)) - Camera.DistanceFromPlayer -= deltaTime; - - if (Input.IsKeyPressed(Key.E)) - Camera.DistanceFromPlayer += deltaTime; - - if (Input.IsKeyPressing(Key.Space)) - { - force.Y += JumpForce; - } - - _rigidBody.ApplyForceToCenter(force); - - if (Input.IsMouseButtonReleasing(MouseButton.MiddleButton)) - { - Log.Info($"Ouha! {MyNumber}"); - Physics2D.Gravity *= new Vector2(1, -1); - } + Yes, + No, + Maybe } - /// - /// Called before the component is being destroyed. - /// - void OnDestroy() + public struct MyStruct { - Log.Trace("Destroy"); + public float TheFloat; + public Vector2 TheVector; + public MyEnum TheEnum; } -} + + class MyTestEntity : Entity + { + //[ShowInEditor] + RigidBody2D _rigidBody; + + public bool Bo; + + public byte By; + public ushort Us; + public uint Ui; + public ulong Ul; + + public sbyte Sb; + public short Sh; + public int In; + public long Lo; + + public float Fl; + public double Do; + public Vector2 V2; + public Vector3 V3; + public Vector4 V4; + + public Entity TheEntity; + + public float JumpForce = 2000; + [ShowInEditor] float MoveForce = 1000; + [ShowInEditor] private int MyNumber = 1337; + [ShowInEditor] public double MyDouble = 1000.0f; + + public MyStruct AStruct; + + public Camera Camera; + + /// + /// Called after the script component was created. (The entity might not be fully created yet) + /// + void OnCreate() + { + Log.Info($"Create! {UUID}"); + + Log.Info($"Jump Force: {JumpForce}"); + + _rigidBody ??= GetComponent() ?? AddComponent(); + + Camera = FindEntityWithName("Camera").As(); + + if (Camera == null) + { + Log.Error("Camera not found."); + } + } + + /// + /// Called every frame. + /// + /// + void OnUpdate(float deltaTime) + { + Vector2 force = Vector2.Zero; + + if (Input.IsKeyPressed(Key.A)) + { + force.X -= MoveForce * deltaTime; + } + + if (Input.IsKeyPressed(Key.D)) + { + force.X += MoveForce * deltaTime; + } + + if (Input.IsKeyPressed(Key.Q)) + Camera.DistanceFromPlayer -= deltaTime; + + if (Input.IsKeyPressed(Key.E)) + Camera.DistanceFromPlayer += deltaTime; + + if (Input.IsKeyPressing(Key.Space)) + { + force.Y += JumpForce; + } + + _rigidBody.ApplyForceToCenter(force); + + if (Input.IsMouseButtonReleasing(MouseButton.MiddleButton)) + { + Log.Info($"Ouha! {MyNumber}"); + Physics2D.Gravity *= new Vector2(1, -1); + } + + Test.Test.P(); + + float2 f2 = new(); + + f2.X = 5; + + Log.Info($"Haleluja! {f2.X}"); + + float4 floaty = new float4(f2, f2); + + Log.Info($"Haleluja2! {floaty}"); + } + + /// + /// Called before the component is being destroyed. + /// + void OnDestroy() + { + Log.Trace("Destroy"); + } + } +} \ No newline at end of file diff --git a/GlitchyEditor/SandboxProject/Assets/Scripts/Sandbox.sln b/GlitchyEditor/SandboxProject/Assets/Scripts/Sandbox.sln index 02c6104..dcc6eec 100644 --- a/GlitchyEditor/SandboxProject/Assets/Scripts/Sandbox.sln +++ b/GlitchyEditor/SandboxProject/Assets/Scripts/Sandbox.sln @@ -5,7 +5,9 @@ VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox.csproj", "{7A70819C-5317-402A-8553-95C5A001E370}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCore", "..\..\..\..\ScriptCore\ScriptCore.csproj", "{6222C226-FC78-498C-80BA-5CF10AC9123C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptCore", "..\..\..\..\ScriptCore\ScriptCore.csproj", "{6222C226-FC78-498C-80BA-5CF10AC9123C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCoreGenerator", "..\..\..\..\ScriptCoreGenerator\ScriptCoreGenerator.csproj", "{5D662996-1E1E-4170-A08A-B26CDB63A0DE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +23,10 @@ Global {6222C226-FC78-498C-80BA-5CF10AC9123C}.Debug|Any CPU.Build.0 = Debug|Any CPU {6222C226-FC78-498C-80BA-5CF10AC9123C}.Release|Any CPU.ActiveCfg = Release|Any CPU {6222C226-FC78-498C-80BA-5CF10AC9123C}.Release|Any CPU.Build.0 = Release|Any CPU + {5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GlitchyEditor/resources/scripts/ScriptCore.deps.json b/GlitchyEditor/resources/scripts/ScriptCore.deps.json new file mode 100644 index 0000000..8dbf87a --- /dev/null +++ b/GlitchyEditor/resources/scripts/ScriptCore.deps.json @@ -0,0 +1,47 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.0/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.0": {}, + ".NETStandard,Version=v2.0/": { + "ScriptCore/1.0.0": { + "dependencies": { + "NETStandard.Library": "2.0.3" + }, + "runtime": { + "ScriptCore.dll": {} + } + }, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "NETStandard.Library/2.0.3": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + } + } + }, + "libraries": { + "ScriptCore/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "NETStandard.Library/2.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "path": "netstandard.library/2.0.3", + "hashPath": "netstandard.library.2.0.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/ScriptCore/Math/Attributes/VectorAttribute.cs b/ScriptCore/Math/Attributes/VectorAttribute.cs new file mode 100644 index 0000000..626631c --- /dev/null +++ b/ScriptCore/Math/Attributes/VectorAttribute.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ScriptCore.Math.Attributes; + +public class VectorAttribute : Attribute +{ + public Type Type { get; set; } + public int ComponentCount { get; set; } + + public string TypeBase { get; set; } + + public VectorAttribute(Type type, int componentCount, string typeBase) + { + Type = type; + ComponentCount = componentCount; + TypeBase = typeBase; + } +} + +public class SwizzleVectorAttribute : Attribute +{ + public SwizzleVectorAttribute() + { + } +} diff --git a/ScriptCore/Math/float2.cs b/ScriptCore/Math/float2.cs new file mode 100644 index 0000000..c6b2ec0 --- /dev/null +++ b/ScriptCore/Math/float2.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; +using GlitchyEngine.Math; +using ScriptCore.Math.Attributes; + +namespace GlitchyEngine.Math; + +[Vector(typeof(float), 2, "float")] +public partial struct float2 +{ +} + +[Vector(typeof(float), 3, "float")] +public partial struct float3 +{ +} + +[Vector(typeof(float), 4, "float")] +public partial struct float4 +{ +} diff --git a/ScriptCore/ScriptCore.csproj b/ScriptCore/ScriptCore.csproj index 0f8deec..56777b2 100644 --- a/ScriptCore/ScriptCore.csproj +++ b/ScriptCore/ScriptCore.csproj @@ -4,10 +4,15 @@ netstandard2.0 latest + true + + + + diff --git a/ScriptCoreGenerator/FunctionGenerator.cs b/ScriptCoreGenerator/FunctionGenerator.cs new file mode 100644 index 0000000..5de9c04 --- /dev/null +++ b/ScriptCoreGenerator/FunctionGenerator.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ScriptCoreGenerator +{ + [Generator] + public class HelloSourceGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + var receiver = (MainSyntaxReceiver)context.SyntaxReceiver; + + + + string output = @" +namespace Test{ +public class Test +{ + public static void P() => GlitchyEngine.Log.Error(""Hello World""); +}} +"; + + // Code generation goes here + context.AddSource("Test/Hello.g.cs", output); + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new MainSyntaxReceiver()); + } + } + + public class MainSyntaxReceiver : ISyntaxReceiver + { + public DefinitionAggregate Definitions { get; } = new(); + public GivethsAggregate Giveths { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + Definitions.OnVisitSyntaxNode(syntaxNode); + Giveths.OnVisitSyntaxNode(syntaxNode); + } + } + + public class DefinitionAggregate : ISyntaxReceiver + { + public List Captures { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "Define" } } attr) + { + return; + } + + var method = attr.GetParent(); + var key = method.Identifier.Text; + + Captures.Add(new Capture(key, method)); + } + + public record Capture(string Key, MethodDeclarationSyntax Method) + { + public string Key { get; } = Key; + public MethodDeclarationSyntax Method { get; } = Method; + } + } + + public class GivethsAggregate : ISyntaxReceiver + { + public List Captures { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "Give" } } attr) + { + return; + } + + var target = (attr.ArgumentList.Arguments.Single().Expression as LiteralExpressionSyntax).Token.ValueText; + + var method = attr.GetParent(); + var @class = attr.GetParent(); + + Captures.Add(new Capture(target, method, @class)); + } + + public record Capture(string TargetImplementation, MethodDeclarationSyntax Method, ClassDeclarationSyntax Class) + { + public string TargetImplementation { get; } = TargetImplementation; + public MethodDeclarationSyntax Method { get; } = Method; + public ClassDeclarationSyntax Class { get; } = Class; + } + } +} diff --git a/ScriptCoreGenerator/Properties/launchSettings.json b/ScriptCoreGenerator/Properties/launchSettings.json new file mode 100644 index 0000000..c0a631e --- /dev/null +++ b/ScriptCoreGenerator/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Debug Code Generator": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\ScriptCore\\ScriptCore.csproj" + } + } +} \ No newline at end of file diff --git a/ScriptCoreGenerator/ScriptCoreGenerator.csproj b/ScriptCoreGenerator/ScriptCoreGenerator.csproj new file mode 100644 index 0000000..7615ede --- /dev/null +++ b/ScriptCoreGenerator/ScriptCoreGenerator.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + latest + true + + + + + + + + diff --git a/ScriptCoreGenerator/SyntaxNodeExtensions.cs b/ScriptCoreGenerator/SyntaxNodeExtensions.cs new file mode 100644 index 0000000..42c4ed8 --- /dev/null +++ b/ScriptCoreGenerator/SyntaxNodeExtensions.cs @@ -0,0 +1,75 @@ +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ScriptCoreGenerator; + +public static class SyntaxNodeExtensions +{ + public static T GetParent(this SyntaxNode node) + { + var parent = node.Parent; + while (true) + { + if (parent == null) + { + throw new Exception(); + } + + if (parent is T t) + { + return t; + } + + parent = parent.Parent; + } + } + + /// + /// determine the namespace the class/enum/struct is declared in, if any + /// + public static string GetNamespace(this BaseTypeDeclarationSyntax syntax) + { + // If we don't have a namespace at all we'll return an empty string + // This accounts for the "default namespace" case + string nameSpace = string.Empty; + + // Get the containing syntax node for the type declaration + // (could be a nested type, for example) + SyntaxNode? potentialNamespaceParent = syntax.Parent; + + // Keep moving "out" of nested classes etc until we get to a namespace + // or until we run out of parents + while (potentialNamespaceParent != null && + potentialNamespaceParent is not NamespaceDeclarationSyntax + && potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax) + { + potentialNamespaceParent = potentialNamespaceParent.Parent; + } + + // Build up the final namespace by looping until we no longer have a namespace declaration + if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent) + { + // We have a namespace. Use that as the type + nameSpace = namespaceParent.Name.ToString(); + + // Keep moving "out" of the namespace declarations until we + // run out of nested namespace declarations + while (true) + { + if (namespaceParent.Parent is not NamespaceDeclarationSyntax parent) + { + break; + } + + // Add the outer namespace as a prefix to the final namespace + nameSpace = $"{namespaceParent.Name}.{nameSpace}"; + namespaceParent = parent; + } + } + + // return the final namespace + return nameSpace; + } + +} \ No newline at end of file diff --git a/ScriptCoreGenerator/VectorGenerator.cs b/ScriptCoreGenerator/VectorGenerator.cs new file mode 100644 index 0000000..ac997e0 --- /dev/null +++ b/ScriptCoreGenerator/VectorGenerator.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Mail; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static ScriptCoreGenerator.VectorSyntaxReceiver; + +namespace ScriptCoreGenerator; + +[Generator] +public class VectorGenerator : ISourceGenerator +{ + public static readonly string[] ComponentNames = {"X", "Y", "Z", "W"}; + + public static readonly string[] LowerComponentNames = {"x", "y", "z", "w"}; + + public void Execute(GeneratorExecutionContext context) + { + var receiver = (VectorSyntaxReceiver)context.SyntaxReceiver; + + if (receiver == null) return; + + StringBuilder builder = new(); + + foreach (var vector in receiver.Vectors) + { + builder.Clear(); + + // Copy all usings from the original file + builder.AppendLine(vector.Struct.GetParent().Usings.ToFullString()); + + builder.Append($$""" + namespace {{vector.Struct.GetNamespace()}}; + + public partial struct {{vector.VectorName}} + { + + """); + + GenerateFields(vector, builder); + GenerateConstructors(vector, builder); + + //var swizzle = receiver.VectorSwizzle.Swizzles.FirstOrDefault(s => s.VectorName == vector.VectorName); + + //if (swizzle != null) + GenerateSwizzle(vector, builder); + + builder.Append('}'); + + context.AddSource($"{vector.VectorName}.g.cs", builder.ToString()); + } + } + + private void GenerateFields(VectorDefinition vector, StringBuilder builder) + { + builder.Append($"\tpublic {vector.ElementTypeName} "); + + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + builder.Append(", "); + + builder.Append(ComponentNames[i]); + } + + builder.Append(";\n\n"); + } + + private void GenerateConstructors(VectorDefinition vector, StringBuilder builder) + { + GenerateSingleConstructor(vector, builder); + + if (vector.ComponentCount == 3) + { + Generatefloat3Constructors(vector, builder); + } + else if (vector.ComponentCount == 4) + { + Generatefloat4Constructors(vector, builder); + } + } + + private void GenerateSingleConstructor(VectorDefinition vector, StringBuilder builder) + { + StringBuilder parameters = new(); + StringBuilder body = new(); + + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + parameters.Append(", "); + + parameters.Append($"{vector.ElementTypeName} {LowerComponentNames[i]}"); + } + + for (int i = 0; i < vector.ComponentCount; i++) + { + body.Append($"\n\t\t{ComponentNames[i]} = {LowerComponentNames[i]};"); + } + + builder.Append($$""" + public {{vector.VectorName}} ({{parameters}}) + {{{body}} + } + + + """); + } + + private void Generatefloat3Constructors(VectorDefinition vector, StringBuilder builder) + { + builder.Append($$""" + public {{vector.VectorName}}({{vector.BaseName}}2 xy, {{vector.ElementTypeName}} z) + { + X = xy.X; + Y = xy.Y; + Z = z; + } + + """); + + builder.Append($$""" + public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.BaseName}}2 yz) + { + X = x; + Y = yz.X; + Z = yz.Y; + } + + """); + } + + private void Generatefloat4Constructors(VectorDefinition vector, StringBuilder builder) + { + builder.Append($$""" + public {{vector.VectorName}}({{vector.BaseName}}2 xy, {{vector.BaseName}}2 zw) + { + //XY = xy; + //ZW = zw; + X = xy.X; + Y = xy.Y; + Z = zw.X; + W = zw.Y; + } + + + """); + + builder.Append($$""" + public {{vector.VectorName}}({{vector.BaseName}}2 xy, {{vector.ElementTypeName}} z, {{vector.ElementTypeName}} w) + { + X = xy.X; + Y = xy.Y; + Z = z; + W = w; + } + + + """); + + builder.Append($$""" + public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.BaseName}}2 yz, {{vector.ElementTypeName}} w) + { + X = x; + Y = yz.X; + Z = yz.Y; + W = w; + } + + + """); + + builder.Append($$""" + public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.ElementTypeName}} y, {{vector.BaseName}}2 zw) + { + X = x; + Y = y; + Z = zw.X; + W = zw.Y; + } + + + """); + + builder.Append($$""" + public {{vector.VectorName}}({{vector.BaseName}}3 xyz, {{vector.ElementTypeName}} w) + { + X = xyz.X; + Y = xyz.Y; + Z = xyz.Z; + W = w; + } + + + """); + + builder.Append($$""" + public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.BaseName}}3 yzw) + { + X = x; + Y = yzw.X; + Z = yzw.Y; + W = yzw.Z; + } + + + """); + } + + /** + * Returns true if the swizzle operator is invalid (same component assigned twice). + */ + static bool IsSwizzleSetterValid(int[] cmp, int vecSize) + { + return cmp[0] == cmp[1] || (vecSize >= 3 && cmp[0] == cmp[2]) || (vecSize == 4 && cmp[0] == cmp[3]) || + (vecSize >= 3 && cmp[1] == cmp[2]) || (vecSize == 4 && cmp[1] == cmp[3]) || + (vecSize == 4 && cmp[2] == cmp[3]); + } + + private void GenerateSwizzle(VectorDefinition vector, StringBuilder builder) + { + for(int swizzleCount = 2; swizzleCount <= 4; swizzleCount++) + { + int[] cmp = new int[4]; + + int cmp2max = swizzleCount > 2 ? vector.ComponentCount : 1; + int cmp3max = swizzleCount > 3 ? vector.ComponentCount : 1; + + for(cmp[0] = 0; cmp[0] < vector.ComponentCount; cmp[0]++) + for(cmp[1] = 0; cmp[1] < vector.ComponentCount; cmp[1]++) + for(cmp[2] = 0; cmp[2] < cmp2max; cmp[2]++) + for(cmp[3] = 0; cmp[3] < cmp3max; cmp[3]++) + { + StringBuilder swizzleName = new StringBuilder(4); + StringBuilder swizzleConstructor = new StringBuilder(swizzleCount * 3); + StringBuilder setter = new StringBuilder(); + + bool setterInvalid = IsSwizzleSetterValid(cmp, swizzleCount); + + for(int c = 0; c < swizzleCount; c++) + { + swizzleName.Append(ComponentNames[cmp[c]]); + + if(c != 0) + { + swizzleConstructor.Append(", "); + } + swizzleConstructor.Append(ComponentNames[cmp[c]]); + + if(!setterInvalid && c < vector.ComponentCount) + { + setter.Append($"\n\t\t\t{ComponentNames[cmp[c]]} = value.{ComponentNames[c]};"); + } + } + // if (!setterInvalid) + // { + // setter.Append( + // """ + // set mut + // { + //"""); + // } + + builder.Append($$""" + public {{vector.BaseName}}{{swizzleCount}} {{swizzleName}} + { + get => new({{swizzleConstructor}}); + + """); + + if (!setterInvalid) + { + builder.Append($$""" + set + {{{setter}} + } + + """); + } + + builder.Append("\t}\n\n"); + + // string swizzleString = $$""" + //public {{swizzle.BaseName}}{{swizzleCount}} {{swizzleName}} + //{ + //get => {{swizzleConstructor}}; + //{{setter}} + //} + + //"""; + + //builder.Append(swizzleString); + } + } + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new VectorSyntaxReceiver()); + } +} + +public class VectorSyntaxReceiver : ISyntaxReceiver +{ + public List Vectors { get; } = new(); + + public VectorSwizzleReceiver VectorSwizzle { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + VectorSwizzle.OnVisitSyntaxNode(syntaxNode); + + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "Vector" } } attr) + { + return; + } + + var @struct = attr.GetParent(); + var name = @struct.Identifier.Text; + + // ToFullString should like probably always work + var elementTypeName = (attr.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).Type.ToFullString(); + + var componentCount = (attr.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax).Token.Value as int?; + + if (componentCount == null) + return; + + var baseName = (attr.ArgumentList.Arguments[2].Expression as LiteralExpressionSyntax).Token.ValueText; + + Vectors.Add(new VectorDefinition(name, @struct, componentCount.Value, baseName, elementTypeName)); + } + + public class VectorDefinition + { + public string VectorName { get; } + public StructDeclarationSyntax Struct { get; } + + public int ComponentCount { get; } + + public string BaseName { get; } + + public string ElementTypeName { get; } + + public VectorDefinition(string vectorName, StructDeclarationSyntax @struct, int componentCount, string baseName, string elementTypeName) + { + VectorName = vectorName; + Struct = @struct; + ComponentCount = componentCount; + BaseName = baseName; + ElementTypeName = elementTypeName; + } + } +} + +public class VectorSwizzleReceiver : ISyntaxReceiver +{ + public List Swizzles { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "SwizzleVector" } } attr) + { + return; + } + + var @struct = attr.GetParent(); + var name = @struct.Identifier.Text; + + // var baseName = (attr.ArgumentList.Arguments[0].Expression as LiteralExpressionSyntax).Token.ValueText; + + Swizzles.Add(new VectorSwizzle(name));//, baseName)); + } + + public class VectorSwizzle + { + public string VectorName { get; } + + //public string BaseName { get; } + + public VectorSwizzle(string vectorName)//, string baseName) + { + VectorName = vectorName; + //BaseName = baseName; + } + } +}