Shader like vectors for C# Scripting

This commit is contained in:
Simon Lübeß
2023-07-20 17:48:28 +02:00
parent f0de874572
commit 3e55a1614a
24 changed files with 1572 additions and 486 deletions
+405 -28
View File
@@ -2,8 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Numerics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static ScriptCoreGenerator.VectorSyntaxReceiver;
@@ -16,13 +18,45 @@ public class VectorGenerator : ISourceGenerator
public static readonly string[] LowerComponentNames = {"x", "y", "z", "w"};
private GeneratorExecutionContext _context;
public void Execute(GeneratorExecutionContext context)
{
_context = context;
var receiver = (VectorSyntaxReceiver)context.SyntaxReceiver;
if (receiver == null) return;
StringBuilder builder = new();
//foreach(var vector in receiver.Vectors)
//{
// var symbol = context.Compilation.GetSymbolsWithName(vector.VectorName);
// var firstSym = symbol.FirstOrDefault();
// context.ReportDiagnostic(Diagnostic.Create(
// new DiagnosticDescriptor(
// "SG0001",
// "Non-void method return type",
// "Type {0} iscool!.",
// "yeet",
// DiagnosticSeverity.Error,
// true), firstSym?.Locations.FirstOrDefault(), firstSym?.Name));
// //if(symbol.ReturnType.SpecialType != SpecialType.System_Void)
// //{
// // context.ReportDiagnostic(Diagnostic.Create(
// // new DiagnosticDescriptor(
// // "SG0001",
// // "Non-void method return type",
// // "Method {0} returns {1}. All methods must return void.",
// // "yeet",
// // DiagnosticSeverity.Error,
// // true), symbol.Locations.FirstOrDefault(), symbol.Name, symbol.ReturnType.Name));
// //}
//}
foreach (var vector in receiver.Vectors)
{
@@ -40,11 +74,35 @@ public class VectorGenerator : ISourceGenerator
""");
GenerateFields(vector, builder);
GenerateCasts(vector, builder);
GenerateConstructors(vector, builder);
//var swizzle = receiver.VectorSwizzle.Swizzles.FirstOrDefault(s => s.VectorName == vector.VectorName);
GenerateArrayAccess(vector, builder);
//if (swizzle != null)
GenerateEqualityOperators(vector, builder);
if (receiver.ComparableReceiver.ComparableVectors.Contains(vector.VectorName))
{
GenerateComparisonOperators(vector, builder);
}
if (receiver.MathReceiver.MathVectors.Contains(vector.VectorName))
{
GenerateMathOperators(vector, builder);
}
if (receiver.LogicReceiver.LogicVectors.Contains(vector.VectorName))
{
GenerateLogicOperators(vector, builder);
}
foreach (var cast in receiver.CastReceiver.VectorCasts.Where(c => c.FromType == vector.VectorName))
{
VectorDefinition toVectorDefinition = receiver.Vectors.First(v => v.VectorName == cast.ToType);
GenerateCastOperator(cast, vector, toVectorDefinition, builder);
}
GenerateSwizzle(vector, builder);
builder.Append('}');
@@ -53,6 +111,43 @@ public class VectorGenerator : ISourceGenerator
}
}
private void GenerateCastOperator(VectorCastSyntaxReceiver.VectorCast cast, VectorDefinition fromVector, VectorDefinition toVector, StringBuilder builder)
{
if (fromVector.ComponentCount != toVector.ComponentCount)
{
_context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor(
"SG0001",
"Vector-Dimensions don't match for cast.",
$"Cannot cast from \"{fromVector.VectorName}\" to \"{toVector.VectorName}\" because the dimensions don't match.",
"Vector Generator",
DiagnosticSeverity.Error,
true), fromVector.Struct.GetLocation()));
return;
}
StringBuilder castBuilder = new();
for (int i = 0; i < fromVector.ComponentCount; i++)
{
if (i != 0)
castBuilder.Append(", ");
castBuilder.Append($"({toVector.ElementTypeName})value.{ComponentNames[i]}");
}
builder.Append($$"""
public static {{(cast.IsExplicit ? "explicit" : "implicit")}} operator {{cast.ToType}}({{cast.FromType}} value)
{
return new {{cast.ToType}}({{castBuilder}});
}
""");
}
private void GenerateFields(VectorDefinition vector, StringBuilder builder)
{
builder.Append($"\tpublic {vector.ElementTypeName} ");
@@ -68,6 +163,53 @@ public class VectorGenerator : ISourceGenerator
builder.Append(";\n\n");
}
private void GenerateCasts(VectorDefinition vector, StringBuilder builder)
{
StringBuilder castBuilder = new();
for (int i = 0; i < vector.ComponentCount; i++)
{
if (i != 0)
castBuilder.Append(", ");
castBuilder.Append("value");
}
builder.Append($$"""
public static implicit operator {{vector.VectorName}}({{vector.ElementTypeName}} value)
{
return new {{vector.VectorName}}({{castBuilder}});
}
""");
// ???
// StringBuilder constructorBody = new();
// for (int i = 0; i < vector.ComponentCount; i++)
// {
// if (i != 0)
// constructorBody.Append(", ");
// constructorBody.Append("value");
// }
// builder.Append($$"""
// public static implicit operator {{}}
// """);
// String castSingleToVector = scope $"""
//public static implicit operator Self({typeof(T)} value)
//{{
// return Self({constructorBody});
// }}
//""";
}
private void GenerateConstructors(VectorDefinition vector, StringBuilder builder)
{
GenerateSingleConstructor(vector, builder);
@@ -208,6 +350,193 @@ public class VectorGenerator : ISourceGenerator
""");
}
private static void GenerateArrayAccess(VectorDefinition vector, StringBuilder builder)
{
StringBuilder getterSwitch = new();
StringBuilder setterSwitch = new();
for (int i = 0; i < vector.ComponentCount; i++)
{
getterSwitch.Append($$"""
case {{i}}:
return {{ComponentNames[i]}};
""");
setterSwitch.Append($$"""
case {{i}}:
{{ComponentNames[i]}} = value;
break;
""");
}
builder.Append($$"""
public {{vector.ElementTypeName}} this[int index]
{
get
{
switch (index)
{{{getterSwitch}}
default:
throw new IndexOutOfRangeException();
}
}
set
{
switch (index)
{{{setterSwitch}}
default:
throw new IndexOutOfRangeException();
}
}
}
""");
}
private void GenerateEqualityOperators(VectorDefinition vector, StringBuilder builder)
{
GenerateComparison("==", vector, builder);
GenerateComparison("!=", vector, builder);
}
public static void GenerateComparison(string op, VectorDefinition vector, StringBuilder builder)
{
StringBuilder arguments = new();
for (int i = 0; i < vector.ComponentCount; i++)
{
if (i != 0)
arguments.Append(", ");
arguments.Append($"left.{ComponentNames[i]} {op} right.{ComponentNames[i]}");
}
builder.Append($$"""
public static bool{{vector.ComponentCount}} operator {{op}}({{vector.VectorName}} left, {{vector.VectorName}} right)
{
return new bool{{vector.ComponentCount}}({{arguments}});
}
""");
}
private void GenerateComparisonOperators(VectorDefinition vector, StringBuilder builder)
{
GenerateComparison(">", vector, builder);
GenerateComparison(">=", vector, builder);
GenerateComparison("<", vector, builder);
GenerateComparison("<=", vector, builder);
}
public static void GenerateMathOperators(VectorDefinition vector, StringBuilder builder)
{
GenerateUnaryOperatorOverload("+", vector, builder);
GenerateUnaryOperatorOverload("-", vector, builder);
GenerateOperatorOverloads("+", vector, builder);
GenerateOperatorOverloads("-", vector, builder);
GenerateOperatorOverloads("*", vector, builder);
GenerateOperatorOverloads("/", vector, builder);
GenerateOperatorOverloads("%", vector, builder);
}
public static void GenerateUnaryOperatorOverload(string op, VectorDefinition vector, StringBuilder builder)
{
StringBuilder negativeArguments = new();
for (int i = 0; i < vector.ComponentCount; i++)
{
if (i != 0)
negativeArguments.Append(", ");
negativeArguments.Append($"{op}value.{ComponentNames[i]}");
}
builder.Append($$"""
public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} value)
{
return new {{vector.VectorName}}({{negativeArguments}});
}
""");
}
public static void GenerateOperatorOverloads(string op, VectorDefinition vector, StringBuilder builder)
{
StringBuilder arguments = new();
// Vector <op> Vector
for (int i = 0; i < vector.ComponentCount; i++)
{
if (i != 0)
arguments.Append(", ");
arguments.Append($"left.{ComponentNames[i]} {op} right.{ComponentNames[i]}");
}
builder.Append($$"""
public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} left, {{vector.VectorName}} right)
{
return new {{vector.VectorName}}({{arguments}});
}
""");
// Vector <op> Scalar
arguments.Clear();
for (int i = 0; i < vector.ComponentCount; i++)
{
if (i != 0)
arguments.Append(", ");
arguments.Append($"left.{ComponentNames[i]} {op} right");
}
builder.Append($$"""
public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} left, {{vector.ElementTypeName}} right)
{
return new {{vector.VectorName}}({{arguments}});
}
""");
// Scalar <op> Vector
arguments.Clear();
for (int i = 0; i < vector.ComponentCount; i++)
{
if (i != 0)
arguments.Append(", ");
arguments.Append($"left {op} right.{ComponentNames[i]}");
}
builder.Append($$"""
public static {{vector.VectorName}} operator {{op}}({{vector.ElementTypeName}} left, {{vector.VectorName}} right)
{
return new {{vector.VectorName}}({{arguments}});
}
""");
}
public static void GenerateLogicOperators(VectorDefinition vector, StringBuilder builder)
{
GenerateOperatorOverloads("&", vector, builder);
GenerateOperatorOverloads("|", vector, builder);
GenerateOperatorOverloads("^", vector, builder);
}
/**
* Returns true if the swizzle operator is invalid (same component assigned twice).
@@ -304,23 +633,26 @@ public class VectorGenerator : ISourceGenerator
public class VectorSyntaxReceiver : ISyntaxReceiver
{
public List<VectorDefinition> Vectors { get; } = new();
public ComparableVectorSyntaxReceiver ComparableReceiver = new();
public VectorMathSyntaxReceiver MathReceiver = new();
public VectorLogicSyntaxReceiver LogicReceiver = new();
public VectorCastSyntaxReceiver CastReceiver = new();
public VectorSwizzleReceiver VectorSwizzle { get; } = new();
public List<VectorDefinition> Vectors { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
VectorSwizzle.OnVisitSyntaxNode(syntaxNode);
ComparableReceiver.OnVisitSyntaxNode(syntaxNode);
MathReceiver.OnVisitSyntaxNode(syntaxNode);
LogicReceiver.OnVisitSyntaxNode(syntaxNode);
CastReceiver.OnVisitSyntaxNode(syntaxNode);
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "Vector" } } attr)
{
return;
}
var @struct = attr.GetParent<StructDeclarationSyntax>();
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?;
@@ -355,35 +687,80 @@ public class VectorSyntaxReceiver : ISyntaxReceiver
}
}
public class VectorSwizzleReceiver : ISyntaxReceiver
public class ComparableVectorSyntaxReceiver : ISyntaxReceiver
{
public List<VectorSwizzle> Swizzles { get; } = new();
public List<string> ComparableVectors { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "SwizzleVector" } } attr)
{
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "ComparableVector" } } attr)
return;
}
var @struct = attr.GetParent<StructDeclarationSyntax>();
var name = @struct.Identifier.Text;
// var baseName = (attr.ArgumentList.Arguments[0].Expression as LiteralExpressionSyntax).Token.ValueText;
Swizzles.Add(new VectorSwizzle(name));//, baseName));
ComparableVectors.Add(name);
}
}
public class VectorMathSyntaxReceiver : ISyntaxReceiver
{
public List<string> MathVectors { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "VectorMath" } } attr)
return;
var @struct = attr.GetParent<StructDeclarationSyntax>();
var name = @struct.Identifier.Text;
MathVectors.Add(name);
}
}
public class VectorLogicSyntaxReceiver : ISyntaxReceiver
{
public List<string> LogicVectors { get; } = new();
public class VectorSwizzle
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
public string VectorName { get; }
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "VectorLogic" } } attr)
return;
//public string BaseName { get; }
var @struct = attr.GetParent<StructDeclarationSyntax>();
var name = @struct.Identifier.Text;
LogicVectors.Add(name);
}
}
public VectorSwizzle(string vectorName)//, string baseName)
{
VectorName = vectorName;
//BaseName = baseName;
}
public class VectorCastSyntaxReceiver : ISyntaxReceiver
{
public List<VectorCast> VectorCasts { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "VectorCast" } } attr)
return;
var @struct = attr.GetParent<StructDeclarationSyntax>();
var fromType = @struct.Identifier.Text;
var toType = (attr.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).Type.ToFullString();
var isExplicit = (attr.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax).Token.Value as bool?;
if (isExplicit == null)
return;
VectorCasts.Add(new VectorCast(fromType, toType, isExplicit.Value));
}
public record VectorCast (string FromType, string ToType, bool IsExplicit)
{
public string FromType { get; } = FromType;
public string ToType { get; } = ToType;
public bool IsExplicit { get; } = IsExplicit;
}
}