@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
84 lines (66 loc) • 4.73 kB
JavaScript
;
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