Support rest parameters
http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters The final parameter to a function is a rest parameter if it is prefixed by "...". FunctionExpression and FunctionDeclaration nodes have a new "rest" property that is null if there is no rest parameter, or contains an Identifer for the parameter. https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API#Functions Implemented by adding a new token, `_ellipsis`, which consists of three dots. Modified the body of parseFunction to allow a single rest parameter at the end of an argument list. Both the token and the rest parameter require `options.ecmaVersion` >= 6, otherwise three dots are tokenized as three dots.
This commit is contained in:
parent
2de16b8cb0
commit
5552e866f9
37
acorn.js
37
acorn.js
@ -308,7 +308,7 @@
|
||||
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};
|
||||
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
|
||||
@ -345,8 +345,8 @@
|
||||
|
||||
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
|
||||
@ -582,8 +582,14 @@
|
||||
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() { // '/'
|
||||
@ -659,7 +665,7 @@
|
||||
function getTokenFromCode(code) {
|
||||
switch(code) {
|
||||
// The interpretation of a dot depends on whether it is followed
|
||||
// by a digit.
|
||||
// by a digit or another two dots.
|
||||
case 46: // '.'
|
||||
return readToken_dot();
|
||||
|
||||
@ -1706,11 +1712,22 @@
|
||||
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`
|
||||
|
||||
323
test/tests.js
323
test/tests.js
@ -23572,6 +23572,171 @@ test("function hello(a, b) { sayHi(); }", {
|
||||
}
|
||||
});
|
||||
|
||||
test("function hello(...rest) { }", {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "FunctionDeclaration",
|
||||
id: {
|
||||
type: "Identifier",
|
||||
name: "hello",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 9
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
params: [],
|
||||
rest: {
|
||||
type: "Identifier",
|
||||
name: "rest",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 18
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 22
|
||||
}
|
||||
}
|
||||
},
|
||||
body: {
|
||||
type: "BlockStatement",
|
||||
body: [],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 24
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 27
|
||||
}
|
||||
}
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 27
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 27
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ecmaVersion: 6,
|
||||
locations: true
|
||||
});
|
||||
|
||||
test("function hello(a, ...rest) { }", {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "FunctionDeclaration",
|
||||
id: {
|
||||
type: "Identifier",
|
||||
name: "hello",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 9
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
params: [
|
||||
{
|
||||
type: "Identifier",
|
||||
name: "a",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 15
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 16
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
rest: {
|
||||
type: "Identifier",
|
||||
name: "rest",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 21
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 25
|
||||
}
|
||||
}
|
||||
},
|
||||
body: {
|
||||
type: "BlockStatement",
|
||||
body: [],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 27
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 30
|
||||
}
|
||||
}
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 30
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 30
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ecmaVersion: 6,
|
||||
locations: true
|
||||
});
|
||||
|
||||
test("var hi = function() { sayHi() };", {
|
||||
type: "Program",
|
||||
body: [
|
||||
@ -23702,6 +23867,153 @@ test("var hi = function() { sayHi() };", {
|
||||
}
|
||||
});
|
||||
|
||||
test("var hi = function (...r) { sayHi() };", {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "VariableDeclaration",
|
||||
declarations: [
|
||||
{
|
||||
type: "VariableDeclarator",
|
||||
id: {
|
||||
type: "Identifier",
|
||||
name: "hi",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 4
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 6
|
||||
}
|
||||
}
|
||||
},
|
||||
init: {
|
||||
type: "FunctionExpression",
|
||||
id: null,
|
||||
params: [],
|
||||
rest: {
|
||||
type: "Identifier",
|
||||
name: "r",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 22
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 23
|
||||
}
|
||||
}
|
||||
},
|
||||
body: {
|
||||
type: "BlockStatement",
|
||||
body: [
|
||||
{
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
type: "CallExpression",
|
||||
callee: {
|
||||
type: "Identifier",
|
||||
name: "sayHi",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 27
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 32
|
||||
}
|
||||
}
|
||||
},
|
||||
arguments: [],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 27
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 34
|
||||
}
|
||||
}
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 27
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 34
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 25
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 36
|
||||
}
|
||||
}
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 9
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 36
|
||||
}
|
||||
}
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 4
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 36
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
kind: "var",
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 37
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 37
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ecmaVersion: 6,
|
||||
locations: true
|
||||
});
|
||||
|
||||
test("var hi = function eval() { };", {
|
||||
type: "Program",
|
||||
body: [
|
||||
@ -26551,6 +26863,17 @@ testFail("({ get i() { }, get i() { } })",
|
||||
testFail("({ set i(x) { }, set i(x) { } })",
|
||||
"Redefinition of property (1:21)");
|
||||
|
||||
testFail("function t(...) { }",
|
||||
"Unexpected token (1:11)");
|
||||
|
||||
testFail("function t(...) { }",
|
||||
"Unexpected token (1:14)",
|
||||
{ ecmaVersion: 6 });
|
||||
|
||||
testFail("function t(...rest, b) { }",
|
||||
"Unexpected token (1:18)",
|
||||
{ ecmaVersion: 6 });
|
||||
|
||||
testFail("function t(if) { }",
|
||||
"Unexpected token (1:11)");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user