Add support for an InterpreterDirective AST node.

This commit is contained in:
Logan Smyth
2018-05-12 10:50:33 -07:00
parent c0013264b7
commit 2058e0686e
2113 changed files with 2281 additions and 162 deletions

View File

@@ -19,15 +19,6 @@ export default class Parser extends StatementParser {
this.input = input;
this.plugins = pluginsMap(this.options.plugins);
this.filename = options.sourceFilename;
// If enabled, skip leading hashbang line.
if (
this.state.pos === 0 &&
this.input[0] === "#" &&
this.input[1] === "!"
) {
this.skipLineComment(2);
}
}
parse(): File {

View File

@@ -23,6 +23,8 @@ export default class StatementParser extends ExpressionParser {
parseTopLevel(file: N.File, program: N.Program): N.File {
program.sourceType = this.options.sourceType;
program.interpreter = this.parseInterpreterDirective();
this.parseBlockBody(program, true, true, tt.eof);
file.program = this.finishNode(program, "Program");
@@ -57,6 +59,17 @@ export default class StatementParser extends ExpressionParser {
return this.finishNodeAt(directive, "Directive", stmt.end, stmt.loc.end);
}
parseInterpreterDirective(): N.InterpreterDirective | null {
if (!this.match(tt.interpreterDirective)) {
return null;
}
const node = this.startNode();
node.value = this.state.value;
this.next();
return this.finishNode(node, "InterpreterDirective");
}
// Parse a single statement.
//
// If expecting a statement and finding a slash operator, parse a

View File

@@ -437,6 +437,32 @@ export default class Tokenizer extends LocationParser {
}
}
readToken_interpreter(): boolean {
if (this.state.pos !== 0 || this.state.input.length < 2) return false;
const start = this.state.pos;
this.state.pos += 1;
let ch = this.input.charCodeAt(this.state.pos);
if (ch !== charCodes.exclamationMark) return false;
while (
ch !== charCodes.lineFeed &&
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.input.length
) {
ch = this.input.charCodeAt(this.state.pos);
}
const value = this.input.slice(start + 2, this.state.pos);
this.finishToken(tt.interpreterDirective, value);
return true;
}
readToken_mult_modulo(code: number): void {
// '%*'
let type = code === charCodes.asterisk ? tt.star : tt.modulo;
@@ -626,6 +652,10 @@ export default class Tokenizer extends LocationParser {
getTokenFromCode(code: number): void {
switch (code) {
case charCodes.numberSign:
if (this.state.pos === 0 && this.readToken_interpreter()) {
return;
}
if (
(this.hasPlugin("classPrivateProperties") ||
this.hasPlugin("classPrivateMethods")) &&

View File

@@ -112,6 +112,9 @@ export const types: { [name: string]: TokenType } = {
at: new TokenType("@"),
hash: new TokenType("#"),
// Special hashbang token.
interpreterDirective: new TokenType("#!..."),
// Operators. These carry several kinds of properties to help the
// parser use them properly (the presence of these properties is
// what categorizes them as operators).

View File

@@ -63,6 +63,11 @@ export type HasDecorators = NodeBase & {
decorators?: $ReadOnlyArray<Decorator>,
};
export type InterpreterDirective = NodeBase & {
type: "InterpreterDirective",
value: string,
};
export type Identifier = PatternBase & {
type: "Identifier",
name: string,
@@ -133,6 +138,7 @@ export type Program = NodeBase & {
sourceType: "script" | "module",
body: Array<Statement | ModuleDeclaration>, // TODO: $ReadOnlyArray
directives: $ReadOnlyArray<Directive>, // TODO: Not in spec
interpreter: InterpreterDirective | null,
};
// Functions