@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
112 lines • 4.21 kB
JavaScript
"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