UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

168 lines 9.95 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.postProcess = postProcess; const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const defined_functions_1 = require("./defined-functions"); const post_processing_1 = require("../../post-processing"); const summarizer_1 = require("../../../../util/summarizer"); const files_1 = require("../../../../util/files"); const time_1 = require("../../../../util/text/time"); const arrays_1 = require("../../../../util/collections/arrays"); function getFnDefCsv(idx, info) { return `${JSON.stringify(idx)},${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.total.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.parameters.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.length.lines.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.length.chars.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.length.nonWhitespaceChars.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)([0]))}` /* this has to be changed once we have explicit returns again */ + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)([0]))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.returns.onlyExplicit.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.returns.onlyImplicit.flat()))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.exitPointsLinePercentageInDef.flat(2)))}` + `,${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(info.linePercentageInFile.flat()))}\n`; } function addToList(data, count, filepath, config) { data.count.push(count); if (count > 0) { (0, post_processing_1.recordFilePath)(data, filepath, config); } } function retrievePerFileDefinitionInformation(featureRoot, info, config, outputPath) { /** * maps fn-name (including namespace) to several definition information * we use tuples to reduce the memory! */ const definitionsPerFile = []; const mergedSuperDefinitions = emptyFunctionDefinitionSummary(); // we collect only `all-calls` (0, files_1.readLineByLineSync)(path_1.default.join(featureRoot, `${defined_functions_1.AllDefinitionsFileBase}.txt`), (line, lineNumber) => processNextLine(definitionsPerFile, lineNumber, info, JSON.parse(String(line)))); console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions process completed, start to write out function info`); const fnOutStream = fs_1.default.createWriteStream(path_1.default.join(outputPath, 'function-definitions.csv')); const prefixes = ['total', 'params', 'length-lines', 'length-chars', 'length-non-ws-chars', 'return-explicit', 'return-implicit', 'return-only-explicit', 'return-only-implicit', 'exit-points-line-crac', 'def-line-frac']; const others = prefixes.flatMap(summarizer_1.summarizedMeasurement2CsvHeader).join(','); fnOutStream.write(`counter,${others}\n`); for (const [idx, info] of definitionsPerFile.entries()) { fnOutStream.write(getFnDefCsv(idx, info)); mergedSuperDefinitions.total.push(...info.total); mergedSuperDefinitions.parameters.push(...info.parameters); mergedSuperDefinitions.length.lines.push(...info.length.lines); mergedSuperDefinitions.length.chars.push(...info.length.chars); mergedSuperDefinitions.length.nonWhitespaceChars.push(...info.length.nonWhitespaceChars); mergedSuperDefinitions.returns.onlyExplicit.push(...info.returns.onlyExplicit); mergedSuperDefinitions.returns.onlyImplicit.push(...info.returns.onlyImplicit); mergedSuperDefinitions.exitPointsLinePercentageInDef.push(...info.exitPointsLinePercentageInDef); mergedSuperDefinitions.linePercentageInFile.push(...info.linePercentageInFile); mergedSuperDefinitions.callsites.push(...info.callsites); } // now, write the ultimate summary at the end of the file fnOutStream.write(getFnDefCsv('all', mergedSuperDefinitions)); fnOutStream.close(); } function retrieveMetaInformation(info, config, outputPath) { const data = { total: (0, post_processing_1.emptySummarizedWithProject)(), lambdasOnly: (0, post_processing_1.emptySummarizedWithProject)(), assignedFunctions: (0, post_processing_1.emptySummarizedWithProject)(), nestedFunctions: (0, post_processing_1.emptySummarizedWithProject)(), recursive: (0, post_processing_1.emptySummarizedWithProject)(), deepestNesting: (0, post_processing_1.emptySummarizedWithProject)() }; for (const [filepath, meta] of info.entries()) { const us = meta.definedFunctions; addToList(data.total, us.total, filepath, config); addToList(data.lambdasOnly, us.lambdasOnly, filepath, config); addToList(data.assignedFunctions, us.assignedFunctions, filepath, config); addToList(data.nestedFunctions, us.nestedFunctions, filepath, config); addToList(data.recursive, us.recursive, filepath, config); addToList(data.deepestNesting, us.deepestNesting, filepath, config); } console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions metadata reading completed, summarizing and writing to file`); const out = fs_1.default.createWriteStream(path_1.default.join(outputPath, 'function-definitions-meta.csv')); out.write(`kind,unique-projects,unique-files,${(0, summarizer_1.summarizedMeasurement2CsvHeader)()}\n`); for (const [key, val] of Object.entries(data)) { const data = val; out.write(`${JSON.stringify(key)},${data.uniqueProjects.size},${data.uniqueFiles.size},${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(data.count))}\n`); } out.close(); } function retrieveAssignedFunctionNames(featureRoot, config, outputPath) { const varNames = new Map(); (0, files_1.readLineByLineSync)(path_1.default.join(featureRoot, 'assignedFunctions.txt'), line => { const parsed = JSON.parse(String(line)); const [hits, context] = parsed; const countsForFile = (0, arrays_1.array2bag)(hits); for (const [name, count] of countsForFile.entries()) { let get = varNames.get(name); if (!get) { get = (0, post_processing_1.emptySummarizedWithProject)(); varNames.set(name, get); } addToList(get, count, context ?? '', config); } }); const varNamesOut = fs_1.default.createWriteStream(path_1.default.join(outputPath, 'function-definitions-var-names.csv')); varNamesOut.write(`name,unique-projects,unique-files,${(0, summarizer_1.summarizedMeasurement2CsvHeader)()}\n`); for (const [key, val] of varNames.entries()) { varNamesOut.write(`${JSON.stringify(key)},${val.uniqueProjects.size},${val.uniqueFiles.size},${(0, summarizer_1.summarizedMeasurement2Csv)((0, summarizer_1.summarizeMeasurement)(val.count))}\n`); } varNamesOut.close(); } /** * Note: the summary does not contain a 0, for each function that `is _not_ called` by a file. Hence, the minimum can not be 0 (division for mean etc. will still be performed on total file count) */ function postProcess(featureRoot, info, outputPath, config) { // each number[][] contains a 'number[]' per file retrievePerFileDefinitionInformation(featureRoot, info, config, outputPath); console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions reading completed, summarizing info...`); retrieveMetaInformation(info, config, outputPath); retrieveAssignedFunctionNames(featureRoot, config, outputPath); } function emptyFunctionDefinitionSummary() { return { total: [], parameters: [], length: { lines: [], chars: [], nonWhitespaceChars: [] }, returns: { explicit: [], implicit: [], onlyExplicit: [], onlyImplicit: [] }, exitPointsLinePercentageInDef: [], linePercentageInFile: [], callsites: [] }; } function processNextLine(data, lineNumber, info, line) { if (lineNumber % 2_500 === 0) { console.log(` [${(0, time_1.date2string)(new Date())}] Defined functions processed ${lineNumber} lines`); } const [hits, context] = line; const forFile = emptyFunctionDefinitionSummary(); for (const { location, length, returns, numberOfParameters, callsites } of hits) { const stats = info.get(context ?? '')?.stats.lines[0].length; // we retrieve the first component fo the path forFile.total.push(1); forFile.parameters.push(numberOfParameters); forFile.length.lines.push(length.lines); forFile.length.chars.push(length.characters); forFile.length.nonWhitespaceChars.push(length.nonWhitespaceCharacters); forFile.exitPointsLinePercentageInDef.push(returns.map(r => r.location[0]).map(l => l / length.lines)); forFile.callsites.push(callsites.length); if (stats) { forFile.linePercentageInFile.push(location[0] / stats); } } // push all of that to main :D forFile.total = [forFile.total.length]; data.push(forFile); } //# sourceMappingURL=post-process.js.map