diff --git a/bin/acorn b/bin/acorn index 506cdc4365..f70fe21ee6 100755 --- a/bin/acorn +++ b/bin/acorn @@ -4,28 +4,42 @@ var path = require("path"); var fs = require("fs"); var acorn = require("../acorn.js"); -var infile, parsed, options = {}, silent = false, compact = false; +var infile, infilecount = 0; +var options = {}, silent = false, compact = false; +var parsed; function help(status) { - console.log("usage: " + path.basename(process.argv[1]) + " infile [--ecma3|--ecma5] [--strictSemicolons]"); - console.log(" [--locations] [--compact] [--silent] [--help]"); + // we want to print to stderr, not stdout, on errors. + var print = (status == 0) ? console.out : console.err; + print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5] [--strictSemicolons]"); + print(" [--locations] [--compact] [--silent] [--help] [--] infile"); process.exit(status); } for (var i = 2; i < process.argv.length; ++i) { var arg = process.argv[i]; - if (arg == "--ecma3") options.ecmaVersion = 3; + if (arg[0] != "-") { + infile = arg; + ++infilecount; + continue; + } else if (arg == "--") { + if (i < process.argv.length - 2) help(1); // we have too many remaining `infile`s + infile = process.argv[i + 1]; // we want the *next* argument, not the current one + ++infilecount; + break; + } + else if (arg == "--ecma3") options.ecmaVersion = 3; else if (arg == "--ecma5") options.ecmaVersion = 5; 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[0] == "-") help(1); - else infile = arg; + else help(1); // we already took care of all arguments without a starting dash } -if (!infile) help(1); +// test against counter: we want exactly 1 file. Any more or less should error. +if (infilecount !== 1) help(1); try { var code = fs.readFileSync(infile, "utf8"); diff --git a/index.html b/index.html index 0e2d6e6361..f336e3c3af 100644 --- a/index.html +++ b/index.html @@ -188,7 +188,7 @@ we assign a variable name to it for quick comparing.

"delete": {keyword: "delete", prefix: true, beforeExpr: true}};

Punctuation token types. Again, the type property is purely for debugging.

  var _bracketL = {type: "[", beforeExpr: true}, _bracketR = {type: "]"}, _braceL = {type: "{", beforeExpr: true};
   var _braceR = {type: "}"}, _parenL = {type: "(", beforeExpr: true}, _parenR = {type: ")"};
   var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true};
-  var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true};

Operators. These carry several kinds of properties to help the + var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _ellipsis = {type: "..."}, _question = {type: "?", beforeExpr: true};

Operators. These carry several kinds of properties to help the parser use them properly (the presence of these properties is what categorizes them as operators).

@@ -217,8 +217,8 @@ in AssignmentExpression nodes.

var _multiplyModulo = {binop: 10, beforeExpr: true};

Provide access to the token types for external users of the tokenizer.

  exports.tokTypes = {bracketL: _bracketL, bracketR: _bracketR, braceL: _braceL, braceR: _braceR,
                       parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon,
-                      dot: _dot, question: _question, slash: _slash, eq: _eq, name: _name, eof: _eof,
-                      num: _num, regexp: _regexp, string: _string};
+                      dot: _dot, ellipsis: _ellipsis, question: _question, slash: _slash, eq: _eq,
+                      name: _name, eof: _eof, num: _num, regexp: _regexp, string: _string};
   for (var kw in keywordTypes) exports.tokTypes["_" + kw] = keywordTypes[kw];

This is a trick taken from Esprima. It turns out that, on non-Chrome browsers, to check whether a string is in a set, a predicate containing a big ugly switch statement is faster than @@ -376,8 +376,14 @@ into it.

tokRegexpAllowed trick does not work. See parseStatement.

  function readToken_dot() {
     var next = input.charCodeAt(tokPos + 1);
     if (next >= 48 && next <= 57) return readNumber(true);
-    ++tokPos;
-    return finishToken(_dot);
+    var next2 = input.charCodeAt(tokPos + 2);
+    if (options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.'
+      tokPos += 3;
+      return finishToken(_ellipsis);
+    } else {
+      ++tokPos;
+      return finishToken(_dot);
+    }
   }
 
   function readToken_slash() { // '/'
@@ -448,7 +454,7 @@ into it.

function getTokenFromCode(code) { switch(code) {

The interpretation of a dot depends on whether it is followed -by a digit.

    case 46: // '.'
+by a digit or another two dots.

    case 46: // '.'
       return readToken_dot();

Punctuation tokens.

    case 40: ++tokPos; return finishToken(_parenL);
     case 41: ++tokPos; return finishToken(_parenR);
     case 59: ++tokPos; return finishToken(_semi);
@@ -1280,11 +1286,22 @@ init properties are also not allowed to be repeated.

else if (isStatement) unexpected(); else node.id = null; node.params = []; - var first = true; + node.rest = null; expect(_parenL); - while (!eat(_parenR)) { - if (!first) expect(_comma); else first = false; - node.params.push(parseIdent()); + for (;;) { + if (eat(_parenR)) { + break; + } else if (options.ecmaVersion >= 6 && eat(_ellipsis)) { + node.rest = parseIdent(); + expect(_parenR); + break; + } else { + node.params.push(parseIdent()); + if (!eat(_comma)) { + expect(_parenR); + break; + } + } }

Start a new scope with regard to labels and the inFunction flag (restore them to their old value afterwards).

    var oldInFunc = inFunction, oldLabels = labels;
     inFunction = true; labels = [];