@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
102 lines • 4.59 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DoesCallQueryDefinition = void 0;
const ansi_1 = require("../../../util/text/ansi");
const joi_1 = __importDefault(require("joi"));
const does_call_query_executor_1 = require("./does-call-query-executor");
const args_1 = require("../../../util/text/args");
const strings_1 = require("../../../util/text/strings");
const range_1 = require("../../../util/range");
const FormatError = 'Invalid constraint format, expected format "(left:$id/"regex")"';
/**
* Parses a constraint from a string argument.
* Returns the constraint or an error message.
*/
function constraintParser(argument) {
if (!argument?.startsWith('(') || !argument.includes(')')) {
return FormatError + ` (got: "${argument}")`;
}
const endBracket = argument.indexOf(')');
const constrPart = argument.slice(1, endBracket);
const args = (0, args_1.splitAtEscapeSensitive)(constrPart, true, ':');
if (args.length !== 2) {
return FormatError + ` (got ${args.length} parts: ${args.join(', ')})`;
}
const [criteria, ...rhs] = args;
const rhsStr = rhs.join(' ');
if (rhsStr.startsWith('$')) {
return {
call: criteria,
constraint: {
type: 'calls-id',
id: rhsStr.slice(1),
}
};
}
else {
const isExact = (0, strings_1.startAndEndsWith)(rhsStr, '"');
const name = isExact ? rhsStr.slice(1, -1) : rhsStr;
return {
call: criteria,
constraint: {
type: 'name',
name: name,
nameExact: isExact ? true : undefined,
}
};
}
}
function doesCallQueryLineParser(output, line, _config) {
const constraint = constraintParser(line[0]);
if (!constraint || typeof constraint === 'string') {
output.stderr(output.formatter.format(`Invalid does-call query format:\n ${constraint}`, { color: 1 /* Colors.Red */, effect: ansi_1.ColorEffect.Foreground, style: 1 /* FontStyles.Bold */ }));
return { query: [] };
}
return {
query: [
{
type: 'does-call',
queryId: constraint.call + ' (shorthand)',
call: constraint.call,
calls: constraint.constraint,
}
],
rCode: line[1]
};
}
exports.DoesCallQueryDefinition = {
executor: does_call_query_executor_1.executeDoesCallQuery,
asciiSummarizer: async (formatter, processed, queryResults, result) => {
const out = queryResults;
result.push(`Query: ${(0, ansi_1.bold)('does-call', formatter)} (${out['.meta'].timing.toFixed(0)}ms)`);
for (const [r, v] of Object.entries(out.results)) {
const idMap = (await processed.normalize()).idMap;
result.push(` - ${(0, ansi_1.bold)(r, formatter)} found:`);
if (v === false) {
result.push(' - Does not call any matching functions.');
}
else {
const loc = idMap.get(v.call)?.location ?? undefined;
result.push(` - Call with id ${(0, ansi_1.bold)(String(v.call), formatter)} (${range_1.SourceRange.format(loc)})`);
}
}
return true;
},
fromLine: doesCallQueryLineParser,
schema: joi_1.default.object({
type: joi_1.default.string().valid('does-call').required().description('The type of the query.'),
queryId: joi_1.default.string().optional().description('An optional unique identifier for this query, to identify it in the output.'),
call: joi_1.default.string().description('The function from which calls are being made. This is a slicing criterion that resolves to a function definition node.'),
calls: joi_1.default.object().required().description('The constraints on which functions are being called. This can be a combination of name-based or id-based constraints, combined with logical operators (and, or, one-of).')
}).description('Either returns all function definitions alongside whether they are recursive, or just those matching the filters.'),
flattenInvolvedNodes: (queryResults) => {
const out = queryResults;
return Object.entries(out.results).flatMap(([, v]) => {
return v !== false ? v.call : [];
});
}
};
//# sourceMappingURL=does-call-query-format.js.map