@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
86 lines • 3.61 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeMagicCommentHandler = makeMagicCommentHandler;
const visitor_1 = require("../../r-bridge/lang-4.x/ast/model/processing/visitor");
const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
const assert_1 = require("../../util/assert");
function getLoc({ location, info: { fullRange } }) {
const loc = location ?? fullRange;
(0, assert_1.guard)(loc !== undefined, 'TODO: support location-less nodes!');
return loc;
}
const magicCommentIdMapper = {
'include_next_line': (n) => {
return [getLoc(n)[0] + 1];
},
'include_this_line': (n) => {
return [getLoc(n)[0]];
},
'include_start': (n, stack) => {
stack.push(getLoc(n)[0] + 1);
return undefined;
},
'include_end': (n, stack) => {
const to = getLoc(n)[0];
(0, assert_1.guard)(stack.length >= 1, `mismatched magic start and end at ${to}`);
const from = stack.pop();
const ret = new Array(to - from - 1);
for (let i = from; i < to; i++) {
ret[i - from] = i;
}
return ret;
}
};
const commentTriggerRegex = / flowr@(\w+)/;
/**
* This takes an {@link NormalizedAst} and returns an auto-select predicate for {@link reconstructToCode},
* which will automatically include lines marked by these special comments!
* Please make sure to create one per source as it will use it to cache.
*
* We support two formats:
* - Line comments in the form of `# flowr@include_next_line` or `# flowr@include_this_line`.
* - Block comments which start with `# flowr@include_start` and end with `# flowr@include_end`.
* This supports nesting, but they have to appear on a single line.
*
* Please note that these comments have to start exactly with this content to work.
*
* @param and - Predicate to composite this one with, If you do not pass a predicate, you may assume composition with
* {@link doNotAutoSelect}.
*/
function makeMagicCommentHandler(and) {
let lines = undefined;
return (node, normalizedAst) => {
if (!lines) {
lines = new Set();
const startLineStack = [];
(0, visitor_1.visitAst)(normalizedAst.ast, n => {
const comments = n.info.additionalTokens;
if (!comments) {
return;
}
for (const c of comments) {
if (c.type !== type_1.RType.Comment || !c.content.startsWith(' flowr@')) {
continue;
}
const match = commentTriggerRegex.exec(c.content);
(0, assert_1.guard)(match !== null, `invalid magic comment: ${c.content}`);
const idMapper = magicCommentIdMapper[match[1]];
(0, assert_1.guard)(idMapper !== undefined, `unknown magic comment: ${match[1]}`);
const ls = idMapper(c, startLineStack);
if (ls !== undefined) {
for (const l of ls) {
lines.add(l);
}
}
}
});
(0, assert_1.guard)(startLineStack.length === 0, `mismatched magic start and end at end of file (${JSON.stringify(startLineStack)})`);
}
const loc = node.location ?? node.info.fullRange;
if (loc && lines.has(loc[0])) {
return true;
}
return and?.(node, normalizedAst) ?? false;
};
}
//# sourceMappingURL=magic-comments.js.map