Skip to content

Commit

Permalink
Merge pull request #47 from Sergio0694/feature_static-methods
Browse files Browse the repository at this point in the history
Added support for static methods
  • Loading branch information
Sergio0694 authored Sep 4, 2019
2 parents 7a9afa3 + d281236 commit a16ca5b
Show file tree
Hide file tree
Showing 11 changed files with 510 additions and 80 deletions.
57 changes: 35 additions & 22 deletions src/ComputeSharp.Shaders/Extensions/SyntaxNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ public static TRoot ReplaceType<TRoot>(this TRoot node, TypeSyntax type) where T
/// <param name="node">The input <see cref="MemberAccessExpressionSyntax"/> to check and modify if needed</param>
/// <param name="semanticModel">The <see cref="SemanticModel"/> to use to load symbols for the input node</param>
/// <param name="variable">The info on parsed static members, if any</param>
/// <param name="method">The info on parsed static methods, if any</param>
/// <returns>A <see cref="SyntaxNode"/> instance that is compatible with HLSL</returns>
[Pure]
public static SyntaxNode ReplaceMember(this MemberAccessExpressionSyntax node, SemanticModel semanticModel, out (string Name, ReadableMember MemberInfo)? variable)
public static SyntaxNode ReplaceMember(this MemberAccessExpressionSyntax node, SemanticModel semanticModel, out (string Name, ReadableMember MemberInfo)? variable, out (string Name, MethodInfo MethodInfo)? method)
{
// Set the variable to null, replace it later on if needed
// Set the out parameters to null, replace them later on if needed
variable = null;
method = null;

SymbolInfo containingMemberSymbolInfo;
ISymbol? memberSymbol;
Expand Down Expand Up @@ -115,37 +117,48 @@ public static SyntaxNode ReplaceMember(this MemberAccessExpressionSyntax node, S
return SyntaxFactory.IdentifierName(expression).WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia());
}

// Handle static fields as a special case
// Handle static members as a special case
if (memberSymbol.IsStatic && (
memberSymbol.Kind == SymbolKind.Field ||
memberSymbol.Kind == SymbolKind.Property))
memberSymbol.Kind == SymbolKind.Property ||
memberSymbol.Kind == SymbolKind.Method))
{
// Get the containing type
string
typeFullname = memberSymbol.ContainingType.ToString(),
assemblyFullname = memberSymbol.ContainingAssembly.ToString();
Type fieldDeclaringType = Type.GetType($"{typeFullname}, {assemblyFullname}");
Type memberDeclaringType = Type.GetType($"{typeFullname}, {assemblyFullname}");

// Retrieve the field or property info
bool isReadonly;
ReadableMember memberInfo;
switch (memberSymbol.Kind)
// Static field or property
if (memberSymbol.Kind == SymbolKind.Field || memberSymbol.Kind == SymbolKind.Property)
{
case SymbolKind.Field:
FieldInfo fieldInfo = fieldDeclaringType.GetField(memberSymbol.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
isReadonly = fieldInfo.IsInitOnly;
memberInfo = fieldInfo;
break;
case SymbolKind.Property:
PropertyInfo propertyInfo = fieldDeclaringType.GetProperty(memberSymbol.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
isReadonly = !propertyInfo.CanWrite;
memberInfo = propertyInfo;
break;
default: throw new InvalidOperationException($"Invalid symbol kind: {memberSymbol.Kind}");
bool isReadonly;
ReadableMember memberInfo;
switch (memberSymbol.Kind)
{
case SymbolKind.Field:
FieldInfo fieldInfo = memberDeclaringType.GetField(memberSymbol.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
isReadonly = fieldInfo.IsInitOnly;
memberInfo = fieldInfo;
break;
case SymbolKind.Property:
PropertyInfo propertyInfo = memberDeclaringType.GetProperty(memberSymbol.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
isReadonly = !propertyInfo.CanWrite;
memberInfo = propertyInfo;
break;
default: throw new InvalidOperationException($"Invalid symbol kind: {memberSymbol.Kind}");
}

// Handle the loaded info
return ProcessStaticMember(node, memberInfo, isReadonly, ref variable);
}

// Handle the loaded info
return ProcessStaticMember(node, memberInfo, isReadonly, ref variable);
// Static method
MethodInfo methodInfo = memberDeclaringType.GetMethod(memberSymbol.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
string name = $"{methodInfo.DeclaringType.Name}_{methodInfo.Name}";
method = (name, methodInfo);

return SyntaxFactory.IdentifierName(name).WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia());
}

return node;
Expand Down
75 changes: 75 additions & 0 deletions src/ComputeSharp.Shaders/Renderer/Models/Functions/FunctionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using ComputeSharp.Shaders.Extensions;

namespace ComputeSharp.Shaders.Renderer.Models.Functions
{
/// <summary>
/// A <see langword="class"/> that contains info on a shader function
/// </summary>
internal class FunctionInfo
{
/// <summary>
/// Gets the return type of the current function in the C# source
/// </summary>
public string FunctionCsharpReturnType { get; }

/// <summary>
/// Gets the fullname of the current function in the C# source
/// </summary>
public string FunctionFullName { get; }

/// <summary>
/// Gets the parameters of the function in the C# source
/// </summary>
public string FunctionCsharpParameters { get; }

/// <summary>
/// Gets the return type of the current function
/// </summary>
public string ReturnType { get; }

/// <summary>
/// Gets the name of the current function
/// </summary>
public string FunctionName { get; }

/// <summary>
/// Gets the list of parameters for the current function
/// </summary>
public IReadOnlyList<ParameterInfo> ParametersList { get; }

/// <summary>
/// Gets the body of the current function
/// </summary>
public string FunctionBody { get; }

/// <summary>
/// Creates a new <see cref="FunctionInfo"/> instance with the specified parameters
/// </summary>
/// <param name="functionCsharpType">The concrete return type for the function</param>
/// <param name="functionFullname">The fullname of the function in the C# source</param>
/// <param name="functionCsharpParameters">The parameters of the function in the C# source</param>
/// <param name="returnType">The return type of the current function</param>
/// <param name="functionName">The name of the current function</param>
/// <param name="parameters">The function parameters, if any</param>
/// <param name="functionBody">The current function</param>
public FunctionInfo(
Type functionCsharpType,
string functionFullname,
string functionCsharpParameters,
string returnType,
string functionName,
IReadOnlyList<ParameterInfo> parameters,
string functionBody)
{
FunctionCsharpReturnType = functionCsharpType.ToFriendlyString();
FunctionFullName = functionFullname;
FunctionCsharpParameters = functionCsharpParameters;
ReturnType = returnType;
FunctionName = functionName;
ParametersList = parameters;
FunctionBody = functionBody;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace ComputeSharp.Shaders.Renderer.Models.Functions
{
/// <summary>
/// A <see langword="class"/> that contains info on a function parameter
/// </summary>
internal class ParameterInfo
{
/// <summary>
/// Gets the modifier to use for the current parameter
/// </summary>
public string ParameterModifier { get; }

/// <summary>
/// Gets the type of the current parameter
/// </summary>
public string ParameterType { get; }

/// <summary>
/// Gets the name to use for the current parameter
/// </summary>
public string ParameterName { get; }

/// <summary>
/// Gets whether or not the current parameter is the last one for the parent function
/// </summary>
public bool IsLastParameter { get; }

/// <summary>
/// Creates a new <see cref="ParameterInfo"/> instance with the specified parameters
/// </summary>
/// <param name="parameterModifiers">The modifiers used in the current parameter</param>
/// <param name="parameterType">The type of the current parameter</param>
/// <param name="parameterName">The name of the current parameter</param>
/// <param name="last">Indicates whether or not the current parameter is the last one</param>
public ParameterInfo(IReadOnlyList<SyntaxToken> parameterModifiers, string parameterType, string parameterName, bool last)
{
if (parameterModifiers.Count == 0) ParameterModifier = "in";
else if (parameterModifiers.First().IsKind(SyntaxKind.OutKeyword)) ParameterModifier = "out";
else if (parameterModifiers.Any(m => m.IsKind(SyntaxKind.RefKeyword)) && !parameterModifiers.Any(m => m.IsKind(SyntaxKind.ReadOnlyKeyword))) ParameterModifier = "inout";
else ParameterModifier = "in";

ParameterType = parameterType;
ParameterName = parameterName;
IsLastParameter = last;
}
}
}
10 changes: 8 additions & 2 deletions src/ComputeSharp.Shaders/Renderer/Models/ShaderInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using ComputeSharp.Shaders.Renderer.Models.Fields;
using ComputeSharp.Shaders.Renderer.Models.Fields.Abstract;
using ComputeSharp.Shaders.Renderer.Models.Functions;

#pragma warning disable CS8618 // Non-nullable field is uninitialized

Expand All @@ -12,12 +13,12 @@ namespace ComputeSharp.Shaders.Renderer.Models
internal sealed class ShaderInfo
{
/// <summary>
/// Gets the list of captured buffers being present in the current shader
/// Gets or sets the list of captured buffers being present in the current shader
/// </summary>
public IReadOnlyList<HlslBufferInfo> BuffersList { get; set; }

/// <summary>
/// Gets the list of captured variables being present in the current shader
/// Gets or sets the list of captured variables being present in the current shader
/// </summary>
public IReadOnlyList<CapturedFieldInfo> FieldsList { get; set; }

Expand Down Expand Up @@ -45,5 +46,10 @@ internal sealed class ShaderInfo
/// Gets or sets the shader body to compile
/// </summary>
public string ShaderBody { get; set; }

/// <summary>
/// Gets or sets the list of static functions used by the shader
/// </summary>
public IReadOnlyList<FunctionInfo> FunctionsList { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ cbuffer _{{FieldName}} : register(b{{BufferIndex}})
{{/IsReadWriteBuffer}}
{{/BuffersList}}

{{!Shader private functions}}
{{#FunctionsList}}
// {{FunctionCsharpReturnType}} {{FunctionFullName}}({{FunctionCsharpParameters}})
{{ReturnType}} {{FunctionName}}({{#ParametersList}}{{ParameterModifier}} {{ParameterType}} {{ParameterName}}{{^IsLastParameter}}, {{/IsLastParameter}}{{/ParametersList}})
{{FunctionBody}}
{{/FunctionsList}}

{{!Shader entry point}}
// Shader body
[Shader("compute")]
Expand Down
3 changes: 2 additions & 1 deletion src/ComputeSharp.Shaders/ShaderRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ public static void Run(
NumThreadsY = threadsY,
NumThreadsZ = threadsZ,
ThreadsIdsVariableName = shaderLoader.ThreadsIdsVariableName,
ShaderBody = shaderLoader.MethodBody
ShaderBody = shaderLoader.MethodBody,
FunctionsList = shaderLoader.FunctionsList
};
string shaderSource = ShaderRenderer.Instance.Render(shaderInfo);

Expand Down
18 changes: 18 additions & 0 deletions src/ComputeSharp.Shaders/Translation/Enums/MethodType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace ComputeSharp.Shaders.Translation.Enums
{
/// <summary>
/// An <see langword="enum"/> that indicates a type of method to decompile
/// </summary>
internal enum MethodType
{
/// <summary>
/// An instance method that belongs to a closure class
/// </summary>
Closure,

/// <summary>
/// A standalone, static method
/// </summary>
Static
}
}
Loading

0 comments on commit a16ca5b

Please sign in to comment.