coffee-lex
Advanced tools
Comparing version 9.1.5 to 9.2.0
@@ -1,17 +0,276 @@ | ||
import SourceLocation from './SourceLocation'; | ||
import SourceTokenList from './SourceTokenList'; | ||
import SourceType from './SourceType'; | ||
export declare type Options = { | ||
useCS2: boolean; | ||
}; | ||
export declare const DEFAULT_OPTIONS: Options; | ||
/** | ||
* Represents a particular type of CoffeeScript code. | ||
*/ | ||
declare enum SourceType { | ||
AT = "AT", | ||
BOOL = "BOOL", | ||
BREAK = "BREAK", | ||
CATCH = "CATCH", | ||
CALL_END = "CALL_END", | ||
CALL_START = "CALL_START", | ||
CLASS = "CLASS", | ||
COLON = "COLON", | ||
COMMA = "COMMA", | ||
COMMENT = "COMMENT", | ||
CONTINUATION = "CONTINUATION", | ||
CONTINUE = "CONTINUE", | ||
CSX_BODY = "CSX_BODY", | ||
CSX_CLOSE_TAG_START = "CSX_CLOSE_TAG_START", | ||
CSX_CLOSE_TAG_END = "CSX_CLOSE_TAG_END", | ||
CSX_OPEN_TAG_START = "CSX_OPEN_TAG_START", | ||
CSX_OPEN_TAG_END = "CSX_OPEN_TAG_END", | ||
CSX_SELF_CLOSING_TAG_END = "CSX_SELF_CLOSING_TAG_END", | ||
DECREMENT = "DECREMENT", | ||
DEFAULT = "DEFAULT", | ||
DELETE = "DELETE", | ||
DO = "DO", | ||
DOT = "DOT", | ||
DSTRING_START = "DSTRING_START", | ||
DSTRING_END = "DSTRING_END", | ||
ELSE = "ELSE", | ||
EXPORT = "EXPORT", | ||
EOF = "EOF", | ||
EXISTENCE = "EXISTENCE", | ||
EXTENDS = "EXTENDS", | ||
FINALLY = "FINALLY", | ||
FOR = "FOR", | ||
FUNCTION = "FUNCTION", | ||
HERECOMMENT = "HERECOMMENT", | ||
HEREJS = "HEREJS", | ||
HEREGEXP_COMMENT = "HEREGEXP_COMMENT", | ||
HEREGEXP_START = "HEREGEXP_START", | ||
HEREGEXP_END = "HEREGEXP_END", | ||
IF = "IF", | ||
IMPORT = "IMPORT", | ||
INCREMENT = "INCREMENT", | ||
INTERPOLATION_START = "INTERPOLATION_START", | ||
INTERPOLATION_END = "INTERPOLATION_END", | ||
JS = "JS", | ||
LBRACE = "LBRACE", | ||
LBRACKET = "LBRACKET", | ||
LOOP = "LOOP", | ||
LPAREN = "LPAREN", | ||
NEW = "NEW", | ||
NEWLINE = "NEWLINE", | ||
NORMAL = "NORMAL", | ||
NULL = "NULL", | ||
NUMBER = "NUMBER", | ||
OPERATOR = "OPERATOR", | ||
OWN = "OWN", | ||
PROTO = "PROTO", | ||
RANGE = "RANGE", | ||
REGEXP = "REGEXP", | ||
RBRACE = "RBRACE", | ||
RBRACKET = "RBRACKET", | ||
RELATION = "RELATION", | ||
RETURN = "RETURN", | ||
RPAREN = "RPAREN", | ||
SEMICOLON = "SEMICOLON", | ||
SPACE = "SPACE", | ||
SUPER = "SUPER", | ||
SWITCH = "SWITCH", | ||
SSTRING_START = "SSTRING_START", | ||
SSTRING_END = "SSTRING_END", | ||
STRING_CONTENT = "STRING_CONTENT", | ||
STRING_LINE_SEPARATOR = "STRING_LINE_SEPARATOR", | ||
STRING_PADDING = "STRING_PADDING", | ||
TDSTRING_START = "TDSTRING_START", | ||
TDSTRING_END = "TDSTRING_END", | ||
THEN = "THEN", | ||
THIS = "THIS", | ||
THROW = "THROW", | ||
TRY = "TRY", | ||
TSSTRING_START = "TSSTRING_START", | ||
TSSTRING_END = "TSSTRING_END", | ||
UNDEFINED = "UNDEFINED", | ||
UNKNOWN = "UNKNOWN", | ||
WHEN = "WHEN", | ||
WHILE = "WHILE", | ||
IDENTIFIER = "IDENTIFIER", | ||
YIELD = "YIELD", | ||
YIELDFROM = "YIELDFROM" | ||
} | ||
/** | ||
* Represents a change in source code type at a particular index. | ||
*/ | ||
declare class SourceLocation { | ||
readonly type: SourceType; | ||
readonly index: number; | ||
constructor(type: SourceType, index: number); | ||
} | ||
declare class SourceToken { | ||
readonly type: SourceType; | ||
readonly start: number; | ||
readonly end: number; | ||
constructor(type: SourceType, start: number, end: number); | ||
} | ||
/** | ||
* Represents a token at a particular index within a list of tokens. | ||
*/ | ||
declare class SourceTokenListIndex { | ||
private _sourceTokenList; | ||
private _index; | ||
constructor(sourceTokenList: SourceTokenList, index: number); | ||
/** | ||
* Get a new index offset from this one, if the resulting offset is within | ||
* the list range. | ||
*/ | ||
advance(offset: number): SourceTokenListIndex | null; | ||
/** | ||
* Get the index of the token after this one, if it's not the last one. | ||
*/ | ||
next(): SourceTokenListIndex | null; | ||
/** | ||
* Get the index of the token before this one, if it's not the first one. | ||
*/ | ||
previous(): SourceTokenListIndex | null; | ||
/** | ||
* Determines whether this index comes before another. | ||
*/ | ||
isBefore(other: SourceTokenListIndex): boolean; | ||
/** | ||
* Determines whether this index comes after another. | ||
*/ | ||
isAfter(other: SourceTokenListIndex): boolean; | ||
/** | ||
* Compare this index to another, returning 0 for equality, a negative number | ||
* if this is less than `other`, and a positive number otherwise. | ||
*/ | ||
compare(other: SourceTokenListIndex): number; | ||
/** | ||
* Returns an int of the relative distance between this index and the other | ||
* index (positive if the other one is later, negative if the other one is | ||
* earlier). | ||
*/ | ||
distance(other: SourceTokenListIndex): number; | ||
} | ||
declare type SourceTokenListIndexRange = [ | ||
SourceTokenListIndex, | ||
SourceTokenListIndex | ||
]; | ||
/** | ||
* Represents a list of tokens and provides various utility functions for | ||
* finding tokens within it. | ||
*/ | ||
declare class SourceTokenList { | ||
private _tokens; | ||
private _indexCache; | ||
private _indexBySourceIndex; | ||
private _indexByStartSourceIndex; | ||
private _indexByEndSourceIndex; | ||
readonly length: number; | ||
readonly startIndex: SourceTokenListIndex; | ||
readonly endIndex: SourceTokenListIndex; | ||
constructor(tokens: Array<SourceToken>); | ||
/** | ||
* Iterate over each token. | ||
*/ | ||
forEach(iterator: (token: SourceToken, index: SourceTokenListIndex, list: SourceTokenList) => void): void; | ||
/** | ||
* Map each token to an element of an array. | ||
*/ | ||
map<T>(mapper: (token: SourceToken, index: SourceTokenListIndex, list: SourceTokenList) => T): Array<T>; | ||
/** | ||
* Filter tokens by a predicate. | ||
*/ | ||
filter(predicate: (token: SourceToken, index: SourceTokenListIndex, list: SourceTokenList) => boolean): SourceTokenList; | ||
/** | ||
* Get a slice of this token list using the given indexes. | ||
*/ | ||
slice(start: SourceTokenListIndex, end: SourceTokenListIndex): SourceTokenList; | ||
/** | ||
* Get the token at the given index, if it exists. | ||
* | ||
* NOTE: The only value for which this should return `null` is this list's | ||
* `endIndex`. | ||
*/ | ||
tokenAtIndex(index: SourceTokenListIndex): SourceToken | null; | ||
/** | ||
* Get the range of tokens representing an interpolated string that contains | ||
* the token at `index`. This will return the innermost interpolated string in | ||
* the case of nesting. | ||
*/ | ||
rangeOfInterpolatedStringTokensContainingTokenIndex(index: SourceTokenListIndex): SourceTokenListIndexRange | null; | ||
/** | ||
* Get the range of tokens starting with a token of type `startType` and | ||
* ending one past a token of type `endType`, ensuring that the tokens match. | ||
* That is, it ensures they are balanced and properly account for nesting. | ||
* This range will contain `index`. If no such range can be found, `null` is | ||
* returned. | ||
*/ | ||
rangeOfMatchingTokensContainingTokenIndex(startType: SourceType, endType: SourceType, index: SourceTokenListIndex): SourceTokenListIndexRange | null; | ||
/** | ||
* Finds the index of the token whose source range includes the given index. | ||
* If the given index does not correspond to the range of a token, returns | ||
* null. | ||
*/ | ||
indexOfTokenContainingSourceIndex(index: number): SourceTokenListIndex | null; | ||
/** | ||
* If the given source index lands on a token, return the index of that token. | ||
* Otherwise, return the index of the previous token in the source code, or | ||
* the first token if there is no previous token. | ||
*/ | ||
indexOfTokenNearSourceIndex(index: number): SourceTokenListIndex; | ||
/** | ||
* Finds the index of the token whose source range starts at the given index. | ||
*/ | ||
indexOfTokenStartingAtSourceIndex(index: number): SourceTokenListIndex | null; | ||
/** | ||
* Finds the index of the token whose source range ends at the given index. | ||
*/ | ||
indexOfTokenEndingAtSourceIndex(index: number): SourceTokenListIndex | null; | ||
/** | ||
* Finds the index of the first token matching a predicate. | ||
*/ | ||
indexOfTokenMatchingPredicate(predicate: (token: SourceToken) => boolean, start?: SourceTokenListIndex | null, end?: SourceTokenListIndex | null): SourceTokenListIndex | null; | ||
/** | ||
* Finds the index of the first token matching a predicate, traversing | ||
* backwards. | ||
*/ | ||
lastIndexOfTokenMatchingPredicate(predicate: (token: SourceToken) => boolean, start?: SourceTokenListIndex | null, end?: SourceTokenListIndex | null): SourceTokenListIndex | null; | ||
/** | ||
* Allow iterating over the tokens in this list using e.g. `for (… of …)`. | ||
*/ | ||
[Symbol.iterator](): Iterator<SourceToken>; | ||
/** | ||
* @internal | ||
*/ | ||
private _validateTokens; | ||
/** | ||
* @internal | ||
*/ | ||
private _validateIndex; | ||
/** | ||
* @internal | ||
*/ | ||
private _validateSourceIndex; | ||
/** | ||
* @internal | ||
*/ | ||
private _getIndex; | ||
/** | ||
* Get the list of tokens. | ||
*/ | ||
toArray(): Array<SourceToken>; | ||
} | ||
interface Options { | ||
readonly useCS2: boolean; | ||
} | ||
declare const DEFAULT_OPTIONS: Options; | ||
/** | ||
* Generate a list of tokens from CoffeeScript source code. | ||
*/ | ||
export default function lex(source: string, options?: Options): SourceTokenList; | ||
export { SourceType }; | ||
declare function lex(source: string, options?: Options): SourceTokenList; | ||
/** | ||
* Provides a stream of source type change locations. | ||
*/ | ||
export declare function stream(source: string, index?: number, options?: Options): () => SourceLocation; | ||
export declare function consumeStream(lexer: () => SourceLocation): Array<SourceLocation>; | ||
declare function stream(source: string, index?: number, options?: Options): () => SourceLocation; | ||
declare function consumeStream(lexer: () => SourceLocation): Array<SourceLocation>; | ||
export { DEFAULT_OPTIONS, Options, SourceType, consumeStream, lex as default, lex, stream }; |
2357
dist/index.js
@@ -1,142 +0,904 @@ | ||
"use strict"; | ||
var __spreadArrays = (this && this.__spreadArrays) || function () { | ||
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; | ||
for (var r = Array(s), k = 0, i = 0; i < il; i++) | ||
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) | ||
r[k] = a[j]; | ||
return r; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var SourceLocation_1 = require("./SourceLocation"); | ||
var SourceToken_1 = require("./SourceToken"); | ||
var SourceTokenList_1 = require("./SourceTokenList"); | ||
var SourceType_1 = require("./SourceType"); | ||
exports.SourceType = SourceType_1.default; | ||
var BufferedStream_1 = require("./utils/BufferedStream"); | ||
var calculateHeregexpPadding_1 = require("./utils/calculateHeregexpPadding"); | ||
var calculateNormalStringPadding_1 = require("./utils/calculateNormalStringPadding"); | ||
var calculateTripleQuotedStringPadding_1 = require("./utils/calculateTripleQuotedStringPadding"); | ||
var ContextType; | ||
(function (ContextType) { | ||
ContextType["STRING"] = "STRING"; | ||
ContextType["INTERPOLATION"] = "INTERPOLATION"; | ||
ContextType["CSX_OPEN_TAG"] = "CSX_OPEN_TAG"; | ||
ContextType["CSX_CLOSE_TAG"] = "CSX_CLOSE_TAG"; | ||
ContextType["CSX_BODY"] = "CSX_BODY"; | ||
ContextType["BRACE"] = "BRACE"; | ||
ContextType["PAREN"] = "PAREN"; | ||
})(ContextType || (ContextType = {})); | ||
exports.DEFAULT_OPTIONS = { | ||
useCS2: false | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
/** | ||
* Generate a list of tokens from CoffeeScript source code. | ||
*/ | ||
function lex(source, options) { | ||
if (options === void 0) { options = exports.DEFAULT_OPTIONS; } | ||
var location; | ||
var previousLocation; | ||
var tokens = []; | ||
var pending = new BufferedStream_1.default(stream(source, 0, options)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
// src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
DEFAULT_OPTIONS: () => DEFAULT_OPTIONS, | ||
SourceType: () => SourceType, | ||
consumeStream: () => consumeStream, | ||
default: () => lex, | ||
lex: () => lex, | ||
stream: () => stream | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// src/SourceLocation.ts | ||
var SourceLocation = class { | ||
constructor(type, index) { | ||
this.type = type; | ||
this.index = index; | ||
} | ||
}; | ||
// src/SourceToken.ts | ||
var SourceToken = class { | ||
constructor(type, start, end) { | ||
this.type = type; | ||
this.start = start; | ||
this.end = end; | ||
if (start > end) { | ||
throw new Error(`Token start may not be after end. Got ${type}, ${start}, ${end}`); | ||
} | ||
} | ||
}; | ||
// src/SourceTokenListIndex.ts | ||
var SourceTokenListIndex = class { | ||
constructor(sourceTokenList, index) { | ||
this._sourceTokenList = sourceTokenList; | ||
this._index = index; | ||
} | ||
advance(offset) { | ||
const newIndex = this._index + offset; | ||
if (newIndex < 0 || this._sourceTokenList.length < newIndex) { | ||
return null; | ||
} | ||
return this._sourceTokenList["_getIndex"](newIndex); | ||
} | ||
next() { | ||
return this.advance(1); | ||
} | ||
previous() { | ||
return this.advance(-1); | ||
} | ||
isBefore(other) { | ||
return this.compare(other) > 0; | ||
} | ||
isAfter(other) { | ||
return this.compare(other) < 0; | ||
} | ||
compare(other) { | ||
return this.distance(other); | ||
} | ||
distance(other) { | ||
if (other._sourceTokenList !== this._sourceTokenList) { | ||
throw new Error("cannot compare indexes from different lists"); | ||
} | ||
return other._index - this._index; | ||
} | ||
}; | ||
// src/SourceType.ts | ||
var SourceType = /* @__PURE__ */ ((SourceType2) => { | ||
SourceType2["AT"] = "AT"; | ||
SourceType2["BOOL"] = "BOOL"; | ||
SourceType2["BREAK"] = "BREAK"; | ||
SourceType2["CATCH"] = "CATCH"; | ||
SourceType2["CALL_END"] = "CALL_END"; | ||
SourceType2["CALL_START"] = "CALL_START"; | ||
SourceType2["CLASS"] = "CLASS"; | ||
SourceType2["COLON"] = "COLON"; | ||
SourceType2["COMMA"] = "COMMA"; | ||
SourceType2["COMMENT"] = "COMMENT"; | ||
SourceType2["CONTINUATION"] = "CONTINUATION"; | ||
SourceType2["CONTINUE"] = "CONTINUE"; | ||
SourceType2["CSX_BODY"] = "CSX_BODY"; | ||
SourceType2["CSX_CLOSE_TAG_START"] = "CSX_CLOSE_TAG_START"; | ||
SourceType2["CSX_CLOSE_TAG_END"] = "CSX_CLOSE_TAG_END"; | ||
SourceType2["CSX_OPEN_TAG_START"] = "CSX_OPEN_TAG_START"; | ||
SourceType2["CSX_OPEN_TAG_END"] = "CSX_OPEN_TAG_END"; | ||
SourceType2["CSX_SELF_CLOSING_TAG_END"] = "CSX_SELF_CLOSING_TAG_END"; | ||
SourceType2["DECREMENT"] = "DECREMENT"; | ||
SourceType2["DEFAULT"] = "DEFAULT"; | ||
SourceType2["DELETE"] = "DELETE"; | ||
SourceType2["DO"] = "DO"; | ||
SourceType2["DOT"] = "DOT"; | ||
SourceType2["DSTRING_START"] = "DSTRING_START"; | ||
SourceType2["DSTRING_END"] = "DSTRING_END"; | ||
SourceType2["ELSE"] = "ELSE"; | ||
SourceType2["EXPORT"] = "EXPORT"; | ||
SourceType2["EOF"] = "EOF"; | ||
SourceType2["EXISTENCE"] = "EXISTENCE"; | ||
SourceType2["EXTENDS"] = "EXTENDS"; | ||
SourceType2["FINALLY"] = "FINALLY"; | ||
SourceType2["FOR"] = "FOR"; | ||
SourceType2["FUNCTION"] = "FUNCTION"; | ||
SourceType2["HERECOMMENT"] = "HERECOMMENT"; | ||
SourceType2["HEREJS"] = "HEREJS"; | ||
SourceType2["HEREGEXP_COMMENT"] = "HEREGEXP_COMMENT"; | ||
SourceType2["HEREGEXP_START"] = "HEREGEXP_START"; | ||
SourceType2["HEREGEXP_END"] = "HEREGEXP_END"; | ||
SourceType2["IF"] = "IF"; | ||
SourceType2["IMPORT"] = "IMPORT"; | ||
SourceType2["INCREMENT"] = "INCREMENT"; | ||
SourceType2["INTERPOLATION_START"] = "INTERPOLATION_START"; | ||
SourceType2["INTERPOLATION_END"] = "INTERPOLATION_END"; | ||
SourceType2["JS"] = "JS"; | ||
SourceType2["LBRACE"] = "LBRACE"; | ||
SourceType2["LBRACKET"] = "LBRACKET"; | ||
SourceType2["LOOP"] = "LOOP"; | ||
SourceType2["LPAREN"] = "LPAREN"; | ||
SourceType2["NEW"] = "NEW"; | ||
SourceType2["NEWLINE"] = "NEWLINE"; | ||
SourceType2["NORMAL"] = "NORMAL"; | ||
SourceType2["NULL"] = "NULL"; | ||
SourceType2["NUMBER"] = "NUMBER"; | ||
SourceType2["OPERATOR"] = "OPERATOR"; | ||
SourceType2["OWN"] = "OWN"; | ||
SourceType2["PROTO"] = "PROTO"; | ||
SourceType2["RANGE"] = "RANGE"; | ||
SourceType2["REGEXP"] = "REGEXP"; | ||
SourceType2["RBRACE"] = "RBRACE"; | ||
SourceType2["RBRACKET"] = "RBRACKET"; | ||
SourceType2["RELATION"] = "RELATION"; | ||
SourceType2["RETURN"] = "RETURN"; | ||
SourceType2["RPAREN"] = "RPAREN"; | ||
SourceType2["SEMICOLON"] = "SEMICOLON"; | ||
SourceType2["SPACE"] = "SPACE"; | ||
SourceType2["SUPER"] = "SUPER"; | ||
SourceType2["SWITCH"] = "SWITCH"; | ||
SourceType2["SSTRING_START"] = "SSTRING_START"; | ||
SourceType2["SSTRING_END"] = "SSTRING_END"; | ||
SourceType2["STRING_CONTENT"] = "STRING_CONTENT"; | ||
SourceType2["STRING_LINE_SEPARATOR"] = "STRING_LINE_SEPARATOR"; | ||
SourceType2["STRING_PADDING"] = "STRING_PADDING"; | ||
SourceType2["TDSTRING_START"] = "TDSTRING_START"; | ||
SourceType2["TDSTRING_END"] = "TDSTRING_END"; | ||
SourceType2["THEN"] = "THEN"; | ||
SourceType2["THIS"] = "THIS"; | ||
SourceType2["THROW"] = "THROW"; | ||
SourceType2["TRY"] = "TRY"; | ||
SourceType2["TSSTRING_START"] = "TSSTRING_START"; | ||
SourceType2["TSSTRING_END"] = "TSSTRING_END"; | ||
SourceType2["UNDEFINED"] = "UNDEFINED"; | ||
SourceType2["UNKNOWN"] = "UNKNOWN"; | ||
SourceType2["WHEN"] = "WHEN"; | ||
SourceType2["WHILE"] = "WHILE"; | ||
SourceType2["IDENTIFIER"] = "IDENTIFIER"; | ||
SourceType2["YIELD"] = "YIELD"; | ||
SourceType2["YIELDFROM"] = "YIELDFROM"; | ||
return SourceType2; | ||
})(SourceType || {}); | ||
// src/SourceTokenList.ts | ||
var SourceTokenList = class { | ||
constructor(tokens) { | ||
this._validateTokens(tokens); | ||
this._tokens = tokens; | ||
this._indexCache = new Array(tokens.length); | ||
this.length = tokens.length; | ||
this.startIndex = this._getIndex(0); | ||
this.endIndex = this._getIndex(tokens.length); | ||
this._indexBySourceIndex = []; | ||
this._indexByStartSourceIndex = []; | ||
this._indexByEndSourceIndex = []; | ||
for (let tokenIndex = tokens.length - 1; tokenIndex >= 0; tokenIndex--) { | ||
const token = tokens[tokenIndex]; | ||
for (let sourceIndex = token.start; sourceIndex < token.end; sourceIndex++) { | ||
this._indexBySourceIndex[sourceIndex] = this._getIndex(tokenIndex); | ||
} | ||
this._indexByStartSourceIndex[token.start] = this._getIndex(tokenIndex); | ||
this._indexByEndSourceIndex[token.end] = this._getIndex(tokenIndex); | ||
} | ||
} | ||
forEach(iterator) { | ||
this._tokens.forEach((token, i) => iterator(token, this._getIndex(i), this)); | ||
} | ||
map(mapper) { | ||
const result = []; | ||
this.forEach((token, index, list) => { | ||
result.push(mapper(token, index, list)); | ||
}); | ||
return result; | ||
} | ||
filter(predicate) { | ||
const result = []; | ||
this.forEach((token, index, list) => { | ||
if (predicate(token, index, list)) { | ||
result.push(token); | ||
} | ||
}); | ||
return new SourceTokenList(result); | ||
} | ||
slice(start, end) { | ||
if (start["_sourceTokenList"] !== this || end["_sourceTokenList"] !== this) { | ||
throw new Error("cannot slice a list using indexes from another list"); | ||
} | ||
return new SourceTokenList(this._tokens.slice(start["_index"], end["_index"])); | ||
} | ||
tokenAtIndex(index) { | ||
this._validateIndex(index); | ||
return this._tokens[index["_index"]] || null; | ||
} | ||
rangeOfInterpolatedStringTokensContainingTokenIndex(index) { | ||
let bestRange = null; | ||
for (const [startType, endType] of [ | ||
["DSTRING_START" /* DSTRING_START */, "DSTRING_END" /* DSTRING_END */], | ||
["TDSTRING_START" /* TDSTRING_START */, "TDSTRING_END" /* TDSTRING_END */], | ||
["HEREGEXP_START" /* HEREGEXP_START */, "HEREGEXP_END" /* HEREGEXP_END */] | ||
]) { | ||
const range = this.rangeOfMatchingTokensContainingTokenIndex(startType, endType, index); | ||
if (bestRange === null || bestRange === void 0 || range !== null && range !== void 0 && range[0].distance(range[1]) < bestRange[0].distance(bestRange[1])) { | ||
bestRange = range; | ||
} | ||
} | ||
return bestRange; | ||
} | ||
rangeOfMatchingTokensContainingTokenIndex(startType, endType, index) { | ||
this._validateIndex(index); | ||
const token = this.tokenAtIndex(index); | ||
if (!token) { | ||
return null; | ||
} | ||
switch (token.type) { | ||
case startType: { | ||
let level = 0; | ||
const start = index; | ||
const endIndex = this.indexOfTokenMatchingPredicate((token2) => { | ||
if (token2.type === startType) { | ||
level += 1; | ||
} else if (token2.type === endType) { | ||
level -= 1; | ||
if (level === 0) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}, start); | ||
if (!endIndex) { | ||
return null; | ||
} else { | ||
const rangeEnd = endIndex.next(); | ||
if (!rangeEnd) { | ||
return null; | ||
} | ||
return [start, rangeEnd]; | ||
} | ||
} | ||
case endType: { | ||
let level = 0; | ||
const endIndex = index; | ||
const startIndex = this.lastIndexOfTokenMatchingPredicate((token2) => { | ||
if (token2.type === startType) { | ||
level -= 1; | ||
if (level === 0) { | ||
return true; | ||
} | ||
} else if (token2.type === endType) { | ||
level += 1; | ||
} | ||
return false; | ||
}, endIndex); | ||
if (!startIndex) { | ||
return null; | ||
} else { | ||
const rangeEnd = endIndex.next(); | ||
if (!rangeEnd) { | ||
return null; | ||
} else { | ||
return [startIndex, rangeEnd]; | ||
} | ||
} | ||
} | ||
default: { | ||
let level = 0; | ||
const startIndex = this.lastIndexOfTokenMatchingPredicate((token2) => { | ||
if (token2.type === startType) { | ||
if (level === 0) { | ||
return true; | ||
} | ||
level -= 1; | ||
} else if (token2.type === endType) { | ||
level += 1; | ||
} | ||
return false; | ||
}, index); | ||
if (!startIndex) { | ||
return null; | ||
} else { | ||
return this.rangeOfMatchingTokensContainingTokenIndex(startType, endType, startIndex); | ||
} | ||
} | ||
} | ||
} | ||
indexOfTokenContainingSourceIndex(index) { | ||
this._validateSourceIndex(index); | ||
return this._indexBySourceIndex[index] || null; | ||
} | ||
indexOfTokenNearSourceIndex(index) { | ||
this._validateSourceIndex(index); | ||
for (let searchIndex = index; searchIndex >= 0; searchIndex--) { | ||
const tokenIndex = this._indexBySourceIndex[searchIndex]; | ||
if (tokenIndex) { | ||
return tokenIndex; | ||
} | ||
} | ||
return this.startIndex; | ||
} | ||
indexOfTokenStartingAtSourceIndex(index) { | ||
this._validateSourceIndex(index); | ||
return this._indexByStartSourceIndex[index] || null; | ||
} | ||
indexOfTokenEndingAtSourceIndex(index) { | ||
this._validateSourceIndex(index); | ||
return this._indexByEndSourceIndex[index] || null; | ||
} | ||
indexOfTokenMatchingPredicate(predicate, start = null, end = null) { | ||
if (!start) { | ||
start = this.startIndex; | ||
} | ||
if (!end) { | ||
end = this.endIndex; | ||
} | ||
this._validateIndex(start); | ||
this._validateIndex(end); | ||
for (let i = start; i && i !== end; i = i.next()) { | ||
const token = this.tokenAtIndex(i); | ||
if (!token) { | ||
break; | ||
} else if (predicate(token)) { | ||
return i; | ||
} | ||
} | ||
return null; | ||
} | ||
lastIndexOfTokenMatchingPredicate(predicate, start = null, end = null) { | ||
if (!start) { | ||
start = this.endIndex.previous(); | ||
if (!start) { | ||
return null; | ||
} | ||
} | ||
this._validateIndex(start); | ||
if (end) { | ||
this._validateIndex(end); | ||
} | ||
let i = start; | ||
do { | ||
pending.unshift.apply(pending, calculateNormalStringPadding_1.default(source, pending)); | ||
pending.unshift.apply(pending, calculateTripleQuotedStringPadding_1.default(source, pending)); | ||
pending.unshift.apply(pending, calculateHeregexpPadding_1.default(source, pending)); | ||
pending.unshift.apply(pending, combinedLocationsForNegatedOperators(pending, source)); | ||
location = pending.shift(); | ||
if (previousLocation && previousLocation.type !== SourceType_1.default.SPACE) { | ||
tokens.push(new SourceToken_1.default(previousLocation.type, previousLocation.index, location.index)); | ||
const token = this.tokenAtIndex(i); | ||
if (!token) { | ||
break; | ||
} else if (predicate(token)) { | ||
return i; | ||
} else { | ||
i = i.previous(); | ||
} | ||
} while (i && i !== end); | ||
return null; | ||
} | ||
[Symbol.iterator]() { | ||
let index = this.startIndex; | ||
const { endIndex } = this; | ||
return { | ||
next() { | ||
if (index === endIndex) { | ||
return { done: true, value: void 0 }; | ||
} else { | ||
const result = { done: false, value: this.tokenAtIndex(index) }; | ||
const nextIndex = index.next(); | ||
if (!nextIndex) { | ||
throw new Error(`unexpected null index before the end index`); | ||
} | ||
index = nextIndex; | ||
return result; | ||
} | ||
previousLocation = location; | ||
} while (location.type !== SourceType_1.default.EOF); | ||
return new SourceTokenList_1.default(tokens); | ||
} | ||
}; | ||
} | ||
_validateTokens(tokens) { | ||
for (let i = 0; i < tokens.length - 1; i++) { | ||
if (tokens[i].end > tokens[i + 1].start) { | ||
throw new Error(`Tokens not in order. Expected ${JSON.stringify(tokens[i])} before ${JSON.stringify(tokens[i + 1])}`); | ||
} | ||
} | ||
} | ||
_validateIndex(index) { | ||
if (!index) { | ||
throw new Error(`unexpected 'null' index, perhaps you forgot to check the result of 'indexOfTokenContainingSourceIndex'?`); | ||
} | ||
if (typeof index === "number") { | ||
throw new Error(`to get a token at index ${index}, use list.tokenAtIndex(list.startIndex.advance(${index}))`); | ||
} | ||
if (index["_sourceTokenList"] !== this) { | ||
throw new Error("cannot get token in one list using an index from another"); | ||
} | ||
} | ||
_validateSourceIndex(index) { | ||
if (typeof index !== "number") { | ||
throw new Error(`expected source index to be a number, got: ${index}`); | ||
} | ||
} | ||
_getIndex(index) { | ||
let cached = this._indexCache[index]; | ||
if (!cached) { | ||
cached = new SourceTokenListIndex(this, index); | ||
this._indexCache[index] = cached; | ||
} | ||
return cached; | ||
} | ||
toArray() { | ||
return this._tokens.slice(); | ||
} | ||
}; | ||
// src/utils/assertNever.ts | ||
function assertNever(value, message = `unexpected value: ${value}`) { | ||
throw new Error(message); | ||
} | ||
exports.default = lex; | ||
function combinedLocationsForNegatedOperators(stream, source) { | ||
if (!stream.hasNext(SourceType_1.default.OPERATOR)) { | ||
return []; | ||
// src/utils/BufferedStream.ts | ||
var BufferedStream = class { | ||
constructor(stream2) { | ||
this.pending = []; | ||
this._getNextLocation = stream2; | ||
} | ||
shift() { | ||
return this.pending.shift() || this._getNextLocation(); | ||
} | ||
hasNext(...types) { | ||
const locationsToPutBack = []; | ||
const result = types.every((type) => { | ||
const next = this.shift(); | ||
locationsToPutBack.push(next); | ||
return next.type === type; | ||
}); | ||
this.unshift(...locationsToPutBack); | ||
return result; | ||
} | ||
peek() { | ||
const result = this.shift(); | ||
this.unshift(result); | ||
return result; | ||
} | ||
unshift(...tokens) { | ||
this.pending.unshift(...tokens); | ||
} | ||
}; | ||
// src/utils/PaddingTracker.ts | ||
var PaddingTracker = class { | ||
constructor(source, stream2, endType) { | ||
this.fragments = []; | ||
this._originalLocations = []; | ||
let interpolationLevel = 0; | ||
let location; | ||
do { | ||
location = stream2.shift(); | ||
this._originalLocations.push(location); | ||
if (interpolationLevel === 0 && location.type === "STRING_CONTENT" /* STRING_CONTENT */) { | ||
const start = location.index; | ||
const end = stream2.peek().index; | ||
const content = source.slice(start, end); | ||
const index = this.fragments.length; | ||
this.fragments.push(new TrackedFragment(content, start, end, index)); | ||
} else if (location.type === "INTERPOLATION_START" /* INTERPOLATION_START */) { | ||
interpolationLevel += 1; | ||
} else if (location.type === "INTERPOLATION_END" /* INTERPOLATION_END */) { | ||
interpolationLevel -= 1; | ||
} | ||
} while (interpolationLevel > 0 || location.type !== endType); | ||
} | ||
computeSourceLocations() { | ||
const resultLocations = []; | ||
let rangeIndex = 0; | ||
for (const location of this._originalLocations) { | ||
const currentRange = this.fragments[rangeIndex]; | ||
if (location.type === "STRING_CONTENT" /* STRING_CONTENT */ && currentRange && location.index === currentRange.start) { | ||
resultLocations.push(...currentRange.computeSourceLocations()); | ||
rangeIndex++; | ||
} else { | ||
resultLocations.push(location); | ||
} | ||
} | ||
var locationsToRestore = []; | ||
function shift() { | ||
var location = stream.shift(); | ||
locationsToRestore.push(location); | ||
return location; | ||
if (rangeIndex !== this.fragments.length) { | ||
throw new Error("Expected ranges to correspond to original locations."); | ||
} | ||
var not = shift(); | ||
var space = shift(); | ||
var text = source.slice(not.index, space.index); | ||
var operator; | ||
if (text === 'not') { | ||
if (space.type === SourceType_1.default.SPACE) { | ||
// It is a space, so the operator is at the next location. | ||
operator = shift(); | ||
return resultLocations; | ||
} | ||
}; | ||
var TrackedFragment = class { | ||
constructor(content, start, end, index) { | ||
this.content = content; | ||
this.start = start; | ||
this.end = end; | ||
this.index = index; | ||
this._paddingRanges = []; | ||
this._lineSeparators = []; | ||
} | ||
markPadding(startIndex, endIndex) { | ||
this._paddingRanges.push({ start: startIndex, end: endIndex }); | ||
} | ||
markLineSeparator(index) { | ||
this._lineSeparators.push(index); | ||
} | ||
computeSourceLocations() { | ||
if (this.start === this.end) { | ||
return [new SourceLocation("STRING_CONTENT" /* STRING_CONTENT */, this.start)]; | ||
} | ||
const eventsByIndex = []; | ||
for (let i = 0; i < this.end - this.start + 1; i++) { | ||
eventsByIndex.push([]); | ||
} | ||
for (const range of this._paddingRanges) { | ||
eventsByIndex[range.start].push("START_PADDING"); | ||
eventsByIndex[range.end].push("END_PADDING"); | ||
} | ||
for (const separatorIndex of this._lineSeparators) { | ||
eventsByIndex[separatorIndex].push("START_LINE_SEPARATOR"); | ||
eventsByIndex[separatorIndex + 1].push("END_LINE_SEPARATOR"); | ||
} | ||
const resultLocations = []; | ||
let lastSourceType = null; | ||
let paddingDepth = 0; | ||
let lineSeparatorDepth = 0; | ||
for (let sourceIndex = this.start; sourceIndex < this.end; sourceIndex++) { | ||
for (const event of eventsByIndex[sourceIndex - this.start]) { | ||
if (event === "START_PADDING") { | ||
paddingDepth += 1; | ||
} else if (event === "END_PADDING") { | ||
paddingDepth -= 1; | ||
} else if (event === "START_LINE_SEPARATOR") { | ||
lineSeparatorDepth += 1; | ||
} else if (event === "END_LINE_SEPARATOR") { | ||
lineSeparatorDepth -= 1; | ||
} | ||
else { | ||
// `not` must be followed by a space, so this isn't a match. | ||
return locationsToRestore; | ||
} | ||
if (paddingDepth < 0 || lineSeparatorDepth < 0 || paddingDepth > 0 && lineSeparatorDepth > 0) { | ||
throw new Error(`Illegal padding state: paddingDepth: ${paddingDepth}, lineSeparatorDepth: ${lineSeparatorDepth}`); | ||
} | ||
let sourceType; | ||
if (paddingDepth > 0) { | ||
sourceType = "STRING_PADDING" /* STRING_PADDING */; | ||
} else if (lineSeparatorDepth > 0) { | ||
sourceType = "STRING_LINE_SEPARATOR" /* STRING_LINE_SEPARATOR */; | ||
} else { | ||
sourceType = "STRING_CONTENT" /* STRING_CONTENT */; | ||
} | ||
if (sourceType !== lastSourceType) { | ||
resultLocations.push(new SourceLocation(sourceType, sourceIndex)); | ||
lastSourceType = sourceType; | ||
} | ||
} | ||
return resultLocations; | ||
} | ||
}; | ||
// src/utils/calculateHeregexpPadding.ts | ||
function calculateHeregexpPadding(source, stream2) { | ||
if (!stream2.hasNext("HEREGEXP_START" /* HEREGEXP_START */)) { | ||
return []; | ||
} | ||
const paddingTracker = new PaddingTracker(source, stream2, "HEREGEXP_END" /* HEREGEXP_END */); | ||
for (const fragment of paddingTracker.fragments) { | ||
const content = fragment.content; | ||
let pos = 0; | ||
while (pos < content.length) { | ||
if (/\s/.test(content[pos])) { | ||
if (isWhitespaceEscaped(content, pos)) { | ||
fragment.markPadding(pos - 1, pos); | ||
} else { | ||
fragment.markPadding(pos, pos + 1); | ||
} | ||
pos++; | ||
} else if (content[pos] === "#" && (pos === 0 || /\s/.test(content[pos - 1]))) { | ||
const commentStart = pos; | ||
while (pos < content.length && content[pos] !== "\n") { | ||
pos++; | ||
} | ||
fragment.markPadding(commentStart, pos); | ||
} else { | ||
pos++; | ||
} | ||
} | ||
else if (text === '!') { | ||
if (space.type === SourceType_1.default.SPACE) { | ||
// It is a space, so the operator is at the next location. | ||
operator = shift(); | ||
} | ||
return paddingTracker.computeSourceLocations(); | ||
} | ||
function isWhitespaceEscaped(content, whitespacePos) { | ||
let prevPos = whitespacePos - 1; | ||
while (prevPos >= 0 && content[prevPos] === "\\") { | ||
prevPos--; | ||
} | ||
return (whitespacePos - prevPos) % 2 === 0; | ||
} | ||
// src/utils/isNewlineEscaped.ts | ||
function isNewlineEscaped(content, newlinePos) { | ||
let numSeenBackslashes = 0; | ||
let prevPos = newlinePos - 1; | ||
while (prevPos >= 0) { | ||
const char = content[prevPos]; | ||
if (numSeenBackslashes === 0 && (char === " " || char === " ")) { | ||
prevPos--; | ||
} else if (char === "\\") { | ||
numSeenBackslashes++; | ||
prevPos--; | ||
} else { | ||
break; | ||
} | ||
} | ||
return numSeenBackslashes % 2 === 1; | ||
} | ||
// src/utils/calculateNormalStringPadding.ts | ||
function calculateNormalStringPadding(source, stream2) { | ||
let paddingTracker; | ||
if (stream2.hasNext("SSTRING_START" /* SSTRING_START */)) { | ||
paddingTracker = new PaddingTracker(source, stream2, "SSTRING_END" /* SSTRING_END */); | ||
} else if (stream2.hasNext("DSTRING_START" /* DSTRING_START */)) { | ||
paddingTracker = new PaddingTracker(source, stream2, "DSTRING_END" /* DSTRING_END */); | ||
} else { | ||
return []; | ||
} | ||
for (let fragmentIndex = 0; fragmentIndex < paddingTracker.fragments.length; fragmentIndex++) { | ||
const fragment = paddingTracker.fragments[fragmentIndex]; | ||
const content = fragment.content; | ||
let lastNonWhitespace = -1; | ||
let pos = 0; | ||
while (pos < content.length) { | ||
if (content[pos] === "\n") { | ||
const startIndex = lastNonWhitespace + 1; | ||
fragment.markPadding(lastNonWhitespace + 1, pos); | ||
const newlinePos = pos; | ||
pos++; | ||
while (pos < content.length && " \n".includes(content[pos]) || content.slice(pos, pos + 2) === "\\\n") { | ||
pos++; | ||
} | ||
else { | ||
// The optional space is missing, so the next thing must be the operator. | ||
operator = space; | ||
const endIndex = pos; | ||
if (isNewlineEscaped(content, newlinePos)) { | ||
const backslashPos = content.lastIndexOf("\\", newlinePos); | ||
fragment.markPadding(backslashPos, endIndex); | ||
} else if (fragmentIndex === 0 && startIndex === 0 || fragmentIndex === paddingTracker.fragments.length - 1 && endIndex === content.length) { | ||
fragment.markPadding(startIndex, endIndex); | ||
} else { | ||
fragment.markPadding(startIndex, newlinePos); | ||
fragment.markLineSeparator(newlinePos); | ||
fragment.markPadding(newlinePos + 1, endIndex); | ||
} | ||
lastNonWhitespace = pos; | ||
} else { | ||
if (content[pos] !== " " && content[pos] !== " ") { | ||
lastNonWhitespace = pos; | ||
} | ||
pos++; | ||
} | ||
} | ||
else { | ||
// Not a negation token, so put them back. | ||
return locationsToRestore; | ||
} | ||
return paddingTracker.computeSourceLocations(); | ||
} | ||
// src/utils/calculateTripleQuotedStringPadding.ts | ||
function calculateTripleQuotedStringPadding(source, stream2) { | ||
let paddingTracker; | ||
if (stream2.hasNext("TSSTRING_START" /* TSSTRING_START */)) { | ||
paddingTracker = new PaddingTracker(source, stream2, "TSSTRING_END" /* TSSTRING_END */); | ||
} else if (stream2.hasNext("TDSTRING_START" /* TDSTRING_START */)) { | ||
paddingTracker = new PaddingTracker(source, stream2, "TDSTRING_END" /* TDSTRING_END */); | ||
} else { | ||
return []; | ||
} | ||
const firstFragment = paddingTracker.fragments[0]; | ||
const firstContent = firstFragment.content; | ||
const lastFragment = paddingTracker.fragments[paddingTracker.fragments.length - 1]; | ||
const lastContent = lastFragment.content; | ||
const sharedIndent = getIndentForFragments(paddingTracker.fragments); | ||
const firstContentLines = splitUnescapedNewlines(firstContent); | ||
if (firstContentLines.length > 1 && isWhitespace(firstContentLines[0])) { | ||
firstFragment.markPadding(0, firstContentLines[0].length + 1); | ||
} | ||
if (!shouldSkipRemovingLastLine(paddingTracker)) { | ||
const lastLines = splitUnescapedNewlines(lastContent); | ||
if (lastLines.length > 1) { | ||
const lastLine = lastLines[lastLines.length - 1]; | ||
if (isWhitespace(lastLine)) { | ||
lastFragment.markPadding(lastFragment.content.length - lastLine.length - 1, lastFragment.content.length); | ||
} | ||
} | ||
var next = stream.peek(); | ||
var op = source.slice(operator.index, next.index); | ||
switch (op) { | ||
case 'in': | ||
case 'of': | ||
return [new SourceLocation_1.default(SourceType_1.default.RELATION, not.index)]; | ||
case 'instanceof': | ||
return [new SourceLocation_1.default(SourceType_1.default.OPERATOR, not.index)]; | ||
} | ||
for (const fragment of paddingTracker.fragments) { | ||
for (let i = 0; i < fragment.content.length; i++) { | ||
if (fragment.content[i] === "\n" && isNewlineEscaped(fragment.content, i)) { | ||
const backslashPos = fragment.content.lastIndexOf("\\", i); | ||
let paddingEnd = i; | ||
while (paddingEnd < fragment.content.length && " \n".includes(fragment.content[paddingEnd])) { | ||
paddingEnd++; | ||
} | ||
fragment.markPadding(backslashPos, paddingEnd); | ||
} | ||
const isStartOfLine = i > 0 && fragment.content[i - 1] === "\n"; | ||
if (isStartOfLine) { | ||
const paddingStart = i; | ||
const paddingEnd = i + sharedIndent.length; | ||
if (fragment.content.slice(paddingStart, paddingEnd) === sharedIndent) { | ||
fragment.markPadding(paddingStart, paddingEnd); | ||
} | ||
} | ||
} | ||
// Doesn't match, so put them back. | ||
} | ||
return paddingTracker.computeSourceLocations(); | ||
} | ||
function getIndentForFragments(fragments) { | ||
let hasSeenLine = false; | ||
let smallestIndent = null; | ||
for (const fragment of fragments) { | ||
const lines = fragment.content.split("\n"); | ||
for (let i = 1; i < lines.length; i++) { | ||
const line = lines[i]; | ||
const indent = getLineIndent(line); | ||
if (!hasSeenLine && indent.length === 0 && line.length > 0) { | ||
return ""; | ||
} | ||
hasSeenLine = true; | ||
const isFullLine = i < lines.length - 1 || fragment.index === fragments.length - 1; | ||
if (indent.length === 0 || isFullLine && indent === line) { | ||
continue; | ||
} | ||
if (smallestIndent === null || indent.length < smallestIndent.length) { | ||
smallestIndent = indent; | ||
} | ||
} | ||
} | ||
if (smallestIndent === null) { | ||
return ""; | ||
} | ||
return smallestIndent; | ||
} | ||
function shouldSkipRemovingLastLine(paddingTracker) { | ||
if (paddingTracker.fragments.length !== 1) { | ||
return false; | ||
} | ||
const lines = paddingTracker.fragments[0].content.split("\n"); | ||
return lines.length === 2 && isWhitespace(lines[0]) && isWhitespace(lines[1]); | ||
} | ||
function getLineIndent(line) { | ||
const match = /[^\n\S]*/.exec(line); | ||
if (match) { | ||
return match[0]; | ||
} else { | ||
return ""; | ||
} | ||
} | ||
function splitUnescapedNewlines(str) { | ||
const lines = [""]; | ||
let numBackslashes = 0; | ||
let isEatingWhitespace = false; | ||
for (const chr of str) { | ||
if (chr === "\n" && numBackslashes % 2 === 0 && !isEatingWhitespace) { | ||
lines.push(""); | ||
} else { | ||
if (chr === "\n" && numBackslashes % 2 === 1) { | ||
isEatingWhitespace = true; | ||
} | ||
if (chr === "\\") { | ||
numBackslashes++; | ||
} else { | ||
numBackslashes = 0; | ||
} | ||
if (!" \n".includes(chr)) { | ||
isEatingWhitespace = false; | ||
} | ||
lines[lines.length - 1] += chr; | ||
} | ||
} | ||
return lines; | ||
} | ||
function isWhitespace(line) { | ||
for (let i = 0; i < line.length; i++) { | ||
if (!" \n".includes(line[i]) && !(line[i] === "\\" && line[i + 1] === "\n")) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
// src/lex.ts | ||
var DEFAULT_OPTIONS = { | ||
useCS2: false | ||
}; | ||
function lex(source, options = DEFAULT_OPTIONS) { | ||
let location; | ||
let previousLocation; | ||
const tokens = []; | ||
const pending = new BufferedStream(stream(source, 0, options)); | ||
do { | ||
pending.unshift(...calculateNormalStringPadding(source, pending)); | ||
pending.unshift(...calculateTripleQuotedStringPadding(source, pending)); | ||
pending.unshift(...calculateHeregexpPadding(source, pending)); | ||
pending.unshift(...combinedLocationsForNegatedOperators(pending, source)); | ||
location = pending.shift(); | ||
if (previousLocation && previousLocation.type !== "SPACE" /* SPACE */) { | ||
tokens.push(new SourceToken(previousLocation.type, previousLocation.index, location.index)); | ||
} | ||
previousLocation = location; | ||
} while (location.type !== "EOF" /* EOF */); | ||
return new SourceTokenList(tokens); | ||
} | ||
function combinedLocationsForNegatedOperators(stream2, source) { | ||
if (!stream2.hasNext("OPERATOR" /* OPERATOR */)) { | ||
return []; | ||
} | ||
const locationsToRestore = []; | ||
function shift() { | ||
const location = stream2.shift(); | ||
locationsToRestore.push(location); | ||
return location; | ||
} | ||
const not = shift(); | ||
const space = shift(); | ||
const text = source.slice(not.index, space.index); | ||
let operator; | ||
if (text === "not") { | ||
if (space.type === "SPACE" /* SPACE */) { | ||
operator = shift(); | ||
} else { | ||
return locationsToRestore; | ||
} | ||
} else if (text === "!") { | ||
if (space.type === "SPACE" /* SPACE */) { | ||
operator = shift(); | ||
} else { | ||
operator = space; | ||
} | ||
} else { | ||
return locationsToRestore; | ||
} | ||
const next = stream2.peek(); | ||
const op = source.slice(operator.index, next.index); | ||
switch (op) { | ||
case "in": | ||
case "of": | ||
return [new SourceLocation("RELATION" /* RELATION */, not.index)]; | ||
case "instanceof": | ||
return [new SourceLocation("OPERATOR" /* OPERATOR */, not.index)]; | ||
} | ||
return locationsToRestore; | ||
} | ||
var REGEXP_FLAGS = ['i', 'g', 'm', 'u', 'y']; | ||
/** | ||
* Borrowed, with tweaks, from CoffeeScript's lexer.coffee. | ||
*/ | ||
var REGEXP_FLAGS = ["i", "g", "m", "u", "y"]; | ||
var STRING = [ | ||
SourceType_1.default.SSTRING_END, | ||
SourceType_1.default.DSTRING_END, | ||
SourceType_1.default.TSSTRING_END, | ||
SourceType_1.default.TDSTRING_END | ||
"SSTRING_END" /* SSTRING_END */, | ||
"DSTRING_END" /* DSTRING_END */, | ||
"TSSTRING_END" /* TSSTRING_END */, | ||
"TDSTRING_END" /* TDSTRING_END */ | ||
]; | ||
var CALLABLE = [ | ||
SourceType_1.default.IDENTIFIER, | ||
SourceType_1.default.CALL_END, | ||
SourceType_1.default.RPAREN, | ||
SourceType_1.default.RBRACKET, | ||
SourceType_1.default.EXISTENCE, | ||
SourceType_1.default.AT, | ||
SourceType_1.default.THIS, | ||
SourceType_1.default.SUPER | ||
"IDENTIFIER" /* IDENTIFIER */, | ||
"CALL_END" /* CALL_END */, | ||
"RPAREN" /* RPAREN */, | ||
"RBRACKET" /* RBRACKET */, | ||
"EXISTENCE" /* EXISTENCE */, | ||
"AT" /* AT */, | ||
"THIS" /* THIS */, | ||
"SUPER" /* SUPER */ | ||
]; | ||
var INDEXABLE = CALLABLE.concat(__spreadArrays([ | ||
SourceType_1.default.NUMBER | ||
], STRING, [ | ||
SourceType_1.default.REGEXP, | ||
SourceType_1.default.HEREGEXP_END, | ||
SourceType_1.default.BOOL, | ||
SourceType_1.default.NULL, | ||
SourceType_1.default.UNDEFINED, | ||
SourceType_1.default.RBRACE, | ||
SourceType_1.default.PROTO | ||
])); | ||
var INDEXABLE = CALLABLE.concat([ | ||
"NUMBER" /* NUMBER */, | ||
...STRING, | ||
"REGEXP" /* REGEXP */, | ||
"HEREGEXP_END" /* HEREGEXP_END */, | ||
"BOOL" /* BOOL */, | ||
"NULL" /* NULL */, | ||
"UNDEFINED" /* UNDEFINED */, | ||
"RBRACE" /* RBRACE */, | ||
"PROTO" /* PROTO */ | ||
]); | ||
var NOT_REGEXP = INDEXABLE.concat([ | ||
SourceType_1.default.INCREMENT, | ||
SourceType_1.default.DECREMENT | ||
"INCREMENT" /* INCREMENT */, | ||
"DECREMENT" /* DECREMENT */ | ||
]); | ||
var IDENTIFIER_PATTERN = /^(?!\d)((?:(?!\s)[$\w\x7f-\uffff])+)/; | ||
// Like identifier, but includes '-' and '.'. | ||
var CSX_IDENTIFIER_PATTERN = /^(?!\d)((?:(?!\s)[.\-$\w\x7f-\uffff])+)/; | ||
@@ -148,750 +910,653 @@ var NUMBER_PATTERN = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i; | ||
var OPERATORS = [ | ||
// equality | ||
'===', | ||
'==', | ||
'!==', | ||
'!=', | ||
// assignment | ||
'=', | ||
'+=', | ||
'-=', | ||
'/=', | ||
'*=', | ||
'%=', | ||
'%%=', | ||
'||=', | ||
'&&=', | ||
'^=', | ||
'or=', | ||
'and=', | ||
'?=', | ||
'|=', | ||
'&=', | ||
'~=', | ||
'<<=', | ||
'>>>=', | ||
'>>=', | ||
// increment/decrement | ||
'++', | ||
'--', | ||
// math | ||
'+', | ||
'-', | ||
'//', | ||
'/', | ||
'*', | ||
'%', | ||
'%%', | ||
// logical | ||
'||', | ||
'&&', | ||
'^', | ||
'!', | ||
// existence | ||
'?', | ||
// bitwise | ||
'|', | ||
'&', | ||
'~', | ||
'<<', | ||
'>>>', | ||
'>>', | ||
// comparison | ||
'<=', | ||
'<', | ||
'>=', | ||
'>', | ||
// prototype access | ||
'::' | ||
"===", | ||
"==", | ||
"!==", | ||
"!=", | ||
"=", | ||
"+=", | ||
"-=", | ||
"/=", | ||
"*=", | ||
"%=", | ||
"%%=", | ||
"||=", | ||
"&&=", | ||
"^=", | ||
"or=", | ||
"and=", | ||
"?=", | ||
"|=", | ||
"&=", | ||
"~=", | ||
"<<=", | ||
">>>=", | ||
">>=", | ||
"++", | ||
"--", | ||
"+", | ||
"-", | ||
"//", | ||
"/", | ||
"*", | ||
"%", | ||
"%%", | ||
"||", | ||
"&&", | ||
"^", | ||
"!", | ||
"?", | ||
"|", | ||
"&", | ||
"~", | ||
"<<", | ||
">>>", | ||
">>", | ||
"<=", | ||
"<", | ||
">=", | ||
">", | ||
"::" | ||
]; | ||
/** | ||
* Provides a stream of source type change locations. | ||
*/ | ||
function stream(source, index, options) { | ||
if (index === void 0) { index = 0; } | ||
if (options === void 0) { options = exports.DEFAULT_OPTIONS; } | ||
var location = new SourceLocation_1.default(SourceType_1.default.NORMAL, index); | ||
var contextStack = []; | ||
var start = index; | ||
var locations = []; | ||
function currentContext() { | ||
return contextStack[contextStack.length - 1] || null; | ||
} | ||
function currentContextType() { | ||
var context = currentContext(); | ||
return context ? context.type : null; | ||
} | ||
return function step() { | ||
var lastLocation = location; | ||
var shouldStepAgain = false; | ||
do { | ||
start = index; | ||
if (index >= source.length) { | ||
setType(SourceType_1.default.EOF); | ||
function stream(source, index = 0, options = DEFAULT_OPTIONS) { | ||
let location = new SourceLocation("NORMAL" /* NORMAL */, index); | ||
const contextStack = []; | ||
let start = index; | ||
const locations = []; | ||
function currentContext() { | ||
return contextStack[contextStack.length - 1] || null; | ||
} | ||
function currentContextType() { | ||
const context = currentContext(); | ||
return context ? context.type : null; | ||
} | ||
return function step() { | ||
const lastLocation = location; | ||
let shouldStepAgain = false; | ||
do { | ||
start = index; | ||
if (index >= source.length) { | ||
setType("EOF" /* EOF */); | ||
} | ||
switch (location.type) { | ||
case "NORMAL" /* NORMAL */: | ||
case "SPACE" /* SPACE */: | ||
case "IDENTIFIER" /* IDENTIFIER */: | ||
case "DOT" /* DOT */: | ||
case "NUMBER" /* NUMBER */: | ||
case "OPERATOR" /* OPERATOR */: | ||
case "INCREMENT" /* INCREMENT */: | ||
case "DECREMENT" /* DECREMENT */: | ||
case "COMMA" /* COMMA */: | ||
case "LPAREN" /* LPAREN */: | ||
case "RPAREN" /* RPAREN */: | ||
case "CALL_START" /* CALL_START */: | ||
case "CALL_END" /* CALL_END */: | ||
case "NEW" /* NEW */: | ||
case "LBRACE" /* LBRACE */: | ||
case "RBRACE" /* RBRACE */: | ||
case "LBRACKET" /* LBRACKET */: | ||
case "RBRACKET" /* RBRACKET */: | ||
case "NEWLINE" /* NEWLINE */: | ||
case "COLON" /* COLON */: | ||
case "FUNCTION" /* FUNCTION */: | ||
case "THIS" /* THIS */: | ||
case "AT" /* AT */: | ||
case "SEMICOLON" /* SEMICOLON */: | ||
case "IF" /* IF */: | ||
case "ELSE" /* ELSE */: | ||
case "THEN" /* THEN */: | ||
case "FOR" /* FOR */: | ||
case "OWN" /* OWN */: | ||
case "WHILE" /* WHILE */: | ||
case "BOOL" /* BOOL */: | ||
case "NULL" /* NULL */: | ||
case "UNDEFINED" /* UNDEFINED */: | ||
case "REGEXP" /* REGEXP */: | ||
case "SSTRING_END" /* SSTRING_END */: | ||
case "DSTRING_END" /* DSTRING_END */: | ||
case "TSSTRING_END" /* TSSTRING_END */: | ||
case "TDSTRING_END" /* TDSTRING_END */: | ||
case "INTERPOLATION_START" /* INTERPOLATION_START */: | ||
case "SUPER" /* SUPER */: | ||
case "TRY" /* TRY */: | ||
case "CATCH" /* CATCH */: | ||
case "FINALLY" /* FINALLY */: | ||
case "SWITCH" /* SWITCH */: | ||
case "WHEN" /* WHEN */: | ||
case "BREAK" /* BREAK */: | ||
case "CONTINUE" /* CONTINUE */: | ||
case "EXISTENCE" /* EXISTENCE */: | ||
case "CLASS" /* CLASS */: | ||
case "PROTO" /* PROTO */: | ||
case "RANGE" /* RANGE */: | ||
case "DELETE" /* DELETE */: | ||
case "RETURN" /* RETURN */: | ||
case "RELATION" /* RELATION */: | ||
case "LOOP" /* LOOP */: | ||
case "DO" /* DO */: | ||
case "YIELD" /* YIELD */: | ||
case "YIELDFROM" /* YIELDFROM */: | ||
case "THROW" /* THROW */: | ||
case "EXTENDS" /* EXTENDS */: | ||
case "IMPORT" /* IMPORT */: | ||
case "EXPORT" /* EXPORT */: | ||
case "DEFAULT" /* DEFAULT */: | ||
case "CSX_OPEN_TAG_START" /* CSX_OPEN_TAG_START */: | ||
case "CSX_CLOSE_TAG_START" /* CSX_CLOSE_TAG_START */: | ||
case "CONTINUATION" /* CONTINUATION */: | ||
if (consume(SPACE_PATTERN)) { | ||
setType("SPACE" /* SPACE */); | ||
} else if (consume("\n")) { | ||
setType("NEWLINE" /* NEWLINE */); | ||
} else if (consume("...") || consume("..")) { | ||
setType("RANGE" /* RANGE */); | ||
} else if (consume(NUMBER_PATTERN)) { | ||
setType("NUMBER" /* NUMBER */); | ||
} else if (consume(".")) { | ||
setType("DOT" /* DOT */); | ||
} else if (consume('"""')) { | ||
contextStack.push({ | ||
type: "STRING" /* STRING */, | ||
allowComments: false, | ||
allowInterpolations: true, | ||
endingDelimiter: '"""', | ||
endSourceType: "TDSTRING_END" /* TDSTRING_END */ | ||
}); | ||
setType("TDSTRING_START" /* TDSTRING_START */); | ||
} else if (consume('"')) { | ||
contextStack.push({ | ||
type: "STRING" /* STRING */, | ||
allowComments: false, | ||
allowInterpolations: true, | ||
endingDelimiter: '"', | ||
endSourceType: "DSTRING_END" /* DSTRING_END */ | ||
}); | ||
setType("DSTRING_START" /* DSTRING_START */); | ||
} else if (consume("'''")) { | ||
contextStack.push({ | ||
type: "STRING" /* STRING */, | ||
allowComments: false, | ||
allowInterpolations: false, | ||
endingDelimiter: "'''", | ||
endSourceType: "TSSTRING_END" /* TSSTRING_END */ | ||
}); | ||
setType("TSSTRING_START" /* TSSTRING_START */); | ||
} else if (consume("'")) { | ||
contextStack.push({ | ||
type: "STRING" /* STRING */, | ||
allowComments: false, | ||
allowInterpolations: false, | ||
endingDelimiter: "'", | ||
endSourceType: "SSTRING_END" /* SSTRING_END */ | ||
}); | ||
setType("SSTRING_START" /* SSTRING_START */); | ||
} else if (consume(/^###[^#]/)) { | ||
setType("HERECOMMENT" /* HERECOMMENT */); | ||
} else if (consume("#")) { | ||
setType("COMMENT" /* COMMENT */); | ||
} else if (consume("///")) { | ||
contextStack.push({ | ||
type: "STRING" /* STRING */, | ||
allowComments: true, | ||
allowInterpolations: true, | ||
endingDelimiter: "///", | ||
endSourceType: "HEREGEXP_END" /* HEREGEXP_END */ | ||
}); | ||
setType("HEREGEXP_START" /* HEREGEXP_START */); | ||
} else if (consume("(")) { | ||
if (CALLABLE.indexOf(location.type) >= 0) { | ||
contextStack.push({ | ||
type: "PAREN" /* PAREN */, | ||
sourceType: "CALL_START" /* CALL_START */ | ||
}); | ||
setType("CALL_START" /* CALL_START */); | ||
} else { | ||
contextStack.push({ | ||
type: "PAREN" /* PAREN */, | ||
sourceType: "LPAREN" /* LPAREN */ | ||
}); | ||
setType("LPAREN" /* LPAREN */); | ||
} | ||
switch (location.type) { | ||
case SourceType_1.default.NORMAL: | ||
case SourceType_1.default.SPACE: | ||
case SourceType_1.default.IDENTIFIER: | ||
case SourceType_1.default.DOT: | ||
case SourceType_1.default.NUMBER: | ||
case SourceType_1.default.OPERATOR: | ||
case SourceType_1.default.INCREMENT: | ||
case SourceType_1.default.DECREMENT: | ||
case SourceType_1.default.COMMA: | ||
case SourceType_1.default.LPAREN: | ||
case SourceType_1.default.RPAREN: | ||
case SourceType_1.default.CALL_START: | ||
case SourceType_1.default.CALL_END: | ||
case SourceType_1.default.NEW: | ||
case SourceType_1.default.LBRACE: | ||
case SourceType_1.default.RBRACE: | ||
case SourceType_1.default.LBRACKET: | ||
case SourceType_1.default.RBRACKET: | ||
case SourceType_1.default.NEWLINE: | ||
case SourceType_1.default.COLON: | ||
case SourceType_1.default.FUNCTION: | ||
case SourceType_1.default.THIS: | ||
case SourceType_1.default.AT: | ||
case SourceType_1.default.SEMICOLON: | ||
case SourceType_1.default.IF: | ||
case SourceType_1.default.ELSE: | ||
case SourceType_1.default.THEN: | ||
case SourceType_1.default.FOR: | ||
case SourceType_1.default.OWN: | ||
case SourceType_1.default.WHILE: | ||
case SourceType_1.default.BOOL: | ||
case SourceType_1.default.NULL: | ||
case SourceType_1.default.UNDEFINED: | ||
case SourceType_1.default.REGEXP: | ||
case SourceType_1.default.SSTRING_END: | ||
case SourceType_1.default.DSTRING_END: | ||
case SourceType_1.default.TSSTRING_END: | ||
case SourceType_1.default.TDSTRING_END: | ||
case SourceType_1.default.INTERPOLATION_START: | ||
case SourceType_1.default.SUPER: | ||
case SourceType_1.default.TRY: | ||
case SourceType_1.default.CATCH: | ||
case SourceType_1.default.FINALLY: | ||
case SourceType_1.default.SWITCH: | ||
case SourceType_1.default.WHEN: | ||
case SourceType_1.default.BREAK: | ||
case SourceType_1.default.CONTINUE: | ||
case SourceType_1.default.EXISTENCE: | ||
case SourceType_1.default.CLASS: | ||
case SourceType_1.default.PROTO: | ||
case SourceType_1.default.RANGE: | ||
case SourceType_1.default.DELETE: | ||
case SourceType_1.default.RETURN: | ||
case SourceType_1.default.RELATION: | ||
case SourceType_1.default.LOOP: | ||
case SourceType_1.default.DO: | ||
case SourceType_1.default.YIELD: | ||
case SourceType_1.default.YIELDFROM: | ||
case SourceType_1.default.THROW: | ||
case SourceType_1.default.EXTENDS: | ||
case SourceType_1.default.IMPORT: | ||
case SourceType_1.default.EXPORT: | ||
case SourceType_1.default.DEFAULT: | ||
case SourceType_1.default.CSX_OPEN_TAG_START: | ||
case SourceType_1.default.CSX_CLOSE_TAG_START: | ||
case SourceType_1.default.CONTINUATION: | ||
if (consume(SPACE_PATTERN)) { | ||
setType(SourceType_1.default.SPACE); | ||
} | ||
else if (consume('\n')) { | ||
setType(SourceType_1.default.NEWLINE); | ||
} | ||
else if (consume('...') || consume('..')) { | ||
setType(SourceType_1.default.RANGE); | ||
} | ||
else if (consume(NUMBER_PATTERN)) { | ||
setType(SourceType_1.default.NUMBER); | ||
} | ||
else if (consume('.')) { | ||
setType(SourceType_1.default.DOT); | ||
} | ||
else if (consume('"""')) { | ||
contextStack.push({ | ||
type: ContextType.STRING, | ||
allowComments: false, | ||
allowInterpolations: true, | ||
endingDelimiter: '"""', | ||
endSourceType: SourceType_1.default.TDSTRING_END | ||
}); | ||
setType(SourceType_1.default.TDSTRING_START); | ||
} | ||
else if (consume('"')) { | ||
contextStack.push({ | ||
type: ContextType.STRING, | ||
allowComments: false, | ||
allowInterpolations: true, | ||
endingDelimiter: '"', | ||
endSourceType: SourceType_1.default.DSTRING_END | ||
}); | ||
setType(SourceType_1.default.DSTRING_START); | ||
} | ||
else if (consume("'''")) { | ||
contextStack.push({ | ||
type: ContextType.STRING, | ||
allowComments: false, | ||
allowInterpolations: false, | ||
endingDelimiter: "'''", | ||
endSourceType: SourceType_1.default.TSSTRING_END | ||
}); | ||
setType(SourceType_1.default.TSSTRING_START); | ||
} | ||
else if (consume("'")) { | ||
contextStack.push({ | ||
type: ContextType.STRING, | ||
allowComments: false, | ||
allowInterpolations: false, | ||
endingDelimiter: "'", | ||
endSourceType: SourceType_1.default.SSTRING_END | ||
}); | ||
setType(SourceType_1.default.SSTRING_START); | ||
} | ||
else if (consume(/^###[^#]/)) { | ||
setType(SourceType_1.default.HERECOMMENT); | ||
} | ||
else if (consume('#')) { | ||
setType(SourceType_1.default.COMMENT); | ||
} | ||
else if (consume('///')) { | ||
contextStack.push({ | ||
type: ContextType.STRING, | ||
allowComments: true, | ||
allowInterpolations: true, | ||
endingDelimiter: '///', | ||
endSourceType: SourceType_1.default.HEREGEXP_END | ||
}); | ||
setType(SourceType_1.default.HEREGEXP_START); | ||
} | ||
else if (consume('(')) { | ||
if (CALLABLE.indexOf(location.type) >= 0) { | ||
contextStack.push({ | ||
type: ContextType.PAREN, | ||
sourceType: SourceType_1.default.CALL_START | ||
}); | ||
setType(SourceType_1.default.CALL_START); | ||
} | ||
else { | ||
contextStack.push({ | ||
type: ContextType.PAREN, | ||
sourceType: SourceType_1.default.LPAREN | ||
}); | ||
setType(SourceType_1.default.LPAREN); | ||
} | ||
} | ||
else if (consume(')')) { | ||
var context = contextStack.pop(); | ||
if (!context || context.type !== ContextType.PAREN) { | ||
throw new Error("unexpected ')' at " + start); | ||
} | ||
var sourceType = context.sourceType; | ||
switch (sourceType) { | ||
case SourceType_1.default.LPAREN: | ||
setType(SourceType_1.default.RPAREN); | ||
break; | ||
case SourceType_1.default.CALL_START: | ||
setType(SourceType_1.default.CALL_END); | ||
break; | ||
default: | ||
throw new Error("unexpected token type for '(' matching ')' at " + start + ": " + (sourceType ? sourceType.toString() : '??')); | ||
} | ||
} | ||
else if (consume('[')) { | ||
setType(SourceType_1.default.LBRACKET); | ||
} | ||
else if (consume(']')) { | ||
setType(SourceType_1.default.RBRACKET); | ||
} | ||
else if (consume('{')) { | ||
contextStack.push({ type: ContextType.BRACE }); | ||
setType(SourceType_1.default.LBRACE); | ||
} | ||
else if (consume('}')) { | ||
if (currentContextType() === ContextType.INTERPOLATION) { | ||
popInterpolation(); | ||
} | ||
else if (currentContextType() === ContextType.BRACE) { | ||
contextStack.pop(); | ||
setType(SourceType_1.default.RBRACE); | ||
} | ||
else { | ||
throw new Error("Unexpected context type: " + currentContextType()); | ||
} | ||
} | ||
else if (consumeCSXOpenTagStart()) { | ||
contextStack.push({ type: ContextType.CSX_OPEN_TAG }); | ||
setType(SourceType_1.default.CSX_OPEN_TAG_START); | ||
} | ||
else if (currentContextType() === ContextType.CSX_OPEN_TAG && | ||
consume('>')) { | ||
contextStack.pop(); | ||
setType(SourceType_1.default.CSX_OPEN_TAG_END); | ||
} | ||
else if (currentContextType() === ContextType.CSX_OPEN_TAG && | ||
consume('/>')) { | ||
contextStack.pop(); | ||
setType(SourceType_1.default.CSX_SELF_CLOSING_TAG_END); | ||
} | ||
else if (currentContextType() === ContextType.CSX_CLOSE_TAG && | ||
consume('>')) { | ||
contextStack.pop(); | ||
setType(SourceType_1.default.CSX_CLOSE_TAG_END); | ||
} | ||
else if (consumeAny(['->', '=>'])) { | ||
setType(SourceType_1.default.FUNCTION); | ||
} | ||
else if (consumeRegexp()) { | ||
setType(SourceType_1.default.REGEXP); | ||
} | ||
else if (consume('::')) { | ||
setType(SourceType_1.default.PROTO); | ||
} | ||
else if (consume(':')) { | ||
setType(SourceType_1.default.COLON); | ||
} | ||
else if (consume(',')) { | ||
setType(SourceType_1.default.COMMA); | ||
} | ||
else if (consume('@')) { | ||
setType(SourceType_1.default.AT); | ||
} | ||
else if (consume(';')) { | ||
setType(SourceType_1.default.SEMICOLON); | ||
} | ||
else if (consume('```')) { | ||
setType(SourceType_1.default.HEREJS); | ||
} | ||
else if (consume('`')) { | ||
setType(SourceType_1.default.JS); | ||
} | ||
else if (consumeAny(OPERATORS)) { | ||
if (consumed() === '?') { | ||
setType(SourceType_1.default.EXISTENCE); | ||
} | ||
else if (consumed() === '++') { | ||
setType(SourceType_1.default.INCREMENT); | ||
} | ||
else if (consumed() === '--') { | ||
setType(SourceType_1.default.DECREMENT); | ||
} | ||
else { | ||
setType(SourceType_1.default.OPERATOR); | ||
} | ||
} | ||
else if (consume(YIELDFROM_PATTERN)) { | ||
setType(SourceType_1.default.YIELDFROM); | ||
} | ||
else if (currentContextType() === ContextType.CSX_OPEN_TAG && | ||
consume(CSX_IDENTIFIER_PATTERN)) { | ||
setType(SourceType_1.default.IDENTIFIER); | ||
} | ||
else if (consume(IDENTIFIER_PATTERN)) { | ||
var prevLocationIndex = locations.length - 1; | ||
while (prevLocationIndex > 0 && | ||
(locations[prevLocationIndex].type === SourceType_1.default.NEWLINE || | ||
locations[prevLocationIndex].type === SourceType_1.default.SPACE)) { | ||
prevLocationIndex--; | ||
} | ||
var prev = locations[prevLocationIndex]; | ||
var nextIsColon = match(/^\s*:/); | ||
if (nextIsColon || | ||
(prev && | ||
// i.e. `a.b` or `a.\nb` | ||
(prev.type === SourceType_1.default.DOT || | ||
// i.e. `a::b` or `a::\nb` | ||
prev.type === SourceType_1.default.PROTO || | ||
// i.e. `@a` (but not `@\na`, since that's `this\na`–see #175) | ||
(prev.type === SourceType_1.default.AT && | ||
prevLocationIndex === locations.length - 1)))) { | ||
setType(SourceType_1.default.IDENTIFIER); | ||
} | ||
else { | ||
switch (consumed()) { | ||
case 'if': | ||
case 'unless': | ||
setType(SourceType_1.default.IF); | ||
break; | ||
case 'else': | ||
setType(SourceType_1.default.ELSE); | ||
break; | ||
case 'return': | ||
setType(SourceType_1.default.RETURN); | ||
break; | ||
case 'for': | ||
setType(SourceType_1.default.FOR); | ||
break; | ||
case 'own': | ||
setType(SourceType_1.default.OWN); | ||
break; | ||
case 'while': | ||
case 'until': | ||
setType(SourceType_1.default.WHILE); | ||
break; | ||
case 'loop': | ||
setType(SourceType_1.default.LOOP); | ||
break; | ||
case 'then': | ||
setType(SourceType_1.default.THEN); | ||
break; | ||
case 'switch': | ||
setType(SourceType_1.default.SWITCH); | ||
break; | ||
case 'when': | ||
setType(SourceType_1.default.WHEN); | ||
break; | ||
case 'null': | ||
setType(SourceType_1.default.NULL); | ||
break; | ||
case 'undefined': | ||
setType(SourceType_1.default.UNDEFINED); | ||
break; | ||
case 'this': | ||
setType(SourceType_1.default.THIS); | ||
break; | ||
case 'new': | ||
setType(SourceType_1.default.NEW); | ||
break; | ||
case 'super': | ||
setType(SourceType_1.default.SUPER); | ||
break; | ||
case 'true': | ||
case 'false': | ||
case 'yes': | ||
case 'no': | ||
case 'on': | ||
case 'off': | ||
setType(SourceType_1.default.BOOL); | ||
break; | ||
case 'and': | ||
case 'or': | ||
case 'not': | ||
case 'is': | ||
case 'isnt': | ||
case 'instanceof': | ||
setType(SourceType_1.default.OPERATOR); | ||
break; | ||
case 'class': | ||
setType(SourceType_1.default.CLASS); | ||
break; | ||
case 'break': | ||
setType(SourceType_1.default.BREAK); | ||
break; | ||
case 'continue': | ||
setType(SourceType_1.default.CONTINUE); | ||
break; | ||
case 'try': | ||
setType(SourceType_1.default.TRY); | ||
break; | ||
case 'catch': | ||
setType(SourceType_1.default.CATCH); | ||
break; | ||
case 'finally': | ||
setType(SourceType_1.default.FINALLY); | ||
break; | ||
case 'delete': | ||
setType(SourceType_1.default.DELETE); | ||
break; | ||
case 'in': | ||
case 'of': | ||
setType(SourceType_1.default.RELATION); | ||
break; | ||
case 'do': | ||
setType(SourceType_1.default.DO); | ||
break; | ||
case 'yield': | ||
setType(SourceType_1.default.YIELD); | ||
break; | ||
case 'throw': | ||
setType(SourceType_1.default.THROW); | ||
break; | ||
case 'extends': | ||
setType(SourceType_1.default.EXTENDS); | ||
break; | ||
case 'import': | ||
setType(SourceType_1.default.IMPORT); | ||
break; | ||
case 'export': | ||
setType(SourceType_1.default.EXPORT); | ||
break; | ||
case 'default': | ||
setType(SourceType_1.default.DEFAULT); | ||
break; | ||
default: | ||
setType(SourceType_1.default.IDENTIFIER); | ||
} | ||
} | ||
} | ||
else if (consume('\\')) { | ||
setType(SourceType_1.default.CONTINUATION); | ||
} | ||
else { | ||
setType(SourceType_1.default.UNKNOWN); | ||
} | ||
break; | ||
case SourceType_1.default.SSTRING_START: | ||
case SourceType_1.default.DSTRING_START: | ||
case SourceType_1.default.TSSTRING_START: | ||
case SourceType_1.default.TDSTRING_START: | ||
case SourceType_1.default.HEREGEXP_START: | ||
setType(SourceType_1.default.STRING_CONTENT); | ||
break; | ||
case SourceType_1.default.STRING_CONTENT: { | ||
var context = currentContext(); | ||
if (!context || context.type !== ContextType.STRING) { | ||
throw new Error('Unexpected STRING_CONTENT without anything on the string stack.'); | ||
} | ||
var allowComments = context.allowComments, allowInterpolations = context.allowInterpolations, endingDelimiter = context.endingDelimiter, endSourceType = context.endSourceType; | ||
if (consume('\\')) { | ||
index++; | ||
} | ||
else if (consume(endingDelimiter)) { | ||
contextStack.pop(); | ||
setType(endSourceType); | ||
} | ||
else if (allowInterpolations && consume('#{')) { | ||
pushInterpolation(); | ||
} | ||
else if (options.useCS2 && | ||
allowComments && | ||
source[index - 1].match(/\s/) && | ||
match('#') && | ||
!match('#{')) { | ||
setType(SourceType_1.default.HEREGEXP_COMMENT); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
} | ||
case SourceType_1.default.COMMENT: | ||
if (consume('\n')) { | ||
setType(SourceType_1.default.NEWLINE); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
case SourceType_1.default.HERECOMMENT: | ||
if (consume('###')) { | ||
setType(SourceType_1.default.NORMAL); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
case SourceType_1.default.HEREGEXP_COMMENT: | ||
if (consume('\n')) { | ||
setType(SourceType_1.default.STRING_CONTENT); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
case SourceType_1.default.INTERPOLATION_END: { | ||
var context = contextStack.pop(); | ||
if (!context || context.type !== ContextType.INTERPOLATION) { | ||
throw new Error("found interpolation end without any interpolation start"); | ||
} | ||
setType(context.interpolationType); | ||
break; | ||
} | ||
case SourceType_1.default.HEREGEXP_END: | ||
while (consumeAny(REGEXP_FLAGS)) { | ||
// condition has side-effect | ||
} | ||
setType(SourceType_1.default.NORMAL); | ||
break; | ||
case SourceType_1.default.JS: | ||
if (consume('\\')) { | ||
index++; | ||
} | ||
else if (consume('`')) { | ||
setType(SourceType_1.default.NORMAL); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
case SourceType_1.default.HEREJS: | ||
if (consume('\\')) { | ||
index++; | ||
} | ||
else if (consume('```')) { | ||
setType(SourceType_1.default.NORMAL); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
case SourceType_1.default.CSX_OPEN_TAG_END: | ||
setType(SourceType_1.default.CSX_BODY); | ||
contextStack.push({ type: ContextType.CSX_BODY }); | ||
break; | ||
case SourceType_1.default.CSX_BODY: { | ||
if (consume('</')) { | ||
contextStack.pop(); | ||
setType(SourceType_1.default.CSX_CLOSE_TAG_START); | ||
contextStack.push({ type: ContextType.CSX_CLOSE_TAG }); | ||
} | ||
else if (consumeCSXOpenTagStart()) { | ||
setType(SourceType_1.default.CSX_OPEN_TAG_START); | ||
contextStack.push({ type: ContextType.CSX_OPEN_TAG }); | ||
} | ||
else if (consume('{')) { | ||
pushInterpolation(); | ||
} | ||
else { | ||
index++; | ||
} | ||
break; | ||
} | ||
case SourceType_1.default.CSX_SELF_CLOSING_TAG_END: | ||
case SourceType_1.default.CSX_CLOSE_TAG_END: | ||
if (currentContextType() === ContextType.CSX_BODY) { | ||
setType(SourceType_1.default.CSX_BODY); | ||
} | ||
else { | ||
setType(SourceType_1.default.NORMAL); | ||
} | ||
break; | ||
case SourceType_1.default.EOF: { | ||
var context = currentContext(); | ||
if (context !== null) { | ||
throw new Error("unexpected EOF while in context " + context.type); | ||
} | ||
break; | ||
} | ||
case SourceType_1.default.UNKNOWN: | ||
// Jump to the end. | ||
index = source.length; | ||
break; | ||
default: | ||
throw new Error("unknown source type at offset " + location.index + ": " + SourceType_1.default[location.type]); | ||
} else if (consume(")")) { | ||
const context = contextStack.pop(); | ||
if (!context || context.type !== "PAREN" /* PAREN */) { | ||
throw new Error(`unexpected ')' at ${start}`); | ||
} | ||
shouldStepAgain = | ||
// Don't report on going back to "normal" source code. | ||
location.type === SourceType_1.default.NORMAL || | ||
// Don't report if nothing has changed, unless we're at the end. | ||
(location === lastLocation && location.type !== SourceType_1.default.EOF); | ||
} while (shouldStepAgain); | ||
locations.push(location); | ||
return location; | ||
}; | ||
function consumeAny(strings) { | ||
return strings.some(function (string) { return consume(string); }); | ||
} | ||
function consume(value) { | ||
var matchData = match(value); | ||
if (matchData) { | ||
index += matchData[0].length; | ||
return true; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
function consumeRegexp() { | ||
var matchData = match(REGEXP_PATTERN); | ||
if (!matchData) { | ||
return false; | ||
} | ||
var regex = matchData[0], closed = matchData[2]; | ||
var prev = locations[locations.length - 1]; | ||
if (prev) { | ||
var spaced = false; | ||
if (prev.type === SourceType_1.default.SPACE) { | ||
spaced = true; | ||
prev = locations[locations.length - 2]; | ||
const { sourceType } = context; | ||
switch (sourceType) { | ||
case "LPAREN" /* LPAREN */: | ||
setType("RPAREN" /* RPAREN */); | ||
break; | ||
case "CALL_START" /* CALL_START */: | ||
setType("CALL_END" /* CALL_END */); | ||
break; | ||
default: | ||
throw new Error(`unexpected token type for '(' matching ')' at ${start}: ${sourceType ? sourceType.toString() : "??"}`); | ||
} | ||
if (spaced && CALLABLE.indexOf(prev.type) >= 0) { | ||
if (!closed || /^\/=?\s/.test(regex)) { | ||
return false; | ||
} | ||
} else if (consume("[")) { | ||
setType("LBRACKET" /* LBRACKET */); | ||
} else if (consume("]")) { | ||
setType("RBRACKET" /* RBRACKET */); | ||
} else if (consume("{")) { | ||
contextStack.push({ type: "BRACE" /* BRACE */ }); | ||
setType("LBRACE" /* LBRACE */); | ||
} else if (consume("}")) { | ||
if (currentContextType() === "INTERPOLATION" /* INTERPOLATION */) { | ||
popInterpolation(); | ||
} else if (currentContextType() === "BRACE" /* BRACE */) { | ||
contextStack.pop(); | ||
setType("RBRACE" /* RBRACE */); | ||
} else { | ||
throw new Error(`Unexpected context type: ${currentContextType()}`); | ||
} | ||
else if (NOT_REGEXP.indexOf(prev.type) >= 0) { | ||
return false; | ||
} else if (consumeCSXOpenTagStart()) { | ||
contextStack.push({ type: "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ }); | ||
setType("CSX_OPEN_TAG_START" /* CSX_OPEN_TAG_START */); | ||
} else if (currentContextType() === "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && consume(">")) { | ||
contextStack.pop(); | ||
setType("CSX_OPEN_TAG_END" /* CSX_OPEN_TAG_END */); | ||
} else if (currentContextType() === "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && consume("/>")) { | ||
contextStack.pop(); | ||
setType("CSX_SELF_CLOSING_TAG_END" /* CSX_SELF_CLOSING_TAG_END */); | ||
} else if (currentContextType() === "CSX_CLOSE_TAG" /* CSX_CLOSE_TAG */ && consume(">")) { | ||
contextStack.pop(); | ||
setType("CSX_CLOSE_TAG_END" /* CSX_CLOSE_TAG_END */); | ||
} else if (consumeAny(["->", "=>"])) { | ||
setType("FUNCTION" /* FUNCTION */); | ||
} else if (consumeRegexp()) { | ||
setType("REGEXP" /* REGEXP */); | ||
} else if (consume("::")) { | ||
setType("PROTO" /* PROTO */); | ||
} else if (consume(":")) { | ||
setType("COLON" /* COLON */); | ||
} else if (consume(",")) { | ||
setType("COMMA" /* COMMA */); | ||
} else if (consume("@")) { | ||
setType("AT" /* AT */); | ||
} else if (consume(";")) { | ||
setType("SEMICOLON" /* SEMICOLON */); | ||
} else if (consume("```")) { | ||
setType("HEREJS" /* HEREJS */); | ||
} else if (consume("`")) { | ||
setType("JS" /* JS */); | ||
} else if (consumeAny(OPERATORS)) { | ||
if (consumed() === "?") { | ||
setType("EXISTENCE" /* EXISTENCE */); | ||
} else if (consumed() === "++") { | ||
setType("INCREMENT" /* INCREMENT */); | ||
} else if (consumed() === "--") { | ||
setType("DECREMENT" /* DECREMENT */); | ||
} else { | ||
setType("OPERATOR" /* OPERATOR */); | ||
} | ||
} else if (consume(YIELDFROM_PATTERN)) { | ||
setType("YIELDFROM" /* YIELDFROM */); | ||
} else if (currentContextType() === "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && consume(CSX_IDENTIFIER_PATTERN)) { | ||
setType("IDENTIFIER" /* IDENTIFIER */); | ||
} else if (consume(IDENTIFIER_PATTERN)) { | ||
let prevLocationIndex = locations.length - 1; | ||
while (prevLocationIndex > 0 && (locations[prevLocationIndex].type === "NEWLINE" /* NEWLINE */ || locations[prevLocationIndex].type === "SPACE" /* SPACE */)) { | ||
prevLocationIndex--; | ||
} | ||
const prev = locations[prevLocationIndex]; | ||
const nextIsColon = match(/^\s*:/); | ||
if (nextIsColon || prev && (prev.type === "DOT" /* DOT */ || prev.type === "PROTO" /* PROTO */ || prev.type === "AT" /* AT */ && prevLocationIndex === locations.length - 1)) { | ||
setType("IDENTIFIER" /* IDENTIFIER */); | ||
} else { | ||
switch (consumed()) { | ||
case "if": | ||
case "unless": | ||
setType("IF" /* IF */); | ||
break; | ||
case "else": | ||
setType("ELSE" /* ELSE */); | ||
break; | ||
case "return": | ||
setType("RETURN" /* RETURN */); | ||
break; | ||
case "for": | ||
setType("FOR" /* FOR */); | ||
break; | ||
case "own": | ||
setType("OWN" /* OWN */); | ||
break; | ||
case "while": | ||
case "until": | ||
setType("WHILE" /* WHILE */); | ||
break; | ||
case "loop": | ||
setType("LOOP" /* LOOP */); | ||
break; | ||
case "then": | ||
setType("THEN" /* THEN */); | ||
break; | ||
case "switch": | ||
setType("SWITCH" /* SWITCH */); | ||
break; | ||
case "when": | ||
setType("WHEN" /* WHEN */); | ||
break; | ||
case "null": | ||
setType("NULL" /* NULL */); | ||
break; | ||
case "undefined": | ||
setType("UNDEFINED" /* UNDEFINED */); | ||
break; | ||
case "this": | ||
setType("THIS" /* THIS */); | ||
break; | ||
case "new": | ||
setType("NEW" /* NEW */); | ||
break; | ||
case "super": | ||
setType("SUPER" /* SUPER */); | ||
break; | ||
case "true": | ||
case "false": | ||
case "yes": | ||
case "no": | ||
case "on": | ||
case "off": | ||
setType("BOOL" /* BOOL */); | ||
break; | ||
case "and": | ||
case "or": | ||
case "not": | ||
case "is": | ||
case "isnt": | ||
case "instanceof": | ||
setType("OPERATOR" /* OPERATOR */); | ||
break; | ||
case "class": | ||
setType("CLASS" /* CLASS */); | ||
break; | ||
case "break": | ||
setType("BREAK" /* BREAK */); | ||
break; | ||
case "continue": | ||
setType("CONTINUE" /* CONTINUE */); | ||
break; | ||
case "try": | ||
setType("TRY" /* TRY */); | ||
break; | ||
case "catch": | ||
setType("CATCH" /* CATCH */); | ||
break; | ||
case "finally": | ||
setType("FINALLY" /* FINALLY */); | ||
break; | ||
case "delete": | ||
setType("DELETE" /* DELETE */); | ||
break; | ||
case "in": | ||
case "of": | ||
setType("RELATION" /* RELATION */); | ||
break; | ||
case "do": | ||
setType("DO" /* DO */); | ||
break; | ||
case "yield": | ||
setType("YIELD" /* YIELD */); | ||
break; | ||
case "throw": | ||
setType("THROW" /* THROW */); | ||
break; | ||
case "extends": | ||
setType("EXTENDS" /* EXTENDS */); | ||
break; | ||
case "import": | ||
setType("IMPORT" /* IMPORT */); | ||
break; | ||
case "export": | ||
setType("EXPORT" /* EXPORT */); | ||
break; | ||
case "default": | ||
setType("DEFAULT" /* DEFAULT */); | ||
break; | ||
default: | ||
setType("IDENTIFIER" /* IDENTIFIER */); | ||
} | ||
} | ||
} else if (consume("\\")) { | ||
setType("CONTINUATION" /* CONTINUATION */); | ||
} else { | ||
setType("UNKNOWN" /* UNKNOWN */); | ||
} | ||
break; | ||
case "SSTRING_START" /* SSTRING_START */: | ||
case "DSTRING_START" /* DSTRING_START */: | ||
case "TSSTRING_START" /* TSSTRING_START */: | ||
case "TDSTRING_START" /* TDSTRING_START */: | ||
case "HEREGEXP_START" /* HEREGEXP_START */: | ||
setType("STRING_CONTENT" /* STRING_CONTENT */); | ||
break; | ||
case "STRING_CONTENT" /* STRING_CONTENT */: { | ||
const context = currentContext(); | ||
if (!context || context.type !== "STRING" /* STRING */) { | ||
throw new Error("Unexpected STRING_CONTENT without anything on the string stack."); | ||
} | ||
const { | ||
allowComments, | ||
allowInterpolations, | ||
endingDelimiter, | ||
endSourceType | ||
} = context; | ||
if (consume("\\")) { | ||
index++; | ||
} else if (consume(endingDelimiter)) { | ||
contextStack.pop(); | ||
setType(endSourceType); | ||
} else if (allowInterpolations && consume("#{")) { | ||
pushInterpolation(); | ||
} else if (options.useCS2 && allowComments && source[index - 1].match(/\s/) && match("#") && !match("#{")) { | ||
setType("HEREGEXP_COMMENT" /* HEREGEXP_COMMENT */); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
} | ||
if (!closed) { | ||
throw new Error('missing / (unclosed regex)'); | ||
case "COMMENT" /* COMMENT */: | ||
if (consume("\n")) { | ||
setType("NEWLINE" /* NEWLINE */); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
case "HERECOMMENT" /* HERECOMMENT */: | ||
if (consume("###")) { | ||
setType("NORMAL" /* NORMAL */); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
case "HEREGEXP_COMMENT" /* HEREGEXP_COMMENT */: | ||
if (consume("\n")) { | ||
setType("STRING_CONTENT" /* STRING_CONTENT */); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
case "INTERPOLATION_END" /* INTERPOLATION_END */: { | ||
const context = contextStack.pop(); | ||
if (!context || context.type !== "INTERPOLATION" /* INTERPOLATION */) { | ||
throw new Error(`found interpolation end without any interpolation start`); | ||
} | ||
setType(context.interpolationType); | ||
break; | ||
} | ||
index += regex.length; | ||
while (consumeAny(REGEXP_FLAGS)) { | ||
// condition has side-effect | ||
case "HEREGEXP_END" /* HEREGEXP_END */: | ||
while (consumeAny(REGEXP_FLAGS)) { | ||
} | ||
setType("NORMAL" /* NORMAL */); | ||
break; | ||
case "JS" /* JS */: | ||
if (consume("\\")) { | ||
index++; | ||
} else if (consume("`")) { | ||
setType("NORMAL" /* NORMAL */); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
case "HEREJS" /* HEREJS */: | ||
if (consume("\\")) { | ||
index++; | ||
} else if (consume("```")) { | ||
setType("NORMAL" /* NORMAL */); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
case "CSX_OPEN_TAG_END" /* CSX_OPEN_TAG_END */: | ||
setType("CSX_BODY" /* CSX_BODY */); | ||
contextStack.push({ type: "CSX_BODY" /* CSX_BODY */ }); | ||
break; | ||
case "CSX_BODY" /* CSX_BODY */: { | ||
if (consume("</")) { | ||
contextStack.pop(); | ||
setType("CSX_CLOSE_TAG_START" /* CSX_CLOSE_TAG_START */); | ||
contextStack.push({ type: "CSX_CLOSE_TAG" /* CSX_CLOSE_TAG */ }); | ||
} else if (consumeCSXOpenTagStart()) { | ||
setType("CSX_OPEN_TAG_START" /* CSX_OPEN_TAG_START */); | ||
contextStack.push({ type: "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ }); | ||
} else if (consume("{")) { | ||
pushInterpolation(); | ||
} else { | ||
index++; | ||
} | ||
break; | ||
} | ||
return true; | ||
case "CSX_SELF_CLOSING_TAG_END" /* CSX_SELF_CLOSING_TAG_END */: | ||
case "CSX_CLOSE_TAG_END" /* CSX_CLOSE_TAG_END */: | ||
if (currentContextType() === "CSX_BODY" /* CSX_BODY */) { | ||
setType("CSX_BODY" /* CSX_BODY */); | ||
} else { | ||
setType("NORMAL" /* NORMAL */); | ||
} | ||
break; | ||
case "EOF" /* EOF */: { | ||
const context = currentContext(); | ||
if (context !== null) { | ||
throw new Error(`unexpected EOF while in context ${context.type}`); | ||
} | ||
break; | ||
} | ||
case "UNKNOWN" /* UNKNOWN */: | ||
index = source.length; | ||
break; | ||
case "STRING_LINE_SEPARATOR" /* STRING_LINE_SEPARATOR */: | ||
case "STRING_PADDING" /* STRING_PADDING */: | ||
throw new Error(`unexpected source type at offset ${location.index}: ${location.type}`); | ||
default: | ||
assertNever(location.type, `unexpected source type at offset ${location.index}: ${location.type}`); | ||
} | ||
shouldStepAgain = location.type === "NORMAL" /* NORMAL */ || location === lastLocation && location.type !== "EOF" /* EOF */; | ||
} while (shouldStepAgain); | ||
locations.push(location); | ||
return location; | ||
}; | ||
function consumeAny(strings) { | ||
return strings.some((string) => consume(string)); | ||
} | ||
function consume(value) { | ||
const matchData = match(value); | ||
if (matchData) { | ||
index += matchData[0].length; | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
/** | ||
* CSX starts are identified by a less-than sign followed by a CSX identifier | ||
* or `<>` token (no space allowed after the less-than). | ||
* | ||
* We also bail in cases like `a<b`: if we're not already in a CSX context, | ||
* the less-than needs to be preceded by a space or a token other than identifier, | ||
* close-paren, close-bracket, or number. | ||
*/ | ||
function consumeCSXOpenTagStart() { | ||
if (!match('<')) { | ||
return false; | ||
} | ||
function consumeRegexp() { | ||
const matchData = match(REGEXP_PATTERN); | ||
if (!matchData) { | ||
return false; | ||
} | ||
const [regex, , closed] = matchData; | ||
let prev = locations[locations.length - 1]; | ||
if (prev) { | ||
let spaced = false; | ||
if (prev.type === "SPACE" /* SPACE */) { | ||
spaced = true; | ||
prev = locations[locations.length - 2]; | ||
} | ||
if (spaced && CALLABLE.indexOf(prev.type) >= 0) { | ||
if (!closed || /^\/=?\s/.test(regex)) { | ||
return false; | ||
} | ||
if (source[index + 1] !== '>' && | ||
!source.slice(index + 1).match(CSX_IDENTIFIER_PATTERN)) { | ||
return false; | ||
} | ||
var contextType = currentContextType(); | ||
if (contextType !== ContextType.CSX_BODY && | ||
contextType !== ContextType.CSX_OPEN_TAG && | ||
[ | ||
SourceType_1.default.IDENTIFIER, | ||
SourceType_1.default.RPAREN, | ||
SourceType_1.default.RBRACKET, | ||
SourceType_1.default.NUMBER | ||
].includes(location.type)) { | ||
return false; | ||
} | ||
consume('<'); | ||
return true; | ||
} else if (NOT_REGEXP.indexOf(prev.type) >= 0) { | ||
return false; | ||
} | ||
} | ||
function consumed() { | ||
return source.slice(start, index); | ||
if (!closed) { | ||
throw new Error("missing / (unclosed regex)"); | ||
} | ||
function setType(newType) { | ||
location = new SourceLocation_1.default(newType, start); | ||
index += regex.length; | ||
while (consumeAny(REGEXP_FLAGS)) { | ||
} | ||
function match(value) { | ||
if (typeof value === 'string') { | ||
var matches = source.slice(index, index + value.length) === value; | ||
return matches ? [value] : null; | ||
} | ||
else { | ||
return source.slice(index).match(value); | ||
} | ||
return true; | ||
} | ||
function consumeCSXOpenTagStart() { | ||
if (!match("<")) { | ||
return false; | ||
} | ||
function pushInterpolation() { | ||
contextStack.push({ | ||
type: ContextType.INTERPOLATION, | ||
interpolationType: location.type | ||
}); | ||
setType(SourceType_1.default.INTERPOLATION_START); | ||
if (source[index + 1] !== ">" && !source.slice(index + 1).match(CSX_IDENTIFIER_PATTERN)) { | ||
return false; | ||
} | ||
function popInterpolation() { | ||
if (currentContextType() !== ContextType.INTERPOLATION) { | ||
throw new Error("unexpected '}' found in string at " + index + ": " + JSON.stringify(source)); | ||
} | ||
setType(SourceType_1.default.INTERPOLATION_END); | ||
const contextType = currentContextType(); | ||
if (contextType !== "CSX_BODY" /* CSX_BODY */ && contextType !== "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && [ | ||
"IDENTIFIER" /* IDENTIFIER */, | ||
"RPAREN" /* RPAREN */, | ||
"RBRACKET" /* RBRACKET */, | ||
"NUMBER" /* NUMBER */ | ||
].includes(location.type)) { | ||
return false; | ||
} | ||
consume("<"); | ||
return true; | ||
} | ||
function consumed() { | ||
return source.slice(start, index); | ||
} | ||
function setType(newType) { | ||
location = new SourceLocation(newType, start); | ||
} | ||
function match(value) { | ||
if (typeof value === "string") { | ||
const matches = source.slice(index, index + value.length) === value; | ||
return matches ? [value] : null; | ||
} else { | ||
return source.slice(index).match(value); | ||
} | ||
} | ||
function pushInterpolation() { | ||
contextStack.push({ | ||
type: "INTERPOLATION" /* INTERPOLATION */, | ||
interpolationType: location.type | ||
}); | ||
setType("INTERPOLATION_START" /* INTERPOLATION_START */); | ||
} | ||
function popInterpolation() { | ||
if (currentContextType() !== "INTERPOLATION" /* INTERPOLATION */) { | ||
throw new Error(`unexpected '}' found in string at ${index}: ${JSON.stringify(source)}`); | ||
} | ||
setType("INTERPOLATION_END" /* INTERPOLATION_END */); | ||
} | ||
} | ||
exports.stream = stream; | ||
function consumeStream(lexer) { | ||
var result = []; | ||
var location; | ||
do { | ||
location = lexer(); | ||
result.push(location); | ||
} while (location.type !== SourceType_1.default.EOF); | ||
return result; | ||
const result = []; | ||
let location; | ||
do { | ||
location = lexer(); | ||
result.push(location); | ||
} while (location.type !== "EOF" /* EOF */); | ||
return result; | ||
} | ||
exports.consumeStream = consumeStream; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
DEFAULT_OPTIONS, | ||
SourceType, | ||
consumeStream, | ||
lex, | ||
stream | ||
}); |
105
package.json
{ | ||
"name": "coffee-lex", | ||
"version": "9.1.5", | ||
"version": "9.2.0", | ||
"description": "Stupid lexer for CoffeeScript.", | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"reformat": "yarn lint --fix", | ||
"lint": "eslint 'src/**/*.ts'", | ||
"lint:fix": "yarn lint --fix", | ||
"pretest": "yarn lint", | ||
"test": "jest", | ||
"prepare": "script/build.ts" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/decaffeinate/coffee-lex.git" | ||
}, | ||
"keywords": [ | ||
@@ -26,37 +11,75 @@ "coffee", | ||
], | ||
"homepage": "https://github.com/decaffeinate/coffee-lex", | ||
"bugs": { | ||
"url": "https://github.com/decaffeinate/coffee-lex/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/decaffeinate/coffee-lex.git" | ||
}, | ||
"license": "MIT", | ||
"author": "Brian Donovan", | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js" | ||
} | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"author": "Brian Donovan", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/decaffeinate/coffee-lex/issues" | ||
"scripts": { | ||
"lint": "eslint 'src/**/*.ts'", | ||
"lint:fix": "pnpm lint --fix", | ||
"build": "tsup", | ||
"prepublishOnly": "pnpm build", | ||
"reformat": "pnpm lint --fix", | ||
"pretest": "pnpm lint", | ||
"test": "jest", | ||
"test:ci": "jest --ci" | ||
}, | ||
"homepage": "https://github.com/decaffeinate/coffee-lex", | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.{ts,md,json}": [ | ||
"prettier --write" | ||
], | ||
"package.json": [ | ||
"sort-package-json" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@microsoft/node-core-library": "^3.7.1", | ||
"@types/fs-extra": "^8.0.0", | ||
"@types/globby": "^9.1.0", | ||
"@types/jest": "^24.0.18", | ||
"@types/node": "^12.0.8", | ||
"@typescript-eslint/eslint-plugin": "^2.0.0", | ||
"@typescript-eslint/parser": "^2.0.0", | ||
"@types/jest": "^28.1.1", | ||
"@types/node": "14", | ||
"@typescript-eslint/eslint-plugin": "^5.27.1", | ||
"@typescript-eslint/parser": "^5.27.1", | ||
"decaffeinate-coffeescript": "1.12.7-patch.3", | ||
"eslint": "^6.1.0", | ||
"eslint-config-prettier": "^6.0.0", | ||
"eslint-plugin-jest": "^22.12.0", | ||
"eslint-plugin-prettier": "^3.1.0", | ||
"fs-extra": "^8.0.1", | ||
"globby": "^10.0.0", | ||
"jest": "^24.9.0", | ||
"jest-junit": "^8.0.0", | ||
"prettier": "^1.15.2", | ||
"prettier-check": "2.0.0", | ||
"ts-jest": "^24.0.0", | ||
"ts-node": "^8.0.2", | ||
"typescript": "^3.5.2" | ||
"eslint": "^8.17.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-jest": "^26.5.3", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"husky": "^8.0.1", | ||
"jest": "^28.1.1", | ||
"lint-staged": "^13.0.0", | ||
"prettier": "^2.6.2", | ||
"sort-package-json": "^1.57.0", | ||
"ts-jest": "^28.0.4", | ||
"tsup": "^6.1.0", | ||
"typescript": "^4.7.3" | ||
}, | ||
"publishConfig": { | ||
"registry": "https://registry.npmjs.org/" | ||
}, | ||
"release": { | ||
"branches": [ | ||
"main" | ||
] | ||
} | ||
} |
@@ -19,9 +19,9 @@ # coffee-lex [![Build Status](https://circleci.com/gh/decaffeinate/coffee-lex/tree/master.svg?style=svg)](https://circleci.com/gh/decaffeinate/coffee-lex/tree/master) [![package version](https://badge.fury.io/js/coffee-lex.svg)](https://badge.fury.io/js/coffee-lex) [![Greenkeeper badge](https://badges.greenkeeper.io/decaffeinate/coffee-lex.svg)](https://greenkeeper.io/) | ||
```js | ||
import lex, { SourceType } from 'coffee-lex'; | ||
import lex, { SourceType } from 'coffee-lex' | ||
let source = 'a?(b: c)'; | ||
let tokens = lex(source); | ||
const source = 'a?(b: c)' | ||
const tokens = lex(source) | ||
// Print tokens along with their source. | ||
tokens.forEach(token => | ||
tokens.forEach((token) => | ||
console.log( | ||
@@ -32,3 +32,3 @@ SourceType[token.type], | ||
) | ||
); | ||
) | ||
// IDENTIFIER "a" 0→1 | ||
@@ -49,5 +49,5 @@ // EXISTENCE "?" 1→2 | ||
let source = 'a?(b: c)'; | ||
let step = stream(source); | ||
let location; | ||
const source = 'a?(b: c)'; | ||
const step = stream(source); | ||
const location; | ||
@@ -88,3 +88,3 @@ do { | ||
```js | ||
[ | ||
;[ | ||
[ | ||
@@ -94,19 +94,40 @@ 'STRING_START', | ||
{ first_line: 0, first_column: 0, last_line: 0, last_column: 0 }, | ||
(origin: ['STRING', null, [Object]]) | ||
(origin: ['STRING', null, [Object]]), | ||
], | ||
['STRING', '"a"', { first_line: 0, first_column: 0, last_line: 0, last_column: 1 }], | ||
[ | ||
'STRING', | ||
'"a"', | ||
{ first_line: 0, first_column: 0, last_line: 0, last_column: 1 }, | ||
], | ||
['+', '+', { first_line: 0, first_column: 3, last_line: 0, last_column: 3 }], | ||
['(', '(', { first_line: 0, first_column: 3, last_line: 0, last_column: 3 }], | ||
['IDENTIFIER', 'b', { first_line: 0, first_column: 4, last_line: 0, last_column: 4 }, (variable: true)], | ||
[ | ||
'IDENTIFIER', | ||
'b', | ||
{ first_line: 0, first_column: 4, last_line: 0, last_column: 4 }, | ||
(variable: true), | ||
], | ||
[ | ||
')', | ||
')', | ||
{ first_line: 0, first_column: 5, last_line: 0, last_column: 5 }, | ||
(origin: ['', 'end of interpolation', [Object]]) | ||
(origin: ['', 'end of interpolation', [Object]]), | ||
], | ||
['+', '+', { first_line: 0, first_column: 6, last_line: 0, last_column: 6 }], | ||
['STRING', '"c"', { first_line: 0, first_column: 6, last_line: 0, last_column: 7 }], | ||
['STRING_END', ')', { first_line: 0, first_column: 7, last_line: 0, last_column: 7 }], | ||
['TERMINATOR', '\n', { first_line: 0, first_column: 8, last_line: 0, last_column: 8 }] | ||
]; | ||
[ | ||
'STRING', | ||
'"c"', | ||
{ first_line: 0, first_column: 6, last_line: 0, last_column: 7 }, | ||
], | ||
[ | ||
'STRING_END', | ||
')', | ||
{ first_line: 0, first_column: 7, last_line: 0, last_column: 7 }, | ||
], | ||
[ | ||
'TERMINATOR', | ||
'\n', | ||
{ first_line: 0, first_column: 8, last_line: 0, last_column: 8 }, | ||
], | ||
] | ||
``` | ||
@@ -113,0 +134,0 @@ |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
17
145
119895
6
3335
1