@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
82 lines • 3.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CriteriaParseError = void 0;
exports.slicingCriterionToId = slicingCriterionToId;
exports.convertAllSlicingCriteriaToIds = convertAllSlicingCriteriaToIds;
const log_1 = require("../../util/log");
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
const static_slicer_1 = require("../static/static-slicer");
const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
/**
* Thrown if the given slicing criteria can not be found
*/
class CriteriaParseError extends Error {
constructor(message) {
super(message);
this.name = 'CriteriaParseError';
}
}
exports.CriteriaParseError = CriteriaParseError;
/**
* Takes a criterion in the form of `line:column` or `line@variable-name` and returns the corresponding node id
*/
function slicingCriterionToId(criterion, idMap) {
let resolved;
if (criterion.startsWith('$')) {
resolved = (0, node_id_1.normalizeIdToNumberIfPossible)(criterion.substring(1));
}
else if (criterion.includes(':')) {
const [line, column] = criterion.split(':').map(c => parseInt(c));
resolved = locationToId([line, column], idMap);
}
else if (criterion.includes('@')) {
const [line, name] = criterion.split(/@(.*)/s); // only split at first occurrence
resolved = conventionalCriteriaToId(parseInt(line), name, idMap);
}
if (resolved === undefined) {
throw new CriteriaParseError(`invalid slicing criterion ${criterion}`);
}
return resolved;
}
function locationToId(location, dataflowIdMap) {
let candidate;
for (const [id, nodeInfo] of dataflowIdMap.entries()) {
if (nodeInfo.location === undefined || nodeInfo.location[0] !== location[0] || nodeInfo.location[1] !== location[1]) {
continue; // only consider those with position information
}
(0, log_1.expensiveTrace)(static_slicer_1.slicerLogger, () => `can resolve id ${id} (${JSON.stringify(nodeInfo.location)}) for location ${JSON.stringify(location)}`);
// function calls have the same location as the symbol they refer to, so we need to prefer the function call
if (candidate !== undefined && nodeInfo.type !== type_1.RType.FunctionCall || nodeInfo.type === type_1.RType.Argument || nodeInfo.type === type_1.RType.ExpressionList) {
continue;
}
candidate = nodeInfo;
}
const id = candidate?.info.id;
if (id) {
(0, log_1.expensiveTrace)(static_slicer_1.slicerLogger, () => `resolve id ${id} (${JSON.stringify(candidate?.info)}) for location ${JSON.stringify(location)}`);
}
return id;
}
function conventionalCriteriaToId(line, name, dataflowIdMap) {
let candidate;
for (const [id, nodeInfo] of dataflowIdMap.entries()) {
if (nodeInfo.location === undefined || nodeInfo.location[0] !== line || nodeInfo.lexeme !== name) {
continue;
}
static_slicer_1.slicerLogger.trace(`can resolve id ${id} (${JSON.stringify(nodeInfo)}) for line ${line} and name ${name}`);
// function calls have the same location as the symbol they refer to, so we need to prefer the function call
if (candidate !== undefined && nodeInfo.type !== type_1.RType.FunctionCall || nodeInfo.type === type_1.RType.Argument || nodeInfo.type === type_1.RType.ExpressionList) {
continue;
}
candidate = nodeInfo;
}
const id = candidate?.info.id;
if (id) {
static_slicer_1.slicerLogger.trace(`resolve id ${id} (${JSON.stringify(candidate?.info)}) for line ${line} and name ${name}`);
}
return id;
}
function convertAllSlicingCriteriaToIds(criteria, decorated) {
return criteria.map(l => ({ criterion: l, id: slicingCriterionToId(l, decorated) }));
}
//# sourceMappingURL=parse.js.map