UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

274 lines 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RNode = exports.ROther = exports.RFunctions = exports.RConstructs = exports.RLoopConstructs = exports.RSingleNode = exports.RConstant = void 0; const range_1 = require("../../../../util/range"); const type_1 = require("./type"); const r_access_1 = require("./nodes/r-access"); const visitor_1 = require("./processing/visitor"); const assert_1 = require("../../../../util/assert"); const documentation_provider_1 = require("../../../roxygen2/documentation-provider"); /** * Helper object to provide helper functions for {@link RConstant|RConstants}. * @see {@link RNode} - for more general helper functions for all nodes */ exports.RConstant = { name: 'RConstant', /** * Type guard for {@link RConstant} nodes, i.e. checks whether a node is a number, string or logical constant. * If you need the specific type, please either use the respective type guards (e.g., {@link RNumber.is}) or check the `type` node directly. */ is(node) { if (!node) { return false; } const t = node.type; return t === type_1.RType.Number || t === type_1.RType.String || t === type_1.RType.Logical; }, /** * A set of all types of constants in the normalized AST, i.e. number, string and logical constants. */ constantTypes: new Set([type_1.RType.Number, type_1.RType.String, type_1.RType.Logical]) }; /** * Represents a leaf node in the normalized AST, i.e. a node that does not have any children. This includes comment, symbol, constant, break, next and line directive nodes. */ exports.RSingleNode = { name: 'RSingleNode', /** * Type guard for {@link RSingleNode} nodes, i.e. checks whether a node is a comment, symbol, constant, break, next or line directive. * If you need the specific type, please either use the respective type guards (e.g., {@link RComment.is}) or check the `type` node directly. */ is(node) { if (!node) { return false; } const t = node.type; return t === type_1.RType.Comment || t === type_1.RType.Symbol || exports.RConstant.constantTypes.has(t) || t === type_1.RType.Break || t === type_1.RType.Next || t === type_1.RType.LineDirective; }, /** * A set of all types of single nodes in the normalized AST, i.e. comment, symbol, constant, break, next and line directive nodes. */ singleNodeTypes: new Set([type_1.RType.Comment, type_1.RType.Symbol, type_1.RType.Break, type_1.RType.Next, type_1.RType.LineDirective, ...exports.RConstant.constantTypes]) }; exports.RLoopConstructs = { name: 'RLoopConstructs', /** * Type guard for {@link RLoopConstructs} nodes, i.e. checks whether a node is a for, repeat or while loop. * If you need the specific type, please either use the respective type guards (e.g., {@link RForLoop.is}) or check the `type` node directly. */ is(node) { if (!node) { return false; } const t = node.type; return t === type_1.RType.ForLoop || t === type_1.RType.RepeatLoop || t === type_1.RType.WhileLoop; }, /** * A set of all types of loop constructs in the normalized AST, i.e. for, repeat and while loops. */ loopConstructTypes: new Set([type_1.RType.ForLoop, type_1.RType.RepeatLoop, type_1.RType.WhileLoop]) }; exports.RConstructs = { name: 'RConstructs', /** * Type guard for {@link RConstructs} nodes, i.e. checks whether a node is a for, repeat or while loop or an if-then-else construct. * If you need the specific type, please either use the respective type guards (e.g., {@link RForLoop.is}) or check the `type` node directly. */ is(node) { if (!node) { return false; } const t = node.type; return exports.RLoopConstructs.loopConstructTypes.has(t) || t === type_1.RType.IfThenElse; }, /** * A set of all types of constructs in the normalized AST, i.e. for, repeat and while loops and if-then-else constructs. */ constructTypes: new Set([...exports.RLoopConstructs.loopConstructTypes, type_1.RType.IfThenElse]) }; exports.RFunctions = { name: 'RFunctions', /** * Type guard for {@link RFunctions} nodes, i.e. checks whether a node is a function definition, function call, parameter or argument. * If you need the specific type, please either use the respective type guards (e.g., {@link RFunctionDefinition.is}) or check the `type` node directly. */ is(node) { if (!node) { return false; } const t = node.type; return t === type_1.RType.FunctionDefinition || t === type_1.RType.FunctionCall || t === type_1.RType.Parameter || t === type_1.RType.Argument; }, /** * A set of all types of function-related nodes in the normalized AST, i.e. function definitions, function calls, parameters and arguments. */ functionTypes: new Set([type_1.RType.FunctionDefinition, type_1.RType.FunctionCall, type_1.RType.Parameter, type_1.RType.Argument]) }; exports.ROther = { name: 'ROther', /** * Type guard for {@link ROther} nodes, i.e. checks whether a node is a comment or line directive. * If you need the specific type, please either use the respective type guards (e.g., {@link RComment.is}) or check the `type` node directly. */ is(node) { if (!node) { return false; } const t = node.type; return t === type_1.RType.Comment || t === type_1.RType.LineDirective; } }; /** * Helper object to provide helper functions for {@link RNode|RNodes}. * For the individual type checks, please consult the individual vertices, e.g. {@link RPipe.is}. * Some vertices also have a {@link RPipe.availableFromRVersion} property that indicates from which R version they are available, * so you can check for that as well if needed. * @see {@link DefaultNormalizedAstFold} - for a more powerful way to traverse the normalized AST */ exports.RNode = { name: 'RNode', /** * A helper function to retrieve the location of a given node, if available. * @see SourceLocation.fromNode */ getLocation(node) { return range_1.SourceLocation.fromNode(node); }, /** * A helper function to retrieve the id of a given node, if available. */ getId(node) { return node.info.id; }, /** * A helper function to retrieve the type of a given node. */ getType(node) { return node.type; }, /** * Visits all node ids within a tree given by a respective root node using a depth-first search with prefix order. * @param nodes - The root id nodes to start collecting from * @param onVisit - Called before visiting the subtree of each node. Can be used to stop visiting the subtree starting with this node (return `true` stop) * @param onExit - Called after the subtree of a node has been visited, called for leafs too (even though their subtree is empty) * @see {@link RProject.visitAst} - to visit all nodes in a project */ visitAst(nodes, onVisit, onExit) { return new visitor_1.NodeVisitor(onVisit, onExit).visit(nodes); }, /** * Collects all node ids within a tree given by a respective root node * @param nodes - The root id nodes to start collecting from * @see {@link collectAllIdsWithStop} - to stop collecting at certain nodes * @see {@link RProject.collectAllIds} - to collect all ids within a project */ collectAllIds(nodes) { const ids = new Set(); exports.RNode.visitAst(nodes, node => { ids.add(node.info.id); }); return ids; }, /** * Collects all direct children of a given node, i.e. all nodes that are directly reachable via a property of the given node. */ directChildren(node) { const type = node.type; switch (type) { case type_1.RType.FunctionCall: return [node.named ? node.functionName : node.calledFunction, ...node.arguments]; case type_1.RType.FunctionDefinition: return [...node.parameters, node.body]; case type_1.RType.ExpressionList: return node.grouping ? [node.grouping[0], ...node.children, node.grouping[1]] : node.children; case type_1.RType.ForLoop: return [node.variable, node.vector, node.body]; case type_1.RType.WhileLoop: return [node.condition, node.body]; case type_1.RType.RepeatLoop: return [node.body]; case type_1.RType.IfThenElse: return node.otherwise ? [node.condition, node.then, node.otherwise] : [node.condition, node.then]; case type_1.RType.BinaryOp: case type_1.RType.Pipe: return [node.lhs, node.rhs]; case type_1.RType.UnaryOp: return [node.operand]; case type_1.RType.Parameter: return node.defaultValue ? [node.name, node.defaultValue] : [node.name]; case type_1.RType.Argument: return node.name && node.value ? [node.name, node.value] : node.name ? [node.name] : node.value ? [node.value] : []; case type_1.RType.Access: return r_access_1.RAccess.isIndex(node) ? [node.accessed, ...node.access] : [node.accessed]; case type_1.RType.Symbol: case type_1.RType.Logical: case type_1.RType.Number: case type_1.RType.String: case type_1.RType.Comment: case type_1.RType.Break: case type_1.RType.Next: case type_1.RType.LineDirective: return []; default: (0, assert_1.assertUnreachable)(type); } }, /** * Returns the direct parent of a node. * Usually, only root nodes do not have a parent, and you can assume that there is a * linear chain of parents leading to the root node. * @see {@link iterateParents} - to get all parents of a node */ directParent(node, idMap) { const parentId = node.info.parent; if (parentId === undefined) { return undefined; } return idMap.get(parentId); }, /** * Returns an iterable of all parents of a node, starting with the direct parent and ending with the root node. */ *iterateParents(node, idMap) { let currentNode = node; while (currentNode) { currentNode = exports.RNode.directParent(currentNode, idMap); if (currentNode) { yield currentNode; } } }, /** * In contrast to the nesting stored in the {@link RNode} structure, * this function calculates the depth of a node by counting the number of parents until the root node is reached. */ depth(node, idMap) { let depth = 0; let currentNode = node; while (currentNode) { currentNode = exports.RNode.directParent(currentNode, idMap); depth++; } return depth; }, /** * Collects all node ids within a tree given by a respective root node, but stops collecting at nodes where the given `stop` function returns `true`. * <p> * This can be used to exclude certain subtrees from the collection, for example to exclude function bodies when collecting ids on the root level. * @param nodes - The root id nodes to start collecting from * @param stop - A function that determines whether to stop collecting at a given node, does not stop by default * @see {@link collectAllIds} - to collect all ids without stopping * @see {@link RProject.collectAllIdsWithStop} - to collect all ids within a project with stopping */ collectAllIdsWithStop(nodes, stop) { const ids = new Set(); exports.RNode.visitAst(nodes, node => { if (stop(node)) { return true; } ids.add(node.info.id); return false; }); return ids; }, /** * A helper function to retrieve the lexeme of a given node, if available. * If the `fullLexeme` is available, it will be returned, otherwise the `lexeme` will be returned. */ lexeme(node) { return node?.info.fullLexeme ?? node?.lexeme; }, /** * Return the (roxygen) documentation associated with the given node, if available. * @see {@link getDocumentationOf} */ documentation: documentation_provider_1.getDocumentationOf }; //# sourceMappingURL=model.js.map