Skip to content

Commit

Permalink
wip: support for element access through ranges (i.e, convert to span …
Browse files Browse the repository at this point in the history
…and slice)
  • Loading branch information
adrianoc-unity3d authored and adrianoc committed Mar 29, 2024
1 parent f3c547a commit be70ada
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@
using Cecilifier.Core.Extensions;
using Cecilifier.Core.Mappings;
using Cecilifier.Core.Misc;
using Cecilifier.Core.Variables;
using Mono.Cecil.Cil;

namespace Cecilifier.Core.AST;

internal class ElementAccessExpressionWithRangeArgumentVisitor : SyntaxWalkerBase
{
internal ElementAccessExpressionWithRangeArgumentVisitor(IVisitorContext context, string ilVar, ExpressionVisitor expressionVisitor) : base(context)
internal ElementAccessExpressionWithRangeArgumentVisitor(IVisitorContext context, string ilVar, ExpressionVisitor expressionVisitor, bool targetAlreadyLoaded = false) : base(context)
{
_expressionVisitor = expressionVisitor;
_targetAlreadyLoaded = targetAlreadyLoaded;
_ilVar = ilVar;
}

public override void VisitElementAccessExpression(ElementAccessExpressionSyntax node)
{
using var _ = LineInformationTracker.Track(Context, node);
node.Expression.Accept(_expressionVisitor);
if (!_targetAlreadyLoaded)
node.Expression.Accept(_expressionVisitor);

var elementAccessExpressionType = Context.SemanticModel.GetTypeInfo(node.Expression).Type.EnsureNotNull();
var elementAccessExpressionType = Context.SemanticModel.GetTypeInfo(node).Type.EnsureNotNull();
_targetSpanType = elementAccessExpressionType;
_spanCopyVariable = CodeGenerationHelpers.StoreTopOfStackInLocalVariable(Context, _ilVar, "localSpanCopy", elementAccessExpressionType).VariableName;
Context.EmitCilInstruction(_ilVar, OpCodes.Ldloca, _spanCopyVariable);
Expand Down Expand Up @@ -113,6 +114,7 @@ private void ProcessIndexerExpressionWithRangeAsArgument(ExpressionSyntax node)
}

private readonly ExpressionVisitor _expressionVisitor;
private readonly bool _targetAlreadyLoaded;
private string _spanCopyVariable;
private readonly string _ilVar;
private ITypeSymbol _targetSpanType; // Span<T> in which indexer is being invoked
Expand Down
6 changes: 5 additions & 1 deletion Cecilifier.Core/AST/ExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,11 @@ public override void VisitElementAccessExpression(ElementAccessExpressionSyntax
return;
}

if (InlineArrayProcessor.TryHandleIntIndexElementAccess(Context, ilVar, node, out var elementType))
if (InlineArrayProcessor.TryHandleRangeElementAccess(Context, this, ilVar, node, out var elementType1))
{
return;
}
else if (InlineArrayProcessor.TryHandleIntIndexElementAccess(Context, ilVar, node, out var elementType))
{
// if the parent of the element access expression is a member access expression the code
// that handles that expects that the target instance is at the top of the stack so; in
Expand Down
24 changes: 24 additions & 0 deletions Cecilifier.Core/AST/InlineArrayProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal static bool HandleInlineArrayConversionToSpan(IVisitorContext context,
return false;

if (!IsNodeUsedToInitializeSpanLocalVariable(context, fromNode)
&& !fromNode.IsUsedAsReturnValueOfType(context.SemanticModel)
&& !IsNodeAssignedToLocalVariable(context, fromNode)
&& !IsNodeUsedAsSpanArgument(context, fromNode))
return false;
Expand Down Expand Up @@ -76,6 +77,29 @@ static string InlineArrayAsSpanMethodFor(IVisitorContext context, ITypeSymbol in
inlineArrayType);
}
}

internal static bool TryHandleRangeElementAccess(IVisitorContext context, ExpressionVisitor expressionVisitor, string ilVar, ElementAccessExpressionSyntax elementAccess, out ITypeSymbol elementType)
{
elementType = null;
if (elementAccess.Expression.IsKind(SyntaxKind.ElementAccessExpression))
return false;

var storageSymbol = context.SemanticModel.GetSymbolInfo(elementAccess.Expression).Symbol;
var inlineArrayType = storageSymbol.EnsureNotNull().GetMemberType();
if (!inlineArrayType.TryGetAttribute<InlineArrayAttribute>(out _))
return false;

if (elementAccess.ArgumentList.Arguments.Count == 1 && SymbolEqualityComparer.Default.Equals(context.GetTypeInfo(elementAccess.ArgumentList.Arguments[0].Expression).Type, context.RoslynTypeSystem.SystemRange))
{
var k = storageSymbol.ToVariableMemberKind();
var xx = k == VariableMemberKind.LocalVariable ? string.Empty : storageSymbol.ContainingSymbol.ToDisplayString();
HandleInlineArrayConversionToSpan(context, ilVar, inlineArrayType, elementAccess, storageSymbol.LoadAddressOpcodeForMember(), elementAccess.Expression.ToString(), k, xx);
elementAccess.Accept(new ElementAccessExpressionWithRangeArgumentVisitor(context, ilVar, expressionVisitor, targetAlreadyLoaded: true));
return true;
}

return false;
}

internal static bool TryHandleIntIndexElementAccess(IVisitorContext context, string ilVar, ElementAccessExpressionSyntax elementAccess, out ITypeSymbol elementType)
{
Expand Down
14 changes: 14 additions & 0 deletions Cecilifier.Core/Extensions/SyntaxNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,19 @@ internal static bool TryGetLiteralValueFor<T>(this ExpressionSyntax expressionSy
value = (T) literalExpression.Token.Value;
return true;
}

internal static bool IsUsedAsReturnValueOfType(this SyntaxNode self, SemanticModel semanticModel)
{
if (self.Parent == null)
return false;

if (self.Parent.IsKind(SyntaxKind.ReturnStatement) || self.Parent.IsKind(SyntaxKind.ArrowExpressionClause))
{
var type = semanticModel.GetTypeInfo(self.Parent).Type;
return true;
}

return false;
}
}
}

0 comments on commit be70ada

Please sign in to comment.