Пример #1
0
  AwaitExpression: function(path) {
    // Convert await expressions to yield expressions.
    let argument = path.node.argument;

    // Transforming `await x` to `yield regeneratorRuntime.awrap(x)`
    // causes the argument to be wrapped in such a way that the runtime
    // can distinguish between awaited and merely yielded values.
    util.replaceWithOrRemove(path, t.yieldExpression(
      t.callExpression(
        util.runtimeProperty("awrap"),
        [argument]
      ),
      false
    ));
  }
Пример #2
0
export default function (path: NodePath, scope = path.scope) {
  let { node } = path;
  let container = t.functionExpression(null, [], node.body, node.generator, node.async);

  let callee = container;
  let args   = [];

  // todo: only hoist if necessary
  hoistVariables(path, id => scope.push({ id }));

  let state = {
    foundThis: false,
    foundArguments: false
  };

  path.traverse(visitor, state);

  if (state.foundArguments) {
    callee = t.memberExpression(container, t.identifier("apply"));
    args = [];

    if (state.foundThis) {
      args.push(t.thisExpression());
    }

    if (state.foundArguments) {
      if (!state.foundThis) args.push(t.nullLiteral());
      args.push(t.identifier("arguments"));
    }
  }

  let call = t.callExpression(callee, args);
  if (node.generator) call = t.yieldExpression(call, true);

  return t.returnStatement(call);
}
Пример #3
0
  wrapClosure() {
    let block = this.block;

    let outsideRefs = this.outsideLetReferences;

    // remap loop heads with colliding variables
    if (this.loop) {
      for (let name in outsideRefs) {
        let id = outsideRefs[name];

        if (this.scope.hasGlobal(id.name) || this.scope.parentHasBinding(id.name)) {
          delete outsideRefs[id.name];
          delete this.letReferences[id.name];

          this.scope.rename(id.name);

          this.letReferences[id.name] = id;
          outsideRefs[id.name] = id;
        }
      }
    }

    // if we're inside of a for loop then we search to see if there are any
    // `break`s, `continue`s, `return`s etc
    this.has = this.checkLoop();

    // hoist let references to retain scope
    this.hoistVarDeclarations();

    // turn outsideLetReferences into an array
    let params = values(outsideRefs);
    let args   = values(outsideRefs);

    // build the closure that we're going to wrap the block with
    let fn = t.functionExpression(null, params, t.blockStatement(block.body));
    fn.shadow = true;

    // continuation
    this.addContinuations(fn);

    // replace the current block body with the one we're going to build
    block.body = this.body;

    let ref = fn;

    if (this.loop) {
      ref = this.scope.generateUidIdentifier("loop");
      this.loopPath.insertBefore(t.variableDeclaration("var", [
        t.variableDeclarator(ref, fn)
      ]));
    }

    // build a call and a unique id that we can assign the return value to
    let call = t.callExpression(ref, args);
    let ret  = this.scope.generateUidIdentifier("ret");

    // handle generators
    let hasYield = traverse.hasType(fn.body, this.scope, "YieldExpression", t.FUNCTION_TYPES);
    if (hasYield) {
      fn.generator = true;
      call = t.yieldExpression(call, true);
    }

    // handlers async functions
    let hasAsync = traverse.hasType(fn.body, this.scope, "AwaitExpression", t.FUNCTION_TYPES);
    if (hasAsync) {
      fn.async = true;
      call = t.awaitExpression(call);
    }

    this.buildClosure(ret, call);
  }