npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

babel-plugin-recursive-tail-calls

v1.0.0

Published

A babel plugin for performing tail call optimization in recursive functions.

Downloads

12

Readme

Recursive tail calls

A babel plugin for performing tail call optimization in recursive functions.

Usage

Download the plugin from npm, using e.g. npm or yarn.

npm i babel-plugin-recursive-tail-calls

Add it to the plugins in babel.config.json.

More information on using Babel here.

Rationale

Tail call optimization was included in the ECMAScript 2015 language specification. However, some teams raised concerns about this feature, and therefore it is so far only supported by Safari.

In functional programming, recursion is the main way to simulate a loop. So for those wanting to take a functional approach to JavaScript, some kind of tail call optimization is needed to avoid exceeding the maximum stack size.

Implementation

This plugin does not implement the feature as mentioned in the language specification. Rather, it aims to find all locations where a function calls itself in tail position, and rewrites those functions using a loop.

// before transpilation
function f(a) {
  if (a <= 0) {
    return a;
  }
  return f(a - 1);
}

// after transpilation
function f(a) {
  let _continueRecursion = true;
  _tailCallLoop: while (_continueRecursion) {
    _continueRecursion = false;
    if (a <= 0) {
      return a;
    }
    [a] = [a - 1];
    _continueRecursion = true;
    continue _tailCallLoop;
  }
}

Supported scenarios

This plugin aims to support all scenarios where a recursive tail call can occur. Below are some examples. See examples directory for complete examples and their transformations.

Tail call

A tail call is a call that is part of a return statement, such that the call is the last thing evaluated before control is returned back to the calling function. This means that, in addition to being the only part of a return statement, a tail call can occur in the following places:

  • last operand of logical and (&&)
  • last operand of logical or (||)
  • last operand of the nullish coalescing operator (??)
  • if or else-branch of the conditional opertor (? :)

When rewriting occurs in this cases, the evaluation of arguments is only done once.

In case of multiple recursive tail calls, all are rewritten. If function evaluation terminates without a return statement, the loop, to which the code is transpiled, is terminated accordingly.

Shadowing

The scope of the recursive call are checked to see if the function name has been shadowed by another function with the same. In this case optimization is not performed.

Arguments & parameters

As array assignment, which is used in the transformation, exhibits much of the same properties as parameter assignment, all features of parameter assignment are supported.

Anonymous functions

Anonymous functions, e.g. arrow functions, are tricky in the context of recursion since they are, well, anonymous, and identifying which identifier corresponds to which function might not even be possible to do at compile time. The only case where optimization with anonymous functions is done by this plugin is when the function is directly assigned to a const at creation and the label of the const declaration is used in the recursive call. This is supported since it is a common pattern.

const functionName = () => {
  // function body
  return functionName();
};