Index: lib/src/js/builder.dart |
diff --git a/lib/src/js/builder.dart b/lib/src/js/builder.dart |
index 91fa992d28b9050fdf4cdf325915ebe02e9db7d6..b2bdfbca5e04253157fd63e2428bdc0df8215a05 100644 |
--- a/lib/src/js/builder.dart |
+++ b/lib/src/js/builder.dart |
@@ -450,12 +450,16 @@ class MiniJsParser { |
static const COLON = 14; |
static const SEMICOLON = 15; |
static const ARROW = 16; |
- static const HASH = 17; |
- static const WHITESPACE = 18; |
- static const OTHER = 19; |
+ static const ELLIPSIS = 17; |
+ static const HASH = 18; |
+ static const WHITESPACE = 19; |
+ static const OTHER = 20; |
// Make sure that ]] is two symbols. |
- bool singleCharCategory(int category) => category >= DOT; |
+ // TODO(jmesserly): => and ... are not single char tokens, should we change |
+ // their numbers? It shouldn't matter because this is only called on values |
+ // from the [CATEGORIES] table. |
+ bool singleCharCategory(int category) => category > DOT; |
static String categoryToString(int cat) { |
switch (cat) { |
@@ -477,6 +481,7 @@ class MiniJsParser { |
case COLON: return "COLON"; |
case SEMICOLON: return "SEMICOLON"; |
case ARROW: return "ARROW"; |
+ case ELLIPSIS: return "ELLIPSIS"; |
case HASH: return "HASH"; |
case WHITESPACE: return "WHITESPACE"; |
case OTHER: return "OTHER"; |
@@ -528,6 +533,7 @@ class MiniJsParser { |
.toSet(); |
static final ARROW_TOKEN = '=>'; |
+ static final ELLIPSIS_TOKEN = '...'; |
static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS = |
['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet(); |
@@ -642,6 +648,12 @@ class MiniJsParser { |
double.parse(lastToken, (_) { |
error("Unparseable number"); |
}); |
+ } else if (cat == DOT && lastToken.length > 1) { |
+ if (lastToken == ELLIPSIS_TOKEN) { |
+ lastCategory = ELLIPSIS; |
+ } else { |
+ error("Unknown operator"); |
+ } |
} else if (cat == SYMBOL) { |
if (lastToken == ARROW_TOKEN) { |
lastCategory = ARROW; |
@@ -792,26 +804,42 @@ class MiniJsParser { |
Expression parseExpressionOrArrowFunction() { |
if (acceptCategory(RPAREN)) { |
expectCategory(ARROW); |
- return parseArrowFunctionBody(<Identifier>[]); |
+ return parseArrowFunctionBody(<Parameter>[]); |
+ } |
+ if (acceptCategory(ELLIPSIS)) { |
+ var params = <Parameter>[new RestParameter(parseParameter())]; |
+ expectCategory(RPAREN); |
+ expectCategory(ARROW); |
+ return parseArrowFunctionBody(params); |
+ } |
+ Expression expression = parseAssignment(); |
+ while (acceptCategory(COMMA)) { |
+ if (acceptCategory(ELLIPSIS)) { |
+ var params = <Parameter>[]; |
+ _expressionToParameterList(expression, params); |
+ params.add(new RestParameter(parseParameter())); |
+ expectCategory(RPAREN); |
+ expectCategory(ARROW); |
+ return parseArrowFunctionBody(params); |
+ } |
+ Expression right = parseAssignment(); |
+ expression = new Binary(',', expression, right); |
} |
- Expression expression = parseExpression(); |
expectCategory(RPAREN); |
if (acceptCategory(ARROW)) { |
- var params = <Identifier>[]; |
+ var params = <Parameter>[]; |
_expressionToParameterList(expression, params); |
return parseArrowFunctionBody(params); |
} |
return expression; |
- |
} |
/** |
* Converts a parenthesized expression into a list of parameters, issuing an |
* error if the conversion fails. |
*/ |
- void _expressionToParameterList(Expression node, List<Identifier> params) { |
+ void _expressionToParameterList(Expression node, List<Parameter> params) { |
if (node is Identifier) { |
- // TODO(jmesserly): support default/rest parameters |
params.add(node); |
} else if (node is Binary && node.op == ',') { |
// TODO(jmesserly): this will allow illegal parens, such as |
@@ -827,7 +855,7 @@ class MiniJsParser { |
} |
} |
- Expression parseArrowFunctionBody(List<Identifier> params) { |
+ Expression parseArrowFunctionBody(List<Parameter> params) { |
Node body; |
if (acceptCategory(LBRACE)) { |
body = parseBlock(); |
@@ -848,25 +876,22 @@ class MiniJsParser { |
} |
Expression parseFun() { |
- List<Identifier> params = <Identifier>[]; |
+ List<Parameter> params = <Parameter>[]; |
expectCategory(LPAREN); |
if (!acceptCategory(RPAREN)) { |
for (;;) { |
- if (acceptCategory(HASH)) { |
- var nameOrPosition = parseHash(); |
- InterpolatedParameter parameter = |
- new InterpolatedParameter(nameOrPosition); |
- interpolatedValues.add(parameter); |
- params.add(parameter); |
- } else { |
- String argumentName = lastToken; |
- expectCategory(ALPHA); |
- params.add(new Identifier(argumentName)); |
+ if (acceptCategory(ELLIPSIS)) { |
+ params.add(new RestParameter(parseParameter())); |
+ expectCategory(RPAREN); |
+ break; |
+ } |
+ |
+ params.add(parseParameter()); |
+ if (!acceptCategory(COMMA)) { |
+ expectCategory(RPAREN); |
+ break; |
} |
- if (acceptCategory(COMMA)) continue; |
- expectCategory(RPAREN); |
- break; |
} |
} |
AsyncModifier asyncModifier; |
@@ -887,6 +912,21 @@ class MiniJsParser { |
return new Fun(params, block, asyncModifier: asyncModifier); |
} |
+ /** Parse parameter name or interpolated parameter. */ |
+ Identifier parseParameter() { |
+ if (acceptCategory(HASH)) { |
+ var nameOrPosition = parseHash(); |
+ var parameter = new InterpolatedParameter(nameOrPosition); |
+ interpolatedValues.add(parameter); |
+ return parameter; |
+ } else { |
+ // TODO(jmesserly): validate this is not a keyword |
+ String argumentName = lastToken; |
+ expectCategory(ALPHA); |
+ return new Identifier(argumentName); |
+ } |
+ } |
+ |
Expression parseObjectInitializer() { |
List<Property> properties = <Property>[]; |
for (;;) { |
@@ -928,8 +968,12 @@ class MiniJsParser { |
final arguments = <Expression>[]; |
if (!acceptCategory(RPAREN)) { |
while (true) { |
- Expression argument = parseAssignment(); |
- arguments.add(argument); |
+ if (acceptCategory(ELLIPSIS)) { |
+ arguments.add(new Spread(parseAssignment())); |
+ expectCategory(RPAREN); |
+ break; |
+ } |
+ arguments.add(parseAssignment()); |
if (acceptCategory(RPAREN)) break; |
expectCategory(COMMA); |
} |