123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- import defineToJSON from '../jsutils/defineToJSON';
- import { syntaxError } from '../error/syntaxError';
- import { dedentBlockStringValue } from './blockString';
- import { TokenKind } from './tokenKind';
- export function createLexer(source, options) {
- var startOfFileToken = new Tok(TokenKind.SOF, 0, 0, 0, 0, null);
- var lexer = {
- source: source,
- options: options,
- lastToken: startOfFileToken,
- token: startOfFileToken,
- line: 1,
- lineStart: 0,
- advance: advanceLexer,
- lookahead: lookahead
- };
- return lexer;
- }
- function advanceLexer() {
- this.lastToken = this.token;
- var token = this.token = this.lookahead();
- return token;
- }
- function lookahead() {
- var token = this.token;
- if (token.kind !== TokenKind.EOF) {
- do {
-
- token = token.next || (token.next = readToken(this, token));
- } while (token.kind === TokenKind.COMMENT);
- }
- return token;
- }
- export function isPunctuatorToken(token) {
- var kind = token.kind;
- return kind === TokenKind.BANG || kind === TokenKind.DOLLAR || kind === TokenKind.AMP || kind === TokenKind.PAREN_L || kind === TokenKind.PAREN_R || kind === TokenKind.SPREAD || kind === TokenKind.COLON || kind === TokenKind.EQUALS || kind === TokenKind.AT || kind === TokenKind.BRACKET_L || kind === TokenKind.BRACKET_R || kind === TokenKind.BRACE_L || kind === TokenKind.PIPE || kind === TokenKind.BRACE_R;
- }
- function Tok(kind, start, end, line, column, prev, value) {
- this.kind = kind;
- this.start = start;
- this.end = end;
- this.line = line;
- this.column = column;
- this.value = value;
- this.prev = prev;
- this.next = null;
- }
- defineToJSON(Tok, function () {
- return {
- kind: this.kind,
- value: this.value,
- line: this.line,
- column: this.column
- };
- });
- function printCharCode(code) {
- return (
- isNaN(code) ? TokenKind.EOF :
- code < 0x007f ? JSON.stringify(String.fromCharCode(code)) :
- "\"\\u".concat(('00' + code.toString(16).toUpperCase()).slice(-4), "\"")
- );
- }
- function readToken(lexer, prev) {
- var source = lexer.source;
- var body = source.body;
- var bodyLength = body.length;
- var pos = positionAfterWhitespace(body, prev.end, lexer);
- var line = lexer.line;
- var col = 1 + pos - lexer.lineStart;
- if (pos >= bodyLength) {
- return new Tok(TokenKind.EOF, bodyLength, bodyLength, line, col, prev);
- }
- var code = body.charCodeAt(pos);
- switch (code) {
-
- case 33:
- return new Tok(TokenKind.BANG, pos, pos + 1, line, col, prev);
-
- case 35:
- return readComment(source, pos, line, col, prev);
-
- case 36:
- return new Tok(TokenKind.DOLLAR, pos, pos + 1, line, col, prev);
-
- case 38:
- return new Tok(TokenKind.AMP, pos, pos + 1, line, col, prev);
-
- case 40:
- return new Tok(TokenKind.PAREN_L, pos, pos + 1, line, col, prev);
-
- case 41:
- return new Tok(TokenKind.PAREN_R, pos, pos + 1, line, col, prev);
-
- case 46:
- if (body.charCodeAt(pos + 1) === 46 && body.charCodeAt(pos + 2) === 46) {
- return new Tok(TokenKind.SPREAD, pos, pos + 3, line, col, prev);
- }
- break;
-
- case 58:
- return new Tok(TokenKind.COLON, pos, pos + 1, line, col, prev);
-
- case 61:
- return new Tok(TokenKind.EQUALS, pos, pos + 1, line, col, prev);
-
- case 64:
- return new Tok(TokenKind.AT, pos, pos + 1, line, col, prev);
-
- case 91:
- return new Tok(TokenKind.BRACKET_L, pos, pos + 1, line, col, prev);
-
- case 93:
- return new Tok(TokenKind.BRACKET_R, pos, pos + 1, line, col, prev);
-
- case 123:
- return new Tok(TokenKind.BRACE_L, pos, pos + 1, line, col, prev);
-
- case 124:
- return new Tok(TokenKind.PIPE, pos, pos + 1, line, col, prev);
-
- case 125:
- return new Tok(TokenKind.BRACE_R, pos, pos + 1, line, col, prev);
-
- case 65:
- case 66:
- case 67:
- case 68:
- case 69:
- case 70:
- case 71:
- case 72:
- case 73:
- case 74:
- case 75:
- case 76:
- case 77:
- case 78:
- case 79:
- case 80:
- case 81:
- case 82:
- case 83:
- case 84:
- case 85:
- case 86:
- case 87:
- case 88:
- case 89:
- case 90:
- case 95:
- case 97:
- case 98:
- case 99:
- case 100:
- case 101:
- case 102:
- case 103:
- case 104:
- case 105:
- case 106:
- case 107:
- case 108:
- case 109:
- case 110:
- case 111:
- case 112:
- case 113:
- case 114:
- case 115:
- case 116:
- case 117:
- case 118:
- case 119:
- case 120:
- case 121:
- case 122:
- return readName(source, pos, line, col, prev);
-
- case 45:
- case 48:
- case 49:
- case 50:
- case 51:
- case 52:
- case 53:
- case 54:
- case 55:
- case 56:
- case 57:
- return readNumber(source, pos, code, line, col, prev);
-
- case 34:
- if (body.charCodeAt(pos + 1) === 34 && body.charCodeAt(pos + 2) === 34) {
- return readBlockString(source, pos, line, col, prev, lexer);
- }
- return readString(source, pos, line, col, prev);
- }
- throw syntaxError(source, pos, unexpectedCharacterMessage(code));
- }
- function unexpectedCharacterMessage(code) {
- if (code < 0x0020 && code !== 0x0009 && code !== 0x000a && code !== 0x000d) {
- return "Cannot contain the invalid character ".concat(printCharCode(code), ".");
- }
- if (code === 39) {
-
- return 'Unexpected single quote character (\'), did you mean to use a double quote (")?';
- }
- return "Cannot parse the unexpected character ".concat(printCharCode(code), ".");
- }
- function positionAfterWhitespace(body, startPosition, lexer) {
- var bodyLength = body.length;
- var position = startPosition;
- while (position < bodyLength) {
- var code = body.charCodeAt(position);
- if (code === 9 || code === 32 || code === 44 || code === 0xfeff) {
- ++position;
- } else if (code === 10) {
-
- ++position;
- ++lexer.line;
- lexer.lineStart = position;
- } else if (code === 13) {
-
- if (body.charCodeAt(position + 1) === 10) {
- position += 2;
- } else {
- ++position;
- }
- ++lexer.line;
- lexer.lineStart = position;
- } else {
- break;
- }
- }
- return position;
- }
- function readComment(source, start, line, col, prev) {
- var body = source.body;
- var code;
- var position = start;
- do {
- code = body.charCodeAt(++position);
- } while (!isNaN(code) && (
- code > 0x001f || code === 0x0009));
- return new Tok(TokenKind.COMMENT, start, position, line, col, prev, body.slice(start + 1, position));
- }
- function readNumber(source, start, firstCode, line, col, prev) {
- var body = source.body;
- var code = firstCode;
- var position = start;
- var isFloat = false;
- if (code === 45) {
-
- code = body.charCodeAt(++position);
- }
- if (code === 48) {
-
- code = body.charCodeAt(++position);
- if (code >= 48 && code <= 57) {
- throw syntaxError(source, position, "Invalid number, unexpected digit after 0: ".concat(printCharCode(code), "."));
- }
- } else {
- position = readDigits(source, position, code);
- code = body.charCodeAt(position);
- }
- if (code === 46) {
-
- isFloat = true;
- code = body.charCodeAt(++position);
- position = readDigits(source, position, code);
- code = body.charCodeAt(position);
- }
- if (code === 69 || code === 101) {
-
- isFloat = true;
- code = body.charCodeAt(++position);
- if (code === 43 || code === 45) {
-
- code = body.charCodeAt(++position);
- }
- position = readDigits(source, position, code);
- code = body.charCodeAt(position);
- }
- if (code === 46 || code === 69 || code === 101) {
- throw syntaxError(source, position, "Invalid number, expected digit but got: ".concat(printCharCode(code), "."));
- }
- return new Tok(isFloat ? TokenKind.FLOAT : TokenKind.INT, start, position, line, col, prev, body.slice(start, position));
- }
- function readDigits(source, start, firstCode) {
- var body = source.body;
- var position = start;
- var code = firstCode;
- if (code >= 48 && code <= 57) {
-
- do {
- code = body.charCodeAt(++position);
- } while (code >= 48 && code <= 57);
- return position;
- }
- throw syntaxError(source, position, "Invalid number, expected digit but got: ".concat(printCharCode(code), "."));
- }
- function readString(source, start, line, col, prev) {
- var body = source.body;
- var position = start + 1;
- var chunkStart = position;
- var code = 0;
- var value = '';
- while (position < body.length && !isNaN(code = body.charCodeAt(position)) &&
- code !== 0x000a && code !== 0x000d) {
-
- if (code === 34) {
- value += body.slice(chunkStart, position);
- return new Tok(TokenKind.STRING, start, position + 1, line, col, prev, value);
- }
- if (code < 0x0020 && code !== 0x0009) {
- throw syntaxError(source, position, "Invalid character within String: ".concat(printCharCode(code), "."));
- }
- ++position;
- if (code === 92) {
-
- value += body.slice(chunkStart, position - 1);
- code = body.charCodeAt(position);
- switch (code) {
- case 34:
- value += '"';
- break;
- case 47:
- value += '/';
- break;
- case 92:
- value += '\\';
- break;
- case 98:
- value += '\b';
- break;
- case 102:
- value += '\f';
- break;
- case 110:
- value += '\n';
- break;
- case 114:
- value += '\r';
- break;
- case 116:
- value += '\t';
- break;
- case 117:
- {
-
- var charCode = uniCharCode(body.charCodeAt(position + 1), body.charCodeAt(position + 2), body.charCodeAt(position + 3), body.charCodeAt(position + 4));
- if (charCode < 0) {
- var invalidSequence = body.slice(position + 1, position + 5);
- throw syntaxError(source, position, "Invalid character escape sequence: \\u".concat(invalidSequence, "."));
- }
- value += String.fromCharCode(charCode);
- position += 4;
- break;
- }
- default:
- throw syntaxError(source, position, "Invalid character escape sequence: \\".concat(String.fromCharCode(code), "."));
- }
- ++position;
- chunkStart = position;
- }
- }
- throw syntaxError(source, position, 'Unterminated string.');
- }
- function readBlockString(source, start, line, col, prev, lexer) {
- var body = source.body;
- var position = start + 3;
- var chunkStart = position;
- var code = 0;
- var rawValue = '';
- while (position < body.length && !isNaN(code = body.charCodeAt(position))) {
-
- if (code === 34 && body.charCodeAt(position + 1) === 34 && body.charCodeAt(position + 2) === 34) {
- rawValue += body.slice(chunkStart, position);
- return new Tok(TokenKind.BLOCK_STRING, start, position + 3, line, col, prev, dedentBlockStringValue(rawValue));
- }
- if (code < 0x0020 && code !== 0x0009 && code !== 0x000a && code !== 0x000d) {
- throw syntaxError(source, position, "Invalid character within String: ".concat(printCharCode(code), "."));
- }
- if (code === 10) {
-
- ++position;
- ++lexer.line;
- lexer.lineStart = position;
- } else if (code === 13) {
-
- if (body.charCodeAt(position + 1) === 10) {
- position += 2;
- } else {
- ++position;
- }
- ++lexer.line;
- lexer.lineStart = position;
- } else if (
- code === 92 && body.charCodeAt(position + 1) === 34 && body.charCodeAt(position + 2) === 34 && body.charCodeAt(position + 3) === 34) {
- rawValue += body.slice(chunkStart, position) + '"""';
- position += 4;
- chunkStart = position;
- } else {
- ++position;
- }
- }
- throw syntaxError(source, position, 'Unterminated string.');
- }
- function uniCharCode(a, b, c, d) {
- return char2hex(a) << 12 | char2hex(b) << 8 | char2hex(c) << 4 | char2hex(d);
- }
- function char2hex(a) {
- return a >= 48 && a <= 57 ? a - 48
- : a >= 65 && a <= 70 ? a - 55
- : a >= 97 && a <= 102 ? a - 87
- : -1;
- }
- function readName(source, start, line, col, prev) {
- var body = source.body;
- var bodyLength = body.length;
- var position = start + 1;
- var code = 0;
- while (position !== bodyLength && !isNaN(code = body.charCodeAt(position)) && (code === 95 ||
- code >= 48 && code <= 57 ||
- code >= 65 && code <= 90 ||
- code >= 97 && code <= 122)
- ) {
- ++position;
- }
- return new Tok(TokenKind.NAME, start, position, line, col, prev, body.slice(start, position));
- }
|