leap.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /**
  2. * Copyright (c) 2014, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
  7. * additional grant of patent rights can be found in the PATENTS file in
  8. * the same directory.
  9. */
  10. var assert = require("assert");
  11. var types = require("ast-types");
  12. var n = types.namedTypes;
  13. var b = types.builders;
  14. var inherits = require("util").inherits;
  15. var hasOwn = Object.prototype.hasOwnProperty;
  16. function Entry() {
  17. assert.ok(this instanceof Entry);
  18. }
  19. function FunctionEntry(returnLoc) {
  20. Entry.call(this);
  21. n.Literal.assert(returnLoc);
  22. this.returnLoc = returnLoc;
  23. }
  24. inherits(FunctionEntry, Entry);
  25. exports.FunctionEntry = FunctionEntry;
  26. function LoopEntry(breakLoc, continueLoc, label) {
  27. Entry.call(this);
  28. n.Literal.assert(breakLoc);
  29. n.Literal.assert(continueLoc);
  30. if (label) {
  31. n.Identifier.assert(label);
  32. } else {
  33. label = null;
  34. }
  35. this.breakLoc = breakLoc;
  36. this.continueLoc = continueLoc;
  37. this.label = label;
  38. }
  39. inherits(LoopEntry, Entry);
  40. exports.LoopEntry = LoopEntry;
  41. function SwitchEntry(breakLoc) {
  42. Entry.call(this);
  43. n.Literal.assert(breakLoc);
  44. this.breakLoc = breakLoc;
  45. }
  46. inherits(SwitchEntry, Entry);
  47. exports.SwitchEntry = SwitchEntry;
  48. function TryEntry(firstLoc, catchEntry, finallyEntry) {
  49. Entry.call(this);
  50. n.Literal.assert(firstLoc);
  51. if (catchEntry) {
  52. assert.ok(catchEntry instanceof CatchEntry);
  53. } else {
  54. catchEntry = null;
  55. }
  56. if (finallyEntry) {
  57. assert.ok(finallyEntry instanceof FinallyEntry);
  58. } else {
  59. finallyEntry = null;
  60. }
  61. // Have to have one or the other (or both).
  62. assert.ok(catchEntry || finallyEntry);
  63. this.firstLoc = firstLoc;
  64. this.catchEntry = catchEntry;
  65. this.finallyEntry = finallyEntry;
  66. }
  67. inherits(TryEntry, Entry);
  68. exports.TryEntry = TryEntry;
  69. function CatchEntry(firstLoc, paramId) {
  70. Entry.call(this);
  71. n.Literal.assert(firstLoc);
  72. n.Identifier.assert(paramId);
  73. this.firstLoc = firstLoc;
  74. this.paramId = paramId;
  75. }
  76. inherits(CatchEntry, Entry);
  77. exports.CatchEntry = CatchEntry;
  78. function FinallyEntry(firstLoc, afterLoc) {
  79. Entry.call(this);
  80. n.Literal.assert(firstLoc);
  81. n.Literal.assert(afterLoc);
  82. this.firstLoc = firstLoc;
  83. this.afterLoc = afterLoc;
  84. }
  85. inherits(FinallyEntry, Entry);
  86. exports.FinallyEntry = FinallyEntry;
  87. function LabeledEntry(breakLoc, label) {
  88. Entry.call(this);
  89. n.Literal.assert(breakLoc);
  90. n.Identifier.assert(label);
  91. this.breakLoc = breakLoc;
  92. this.label = label;
  93. }
  94. inherits(LabeledEntry, Entry);
  95. exports.LabeledEntry = LabeledEntry;
  96. function LeapManager(emitter) {
  97. assert.ok(this instanceof LeapManager);
  98. var Emitter = require("./emit").Emitter;
  99. assert.ok(emitter instanceof Emitter);
  100. this.emitter = emitter;
  101. this.entryStack = [new FunctionEntry(emitter.finalLoc)];
  102. }
  103. var LMp = LeapManager.prototype;
  104. exports.LeapManager = LeapManager;
  105. LMp.withEntry = function(entry, callback) {
  106. assert.ok(entry instanceof Entry);
  107. this.entryStack.push(entry);
  108. try {
  109. callback.call(this.emitter);
  110. } finally {
  111. var popped = this.entryStack.pop();
  112. assert.strictEqual(popped, entry);
  113. }
  114. };
  115. LMp._findLeapLocation = function(property, label) {
  116. for (var i = this.entryStack.length - 1; i >= 0; --i) {
  117. var entry = this.entryStack[i];
  118. var loc = entry[property];
  119. if (loc) {
  120. if (label) {
  121. if (entry.label &&
  122. entry.label.name === label.name) {
  123. return loc;
  124. }
  125. } else if (entry instanceof LabeledEntry) {
  126. // Ignore LabeledEntry entries unless we are actually breaking to
  127. // a label.
  128. } else {
  129. return loc;
  130. }
  131. }
  132. }
  133. return null;
  134. };
  135. LMp.getBreakLoc = function(label) {
  136. return this._findLeapLocation("breakLoc", label);
  137. };
  138. LMp.getContinueLoc = function(label) {
  139. return this._findLeapLocation("continueLoc", label);
  140. };