compiler/compiler.js
/**
 * Next up, the transformer. Our transformer is going to take the AST that we
 * have built and pass it to our traverser function with a visitor and will
 * create a new ast.
 *
 * ----------------------------------------------------------------------------
 *   Original AST                     |   Transformed AST
 * ----------------------------------------------------------------------------
 *   {                                |   {
 *     type: 'Program',               |     type: 'Program',
 *     body: [{                       |     body: [{
 *       type: 'CallExpression',      |       type: 'ExpressionStatement',
 *       name: 'add',                 |       expression: {
 *       params: [{                   |         type: 'CallExpression',
 *         type: 'NumberLiteral',     |         callee: {
 *         value: '2'                 |           type: 'Identifier',
 *       }, {                         |           name: 'add'
 *         type: 'CallExpression',    |         },
 *         name: 'subtract',          |         arguments: [{
 *         params: [{                 |           type: 'NumberLiteral',
 *           type: 'NumberLiteral',   |           value: '2'
 *           value: '4'               |         }, {
 *         }, {                       |           type: 'CallExpression',
 *           type: 'NumberLiteral',   |           callee: {
 *           value: '2'               |             type: 'Identifier',
 *         }]                         |             name: 'subtract'
 *       }]                           |           },
 *     }]                             |           arguments: [{
 *   }                                |             type: 'NumberLiteral',
 *                                    |             value: '4'
 * ---------------------------------- |           }, {
 *                                    |             type: 'NumberLiteral',
 *                                    |             value: '2'
 *                                    |           }]
 *  (sorry the other one is longer.)  |         }
 *                                    |       }
 *                                    |     }]
 *                                    |   }
 * ----------------------------------------------------------------------------
 */
Next up, the transformer. Our transformer is going to take the AST that we
have built and pass it to our traverser function with a visitor and will
create a new ast.

Original AST                     |   Transformed AST


Next up the transformer . Our transformer is going to take the AST that we have built and pass it to our traverser function with a visitor and will create a new ast . Original AST | Transformed AST
function transformer (ast) {
  let newAst = {
    type: 'Program',
    body: []
  }
  ast._context = newAst.body
  traverser(ast, {
    NumberLiteral: {
      enter (node, parent) {
        parent._context.push({
          type: 'NumberLiteral',
          value: node.value
        })
      }
    },
    StringLiteral: {
      enter (node, parent) {
        parent._context.push({
          type: 'StringLiteral',
          value: node.value,
        })
      }
    },
    CallExpression: {
      enter (node, parent) {
        let expression = {
          type: 'CallExpression',
          callee: {
            type: 'Identifier',
            name: node.name,
          },
          arguments: [],
        }
        node._context = expression.arguments
        if (parent.type !== 'CallExpression') {
          expression = {
            type: 'ExpressionStatement',
            expression: expression,
          }
        }
        parent._context.push(expression)
      }
    }
  })
  return newAst
}
function transformer ( ast ) { let newAst = { type : 'Program' , body : [ ] } ast . _context = newAst . body traverser ( ast , { NumberLiteral : { enter ( node , parent ) { parent . _context . push ( { type : 'NumberLiteral' , value : node . value } ) } } , StringLiteral : { enter ( node , parent ) { parent . _context . push ( { type : 'StringLiteral' , value : node . value , } ) } } , CallExpression : { enter ( node , parent ) { let expression = { type : 'CallExpression' , callee : { type : 'Identifier' , name : node . name , } , arguments : [ ] , } node . _context = expression . arguments if ( parent . type !== 'CallExpression' ) { expression = { type : 'ExpressionStatement' , expression : expression , } } parent . _context . push ( expression ) } } } ) return newAst }
Next up, the transformer.
Next up the transformer .
// We start creating a new node `CallExpression` with a nested // `Identifier`. // Next we're going to define a new context on the original // `CallExpression` node that will reference the `expression`'s arguments // so that we can push arguments. // Then we're going to check if the parent node is a `CallExpression`. // If it is not... // We're going to wrap our `CallExpression` node with an // `ExpressionStatement`. We do this because the top level // `CallExpression` in JavaScript are actually statements. // Last, we push our (possibly wrapped) `CallExpression` to the `parent`'s // `context`.