Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Babel, Maximum call stack size exceeded while using path.replaceWith

I was trying to play with babel modules, babylon, babel-traverse. When I tried to replace a node, the program crashed with Maximum call stack size exceeded. Here is my code

import * as babylon from 'babylon'
import traverse from 'babel-traverse'
import generate from 'babel-generator'
import * as t from 'babel-types'


const code = `
import a from 'b'
n === 3
`
const ast = babylon.parse(code, {
  sourceType: 'module'
})

const visitor = {
  BinaryExpression(path) {
    console.log((path.node))
    path.replaceWith(t.binaryExpression('**', t.numericLiteral(3), t.numericLiteral(4)))
  }
}

traverse(ast, visitor)

let generated = generate(ast, null, code)
console.log(generated.code)

And I'am using below babel dependencies, any idea?

"dependencies": {
"babel-generator": "^6.9.0",
"babel-preset-es2015": "^6.9.0",
"babel-traverse": "^6.9.0",
"babel-types": "^6.9.1",
"babylon": "^6.8.0"
}
like image 740
hjl Avatar asked May 31 '16 07:05

hjl


2 Answers

The reason you're getting a stack error is because your binary expression replacement generates another binary expression. Your replacement binary expression is fed into the visitor over and over again, ad infinitum.

To break the infinite loop, you need to check whether your replacement has already occurred, possibly by ignoring the replaceWith step whenever you see the operator is **.

like image 156
Beevik Avatar answered Oct 24 '22 20:10

Beevik


Adding the new binaryExpression while you have a visitor on BinaryExpression causes the new binaryExpression to be visited, and so it is an infinite loop. You can call path.skip after path.replaceWith to skip visiting the new expression.

path.replaceWith(t.binaryExpression('**', t.numericLiteral(3), t.numericLiteral(4)))
path.skip()
like image 36
m59 Avatar answered Oct 24 '22 21:10

m59