diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index c14d5c67b4..0000000000 --- a/.editorconfig +++ /dev/null @@ -1,7 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -insert_final_newline = true diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index fcadb2cf97..0000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text eol=lf diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 66cc69a8cd..0000000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/node_modules -/.tern-port -/acorn_csp.js -/local diff --git a/.npmignore b/.npmignore deleted file mode 100644 index ecba2911d2..0000000000 --- a/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -/.tern-port -/test -/local diff --git a/.tern-project b/.tern-project deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/.tern-project +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ffb9f710ac..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,2 +0,0 @@ -language: node_js -node_js: '0.10' diff --git a/README.md b/README.md index 0b0d841c34..9aacffb581 100644 --- a/README.md +++ b/README.md @@ -1,313 +1,4 @@ # Acorn -[![Build Status](https://travis-ci.org/marijnh/acorn.svg?branch=master)](https://travis-ci.org/marijnh/acorn) -[![NPM version](https://img.shields.io/npm/v/acorn.svg)](https://www.npmjs.org/package/acorn) -[Author funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png)](https://marijnhaverbeke.nl/fund/) - -A tiny, fast JavaScript parser, written completely in JavaScript. - -## Installation - -The easiest way to install acorn is with [`npm`][npm]. - -[npm]: http://npmjs.org - -```sh -npm install acorn -``` - -Alternately, download the source. - -```sh -git clone https://github.com/marijnh/acorn.git -``` - -## Components - -When run in a CommonJS (node.js) or AMD environment, exported values -appear in the interfaces exposed by the individual files, as usual. -When loaded in the browser (Acorn works in any JS-enabled browser more -recent than IE5) without any kind of module management, a single -global object `acorn` will be defined, and all the exported properties -will be added to that. - -### acorn.js - -This file contains the actual parser (and is what you get when you -`require("acorn")` in node.js). - -**parse**`(input, options)` is used to parse a JavaScript program. -The `input` parameter is a string, `options` can be undefined or an -object setting some of the options listed below. The return value will -be an abstract syntax tree object as specified by the -[Mozilla Parser API][mozapi]. - -When encountering a syntax error, the parser will raise a -`SyntaxError` object with a meaningful message. The error object will -have a `pos` property that indicates the character offset at which the -error occurred, and a `loc` object that contains a `{line, column}` -object referring to that same position. - -[mozapi]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API - -- **ecmaVersion**: Indicates the ECMAScript version to parse. Must be - either 3, 5, or 6. This influences support for strict mode, the set - of reserved words, and support for new syntax features. Default is 5. - -- **strictSemicolons**: If `true`, prevents the parser from doing - automatic semicolon insertion, and statements that do not end with - a semicolon will generate an error. Defaults to `false`. - -- **allowTrailingCommas**: If `false`, the parser will not allow - trailing commas in array and object literals. Default is `true`. - -- **forbidReserved**: If `true`, using a reserved word will generate - an error. Defaults to `false`. When given the value `"everywhere"`, - reserved words and keywords can also not be used as property names - (as in Internet Explorer's old parser). - -- **allowReturnOutsideFunction**: By default, a return statement at - the top level raises an error. Set this to `true` to accept such - code. - -- **allowImportExportEverywhere**: By default, `import` and `export` - declarations can only appear at a program's top level. Setting this - option to `true` allows them anywhere where a statement is allowed. - -- **allowHashBang**: When this is enabled (off by default), if the - code starts with the characters `#!` (as in a shellscript), the - first line will be treated as a comment. - -- **locations**: When `true`, each node has a `loc` object attached - with `start` and `end` subobjects, each of which contains the - one-based line and zero-based column numbers in `{line, column}` - form. Default is `false`. - -- **onToken**: If a function is passed for this option, each found - token will be passed in same format as `tokenize()` returns. - - If array is passed, each found token is pushed to it. - - Note that you are not allowed to call the parser from the - callback—that will corrupt its internal state. - -- **onComment**: If a function is passed for this option, whenever a - comment is encountered the function will be called with the - following parameters: - - - `block`: `true` if the comment is a block comment, false if it - is a line comment. - - `text`: The content of the comment. - - `start`: Character offset of the start of the comment. - - `end`: Character offset of the end of the comment. - - When the `locations` options is on, the `{line, column}` locations - of the comment’s start and end are passed as two additional - parameters. - - If array is passed for this option, each found comment is pushed - to it as object in Esprima format: - - ```javascript - { - "type": "Line" | "Block", - "value": "comment text", - "range": ..., - "loc": ... - } - ``` - - Note that you are not allowed to call the parser from the - callback—that will corrupt its internal state. - -- **ranges**: Nodes have their start and end characters offsets - recorded in `start` and `end` properties (directly on the node, - rather than the `loc` object, which holds line/column data. To also - add a [semi-standardized][range] "range" property holding a - `[start, end]` array with the same numbers, set the `ranges` option - to `true`. - -- **program**: It is possible to parse multiple files into a single - AST by passing the tree produced by parsing the first file as the - `program` option in subsequent parses. This will add the toplevel - forms of the parsed file to the "Program" (top) node of an existing - parse tree. - -- **sourceFile**: When the `locations` option is `true`, you can pass - this option to add a `source` attribute in every node’s `loc` - object. Note that the contents of this option are not examined or - processed in any way; you are free to use whatever format you - choose. - -- **directSourceFile**: Like `sourceFile`, but a `sourceFile` property - will be added directly to the nodes, rather than the `loc` object. - -- **preserveParens**: If this option is `true`, parenthesized expressions - are represented by (non-standard) `ParenthesizedExpression` nodes - that have a single `expression` property containing the expression - inside parentheses. - -[range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 - -**parseExpressionAt**`(input, offset, options)` will parse a single -expression in a string, and return its AST. It will not complain if -there is more of the string left after the expression. - -**getLineInfo**`(input, offset)` can be used to get a `{line, -column}` object for a given program string and character offset. - -**tokenize**`(input, options)` exports a primitive interface to -Acorn's tokenizer. The function takes an input string and options -similar to `parse` (though only some options are meaningful here), and -returns a function that can be called repeatedly to read a single -token, and returns a `{start, end, type, value}` object (with added -`loc` property when the `locations` option is enabled and `range` -property when the `ranges` option is enabled). - -In ES6 environment, returned result can be used as any other protocol-compliant iterable: - -```javascript -for (let token of acorn.tokenize(str)) { - // iterate over the tokens -} - -// transform code to array of tokens: -var tokens = [...acorn.tokenize(str)]; -``` - -**tokTypes** holds an object mapping names to the token type objects -that end up in the `type` properties of tokens. - -#### Note on using with [Escodegen][escodegen] - -Escodegen supports generating comments from AST, attached in -Esprima-specific format. In order to simulate same format in -Acorn, consider following example: - -```javascript -var comments = [], tokens = []; - -var ast = acorn.parse('var x = 42; // answer', { - // collect ranges for each node - ranges: true, - // collect comments in Esprima's format - onComment: comments, - // collect token ranges - onToken: tokens -}); - -// attach comments using collected information -escodegen.attachComments(ast, comments, tokens); - -// generate code -console.log(escodegen.generate(ast, {comment: true})); -// > 'var x = 42; // answer' -``` - -[escodegen]: https://github.com/Constellation/escodegen - -#### Using Acorn in an environment with a Content Security Policy - -Some contexts, such as Chrome Web Apps, disallow run-time code evaluation. -Acorn uses `new Function` to generate fast functions that test whether -a word is in a given set, and will trigger a security error when used -in a context with such a -[Content Security Policy](http://www.html5rocks.com/en/tutorials/security/content-security-policy/#eval-too) -(see [#90](https://github.com/marijnh/acorn/issues/90) and -[#123](https://github.com/marijnh/acorn/issues/123)). - -The `bin/without_eval` script can be used to generate a version of -`acorn.js` that has the generated code inlined, and can thus run -without evaluating anything. In versions of this library downloaded -from NPM, this script will be available as `acorn_csp.js`. - -### acorn_loose.js ### - -This file implements an error-tolerant parser. It exposes a single -function. - -**parse_dammit**`(input, options)` takes the same arguments and -returns the same syntax tree as the `parse` function in `acorn.js`, -but never raises an error, and will do its best to parse syntactically -invalid code in as meaningful a way as it can. It'll insert identifier -nodes with name `"✖"` as placeholders in places where it can't make -sense of the input. Depends on `acorn.js`, because it uses the same -tokenizer. - -### util/walk.js ### - -Implements an abstract syntax tree walker. Will store its interface in -`acorn.walk` when used without a module system. - -**simple**`(node, visitors, base, state)` does a 'simple' walk over -a tree. `node` should be the AST node to walk, and `visitors` an -object with properties whose names correspond to node types in the -[Mozilla Parser API][mozapi]. The properties should contain functions -that will be called with the node object and, if applicable the state -at that point. The last two arguments are optional. `base` is a walker -algorithm, and `state` is a start state. The default walker will -simply visit all statements and expressions and not produce a -meaningful state. (An example of a use of state it to track scope at -each point in the tree.) - -**ancestor**`(node, visitors, base, state)` does a 'simple' walk over -a tree, building up an array of ancestor nodes (including the current node) -and passing the array to callbacks in the `state` parameter. - -**recursive**`(node, state, functions, base)` does a 'recursive' -walk, where the walker functions are responsible for continuing the -walk on the child nodes of their target node. `state` is the start -state, and `functions` should contain an object that maps node types -to walker functions. Such functions are called with `(node, state, c)` -arguments, and can cause the walk to continue on a sub-node by calling -the `c` argument on it with `(node, state)` arguments. The optional -`base` argument provides the fallback walker functions for node types -that aren't handled in the `functions` object. If not given, the -default walkers will be used. - -**make**`(functions, base)` builds a new walker object by using the -walker functions in `functions` and filling in the missing ones by -taking defaults from `base`. - -**findNodeAt**`(node, start, end, test, base, state)` tries to -locate a node in a tree at the given start and/or end offsets, which -satisfies the predicate `test`. `start` end `end` can be either `null` -(as wildcard) or a number. `test` may be a string (indicating a node -type) or a function that takes `(nodeType, node)` arguments and -returns a boolean indicating whether this node is interesting. `base` -and `state` are optional, and can be used to specify a custom walker. -Nodes are tested from inner to outer, so if two nodes match the -boundaries, the inner one will be preferred. - -**findNodeAround**`(node, pos, test, base, state)` is a lot like -`findNodeAt`, but will match any node that exists 'around' (spanning) -the given position. - -**findNodeAfter**`(node, pos, test, base, state)` is similar to -`findNodeAround`, but will match all nodes *after* the given position -(testing outer nodes before inner nodes). - -## Command line interface - -The `bin/acorn` utility can be used to parse a file from the command -line. It accepts as arguments its input file and the following -options: - -- `--ecma3|--ecma5|--ecma6`: Sets the ECMAScript version to parse. Default is - version 5. - -- `--strictSemicolons`: Prevents the parser from doing automatic - semicolon insertion. Statements that do not end in semicolons will - generate an error. - -- `--locations`: Attaches a "loc" object to each node with "start" and - "end" subobjects, each of which contains the one-based line and - zero-based column numbers in `{line, column}` form. - -- `--compact`: No whitespace is used in the AST output. - -- `--silent`: Do not output the AST, just return the exit status. - -- `--help`: Print the usage information and quit. - -The utility spits out the syntax tree as JSON data. +Embedded version with Babel-specific modifications of the excellent +[acorn](https://github.com/marijnh/acorn) parser. diff --git a/acorn.js b/acorn.js index add13940b2..16e07ab099 100644 --- a/acorn.js +++ b/acorn.js @@ -51,17 +51,20 @@ // mode, the set of reserved words, support for getters and // setters and other features. ecmaVersion: 5, - // Turn on `strictSemicolons` to prevent the parser from doing - // automatic semicolon insertion. - strictSemicolons: false, - // When `allowTrailingCommas` is false, the parser will not allow - // trailing commas in array and object literals. - allowTrailingCommas: true, - // By default, reserved words are not enforced. Enable - // `forbidReserved` to enforce them. When this option has the - // value "everywhere", reserved words and keywords can also not be + // `onInsertedSemicolon` can be a callback that will be called + // when a semicolon is automatically inserted. It will be passed + // th position of the comma as an offset, and if `locations` is + // enabled, it is given the location as a `{line, column}` object + // as second argument. + onInsertedSemicolon: null, + // `onTrailingComma` is similar to `onInsertedSemicolon`, but for + // trailing commas. + onTrailingComma: null, + // By default, reserved words are not enforced. Disable + // `allowReserved` to enforce them. When this option has the + // value "never", reserved words and keywords can also not be // used as property names. - forbidReserved: false, + allowReserved: true, // When enabled, a return at the top level is not considered an // error. allowReturnOutsideFunction: false, @@ -117,7 +120,10 @@ // When enabled, parenthesized expressions are represented by // (non-standard) ParenthesizedExpression nodes preserveParens: false, - plugins: {} + plugins: {}, + // Babel-specific options + transformers: {}, + strictMode: false }; exports.plugins = {}; @@ -235,6 +241,7 @@ this.label = label; this.keyword = conf.keyword; this.beforeExpr = !!conf.beforeExpr; + this.rightAssociative = !!conf.rightAssociative; this.isLoop = !!conf.isLoop; this.isAssign = !!conf.isAssign; this.prefix = !!conf.prefix; @@ -302,7 +309,8 @@ plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true}), modulo: binop("%", 10), star: binop("*", 10), - slash: binop("/", 10) + slash: binop("/", 10), + exponent: new TokenType("**", {beforeExpr: true, binop: 11, rightAssociative: true}) }; // Map keyword names to token types. @@ -566,7 +574,7 @@ this.startLoc = this.endLoc = null; // Position information for the previous token - this.lastTokEndLoc = null; + this.lastTokEndLoc = this.lastTokStartLoc = null; this.lastTokStart = this.lastTokEnd = this.pos; // The context stack is used to superficially track syntactic @@ -611,6 +619,7 @@ this.lastTokEnd = this.end; this.lastTokStart = this.start; this.lastTokEndLoc = this.endLoc; + this.lastTokStartLoc = this.startLoc; this.nextToken(); }; @@ -898,9 +907,22 @@ }; pp.readToken_mult_modulo = function(code) { // '%*' + var type = code === 42 ? tt.star : tt.modulo; + var width = 1; var next = this.input.charCodeAt(this.pos + 1); - if (next === 61) return this.finishOp(tt.assign, 2); - return this.finishOp(code === 42 ? tt.star : tt.modulo, 1); + + if (this.options.transformers["es7.exponentiationOperator"] && next === 42) { // '*' + width++; + next = this.input.charCodeAt(this.pos + 2); + type = tt.exponent; + } + + if (next === 61) { + width++; + type = tt.assign; + } + + return this.finishOp(type, width); }; pp.readToken_pipe_amp = function(code) { // '|&' @@ -1078,7 +1100,7 @@ // ASCII symbol to avoid throwing on regular expressions that // are only valid in combination with the `/u` flag. tmp = tmp - .replace(/\\u\{([0-9a-fA-F]{5,6})\}/g, "x") + .replace(/\\u\{([0-9a-fA-F]+)\}/g, "x") .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x"); } } @@ -1453,15 +1475,33 @@ // Test whether a semicolon can be inserted at the current position. pp.canInsertSemicolon = function() { - return !this.options.strictSemicolons && - (this.type === tt.eof || this.type === tt.braceR || newline.test(this.input.slice(this.lastTokEnd, this.start))); + return this.type === tt.eof || + this.type === tt.braceR || + newline.test(this.input.slice(this.lastTokEnd, this.start)); + }; + + pp.insertSemicolon = function() { + if (this.canInsertSemicolon()) { + if (this.options.onInsertedSemicolon) + this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc) + return true; + } }; // Consume a semicolon, or, failing that, see if we are allowed to // pretend that there is a semicolon at this position. pp.semicolon = function() { - if (!this.eat(tt.semi) && !this.canInsertSemicolon()) this.unexpected(); + if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected(); + }; + + pp.afterTrailingComma = function(tokType) { + if (this.type == tokType) { + if (this.options.onTrailingComma) + this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc); + this.next(); + return true; + } }; // Expect a token of a given type. If found, consume it, otherwise, @@ -1583,7 +1623,7 @@ case tt.bracketL: var node = this.startNode(); this.next(); - node.elements = this.parseBindingList(tt.bracketR, true); + node.elements = this.parseBindingList(tt.bracketR, true, true); return this.finishNode(node, "ArrayPattern"); case tt.braceL: @@ -1594,20 +1634,30 @@ } }; - pp.parseBindingList = function(close, allowEmpty) { + pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) { var elts = [], first = true; while (!this.eat(close)) { - first ? first = false : this.expect(tt.comma); - if (this.type === tt.ellipsis) { - elts.push(this.parseRest()); + if (first) first = false; + else this.expect(tt.comma); + if (allowEmpty && this.type === tt.comma) { + elts.push(null); + } else if (allowTrailingComma && this.afterTrailingComma(close)) { + break; + } else if (this.type === tt.ellipsis) { + elts.push(this.parseAssignableListItemTypes(this.parseRest())); this.expect(close); break; + } else { + elts.push(this.parseAssignableListItemTypes(this.parseMaybeDefault())); } - elts.push(allowEmpty && this.type === tt.comma ? null : this.parseMaybeDefault()); } return elts; }; + pp.parseAssignableListItemTypes = function(param) { + return param; + }; + // Parses assignment pattern around given atom if possible. pp.parseMaybeDefault = function(startPos, left) { @@ -1695,8 +1745,11 @@ break; case "ObjectPattern": - for (var i = 0; i < expr.properties.length; i++) - this.checkLVal(expr.properties[i].value, isBinding); + for (var i = 0; i < expr.properties.length; i++) { + var prop = expr.properties[i]; + if (prop.type === "Property") prop = prop.value; + this.checkLVal(prop, isBinding); + } break; case "ArrayPattern": @@ -1710,6 +1763,7 @@ this.checkLVal(expr.left); break; + case "SpreadProperty": case "RestElement": this.checkLVal(expr.argument); break; @@ -1773,7 +1827,7 @@ case tt._throw: return this.parseThrowStatement(node); case tt._try: return this.parseTryStatement(node); case tt._let: case tt._const: if (!declaration) this.unexpected(); // NOTE: falls through to _var - case tt._var: return this.parseVarStatement(node, starttype.keyword); + case tt._var: return this.parseVarStatement(node, starttype); case tt._while: return this.parseWhileStatement(node); case tt._with: return this.parseWithStatement(node); case tt.braceL: return this.parseBlock(); // no point creating a function for this @@ -1800,7 +1854,7 @@ pp.parseBreakContinueStatement = function(node, keyword) { var isBreak = keyword == "break"; this.next(); - if (this.eat(tt.semi) || this.canInsertSemicolon()) node.label = null; + if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null; else if (this.type !== tt.name) this.unexpected(); else { node.label = this.parseIdent(); @@ -1853,13 +1907,13 @@ this.labels.push(loopLabel); this.expect(tt.parenL); if (this.type === tt.semi) return this.parseFor(node, null); - if (this.type === tt._var || this.type === tt._let) { - var init = this.startNode(), varKind = this.type.keyword, isLet = this.type === tt._let; + if (this.type === tt._var || this.type === tt._let || this.type === tt._const) { + var init = this.startNode(), varKind = this.type; this.next(); this.parseVar(init, true, varKind); this.finishNode(init, "VariableDeclaration"); if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init.declarations.length === 1 && - !(isLet && init.declarations[0].init)) + !(varKind !== tt._var && init.declarations[0].init)) return this.parseForIn(node, init); return this.parseFor(node, init); } @@ -1897,7 +1951,7 @@ // optional arguments, we eagerly look for a semicolon or the // possibility to insert one. - if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null; + if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null; else { node.argument = this.parseExpression(); this.semicolon(); } return this.finishNode(node, "ReturnStatement"); }; @@ -2079,18 +2133,28 @@ pp.parseVar = function(node, noIn, kind) { node.declarations = []; - node.kind = kind; + node.kind = kind.keyword; for (;;) { var decl = this.startNode(); - decl.id = this.parseBindingAtom(); - this.checkLVal(decl.id, true); - decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : (kind === tt._const.keyword ? this.unexpected() : null); + this.parseVarHead(decl); + if (this.eat(tt.eq)) { + decl.init = this.parseMaybeAssign(noIn); + } else if (kind === tt._const && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) { + this.unexpected(); + } else { + decl.init = null; + } node.declarations.push(this.finishNode(decl, "VariableDeclarator")); if (!this.eat(tt.comma)) break; } return node; }; + pp.parseVarHead = function (decl) { + decl.id = this.parseBindingAtom(); + this.checkLVal(decl.id, true); + }; + // ### Expression parsing // These nest, from the most general expression type at the top to @@ -2121,7 +2185,9 @@ // Parse an assignment expression. This includes applications of // operators like `+=`. - pp.parseMaybeAssign = function(noIn, refShorthandDefaultPos) { + pp.parseMaybeAssign = function(noIn, refShorthandDefaultPos, afterLeftParse) { + if (this.type == tt._yield && this.inGenerator) return this.parseYield(); + var failOnShorthandAssign; if (!refShorthandDefaultPos) { refShorthandDefaultPos = {start: 0}; @@ -2131,6 +2197,7 @@ } var start = this.currentPos(); var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos); + if (afterLeftParse) left = afterLeftParse.call(this, left, start); if (this.type.isAssign) { var node = this.startNodeAt(start); node.operator = this.value; @@ -2188,7 +2255,7 @@ var op = this.type; this.next(); var start = this.currentPos(); - node.right = this.parseExprOp(this.parseMaybeUnary(), start, prec, noIn); + node.right = this.parseExprOp(this.parseMaybeUnary(), start, op.rightAssociative ? (prec - 1) : prec, noIn); this.finishNode(node, (op === tt.logicalOR || op === tt.logicalAND) ? "LogicalExpression" : "BinaryExpression"); return this.parseExprOp(node, leftStart, minPrec, noIn); } @@ -2276,7 +2343,7 @@ return this.finishNode(node, "ThisExpression"); case tt._yield: - if (this.inGenerator) return this.parseYield(); + if (this.inGenerator) unexpected(); case tt.name: var start = this.currentPos(); @@ -2309,7 +2376,7 @@ var node = this.startNode(); this.next(); // check whether this is array comprehension or regular array - if (this.options.ecmaVersion >= 7 && this.type === tt._for) { + if (this.options.transformers["es7.comprehensions"] && this.type === tt._for) { return this.parseComprehension(node, false); } node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos); @@ -2350,7 +2417,7 @@ if (this.options.ecmaVersion >= 6) { this.next(); - if (this.options.ecmaVersion >= 7 && this.type === tt._for) { + if (this.options.transformers["es7.comprehensions"] && this.type === tt._for) { return this.parseComprehension(this.startNodeAt(start), true); } @@ -2359,14 +2426,15 @@ while (this.type !== tt.parenR) { first ? first = false : this.expect(tt.comma); if (this.type === tt.ellipsis) { + var spreadNodeStart = this.currentPos(); spreadStart = this.start; - exprList.push(this.parseRest()); + exprList.push(this.parseParenItem(this.parseRest(), spreadNodeStart)); break; } else { if (this.type === tt.parenL && !innerParenStart) { innerParenStart = this.start; } - exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos)); + exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem)); } } var innerEnd = this.currentPos(); @@ -2401,6 +2469,10 @@ } }; + pp.parseParenItem = function (node, start) { + return node; + }; + // New's precedence is slightly tricky. It must allow its argument // to be a `[]` or dot subscript expression, but not a call — at // least, not without wrapping it in parentheses. Thus, it uses the @@ -2453,10 +2525,16 @@ while (!this.eat(tt.braceR)) { if (!first) { this.expect(tt.comma); - if (this.options.allowTrailingCommas && this.eat(tt.braceR)) break; + if (this.afterTrailingComma(tt.braceR)) break; } else first = false; var prop = this.startNode(), isGenerator, start; + if (this.options.transformers["es7.objectRestSpread"] && this.type === tt.ellipsis) { + prop = this.parseSpread(); + prop.type = "SpreadProperty"; + node.properties.push(prop); + continue; + } if (this.options.ecmaVersion >= 6) { prop.method = false; prop.shorthand = false; @@ -2538,19 +2616,23 @@ if (isStatement || this.type === tt.name) { node.id = this.parseIdent(); } - this.expect(tt.parenL); - node.params = this.parseBindingList(tt.parenR, false); + this.parseFunctionParams(node); this.parseFunctionBody(node, allowExpressionBody); return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); }; + pp.parseFunctionParams = function(node) { + this.expect(tt.parenL); + node.params = this.parseBindingList(tt.parenR, false, false); + }; + // Parse object or class method. pp.parseMethod = function(isGenerator) { var node = this.startNode(); this.initFunction(node); this.expect(tt.parenL); - node.params = this.parseBindingList(tt.parenR, false); + node.params = this.parseBindingList(tt.parenR, false, false); var allowExpressionBody; if (this.options.ecmaVersion >= 6) { node.generator = isGenerator; @@ -2606,8 +2688,8 @@ pp.parseClass = function(node, isStatement) { this.next(); - node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null; - node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null; + this.parseClassId(node, isStatement); + this.parseClassSuper(node); var classBody = this.startNode(); classBody.body = []; this.expect(tt.braceL); @@ -2640,6 +2722,14 @@ return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression"); }; + pp.parseClassId = function (node, isStatement) { + node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null; + }; + + pp.parseClassSuper = function (node) { + node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null; + }; + // Parses a comma-separated list of expressions, and returns them as // an array. `close` is the token type that ends the list, and // `allowEmpty` can be turned on to allow subsequent commas with @@ -2651,7 +2741,7 @@ while (!this.eat(close)) { if (!first) { this.expect(tt.comma); - if (allowTrailingComma && this.options.allowTrailingCommas && this.eat(close)) break; + if (allowTrailingComma && this.afterTrailingComma(close)) break; } else first = false; if (allowEmpty && this.type === tt.comma) { @@ -2672,10 +2762,10 @@ pp.parseIdent = function(liberal) { var node = this.startNode(); - if (liberal && this.options.forbidReserved == "everywhere") liberal = false; + if (liberal && this.options.allowReserved == "never") liberal = false; if (this.type === tt.name) { if (!liberal && - (this.options.forbidReserved && + (!this.options.allowReserved && (this.options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(this.value) || this.strict && isStrictReservedWord(this.value)) && this.input.slice(this.start, this.end).indexOf("\\") == -1) @@ -2694,15 +2784,13 @@ pp.parseExport = function(node) { this.next(); - // export var|const|let|function|class ...; - if (this.type === tt._var || this.type === tt._const || this.type === tt._let || this.type === tt._function || this.type === tt._class) { - node.declaration = this.parseStatement(true); - node['default'] = false; - node.specifiers = null; - node.source = null; - } else - // export default ...; - if (this.eat(tt._default)) { + // export * from '...'; + if (this.eat(tt.star)) { + this.expectContextual("from"); + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected(); + return this.finishNode(node, "ExportAllDeclaration"); + } + if (this.eat(tt._default)) { // export default ...; var expr = this.parseMaybeAssign(); if (expr.id) { switch (expr.type) { @@ -2711,51 +2799,43 @@ } } node.declaration = expr; - node['default'] = true; - node.specifiers = null; - node.source = null; this.semicolon(); - } else { - // export * from '...'; - // export { x, y as z } [from '...']; - var isBatch = this.type === tt.star; + return this.finishNode(node, "ExportDefaultDeclaration"); + } + // export var|const|let|function|class ...; + if (this.type.keyword) { + node.declaration = this.parseStatement(true); + node.specifiers = []; + node.source = null; + } else { // export { x, y as z } [from '...']; node.declaration = null; - node['default'] = false; node.specifiers = this.parseExportSpecifiers(); if (this.eatContextual("from")) { node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected(); } else { - if (isBatch) this.unexpected(); node.source = null; } this.semicolon(); } - return this.finishNode(node, "ExportDeclaration"); + return this.finishNode(node, "ExportNamedDeclaration"); }; // Parses a comma-separated list of module exports. pp.parseExportSpecifiers = function() { var nodes = [], first = true; - if (this.type === tt.star) { - // export * from '...' - var node = this.startNode(); - this.next(); - nodes.push(this.finishNode(node, "ExportBatchSpecifier")); - } else { - // export { x, y as z } [from '...'] - this.expect(tt.braceL); - while (!this.eat(tt.braceR)) { - if (!first) { - this.expect(tt.comma); - if (this.options.allowTrailingCommas && this.eat(tt.braceR)) break; - } else first = false; + // export { x, y as z } [from '...'] + this.expect(tt.braceL); + while (!this.eat(tt.braceR)) { + if (!first) { + this.expect(tt.comma); + if (this.afterTrailingComma(tt.braceR)) break; + } else first = false; - var node = this.startNode(); - node.id = this.parseIdent(this.type === tt._default); - node.name = this.eatContextual("as") ? this.parseIdent(true) : null; - nodes.push(this.finishNode(node, "ExportSpecifier")); - } + var node = this.startNode(); + node.local = this.parseIdent(this.type === tt._default); + node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local; + nodes.push(this.finishNode(node, "ExportSpecifier")); } return nodes; }; @@ -2785,34 +2865,31 @@ if (this.type === tt.name) { // import defaultObj, { x, y as z } from '...' var node = this.startNode(); - node.id = this.parseIdent(); - this.checkLVal(node.id, true); - node.name = null; - node['default'] = true; - nodes.push(this.finishNode(node, "ImportSpecifier")); + node.local = this.parseIdent(); + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportDefaultSpecifier")); if (!this.eat(tt.comma)) return nodes; } if (this.type === tt.star) { var node = this.startNode(); this.next(); this.expectContextual("as"); - node.name = this.parseIdent(); - this.checkLVal(node.name, true); - nodes.push(this.finishNode(node, "ImportBatchSpecifier")); + node.local = this.parseIdent(); + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportNamespaceSpecifier")); return nodes; } this.expect(tt.braceL); while (!this.eat(tt.braceR)) { if (!first) { this.expect(tt.comma); - if (this.options.allowTrailingCommas && this.eat(tt.braceR)) break; + if (this.afterTrailingComma(tt.braceR)) break; } else first = false; var node = this.startNode(); - node.id = this.parseIdent(true); - node.name = this.eatContextual("as") ? this.parseIdent() : null; - this.checkLVal(node.name || node.id, true); - node['default'] = false; + node.imported = this.parseIdent(true); + node.local = this.eatContextual("as") ? this.parseIdent() : node.imported; + this.checkLVal(node.local, true); nodes.push(this.finishNode(node, "ImportSpecifier")); } return nodes; @@ -2823,7 +2900,7 @@ pp.parseYield = function() { var node = this.startNode(); this.next(); - if (this.eat(tt.semi) || this.canInsertSemicolon()) { + if (this.type == tt.semi || this.canInsertSemicolon()) { node.delegate = false; node.argument = null; } else { diff --git a/acorn_loose.js b/acorn_loose.js deleted file mode 100644 index 67236abbb7..0000000000 --- a/acorn_loose.js +++ /dev/null @@ -1,1150 +0,0 @@ -// Acorn: Loose parser -// -// This module provides an alternative parser (`parse_dammit`) that -// exposes that same interface as `parse`, but will try to parse -// anything as JavaScript, repairing syntax error the best it can. -// There are circumstances in which it will raise an error and give -// up, but they are very rare. The resulting AST will be a mostly -// valid JavaScript AST (as per the [Mozilla parser API][api], except -// that: -// -// - Return outside functions is allowed -// -// - Label consistency (no conflicts, break only to existing labels) -// is not enforced. -// -// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever -// the parser got too confused to return anything meaningful. -// -// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API -// -// The expected use for this is to *first* try `acorn.parse`, and only -// if that fails switch to `parse_dammit`. The loose parser might -// parse badly indented code incorrectly, so **don't** use it as -// your default parser. -// -// Quite a lot of acorn.js is duplicated here. The alternative was to -// add a *lot* of extra cruft to that file, making it less readable -// and slower. Copying and editing the code allowed me to make -// invasive changes and simplifications without creating a complicated -// tangle. - -(function(root, mod) { - if (typeof exports == "object" && typeof module == "object") return mod(exports, require("./acorn")); // CommonJS - if (typeof define == "function" && define.amd) return define(["exports", "./acorn"], mod); // AMD - mod(root.acorn || (root.acorn = {}), root.acorn); // Plain browser env -})(this, function(exports, acorn) { - "use strict"; - - var tt = acorn.tokTypes; - - acorn.defaultOptions.tabSize = 4; - - exports.parse_dammit = function(input, options) { - var p = new LooseParser(options, input); - p.next(); - return p.parseTopLevel(); - }; - - var LooseParser = exports.LooseParser = function(input, options) { - this.toks = new acorn.Parser(input, options); - this.options = this.toks.options; - this.input = this.toks.input; - this.tok = this.last = {type: tt.eof, start: 0, end: 0}; - if (this.options.locations) { - var here = this.toks.curPosition(); - this.tok.loc = new acorn.SourceLocation(this.toks, here, here); - } - this.ahead = []; // Tokens ahead - this.context = []; // Indentation contexted - this.curIndent = 0; - this.curLineStart = 0; - this.nextLineStart = this.lineEnd(this.curLineStart) + 1; - }; - - var lp = LooseParser.prototype; - - lp.next = function() { - this.last = this.tok; - if (this.ahead.length) - this.tok = this.ahead.shift(); - else - this.tok = this.readToken(); - - if (this.tok.start >= this.nextLineStart) { - while (this.tok.start >= this.nextLineStart) { - this.curLineStart = this.nextLineStart; - this.nextLineStart = this.lineEnd(this.curLineStart) + 1; - } - this.curIndent = this.indentationAfter(this.curLineStart); - } - }; - - lp.readToken = function() { - for (;;) { - try { - this.toks.next(); - if (this.toks.type === tt.dot && - this.input.substr(this.toks.end, 1) === "." && - this.options.ecmaVersion >= 6) { - this.toks.end++; - this.toks.type = tt.ellipsis; - } - return new acorn.Token(this.toks); - } catch(e) { - if (!(e instanceof SyntaxError)) throw e; - - // Try to skip some text, based on the error message, and then continue - var msg = e.message, pos = e.raisedAt, replace = true; - if (/unterminated/i.test(msg)) { - pos = this.lineEnd(e.pos + 1); - if (/string/.test(msg)) { - replace = {start: e.pos, end: pos, type: tt.string, value: this.input.slice(e.pos + 1, pos)}; - } else if (/regular expr/i.test(msg)) { - var re = this.input.slice(e.pos, pos); - try { re = new RegExp(re); } catch(e) {} - replace = {start: e.pos, end: pos, type: tt.regexp, value: re}; - } else if (/template/.test(msg)) { - replace = {start: e.pos, end: pos, - type: tt.template, - value: this.input.slice(e.pos, pos)}; - } else { - replace = false; - } - } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(msg)) { - while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos; - } else if (/character escape|expected hexadecimal/i.test(msg)) { - while (pos < this.input.length) { - var ch = this.input.charCodeAt(pos++); - if (ch === 34 || ch === 39 || acorn.isNewLine(ch)) break; - } - } else if (/unexpected character/i.test(msg)) { - pos++; - replace = false; - } else if (/regular expression/i.test(msg)) { - replace = true; - } else { - throw e; - } - this.resetTo(pos); - if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"}; - if (replace) { - if (this.options.locations) - replace.loc = new acorn.SourceLocation( - this.toks, - acorn.getLineInfo(this.input, replace.start), - acorn.getLineInfo(this.input, replace.end)); - return replace; - } - } - } - }; - - lp.resetTo = function(pos) { - this.toks.pos = pos; - var ch = this.input.charAt(pos - 1); - this.toks.exprAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) || - /[enwfd]/.test(ch) && - /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(this.input.slice(pos - 10, pos)); - - if (this.options.locations) { - this.toks.curLine = 1; - this.toks.lineStart = acorn.lineBreak.lastIndex = 0; - var match; - while ((match = acorn.lineBreak.exec(this.input)) && match.index < pos) { - ++this.toks.curLine; - this.toks.lineStart = match.index + match[0].length; - } - } - }; - - lp.lookAhead = function(n) { - while (n > this.ahead.length) - this.ahead.push(this.readToken()); - return this.ahead[n - 1]; - }; - - function isSpace(ch) { - return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || acorn.isNewLine(ch); - } - - lp.pushCx = function() { - this.context.push(this.curIndent); - }; - lp.popCx = function() { - this.curIndent = this.context.pop(); - }; - - lp.lineEnd = function(pos) { - while (pos < this.input.length && !acorn.isNewLine(this.input.charCodeAt(pos))) ++pos; - return pos; - }; - - lp.indentationAfter = function(pos) { - for (var count = 0;; ++pos) { - var ch = this.input.charCodeAt(pos); - if (ch === 32) ++count; - else if (ch === 9) count += this.options.tabSize; - else return count; - } - }; - - lp.closes = function(closeTok, indent, line, blockHeuristic) { - if (this.tok.type === closeTok || this.tok.type === tt.eof) return true; - return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && - (!blockHeuristic || this.nextLineStart >= this.input.length || - this.indentationAfter(this.nextLineStart) < indent); - }; - - lp.tokenStartsLine = function() { - for (var p = this.tok.start - 1; p >= this.curLineStart; --p) { - var ch = this.input.charCodeAt(p); - if (ch !== 9 && ch !== 32) return false; - } - return true; - }; - - lp.startNode = function() { - var node = new acorn.Node; - node.start = this.tok.start; - if (this.options.locations) - node.loc = new acorn.SourceLocation(this.toks, this.tok.loc.start); - if (this.options.directSourceFile) - node.sourceFile = this.options.directSourceFile; - if (this.options.ranges) - node.range = [this.tok.start, 0]; - return node; - }; - - lp.storeCurrentPos = function() { - return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start; - }; - - lp.startNodeAt = function(pos) { - var node = new acorn.Node; - if (this.options.locations) { - node.start = pos[0]; - node.loc = new acorn.SourceLocation(this.toks, pos[1]); - pos = pos[0]; - } else { - node.start = pos; - } - if (this.options.directSourceFile) - node.sourceFile = this.options.directSourceFile; - if (this.options.ranges) - node.range = [pos, 0]; - return node; - }; - - lp.finishNode = function(node, type) { - node.type = type; - node.end = this.last.end; - if (this.options.locations) - node.loc.end = this.last.loc.end; - if (this.options.ranges) - node.range[1] = this.last.end; - return node; - }; - - lp.dummyIdent = function() { - var dummy = this.startNode(); - dummy.name = "✖"; - return this.finishNode(dummy, "Identifier"); - }; - - function isDummy(node) { return node.name == "✖"; } - - lp.eat = function(type) { - if (this.tok.type === type) { - this.next(); - return true; - } else { - return false; - } - }; - - lp.isContextual = function(name) { - return this.tok.type === tt.name && this.tok.value === name; - }; - - lp.eatContextual = function(name) { - return this.tok.value === name && this.eat(tt.name); - }; - - lp.canInsertSemicolon = function() { - return this.tok.type === tt.eof || this.tok.type === tt.braceR || - acorn.newline.test(this.input.slice(this.last.end, this.tok.start)); - }; - - lp.semicolon = function() { - return this.eat(tt.semi); - }; - - lp.expect = function(type) { - if (this.eat(type)) return true; - for (var i = 1; i <= 2; i++) { - if (this.lookAhead(i).type == type) { - for (var j = 0; j < i; j++) this.next(); - return true; - } - } - }; - - lp.checkLVal = function(expr) { - if (!expr) return expr; - switch (expr.type) { - case "Identifier": - case "MemberExpression": - case "ObjectPattern": - case "ArrayPattern": - case "RestElement": - case "AssignmentPattern": - return expr; - - default: - return this.dummyIdent(); - } - }; - - lp.parseTopLevel = function() { - var node = this.startNodeAt(this.options.locations ? [0, acorn.getLineInfo(this.input, 0)] : 0); - node.body = []; - while (this.tok.type !== tt.eof) node.body.push(this.parseStatement()); - this.last = this.tok; - return this.finishNode(node, "Program"); - }; - - lp.parseStatement = function() { - var starttype = this.tok.type, node = this.startNode(); - - switch (starttype) { - case tt._break: case tt._continue: - this.next(); - var isBreak = starttype === tt._break; - if (this.semicolon() || this.canInsertSemicolon()) { - node.label = null; - } else { - node.label = this.tok.type === tt.name ? this.parseIdent() : null; - this.semicolon(); - } - return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement"); - - case tt._debugger: - this.next(); - this.semicolon(); - return this.finishNode(node, "DebuggerStatement"); - - case tt._do: - this.next(); - node.body = this.parseStatement(); - node.test = this.eat(tt._while) ? this.parseParenExpression() : this.dummyIdent(); - this.semicolon(); - return this.finishNode(node, "DoWhileStatement"); - - case tt._for: - this.next(); - this.pushCx(); - this.expect(tt.parenL); - if (this.tok.type === tt.semi) return this.parseFor(node, null); - if (this.tok.type === tt._var || this.tok.type === tt._let) { - var init = this.parseVar(true); - if (init.declarations.length === 1 && (this.tok.type === tt._in || this.isContextual("of"))) { - return this.parseForIn(node, init); - } - return this.parseFor(node, init); - } - var init = this.parseExpression(true); - if (this.tok.type === tt._in || this.isContextual("of")) - return this.parseForIn(node, this.toAssignable(init)); - return this.parseFor(node, init); - - case tt._function: - this.next(); - return this.parseFunction(node, true); - - case tt._if: - this.next(); - node.test = this.parseParenExpression(); - node.consequent = this.parseStatement(); - node.alternate = this.eat(tt._else) ? this.parseStatement() : null; - return this.finishNode(node, "IfStatement"); - - case tt._return: - this.next(); - if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null; - else { node.argument = this.parseExpression(); this.semicolon(); } - return this.finishNode(node, "ReturnStatement"); - - case tt._switch: - var blockIndent = this.curIndent, line = this.curLineStart; - this.next(); - node.discriminant = this.parseParenExpression(); - node.cases = []; - this.pushCx(); - this.expect(tt.braceL); - - for (var cur; !this.closes(tt.braceR, blockIndent, line, true);) { - if (this.tok.type === tt._case || this.tok.type === tt._default) { - var isCase = this.tok.type === tt._case; - if (cur) this.finishNode(cur, "SwitchCase"); - node.cases.push(cur = this.startNode()); - cur.consequent = []; - this.next(); - if (isCase) cur.test = this.parseExpression(); - else cur.test = null; - this.expect(tt.colon); - } else { - if (!cur) { - node.cases.push(cur = this.startNode()); - cur.consequent = []; - cur.test = null; - } - cur.consequent.push(this.parseStatement()); - } - } - if (cur) this.finishNode(cur, "SwitchCase"); - this.popCx(); - this.eat(tt.braceR); - return this.finishNode(node, "SwitchStatement"); - - case tt._throw: - this.next(); - node.argument = this.parseExpression(); - this.semicolon(); - return this.finishNode(node, "ThrowStatement"); - - case tt._try: - this.next(); - node.block = this.parseBlock(); - node.handler = null; - if (this.tok.type === tt._catch) { - var clause = this.startNode(); - this.next(); - this.expect(tt.parenL); - clause.param = this.toAssignable(this.parseExprAtom()); - this.expect(tt.parenR); - clause.guard = null; - clause.body = this.parseBlock(); - node.handler = this.finishNode(clause, "CatchClause"); - } - node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null; - if (!node.handler && !node.finalizer) return node.block; - return this.finishNode(node, "TryStatement"); - - case tt._var: - case tt._let: - case tt._const: - return this.parseVar(); - - case tt._while: - this.next(); - node.test = this.parseParenExpression(); - node.body = this.parseStatement(); - return this.finishNode(node, "WhileStatement"); - - case tt._with: - this.next(); - node.object = this.parseParenExpression(); - node.body = this.parseStatement(); - return this.finishNode(node, "WithStatement"); - - case tt.braceL: - return this.parseBlock(); - - case tt.semi: - this.next(); - return this.finishNode(node, "EmptyStatement"); - - case tt._class: - return this.parseObj(true, true); - - case tt._import: - return this.parseImport(); - - case tt._export: - return this.parseExport(); - - default: - var expr = this.parseExpression(); - if (isDummy(expr)) { - this.next(); - if (this.tok.type === tt.eof) return this.finishNode(node, "EmptyStatement"); - return this.parseStatement(); - } else if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) { - node.body = this.parseStatement(); - node.label = expr; - return this.finishNode(node, "LabeledStatement"); - } else { - node.expression = expr; - this.semicolon(); - return this.finishNode(node, "ExpressionStatement"); - } - } - }; - - lp.parseBlock = function() { - var node = this.startNode(); - this.pushCx(); - this.expect(tt.braceL); - var blockIndent = this.curIndent, line = this.curLineStart; - node.body = []; - while (!this.closes(tt.braceR, blockIndent, line, true)) - node.body.push(this.parseStatement()); - this.popCx(); - this.eat(tt.braceR); - return this.finishNode(node, "BlockStatement"); - }; - - lp.parseFor = function(node, init) { - node.init = init; - node.test = node.update = null; - if (this.eat(tt.semi) && this.tok.type !== tt.semi) node.test = this.parseExpression(); - if (this.eat(tt.semi) && this.tok.type !== tt.parenR) node.update = this.parseExpression(); - this.popCx(); - this.expect(tt.parenR); - node.body = this.parseStatement(); - return this.finishNode(node, "ForStatement"); - }; - - lp.parseForIn = function(node, init) { - var type = this.tok.type === tt._in ? "ForInStatement" : "ForOfStatement"; - this.next(); - node.left = init; - node.right = this.parseExpression(); - this.popCx(); - this.expect(tt.parenR); - node.body = this.parseStatement(); - return this.finishNode(node, type); - }; - - lp.parseVar = function(noIn) { - var node = this.startNode(); - node.kind = this.tok.type.keyword; - this.next(); - node.declarations = []; - do { - var decl = this.startNode(); - decl.id = this.options.ecmaVersion >= 6 ? this.toAssignable(this.parseExprAtom()) : this.parseIdent(); - decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : null; - node.declarations.push(this.finishNode(decl, "VariableDeclarator")); - } while (this.eat(tt.comma)); - if (!node.declarations.length) { - var decl = this.startNode(); - decl.id = this.dummyIdent(); - node.declarations.push(this.finishNode(decl, "VariableDeclarator")); - } - if (!noIn) this.semicolon(); - return this.finishNode(node, "VariableDeclaration"); - }; - - lp.parseExpression = function(noIn) { - var start = this.storeCurrentPos(); - var expr = this.parseMaybeAssign(noIn); - if (this.tok.type === tt.comma) { - var node = this.startNodeAt(start); - node.expressions = [expr]; - while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn)); - return this.finishNode(node, "SequenceExpression"); - } - return expr; - }; - - lp.parseParenExpression = function() { - this.pushCx(); - this.expect(tt.parenL); - var val = this.parseExpression(); - this.popCx(); - this.expect(tt.parenR); - return val; - }; - - lp.parseMaybeAssign = function(noIn) { - var start = this.storeCurrentPos(); - var left = this.parseMaybeConditional(noIn); - if (this.tok.type.isAssign) { - var node = this.startNodeAt(start); - node.operator = this.tok.value; - node.left = this.tok.type === tt.eq ? this.toAssignable(left) : this.checkLVal(left); - this.next(); - node.right = this.parseMaybeAssign(noIn); - return this.finishNode(node, "AssignmentExpression"); - } - return left; - }; - - lp.parseMaybeConditional = function(noIn) { - var start = this.storeCurrentPos(); - var expr = this.parseExprOps(noIn); - if (this.eat(tt.question)) { - var node = this.startNodeAt(start); - node.test = expr; - node.consequent = this.parseMaybeAssign(); - node.alternate = this.expect(tt.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent(); - return this.finishNode(node, "ConditionalExpression"); - } - return expr; - }; - - lp.parseExprOps = function(noIn) { - var start = this.storeCurrentPos(); - var indent = this.curIndent, line = this.curLineStart; - return this.parseExprOp(this.parseMaybeUnary(noIn), start, -1, noIn, indent, line); - }; - - lp.parseExprOp = function(left, start, minPrec, noIn, indent, line) { - if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) return left; - var prec = this.tok.type.binop; - if (prec != null && (!noIn || this.tok.type !== tt._in)) { - if (prec > minPrec) { - var node = this.startNodeAt(start); - node.left = left; - node.operator = this.tok.value; - this.next(); - if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) { - node.right = this.dummyIdent(); - } else { - var rightStart = this.storeCurrentPos(); - node.right = this.parseExprOp(this.parseMaybeUnary(noIn), rightStart, prec, noIn, indent, line); - } - this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression"); - return this.parseExprOp(node, start, minPrec, noIn, indent, line); - } - } - return left; - }; - - lp.parseMaybeUnary = function(noIn) { - if (this.tok.type.prefix) { - var node = this.startNode(), update = this.tok.type === tt.incDec; - node.operator = this.tok.value; - node.prefix = true; - this.next(); - node.argument = this.parseMaybeUnary(noIn); - if (update) node.argument = this.checkLVal(node.argument); - return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); - } else if (this.tok.type === tt.ellipsis) { - var node = this.startNode(); - this.next(); - node.argument = this.parseMaybeUnary(noIn); - return this.finishNode(node, "SpreadElement"); - } - var start = this.storeCurrentPos(); - var expr = this.parseExprSubscripts(); - while (this.tok.type.postfix && !this.canInsertSemicolon()) { - var node = this.startNodeAt(start); - node.operator = this.tok.value; - node.prefix = false; - node.argument = this.checkLVal(expr); - this.next(); - expr = this.finishNode(node, "UpdateExpression"); - } - return expr; - }; - - lp.parseExprSubscripts = function() { - var start = this.storeCurrentPos(); - return this.parseSubscripts(this.parseExprAtom(), start, false, this.curIndent, this.curLineStart); - }; - - lp.parseSubscripts = function(base, start, noCalls, startIndent, line) { - for (;;) { - if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) { - if (this.tok.type == tt.dot && this.curIndent == startIndent) - --startIndent; - else - return base; - } - - if (this.eat(tt.dot)) { - var node = this.startNodeAt(start); - node.object = base; - if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) - node.property = this.dummyIdent(); - else - node.property = this.parsePropertyAccessor() || this.dummyIdent(); - node.computed = false; - base = this.finishNode(node, "MemberExpression"); - } else if (this.tok.type == tt.bracketL) { - this.pushCx(); - this.next(); - var node = this.startNodeAt(start); - node.object = base; - node.property = this.parseExpression(); - node.computed = true; - this.popCx(); - this.expect(tt.bracketR); - base = this.finishNode(node, "MemberExpression"); - } else if (!noCalls && this.tok.type == tt.parenL) { - this.pushCx(); - var node = this.startNodeAt(start); - node.callee = base; - node.arguments = this.parseExprList(tt.parenR); - base = this.finishNode(node, "CallExpression"); - } else if (this.tok.type == tt.backQuote) { - var node = this.startNodeAt(start); - node.tag = base; - node.quasi = this.parseTemplate(); - base = this.finishNode(node, "TaggedTemplateExpression"); - } else { - return base; - } - } - }; - - lp.parseExprAtom = function() { - switch (this.tok.type) { - case tt._this: - var node = this.startNode(); - this.next(); - return this.finishNode(node, "ThisExpression"); - - case tt.name: - var start = this.storeCurrentPos(); - var id = this.parseIdent(); - return this.eat(tt.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id]) : id; - - case tt.regexp: - var node = this.startNode(); - var val = this.tok.value; - node.regex = {pattern: val.pattern, flags: val.flags}; - node.value = val.value; - node.raw = this.input.slice(this.tok.start, this.tok.end); - this.next(); - return this.finishNode(node, "Literal"); - - case tt.num: case tt.string: - var node = this.startNode(); - node.value = this.tok.value; - node.raw = this.input.slice(this.tok.start, this.tok.end); - this.next(); - return this.finishNode(node, "Literal"); - - case tt._null: case tt._true: case tt._false: - var node = this.startNode(); - node.value = this.tok.type === tt._null ? null : this.tok.type === tt._true; - node.raw = this.tok.type.keyword; - this.next(); - return this.finishNode(node, "Literal"); - - case tt.parenL: - var start = this.storeCurrentPos(); - this.next(); - var val = this.parseExpression(); - this.expect(tt.parenR); - if (this.eat(tt.arrow)) { - return this.parseArrowExpression(this.startNodeAt(start), val.expressions || (isDummy(val) ? [] : [val])); - } - if (this.options.preserveParens) { - var par = this.startNodeAt(start); - par.expression = val; - val = this.finishNode(par, "ParenthesizedExpression"); - } - return val; - - case tt.bracketL: - var node = this.startNode(); - this.pushCx(); - node.elements = this.parseExprList(tt.bracketR, true); - return this.finishNode(node, "ArrayExpression"); - - case tt.braceL: - return this.parseObj(); - - case tt._class: - return this.parseObj(true); - - case tt._function: - var node = this.startNode(); - this.next(); - return this.parseFunction(node, false); - - case tt._new: - return this.parseNew(); - - case tt._yield: - var node = this.startNode(); - this.next(); - if (this.semicolon() || this.canInsertSemicolon()) { - node.delegate = false; - node.argument = null; - } else { - node.delegate = this.eat(tt.star); - node.argument = this.parseMaybeAssign(); - } - return this.finishNode(node, "YieldExpression"); - - case tt.backQuote: - return this.parseTemplate(); - - default: - return this.dummyIdent(); - } - }; - - lp.parseNew = function() { - var node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart; - this.next(); - var start = this.storeCurrentPos(); - node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line); - if (this.tok.type == tt.parenL) { - this.pushCx(); - node.arguments = this.parseExprList(tt.parenR); - } else { - node.arguments = []; - } - return this.finishNode(node, "NewExpression"); - }; - - lp.parseTemplateElement = function() { - var elem = this.startNode(); - elem.value = { - raw: this.input.slice(this.tok.start, this.tok.end), - cooked: this.tok.value - }; - this.next(); - elem.tail = this.tok.type === tt.backQuote; - return this.finishNode(elem, "TemplateElement"); - }; - - lp.parseTemplate = function() { - var node = this.startNode(); - this.next(); - node.expressions = []; - var curElt = this.parseTemplateElement(); - node.quasis = [curElt]; - while (!curElt.tail) { - this.next(); - node.expressions.push(this.parseExpression()); - if (this.expect(tt.braceR)) { - curElt = this.parseTemplateElement(); - } else { - curElt = this.startNode(); - curElt.value = {cooked: '', raw: ''}; - curElt.tail = true; - } - node.quasis.push(curElt); - } - this.expect(tt.backQuote); - return this.finishNode(node, "TemplateLiteral"); - }; - - lp.parseObj = function(isClass, isStatement) { - var node = this.startNode(); - if (isClass) { - this.next(); - if (this.tok.type === tt.name) node.id = this.parseIdent(); - else if (isStatement) node.id = this.dummyIdent(); - else node.id = null; - node.superClass = this.eat(tt._extends) ? this.parseExpression() : null; - node.body = this.startNode(); - node.body.body = []; - } else { - node.properties = []; - } - this.pushCx(); - var indent = this.curIndent + 1, line = this.curLineStart; - this.eat(tt.braceL); - if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; } - while (!this.closes(tt.braceR, indent, line)) { - if (isClass && this.semicolon()) continue; - var prop = this.startNode(), isGenerator, start; - if (this.options.ecmaVersion >= 6) { - if (isClass) { - prop['static'] = false; - } else { - start = this.storeCurrentPos(); - prop.method = false; - prop.shorthand = false; - } - isGenerator = this.eat(tt.star); - } - this.parsePropertyName(prop); - if (isDummy(prop.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue; } - if (isClass) { - if (prop.key.type === "Identifier" && !prop.computed && prop.key.name === "static" && - (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) { - prop['static'] = true; - isGenerator = this.eat(tt.star); - this.parsePropertyName(prop); - } else { - prop['static'] = false; - } - } - if (!isClass && this.eat(tt.colon)) { - prop.kind = "init"; - prop.value = this.parseMaybeAssign(); - } else if (this.options.ecmaVersion >= 6 && (this.tok.type === tt.parenL || this.tok.type === tt.braceL)) { - if (isClass) { - prop.kind = ""; - } else { - prop.kind = "init"; - prop.method = true; - } - prop.value = this.parseMethod(isGenerator); - } else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && - !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && - (this.tok.type != tt.comma && this.tok.type != tt.braceR)) { - prop.kind = prop.key.name; - this.parsePropertyName(prop); - prop.value = this.parseMethod(false); - } else if (isClass) { - prop.kind = ""; - prop.value = this.parseMethod(isGenerator); - } else { - prop.kind = "init"; - if (this.options.ecmaVersion >= 6) { - if (this.eat(tt.eq)) { - var assign = this.startNodeAt(start); - assign.operator = "="; - assign.left = prop.key; - assign.right = this.parseMaybeAssign(); - prop.value = this.finishNode(assign, "AssignmentExpression"); - } else { - prop.value = prop.key; - } - } else { - prop.value = this.dummyIdent(); - } - prop.shorthand = true; - } - - if (isClass) { - node.body.body.push(this.finishNode(prop, "MethodDefinition")); - } else { - node.properties.push(this.finishNode(prop, "Property")); - this.eat(tt.comma); - } - } - this.popCx(); - if (!this.eat(tt.braceR)) { - // If there is no closing brace, make the node span to the start - // of the next token (this is useful for Tern) - this.last.end = this.tok.start; - if (this.options.locations) this.last.loc.end = this.tok.loc.start; - } - if (isClass) { - this.semicolon(); - this.finishNode(node.body, "ClassBody"); - return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression"); - } else { - return this.finishNode(node, "ObjectExpression"); - } - }; - - lp.parsePropertyName = function(prop) { - if (this.options.ecmaVersion >= 6) { - if (this.eat(tt.bracketL)) { - prop.computed = true; - prop.key = this.parseExpression(); - this.expect(tt.bracketR); - return; - } else { - prop.computed = false; - } - } - var key = (this.tok.type === tt.num || this.tok.type === tt.string) ? this.parseExprAtom() : this.parseIdent(); - prop.key = key || this.dummyIdent(); - }; - - lp.parsePropertyAccessor = function() { - if (this.tok.type === tt.name || this.tok.type.keyword) return this.parseIdent(); - }; - - lp.parseIdent = function() { - var node = this.startNode(); - node.name = this.tok.type === tt.name ? this.tok.value : this.tok.type.keyword; - this.next(); - return this.finishNode(node, "Identifier"); - }; - - lp.initFunction = function(node) { - node.id = null; - node.params = []; - if (this.options.ecmaVersion >= 6) { - node.generator = false; - node.expression = false; - } - }; - - // Convert existing expression atom to assignable pattern - // if possible. - - lp.toAssignable = function(node) { - if (this.options.ecmaVersion >= 6 && node) { - switch (node.type) { - case "ObjectExpression": - node.type = "ObjectPattern"; - var props = node.properties; - for (var i = 0; i < props.length; i++) - this.toAssignable(props[i].value); - break; - - case "ArrayExpression": - node.type = "ArrayPattern"; - this.toAssignableList(node.elements); - break; - - case "SpreadElement": - node.type = "RestElement"; - node.argument = this.toAssignable(node.argument); - break; - - case "AssignmentExpression": - node.type = "AssignmentPattern"; - break; - } - } - return this.checkLVal(node); - }; - - lp.toAssignableList = function(exprList) { - for (var i = 0; i < exprList.length; i++) - this.toAssignable(exprList[i]); - return exprList; - }; - - lp.parseFunctionParams = function(params) { - this.pushCx(); - params = this.parseExprList(tt.parenR); - return this.toAssignableList(params); - }; - - lp.parseFunction = function(node, isStatement) { - this.initFunction(node); - if (this.options.ecmaVersion >= 6) { - node.generator = this.eat(tt.star); - } - if (this.tok.type === tt.name) node.id = this.parseIdent(); - else if (isStatement) node.id = this.dummyIdent(); - node.params = this.parseFunctionParams(); - node.body = this.parseBlock(); - return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); - }; - - lp.parseMethod = function(isGenerator) { - var node = this.startNode(); - this.initFunction(node); - node.params = this.parseFunctionParams(); - node.generator = isGenerator || false; - node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== tt.braceL; - node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock(); - return this.finishNode(node, "FunctionExpression"); - }; - - lp.parseArrowExpression = function(node, params) { - this.initFunction(node); - node.params = this.toAssignableList(params); - node.expression = this.tok.type !== tt.braceL; - node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock(); - return this.finishNode(node, "ArrowFunctionExpression"); - }; - - lp.parseExport = function() { - var node = this.startNode(); - this.next(); - node['default'] = this.eat(tt._default); - node.specifiers = node.source = null; - if (node['default']) { - var expr = this.parseMaybeAssign(); - if (expr.id) { - switch (expr.type) { - case "FunctionExpression": expr.type = "FunctionDeclaration"; break; - case "ClassExpression": expr.type = "ClassDeclaration"; break; - } - } - node.declaration = expr; - this.semicolon(); - } else if (this.tok.type.keyword) { - node.declaration = this.parseStatement(); - } else { - node.declaration = null; - this.parseSpecifierList(node, "Export"); - } - this.semicolon(); - return this.finishNode(node, "ExportDeclaration"); - }; - - lp.parseImport = function() { - var node = this.startNode(); - this.next(); - if (this.tok.type === tt.string) { - node.specifiers = []; - node.source = this.parseExprAtom(); - node.kind = ''; - } else { - if (this.tok.type === tt.name && this.tok.value !== "from") { - var elt = this.startNode(); - elt.id = this.parseIdent(); - elt.name = null; - elt['default'] = true; - this.finishNode(elt, "ImportSpecifier"); - this.eat(tt.comma); - } - this.parseSpecifierList(node, "Import"); - var specs = node.specifiers; - for (var i = 0; i < specs.length; i++) specs[i]['default'] = false; - if (elt) node.specifiers.unshift(elt); - } - this.semicolon(); - return this.finishNode(node, "ImportDeclaration"); - }; - - lp.parseSpecifierList = function(node, prefix) { - var elts = node.specifiers = []; - if (this.tok.type === tt.star) { - var elt = this.startNode(); - this.next(); - if (this.eatContextual("as")) elt.name = this.parseIdent(); - elts.push(this.finishNode(elt, prefix + "BatchSpecifier")); - } else { - var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart; - this.pushCx(); - this.eat(tt.braceL); - if (this.curLineStart > continuedLine) continuedLine = this.curLineStart; - while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { - var elt = this.startNode(); - if (this.eat(tt.star)) { - if (this.eatContextual("as")) elt.name = this.parseIdent(); - this.finishNode(elt, prefix + "BatchSpecifier"); - } else { - if (this.isContextual("from")) break; - elt.id = this.parseIdent(); - elt.name = this.eatContextual("as") ? this.parseIdent() : null; - this.finishNode(elt, prefix + "Specifier"); - } - elts.push(elt); - this.eat(tt.comma); - } - this.eat(tt.braceR); - this.popCx(); - } - node.source = this.eatContextual("from") ? this.parseExprAtom() : null; - }; - - lp.parseExprList = function(close, allowEmpty) { - var indent = this.curIndent, line = this.curLineStart, elts = []; - this.next(); // Opening bracket - while (!this.closes(close, indent + 1, line)) { - if (this.eat(tt.comma)) { - elts.push(allowEmpty ? null : this.dummyIdent()); - continue; - } - var elt = this.parseMaybeAssign(); - if (isDummy(elt)) { - if (this.closes(close, indent, line)) break; - this.next(); - } else { - elts.push(elt); - } - this.eat(tt.comma); - } - this.popCx(); - if (!this.eat(close)) { - // If there is no closing brace, make the node span to the start - // of the next token (this is useful for Tern) - this.last.end = this.tok.start; - if (this.options.locations) this.last.loc.end = this.tok.loc.start; - } - return elts; - }; -}); diff --git a/bin/acorn b/bin/acorn deleted file mode 100755 index b80ad29d51..0000000000 --- a/bin/acorn +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env node - -var path = require("path"); -var fs = require("fs"); -var acorn = require("../acorn.js"); - -var infile, parsed, tokens, options = {}, silent = false, compact = false, tokenize = false; - -function help(status) { - var print = (status == 0) ? console.log : console.error; - print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6] [--strictSemicolons]"); - print(" [--tokenize] [--locations] [--compact] [--silent] [--help] [--] infile"); - process.exit(status); -} - -for (var i = 2; i < process.argv.length; ++i) { - var arg = process.argv[i]; - if (arg[0] != "-" && !infile) infile = arg; - else if (arg == "--" && !infile && i + 2 == process.argv.length) infile = process.argv[++i]; - else if (arg == "--ecma3") options.ecmaVersion = 3; - else if (arg == "--ecma5") options.ecmaVersion = 5; - else if (arg == "--ecma6") options.ecmaVersion = 6; - else if (arg == "--ecma7") options.ecmaVersion = 7; - else if (arg == "--strictSemicolons") options.strictSemicolons = true; - else if (arg == "--locations") options.locations = true; - else if (arg == "--silent") silent = true; - else if (arg == "--compact") compact = true; - else if (arg == "--help") help(0); - else if (arg == "--tokenize") tokenize = true; - else help(1); -} - -try { - var code = fs.readFileSync(infile, "utf8"); - - if (!tokenize) - parsed = acorn.parse(code, options); - else { - var get = acorn.tokenize(code, options); - tokens = []; - while (true) { - var token = get(); - tokens.push(token); - if (token.type.type == "eof") - break; - } - } -} catch(e) { - console.log(e.message); - process.exit(1); -} - -if (!silent) - console.log(JSON.stringify(tokenize ? tokens : parsed, null, compact ? null : 2)); diff --git a/bin/update_authors.sh b/bin/update_authors.sh deleted file mode 100755 index 466c8db586..0000000000 --- a/bin/update_authors.sh +++ /dev/null @@ -1,6 +0,0 @@ -# Combine existing list of authors with everyone known in git, sort, add header. -tail --lines=+3 AUTHORS > AUTHORS.tmp -git log --format='%aN' | grep -v abraidwood >> AUTHORS.tmp -echo -e "List of Acorn contributors. Updated before every release.\n" > AUTHORS -sort -u AUTHORS.tmp >> AUTHORS -rm -f AUTHORS.tmp diff --git a/bin/without_eval b/bin/without_eval deleted file mode 100755 index e9ef18f380..0000000000 --- a/bin/without_eval +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env node - -var fs = require("fs"); - -var acornSrc = fs.readFileSync(require.resolve("../acorn"), "utf8"); -var acorn = require("../acorn"), walk = require("../util/walk"); - -var ast = acorn.parse(acornSrc); -var touchups = [], uses = []; - -walk.simple(ast, { - FunctionDeclaration: function(node) { - if (node.id.name == "makePredicate") - touchups.push({text: "// Removed to create an eval-free library", from: node.start, to: node.end}); - }, - VariableDeclaration: function(node) { - node.declarations.forEach(function(decl) { - if (decl.init && decl.init.type == "CallExpression" && - decl.init.callee.name == "makePredicate") - uses.push(decl); - }); - } -}); - -var results = Object.create(null); -var functions = new Function("predicates", acornSrc.replace( - /\}\);\s*$/, uses.map(function(decl) { - return "predicates[" + JSON.stringify(decl.id.name) + "] = " + decl.id.name + ";"; - }).join("") + "});"))(results); - -uses.forEach(function(decl) { - touchups.push({text: results[decl.id.name].toString(), - from: decl.init.start, to: decl.init.end}); -}); - -var result = "", pos = 0; -touchups.sort(function(a, b) { return a.from - b.from; }); -touchups.forEach(function(touchup) { - result += acornSrc.slice(pos, touchup.from); - result += touchup.text; - pos = touchup.to; -}); -result += acornSrc.slice(pos); - -process.stdout.write(result); diff --git a/docco.css b/docco.css deleted file mode 100644 index 04cc7ecb8a..0000000000 --- a/docco.css +++ /dev/null @@ -1,192 +0,0 @@ -/*--------------------- Layout and Typography ----------------------------*/ -body { - font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; - font-size: 15px; - line-height: 22px; - color: #252519; - margin: 0; padding: 0; -} -a { - color: #261a3b; -} - a:visited { - color: #261a3b; - } -p { - margin: 0 0 15px 0; -} -h1, h2, h3, h4, h5, h6 { - margin: 0px 0 15px 0; -} - h1 { - margin-top: 40px; - } -hr { - border: 0 none; - border-top: 1px solid #e5e5ee; - height: 1px; - margin: 20px 0; -} -#container { - position: relative; -} -#background { - position: fixed; - top: 0; left: 525px; right: 0; bottom: 0; - background: #f5f5ff; - border-left: 1px solid #e5e5ee; - z-index: -1; -} -#jump_to, #jump_page { - background: white; - -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; - -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; - font: 10px Arial; - text-transform: uppercase; - cursor: pointer; - text-align: right; -} -#jump_to, #jump_wrapper { - position: fixed; - right: 0; top: 0; - padding: 5px 10px; -} - #jump_wrapper { - padding: 0; - display: none; - } - #jump_to:hover #jump_wrapper { - display: block; - } - #jump_page { - padding: 5px 0 3px; - margin: 0 0 25px 25px; - } - #jump_page .source { - display: block; - padding: 5px 10px; - text-decoration: none; - border-top: 1px solid #eee; - } - #jump_page .source:hover { - background: #f5f5ff; - } - #jump_page .source:first-child { - } -table td { - border: 0; - outline: 0; -} - td.docs, th.docs { - max-width: 450px; - min-width: 450px; - min-height: 5px; - padding: 10px 25px 1px 50px; - overflow-x: hidden; - vertical-align: top; - text-align: left; - } - .docs pre { - margin: 15px 0 15px; - padding-left: 15px; - } - .docs p tt, .docs p code { - background: #f8f8ff; - border: 1px solid #dedede; - font-size: 12px; - padding: 0 0.2em; - } - .pilwrap { - position: relative; - } - .pilcrow { - font: 12px Arial; - text-decoration: none; - color: #454545; - position: absolute; - top: 3px; left: -20px; - padding: 1px 2px; - opacity: 0; - -webkit-transition: opacity 0.2s linear; - } - td.docs:hover .pilcrow { - opacity: 1; - } - td.code, th.code { - padding: 14px 15px 16px 25px; - width: 100%; - vertical-align: top; - background: #f5f5ff; - border-left: 1px solid #e5e5ee; - } - pre, tt, code { - font-size: 12px; line-height: 18px; - font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; - margin: 0; padding: 0; - } - - -/*---------------------- Syntax Highlighting -----------------------------*/ -td.linenos { background-color: #f0f0f0; padding-right: 10px; } -span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } -body .hll { background-color: #ffffcc } -body .c { color: #408080; font-style: italic } /* Comment */ -body .err { border: 1px solid #FF0000 } /* Error */ -body .k { color: #954121 } /* Keyword */ -body .o { color: #666666 } /* Operator */ -body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ -body .cp { color: #BC7A00 } /* Comment.Preproc */ -body .c1 { color: #408080; font-style: italic } /* Comment.Single */ -body .cs { color: #408080; font-style: italic } /* Comment.Special */ -body .gd { color: #A00000 } /* Generic.Deleted */ -body .ge { font-style: italic } /* Generic.Emph */ -body .gr { color: #FF0000 } /* Generic.Error */ -body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -body .gi { color: #00A000 } /* Generic.Inserted */ -body .go { color: #808080 } /* Generic.Output */ -body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -body .gs { font-weight: bold } /* Generic.Strong */ -body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -body .gt { color: #0040D0 } /* Generic.Traceback */ -body .kc { color: #954121 } /* Keyword.Constant */ -body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ -body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ -body .kp { color: #954121 } /* Keyword.Pseudo */ -body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ -body .kt { color: #B00040 } /* Keyword.Type */ -body .m { color: #666666 } /* Literal.Number */ -body .s { color: #219161 } /* Literal.String */ -body .na { color: #7D9029 } /* Name.Attribute */ -body .nb { color: #954121 } /* Name.Builtin */ -body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ -body .no { color: #880000 } /* Name.Constant */ -body .nd { color: #AA22FF } /* Name.Decorator */ -body .ni { color: #999999; font-weight: bold } /* Name.Entity */ -body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -body .nf { color: #0000FF } /* Name.Function */ -body .nl { color: #A0A000 } /* Name.Label */ -body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -body .nt { color: #954121; font-weight: bold } /* Name.Tag */ -body .nv { color: #19469D } /* Name.Variable */ -body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -body .w { color: #bbbbbb } /* Text.Whitespace */ -body .mf { color: #666666 } /* Literal.Number.Float */ -body .mh { color: #666666 } /* Literal.Number.Hex */ -body .mi { color: #666666 } /* Literal.Number.Integer */ -body .mo { color: #666666 } /* Literal.Number.Oct */ -body .sb { color: #219161 } /* Literal.String.Backtick */ -body .sc { color: #219161 } /* Literal.String.Char */ -body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ -body .s2 { color: #219161 } /* Literal.String.Double */ -body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -body .sh { color: #219161 } /* Literal.String.Heredoc */ -body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -body .sx { color: #954121 } /* Literal.String.Other */ -body .sr { color: #BB6688 } /* Literal.String.Regex */ -body .s1 { color: #219161 } /* Literal.String.Single */ -body .ss { color: #19469D } /* Literal.String.Symbol */ -body .bp { color: #954121 } /* Name.Builtin.Pseudo */ -body .vc { color: #19469D } /* Name.Variable.Class */ -body .vg { color: #19469D } /* Name.Variable.Global */ -body .vi { color: #19469D } /* Name.Variable.Instance */ -body .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/package.json b/package.json index 3cda09c316..c657c2d2f5 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "acorn.js", "version": "0.12.1", "engines": {"node": ">=0.4.0"}, + "browser": "acorn_csp.js", "maintainers": [{"name": "Marijn Haverbeke", "email": "marijnh@gmail.com", "web": "http://marijnhaverbeke.nl"}], diff --git a/test/driver.js b/test/driver.js index 6de53dc9e3..d8998b930b 100644 --- a/test/driver.js +++ b/test/driver.js @@ -17,43 +17,17 @@ for (var i = 0; i < tests.length; ++i) { var test = tests[i]; if (config.filter && !config.filter(test)) continue; + var testOpts = test.options || {locations: true}; + var expected = {}; + if (expected.onComment = testOpts.onComment) + testOpts.onComment = [] + if (expected.onToken = testOpts.onToken) + testOpts.onToken = []; + try { - var testOpts = test.options || {locations: true}; - var expected = {}; - if (expected.onComment = testOpts.onComment) { - testOpts.onComment = [] - } - if (expected.onToken = testOpts.onToken) { - testOpts.onToken = []; - } var ast = parse(test.code, testOpts); - if (test.error) { - if (config.loose) { - callback("ok", test.code); - } else { - callback("fail", test.code, "Expected error message: " + test.error + "\nBut parsing succeeded."); - } - } else if (test.assert) { - var error = test.assert(ast); - if (error) callback("fail", test.code, - "\n Assertion failed:\n " + error); - else callback("ok", test.code); - } else { - var mis = misMatch(test.ast, ast); - for (var name in expected) { - if (mis) break; - if (expected[name]) { - mis = misMatch(expected[name], testOpts[name]); - testOpts[name] = expected[name]; - } - } - if (mis) callback("fail", test.code, mis); - else callback("ok", test.code); - } } catch(e) { - if (!(e instanceof SyntaxError)) { - throw e; - } + if (!(e instanceof SyntaxError)) throw e; if (test.error) { if (e.message == test.error) callback("ok", test.code); else callback("fail", test.code, @@ -61,6 +35,27 @@ } else { callback("error", test.code, e.message || e.toString()); } + continue + } + + if (test.error) { + if (config.loose) callback("ok", test.code); + else callback("fail", test.code, "Expected error message: " + test.error + "\nBut parsing succeeded."); + } else if (test.assert) { + var error = test.assert(ast); + if (error) callback("fail", test.code, "\n Assertion failed:\n " + error); + else callback("ok", test.code); + } else { + var mis = misMatch(test.ast, ast); + for (var name in expected) { + if (mis) break; + if (expected[name]) { + mis = misMatch(expected[name], testOpts[name]); + testOpts[name] = expected[name]; + } + } + if (mis) callback("fail", test.code, mis); + else callback("ok", test.code); } } }; diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 8e3dd24c13..3fde855cfb 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -4453,7 +4453,7 @@ test("var {a:b} = {}", { test("export var document", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "VariableDeclaration", declarations: [{ @@ -4478,8 +4478,7 @@ test("export var document", { end: {line: 1, column: 19} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4499,7 +4498,7 @@ test("export var document", { test("export var document = { }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "VariableDeclaration", declarations: [{ @@ -4531,8 +4530,7 @@ test("export var document = { }", { end: {line: 1, column: 25} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4552,7 +4550,7 @@ test("export var document = { }", { test("export let document", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "VariableDeclaration", declarations: [{ @@ -4577,8 +4575,7 @@ test("export let document", { end: {line: 1, column: 19} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4598,7 +4595,7 @@ test("export let document", { test("export let document = { }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "VariableDeclaration", declarations: [{ @@ -4630,8 +4627,7 @@ test("export let document = { }", { end: {line: 1, column: 25} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4651,7 +4647,7 @@ test("export let document = { }", { test("export const document = { }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "VariableDeclaration", declarations: [{ @@ -4683,8 +4679,7 @@ test("export const document = { }", { end: {line: 1, column: 27} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4704,7 +4699,7 @@ test("export const document = { }", { test("export function parse() { }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "FunctionDeclaration", id: { @@ -4731,8 +4726,7 @@ test("export function parse() { }", { end: {line: 1, column: 27} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4752,7 +4746,7 @@ test("export function parse() { }", { test("export class Class {}", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: { type: "ClassDeclaration", id: { @@ -4777,8 +4771,7 @@ test("export class Class {}", { end: {line: 1, column: 21} } }, - default: false, - specifiers: null, + specifiers: [], source: null, loc: { start: {line: 1, column: 0}, @@ -4798,7 +4791,7 @@ test("export class Class {}", { test("export default 42", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportDefaultDeclaration", declaration: { type: "Literal", value: 42, @@ -4808,9 +4801,6 @@ test("export default 42", { end: {line: 1, column: 17} } }, - default: true, - specifiers: null, - source: null, loc: { start: {line: 1, column: 0}, end: {line: 1, column: 17} @@ -4830,7 +4820,7 @@ test("export default function () {}", { type: "Program", range: [0, 29], body: [{ - type: "ExportDeclaration", + type: "ExportDefaultDeclaration", range: [0, 29], declaration: { type: "FunctionExpression", @@ -4844,10 +4834,7 @@ test("export default function () {}", { range: [27, 29], body: [] } - }, - default: true, - specifiers: null, - source: null + } }] }, {ecmaVersion: 6, ranges: true}); @@ -4855,7 +4842,7 @@ test("export default function f() {}", { type: "Program", range: [0, 30], body: [{ - type: "ExportDeclaration", + type: "ExportDefaultDeclaration", range: [0, 30], declaration: { type: "FunctionDeclaration", @@ -4873,10 +4860,7 @@ test("export default function f() {}", { range: [28, 30], body: [] } - }, - default: true, - specifiers: null, - source: null + } }] }, {ecmaVersion: 6, ranges: true}); @@ -4884,7 +4868,7 @@ test("export default class {}", { type: "Program", range: [0, 23], body: [{ - type: "ExportDeclaration", + type: "ExportDefaultDeclaration", range: [0, 23], declaration: { type: "ClassExpression", @@ -4896,10 +4880,7 @@ test("export default class {}", { range: [21, 23], body: [] } - }, - default: true, - specifiers: null, - source: null + } }] }, {ecmaVersion: 6, ranges: true}); @@ -4907,7 +4888,7 @@ test("export default class A {}", { type: "Program", range: [0, 25], body: [{ - type: "ExportDeclaration", + type: "ExportDefaultDeclaration", range: [0, 25], declaration: { type: "ClassDeclaration", @@ -4923,10 +4904,7 @@ test("export default class A {}", { range: [23, 25], body: [] } - }, - default: true, - specifiers: null, - source: null + } }] }, {ecmaVersion: 6, ranges: true}); @@ -4935,15 +4913,7 @@ testFail("export *", "Unexpected token (1:8)", {ecmaVersion: 6}); test("export * from \"crypto\"", { type: "Program", body: [{ - type: "ExportDeclaration", - declaration: null, - specifiers: [{ - type: "ExportBatchSpecifier", - loc: { - start: {line: 1, column: 7}, - end: {line: 1, column: 8} - } - }], + type: "ExportAllDeclaration", source: { type: "Literal", value: "crypto", @@ -4971,11 +4941,19 @@ test("export * from \"crypto\"", { test("export { encrypt }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: null, specifiers: [{ type: "ExportSpecifier", - id: { + exported: { + type: "Identifier", + name: "encrypt", + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + } + }, + local: { type: "Identifier", name: "encrypt", loc: { @@ -4983,7 +4961,6 @@ test("export { encrypt }", { end: {line: 1, column: 16} } }, - name: null, loc: { start: {line: 1, column: 9}, end: {line: 1, column: 16} @@ -5008,12 +4985,20 @@ test("export { encrypt }", { test("export { encrypt, decrypt }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: null, specifiers: [ { type: "ExportSpecifier", - id: { + exported: { + type: "Identifier", + name: "encrypt", + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + } + }, + local: { type: "Identifier", name: "encrypt", loc: { @@ -5021,7 +5006,6 @@ test("export { encrypt, decrypt }", { end: {line: 1, column: 16} } }, - name: null, loc: { start: {line: 1, column: 9}, end: {line: 1, column: 16} @@ -5029,7 +5013,15 @@ test("export { encrypt, decrypt }", { }, { type: "ExportSpecifier", - id: { + exported: { + type: "Identifier", + name: "decrypt", + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 25} + } + }, + local: { type: "Identifier", name: "decrypt", loc: { @@ -5037,7 +5029,6 @@ test("export { encrypt, decrypt }", { end: {line: 1, column: 25} } }, - name: null, loc: { start: {line: 1, column: 18}, end: {line: 1, column: 25} @@ -5063,19 +5054,11 @@ test("export { encrypt, decrypt }", { test("export { encrypt as default }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: null, specifiers: [{ type: "ExportSpecifier", - id: { - type: "Identifier", - name: "encrypt", - loc: { - start: {line: 1, column: 9}, - end: {line: 1, column: 16} - } - }, - name: { + exported: { type: "Identifier", name: "default", loc: { @@ -5083,6 +5066,14 @@ test("export { encrypt as default }", { end: {line: 1, column: 27} } }, + local: { + type: "Identifier", + name: "encrypt", + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + } + }, loc: { start: {line: 1, column: 9}, end: {line: 1, column: 27} @@ -5107,12 +5098,20 @@ test("export { encrypt as default }", { test("export { encrypt, decrypt as dec }", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: null, specifiers: [ { type: "ExportSpecifier", - id: { + exported: { + type: "Identifier", + name: "encrypt", + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + } + }, + local: { type: "Identifier", name: "encrypt", loc: { @@ -5120,7 +5119,6 @@ test("export { encrypt, decrypt as dec }", { end: {line: 1, column: 16} } }, - name: null, loc: { start: {line: 1, column: 9}, end: {line: 1, column: 16} @@ -5128,15 +5126,7 @@ test("export { encrypt, decrypt as dec }", { }, { type: "ExportSpecifier", - id: { - type: "Identifier", - name: "decrypt", - loc: { - start: {line: 1, column: 18}, - end: {line: 1, column: 25} - } - }, - name: { + exported: { type: "Identifier", name: "dec", loc: { @@ -5144,6 +5134,14 @@ test("export { encrypt, decrypt as dec }", { end: {line: 1, column: 32} } }, + local: { + type: "Identifier", + name: "decrypt", + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 25} + } + }, loc: { start: {line: 1, column: 18}, end: {line: 1, column: 32} @@ -5169,12 +5167,20 @@ test("export { encrypt, decrypt as dec }", { test("export { default } from \"other\"", { type: "Program", body: [{ - type: "ExportDeclaration", + type: "ExportNamedDeclaration", declaration: null, specifiers: [ { type: "ExportSpecifier", - id: { + exported: { + type: "Identifier", + name: "default", + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + } + }, + local: { type: "Identifier", name: "default", loc: { @@ -5182,7 +5188,6 @@ test("export { default } from \"other\"", { end: {line: 1, column: 16} } }, - name: null, loc: { start: {line: 1, column: 9}, end: {line: 1, column: 16} @@ -5253,8 +5258,8 @@ test("import $ from \"jquery\"", { body: [{ type: "ImportDeclaration", specifiers: [{ - type: "ImportSpecifier", - id: { + type: "ImportDefaultSpecifier", + local: { type: "Identifier", name: "$", loc: { @@ -5262,7 +5267,6 @@ test("import $ from \"jquery\"", { end: {line: 1, column: 8} } }, - name: null, loc: { start: {line: 1, column: 7}, end: {line: 1, column: 8} @@ -5299,7 +5303,15 @@ test("import { encrypt, decrypt } from \"crypto\"", { specifiers: [ { type: "ImportSpecifier", - id: { + imported: { + type: "Identifier", + name: "encrypt", + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + } + }, + local: { type: "Identifier", name: "encrypt", loc: { @@ -5307,7 +5319,6 @@ test("import { encrypt, decrypt } from \"crypto\"", { end: {line: 1, column: 16} } }, - name: null, loc: { start: {line: 1, column: 9}, end: {line: 1, column: 16} @@ -5315,7 +5326,15 @@ test("import { encrypt, decrypt } from \"crypto\"", { }, { type: "ImportSpecifier", - id: { + imported: { + type: "Identifier", + name: "decrypt", + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 25} + } + }, + local: { type: "Identifier", name: "decrypt", loc: { @@ -5323,7 +5342,6 @@ test("import { encrypt, decrypt } from \"crypto\"", { end: {line: 1, column: 25} } }, - name: null, loc: { start: {line: 1, column: 18}, end: {line: 1, column: 25} @@ -5360,7 +5378,7 @@ test("import { encrypt as enc } from \"crypto\"", { type: "ImportDeclaration", specifiers: [{ type: "ImportSpecifier", - id: { + imported: { type: "Identifier", name: "encrypt", loc: { @@ -5368,7 +5386,7 @@ test("import { encrypt as enc } from \"crypto\"", { end: {line: 1, column: 16} } }, - name: { + local: { type: "Identifier", name: "enc", loc: { @@ -5419,21 +5437,19 @@ test("import crypto, { decrypt, encrypt as enc } from \"crypto\"", { }, specifiers: [ { - type: "ImportSpecifier", + type: "ImportDefaultSpecifier", loc: { start: {line: 1, column: 7}, end: {line: 1, column: 13} }, - id: { + local: { type: "Identifier", loc: { start: {line: 1, column: 7}, end: {line: 1, column: 13} }, name: "crypto" - }, - name: null, - default: true + } }, { type: "ImportSpecifier", @@ -5441,7 +5457,7 @@ test("import crypto, { decrypt, encrypt as enc } from \"crypto\"", { start: {line: 1, column: 17}, end: {line: 1, column: 24} }, - id: { + imported: { type: "Identifier", loc: { start: {line: 1, column: 17}, @@ -5449,8 +5465,14 @@ test("import crypto, { decrypt, encrypt as enc } from \"crypto\"", { }, name: "decrypt" }, - name: null, - default: false + local: { + type: "Identifier", + loc: { + start: {line: 1, column: 17}, + end: {line: 1, column: 24} + }, + name: "decrypt" + } }, { type: "ImportSpecifier", @@ -5458,7 +5480,7 @@ test("import crypto, { decrypt, encrypt as enc } from \"crypto\"", { start: {line: 1, column: 26}, end: {line: 1, column: 40} }, - id: { + imported: { type: "Identifier", loc: { start: {line: 1, column: 26}, @@ -5466,15 +5488,14 @@ test("import crypto, { decrypt, encrypt as enc } from \"crypto\"", { }, name: "encrypt" }, - name: { + local: { type: "Identifier", loc: { start: {line: 1, column: 37}, end: {line: 1, column: 40} }, name: "enc" - }, - default: false + } } ], source: { @@ -5501,7 +5522,7 @@ test("import { null as nil } from \"bar\"", { type: "ImportDeclaration", specifiers: [{ type: "ImportSpecifier", - id: { + imported: { type: "Identifier", name: "null", loc: { @@ -5509,7 +5530,7 @@ test("import { null as nil } from \"bar\"", { end: {line: 1, column: 13} } }, - name: { + local: { type: "Identifier", name: "nil", loc: { @@ -5559,12 +5580,12 @@ test("import * as crypto from \"crypto\"", { end: {line: 1, column: 32} }, specifiers: [{ - type: "ImportBatchSpecifier", + type: "ImportNamespaceSpecifier", loc: { start: {line: 1, column: 7}, end: {line: 1, column: 18} }, - name: { + local: { type: "Identifier", loc: { start: {line: 1, column: 12}, @@ -13850,7 +13871,7 @@ testFail("function hello() {'use strict'; ({ i: 10, s(eval) { } }); }", "Definin testFail("function a() { \"use strict\"; ({ b(t, t) { } }); }", "Argument name clash in strict mode (1:37)", {ecmaVersion: 6}); -testFail("var super", "The keyword 'super' is reserved (1:4)", {ecmaVersion: 6, forbidReserved: true}); +testFail("var super", "The keyword 'super' is reserved (1:4)", {ecmaVersion: 6, allowReserved: false}); testFail("var default", "Unexpected token (1:4)", {ecmaVersion: 6}); @@ -14346,17 +14367,15 @@ test("import foo, * as bar from 'baz';", { type: "ImportDeclaration", specifiers: [ { - type: "ImportSpecifier", - id: { + type: "ImportDefaultSpecifier", + local: { type: "Identifier", name: "foo" - }, - name: null, - default: true + } }, { - type: "ImportBatchSpecifier", - name: { + type: "ImportNamespaceSpecifier", + local: { type: "Identifier", name: "bar" } @@ -14951,6 +14970,55 @@ test("class A { static() {} }", { locations: true }); +// https://github.com/marijnh/acorn/issues/213 + +test("for (const x of list) process(x);", { + type: "Program", + body: [{ + type: "ForOfStatement", + left: { + type: "VariableDeclaration", + declarations: [{ + type: "VariableDeclarator", + id: { + type: "Identifier", + name: "x", + range: [11, 12] + }, + init: null, + range: [11, 12] + }], + kind: "const", + range: [5, 12] + }, + right: { + type: "Identifier", + name: "list", + range: [16, 20] + }, + body: { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "Identifier", + name: "process", + range: [22, 29] + }, + arguments: [{ + type: "Identifier", + name: "x", + range: [30, 31] + }], + range: [22, 32] + }, + range: [22, 33] + }, + range: [0, 33] + }], + range: [0, 33] +}, {ecmaVersion: 6, ranges: true}); + test("class A { *static() {} }", { type: "Program", range: [0, 24], @@ -15195,6 +15263,109 @@ test("var _\\u{104A6} = 10;", { ] }, {ecmaVersion: 6}); +test("let [x,] = [1]", { + "start": 0, + "body": [ + { + "start": 0, + "declarations": [ + { + "start": 4, + "id": { + "start": 4, + "elements": [ + { + "start": 5, + "name": "x", + "type": "Identifier", + "end": 6 + } + ], + "type": "ArrayPattern", + "end": 8 + }, + "init": { + "start": 11, + "elements": [ + { + "start": 12, + "value": 1, + "raw": "1", + "type": "Literal", + "end": 13 + } + ], + "type": "ArrayExpression", + "end": 14 + }, + "type": "VariableDeclarator", + "end": 14 + } + ], + "kind": "let", + "type": "VariableDeclaration", + "end": 14 + } + ], + "type": "Program", + "end": 14 +}, {ecmaVersion: 6}); + +test("let {x} = y", { + "start": 0, + "body": [ + { + "start": 0, + "declarations": [ + { + "start": 4, + "id": { + "start": 4, + "properties": [ + { + "start": 5, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "start": 5, + "name": "x", + "type": "Identifier", + "end": 6 + }, + "kind": "init", + "value": { + "start": 5, + "name": "x", + "type": "Identifier", + "end": 6 + }, + "type": "Property", + "end": 6 + } + ], + "type": "ObjectPattern", + "end": 7 + }, + "init": { + "start": 10, + "name": "y", + "type": "Identifier", + "end": 11 + }, + "type": "VariableDeclarator", + "end": 11 + } + ], + "kind": "let", + "type": "VariableDeclaration", + "end": 11 + } + ], + "type": "Program", + "end": 11 +}, {ecmaVersion: 6}) + testFail("var _𖫵 = 11;", "Unexpected character '𖫵' (1:5)", {ecmaVersion: 6}); testFail("var 𫠞_ = 12;", "Unexpected character '𫠞' (1:4)", {ecmaVersion: 6}); testFail("var 𫠝_ = 10;", "Unexpected character '𫠝' (1:4)", {ecmaVersion: 5}); diff --git a/test/tests.js b/test/tests.js index 92f23f2ac4..f3d499dd11 100644 --- a/test/tests.js +++ b/test/tests.js @@ -28682,7 +28682,39 @@ test("const x = 14, y = 3, z = 1977", { testFail("const a;", "Unexpected token (1:7)", {ecmaVersion: 6}); -testFail("for(const x = 0;;);", "Unexpected token (1:4)", {ecmaVersion: 6}); +test("for(const x = 0;;);", { + type: "Program", + body: [{ + type: "ForStatement", + init: { + type: "VariableDeclaration", + declarations: [{ + type: "VariableDeclarator", + id: { + type: "Identifier", + name: "x", + range: [10, 11] + }, + init: { + type: "Literal", + value: 0, + range: [14, 15] + }, + range: [10, 15] + }], + kind: "const", + range: [4, 15] + }, + test: null, + update: null, + body: { + type: "EmptyStatement", + range: [18, 19] + }, + range: [0, 19] + }], + range: [0, 19] +}, {ecmaVersion: 6, ranges: true}); testFail("for(x of a);", "Unexpected token (1:6)"); @@ -28914,3 +28946,22 @@ test("function f() {} / 1 /", { } ] }); + +var semicolons = [] +testAssert("var x\nreturn\n10", function() { + var result = semicolons.join(" "); + semicolons.length = 0; + if (result != "5 12 15") + return "Unexpected result for onInsertedSemicolon: " + result; +}, {onInsertedSemicolon: function(pos) { semicolons.push(pos); }, + allowReturnOutsideFunction: true, + loose: false}) + +var trailingCommas = [] +testAssert("[1,2,] + {foo: 1,}", function() { + var result = trailingCommas.join(" "); + trailingCommas.length = 0; + if (result != "4 16") + return "Unexpected result for onTrailingComma: " + result; +}, {onTrailingComma: function(pos) { trailingCommas.push(pos); }, + loose: false}) diff --git a/util/walk.js b/util/walk.js deleted file mode 100644 index 9dcddaa3e9..0000000000 --- a/util/walk.js +++ /dev/null @@ -1,359 +0,0 @@ -// AST walker module for Mozilla Parser API compatible trees - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") return mod(exports); // CommonJS - if (typeof define == "function" && define.amd) return define(["exports"], mod); // AMD - mod((this.acorn || (this.acorn = {})).walk = {}); // Plain browser env -})(function(exports) { - "use strict"; - - // A simple walk is one where you simply specify callbacks to be - // called on specific nodes. The last two arguments are optional. A - // simple use would be - // - // walk.simple(myTree, { - // Expression: function(node) { ... } - // }); - // - // to do something with all expressions. All Parser API node types - // can be used to identify node types, as well as Expression, - // Statement, and ScopeBody, which denote categories of nodes. - // - // The base argument can be used to pass a custom (recursive) - // walker, and state can be used to give this walked an initial - // state. - exports.simple = function(node, visitors, base, state) { - if (!base) base = exports.base; - function c(node, st, override) { - var type = override || node.type, found = visitors[type]; - base[type](node, st, c); - if (found) found(node, st); - } - c(node, state); - }; - - // An ancestor walk builds up an array of ancestor nodes (including - // the current node) and passes them to the callback as the state parameter. - exports.ancestor = function(node, visitors, base, state) { - if (!base) base = exports.base; - if (!state) state = []; - function c(node, st, override) { - var type = override || node.type, found = visitors[type]; - if (node != st[st.length - 1]) { - st = st.slice(); - st.push(node); - } - base[type](node, st, c); - if (found) found(node, st); - } - c(node, state); - }; - - // A recursive walk is one where your functions override the default - // walkers. They can modify and replace the state parameter that's - // threaded through the walk, and can opt how and whether to walk - // their child nodes (by calling their third argument on these - // nodes). - exports.recursive = function(node, state, funcs, base) { - var visitor = funcs ? exports.make(funcs, base) : base; - function c(node, st, override) { - visitor[override || node.type](node, st, c); - } - c(node, state); - }; - - function makeTest(test) { - if (typeof test == "string") - return function(type) { return type == test; }; - else if (!test) - return function() { return true; }; - else - return test; - } - - function Found(node, state) { this.node = node; this.state = state; } - - // Find a node with a given start, end, and type (all are optional, - // null can be used as wildcard). Returns a {node, state} object, or - // undefined when it doesn't find a matching node. - exports.findNodeAt = function(node, start, end, test, base, state) { - test = makeTest(test); - try { - if (!base) base = exports.base; - var c = function(node, st, override) { - var type = override || node.type; - if ((start == null || node.start <= start) && - (end == null || node.end >= end)) - base[type](node, st, c); - if (test(type, node) && - (start == null || node.start == start) && - (end == null || node.end == end)) - throw new Found(node, st); - }; - c(node, state); - } catch (e) { - if (e instanceof Found) return e; - throw e; - } - }; - - // Find the innermost node of a given type that contains the given - // position. Interface similar to findNodeAt. - exports.findNodeAround = function(node, pos, test, base, state) { - test = makeTest(test); - try { - if (!base) base = exports.base; - var c = function(node, st, override) { - var type = override || node.type; - if (node.start > pos || node.end < pos) return; - base[type](node, st, c); - if (test(type, node)) throw new Found(node, st); - }; - c(node, state); - } catch (e) { - if (e instanceof Found) return e; - throw e; - } - }; - - // Find the outermost matching node after a given position. - exports.findNodeAfter = function(node, pos, test, base, state) { - test = makeTest(test); - try { - if (!base) base = exports.base; - var c = function(node, st, override) { - if (node.end < pos) return; - var type = override || node.type; - if (node.start >= pos && test(type, node)) throw new Found(node, st); - base[type](node, st, c); - }; - c(node, state); - } catch (e) { - if (e instanceof Found) return e; - throw e; - } - }; - - // Find the outermost matching node before a given position. - exports.findNodeBefore = function(node, pos, test, base, state) { - test = makeTest(test); - if (!base) base = exports.base; - var max; - var c = function(node, st, override) { - if (node.start > pos) return; - var type = override || node.type; - if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node)) - max = new Found(node, st); - base[type](node, st, c); - }; - c(node, state); - return max; - }; - - // Used to create a custom walker. Will fill in all missing node - // type properties with the defaults. - exports.make = function(funcs, base) { - if (!base) base = exports.base; - var visitor = {}; - for (var type in base) visitor[type] = base[type]; - for (var type in funcs) visitor[type] = funcs[type]; - return visitor; - }; - - function skipThrough(node, st, c) { c(node, st); } - function ignore(_node, _st, _c) {} - - // Node walkers. - - var base = exports.base = {}; - base.Program = base.BlockStatement = function(node, st, c) { - for (var i = 0; i < node.body.length; ++i) - c(node.body[i], st, "Statement"); - }; - base.Statement = skipThrough; - base.EmptyStatement = ignore; - base.ExpressionStatement = base.ParenthesizedExpression = function(node, st, c) { - c(node.expression, st, "Expression"); - }; - base.IfStatement = function(node, st, c) { - c(node.test, st, "Expression"); - c(node.consequent, st, "Statement"); - if (node.alternate) c(node.alternate, st, "Statement"); - }; - base.LabeledStatement = function(node, st, c) { - c(node.body, st, "Statement"); - }; - base.BreakStatement = base.ContinueStatement = ignore; - base.WithStatement = function(node, st, c) { - c(node.object, st, "Expression"); - c(node.body, st, "Statement"); - }; - base.SwitchStatement = function(node, st, c) { - c(node.discriminant, st, "Expression"); - for (var i = 0; i < node.cases.length; ++i) { - var cs = node.cases[i]; - if (cs.test) c(cs.test, st, "Expression"); - for (var j = 0; j < cs.consequent.length; ++j) - c(cs.consequent[j], st, "Statement"); - } - }; - base.ReturnStatement = base.YieldExpression = function(node, st, c) { - if (node.argument) c(node.argument, st, "Expression"); - }; - base.ThrowStatement = base.SpreadElement = base.RestElement = function(node, st, c) { - c(node.argument, st, "Expression"); - }; - base.TryStatement = function(node, st, c) { - c(node.block, st, "Statement"); - if (node.handler) c(node.handler.body, st, "ScopeBody"); - if (node.finalizer) c(node.finalizer, st, "Statement"); - }; - base.WhileStatement = function(node, st, c) { - c(node.test, st, "Expression"); - c(node.body, st, "Statement"); - }; - base.DoWhileStatement = base.WhileStatement; - base.ForStatement = function(node, st, c) { - if (node.init) c(node.init, st, "ForInit"); - if (node.test) c(node.test, st, "Expression"); - if (node.update) c(node.update, st, "Expression"); - c(node.body, st, "Statement"); - }; - base.ForInStatement = base.ForOfStatement = function(node, st, c) { - c(node.left, st, "ForInit"); - c(node.right, st, "Expression"); - c(node.body, st, "Statement"); - }; - base.ForInit = function(node, st, c) { - if (node.type == "VariableDeclaration") c(node, st); - else c(node, st, "Expression"); - }; - base.DebuggerStatement = ignore; - - base.FunctionDeclaration = function(node, st, c) { - c(node, st, "Function"); - }; - base.VariableDeclaration = function(node, st, c) { - for (var i = 0; i < node.declarations.length; ++i) { - var decl = node.declarations[i]; - if (decl.init) c(decl.init, st, "Expression"); - } - }; - - base.Function = function(node, st, c) { - c(node.body, st, "ScopeBody"); - }; - base.ScopeBody = function(node, st, c) { - c(node, st, "Statement"); - }; - - base.Expression = skipThrough; - base.ThisExpression = ignore; - base.ArrayExpression = base.ArrayPattern = function(node, st, c) { - for (var i = 0; i < node.elements.length; ++i) { - var elt = node.elements[i]; - if (elt) c(elt, st, "Expression"); - } - }; - base.ObjectExpression = base.ObjectPattern = function(node, st, c) { - for (var i = 0; i < node.properties.length; ++i) - c(node.properties[i], st); - }; - base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration; - base.SequenceExpression = base.TemplateLiteral = function(node, st, c) { - for (var i = 0; i < node.expressions.length; ++i) - c(node.expressions[i], st, "Expression"); - }; - base.UnaryExpression = base.UpdateExpression = function(node, st, c) { - c(node.argument, st, "Expression"); - }; - base.BinaryExpression = base.AssignmentExpression = base.AssignmentPattern = base.LogicalExpression = function(node, st, c) { - c(node.left, st, "Expression"); - c(node.right, st, "Expression"); - }; - base.ConditionalExpression = function(node, st, c) { - c(node.test, st, "Expression"); - c(node.consequent, st, "Expression"); - c(node.alternate, st, "Expression"); - }; - base.NewExpression = base.CallExpression = function(node, st, c) { - c(node.callee, st, "Expression"); - if (node.arguments) for (var i = 0; i < node.arguments.length; ++i) - c(node.arguments[i], st, "Expression"); - }; - base.MemberExpression = function(node, st, c) { - c(node.object, st, "Expression"); - if (node.computed) c(node.property, st, "Expression"); - }; - base.ExportDeclaration = function (node, st, c) { - c(node.declaration, st); - }; - base.ImportDeclaration = function (node, st, c) { - node.specifiers.forEach(function (specifier) { - c(specifier, st); - }); - }; - base.ImportSpecifier = base.ImportBatchSpecifier = base.Identifier = base.Literal = ignore; - - base.TaggedTemplateExpression = function(node, st, c) { - c(node.tag, st, "Expression"); - c(node.quasi, st); - }; - base.ClassDeclaration = base.ClassExpression = function(node, st, c) { - if (node.superClass) c(node.superClass, st, "Expression"); - for (var i = 0; i < node.body.body.length; i++) - c(node.body.body[i], st); - }; - base.MethodDefinition = base.Property = function(node, st, c) { - if (node.computed) c(node.key, st, "Expression"); - c(node.value, st, "Expression"); - }; - base.ComprehensionExpression = function(node, st, c) { - for (var i = 0; i < node.blocks.length; i++) - c(node.blocks[i].right, st, "Expression"); - c(node.body, st, "Expression"); - }; - - // NOTE: the stuff below is deprecated, and will be removed when 1.0 is released - - // A custom walker that keeps track of the scope chain and the - // variables defined in it. - function makeScope(prev, isCatch) { - return {vars: Object.create(null), prev: prev, isCatch: isCatch}; - } - function normalScope(scope) { - while (scope.isCatch) scope = scope.prev; - return scope; - } - exports.scopeVisitor = exports.make({ - Function: function(node, scope, c) { - var inner = makeScope(scope); - for (var i = 0; i < node.params.length; ++i) - inner.vars[node.params[i].name] = {type: "argument", node: node.params[i]}; - if (node.id) { - var decl = node.type == "FunctionDeclaration"; - (decl ? normalScope(scope) : inner).vars[node.id.name] = - {type: decl ? "function" : "function name", node: node.id}; - } - c(node.body, inner, "ScopeBody"); - }, - TryStatement: function(node, scope, c) { - c(node.block, scope, "Statement"); - if (node.handler) { - var inner = makeScope(scope, true); - inner.vars[node.handler.param.name] = {type: "catch clause", node: node.handler.param}; - c(node.handler.body, inner, "ScopeBody"); - } - if (node.finalizer) c(node.finalizer, scope, "Statement"); - }, - VariableDeclaration: function(node, scope, c) { - var target = normalScope(scope); - for (var i = 0; i < node.declarations.length; ++i) { - var decl = node.declarations[i]; - target.vars[decl.id.name] = {type: "var", node: decl.id}; - if (decl.init) c(decl.init, scope, "Expression"); - } - } - }); - -});