Example #1
0
  wrapSuperCall(bareSuper, superRef, thisRef, body) {
    let bareSuperNode = bareSuper.node;

    if (this.isLoose) {
      bareSuperNode.arguments.unshift(t.thisExpression());
      if (bareSuperNode.arguments.length === 2 && t.isSpreadElement(bareSuperNode.arguments[1]) && t.isIdentifier(bareSuperNode.arguments[1].argument, { name: "arguments" })) {
        // special case single arguments spread
        bareSuperNode.arguments[1] = bareSuperNode.arguments[1].argument;
        bareSuperNode.callee = t.memberExpression(superRef, t.identifier("apply"));
      } else {
        bareSuperNode.callee = t.memberExpression(superRef, t.identifier("call"));
      }
    } else {
      bareSuperNode = optimiseCall(
        t.callExpression(
          t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
          [this.classRef]
        ),
        t.thisExpression(),
        bareSuperNode.arguments
      );
    }

    let call = t.callExpression(
      this.file.addHelper("possibleConstructorReturn"),
      [t.thisExpression(), bareSuperNode]
    );

    let bareSuperAfter = this.bareSuperAfter.map((fn) => fn(thisRef));

    if (bareSuper.parentPath.isExpressionStatement() && bareSuper.parentPath.container === body.node.body && body.node.body.length - 1 === bareSuper.parentPath.key) {
      // this super call is the last statement in the body so we can just straight up
      // turn it into a return

      if (this.superThises.length || bareSuperAfter.length) {
        bareSuper.scope.push({ id: thisRef });
        call = t.assignmentExpression("=", thisRef, call);
      }

      if (bareSuperAfter.length) {
        call = t.toSequenceExpression([call, ...bareSuperAfter, thisRef]);
      }

      bareSuper.parentPath.replaceWith(t.returnStatement(call));
    } else {
      bareSuper.replaceWithMultiple([
        t.variableDeclaration("var", [
          t.variableDeclarator(thisRef, call)
        ]),
        ...bareSuperAfter,
        t.expressionStatement(thisRef)
      ]);
    }

  }
Example #2
0
function classMethod(path: NodePath, callId: Object) {
  let node = path.node;
  let body = node.body;

  node.async = false;

  let container = t.functionExpression(null, [], t.blockStatement(body.body), true);
  container.shadow = true;
  body.body = [
    t.returnStatement(t.callExpression(
      t.callExpression(callId, [container]),
      []
    ))
  ];
}
Example #3
0
File: index.js Project: ANWSY/babel
 getSuperProperty(property: Object, isComputed: boolean): Object {
   return t.callExpression(
     this.file.addHelper("get"),
     [
       t.callExpression(
         t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
         [
           this.isStatic ? this.getObjectRef() : t.memberExpression(this.getObjectRef(), t.identifier("prototype"))
         ]
       ),
       isComputed ? property : t.stringLiteral(property.name),
       t.thisExpression()
     ]
   );
 }
Example #4
0
function plainFunction(path: NodePath, callId: Object) {
  let node = path.node;

  node.async = false;
  node.generator = true;

  path.traverse(awaitVisitor);

  let built = t.callExpression(callId, [node]);
  let container = buildWrapper({
    FUNCTION: built,
    PARAMS: node.params.map(() => path.scope.generateUidIdentifier("x"))
  }).expression;

  let retFunction = container.body.body[1].argument;

  if (path.isFunctionDeclaration()) {
    let declar = t.variableDeclaration("let", [
      t.variableDeclarator(
        t.identifier(node.id.name),
        t.callExpression(container, [])
      )
    ]);
    declar._blockHoist = true;

    nameFunction({
      node: retFunction,
      parent: declar.declarations[0],
      scope: path.scope
    });

    path.replaceWith(declar);
  } else {
    nameFunction({
      node: retFunction,
      parent: path.parent,
      scope: path.scope
    });

    if (retFunction.id || node.params.length) {
      // we have an inferred function id or params so we need this wrapper
      path.replaceWith(t.callExpression(container, []));
    } else {
      // we can omit this wrapper as the conditions it protects for do not apply
      path.replaceWith(built);
    }
  }
}
Example #5
0
  run() {
    let superName = this.superName;
    let file      = this.file;
    let body      = this.body;

    //

    let constructorBody = this.constructorBody = t.blockStatement([]);
    this.constructor    = this.buildConstructor();

    //

    let closureParams = [];
    let closureArgs = [];

    //
    if (this.isDerived) {
      closureArgs.push(superName);

      superName = this.scope.generateUidIdentifierBasedOnNode(superName);
      closureParams.push(superName);

      this.superName = superName;
    }

    //
    this.buildBody();

    // make sure this class isn't directly called
    constructorBody.body.unshift(t.expressionStatement(t.callExpression(file.addHelper("classCallCheck"), [
      t.thisExpression(),
      this.classRef
    ])));

    body = body.concat(this.staticPropBody.map((fn) => fn(this.classRef)));

    if (this.classId) {
      // named class with only a constructor
      if (body.length === 1) return t.toExpression(body[0]);
    }

    //
    body.push(t.returnStatement(this.classRef));

    let container = t.functionExpression(null, closureParams, t.blockStatement(body));
    container.shadow = true;
    return t.callExpression(container, closureArgs);
  }
Example #6
0
File: index.js Project: lxe/babel
  addTemplateObject(
    helperName: string,
    strings: Array<Object>,
    raw: Object,
  ): Object {
    // Generate a unique name based on the string literals so we dedupe
    // identical strings used in the program.
    let stringIds = raw.elements.map(function(string) {
      return string.value;
    });
    let name = `${helperName}_${raw.elements.length}_${stringIds.join(",")}`;

    let declar = this.declarations[name];
    if (declar) return declar;

    let uid = this.declarations[name] = this.scope.generateUidIdentifier("templateObject");

    let helperId = this.addHelper(helperName);
    let init = t.callExpression(helperId, [strings, raw]);
    init._compact = true;
    this.scope.push({
      id: uid,
      init: init,
      _blockHoist: 1.9    // This ensures that we don't fail if not using function expression helpers
    });
    return uid;
  }
Example #7
0
 ast.program.body.forEach((node, index, body) => {
     if (node === statementPath.node) {
         body.splice(index + 1, 0, t.expressionStatement(t.callExpression(t.identifier('setStore'), [
             t.identifier(storeName)
         ])));
     }
 });
				it("does not update an object property type if the variable has been reassigned in the function call", function () {
					// arrange
					const personExpression = t.identifier("person");
					const callExpression = t.callExpression(t.identifier("setName"), [personExpression]);
					const setNameDeclaration = functionDeclaration(t.identifier("setName"), t.identifier("person")); // body is p = { name: 'Test' }

					const person = new Symbol("person", SymbolFlags.Variable);
					program.symbolTable.setSymbol(personExpression, person);
					const personType = ObjectType.create();
					context.setType(person, personType);

					const personParameter = new Symbol("person", SymbolFlags.Variable);
					program.symbolTable.setSymbol(setNameDeclaration.params[0], personParameter);

					const setNameType = new FunctionType(TypeVariable.create(), [TypeVariable.create()], VoidType.create(), setNameDeclaration);

					typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(setNameType);
					typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(personType);

					// a property name is added in the called function to the person object
					typeInferenceAnalysis.analyse = (node, typeEnvironment) => new Map([[null, typeEnvironment.setType(personParameter, ObjectType.create([[ new Symbol("name"), StringType.create() ]]))]]);

					// act
					rule.refine(callExpression, context);

					// assert
					expect(context.getType(person)).to.be.instanceOf(ObjectType);
					expect(context.getType(person).getType(new Symbol("name"))).to.be.undefined;
				});
				it("updates the types of objects when they have been passed as arguments", function () {
					// arrange
					const personExpression = t.identifier("person");
					const callExpression = t.callExpression(t.identifier("setName"), [personExpression]);
					const setNameDeclaration = functionDeclaration(t.identifier("setName"), t.identifier("person")); // body is p.name = 'Test'

					const person = new Symbol("person", SymbolFlags.Variable);
					program.symbolTable.setSymbol(personExpression, person);
					const personType = ObjectType.create();
					context.setType(person, personType);

					const personParameter = new Symbol("person", SymbolFlags.Variable);
					program.symbolTable.setSymbol(setNameDeclaration.params[0], personParameter);

					const setNameType = new FunctionType(TypeVariable.create(), [TypeVariable.create()], VoidType.create(), setNameDeclaration);

					typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(setNameType);
					typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(personType);

					// a property name is added in the called function to the person object
					typeInferenceAnalysis.analyse = (node, typeEnvironment) => new Map([[null, typeEnvironment.substitute(personType, personType.addProperty(new Symbol("name"), StringType.create()))]]);

					// act
					rule.refine(callExpression, context);

					// assert
					expect(context.getType(person)).to.be.instanceOf(ObjectType);
					expect(context.getType(person).getType(new Symbol("name"))).to.be.instanceOf(StringType);
				});
		it("returns for a call expression", function () {
			// arrange
			const node = t.callExpression(t.identifier("log"), []);

			// act, assert
			expect(rule.canRefine(node)).to.be.true;
		});
			it("adds type mappings from the function declaration context to the call context", function () {
				// arrange
				const callExpression = t.callExpression(t.identifier("log"), [t.stringLiteral("Hy")]);
				const logDeclaration = functionDeclaration(t.identifier("log"), t.identifier("m"));

				const m = new Symbol("m", SymbolFlags.Variable);
				program.symbolTable.setSymbol(logDeclaration.params[0], m);

				const x = new Symbol("x", SymbolFlags.Variable); // variable from the declaration scope
				const logType = new FunctionType(TypeVariable.create(), [TypeVariable.create()], VoidType.create(), logDeclaration);
				logType.typeEnvironment = TypeEnvironment.EMPTY.setType(x, StringType.create());

				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(logType);
				typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(StringType.create());
				typeInferenceAnalysis.analyse.withArgs(logDeclaration.body).returns(new Map([[null, TypeEnvironment.EMPTY]]));

				// act
				rule.refine(callExpression, context);

				// assert
				const analyseCall = typeInferenceAnalysis.analyse.getCall(0);
				const analyseTypeEnv = analyseCall.args[1];

				expect(analyseTypeEnv.getType(x)).to.be.instanceOf(StringType);
			});
			it("sets this to the object of the callee, if the callee is a member expression", function () {
				// arrange
				const personNode = t.identifier("person");
				const logMember = t.memberExpression(personNode, t.identifier("log"));
				const callExpression = t.callExpression(logMember, [t.stringLiteral("Hy")]);
				const logDeclaration = functionDeclaration(t.identifier("log"), t.identifier("m"));

				const m = new Symbol("m", SymbolFlags.Variable);
				program.symbolTable.setSymbol(logDeclaration.params[0], m);

				const log = new Symbol("log", SymbolFlags.Function & SymbolFlags.Property);
				const personType = ObjectType.create([[log, new FunctionType(new TypeVariable(), [], VoidType.create(), logDeclaration)]]);

				typeInferenceAnalysis.infer.withArgs(personNode).returns(personType);
				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(new FunctionType(TypeVariable.create(), [TypeVariable.create()], VoidType.create(), logDeclaration));
				typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(StringType.create());
				typeInferenceAnalysis.analyse.withArgs(logDeclaration.body).returns(new Map([[null, TypeEnvironment.EMPTY]]));

				sinon.stub(context, "getObjectType").withArgs(logMember).returns(personType);

				// act
				rule.refine(callExpression, context);

				// assert
				const analyseCall = typeInferenceAnalysis.analyse.getCall(0);
				const analyseTypeEnv = analyseCall.args[1];
				const thiz = logDeclaration.scope.resolveSymbol("this");

				expect(analyseTypeEnv.getType(thiz)).to.be.equals(personType);
			});
Example #13
0
export default function bindifyDecorators(decorators: Array<NodePath>): Array<NodePath> {
  for (let decoratorPath of decorators) {
    let decorator = decoratorPath.node;
    let expression = decorator.expression;
    if (!t.isMemberExpression(expression)) continue;

    let temp = decoratorPath.scope.maybeGenerateMemoised(expression.object);
    let ref;

    let nodes = [];

    if (temp) {
      ref = temp;
      nodes.push(t.assignmentExpression("=", temp, expression.object));
    } else {
      ref = expression.object;
    }

    nodes.push(t.callExpression(
      t.memberExpression(
        t.memberExpression(ref, expression.property, expression.computed),
        t.identifier("bind")
      ),
      [ref]
    ));

    if (nodes.length === 1) {
      decorator.expression = nodes[0];
    } else {
      decorator.expression = t.sequenceExpression(nodes);
    }
  }
}
			it("analyses the body of a callback that has been passed as argument", function () {
				// arrange
				const predicateDeclaration = functionDeclaration(t.identifier("isEven"), t.identifier("x")); // body x % 2 === 0;
				const predicate = new FunctionType(VoidType.create(), [TypeVariable.create()], TypeVariable.create(), predicateDeclaration);
				const x = new Symbol("x", SymbolFlags.Variable);
				program.symbolTable.setSymbol(predicateDeclaration.params[0], x);

				const elementType = TypeVariable.create();
				const predicateExpectedSignature = new FunctionType(VoidType.create(), [elementType], BooleanType.create());
				const filter = new FunctionType(VoidType.create(), [ArrayType.of(elementType), predicateExpectedSignature], ArrayType.of(elementType));
				const callExpression = t.callExpression(t.identifier("filter"), [t.arrayExpression([t.numericLiteral(1), t.numericLiteral(2)]), t.identifier("isEven")]);

				const callContext = context.fresh();
				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(filter);
				typeInferenceAnalysis.infer.withArgs(callExpression.arguments[0]).returns(ArrayType.of(NumberType.create()));
				typeInferenceAnalysis.infer.withArgs(callExpression.arguments[1]).returns(predicate);
				sinon.stub(context, "fresh").returns(callContext);
				sinon.stub(context, "unify").returnsArg(0); // return the actual argument type

				// unifying the parameter with the argument type requires that the type variables in the parameter type are substituted
				callContext.unify = (t1, t2) => {
					if (t1 instanceof ArrayType && t1.of instanceof NumberType && t2 instanceof ArrayType && t2.of instanceof TypeVariable) {
						callContext.substitute(t2.of, t1.of);
						return t2;
					}
				};

				// Fake analysis of the predicate function by setting the return type
				callContext.analyse = () => callContext.typeEnvironment = callContext.typeEnvironment.setType(Symbol.RETURN, BooleanType.create());

				// expect
				expect(rule.refine(callExpression, context)).to.be.instanceOf(ArrayType).and.to.have.property("of").that.is.an.instanceOf(NumberType);
			});
Example #15
0
 ast_with: function(ast) {
     let exclude = this.options.globals ? this.options.globals.concat(INTERNAL_VARIABLES) : INTERNAL_VARIABLES;
     exclude = exclude.concat(this.runtimeFunctionsUsed.map(function (name) { return 'pug_' + name; }));
     exclude.push('undefined', 'this', 'locals')
     let vars = findGlobals(t.program(ast)).map(function(v) { return v.name }).filter(function(v) { return exclude.indexOf(v) === -1 })
     if (vars.length > 0) {
       let bag = 'locals' 
       ast = [t.expressionStatement(
         t.callExpression(
           t.memberExpression(t.functionExpression(null, vars.map(function(v) { return t.identifier(v)}), t.blockStatement(ast)), t.identifier('call')),
           [ t.thisExpression() ].concat(vars.map(function(v) {
             return t.conditionalExpression(
               t.binaryExpression('in', t.stringLiteral(v), t.logicalExpression('||', t.identifier(bag), t.objectExpression([]))),
               t.memberExpression(t.logicalExpression('||', t.identifier(bag), t.objectExpression([])), t.identifier(v)),
               t.conditionalExpression(
                 t.binaryExpression('!==', t.unaryExpression('typeof', t.identifier(v)), t.stringLiteral('undefined')),
                 t.identifier(v),
                 t.identifier('undefined')
               )
             )
           }))
         ))]
       }
       return ast;
 },
Example #16
0
function getRuntimeMarkDecl(blockPath) {
  let block = blockPath.node;
  assert.ok(Array.isArray(block.body));

  let info = getMarkInfo(block);
  if (info.decl) {
    return info.decl;
  }

  info.decl = t.variableDeclaration("var", [
    t.variableDeclarator(
      blockPath.scope.generateUidIdentifier("marked"),
      t.callExpression(
        t.memberExpression(
          t.arrayExpression([]),
          t.identifier("map"),
          false
        ),
        [util.runtimeProperty("mark")]
      )
    )
  ]);

  blockPath.unshiftContainer("body", info.decl);

  return info.decl;
}
				it("detects recursive calls with the same arguments and uses the return type of the previously called function", function () {
					// arrange
					const func = functionDeclaration(t.identifier("successor"), t.identifier("x"));
					const x = new Symbol("x", SymbolFlags.Variable);
					program.symbolTable.setSymbol(func.params[0], x);

					const funcT = new FunctionType(new TypeVariable(), [], VoidType.create(), func);

					const call = t.callExpression(t.identifier("successor"), [t.numericLiteral(4)]);
					typeInferenceAnalysis.infer.withArgs(call.callee).returns(funcT);

					let analyseCount = 0;
					typeInferenceAnalysis.analyse = (node, typeEnvironment) => {
						++analyseCount;
						const recursiveCall = t.callExpression(t.identifier("successor"), [t.binaryExpression("-", t.identifier("x"), t.numericLiteral(-1))]);
						typeInferenceAnalysis.infer.withArgs(recursiveCall.callee).returns(funcT);
						program.symbolTable.setSymbol(recursiveCall.arguments[0].left, x);
						rule.refine(recursiveCall, context);

						return new Map([[null, typeEnvironment.setType(Symbol.RETURN, NumberType.create())]]);
					};

					typeInferenceAnalysis.infer.returns(NumberType.create());

					// act
					expect(rule.refine(call, context)).to.be.instanceOf(NumberType);
					expect(analyseCount).to.equals(1);
				});
Example #18
0
  // add, addCatch and addFinally were designed to be called only one time each
  // at most. Call them more at your own risk.
  //
  // addCatch() and addFinally() are not guaranteed to handle return values
  // correctly. FIXME.
  constructor(inner, dirtyAllowed, respName, errName) {
    this._inner = inner;
    this._dirtyAllowed = dirtyAllowed;
    this._respName = respName;
    this._errName = errName;

    this._ast = callExpression(memberExpression(identifier('Promise'), identifier('resolve')), []);
  }
			it("throws if the type is not a function type", function () {
				// arrange
				const callExpression = t.callExpression(t.identifier("log"), [t.stringLiteral("Hy")]);
				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(StringType.create());

				// act, assert
				expect(() => rule.refine(callExpression, context)).to.throw("Type inference failure: Cannot invoke the non function type string.");
			});
Example #20
0
export default opts => {
    const tests = opts.candidates.reduce((list, candidate) => {
        if (candidate.type === 'keyword') {
            list.push(
                createTest(candidate.value),
                createTest(candidate.value.toUpperCase()),
            );
        }
        if (candidate.type === 'data') {
            const camel = camelCase(candidate.value);
            if (fixtures[camel]) { // eslint-disable-line
                const values = fixtures[camel].fixtures; // eslint-disable-line
                list.push.apply(list, values.valid.map(fixture => {
                    return createTest(fixture);
                }));
                list.push.apply(list, values.invalid.map(fixture => {
                    return createTest(fixture, false);
                }));
                if (candidate.min === 1 && candidate.max === false && candidate.separator === ',') {
                    list.push(
                        createTest(`${values.valid[0]}, ${values.valid[0]}`),
                        createTest(`${values.valid[0]}, ${values.valid[0]},`, false),
                        createTest(`var(--foo), var(--bar)`),
                        createTest(`var(--foo), var(--bar),`, false)
                    );
                }
            }
        }
        return list;
    }, [...globals, ...globals.map(val => val.toUpperCase()), 'var(--foo)'].map(ident => createTest(ident)));
    if (opts.properties.length === 1) {
        return generateProgram([
            template(`const property = PROPERTY;`)({
                PROPERTY: t.stringLiteral(opts.properties[0]),
            }),
            template(`export default SUITE;`)({
                SUITE: t.arrayExpression(tests),
            }),
        ]);
    }
    return generateProgram([
        template(`
            export default PROPERTIES.reduce((suite, property) => {
                SUITE;

                return suite;
            }, []);
        `)({
            PROPERTIES: arrayOfStrings(opts.properties),
            SUITE: t.callExpression(
                t.memberExpression(
                    t.identifier('suite'),
                    t.identifier('push')
                ), tests),
        }),
    ]);
};
			it("infers the return type from the function signature", function () {
				// arrange
				const trimType = new FunctionType(VoidType.create(), [], StringType.create());
				const callExpression = t.callExpression(t.identifier("trim"), []);
				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(trimType);

				// act, assert
				expect(rule.refine(callExpression, context)).to.be.instanceOf(StringType);
			});
					typeInferenceAnalysis.analyse = (node, typeEnvironment) => {
						++analyseCount;
						const recursiveCall = t.callExpression(t.identifier("successor"), [t.binaryExpression("-", t.identifier("x"), t.numericLiteral(-1))]);
						typeInferenceAnalysis.infer.withArgs(recursiveCall.callee).returns(funcT);
						program.symbolTable.setSymbol(recursiveCall.arguments[0].left, x);
						rule.refine(recursiveCall, context);

						return new Map([[null, typeEnvironment.setType(Symbol.RETURN, NumberType.create())]]);
					};
			it("throws if the call misses required arguments", function () {
				// arrange
				const includesType = new FunctionType(VoidType.create(), [StringType.create()], StringType.create());
				const callExpression = t.callExpression(t.identifier("includes"), []);
				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(includesType);

				// act, assert
				expect(() => rule.refine(callExpression, context)).to.throw("Type inference failure: The argument 1 with type 'undefined' is not a subtype of the required parameter type 'string'.");
			});
			it("throws if the this type of the called function is not a subtype of the this expected by the function", function () {
				// arrange
				const trimType = new FunctionType(StringType.create(), [], StringType.create());
				const callExpression = t.callExpression(t.identifier("trim"), []);
				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(trimType);

				// act, assert
				expect(() => rule.refine(callExpression, context)).to.throw("Type inference failure: The function cannot be called with this of type 'undefined' whereas 'string' is required.");
			});
			it("returns any if the called function any", function () {
				// arrange
				const callExpression = t.callExpression(t.identifier("log"), [t.stringLiteral("Hy")]);

				typeInferenceAnalysis.infer.withArgs(callExpression.callee).returns(AnyType.create());

				// assert
				expect(rule.refine(callExpression, context)).to.be.instanceOf(AnyType);
			});
Example #26
0
var formCSSXElement = function (args, pure) {
  return t.callExpression(
    t.memberExpression(
      t.identifier('cssx'),
      t.identifier('push')
    ),
    [t.arrayExpression(args)]
  );
};
			t.switchStatement(t.identifier('variableName'), Object.keys(this.accessors).map(function(identifierName) {
				let accessOriginalVariable = noRewire(t.identifier(identifierName));

				if(this.isWildcardImport[identifierName]) {
					accessOriginalVariable = t.callExpression(filterWildcardImportIdentifier, [ accessOriginalVariable ]);
				}

				return t.switchCase(t.stringLiteral(identifierName), [ t.returnStatement(accessOriginalVariable) ] );
			}, this)),
Example #28
0
 getSuperProperty(property: Object, isComputed: boolean): Object {
   return t.callExpression(
     this.file.addHelper("get"),
     [
       getPrototypeOfExpression(this.getObjectRef(), this.isStatic),
       isComputed ? property : t.stringLiteral(property.name),
       t.thisExpression()
     ]
   );
 }
Example #29
0
Ep.getDispatchLoop = function() {
  let self = this;
  let cases = [];
  let current;

  // If we encounter a break, continue, or return statement in a switch
  // case, we can skip the rest of the statements until the next case.
  let alreadyEnded = false;

  self.listing.forEach(function(stmt, i) {
    if (self.marked.hasOwnProperty(i)) {
      cases.push(t.switchCase(
        t.numericLiteral(i),
        current = []));
      alreadyEnded = false;
    }

    if (!alreadyEnded) {
      current.push(stmt);
      if (t.isCompletionStatement(stmt))
        alreadyEnded = true;
    }
  });

  // Now that we know how many statements there will be in this.listing,
  // we can finally resolve this.finalLoc.value.
  this.finalLoc.value = this.listing.length;

  cases.push(
    t.switchCase(this.finalLoc, [
      // Intentionally fall through to the "end" case...
    ]),

    // So that the runtime can jump to the final location without having
    // to know its offset, we provide the "end" case as a synonym.
    t.switchCase(t.stringLiteral("end"), [
      // This will check/clear both context.thrown and context.rval.
      t.returnStatement(
        t.callExpression(this.contextProperty("stop"), [])
      )
    ])
  );

  return t.whileStatement(
    t.numericLiteral(1),
    t.switchStatement(
      t.assignmentExpression(
        "=",
        this.contextProperty("prev"),
        this.contextProperty("next")
      ),
      cases
    )
  );
};
const addHotAccept = (node) => {
  const acceptCall = t.callExpression(
    t.memberExpression(t.identifier('module.hot'), t.identifier('accept')),
    [t.identifier('function (err) {err && console.error(`Can not accept module: `, err)}')]
  )
  const statement = t.ifStatement(
    t.identifier('(typeof module === "object" && module.hot) && !(typeof global === "object" && global.noCycleHmr)'),
    t.expressionStatement(acceptCall)
  )
  node.body.unshift(statement);
}