From 20f643b419c0362eadc98308d64a1b46e2f2810a Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 23 Sep 2015 15:59:41 +0100 Subject: [PATCH] type annotate babylon --- packages/babylon/src/index.js | 2 + packages/babylon/src/options.js | 4 +- packages/babylon/src/parser/comments.js | 2 + packages/babylon/src/parser/expression.js | 6 +- packages/babylon/src/parser/index.js | 16 +++- packages/babylon/src/parser/location.js | 2 + packages/babylon/src/parser/lval.js | 8 +- packages/babylon/src/parser/node.js | 17 ++-- packages/babylon/src/parser/statement.js | 4 +- packages/babylon/src/parser/util.js | 2 + packages/babylon/src/plugins/flow.js | 2 + packages/babylon/src/plugins/jsx/index.js | 2 + packages/babylon/src/tokenizer/context.js | 14 +++- packages/babylon/src/tokenizer/index.js | 14 ++-- packages/babylon/src/tokenizer/state.js | 96 +++++++++++++++++------ packages/babylon/src/tokenizer/types.js | 2 + packages/babylon/src/util/identifier.js | 2 + packages/babylon/src/util/location.js | 2 + packages/babylon/src/util/whitespace.js | 2 + 19 files changed, 154 insertions(+), 45 deletions(-) diff --git a/packages/babylon/src/index.js b/packages/babylon/src/index.js index 694c4e4838..b01a0b1197 100755 --- a/packages/babylon/src/index.js +++ b/packages/babylon/src/index.js @@ -1,3 +1,5 @@ +/* @flow */ + import Parser, { plugins } from "./parser"; import "./parser/util"; import "./parser/statement"; diff --git a/packages/babylon/src/options.js b/packages/babylon/src/options.js index f33e39d920..3b97f93a63 100755 --- a/packages/babylon/src/options.js +++ b/packages/babylon/src/options.js @@ -1,3 +1,5 @@ +/* @flow */ + // A second optional argument can be given to further configure // the parser process. These options are recognized: @@ -18,7 +20,7 @@ export const defaultOptions = { // Interpret and default an options object -export function getOptions(opts) { +export function getOptions(opts?: Object): Object { let options = {}; for (let key in defaultOptions) { options[key] = opts && key in opts ? opts[key] : defaultOptions[key]; diff --git a/packages/babylon/src/parser/comments.js b/packages/babylon/src/parser/comments.js index 39aa197872..5a3e96abcc 100644 --- a/packages/babylon/src/parser/comments.js +++ b/packages/babylon/src/parser/comments.js @@ -1,3 +1,5 @@ +/* @flow */ + /** * Based on the comment attachment algorithm used in espree and estraverse. * diff --git a/packages/babylon/src/parser/expression.js b/packages/babylon/src/parser/expression.js index 786b094a25..8c9898429c 100644 --- a/packages/babylon/src/parser/expression.js +++ b/packages/babylon/src/parser/expression.js @@ -1,3 +1,5 @@ +/* @flow */ + // A recursive descent parser operates by defining functions for all // syntactic elements, and recursively calling those, each function // advancing the input stream and returning an AST node. Precedence @@ -793,7 +795,7 @@ pp.parseFunctionBody = function (node, allowExpression) { // normal function if (!isExpression && node.body.directives.length) { - for (var directive of (node.body.directives: Array)) { + for (var directive of (node.body.directives: Array)) { if (directive.value === "use strict") { checkLVal = true; checkLValStrict = true; @@ -809,7 +811,7 @@ pp.parseFunctionBody = function (node, allowExpression) { if (node.id) { this.checkLVal(node.id, true); } - for (let param of (node.params: Array)) { + for (let param of (node.params: Array)) { this.checkLVal(param, true, nameHash); } this.state.strict = oldStrict; diff --git a/packages/babylon/src/parser/index.js b/packages/babylon/src/parser/index.js index d0752f5af1..59dd256bae 100644 --- a/packages/babylon/src/parser/index.js +++ b/packages/babylon/src/parser/index.js @@ -1,3 +1,5 @@ +/* @flow */ + import { reservedWords } from "../util/identifier"; import { getOptions } from "../options"; import Tokenizer from "../tokenizer"; @@ -7,7 +9,7 @@ import Tokenizer from "../tokenizer"; export const plugins = {}; export default class Parser extends Tokenizer { - constructor(options, input) { + constructor(options, input: string) { options = getOptions(options); super(options, input); @@ -25,11 +27,11 @@ export default class Parser extends Tokenizer { } } - hasFeature(name) { + hasFeature(name: string): boolean { return !!this.options.features[name]; } - extend(name, f) { + extend(name: string, f: Function) { this[name] = f(this[name]); } @@ -41,7 +43,13 @@ export default class Parser extends Tokenizer { } } - parse() { + parse(): { + type: "File", + program: { + type: "Program", + body: Array + } + } { let file = this.startNode(); let program = this.startNode(); this.nextToken(); diff --git a/packages/babylon/src/parser/location.js b/packages/babylon/src/parser/location.js index c8f10cc172..3029551c43 100644 --- a/packages/babylon/src/parser/location.js +++ b/packages/babylon/src/parser/location.js @@ -1,3 +1,5 @@ +/* @flow */ + import { getLineInfo } from "../util/location"; import Parser from "./index"; diff --git a/packages/babylon/src/parser/lval.js b/packages/babylon/src/parser/lval.js index cb8cae285a..333b6457b8 100644 --- a/packages/babylon/src/parser/lval.js +++ b/packages/babylon/src/parser/lval.js @@ -1,3 +1,5 @@ +/* @flow */ + import { types as tt } from "../tokenizer/types"; import Parser from "./index"; import { reservedWords } from "../util/identifier"; @@ -18,7 +20,7 @@ pp.toAssignable = function (node, isBinding) { case "ObjectExpression": node.type = "ObjectPattern"; - for (let prop of (node.properties: Array)) { + for (let prop of (node.properties: Array)) { if (prop.type === "SpreadProperty") continue; if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter"); this.toAssignable(prop.value, isBinding); @@ -184,14 +186,14 @@ pp.checkLVal = function (expr, isBinding, checkClashes) { break; case "ObjectPattern": - for (let prop of (expr.properties: Array)) { + for (let prop of (expr.properties: Array)) { if (prop.type === "Property") prop = prop.value; this.checkLVal(prop, isBinding, checkClashes); } break; case "ArrayPattern": - for (let elem of (expr.elements: Array)) { + for (let elem of (expr.elements: Array)) { if (elem) this.checkLVal(elem, isBinding, checkClashes); } break; diff --git a/packages/babylon/src/parser/node.js b/packages/babylon/src/parser/node.js index 7fb0cd2a62..d3544bc816 100644 --- a/packages/babylon/src/parser/node.js +++ b/packages/babylon/src/parser/node.js @@ -1,3 +1,5 @@ +/* @flow */ + import Parser from "./index"; import { SourceLocation } from "../util/location"; @@ -5,15 +7,20 @@ import { SourceLocation } from "../util/location"; const pp = Parser.prototype; -export class Node { - constructor(parser, pos, loc) { +class Node { + constructor(pos?: number, loc?: SourceLocation) { this.type = ""; this.start = pos; this.end = 0; this.loc = new SourceLocation(loc); } - __clone() { + type: string; + start: ?number; + end: number; + loc: SourceLocation; + + __clone(): Node { var node2 = new Node; for (var key in this) node2[key] = this[key]; return node2; @@ -21,11 +28,11 @@ export class Node { } pp.startNode = function () { - return new Node(this, this.state.start, this.state.startLoc); + return new Node(this.state.start, this.state.startLoc); }; pp.startNodeAt = function (pos, loc) { - return new Node(this, pos, loc); + return new Node(pos, loc); }; function finishNodeAt(node, type, pos, loc) { diff --git a/packages/babylon/src/parser/statement.js b/packages/babylon/src/parser/statement.js index 536db0a82c..14cc0daa40 100644 --- a/packages/babylon/src/parser/statement.js +++ b/packages/babylon/src/parser/statement.js @@ -1,3 +1,5 @@ +/* @flow */ + import { types as tt } from "../tokenizer/types"; import Parser from "./index"; import { lineBreak } from "../util/whitespace"; @@ -380,7 +382,7 @@ pp.parseEmptyStatement = function (node) { }; pp.parseLabeledStatement = function (node, maybeName, expr) { - for (let label of (this.state.labels: Array)){ + for (let label of (this.state.labels: Array)){ if (label.name === maybeName) { this.raise(expr.start, `Label '${maybeName}' is already declared`); } diff --git a/packages/babylon/src/parser/util.js b/packages/babylon/src/parser/util.js index 2719607626..e20e2467c9 100644 --- a/packages/babylon/src/parser/util.js +++ b/packages/babylon/src/parser/util.js @@ -1,3 +1,5 @@ +/* @flow */ + import { types as tt } from "../tokenizer/types"; import Parser from "./index"; import { lineBreak } from "../util/whitespace"; diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index ea58d81aae..7fe1d97d19 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -1,3 +1,5 @@ +/* @flow */ + import { types as tt } from "../tokenizer/types"; import Parser from "../parser"; diff --git a/packages/babylon/src/plugins/jsx/index.js b/packages/babylon/src/plugins/jsx/index.js index b6ae663bee..c373f88b8d 100644 --- a/packages/babylon/src/plugins/jsx/index.js +++ b/packages/babylon/src/plugins/jsx/index.js @@ -1,3 +1,5 @@ +/* @flow */ + import XHTMLEntities from "./xhtml"; import { TokenType, types as tt } from "../../tokenizer/types"; import { TokContext, types as tc } from "../../tokenizer/context"; diff --git a/packages/babylon/src/tokenizer/context.js b/packages/babylon/src/tokenizer/context.js index 05fb07056f..ef44998c8d 100644 --- a/packages/babylon/src/tokenizer/context.js +++ b/packages/babylon/src/tokenizer/context.js @@ -1,3 +1,5 @@ +/* @flow */ + // The algorithm used to determine whether a regexp can appear at a // given point in the program is loosely based on sweet.js' approach. // See https://github.com/mozilla/sweet.js/wiki/design @@ -5,12 +7,22 @@ import { types as tt } from "./types"; export class TokContext { - constructor(token, isExpr, preserveSpace, override) { + constructor( + token: string, + isExpr?: boolean, + preserveSpace?: boolean, + override?: Function, + ) { this.token = token; this.isExpr = !!isExpr; this.preserveSpace = !!preserveSpace; this.override = override; } + + token: string; + isExpr: boolean; + preserveSpace: boolean; + override: ?Function; } export const types = { diff --git a/packages/babylon/src/tokenizer/index.js b/packages/babylon/src/tokenizer/index.js index 3839f81e58..535fd5b856 100644 --- a/packages/babylon/src/tokenizer/index.js +++ b/packages/babylon/src/tokenizer/index.js @@ -1,3 +1,6 @@ +/* @flow */ + +import type { TokenType } from "./types"; import { isIdentifierStart, isIdentifierChar, isKeyword } from "../util/identifier"; import { types as tt, keywords as keywordTypes } from "./types"; import { types as ct } from "./context"; @@ -18,9 +21,11 @@ export class Token { this.loc = new SourceLocation(state.startLoc, state.endLoc); } - get range() { - return [this.start, this.end]; - } + type: TokenType; + value: any; + start: number; + end: number; + loc: SourceLocation; } // ## Tokenizer @@ -162,8 +167,7 @@ export default class Tokenizer { value: text, start: start, end: end, - loc: new SourceLocation(startLoc, endLoc), - range: [start, end] + loc: new SourceLocation(startLoc, endLoc) }; if (!this.isLookahead) { diff --git a/packages/babylon/src/tokenizer/state.js b/packages/babylon/src/tokenizer/state.js index b5a846ae20..b536a1fd8a 100644 --- a/packages/babylon/src/tokenizer/state.js +++ b/packages/babylon/src/tokenizer/state.js @@ -1,70 +1,120 @@ +/* @flow */ + +import type { TokContext } from "./context"; +import type { Token } from "./index"; import { Position } from "../util/location"; import { types as ct } from "./context"; import { types as tt } from "./types"; export default class State { - init(options, input) { - // strict + init(options: Object, input: string) { this.strict = options.strictMode === false ? false : options.sourceType === "module"; this.input = input; - // Used to signify the start of a potential arrow function this.potentialArrowAt = -1; - // Flags to track whether we are in a function, a generator. this.inFunction = this.inGenerator = false; - // Labels in scope. this.labels = []; - // Leading decorators. this.decorators = []; - // Token store. this.tokens = []; - // Comment store. this.comments = []; - // Comment attachment store this.trailingComments = []; this.leadingComments = []; this.commentStack = []; - // The current position of the tokenizer in the input. this.pos = this.lineStart = 0; this.curLine = 1; - // Properties of the current token: - // Its type this.type = tt.eof; - // For tokens that include more information than their type, the value this.value = null; - // Its start and end offset this.start = this.end = this.pos; - // And, if locations are used, the {line, column} object - // corresponding to those offsets this.startLoc = this.endLoc = this.curPosition(); - // Position information for the previous token this.lastTokEndLoc = this.lastTokStartLoc = null; this.lastTokStart = this.lastTokEnd = this.pos; - // The context stack is used to superficially track syntactic - // context to predict whether a regular expression is allowed in a - // given position. this.context = [ct.b_stat]; this.exprAllowed = true; - // Used to signal to callers of `readWord1` whether the word - // contained any escape sequences. This is needed because words with - // escape sequences must not be interpreted as keywords. this.containsEsc = false; return this; } + // TODO + strict: boolean; + + // TODO + input: string; + + // Used to signify the start of a potential arrow function + potentialArrowAt: number; + + // Flags to track whether we are in a function, a generator. + inFunction: boolean; + inGenerator: boolean; + + // Labels in scope. + labels: Array; + + // Leading decorators. + decorators: Array; + + // Token store. + tokens: Array; + + // Comment store. + comments: Array; + + // Comment attachment store + trailingComments: Array; + leadingComments: Array; + commentStack: Array; + + // The current position of the tokenizer in the input. + pos: number; + lineStart: number; + curLine: number; + + // Properties of the current token: + // Its type + type: Token; + + // For tokens that include more information than their type, the value + value: any; + + // Its start and end offset + start: number; + end: number; + + // And, if locations are used, the {line, column} object + // corresponding to those offsets + startLoc: Position; + endLoc: Position; + + // Position information for the previous token + lastTokEndLoc: ?Position; + lastTokStartLoc: ?Position; + lastTokStart: number; + lastTokEnd: number; + + // The context stack is used to superficially track syntactic + // context to predict whether a regular expression is allowed in a + // given position. + context: Array; + exprAllowed: boolean; + + // Used to signal to callers of `readWord1` whether the word + // contained any escape sequences. This is needed because words with + // escape sequences must not be interpreted as keywords. + containsEsc: boolean; + curPosition() { return new Position(this.curLine, this.pos - this.lineStart); } diff --git a/packages/babylon/src/tokenizer/types.js b/packages/babylon/src/tokenizer/types.js index d64407e920..90b60f4ca2 100644 --- a/packages/babylon/src/tokenizer/types.js +++ b/packages/babylon/src/tokenizer/types.js @@ -1,3 +1,5 @@ +/* @flow */ + // ## Token types // The assignment of fine-grained, information-carrying type objects diff --git a/packages/babylon/src/util/identifier.js b/packages/babylon/src/util/identifier.js index 48847c6277..947e993ade 100644 --- a/packages/babylon/src/util/identifier.js +++ b/packages/babylon/src/util/identifier.js @@ -1,3 +1,5 @@ +/* @flow */ + // This is a trick taken from Esprima. It turns out that, on // non-Chrome browsers, to check whether a string is in a set, a // predicate containing a big ugly `switch` statement is faster than diff --git a/packages/babylon/src/util/location.js b/packages/babylon/src/util/location.js index 883d4b3daa..47019f1068 100644 --- a/packages/babylon/src/util/location.js +++ b/packages/babylon/src/util/location.js @@ -1,3 +1,5 @@ +/* @flow */ + import { lineBreakG } from "./whitespace"; // These are used when `options.locations` is on, for the diff --git a/packages/babylon/src/util/whitespace.js b/packages/babylon/src/util/whitespace.js index d517d1f28a..78d800df7c 100644 --- a/packages/babylon/src/util/whitespace.js +++ b/packages/babylon/src/util/whitespace.js @@ -1,3 +1,5 @@ +/* @flow */ + // Matches a whole line break (where CRLF is considered a single // line break). Used to count lines.