UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

156 lines 6.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FlowrAnalyzerCache = void 0; const flowr_cache_1 = require("./flowr-cache"); const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines"); const assert_1 = require("../../util/assert"); const flowr_analyzer_controlflow_cache_1 = require("./flowr-analyzer-controlflow-cache"); const call_graph_1 = require("../../dataflow/graph/call-graph"); /** * This provides the full analyzer caching layer, please avoid using this directly * and prefer the {@link FlowrAnalyzer}. */ class FlowrAnalyzerCache extends flowr_cache_1.FlowrCache { args; pipeline = undefined; controlFlowCache = undefined; callGraphCache = undefined; constructor(args) { super(); this.args = args; this.initCacheProviders(); } initCacheProviders() { this.pipeline = (0, default_pipelines_1.createDataflowPipeline)(this.args.parser, { context: this.args.context, getId: this.args.getId }); this.controlFlowCache = new flowr_analyzer_controlflow_cache_1.FlowrAnalyzerControlFlowCache(); this.callGraphCache = undefined; } static create(data) { return new FlowrAnalyzerCache(data); } receive(event) { super.receive(event); switch (event.type) { case "full" /* CacheInvalidationEventType.Full */: this.initCacheProviders(); break; default: (0, assert_1.assertUnreachable)(event.type); } } get() { /* this will do a ref assignment, so indirect force */ return this.computeIfAbsent(false, () => this.pipeline.getResults(true)); } reset() { this.receive({ type: "full" /* CacheInvalidationEventType.Full */ }); } async runTapeUntil(force, until) { (0, assert_1.guard)(this.args.context.files.loadingOrder.getUnorderedRequests().length > 0, 'At least one request must be set to run the analysis pipeline'); if (force) { this.reset(); } let g; while ((g = until()) === undefined && this.pipeline.hasNextStep()) { await this.pipeline.nextStep(); } (0, assert_1.guard)(g !== undefined, 'Could not reach the desired pipeline step, invalid cache state(?)'); return g; } /** * Get the parse output for the request, parsing if necessary. * @param force - Do not use the cache, instead force a new parse. * @see {@link FlowrAnalyzerCache#peekParse} - to get the parse output if already available without triggering a new parse. */ async parse(force) { const d = this.get(); return this.runTapeUntil(force, () => d.parse); } /** * Get the parse output for the request if already available, otherwise return `undefined`. * This will not trigger a new parse. * @see {@link FlowrAnalyzerCache#parse} - to get the parse output, parsing if necessary. */ peekParse() { return this.get().parse; } /** * Get the normalized abstract syntax tree for the request, normalizing if necessary. * @param force - Do not use the cache, instead force new analyses. * @see {@link FlowrAnalyzerCache#peekNormalize} - to get the normalized AST if already available without triggering a new normalization. */ async normalize(force) { const d = this.get(); return this.runTapeUntil(force, () => d.normalize); } /** * Get the normalized abstract syntax tree for the request if already available, otherwise return `undefined`. * This will not trigger a new normalization. * @see {@link FlowrAnalyzerCache#normalize} - to get the normalized AST, normalizing if necessary. */ peekNormalize() { return this.get().normalize; } /** * Get the dataflow graph for the request, computing if necessary. * @param force - Do not use the cache, instead force new analyses. * @see {@link FlowrAnalyzerCache#peekDataflow} - to get the dataflow graph if already available without triggering a new computation. */ async dataflow(force) { const d = this.get(); return this.runTapeUntil(force, () => d.dataflow); } /** * Get the dataflow graph for the request if already available, otherwise return `undefined`. * This will not trigger a new computation. * @see {@link FlowrAnalyzerCache#dataflow} - to get the dataflow graph, computing if necessary. */ peekDataflow() { return this.get().dataflow; } /** * Get the control flow graph (CFG) for the request, computing if necessary. * @param force - Do not use the cache, instead force new analyses. * @param kind - The kind of CFG that is requested. * @param simplifications - Simplification passes to be applied to the CFG. */ async controlflow(force, kind, simplifications) { const cfgInfo = { ctx: this.args.context, cfgQuick: this.peekDataflow()?.cfgQuick, ast: async () => await this.normalize(), dfg: async () => await this.dataflow() }; return this.controlFlowCache.get(force, kind, cfgInfo, simplifications); } /** * Get the control flow graph (CFG) for the request if already available, otherwise return `undefined`. * @param kind - The kind of CFG that is requested. * @param simplifications - Simplification passes to be applied to the CFG. * @see {@link FlowrAnalyzerCache#controlflow} - to get the control flow graph, computing if necessary. */ peekControlflow(kind, simplifications) { return this.controlFlowCache.peek(kind, simplifications); } /** * Get the call graph for the request, computing if necessary. * @param force - Do not use the cache, instead force new analyses. */ async callGraph(force) { if (!this.callGraphCache || force) { this.callGraphCache = call_graph_1.CallGraph.compute((await this.dataflow(force)).graph); } return this.callGraphCache; } /** * Get the call graph for the request if already available, otherwise return `undefined`. */ peekCallGraph() { return this.callGraphCache; } } exports.FlowrAnalyzerCache = FlowrAnalyzerCache; //# sourceMappingURL=flowr-analyzer-cache.js.map