index.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.Token = undefined;
  6. var _createClass2 = require("babel-runtime/helpers/createClass");
  7. var _createClass3 = _interopRequireDefault(_createClass2);
  8. var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
  9. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  10. var _identifier = require("../util/identifier");
  11. var _types = require("./types");
  12. var _context = require("./context");
  13. var _location = require("../util/location");
  14. var _whitespace = require("../util/whitespace");
  15. var _state = require("./state");
  16. var _state2 = _interopRequireDefault(_state);
  17. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  18. // Object type used to represent tokens. Note that normally, tokens
  19. // simply exist as properties on the parser object. This is only
  20. // used for the onToken callback and the external tokenizer.
  21. var Token = exports.Token = function Token(state) {
  22. (0, _classCallCheck3.default)(this, Token);
  23. this.type = state.type;
  24. this.value = state.value;
  25. this.start = state.start;
  26. this.end = state.end;
  27. this.loc = new _location.SourceLocation(state.startLoc, state.endLoc);
  28. };
  29. // ## Tokenizer
  30. /* eslint max-len: 0 */
  31. /* eslint indent: 0 */
  32. function codePointToString(code) {
  33. // UTF-16 Decoding
  34. if (code <= 0xFFFF) {
  35. return String.fromCharCode(code);
  36. } else {
  37. return String.fromCharCode((code - 0x10000 >> 10) + 0xD800, (code - 0x10000 & 1023) + 0xDC00);
  38. }
  39. }
  40. var Tokenizer = function () {
  41. function Tokenizer(options, input) {
  42. (0, _classCallCheck3.default)(this, Tokenizer);
  43. this.state = new _state2.default();
  44. this.state.init(options, input);
  45. }
  46. // Move to the next token
  47. (0, _createClass3.default)(Tokenizer, [{
  48. key: "next",
  49. value: function next() {
  50. if (!this.isLookahead) {
  51. this.state.tokens.push(new Token(this.state));
  52. }
  53. this.state.lastTokEnd = this.state.end;
  54. this.state.lastTokStart = this.state.start;
  55. this.state.lastTokEndLoc = this.state.endLoc;
  56. this.state.lastTokStartLoc = this.state.startLoc;
  57. this.nextToken();
  58. }
  59. // TODO
  60. }, {
  61. key: "eat",
  62. value: function eat(type) {
  63. if (this.match(type)) {
  64. this.next();
  65. return true;
  66. } else {
  67. return false;
  68. }
  69. }
  70. // TODO
  71. }, {
  72. key: "match",
  73. value: function match(type) {
  74. return this.state.type === type;
  75. }
  76. // TODO
  77. }, {
  78. key: "isKeyword",
  79. value: function isKeyword(word) {
  80. return (0, _identifier.isKeyword)(word);
  81. }
  82. // TODO
  83. }, {
  84. key: "lookahead",
  85. value: function lookahead() {
  86. var old = this.state;
  87. this.state = old.clone(true);
  88. this.isLookahead = true;
  89. this.next();
  90. this.isLookahead = false;
  91. var curr = this.state.clone(true);
  92. this.state = old;
  93. return curr;
  94. }
  95. // Toggle strict mode. Re-reads the next number or string to please
  96. // pedantic tests (`"use strict"; 010;` should fail).
  97. }, {
  98. key: "setStrict",
  99. value: function setStrict(strict) {
  100. this.state.strict = strict;
  101. if (!this.match(_types.types.num) && !this.match(_types.types.string)) return;
  102. this.state.pos = this.state.start;
  103. while (this.state.pos < this.state.lineStart) {
  104. this.state.lineStart = this.input.lastIndexOf("\n", this.state.lineStart - 2) + 1;
  105. --this.state.curLine;
  106. }
  107. this.nextToken();
  108. }
  109. }, {
  110. key: "curContext",
  111. value: function curContext() {
  112. return this.state.context[this.state.context.length - 1];
  113. }
  114. // Read a single token, updating the parser object's token-related
  115. // properties.
  116. }, {
  117. key: "nextToken",
  118. value: function nextToken() {
  119. var curContext = this.curContext();
  120. if (!curContext || !curContext.preserveSpace) this.skipSpace();
  121. this.state.containsOctal = false;
  122. this.state.octalPosition = null;
  123. this.state.start = this.state.pos;
  124. this.state.startLoc = this.state.curPosition();
  125. if (this.state.pos >= this.input.length) return this.finishToken(_types.types.eof);
  126. if (curContext.override) {
  127. return curContext.override(this);
  128. } else {
  129. return this.readToken(this.fullCharCodeAtPos());
  130. }
  131. }
  132. }, {
  133. key: "readToken",
  134. value: function readToken(code) {
  135. // Identifier or keyword. '\uXXXX' sequences are allowed in
  136. // identifiers, so '\' also dispatches to that.
  137. if ((0, _identifier.isIdentifierStart)(code) || code === 92 /* '\' */) {
  138. return this.readWord();
  139. } else {
  140. return this.getTokenFromCode(code);
  141. }
  142. }
  143. }, {
  144. key: "fullCharCodeAtPos",
  145. value: function fullCharCodeAtPos() {
  146. var code = this.input.charCodeAt(this.state.pos);
  147. if (code <= 0xd7ff || code >= 0xe000) return code;
  148. var next = this.input.charCodeAt(this.state.pos + 1);
  149. return (code << 10) + next - 0x35fdc00;
  150. }
  151. }, {
  152. key: "pushComment",
  153. value: function pushComment(block, text, start, end, startLoc, endLoc) {
  154. var comment = {
  155. type: block ? "CommentBlock" : "CommentLine",
  156. value: text,
  157. start: start,
  158. end: end,
  159. loc: new _location.SourceLocation(startLoc, endLoc)
  160. };
  161. if (!this.isLookahead) {
  162. this.state.tokens.push(comment);
  163. this.state.comments.push(comment);
  164. this.addComment(comment);
  165. }
  166. }
  167. }, {
  168. key: "skipBlockComment",
  169. value: function skipBlockComment() {
  170. var startLoc = this.state.curPosition();
  171. var start = this.state.pos,
  172. end = this.input.indexOf("*/", this.state.pos += 2);
  173. if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment");
  174. this.state.pos = end + 2;
  175. _whitespace.lineBreakG.lastIndex = start;
  176. var match = void 0;
  177. while ((match = _whitespace.lineBreakG.exec(this.input)) && match.index < this.state.pos) {
  178. ++this.state.curLine;
  179. this.state.lineStart = match.index + match[0].length;
  180. }
  181. this.pushComment(true, this.input.slice(start + 2, end), start, this.state.pos, startLoc, this.state.curPosition());
  182. }
  183. }, {
  184. key: "skipLineComment",
  185. value: function skipLineComment(startSkip) {
  186. var start = this.state.pos;
  187. var startLoc = this.state.curPosition();
  188. var ch = this.input.charCodeAt(this.state.pos += startSkip);
  189. while (this.state.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) {
  190. ++this.state.pos;
  191. ch = this.input.charCodeAt(this.state.pos);
  192. }
  193. this.pushComment(false, this.input.slice(start + startSkip, this.state.pos), start, this.state.pos, startLoc, this.state.curPosition());
  194. }
  195. // Called at the start of the parse and after every token. Skips
  196. // whitespace and comments, and.
  197. }, {
  198. key: "skipSpace",
  199. value: function skipSpace() {
  200. loop: while (this.state.pos < this.input.length) {
  201. var ch = this.input.charCodeAt(this.state.pos);
  202. switch (ch) {
  203. case 32:case 160:
  204. // ' '
  205. ++this.state.pos;
  206. break;
  207. case 13:
  208. if (this.input.charCodeAt(this.state.pos + 1) === 10) {
  209. ++this.state.pos;
  210. }
  211. case 10:case 8232:case 8233:
  212. ++this.state.pos;
  213. ++this.state.curLine;
  214. this.state.lineStart = this.state.pos;
  215. break;
  216. case 47:
  217. // '/'
  218. switch (this.input.charCodeAt(this.state.pos + 1)) {
  219. case 42:
  220. // '*'
  221. this.skipBlockComment();
  222. break;
  223. case 47:
  224. this.skipLineComment(2);
  225. break;
  226. default:
  227. break loop;
  228. }
  229. break;
  230. default:
  231. if (ch > 8 && ch < 14 || ch >= 5760 && _whitespace.nonASCIIwhitespace.test(String.fromCharCode(ch))) {
  232. ++this.state.pos;
  233. } else {
  234. break loop;
  235. }
  236. }
  237. }
  238. }
  239. // Called at the end of every token. Sets `end`, `val`, and
  240. // maintains `context` and `exprAllowed`, and skips the space after
  241. // the token, so that the next one's `start` will point at the
  242. // right position.
  243. }, {
  244. key: "finishToken",
  245. value: function finishToken(type, val) {
  246. this.state.end = this.state.pos;
  247. this.state.endLoc = this.state.curPosition();
  248. var prevType = this.state.type;
  249. this.state.type = type;
  250. this.state.value = val;
  251. this.updateContext(prevType);
  252. }
  253. // ### Token reading
  254. // This is the function that is called to fetch the next token. It
  255. // is somewhat obscure, because it works in character codes rather
  256. // than characters, and because operator parsing has been inlined
  257. // into it.
  258. //
  259. // All in the name of speed.
  260. //
  261. }, {
  262. key: "readToken_dot",
  263. value: function readToken_dot() {
  264. var next = this.input.charCodeAt(this.state.pos + 1);
  265. if (next >= 48 && next <= 57) {
  266. return this.readNumber(true);
  267. }
  268. var next2 = this.input.charCodeAt(this.state.pos + 2);
  269. if (next === 46 && next2 === 46) {
  270. // 46 = dot '.'
  271. this.state.pos += 3;
  272. return this.finishToken(_types.types.ellipsis);
  273. } else {
  274. ++this.state.pos;
  275. return this.finishToken(_types.types.dot);
  276. }
  277. }
  278. }, {
  279. key: "readToken_slash",
  280. value: function readToken_slash() {
  281. // '/'
  282. if (this.state.exprAllowed) {
  283. ++this.state.pos;
  284. return this.readRegexp();
  285. }
  286. var next = this.input.charCodeAt(this.state.pos + 1);
  287. if (next === 61) {
  288. return this.finishOp(_types.types.assign, 2);
  289. } else {
  290. return this.finishOp(_types.types.slash, 1);
  291. }
  292. }
  293. }, {
  294. key: "readToken_mult_modulo",
  295. value: function readToken_mult_modulo(code) {
  296. // '%*'
  297. var type = code === 42 ? _types.types.star : _types.types.modulo;
  298. var width = 1;
  299. var next = this.input.charCodeAt(this.state.pos + 1);
  300. if (next === 42) {
  301. // '*'
  302. width++;
  303. next = this.input.charCodeAt(this.state.pos + 2);
  304. type = _types.types.exponent;
  305. }
  306. if (next === 61) {
  307. width++;
  308. type = _types.types.assign;
  309. }
  310. return this.finishOp(type, width);
  311. }
  312. }, {
  313. key: "readToken_pipe_amp",
  314. value: function readToken_pipe_amp(code) {
  315. // '|&'
  316. var next = this.input.charCodeAt(this.state.pos + 1);
  317. if (next === code) return this.finishOp(code === 124 ? _types.types.logicalOR : _types.types.logicalAND, 2);
  318. if (next === 61) return this.finishOp(_types.types.assign, 2);
  319. return this.finishOp(code === 124 ? _types.types.bitwiseOR : _types.types.bitwiseAND, 1);
  320. }
  321. }, {
  322. key: "readToken_caret",
  323. value: function readToken_caret() {
  324. // '^'
  325. var next = this.input.charCodeAt(this.state.pos + 1);
  326. if (next === 61) {
  327. return this.finishOp(_types.types.assign, 2);
  328. } else {
  329. return this.finishOp(_types.types.bitwiseXOR, 1);
  330. }
  331. }
  332. }, {
  333. key: "readToken_plus_min",
  334. value: function readToken_plus_min(code) {
  335. // '+-'
  336. var next = this.input.charCodeAt(this.state.pos + 1);
  337. if (next === code) {
  338. if (next === 45 && this.input.charCodeAt(this.state.pos + 2) === 62 && _whitespace.lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.pos))) {
  339. // A `-->` line comment
  340. this.skipLineComment(3);
  341. this.skipSpace();
  342. return this.nextToken();
  343. }
  344. return this.finishOp(_types.types.incDec, 2);
  345. }
  346. if (next === 61) {
  347. return this.finishOp(_types.types.assign, 2);
  348. } else {
  349. return this.finishOp(_types.types.plusMin, 1);
  350. }
  351. }
  352. }, {
  353. key: "readToken_lt_gt",
  354. value: function readToken_lt_gt(code) {
  355. // '<>'
  356. var next = this.input.charCodeAt(this.state.pos + 1);
  357. var size = 1;
  358. if (next === code) {
  359. size = code === 62 && this.input.charCodeAt(this.state.pos + 2) === 62 ? 3 : 2;
  360. if (this.input.charCodeAt(this.state.pos + size) === 61) return this.finishOp(_types.types.assign, size + 1);
  361. return this.finishOp(_types.types.bitShift, size);
  362. }
  363. if (next === 33 && code === 60 && this.input.charCodeAt(this.state.pos + 2) === 45 && this.input.charCodeAt(this.state.pos + 3) === 45) {
  364. if (this.inModule) this.unexpected();
  365. // `<!--`, an XML-style comment that should be interpreted as a line comment
  366. this.skipLineComment(4);
  367. this.skipSpace();
  368. return this.nextToken();
  369. }
  370. if (next === 61) {
  371. // <= | >=
  372. size = 2;
  373. }
  374. return this.finishOp(_types.types.relational, size);
  375. }
  376. }, {
  377. key: "readToken_eq_excl",
  378. value: function readToken_eq_excl(code) {
  379. // '=!'
  380. var next = this.input.charCodeAt(this.state.pos + 1);
  381. if (next === 61) return this.finishOp(_types.types.equality, this.input.charCodeAt(this.state.pos + 2) === 61 ? 3 : 2);
  382. if (code === 61 && next === 62) {
  383. // '=>'
  384. this.state.pos += 2;
  385. return this.finishToken(_types.types.arrow);
  386. }
  387. return this.finishOp(code === 61 ? _types.types.eq : _types.types.prefix, 1);
  388. }
  389. }, {
  390. key: "getTokenFromCode",
  391. value: function getTokenFromCode(code) {
  392. switch (code) {
  393. // The interpretation of a dot depends on whether it is followed
  394. // by a digit or another two dots.
  395. case 46:
  396. // '.'
  397. return this.readToken_dot();
  398. // Punctuation tokens.
  399. case 40:
  400. ++this.state.pos;return this.finishToken(_types.types.parenL);
  401. case 41:
  402. ++this.state.pos;return this.finishToken(_types.types.parenR);
  403. case 59:
  404. ++this.state.pos;return this.finishToken(_types.types.semi);
  405. case 44:
  406. ++this.state.pos;return this.finishToken(_types.types.comma);
  407. case 91:
  408. ++this.state.pos;return this.finishToken(_types.types.bracketL);
  409. case 93:
  410. ++this.state.pos;return this.finishToken(_types.types.bracketR);
  411. case 123:
  412. ++this.state.pos;return this.finishToken(_types.types.braceL);
  413. case 125:
  414. ++this.state.pos;return this.finishToken(_types.types.braceR);
  415. case 58:
  416. if (this.hasPlugin("functionBind") && this.input.charCodeAt(this.state.pos + 1) === 58) {
  417. return this.finishOp(_types.types.doubleColon, 2);
  418. } else {
  419. ++this.state.pos;
  420. return this.finishToken(_types.types.colon);
  421. }
  422. case 63:
  423. ++this.state.pos;return this.finishToken(_types.types.question);
  424. case 64:
  425. ++this.state.pos;return this.finishToken(_types.types.at);
  426. case 96:
  427. // '`'
  428. ++this.state.pos;
  429. return this.finishToken(_types.types.backQuote);
  430. case 48:
  431. // '0'
  432. var next = this.input.charCodeAt(this.state.pos + 1);
  433. if (next === 120 || next === 88) return this.readRadixNumber(16); // '0x', '0X' - hex number
  434. if (next === 111 || next === 79) return this.readRadixNumber(8); // '0o', '0O' - octal number
  435. if (next === 98 || next === 66) return this.readRadixNumber(2); // '0b', '0B' - binary number
  436. // Anything else beginning with a digit is an integer, octal
  437. // number, or float.
  438. case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:
  439. // 1-9
  440. return this.readNumber(false);
  441. // Quotes produce strings.
  442. case 34:case 39:
  443. // '"', "'"
  444. return this.readString(code);
  445. // Operators are parsed inline in tiny state machines. '=' (61) is
  446. // often referred to. `finishOp` simply skips the amount of
  447. // characters it is given as second argument, and returns a token
  448. // of the type given by its first argument.
  449. case 47:
  450. // '/'
  451. return this.readToken_slash();
  452. case 37:case 42:
  453. // '%*'
  454. return this.readToken_mult_modulo(code);
  455. case 124:case 38:
  456. // '|&'
  457. return this.readToken_pipe_amp(code);
  458. case 94:
  459. // '^'
  460. return this.readToken_caret();
  461. case 43:case 45:
  462. // '+-'
  463. return this.readToken_plus_min(code);
  464. case 60:case 62:
  465. // '<>'
  466. return this.readToken_lt_gt(code);
  467. case 61:case 33:
  468. // '=!'
  469. return this.readToken_eq_excl(code);
  470. case 126:
  471. // '~'
  472. return this.finishOp(_types.types.prefix, 1);
  473. }
  474. this.raise(this.state.pos, "Unexpected character '" + codePointToString(code) + "'");
  475. }
  476. }, {
  477. key: "finishOp",
  478. value: function finishOp(type, size) {
  479. var str = this.input.slice(this.state.pos, this.state.pos + size);
  480. this.state.pos += size;
  481. return this.finishToken(type, str);
  482. }
  483. }, {
  484. key: "readRegexp",
  485. value: function readRegexp() {
  486. var escaped = void 0,
  487. inClass = void 0,
  488. start = this.state.pos;
  489. for (;;) {
  490. if (this.state.pos >= this.input.length) this.raise(start, "Unterminated regular expression");
  491. var ch = this.input.charAt(this.state.pos);
  492. if (_whitespace.lineBreak.test(ch)) {
  493. this.raise(start, "Unterminated regular expression");
  494. }
  495. if (escaped) {
  496. escaped = false;
  497. } else {
  498. if (ch === "[") {
  499. inClass = true;
  500. } else if (ch === "]" && inClass) {
  501. inClass = false;
  502. } else if (ch === "/" && !inClass) {
  503. break;
  504. }
  505. escaped = ch === "\\";
  506. }
  507. ++this.state.pos;
  508. }
  509. var content = this.input.slice(start, this.state.pos);
  510. ++this.state.pos;
  511. // Need to use `readWord1` because '\uXXXX' sequences are allowed
  512. // here (don't ask).
  513. var mods = this.readWord1();
  514. if (mods) {
  515. var validFlags = /^[gmsiyu]*$/;
  516. if (!validFlags.test(mods)) this.raise(start, "Invalid regular expression flag");
  517. }
  518. return this.finishToken(_types.types.regexp, {
  519. pattern: content,
  520. flags: mods
  521. });
  522. }
  523. // Read an integer in the given radix. Return null if zero digits
  524. // were read, the integer value otherwise. When `len` is given, this
  525. // will return `null` unless the integer has exactly `len` digits.
  526. }, {
  527. key: "readInt",
  528. value: function readInt(radix, len) {
  529. var start = this.state.pos,
  530. total = 0;
  531. for (var i = 0, e = len == null ? Infinity : len; i < e; ++i) {
  532. var code = this.input.charCodeAt(this.state.pos),
  533. val = void 0;
  534. if (code >= 97) {
  535. val = code - 97 + 10; // a
  536. } else if (code >= 65) {
  537. val = code - 65 + 10; // A
  538. } else if (code >= 48 && code <= 57) {
  539. val = code - 48; // 0-9
  540. } else {
  541. val = Infinity;
  542. }
  543. if (val >= radix) break;
  544. ++this.state.pos;
  545. total = total * radix + val;
  546. }
  547. if (this.state.pos === start || len != null && this.state.pos - start !== len) return null;
  548. return total;
  549. }
  550. }, {
  551. key: "readRadixNumber",
  552. value: function readRadixNumber(radix) {
  553. this.state.pos += 2; // 0x
  554. var val = this.readInt(radix);
  555. if (val == null) this.raise(this.state.start + 2, "Expected number in radix " + radix);
  556. if ((0, _identifier.isIdentifierStart)(this.fullCharCodeAtPos())) this.raise(this.state.pos, "Identifier directly after number");
  557. return this.finishToken(_types.types.num, val);
  558. }
  559. // Read an integer, octal integer, or floating-point number.
  560. }, {
  561. key: "readNumber",
  562. value: function readNumber(startsWithDot) {
  563. var start = this.state.pos,
  564. isFloat = false,
  565. octal = this.input.charCodeAt(this.state.pos) === 48;
  566. if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number");
  567. var next = this.input.charCodeAt(this.state.pos);
  568. if (next === 46) {
  569. // '.'
  570. ++this.state.pos;
  571. this.readInt(10);
  572. isFloat = true;
  573. next = this.input.charCodeAt(this.state.pos);
  574. }
  575. if (next === 69 || next === 101) {
  576. // 'eE'
  577. next = this.input.charCodeAt(++this.state.pos);
  578. if (next === 43 || next === 45) ++this.state.pos; // '+-'
  579. if (this.readInt(10) === null) this.raise(start, "Invalid number");
  580. isFloat = true;
  581. }
  582. if ((0, _identifier.isIdentifierStart)(this.fullCharCodeAtPos())) this.raise(this.state.pos, "Identifier directly after number");
  583. var str = this.input.slice(start, this.state.pos),
  584. val = void 0;
  585. if (isFloat) {
  586. val = parseFloat(str);
  587. } else if (!octal || str.length === 1) {
  588. val = parseInt(str, 10);
  589. } else if (/[89]/.test(str) || this.state.strict) {
  590. this.raise(start, "Invalid number");
  591. } else {
  592. val = parseInt(str, 8);
  593. }
  594. return this.finishToken(_types.types.num, val);
  595. }
  596. // Read a string value, interpreting backslash-escapes.
  597. }, {
  598. key: "readCodePoint",
  599. value: function readCodePoint() {
  600. var ch = this.input.charCodeAt(this.state.pos),
  601. code = void 0;
  602. if (ch === 123) {
  603. var codePos = ++this.state.pos;
  604. code = this.readHexChar(this.input.indexOf("}", this.state.pos) - this.state.pos);
  605. ++this.state.pos;
  606. if (code > 0x10FFFF) this.raise(codePos, "Code point out of bounds");
  607. } else {
  608. code = this.readHexChar(4);
  609. }
  610. return code;
  611. }
  612. }, {
  613. key: "readString",
  614. value: function readString(quote) {
  615. var out = "",
  616. chunkStart = ++this.state.pos;
  617. for (;;) {
  618. if (this.state.pos >= this.input.length) this.raise(this.state.start, "Unterminated string constant");
  619. var ch = this.input.charCodeAt(this.state.pos);
  620. if (ch === quote) break;
  621. if (ch === 92) {
  622. // '\'
  623. out += this.input.slice(chunkStart, this.state.pos);
  624. out += this.readEscapedChar(false);
  625. chunkStart = this.state.pos;
  626. } else {
  627. if ((0, _whitespace.isNewLine)(ch)) this.raise(this.state.start, "Unterminated string constant");
  628. ++this.state.pos;
  629. }
  630. }
  631. out += this.input.slice(chunkStart, this.state.pos++);
  632. return this.finishToken(_types.types.string, out);
  633. }
  634. // Reads template string tokens.
  635. }, {
  636. key: "readTmplToken",
  637. value: function readTmplToken() {
  638. var out = "",
  639. chunkStart = this.state.pos;
  640. for (;;) {
  641. if (this.state.pos >= this.input.length) this.raise(this.state.start, "Unterminated template");
  642. var ch = this.input.charCodeAt(this.state.pos);
  643. if (ch === 96 || ch === 36 && this.input.charCodeAt(this.state.pos + 1) === 123) {
  644. // '`', '${'
  645. if (this.state.pos === this.state.start && this.match(_types.types.template)) {
  646. if (ch === 36) {
  647. this.state.pos += 2;
  648. return this.finishToken(_types.types.dollarBraceL);
  649. } else {
  650. ++this.state.pos;
  651. return this.finishToken(_types.types.backQuote);
  652. }
  653. }
  654. out += this.input.slice(chunkStart, this.state.pos);
  655. return this.finishToken(_types.types.template, out);
  656. }
  657. if (ch === 92) {
  658. // '\'
  659. out += this.input.slice(chunkStart, this.state.pos);
  660. out += this.readEscapedChar(true);
  661. chunkStart = this.state.pos;
  662. } else if ((0, _whitespace.isNewLine)(ch)) {
  663. out += this.input.slice(chunkStart, this.state.pos);
  664. ++this.state.pos;
  665. switch (ch) {
  666. case 13:
  667. if (this.input.charCodeAt(this.state.pos) === 10) ++this.state.pos;
  668. case 10:
  669. out += "\n";
  670. break;
  671. default:
  672. out += String.fromCharCode(ch);
  673. break;
  674. }
  675. ++this.state.curLine;
  676. this.state.lineStart = this.state.pos;
  677. chunkStart = this.state.pos;
  678. } else {
  679. ++this.state.pos;
  680. }
  681. }
  682. }
  683. // Used to read escaped characters
  684. }, {
  685. key: "readEscapedChar",
  686. value: function readEscapedChar(inTemplate) {
  687. var ch = this.input.charCodeAt(++this.state.pos);
  688. ++this.state.pos;
  689. switch (ch) {
  690. case 110:
  691. return "\n"; // 'n' -> '\n'
  692. case 114:
  693. return "\r"; // 'r' -> '\r'
  694. case 120:
  695. return String.fromCharCode(this.readHexChar(2)); // 'x'
  696. case 117:
  697. return codePointToString(this.readCodePoint()); // 'u'
  698. case 116:
  699. return "\t"; // 't' -> '\t'
  700. case 98:
  701. return "\b"; // 'b' -> '\b'
  702. case 118:
  703. return "\u000b"; // 'v' -> '\u000b'
  704. case 102:
  705. return "\f"; // 'f' -> '\f'
  706. case 13:
  707. if (this.input.charCodeAt(this.state.pos) === 10) ++this.state.pos; // '\r\n'
  708. case 10:
  709. // ' \n'
  710. this.state.lineStart = this.state.pos;
  711. ++this.state.curLine;
  712. return "";
  713. default:
  714. if (ch >= 48 && ch <= 55) {
  715. var octalStr = this.input.substr(this.state.pos - 1, 3).match(/^[0-7]+/)[0];
  716. var octal = parseInt(octalStr, 8);
  717. if (octal > 255) {
  718. octalStr = octalStr.slice(0, -1);
  719. octal = parseInt(octalStr, 8);
  720. }
  721. if (octal > 0) {
  722. if (!this.state.containsOctal) {
  723. this.state.containsOctal = true;
  724. this.state.octalPosition = this.state.pos - 2;
  725. }
  726. if (this.state.strict || inTemplate) {
  727. this.raise(this.state.pos - 2, "Octal literal in strict mode");
  728. }
  729. }
  730. this.state.pos += octalStr.length - 1;
  731. return String.fromCharCode(octal);
  732. }
  733. return String.fromCharCode(ch);
  734. }
  735. }
  736. // Used to read character escape sequences ('\x', '\u', '\U').
  737. }, {
  738. key: "readHexChar",
  739. value: function readHexChar(len) {
  740. var codePos = this.state.pos;
  741. var n = this.readInt(16, len);
  742. if (n === null) this.raise(codePos, "Bad character escape sequence");
  743. return n;
  744. }
  745. // Read an identifier, and return it as a string. Sets `this.state.containsEsc`
  746. // to whether the word contained a '\u' escape.
  747. //
  748. // Incrementally adds only escaped chars, adding other chunks as-is
  749. // as a micro-optimization.
  750. }, {
  751. key: "readWord1",
  752. value: function readWord1() {
  753. this.state.containsEsc = false;
  754. var word = "",
  755. first = true,
  756. chunkStart = this.state.pos;
  757. while (this.state.pos < this.input.length) {
  758. var ch = this.fullCharCodeAtPos();
  759. if ((0, _identifier.isIdentifierChar)(ch)) {
  760. this.state.pos += ch <= 0xffff ? 1 : 2;
  761. } else if (ch === 92) {
  762. // "\"
  763. this.state.containsEsc = true;
  764. word += this.input.slice(chunkStart, this.state.pos);
  765. var escStart = this.state.pos;
  766. if (this.input.charCodeAt(++this.state.pos) !== 117) {
  767. // "u"
  768. this.raise(this.state.pos, "Expecting Unicode escape sequence \\uXXXX");
  769. }
  770. ++this.state.pos;
  771. var esc = this.readCodePoint();
  772. if (!(first ? _identifier.isIdentifierStart : _identifier.isIdentifierChar)(esc, true)) {
  773. this.raise(escStart, "Invalid Unicode escape");
  774. }
  775. word += codePointToString(esc);
  776. chunkStart = this.state.pos;
  777. } else {
  778. break;
  779. }
  780. first = false;
  781. }
  782. return word + this.input.slice(chunkStart, this.state.pos);
  783. }
  784. // Read an identifier or keyword token. Will check for reserved
  785. // words when necessary.
  786. }, {
  787. key: "readWord",
  788. value: function readWord() {
  789. var word = this.readWord1();
  790. var type = _types.types.name;
  791. if (!this.state.containsEsc && this.isKeyword(word)) {
  792. type = _types.keywords[word];
  793. }
  794. return this.finishToken(type, word);
  795. }
  796. }, {
  797. key: "braceIsBlock",
  798. value: function braceIsBlock(prevType) {
  799. if (prevType === _types.types.colon) {
  800. var parent = this.curContext();
  801. if (parent === _context.types.braceStatement || parent === _context.types.braceExpression) {
  802. return !parent.isExpr;
  803. }
  804. }
  805. if (prevType === _types.types._return) {
  806. return _whitespace.lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start));
  807. }
  808. if (prevType === _types.types._else || prevType === _types.types.semi || prevType === _types.types.eof || prevType === _types.types.parenR) {
  809. return true;
  810. }
  811. if (prevType === _types.types.braceL) {
  812. return this.curContext() === _context.types.braceStatement;
  813. }
  814. return !this.state.exprAllowed;
  815. }
  816. }, {
  817. key: "updateContext",
  818. value: function updateContext(prevType) {
  819. var update = void 0,
  820. type = this.state.type;
  821. if (type.keyword && prevType === _types.types.dot) {
  822. this.state.exprAllowed = false;
  823. } else if (update = type.updateContext) {
  824. update.call(this, prevType);
  825. } else {
  826. this.state.exprAllowed = type.beforeExpr;
  827. }
  828. }
  829. }]);
  830. return Tokenizer;
  831. }();
  832. exports.default = Tokenizer;