etnbrd/flx-compiler

View on GitHub
prototypes/shreder/lib/traverse.js

Summary

Maintainability
C
1 day
Test Coverage
module.exports = {
  map: _maper(),
  reduce: _reducer()
}


/******************************************************************************/
/* MAP                                                                        */
/******************************************************************************/

function _maper() {

  function map(n, it) {

    if (it.enter)
      var res = it.enter(n);
  
    if (res)
      return res

    types[n.type](n, it);

    if (it.leave)
      res = it.leave(n);

    return res || n;
  }

  var mapers = {};
  mapers.array = function(name) {
    return function(n, it) {
      n[name] = n[name].map(function(n) {
        return map(n, it) || n;
      });
    }
  }

  mapers.single = function(name) {
    return function(n, it) {
      n[name] = map(n[name], it) || n[name];
    }
  }

  mapers.binary = function(left, right) {
    return function(n, it) {
      [left, right].forEach(function(op) {
        n[op] = map(n[op], it) || n[op];
      })
    }
  }

  mapers.end = function(n, it) {
    return false;
  }

  mapers.composite = function(childs) {
    return function(n, it) {
      for(var name in childs) {
        mapers[name](childs[name])(n, it);
      }
    }
  }

  mapers.todo = function(n, it) {
    console.log("// TODO ", n);
  }

  var types = _types(mapers);

  return map;
}


/******************************************************************************/
/* REDUCE                                                                     */
/******************************************************************************/

function _reducer() {

  function reduce(n, it) {

    function _agg(n) {
      if (n)
        return it.aggregate(it.init, n);
      else
        return it.init;
    }

    if (it.enter) {
      it.init = _agg(it.enter(n));
    }

    var res = types[n.type](n, it);

    if (it.leave) {
      it.init = _agg(it.leave(n, it.init));
    }

    return it.init;
  }

  var reducers = {};
  reducers.array = function(name) {
    return function(n, it) {
      return n[name].reduce(function(prev, n) {
        return reduce(n, it);
      }, it.init);
    }
  }

  reducers.single = function(name) {
    return function(n, it) {
      return reduce(n[name], it);
    }
  }

  reducers.binary = function(left, right) {
    return function(n, it) {
      return [left, right].reduce(function(prev, op) {
        return reduce(n[op], it);
      }, it.init)
    }
  }

  reducers.end = function(n, it) {
    return false;
  }

  reducers.composite = function(childs) {
    return function(n, it) {
      for(var name in childs) {
        it.init = reducers[name](childs[name])(n, it);;
      }

      return it.init;
    }
  }

  reducers.todo = function(n, it) {
    console.log("// TODO ", n);
  }

  var types = _types(reducers);

  return reduce;
}





/******************************************************************************/
/* WALKERS                                                                    */
/******************************************************************************/

function _types(_walkers) {

  return {
////////////////////////////////////////////////////////////////////////////////
// Programs                                                                   //
////////////////////////////////////////////////////////////////////////////////
    Program: _walkers.array("body"),

////////////////////////////////////////////////////////////////////////////////
// Statements                                                                 //
////////////////////////////////////////////////////////////////////////////////
    EmptyStatement: _walkers.todo,
    BlockStatement: _walkers.array("body"),
    ExpressionStatement: _walkers.single("expression"),
    LabeledStatement: _walkers.todo,
    IfStatement: _walkers.todo,
    SwitchStatement: _walkers.todo,
    WhileStatement: _walkers.todo,
    DoWhileStatement: _walkers.todo,
    ForStatement: _walkers.todo,
    ForInStatement: _walkers.todo,
    BreakStatement: _walkers.todo,
    ContinueStatement: _walkers.todo,
    WithStatement: _walkers.todo,
    ReturnStatement: _walkers.single("argument"),
    TryStatement: _walkers.todo,
    ThrowStatement: _walkers.todo,
    DebuggerStatement: _walkers.todo,
    LetStatement: _walkers.todo,


////////////////////////////////////////////////////////////////////////////////
// Declarations                                                               //
////////////////////////////////////////////////////////////////////////////////
    FunctionDeclaration: _walkers.composite({
      single: "id",
      array: "params",
      single: "body"
    }),
    VariableDeclaration: _walkers.array("declarations"),
    VariableDeclarator: _walkers.binary("id", "init"),

////////////////////////////////////////////////////////////////////////////////
// Expressions                                                                //
////////////////////////////////////////////////////////////////////////////////
    SequenceExpression: _walkers.todo,
    ConditionalExpression: _walkers.todo,
    UnaryExpression: _walkers.todo,
    BinaryExpression: _walkers.binary("left", "right"),
    AssignmentExpression: _walkers.binary("left", "right"),
    LogicalExpression: _walkers.binary("left", "right"),
    UpdateExpression: _walkers.todo,
    NewExpression: _walkers.todo,
    Argument: _walkers.todo,
    CallExpression: _walkers.composite({
      single: "callee",
      array: "arguments"
    }),
    MemberExpression: _walkers.binary("object", "property"),
    FunctionExpression: _walkers.composite({
      single: "id",
      array: "params",
      single: "body"
    }),
    ArrayExpression: _walkers.todo,
    ObjectExpression: _walkers.array("properties"),
    ThisExpression: _walkers.todo,
    GraphExpression: _walkers.todo,
    GraphIndexExpression: _walkers.todo,
    ComprehensionExpression: _walkers.todo,
    GeneratorExpression: _walkers.todo,
    YieldExpression: _walkers.todo,
    LetExpression: _walkers.todo,


////////////////////////////////////////////////////////////////////////////////
// Patterns                                                                   //
////////////////////////////////////////////////////////////////////////////////
    ArrayPattern: _walkers.todo,
    ObjectPattern: _walkers.todo,
    PropertyPattern: _walkers.todo,


////////////////////////////////////////////////////////////////////////////////
// Clauses                                                                    //
////////////////////////////////////////////////////////////////////////////////
    SwitchCase: _walkers.todo,
    CatchClause: _walkers.todo,
    ComprehensionBlock: _walkers.todo,


////////////////////////////////////////////////////////////////////////////////
// Miscellaneous                                                              //
////////////////////////////////////////////////////////////////////////////////
    Identifier: _walkers.end,
    Literal: _walkers.end,
    Property: _walkers.todo,

    Placeholder: _walkers.end
  }
}