コード例 #1
0
        private void ReplaceUnnamedMessageScriptConstants()
        {
            foreach (var evaluatedStatement in mEvaluatedStatements)
            {
                var calls = SyntaxNodeCollector <CallOperator> .Collect(evaluatedStatement.Statement);

                if (calls.Any())
                {
                    foreach (var call in calls)
                    {
                        // TODO: Add this meta info to the library function definition somehow
                        if (call.Identifier.Text == "MSG" ||
                            call.Identifier.Text == "SEL" ||
                            call.Identifier.Text == "FLD_SIMPLE_SYS_MSG" ||
                            call.Identifier.Text == "MSG_SYSTEM")
                        {
                            if (call.Arguments[0].Expression is IntLiteral dialogIndex)
                            {
                                call.Arguments[0].Expression = new Identifier(
                                    ValueKind.Int,
                                    mEvaluatedScript.FlowScript.MessageScript.Dialogs[dialogIndex.Value].Name);
                            }
                        }
                    }
                }
            }
        }
コード例 #2
0
        internal static int CountLinesOfCode(SyntaxNode body)
        {
            var nodes = SyntaxNodeCollector <StatementSyntax> .Collect(body);

            var lines = new HashSet <int>();

            CountLinesOfCode(nodes, lines);

            // var all = string.Join(Environment.NewLine, lines.OrderBy(_ => _));

            return(lines.Count);
        }
コード例 #3
0
        private void ApplyMessageScriptConstants()
        {
            foreach (var evaluatedStatement in mEvaluatedStatements)
            {
                var calls = SyntaxNodeCollector <CallOperator> .Collect(evaluatedStatement.Statement);

                if (calls.Any())
                {
                    foreach (var call in calls)
                    {
                        if (call.Identifier.Text == "MSG" || call.Identifier.Text == "SEL")
                        {
                            if (call.Arguments[0].Expression is IntLiteral windowIndexLiteral)
                            {
                                call.Arguments[0].Expression = new Identifier(
                                    ValueKind.Int,
                                    mEvaluatedScript.FlowScript.MessageScript.Dialogs[windowIndexLiteral.Value].Name);
                            }
                        }
                    }
                }
            }
        }
コード例 #4
0
        private void CoagulateVariableDeclarationAssignmentsRecursively(List <EvaluatedStatement> evaluatedStatements, HashSet <string> parentScopeDeclaredVariables)
        {
            if (!evaluatedStatements.Any())
            {
                return;
            }

            int firstIndex = evaluatedStatements.First().InstructionIndex;
            int lastIndex  = evaluatedStatements.Last().InstructionIndex;
            //LogInfo( $"Coagulating variable declarations and assignments: { firstIndex } - { lastIndex }" );

            // Declared variables in the current scope
            var declaredVariables = new HashSet <string>();

            var allIfStatements = mOriginalEvaluatedStatements
                                  .Where(x => x.InstructionIndex >= firstIndex)
                                  .Where(x => x.InstructionIndex <= lastIndex)
                                  .Where(x => x.Statement is IfStatement)
                                  .ToList();

            // All referenced variable identifiers in statements, and if statements
            var referencedLocalVariableIdentifiers =
                mEvaluatedProcedure.ReferencedVariables
                .Where(x => x.InstructionIndex >= firstIndex && x.InstructionIndex <= lastIndex)
                .GroupBy(x => x.Identifier.Text);

            foreach (var referencedLocalVariableIdentifier in referencedLocalVariableIdentifiers)
            {
                var identifierText = referencedLocalVariableIdentifier.Key;
                int firstReferenceInstructionIndex = referencedLocalVariableIdentifier.Min(x => x.InstructionIndex);

                // Check if the variable was declared in either the scope of the parent or the current scope
                if (parentScopeDeclaredVariables.Contains(identifierText) ||
                    declaredVariables.Contains(identifierText) ||
                    !mEvaluatedProcedure.Scope.Variables.TryGetValue(identifierText, out var declaration))
                {
                    continue;
                }

                // Variable hasn't already been declared
                // Find the index of the statement
                int        evaluatedStatementIndex         = evaluatedStatements.FindIndex(x => x.InstructionIndex == firstReferenceInstructionIndex);
                Expression initializer                     = null;
                bool       shouldDeclareBeforeIfStatements = false;
                bool       accessedLaterInBody             = referencedLocalVariableIdentifier.Any(x => evaluatedStatements.Any(y => y.InstructionIndex == x.InstructionIndex));

                // Hack: Edge case - variable was assigned a non existent value
                // This causes the assignment to not exist in the AST
                // So just insert the assignment before the first reference
                if (evaluatedStatementIndex == -1 &&
                    evaluatedStatements.Any(x => x.InstructionIndex == firstReferenceInstructionIndex - 1) && evaluatedStatements.Any(x => x.InstructionIndex == firstReferenceInstructionIndex + 1))
                {
                    evaluatedStatementIndex = evaluatedStatements.FindIndex(x => x.InstructionIndex == firstReferenceInstructionIndex - 1);
                }

                if (evaluatedStatementIndex == -1 && !mConvertIfStatementsToGotos)
                {
                    // Referenced first in one of the if statements

                    // But maybe it's accessed later in the body?
                    bool accessedInIfStatementOnce = false;
                    var  curIfStatements           = allIfStatements;

                    foreach (var ifStatement in allIfStatements)
                    {
                        // Check condition
                        var conditionIdentifiers = SyntaxNodeCollector <Identifier> .Collect((( IfStatement )ifStatement.Statement).Condition);

                        if (conditionIdentifiers.Any(x => x.Text == referencedLocalVariableIdentifier.Key))
                        {
                            // Really Good Code
                            shouldDeclareBeforeIfStatements = true;
                            break;
                        }

                        // Check if any of instructions in the if body map to any of the instruction indices of the references
                        var body            = mIfStatementBodyMap[ifStatement.InstructionIndex];
                        var bodyIdentifiers = body.SelectMany(x => SyntaxNodeCollector <Identifier> .Collect(x.Statement));
                        if (bodyIdentifiers.Any(x => x.Text == referencedLocalVariableIdentifier.Key))
                        {
                            if (!accessedInIfStatementOnce)
                            {
                                accessedInIfStatementOnce = true;
                                if (accessedLaterInBody)
                                {
                                    shouldDeclareBeforeIfStatements = true;
                                }
                            }
                            else
                            {
                                shouldDeclareBeforeIfStatements = true;
                                break;
                            }
                        }

                        // Same for else body
                        if (mIfStatementElseBodyMap.TryGetValue(ifStatement.InstructionIndex, out var elseBody))
                        {
                            // Check if any of instructions in the if else body map to any of the instruction indices of the references
                            var elseBodyIdentifiers = body.SelectMany(x => SyntaxNodeCollector <Identifier> .Collect(x.Statement));
                            if (elseBodyIdentifiers.Any(x => x.Text == referencedLocalVariableIdentifier.Key))
                            {
                                if (!accessedInIfStatementOnce)
                                {
                                    accessedInIfStatementOnce = true;
                                    if (accessedLaterInBody)
                                    {
                                        shouldDeclareBeforeIfStatements = true;
                                    }
                                }
                                else
                                {
                                    shouldDeclareBeforeIfStatements = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                else
                {
                    var evaluatedStatement = evaluatedStatements[evaluatedStatementIndex];

                    // Check if the statement is an assignment expression
                    // Which would mean we have an initializer
                    if (evaluatedStatement.Statement is AssignmentOperator assignment)
                    {
                        // Only match initializers if the target of the operator
                        // Is actually the same identifier
                        if (((Identifier)assignment.Left).Text == identifierText)
                        {
                            initializer = assignment.Right;
                        }
                    }
                }

                if ((evaluatedStatementIndex != -1 || shouldDeclareBeforeIfStatements) && !mConvertIfStatementsToGotos)
                {
                    // Find the best insertion index
                    int insertionIndex;
                    if (evaluatedStatementIndex != -1)
                    {
                        insertionIndex = evaluatedStatementIndex;
                    }
                    else
                    {
                        insertionIndex = evaluatedStatements.IndexOf(allIfStatements.First());
                    }

                    int instructionIndex = firstReferenceInstructionIndex;

                    // Check if the variable has been referenced before in an if statement
                    foreach (var evaluatedIfStatement in allIfStatements.Where(x => x.InstructionIndex <= firstReferenceInstructionIndex))
                    {
                        var ifStatementBody = mIfStatementBodyMap[evaluatedIfStatement.InstructionIndex];
                        var referencedLocalVariableIdentifiersInIfStatementBody =
                            mEvaluatedProcedure.ReferencedVariables.Where(
                                x => ifStatementBody.Any(y => x.InstructionIndex == y.InstructionIndex));

                        if (referencedLocalVariableIdentifiersInIfStatementBody.Any(
                                x => x.Identifier.Text == identifierText))
                        {
                            // The variable was referenced in a previous if statement, so we should insert it before the start of the if statement
                            insertionIndex   = evaluatedStatements.IndexOf(evaluatedIfStatement);
                            instructionIndex = evaluatedIfStatement.InstructionIndex - 1;

                            // Edge case
                            if (instructionIndex < 0)
                            {
                                instructionIndex = 0;
                            }

                            break;
                        }

                        if (mIfStatementElseBodyMap.TryGetValue(evaluatedIfStatement.InstructionIndex,
                                                                out var ifStatementElseBody))
                        {
                            var referencedLocalVariableIdentifiersInIfStatementElseBody =
                                mEvaluatedProcedure.ReferencedVariables.Where(
                                    x => ifStatementElseBody.Any(y => x.InstructionIndex == y.InstructionIndex));

                            if (referencedLocalVariableIdentifiersInIfStatementElseBody.Any(
                                    x => x.Identifier.Text == identifierText))
                            {
                                // The variable was referenced in a previous if statement, so we should insert it before the start of the if statement
                                insertionIndex   = evaluatedStatements.IndexOf(evaluatedIfStatement);
                                instructionIndex = evaluatedIfStatement.InstructionIndex - 1;

                                // Edge case
                                if (instructionIndex < 0)
                                {
                                    instructionIndex = 0;
                                }

                                break;
                            }
                        }
                    }

                    if (insertionIndex == -1)
                    {
                        // Variable was referenced in both the body and in a nested if statement
                        if (evaluatedStatements.Any(x => x.Statement is IfStatement))
                        {
                            insertionIndex = evaluatedStatements.IndexOf(evaluatedStatements.First(x => x.Statement is IfStatement));
                        }
                        else
                        {
                            insertionIndex = 0;
                        }
                    }

                    if (insertionIndex != evaluatedStatementIndex)
                    {
                        // If the insertion index isn't equal to the evaluated statement index
                        // Then that means it was previously referenced in the body of an if statement
                        // So we insert declaration before if statement in which it was used

                        // Just to be safe
                        declaration.Initializer = new IntLiteral(0);

                        evaluatedStatements.Insert(insertionIndex,
                                                   new EvaluatedStatement(declaration, instructionIndex, null));
                    }
                    else
                    {
                        // If the insertion index is still the same, then that means we probably have a declaration with an assignment
                        // Or maybe we have a reference to an undeclared variable!

                        if (initializer == null)
                        {
                            // Reference to undeclared variable
                            LogInfo($"Reference to uninitialized variable! Adding 0 initializer: {declaration}");
                            initializer = new IntLiteral(0);
                        }

                        // Coagulate assignment with declaration
                        declaration.Initializer = initializer;
                        evaluatedStatements[evaluatedStatementIndex] = new EvaluatedStatement(
                            declaration, instructionIndex, null);
                    }

                    declaredVariables.Add(identifierText);
                }
            }

            // Merge parent scope with local scope
            foreach (string declaredVariable in parentScopeDeclaredVariables)
            {
                declaredVariables.Add(declaredVariable);
            }

            if (!mConvertIfStatementsToGotos)
            {
                var ifStatementsInScope = evaluatedStatements
                                          .Where(x => x.Statement is IfStatement);

                foreach (var ifStatement in ifStatementsInScope)
                {
                    // Do the same for each if statement
                    var body = mIfStatementBodyMap[ifStatement.InstructionIndex];
                    CoagulateVariableDeclarationAssignmentsRecursively(body, declaredVariables);

                    if (mIfStatementElseBodyMap.TryGetValue(ifStatement.InstructionIndex, out var elseBody))
                    {
                        CoagulateVariableDeclarationAssignmentsRecursively(elseBody, declaredVariables);
                    }
                }
            }
        }
コード例 #5
0
        private void InsertFunctionCallEnumParameterValues()
        {
            foreach (var evaluatedStatement in mEvaluatedStatements)
            {
                var calls = SyntaxNodeCollector <CallOperator> .Collect(evaluatedStatement.Statement);

                foreach (var call in calls)
                {
                    var libraryFunctions = Library.FlowScriptModules
                                           .SelectMany(x => x.Functions)
                                           .Where(x => x.Name == call.Identifier.Text)
                                           .ToList();

                    if (libraryFunctions.Count == 0)
                    {
                        continue;
                    }

                    if (libraryFunctions.Count != 1)
                    {
                        LogError($"More than one library function defined with the name '{call.Identifier.Text}' exit; using first definition...");
                    }

                    var libraryFunction = libraryFunctions[0];

                    for (var i = 0; i < libraryFunction.Parameters.Count; i++)
                    {
                        var        parameter = libraryFunction.Parameters[i];
                        Expression argument;

                        if (i < call.Arguments.Count)
                        {
                            argument = call.Arguments[i].Expression;
                        }
                        else
                        {
                            LogError($"Missing argument {i} for call expression: {call}");
                            continue;
                        }

                        if (!(argument is IntLiteral argumentValue))
                        {
                            continue;
                        }

                        var libraryEnum = Library.FlowScriptModules
                                          .Where(x => x.Enums != null)
                                          .SelectMany(x => x.Enums)
                                          .FirstOrDefault(x => x.Name == parameter.Type);

                        if (libraryEnum == null)
                        {
                            continue;
                        }

                        var libraryEnumMember = libraryEnum.Members.FirstOrDefault(x => x.Value == argumentValue.Value.ToString());
                        if (libraryEnumMember == null)
                        {
                            continue;
                        }

                        call.Arguments[i].Expression = new MemberAccessExpression
                        {
                            Operand = new TypeIdentifier(libraryEnum.Name),
                            Member  = new Identifier(libraryEnumMember.Name)
                        };
                    }
                }
            }
        }
コード例 #6
0
        public static int CountCyclomaticComplexity(BlockSyntax body)
        {
            var count = SyntaxNodeCollector <SyntaxNode> .Collect(body).Count(_ => CCSyntaxKinds.Any(_.IsKind));

            return(1 + count);
        }