| 1 | import {input, state} from "../traverser/base";
|
|---|
| 2 | import {charCodes} from "../util/charcodes";
|
|---|
| 3 | import {IS_IDENTIFIER_CHAR} from "../util/identifier";
|
|---|
| 4 | import {finishToken} from "./index";
|
|---|
| 5 | import {READ_WORD_TREE} from "./readWordTree";
|
|---|
| 6 | import {TokenType as tt} from "./types";
|
|---|
| 7 |
|
|---|
| 8 | /**
|
|---|
| 9 | * Read an identifier, producing either a name token or matching on one of the existing keywords.
|
|---|
| 10 | * For performance, we pre-generate big decision tree that we traverse. Each node represents a
|
|---|
| 11 | * prefix and has 27 values, where the first value is the token or contextual token, if any (-1 if
|
|---|
| 12 | * not), and the other 26 values are the transitions to other nodes, or -1 to stop.
|
|---|
| 13 | */
|
|---|
| 14 | export default function readWord() {
|
|---|
| 15 | let treePos = 0;
|
|---|
| 16 | let code = 0;
|
|---|
| 17 | let pos = state.pos;
|
|---|
| 18 | while (pos < input.length) {
|
|---|
| 19 | code = input.charCodeAt(pos);
|
|---|
| 20 | if (code < charCodes.lowercaseA || code > charCodes.lowercaseZ) {
|
|---|
| 21 | break;
|
|---|
| 22 | }
|
|---|
| 23 | const next = READ_WORD_TREE[treePos + (code - charCodes.lowercaseA) + 1];
|
|---|
| 24 | if (next === -1) {
|
|---|
| 25 | break;
|
|---|
| 26 | } else {
|
|---|
| 27 | treePos = next;
|
|---|
| 28 | pos++;
|
|---|
| 29 | }
|
|---|
| 30 | }
|
|---|
| 31 |
|
|---|
| 32 | const keywordValue = READ_WORD_TREE[treePos];
|
|---|
| 33 | if (keywordValue > -1 && !IS_IDENTIFIER_CHAR[code]) {
|
|---|
| 34 | state.pos = pos;
|
|---|
| 35 | if (keywordValue & 1) {
|
|---|
| 36 | finishToken(keywordValue >>> 1);
|
|---|
| 37 | } else {
|
|---|
| 38 | finishToken(tt.name, keywordValue >>> 1);
|
|---|
| 39 | }
|
|---|
| 40 | return;
|
|---|
| 41 | }
|
|---|
| 42 |
|
|---|
| 43 | while (pos < input.length) {
|
|---|
| 44 | const ch = input.charCodeAt(pos);
|
|---|
| 45 | if (IS_IDENTIFIER_CHAR[ch]) {
|
|---|
| 46 | pos++;
|
|---|
| 47 | } else if (ch === charCodes.backslash) {
|
|---|
| 48 | // \u
|
|---|
| 49 | pos += 2;
|
|---|
| 50 | if (input.charCodeAt(pos) === charCodes.leftCurlyBrace) {
|
|---|
| 51 | while (pos < input.length && input.charCodeAt(pos) !== charCodes.rightCurlyBrace) {
|
|---|
| 52 | pos++;
|
|---|
| 53 | }
|
|---|
| 54 | pos++;
|
|---|
| 55 | }
|
|---|
| 56 | } else if (ch === charCodes.atSign && input.charCodeAt(pos + 1) === charCodes.atSign) {
|
|---|
| 57 | pos += 2;
|
|---|
| 58 | } else {
|
|---|
| 59 | break;
|
|---|
| 60 | }
|
|---|
| 61 | }
|
|---|
| 62 | state.pos = pos;
|
|---|
| 63 | finishToken(tt.name);
|
|---|
| 64 | }
|
|---|