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); } } } } } }
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); }
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); } } } } } }
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); } } } }
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) }; } } } }
public static int CountCyclomaticComplexity(BlockSyntax body) { var count = SyntaxNodeCollector <SyntaxNode> .Collect(body).Count(_ => CCSyntaxKinds.Any(_.IsKind)); return(1 + count); }