UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

84 lines (66 loc) 4.73 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const shell_1 = require("../r-bridge/shell"); const log_1 = require("../../test/functionality/_helper/log"); const doc_auto_gen_1 = require("./doc-util/doc-auto-gen"); const doc_code_1 = require("./doc-util/doc-code"); const doc_types_1 = require("./doc-util/doc-types"); const path_1 = __importDefault(require("path")); const doc_files_1 = require("./doc-util/doc-files"); const doc_cli_option_1 = require("./doc-util/doc-cli-option"); const doc_structure_1 = require("./doc-util/doc-structure"); const doc_issue_1 = require("./doc-util/doc-issue"); const doc_cfg_1 = require("./doc-util/doc-cfg"); const visitor_1 = require("../util/cfg/visitor"); async function getText(shell) { const rversion = (await shell.usedRVersion())?.format() ?? 'unknown'; const types = (0, doc_types_1.getTypesFromFolderAsMermaid)({ rootFolder: path_1.default.resolve('./src'), typeName: 'RNode', inlineTypes: doc_types_1.mermaidHide }); return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'control flow graph', rVersion: rversion })} _flowR_ produces two main perspectives of the program: 1) a [normalized version of the AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST) and 2) a [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph). However, for further analyses, we also provide an explicit control flow graph that is calculated from the normalized AST **and** the dataflow graph to incorporate change in language semantics. flowR also uses this CFG for some of its queries (e.g., to link to the last call in a [Call-Context Query](${doc_files_1.FlowrWikiBaseRef}/Query-API)) but does not incorporate it into its core analysis. ${(0, doc_structure_1.block)({ type: 'TIP', content: `If you want to investigate the Control Flow Graph, you can use the ${(0, doc_cli_option_1.getReplCommand)('controlflow*')} command in the REPL (see the [Interface wiki page](${doc_files_1.FlowrWikiBaseRef}/Interface) for more information).` })} The CFG may be a little bit uncommon compared to the classical CFG with basic blocks. This is mostly due to historical reasons. Please [open a new issue](${doc_issue_1.NewIssueUrl}) if you are interested in such a perspective. But for now, let's look at a simple CFG for a program without any branching: ${(0, doc_code_1.codeBlock)('r', 'x <- 2 * 3 + 1')} The corresponding CFG is a directed, labeled graph with two types of edges (control and flow dependencies): ${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })} Every normalized node of the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST) that has any relevance to the execution is added and automatically linked using its id (similarly to vertices of the [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph)). Higher expressions, such as \`2 * 3\` get an additional node with an artificial id that ends in \`-exit\` to mark whenever their calculation is over. To gain a better understanding, let's have a look at a simple program with a single branching structure: ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u) 3 else 2', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })} Here, you can see the \`if\` node followed by the condition (in this case merely \`u\`) that then splits into two branches for the two possible outcomes. The \`if\` structure is terminated by the corresponding \`-exit\` node. For you to compare, the following shows the CFG of an \`if\` without an \`else\` branch: ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })} The control flow graph also harmonizes with function definitions, and calls: ${await (0, doc_cfg_1.printCFGCode)(shell, 'f <- function() { 3 }\nf()', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })} In general, it is probably best to use the ${(0, doc_cli_option_1.getReplCommand)('controlflow*')} command in the REPL to investigate the CFG interactively. Have a look at the ${(0, doc_types_1.shortLink)(visitor_1.visitCfgInReverseOrder.name, types.info)} function for a generic CFG visitor. `; } if (require.main === module) { (0, log_1.setMinLevelOfAllLogs)(6 /* LogLevel.Fatal */); const shell = new shell_1.RShell(); void getText(shell).then(str => { console.log(str); }).finally(() => { shell.close(); }); } //# sourceMappingURL=print-cfg-wiki.js.map