UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

136 lines 4.55 kB
"use strict"; 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