"use strict"; exports.__esModule = true; exports.Token = undefined; var _identifier = require("../util/identifier"); var _types = require("./types"); var _context = require("./context"); var _location = require("../util/location"); var _whitespace = require("../util/whitespace"); var _state = require("./state"); var _state2 = _interopRequireDefault(_state); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* eslint max-len: 0 */ /* eslint indent: 0 */ // Object type used to represent tokens. Note that normally, tokens // simply exist as properties on the parser object. This is only // used for the onToken callback and the external tokenizer. var Token = exports.Token = function Token(state) { _classCallCheck(this, Token); this.type = state.type; this.value = state.value; this.start = state.start; this.end = state.end; this.loc = new _location.SourceLocation(state.startLoc, state.endLoc); }; // ## Tokenizer function codePointToString(code) { // UTF-16 Decoding if (code <= 0xFFFF) { return String.fromCharCode(code); } else { return String.fromCharCode((code - 0x10000 >> 10) + 0xD800, (code - 0x10000 & 1023) + 0xDC00); } } var Tokenizer = function () { function Tokenizer(options, input) { _classCallCheck(this, Tokenizer); this.state = new _state2.default(); this.state.init(options, input); } // Move to the next token Tokenizer.prototype.next = function next() { if (!this.isLookahead) { this.state.tokens.push(new Token(this.state)); } this.state.lastTokEnd = this.state.end; this.state.lastTokStart = this.state.start; this.state.lastTokEndLoc = this.state.endLoc; this.state.lastTokStartLoc = this.state.startLoc; this.nextToken(); }; // TODO Tokenizer.prototype.eat = function eat(type) { if (this.match(type)) { this.next(); return true; } else { return false; } }; // TODO Tokenizer.prototype.match = function match(type) { return this.state.type === type; }; // TODO Tokenizer.prototype.isKeyword = function isKeyword(word) { return (0, _identifier.isKeyword)(word); }; // TODO Tokenizer.prototype.lookahead = function lookahead() { var old = this.state; this.state = old.clone(true); this.isLookahead = true; this.next(); this.isLookahead = false; var curr = this.state.clone(true); this.state = old; return curr; }; // Toggle strict mode. Re-reads the next number or string to please // pedantic tests (`"use strict"; 010;` should fail). Tokenizer.prototype.setStrict = function setStrict(strict) { this.state.strict = strict; if (!this.match(_types.types.num) && !this.match(_types.types.string)) return; this.state.pos = this.state.start; while (this.state.pos < this.state.lineStart) { this.state.lineStart = this.input.lastIndexOf("\n", this.state.lineStart - 2) + 1; --this.state.curLine; } this.nextToken(); }; Tokenizer.prototype.curContext = function curContext() { return this.state.context[this.state.context.length - 1]; }; // Read a single token, updating the parser object's token-related // properties. Tokenizer.prototype.nextToken = function nextToken() { var curContext = this.curContext(); if (!curContext || !curContext.preserveSpace) this.skipSpace(); this.state.containsOctal = false; this.state.octalPosition = null; this.state.start = this.state.pos; this.state.startLoc = this.state.curPosition(); if (this.state.pos >= this.input.length) return this.finishToken(_types.types.eof); if (curContext.override) { return curContext.override(this); } else { return this.readToken(this.fullCharCodeAtPos()); } }; Tokenizer.prototype.readToken = function readToken(code) { // Identifier or keyword. '\uXXXX' sequences are allowed in // identifiers, so '\' also dispatches to that. if ((0, _identifier.isIdentifierStart)(code) || code === 92 /* '\' */) { return this.readWord(); } else { return this.getTokenFromCode(code); } }; Tokenizer.prototype.fullCharCodeAtPos = function fullCharCodeAtPos() { var code = this.input.charCodeAt(this.state.pos); if (code <= 0xd7ff || code >= 0xe000) return code; var next = this.input.charCodeAt(this.state.pos + 1); return (code << 10) + next - 0x35fdc00; }; Tokenizer.prototype.pushComment = function pushComment(block, text, start, end, startLoc, endLoc) { var comment = { type: block ? "CommentBlock" : "CommentLine", value: text, start: start, end: end, loc: new _location.SourceLocation(startLoc, endLoc) }; if (!this.isLookahead) { this.state.tokens.push(comment); this.state.comments.push(comment); this.addComment(comment); } }; Tokenizer.prototype.skipBlockComment = function skipBlockComment() { var startLoc = this.state.curPosition(); var start = this.state.pos, end = this.input.indexOf("*/", this.state.pos += 2); if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment"); this.state.pos = end + 2; _whitespace.lineBreakG.lastIndex = start; var match = void 0; while ((match = _whitespace.lineBreakG.exec(this.input)) && match.index < this.state.pos) { ++this.state.curLine; this.state.lineStart = match.index + match[0].length; } this.pushComment(true, this.input.slice(start + 2, end), start, this.state.pos, startLoc, this.state.curPosition()); }; Tokenizer.prototype.skipLineComment = function skipLineComment(startSkip) { var start = this.state.pos; var startLoc = this.state.curPosition(); var ch = this.input.charCodeAt(this.state.pos += startSkip); while (this.state.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { ++this.state.pos; ch = this.input.charCodeAt(this.state.pos); } this.pushComment(false, this.input.slice(start + startSkip, this.state.pos), start, this.state.pos, startLoc, this.state.curPosition()); }; // Called at the start of the parse and after every token. Skips // whitespace and comments, and. Tokenizer.prototype.skipSpace = function skipSpace() { loop: while (this.state.pos < this.input.length) { var ch = this.input.charCodeAt(this.state.pos); switch (ch) { case 32:case 160: // ' ' ++this.state.pos; break; case 13: if (this.input.charCodeAt(this.state.pos + 1) === 10) { ++this.state.pos; } case 10:case 8232:case 8233: ++this.state.pos; ++this.state.curLine; this.state.lineStart = this.state.pos; break; case 47: // '/' switch (this.input.charCodeAt(this.state.pos + 1)) { case 42: // '*' this.skipBlockComment(); break; case 47: this.skipLineComment(2); break; default: break loop; } break; default: if (ch > 8 && ch < 14 || ch >= 5760 && _whitespace.nonASCIIwhitespace.test(String.fromCharCode(ch))) { ++this.state.pos; } else { break loop; } } } }; // Called at the end of every token. Sets `end`, `val`, and // maintains `context` and `exprAllowed`, and skips the space after // the token, so that the next one's `start` will point at the // right position. Tokenizer.prototype.finishToken = function finishToken(type, val) { this.state.end = this.state.pos; this.state.endLoc = this.state.curPosition(); var prevType = this.state.type; this.state.type = type; this.state.value = val; this.updateContext(prevType); }; // ### Token reading // This is the function that is called to fetch the next token. It // is somewhat obscure, because it works in character codes rather // than characters, and because operator parsing has been inlined // into it. // // All in the name of speed. // Tokenizer.prototype.readToken_dot = function readToken_dot() { var next = this.input.charCodeAt(this.state.pos + 1); if (next >= 48 && next <= 57) { return this.readNumber(true); } var next2 = this.input.charCodeAt(this.state.pos + 2); if (next === 46 && next2 === 46) { // 46 = dot '.' this.state.pos += 3; return this.finishToken(_types.types.ellipsis); } else { ++this.state.pos; return this.finishToken(_types.types.dot); } }; Tokenizer.prototype.readToken_slash = function readToken_slash() { // '/' if (this.state.exprAllowed) { ++this.state.pos; return this.readRegexp(); } var next = this.input.charCodeAt(this.state.pos + 1); if (next === 61) { return this.finishOp(_types.types.assign, 2); } else { return this.finishOp(_types.types.slash, 1); } }; Tokenizer.prototype.readToken_mult_modulo = function readToken_mult_modulo(code) { // '%*' var type = code === 42 ? _types.types.star : _types.types.modulo; var width = 1; var next = this.input.charCodeAt(this.state.pos + 1); if (next === 42) { // '*' width++; next = this.input.charCodeAt(this.state.pos + 2); type = _types.types.exponent; } if (next === 61) { width++; type = _types.types.assign; } return this.finishOp(type, width); }; Tokenizer.prototype.readToken_pipe_amp = function readToken_pipe_amp(code) { // '|&' var next = this.input.charCodeAt(this.state.pos + 1); if (next === code) return this.finishOp(code === 124 ? _types.types.logicalOR : _types.types.logicalAND, 2); if (next === 61) return this.finishOp(_types.types.assign, 2); if (code === 124 && next === 125 && this.hasPlugin("flow")) return this.finishOp(_types.types.braceBarR, 2); return this.finishOp(code === 124 ? _types.types.bitwiseOR : _types.types.bitwiseAND, 1); }; Tokenizer.prototype.readToken_caret = function readToken_caret() { // '^' var next = this.input.charCodeAt(this.state.pos + 1); if (next === 61) { return this.finishOp(_types.types.assign, 2); } else { return this.finishOp(_types.types.bitwiseXOR, 1); } }; Tokenizer.prototype.readToken_plus_min = function readToken_plus_min(code) { // '+-' var next = this.input.charCodeAt(this.state.pos + 1); if (next === code) { if (next === 45 && this.input.charCodeAt(this.state.pos + 2) === 62 && _whitespace.lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.pos))) { // A `-->` line comment this.skipLineComment(3); this.skipSpace(); return this.nextToken(); } return this.finishOp(_types.types.incDec, 2); } if (next === 61) { return this.finishOp(_types.types.assign, 2); } else { return this.finishOp(_types.types.plusMin, 1); } }; Tokenizer.prototype.readToken_lt_gt = function readToken_lt_gt(code) { // '<>' var next = this.input.charCodeAt(this.state.pos + 1); var size = 1; if (next === code) { size = code === 62 && this.input.charCodeAt(this.state.pos + 2) === 62 ? 3 : 2; if (this.input.charCodeAt(this.state.pos + size) === 61) return this.finishOp(_types.types.assign, size + 1); return this.finishOp(_types.types.bitShift, size); } if (next === 33 && code === 60 && this.input.charCodeAt(this.state.pos + 2) === 45 && this.input.charCodeAt(this.state.pos + 3) === 45) { if (this.inModule) this.unexpected(); // `