Roslyn C # перестроить неверное выражение для оператора for for - PullRequest
0 голосов
/ 19 ноября 2018

У меня проблема с перестроением для утверждения. Я хочу восстановить фрагмент кода:

FOR(j, variable or integer, integer, > or < or <= or >=, - or +);

до

for(var j = variable or integer; j > or < or >= or <= 15; j-- or j++){}

Например FOR(j, k, >, -); -> for(var j = k; j > 15; j--){}. Кроме того, я не знаю, как можно разделить элементы в списке от <ArgumentListSyntax> до IdentifierNameSyntax или LiteralExpressionSyntax, когда в списке будет два IdentifierNameSyntax или LiteralExpressionSyntax. Поэтому я не знаю, верна ли моя попытка решить.

public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
{
    // FOR(j, k, 10, >, -);

    if (node.Kind() == SyntaxKind.InvocationExpression)
    {
        InvocationExpressionSyntax invocationExpression = node;

        if (invocationExpression.GetFirstToken().ToString() == "FOR")
        {
            //List<ArgumentSyntax> argumentList = new List<ArgumentSyntax>();
            //List<IdentifierNameSyntax> test = new List<IdentifierNameSyntax>();
            var tmp = node.ChildNodes().OfType<ArgumentListSyntax>().FirstOrDefault();
            var tmp1 = tmp.ChildNodes().OfType<ArgumentSyntax>().FirstOrDefault();
            var tmp2 = tmp1.ChildNodes().OfType<IdentifierNameSyntax>().FirstOrDefault();
            var tmp3 = tmp.Arguments.ElementAt(1);
            var tmp4 = tmp3.ChildNodes().OfType<IdentifierNameSyntax>().FirstOrDefault();

            Console.WriteLine(tmp.Arguments.ElementAt(0));
            Console.WriteLine(tmp.Arguments);
            Console.WriteLine(tmp2.GetFirstToken());
            Console.WriteLine(tmp4);


            node = node.ReplaceNode(node, SyntaxFactory.ForStatement(SyntaxKind.ForKeyword, SyntaxKind.OpenParenToken,
                                    SyntaxFactory.VariableDeclaration(SyntaxFactory.IdentifierName("var"), )));
        }

    }
    return base.VisitInvocationExpression(node);
}

1 Ответ

0 голосов
/ 23 ноября 2018

Вам не нужно разделять элементы в ArgumentListSyntax на литералы или идентификаторы, потому что у вас фактически есть формальная структура поддержки вызова: FOR(j, variable|integer, variable|integer, >|<|<=|>=, -|+);, поэтому вы предполагаете, что второй и третий аргументы могут быть литералами или идентификаторами.четвертый элемент сравнения и так далее.Поэтому вам нужно проверить, что входные аргументы удовлетворяют этим условиям, и если они выполнимы, сделайте что-нибудь полезное:

...
// FOR(j, variable | integer, variable | integer, > | < | <= | >=, - | +);
if (node.Expression is IdentifierNameSyntax identifier && identifier.Identifier.ValueText.Equals("FOR"))
{
    var arguments = node.ArgumentList.Arguments;
    if (arguments.Count != 5) return node;
    var second = arguments[1].Expression;
    switch (second)
    {
        case IdentifierNameSyntax variable:
            // and some sepcific logic for identifier
            break;

        case LiteralExpressionSyntax literal when literal.Kind() == SyntaxKind.NumericLiteralExpression:
            // and some sepcific logic for literals and check, 
            // that the input literal is integer and is not rational value
            break;

        default:
            // current argument isn't literal or identifier you can not do anything
            return node;
    }

    // do the similar check for the other arguments
    // and replace node as you wish
    ...
}

Если вы все еще предполагаете, что ваш вызов может содержать пару других узлов в качестве аргументов, например for(j, "foo", "foo", method(), initValue, method(), 15, >, >, >, -, "foo") вам нужно будет принимать аргументы по другой логике, например, взять первый литерал или идентификатор или что-то еще:

...
    // the same code from the example above

    // here you can use an another logic to retrieve expression that you want
    var second = arguments.First(x => x.IsKind(SyntaxKind.NumericLiteralExpression) || x.IsKind(SyntaxKind.IdentifierName)).Expression; 
    switch (second)
    {
        // the same code from the example above
    }
    // the same code from the example above

    ...
}
...