etnbrd/flx-compiler

View on GitHub
prototypes/blender/lib/builders.js

Summary

Maintainability
B
4 hrs
Test Coverage
var b = require("recast").types.builders;

var errors = require("./errors");
var cons = require("./constructors");
var h = require("./helpers");

module.exports = start;

var _types = {};

function start(tree) {
  // Get the bottom nodes
  return tree.nodes.filter(function(node) {
    return tree.deps.every(function(dep) {
      return dep.id !== node.id;
    })
  }).map(function(node) {
    return _next(node, tree);
  })
}

function _next(n, c) {

  console.log(">> ", n);

  if (!n.kind)
    throw errors.missingType(n);

  if (!_types[n.kind])
    throw errors.missingHandler(n);

  return _types[n.kind](n, c);
}

/******************************************************************************************
 * TYPES                                                                                  *
 ******************************************************************************************


Programs
  program(body[, loc])

Statements
  emptyStatement([loc])
  blockStatement(body[, loc])
  expressionStatement(expr[, loc])
  labeledStatement(label, body[, loc])
  ifStatement(test, cons, alt[, loc])
  switchStatement(disc, cases, isLexical[, loc])
  whileStatement(test, body[, loc])
  doWhileStatement(body, test[, loc])
  forStatement(init, test, update, body[, loc])
  forInStatement(left, right, body, isForEach[, loc])
  breakStatement(label[, loc])
  continueStatement(label[, loc])
  withStatement(obj, body[, loc])
  returnStatement(arg[, loc])
  tryStatement(body, handlers, fin[, loc])
  throwStatement(arg[, loc])
  debuggerStatement([loc])
  letStatement(head, body[, loc])

Declarations
  functionDeclaration(name, args, body, isGenerator, isExpression[, loc])
  variableDeclaration(kind, dtors[, loc])
  variableDeclarator(patt, init[, loc])

Expressions
  sequenceExpression(exprs[, loc])
  conditionalExpression(test, cons, alt[, loc])
  unaryExpression(op, arg, isPrefix[, loc])
  binaryExpression(op, left, right[, loc])
  assignmentExpression(op, left, right[, loc])
  logicalExpression(op, left, right[, loc])
  updateExpression(op, arg, isPrefix[, loc])
  newExpression(callee, args[, loc])
  callExpression(callee, args[, loc])
  memberExpression(obj, prop, isComputed[, loc])
  functionExpression(name, args, body, isGenerator, isExpression[, loc])
  arrayExpression(elts[, loc])
  objectExpression(props[, loc])
  thisExpression([loc])
  graphExpression(index, expr[, loc])
  graphIndexExpression(index[, loc])
  comprehensionExpression(body, blocks, filter[, loc])
  generatorExpression(body, blocks, filter[, loc])
  yieldExpression(arg[, loc])
  letExpression(head, body[, loc])

Patterns
  arrayPattern(elts[, loc])
  objectPattern(props[, loc])
  propertyPattern(key, patt[, loc])

Clauses
  switchCase(test, cons[, loc])
  catchClause(arg, guard, body[, loc])
  comprehensionBlock(left, right, isForEach[, loc])

Miscellaneous
  identifier(name[, loc])
  literal(val[, loc])
  property(kind, key, val[, loc])

*/

////////////////////////////////////////////////////////////////////////////////
// Programs                                                                   //
////////////////////////////////////////////////////////////////////////////////

//   program(body[, loc])

////////////////////////////////////////////////////////////////////////////////
// Statements                                                                 //
////////////////////////////////////////////////////////////////////////////////

//   emptyStatement([loc])
// TODO

//   blockStatement(body[, loc])
// TODO

//   expressionStatement(expr[, loc])
// TODO

//   labeledStatement(label, body[, loc])
// TODO

//   ifStatement(test, cons, alt[, loc])
// TODO

//   switchStatement(disc, cases, isLexical[, loc])
// TODO

//   whileStatement(test, body[, loc])
// TODO

//   doWhileStatement(body, test[, loc])
// TODO

//   forStatement(init, test, update, body[, loc])
// TODO

//   forInStatement(left, right, body, isForEach[, loc])
// TODO

//   breakStatement(label[, loc])
// TODO

//   continueStatement(label[, loc])
// TODO

//   withStatement(obj, body[, loc])
// TODO

//   returnStatement(arg[, loc])
// TODO

//   tryStatement(body, handlers, fin[, loc])
// TODO

//   throwStatement(arg[, loc])
// TODO

//   debuggerStatement([loc])
// TODO

//   letStatement(head, body[, loc])
// TODO


////////////////////////////////////////////////////////////////////////////////
// Declarations                                                               //
////////////////////////////////////////////////////////////////////////////////

//   functionDeclaration(name, args, body, isGenerator, isExpression[, loc])
// TODO

//   variableDeclaration(kind, dtors[, loc])
// TODO

//   variableDeclarator(patt, init[, loc])
_types.VariableDeclarator = function(n, t) {

  // TODO we might not find Assignment dependency, but there is still other dependency, like VariableDeclarator
  // but if variable is global, need to put it in a different chain of compilation.
  // We could return {global: [], local: []} and a peeler function to plug everything correctly by merging stuffs.

  var upwards = t.deps.filter(h.toFinder(n.id));
  if (upwards.length > 1) throw errors.multipleOccurences(upwards);
  else  upwards = upwards[0];

  if (upwards && (upwards.type == "Assignment" || upwards.type === "VariableDeclarator")) {
    var up = t.nodes.filter(h.idFinder(upwards.id));
    if (up.length > 1) throw errors.multipleOccurences(up);
    else  up = up[0];

    var id = _types.Identifier(n, t); // TODO bad design
    var ass = _next(up, t);

  
    return b.variableDeclarator(id, ass);
  } else {
    return this.Identifier(n, t);
  }
}

////////////////////////////////////////////////////////////////////////////////
// Expressions                                                                //
////////////////////////////////////////////////////////////////////////////////

//   sequenceExpression(exprs[, loc])
// TODO

//   conditionalExpression(test, cons, alt[, loc])
// TODO

//   unaryExpression(op, arg, isPrefix[, loc])
// TODO

//   binaryExpression(op, left, right[, loc])
_types.BinaryExpression = function(n, t) {
  var ops = ['left', 'right'].map(function(op) {
    // transform the op name in their respective dependencies
    return t.deps.filter(function(dep) {
      return dep.to === n.id && dep.side === op;
    })[0]
  }).map(function(op) {
    // transform the dependencies in their respective up nodes
    return t.nodes.filter(function(n) {
      return n.id === op.id
    })[0] // TODO might lead to some problems
  }).map(function(op) {
    // build the nodes
    return _next(op, t);
  })

  ops.unshift(n.operator);

  return b.binaryExpression.apply(this, ops);
}

//   assignmentExpression(op, left, right[, loc])
// TODO

//   logicalExpression(op, left, right[, loc])
// TODO

//   updateExpression(op, arg, isPrefix[, loc])
// TODO

//   newExpression(callee, args[, loc])
// TODO

//   callExpression(callee, args[, loc])
// TODO

//   memberExpression(obj, prop, isComputed[, loc])
_types.MemberExpression = function(n, t) {
  var ops = ['object', 'property'].map(function(op) {
    // transform the op name in their respective dependencies
    return t.deps.filter(function(dep) {
      return dep.to === n.id && dep.type === op;
    })[0]
  }).map(function(op) {
    // transform the dependencies in their respective up nodes
    return t.nodes.filter(function(node) {
      return node.id === op.id
    })[0]
  }).map(function(op) {
    // build the nodes
    return _next(op, t);
  })

  ops.push(false) // isComputed ?

  // TODO bad design, this shouldn't be here, should be gathered for every nodes.
  // Detect every upwards dependencies, then process them with the types constructor.
  var upwards = t.deps.filter(h.customFinder({to: node.id, type: "Assignment"}));
  if (upwards.length > 1) throw errors.multipleOccurences(upwards);

  console.log(t.deps);

  if (upwards.length > 0) { // There is an assignement
    var _node = t.nodes.find(function(node) {
      return node.id === upwards.id;
    })

    return b.assignmentExpression(upwards.operator, b.memberExpression.apply(this, ops), _next(_node, t) )
  } else {
    return b.memberExpression.apply(this, ops);
  }

}

//   functionExpression(name, args, body, isGenerator, isExpression[, loc])
// TODO

//   arrayExpression(elts[, loc])
// TODO

//   objectExpression(props[, loc])
// TODO

//   thisExpression([loc])
_types.ThisExpression = function(n, t) {
  return b.thisExpression();
}

//   graphExpression(index, expr[, loc])
// TODO

//   graphIndexExpression(index[, loc])
// TODO

//   comprehensionExpression(body, blocks, filter[, loc])
// TODO

//   generatorExpression(body, blocks, filter[, loc])
// TODO

//   yieldExpression(arg[, loc])
// TODO

//   letExpression(head, body[, loc])
// TODO


////////////////////////////////////////////////////////////////////////////////
// Patterns                                                                   //
////////////////////////////////////////////////////////////////////////////////

//   arrayPattern(elts[, loc])
// TODO

//   objectPattern(props[, loc])
// TODO

//   propertyPattern(key, patt[, loc])
// TODO


////////////////////////////////////////////////////////////////////////////////
// Clauses                                                                    //
////////////////////////////////////////////////////////////////////////////////

//   switchCase(test, cons[, loc])
// TODO

//   catchClause(arg, guard, body[, loc])
// TODO

//   comprehensionBlock(left, right, isForEach[, loc])
// TODO


////////////////////////////////////////////////////////////////////////////////
// Miscellaneous                                                              //
////////////////////////////////////////////////////////////////////////////////

//   identifier(name[, loc])
_types.Identifier = function(n, t) {
  return b.identifier(n.name);
}

//   literal(val[, loc])
_types.Literal = function(n, t) {
  var lit = b.literal(n.name);
  return lit;
}

//   property(kind, key, val[, loc])
// TODO