@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
136 lines • 4.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlowrFilterCombinator = exports.FlowrFilters = exports.ValidFlowrFiltersReverse = exports.ValidFlowrFilters = exports.FlowrFilter = void 0;
exports.binaryTreeToString = binaryTreeToString;
exports.isBinaryTree = isBinaryTree;
exports.evalFilter = evalFilter;
const type_1 = require("../r-bridge/lang-4.x/ast/model/type");
const vertex_1 = require("../dataflow/graph/vertex");
var FlowrFilter;
(function (FlowrFilter) {
FlowrFilter["DropEmptyArguments"] = "drop-empty-arguments";
})(FlowrFilter || (exports.FlowrFilter = FlowrFilter = {}));
exports.ValidFlowrFilters = new Set(Object.values(FlowrFilter));
exports.ValidFlowrFiltersReverse = Object.fromEntries(Object.entries(FlowrFilter).map(([k, v]) => [v, k]));
exports.FlowrFilters = {
[FlowrFilter.DropEmptyArguments]: (n) => {
return n.type !== type_1.RType.Argument || n.name !== undefined;
}
};
/**
* @see {@link FlowrFilterCombinator.is}
* @see {@link evalFilter}
* @see {@link binaryTreeToString}
*/
class FlowrFilterCombinator {
tree;
constructor(init) {
this.tree = this.unpack(init);
}
static is(value) {
if (typeof value === 'object') {
return new this(value);
}
else if (type_1.ValidRTypes.has(value)) {
return new this({ type: 'r-type', value: value });
}
else if (vertex_1.ValidVertexTypes.has(value)) {
return new this({ type: 'vertex-type', value: value });
}
else if (exports.ValidFlowrFilters.has(value)) {
return new this({ type: 'special', value: value });
}
else {
throw new Error(`Invalid filter value: ${value}`);
}
}
and(right) {
return this.binaryRight('and', right);
}
or(right) {
return this.binaryRight('or', right);
}
xor(right) {
return this.binaryRight('xor', right);
}
binaryRight(op, right) {
this.tree = {
type: op,
left: this.tree,
right: this.unpack(FlowrFilterCombinator.is(right))
};
return this;
}
not() {
return this.unary('not');
}
unary(op) {
this.tree = {
type: op,
operand: this.tree
};
return this;
}
unpack(val) {
return val instanceof FlowrFilterCombinator ? val.tree : val;
}
get() {
return this.tree;
}
}
exports.FlowrFilterCombinator = FlowrFilterCombinator;
function binaryTreeToString(tree) {
const res = treeToStringImpl(tree, 0);
// drop outer parens
if (res.startsWith('(') && res.endsWith(')')) {
return res.slice(1, -1);
}
else {
return res;
}
}
const typeToSymbol = {
'and': '∧',
'or': '∨',
'xor': '⊕',
'not': '¬'
};
function treeToStringImpl(tree, depth) {
if (tree.type === 'r-type' || tree.type === 'vertex-type' || tree.type === 'special') {
return tree.value;
}
if (tree.type === 'not') {
return `${typeToSymbol[tree.type]}${treeToStringImpl(tree.operand, depth)}`;
}
const left = treeToStringImpl(tree.left, depth + 1);
const right = treeToStringImpl(tree.right, depth + 1);
return `(${left} ${typeToSymbol[tree.type]} ${right})`;
}
function isBinaryTree(tree) {
return typeof tree === 'object' && tree !== null && 'tree' in tree;
}
const evalVisit = {
and: ({ left, right }, data) => evalTree(left, data) && evalTree(right, data),
or: ({ left, right }, data) => evalTree(left, data) || evalTree(right, data),
xor: ({ left, right }, data) => evalTree(left, data) !== evalTree(right, data),
not: ({ operand }, data) => !evalTree(operand, data),
'r-type': ({ value }, { node }) => node.type === value,
'vertex-type': ({ value }, { dataflow: { graph }, node }) => graph.getVertex(node.info.id)?.tag === value,
'special': ({ value }, { node }) => {
const getHandler = exports.FlowrFilters[value];
if (getHandler) {
return getHandler(node);
}
throw new Error(`Special filter not implemented: ${value}`);
}
};
function evalTree(tree, data) {
/* we ensure that the types fit */
return evalVisit[tree.type](tree, data);
}
function evalFilter(filter, data) {
/* common lift, this can be improved easily :D */
const tree = FlowrFilterCombinator.is(filter);
return evalTree(tree.get(), data);
}
//# sourceMappingURL=flowr-search-filters.js.map