@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
98 lines • 3.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RootId = void 0;
exports.prepareParsedData = prepareParsedData;
exports.convertPreparedParsedData = convertPreparedParsedData;
const retriever_1 = require("../../../../retriever");
const assert_1 = require("../../../../../util/assert");
const type_1 = require("../../model/type");
exports.RootId = 0;
/**
* Takes the raw {@link RShell} output and extracts the csv information contained
*/
function prepareParsedData(data) {
let json;
try {
json = JSON.parse(`[${data.trim()}]`);
}
catch (e) {
throw new Error(`Failed to parse data [${data}]: ${e?.message}`);
}
(0, assert_1.guard)(Array.isArray(json), () => `Expected ${data} to be an array but was not`);
const ret = new Map(json.map(([line1, col1, line2, col2, id, parent, token, terminal, text]) => {
return [id, { line1, col1, line2, col2, id, parent, token: (0, retriever_1.removeRQuotes)(token), terminal, text }];
}));
const roots = [];
// iterate a second time to set parent-child relations (since they may be out of order in the csv)
for (const entry of ret.values()) {
if (entry.parent != exports.RootId) {
/** it turns out that comments may return a negative id pair to their parent */
const parent = ret.get(Math.abs(entry.parent));
if (parent) {
parent.children ??= [];
parent.children.push(entry);
}
}
else {
roots.push(entry);
}
}
return roots;
}
/**
* Takes the CSV-Entries and maps them to the old json format for compatibility.
*/
function convertPreparedParsedData(roots) {
const partialEntry = {
token: type_1.RawRType.ExpressionList,
text: '',
id: exports.RootId,
parent: exports.RootId
};
// if we don't have children, this is simple
if (roots.length <= 0) {
return {
...partialEntry,
line1: 1,
col1: 1,
line2: 1,
col2: 1,
children: []
};
}
// Locate start, end of a source file (order children in advance).
const rootEntries = [...roots].sort(orderOf);
const start = rootEntries[0];
const end = rootEntries[rootEntries.length - 1];
// Construct CsvEntry for the root, handling empty input.
const csvParent = {
...partialEntry,
line1: start?.line1 ?? 1,
col1: start?.col1 ?? 1,
line2: end?.line2 ?? 1,
col2: end?.col2 ?? 1,
children: rootEntries,
terminal: false
};
// Return actual value.
return convertEntry(csvParent);
}
function convertEntry(csvEntry) {
return {
...csvEntry,
// check and recursively iterate children
children: csvEntry.children?.sort(orderOf).map(convertEntry) ?? []
};
}
/**
* we sort children the same way xmlparsedata does (by line, by column, by inverse end line, by inverse end column, by terminal state, by combined "start" tiebreaker value)
* (https://github.com/r-lib/xmlparsedata/blob/v1.0.5/R/package.R#L120)
*/
function orderOf(c1, c2) {
return c1.line1 - c2.line1 || c1.col1 - c2.col1 || c2.line2 - c1.line2 || c2.col2 - c1.col2 || Number(c1.terminal) - Number(c2.terminal) || sortTiebreak(c1) - sortTiebreak(c2);
}
function sortTiebreak({ line1, col1, col2 }) {
// see https://github.com/r-lib/xmlparsedata/blob/v1.0.5/R/package.R#L86
return line1 * (Math.max(col1, col2) + 1) + col1;
}
//# sourceMappingURL=format.js.map