UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

112 lines 4.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.visitAst = visitAst; const type_1 = require("../type"); const assert_1 = require("../../../../../util/assert"); const r_function_call_1 = require("../nodes/r-function-call"); // capsuled as a class to avoid passing onExit and onEnter on *each* visit call class NodeVisitor { onEnter; onExit; constructor(onEnter, onExit) { this.onEnter = onEnter; this.onExit = onExit; } visitSingle(node) { if (this.onEnter?.(node)) { return; } /* let the type system know that the type does not change */ const type = node.type; switch (type) { case type_1.RType.FunctionCall: this.visitSingle(node.named ? node.functionName : node.calledFunction); this.visit(node.arguments); break; case type_1.RType.FunctionDefinition: this.visit(node.parameters); this.visitSingle(node.body); break; case type_1.RType.ExpressionList: this.visit(node.grouping); this.visit(node.children); break; case type_1.RType.ForLoop: this.visitSingle(node.variable); this.visitSingle(node.vector); this.visitSingle(node.body); break; case type_1.RType.WhileLoop: this.visitSingle(node.condition); this.visitSingle(node.body); break; case type_1.RType.RepeatLoop: this.visitSingle(node.body); break; case type_1.RType.IfThenElse: this.visitSingle(node.condition); this.visitSingle(node.then); this.visit(node.otherwise); break; case type_1.RType.BinaryOp: case type_1.RType.Pipe: this.visitSingle(node.lhs); this.visitSingle(node.rhs); break; case type_1.RType.UnaryOp: this.visitSingle(node.operand); break; case type_1.RType.Parameter: this.visitSingle(node.name); this.visit(node.defaultValue); break; case type_1.RType.Argument: this.visit(node.name); this.visit(node.value); break; case type_1.RType.Access: this.visitSingle(node.accessed); if (node.operator === '[' || node.operator === '[[') { this.visit(node.access); } break; 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: // leafs break; default: (0, assert_1.assertUnreachable)(type); } this.onExit?.(node); } visit(nodes) { if (Array.isArray(nodes)) { const n = nodes; for (const node of n) { if (node && node !== r_function_call_1.EmptyArgument) { this.visitSingle(node); } } } else if (nodes) { this.visitSingle(nodes); } } } /** * 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) */ function visitAst(nodes, onVisit, onExit) { return new NodeVisitor(onVisit, onExit).visit(nodes); } //# sourceMappingURL=visitor.js.map