sucrase
Version:
Super-fast alternative to Babel for when you can target modern JS runtimes
56 lines (55 loc) • 2.17 kB
JavaScript
import Tokenizer from "../tokenizer";
import { types as tt } from "../tokenizer/types";
import { lineBreak } from "../util/whitespace";
// ## Parser utilities
export default class UtilParser extends Tokenizer {
// Tests whether parsed token is a contextual keyword.
isContextual(name) {
return this.match(tt.name) && this.state.value === name;
}
isLookaheadContextual(name) {
const l = this.lookaheadTypeAndValue();
return l.type === tt.name && l.value === name;
}
// Consumes contextual keyword if possible.
eatContextual(name) {
return this.state.value === name && this.eat(tt.name);
}
// Asserts that following token is given contextual keyword.
expectContextual(name, message) {
if (!this.eatContextual(name))
this.unexpected(null, message);
}
// Test whether a semicolon can be inserted at the current position.
canInsertSemicolon() {
return this.match(tt.eof) || this.match(tt.braceR) || this.hasPrecedingLineBreak();
}
hasPrecedingLineBreak() {
return lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start));
}
isLineTerminator() {
return this.eat(tt.semi) || this.canInsertSemicolon();
}
// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.
semicolon() {
if (!this.isLineTerminator())
this.unexpected(null, tt.semi);
}
// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error at given pos.
expect(type, pos) {
const matched = this.eat(type);
if (!matched) {
this.unexpected(pos, type);
}
}
// Raise an unexpected token error. Can take the expected token type
// instead of a message string.
unexpected(pos = null, messageOrType = "Unexpected token") {
if (typeof messageOrType !== "string") {
messageOrType = `Unexpected token, expected "${messageOrType.label}"`;
}
throw this.raise(pos != null ? pos : this.state.start, messageOrType);
}
}