UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

121 lines 4.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dataAccess = void 0; const common_syntax_probability_1 = require("../../common-syntax-probability"); const post_process_1 = require("./post-process"); const assert_1 = require("../../../../util/assert"); const type_1 = require("../../../../r-bridge/lang-4.x/ast/model/type"); const visitor_1 = require("../../../../r-bridge/lang-4.x/ast/model/processing/visitor"); const role_1 = require("../../../../r-bridge/lang-4.x/ast/model/processing/role"); const statistics_file_1 = require("../../../output/statistics-file"); const r_function_call_1 = require("../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const initialDataAccessInfo = { // for the nth argument, how many of them are constant, etc. singleBracket: { // only counts if empty 0: 0n, 1: (0, common_syntax_probability_1.emptyCommonSyntaxTypeCounts)() }, doubleBracket: { // similar to single bracket 0: 0n, 1: (0, common_syntax_probability_1.emptyCommonSyntaxTypeCounts)() }, chainedOrNestedAccess: 0, longestChain: 0, deepestNesting: 0, byName: 0, bySlot: 0, }; function classifyArguments(args, existing) { if (args.length === 0) { existing[0]++; return; } let i = 1; for (const arg of args) { if (arg === null || arg === undefined || arg === r_function_call_1.EmptyArgument) { existing[0]++; continue; } existing[i] = (0, common_syntax_probability_1.updateCommonSyntaxTypeCounts)(existing[i] ?? (0, common_syntax_probability_1.emptyCommonSyntaxTypeCounts)(), arg); i++; } } function visitAccess(info, input) { const accessNest = []; const accessChain = []; const parentRoleCache = new Map(); (0, visitor_1.visitAst)(input.normalizedRAst.ast, node => { if (node.type !== type_1.RType.Access) { return; } const roles = (0, role_1.rolesOfParents)(node, input.normalizedRAst.idMap); let acc = false; let idxAcc = false; for (const role of roles) { if (role === "accessed" /* RoleInParent.Accessed */) { acc = true; break; // we only account for the first one } else if (role === "index-access" /* RoleInParent.IndexAccess */) { idxAcc = true; break; } } // here we have to check after the addition as we can only check the parental context if (acc) { accessChain.push(node); info.chainedOrNestedAccess++; info.longestChain = Math.max(info.longestChain, accessChain.length); } else if (idxAcc) { accessNest.push(node); info.chainedOrNestedAccess++; info.deepestNesting = Math.max(info.deepestNesting, accessNest.length); } parentRoleCache.set(node.info.id, { acc, idxAcc }); if (accessNest.length === 0 && accessChain.length === 0) { // store topmost, after add as it must not be a child to do that (0, statistics_file_1.appendStatisticsFile)(exports.dataAccess.name, 'dataAccess', [node.info.fullLexeme ?? node.lexeme], input.filepath); } const op = node.operator; switch (op) { case '@': info.bySlot++; return; case '$': info.byName++; return; case '[': classifyArguments(node.access, info.singleBracket); break; case '[[': classifyArguments(node.access, info.doubleBracket); break; default: (0, assert_1.assertUnreachable)(op); } (0, assert_1.guard)(Array.isArray(node.access), '[ and [[ must provide access as array'); }, node => { // drop again :D if (node.type === type_1.RType.Access) { const ctx = parentRoleCache.get(node.info.id); if (ctx?.acc) { accessChain.pop(); } else if (ctx?.idxAcc) { accessNest.pop(); } } }); } exports.dataAccess = { name: 'Data Access', description: 'Ways of accessing data structures in R', process(existing, input) { visitAccess(existing, input); return existing; }, initialValue: initialDataAccessInfo, postProcess: post_process_1.postProcess }; //# sourceMappingURL=data-access.js.map