Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
4d764e615This file is pinned to the selected release. Download the original to open it in your design tool.
using Hast.Common.Services;
using Hast.Layer;
using Hast.Transformer.Helpers;
using Hast.Transformer.Models;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem;
using System.Collections.Generic;
namespace Hast.Transformer.Services;
/// <summary>
/// Searches for assignment expressions embedded in other expressions and brings them up to their own statements,
/// allowing easier processing later.
/// </summary>
/// <example>
/// <code>
/// if (skipCount = skipCount - 1u <= 0u)
/// {
/// ...
///
/// ...will be converted into:
/// uint assignment;
/// assignment = skipCount - 1u;
/// skipCount = assignment;
/// if (assignment <= 0u)
/// {
/// ...
/// </code>
/// </example>
/// <remarks>
/// <para>
/// The MakeAssignmentExpressions configuration of <see cref="ICSharpCode.Decompiler.DecompilerSettings"/> serves
/// something similar but that also changes how a decompiled Task.Factory.StartNew() looks like.
/// </para>
/// </remarks>
public class EmbeddedAssignmentExpressionsExpander : IConverter
{
private readonly IHashProvider _hashProvider;
public IEnumerable<string> Dependencies { get; } = new[] { nameof(ObjectInitializerExpander) };
public EmbeddedAssignmentExpressionsExpander(IHashProvider hashProvider) => _hashProvider = hashProvider;
public void Convert(
SyntaxTree syntaxTree,
IHardwareGenerationConfiguration configuration,
IKnownTypeLookupTable knownTypeLookupTable) =>
syntaxTree.AcceptVisitor(new EmbeddedAssignmentExpressionsExpandingVisitor(_hashProvider));
private sealed class EmbeddedAssignmentExpressionsExpandingVisitor : DepthFirstAstVisitor
{
private readonly IHashProvider _hashProvider;
public EmbeddedAssignmentExpressionsExpandingVisitor(IHashProvider hashProvider) => _hashProvider = hashProvider;
public override void VisitAssignmentExpression(AssignmentExpression assignmentExpression)
{
base.VisitAssignmentExpression(assignmentExpression);
var type = assignmentExpression.GetActualType();
if (assignmentExpression.Parent is Statement ||
assignmentExpression.Parent is Attribute ||
// This is a DisplayClass-related if, those are handled specially later on.
type.IsFunc())
{
return;
}
// Saving the right side of the assignment to a variable and then using that instead of the original
// embedded assignment. Not using the left side directly later because that can be any complex value access,
// keeping it simple.
var variableIdentifier = VariableHelper.DeclareAndReferenceVariable(
"assignment",
assignmentExpression,
TypeHelper.CreateAstType(type),
_hashProvider);
var firstParentStatement = assignmentExpression.FindFirstParentStatement();
var resolveResult = assignmentExpression.CreateResolveResultFromActualType();
var tempVariableAssignment = new AssignmentExpression(variableIdentifier, assignmentExpression.Right.Clone())
.WithAnnotation(resolveResult);
AstInsertionHelper.InsertStatementBefore(firstParentStatement, new ExpressionStatement(tempVariableAssignment));
var leftAssignment = new AssignmentExpression(assignmentExpression.Left.Clone(), variableIdentifier.Clone())
.WithAnnotation(resolveResult);
AstInsertionHelper.InsertStatementBefore(firstParentStatement, new ExpressionStatement(leftAssignment));
assignmentExpression.ReplaceWith(variableIdentifier.Clone());
}
}
}