// ToDo: Remove workaround; use executed lines in PythonStatementSemantic public Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> > EvaluateAndTraceProgram(PythonProcess pythonProcess, string program, string input, string output, IEnumerable <int> indices, string header, string footer, ISymbolicExpressionTree tree, double timeout = 1) { string traceProgram = traceCodeWithVariables + program; traceProgram += traceCodeWithVariables == String.Empty ? String.Empty : traceTableReduceEntries; EvaluationScript es = pythonProcess.CreateEvaluationScript(traceProgram, input, output, timeout); es.Variables.Add("traceTable"); es.Variables.Add("traceTableBefore"); es.Variables.Add("executedLines"); JObject json = pythonProcess.SendAndEvaluateProgram(es); var baseResult = pythonProcess.GetVariablesFromJson(json, indices.Count()); if (json["traceTable"] == null) { return(new Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> >(baseResult.Item1, baseResult.Item2, baseResult.Item3, baseResult.Item4, new List <PythonStatementSemantic>())); } var traceTable = json["traceTable"].ToObject <IDictionary <int, IDictionary <string, IList> > >(); var traceTableBefore = json["traceTableBefore"].ToObject <IDictionary <int, IDictionary <string, IList> > >(); var executedLines = json["executedLines"].ToObject <IDictionary <int, List <int> > >(); List <PythonStatementSemantic> semantics = new List <PythonStatementSemantic>(); ISymbolicExpressionTreeNode root = tree.Root; var statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(root.Grammar); // calculate the correct line the semantic evaluation starts from var code = CFGSymbolicExpressionTreeStringFormatter.StaticFormat(tree); int curline = es.Script.Count(c => c == '\n') - code.Count(c => c == '\n') - footer.Count(c => c == '\n') - traceTableReduceEntries.Count(c => c == '\n'); var symbolToLineDict = FindStatementSymbolsInTree(root, statementProductionNames, ref curline); #region workaround: empty line problem with while, can't fix, otherwise FindStatementSymbolsInTree won't work string[] sciptLines = es.Script.Split('\n'); var beginLineNumbers = symbolToLineDict.Values.Select(x => x[0]).Distinct().ToList(); var moveLines = new Dictionary <int, int>(beginLineNumbers.Count); foreach (var l in beginLineNumbers) { // decrease by one, as sciptLines is an array and start from zero, where lineNumbers started counting from 1 if (String.IsNullOrWhiteSpace(sciptLines[l - 1]) || sciptLines[l - 1].TrimStart().StartsWith("#")) { // empty line or comment var i = l + 1; while (i - 1 < sciptLines.Length && (String.IsNullOrWhiteSpace(sciptLines[i - 1]) || sciptLines[i - 1].TrimStart().StartsWith("#"))) { i++; } moveLines.Add(l, i); } else { moveLines.Add(l, l); } } foreach (var symbolLine in symbolToLineDict) { symbolLine.Value[0] = moveLines[symbolLine.Value[0]]; } #endregion #region fix Before line for <predefined> to have all variables initialised // not a great way to do it, but the python interpreter does not stop at e.g. 'while False:' int newMinBefore = traceTableBefore.OrderBy(x => x.Key).First(x => x.Value.ContainsKey("res0") && !x.Value["res0"].Contains(null)).Key; // first line that changes res0 foreach (var symbolToLine in symbolToLineDict) { symbolToLine.Value.Add(symbolToLine.Value[0]); // original beginning at [2], which is needed for executed lines if (symbolToLine.Value[0] < newMinBefore) { symbolToLine.Value[0] = newMinBefore; } } #endregion var prefixTreeNodes = tree.IterateNodesPrefix().ToList(); foreach (var symbolLine in symbolToLineDict) { // Before Dictionary <string, IList> before = new Dictionary <string, IList>(); foreach (var traceChange in traceTableBefore.Where(x => x.Key <= symbolLine.Value[0]).OrderByDescending(x => x.Key)) { foreach (var variableChange in traceChange.Value) { if (!before.ContainsKey(variableChange.Key)) { before.Add(variableChange.Key, variableChange.Value); } } } // After Dictionary <string, IList> after = new Dictionary <string, IList>(); foreach (var traceChange in traceTable.Where(x => x.Key >= symbolLine.Value[0] && x.Key <= symbolLine.Value[1]).OrderByDescending(x => x.Key)) { foreach (var variableChange in traceChange.Value) { if (!after.ContainsKey(variableChange.Key)) { after.Add(variableChange.Key, variableChange.Value); } } } // clean after with before foreach (var key in after.Keys.ToList()) { if (PythonSemanticComparer.CompareSequence(after[key], before[key])) { after.Remove(key); } } // add semantics var executedLinesWithinStatement = executedLines.Where(x => x.Key >= symbolLine.Value[2] && x.Key <= symbolLine.Value[1]); semantics.Add(new PythonStatementSemantic() { TreeNodePrefixPos = prefixTreeNodes.IndexOf(symbolLine.Key), ExecutedCases = executedLinesWithinStatement.Any() ? executedLinesWithinStatement.OrderByDescending(x => x.Value.Count).First().Value : new List <int>(), Before = before, After = after, }); } return(new Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> >(baseResult.Item1, baseResult.Item2, baseResult.Item3, baseResult.Item4, semantics)); }
public Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> > EvaluateAndTraceProgram(PythonProcess pythonProcess, string program, string input, string output, IEnumerable <int> indices, string header, string footer, ISymbolicExpressionTree tree, double timeout = 1) { string traceProgram = traceCodeWithVariables + program; traceProgram += traceCodeWithVariables == String.Empty ? String.Empty : traceTableReduceEntries; EvaluationScript es = pythonProcess.CreateEvaluationScript(traceProgram, input, output, timeout); es.Variables.Add("traceTable"); es.Variables.Add("traceTableBefore"); es.Variables.Add("executedLines"); JObject json = pythonProcess.SendAndEvaluateProgram(es); var baseResult = pythonProcess.GetVariablesFromJson(json, indices.Count()); if (json["traceTable"] == null || json["traceTableBefore"] == null) { return(new Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> >(baseResult.Item1, baseResult.Item2, baseResult.Item3, baseResult.Item4, new List <PythonStatementSemantic>())); } var traceTable = JsonConvert.DeserializeObject <IDictionary <int, IDictionary <string, IList> > >(json["traceTable"].ToString()); var traceTableBefore = JsonConvert.DeserializeObject <IDictionary <int, IDictionary <string, IList> > >(json["traceTableBefore"].ToString()); var executedLinesNew = JsonConvert.DeserializeObject <IDictionary <int, List <int> > >(json["executedLines"].ToString()); var executedLines = executedLinesNew.Keys.ToList(); executedLines.Sort(); IList <int> traceChanges = traceTable.Keys.OrderBy(x => x).ToList(); IList <int> traceBeforeChanges = traceTableBefore.Keys.OrderBy(x => x).ToList(); List <PythonStatementSemantic> semantics = new List <PythonStatementSemantic>(); ISymbolicExpressionTreeNode root = tree.Root; var statementProductionNames = SemanticOperatorHelper.GetSemanticProductionNames(root.Grammar); // calculate the correct line the semantic evaluation starts from var code = CFGSymbolicExpressionTreeStringFormatter.StaticFormat(tree); int curline = es.Script.Count(c => c == '\n') - code.Count(c => c == '\n') - footer.Count(c => c == '\n') - traceTableReduceEntries.Count(c => c == '\n'); var symbolToLineDict = FindStatementSymbolsInTree(root, statementProductionNames, ref curline); var prefixTreeNodes = tree.IterateNodesPrefix().ToList(); foreach (var symbolLine in symbolToLineDict) { // Before Dictionary <string, IList> before = new Dictionary <string, IList>(); foreach (var traceChange in traceTableBefore.Where(x => x.Key <= symbolLine.Value[0]).OrderByDescending(x => x.Key)) { foreach (var variableChange in traceChange.Value) { if (!before.ContainsKey(variableChange.Key)) { before.Add(variableChange.Key, variableChange.Value); } } } // After Dictionary <string, IList> after = new Dictionary <string, IList>(); foreach (var traceChange in traceTable.Where(x => x.Key >= symbolLine.Value[0] && x.Key <= symbolLine.Value[1]).OrderByDescending(x => x.Key)) { foreach (var variableChange in traceChange.Value) { if (!after.ContainsKey(variableChange.Key)) { after.Add(variableChange.Key, variableChange.Value); } } } // clean after with before foreach (var key in after.Keys.ToList()) { if (CompareSequence(after[key], before[key])) { after.Remove(key); } } semantics.Add(new PythonStatementSemantic() { TreeNodePrefixPos = prefixTreeNodes.IndexOf(symbolLine.Key), Before = before, After = after, }); } return(new Tuple <IEnumerable <bool>, IEnumerable <double>, double, string, List <PythonStatementSemantic> >(baseResult.Item1, baseResult.Item2, baseResult.Item3, baseResult.Item4, semantics)); }