Skip to content

Commit 5d8c5f3

Browse files
authored
Support comma after last argument for function declarations (#3910)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
1 parent e64fc9a commit 5d8c5f3

File tree

5 files changed

+142
-62
lines changed

5 files changed

+142
-62
lines changed

jerry-core/parser/js/js-parser.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,11 +1802,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
18021802
while (true)
18031803
{
18041804
#if ENABLED (JERRY_ESNEXT)
1805-
if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM)
1806-
{
1807-
parser_raise_error (context_p, PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER);
1808-
}
1809-
else if (context_p->token.type == LEXER_THREE_DOTS)
1805+
if (context_p->token.type == LEXER_THREE_DOTS)
18101806
{
18111807
if (context_p->status_flags & PARSER_IS_PROPERTY_SETTER)
18121808
{
@@ -1974,18 +1970,31 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
19741970

19751971
if (context_p->token.type != LEXER_COMMA)
19761972
{
1973+
if (context_p->token.type != end_type)
1974+
{
1975+
parser_error_t error = ((end_type == LEXER_RIGHT_PAREN) ? PARSER_ERR_RIGHT_PAREN_EXPECTED
1976+
: PARSER_ERR_IDENTIFIER_EXPECTED);
1977+
1978+
parser_raise_error (context_p, error);
1979+
}
19771980
break;
19781981
}
19791982

1980-
lexer_next_token (context_p);
1981-
}
1983+
#if ENABLED (JERRY_ESNEXT)
1984+
if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM)
1985+
{
1986+
parser_raise_error (context_p, PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER);
1987+
}
1988+
#endif /* ENABLED (JERRY_ESNEXT) */
19821989

1983-
if (context_p->token.type != end_type)
1984-
{
1985-
parser_error_t error = ((end_type == LEXER_RIGHT_PAREN) ? PARSER_ERR_RIGHT_PAREN_EXPECTED
1986-
: PARSER_ERR_IDENTIFIER_EXPECTED);
1990+
lexer_next_token (context_p);
19871991

1988-
parser_raise_error (context_p, error);
1992+
#if ENABLED (JERRY_ESNEXT)
1993+
if (context_p->token.type == end_type)
1994+
{
1995+
break;
1996+
}
1997+
#endif /* ENABLED (JERRY_ESNEXT) */
19891998
}
19901999

19912000
scanner_revert_active (context_p);

jerry-core/parser/js/js-scanner-ops.c

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -182,65 +182,78 @@ scanner_check_arrow_arg (parser_context_t *context_p, /**< context */
182182
lexer_next_token (context_p);
183183
}
184184

185-
if (context_p->token.type == LEXER_LITERAL
186-
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
185+
switch (context_p->token.type)
187186
{
188-
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
189-
190-
if (lexer_check_arrow (context_p))
187+
case LEXER_RIGHT_PAREN:
191188
{
192-
process_arrow = true;
189+
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
190+
return;
193191
}
194-
else
192+
case LEXER_LITERAL:
195193
{
194+
if (context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
195+
{
196+
break;
197+
}
198+
199+
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
200+
201+
if (lexer_check_arrow (context_p))
202+
{
203+
process_arrow = true;
204+
break;
205+
}
206+
196207
lexer_lit_location_t *argument_literal_p = scanner_append_argument (context_p, scanner_context_p);
197208

198209
scanner_detect_eval_call (context_p, scanner_context_p);
199210

200211
lexer_next_token (context_p);
201212

202-
if (context_p->token.type == LEXER_ASSIGN)
213+
if (context_p->token.type == LEXER_COMMA || context_p->token.type == LEXER_RIGHT_PAREN)
203214
{
204-
if (argument_literal_p->type & SCANNER_LITERAL_IS_USED)
205-
{
206-
JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE);
207-
return;
208-
}
215+
return;
216+
}
209217

210-
scanner_binding_literal_t binding_literal;
211-
binding_literal.literal_p = argument_literal_p;
218+
if (context_p->token.type != LEXER_ASSIGN)
219+
{
220+
break;
221+
}
212222

213-
parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t));
214-
parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT);
223+
if (argument_literal_p->type & SCANNER_LITERAL_IS_USED)
224+
{
225+
JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE);
215226
return;
216227
}
217228

218-
if (context_p->token.type == LEXER_COMMA || context_p->token.type == LEXER_RIGHT_PAREN)
229+
scanner_binding_literal_t binding_literal;
230+
binding_literal.literal_p = argument_literal_p;
231+
232+
parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t));
233+
parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT);
234+
return;
235+
}
236+
case LEXER_LEFT_SQUARE:
237+
case LEXER_LEFT_BRACE:
238+
{
239+
scanner_append_hole (context_p, scanner_context_p);
240+
scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_ARROW_ARG, false);
241+
242+
if (context_p->token.type == LEXER_LEFT_BRACE)
219243
{
244+
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
245+
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
220246
return;
221247
}
222-
}
223-
}
224-
else if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE)
225-
{
226-
scanner_append_hole (context_p, scanner_context_p);
227-
scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_ARROW_ARG, false);
228248

229-
if (context_p->token.type == LEXER_LEFT_BRACE)
230-
{
231-
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
232-
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
249+
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
250+
scanner_context_p->mode = SCAN_MODE_BINDING;
251+
lexer_next_token (context_p);
233252
return;
234253
}
235-
236-
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
237-
scanner_context_p->mode = SCAN_MODE_BINDING;
238-
lexer_next_token (context_p);
239-
return;
240254
}
241255

242256
scanner_pop_literal_pool (context_p, scanner_context_p);
243-
244257
parser_stack_pop_uint8 (context_p);
245258

246259
if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC)

jerry-core/parser/js/js-scanner.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,20 +2738,15 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
27382738
}
27392739
case SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS:
27402740
{
2741-
#endif /* ENABLED (JERRY_ESNEXT) */
27422741
if (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS)
27432742
{
2744-
#if ENABLED (JERRY_ESNEXT)
27452743
lexer_lit_location_t *argument_literal_p;
2746-
#endif /* ENABLED (JERRY_ESNEXT) */
27472744

2748-
while (true)
2745+
do
27492746
{
2750-
#if ENABLED (JERRY_ESNEXT)
27512747
if (context_p->token.type == LEXER_THREE_DOTS)
27522748
{
27532749
scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED;
2754-
27552750
lexer_next_token (context_p);
27562751
}
27572752

@@ -2760,30 +2755,25 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
27602755
argument_literal_p = NULL;
27612756
break;
27622757
}
2763-
#endif /* ENABLED (JERRY_ESNEXT) */
27642758

27652759
if (context_p->token.type != LEXER_LITERAL
27662760
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
27672761
{
27682762
scanner_raise_error (context_p);
27692763
}
27702764

2771-
#if ENABLED (JERRY_ESNEXT)
27722765
argument_literal_p = scanner_append_argument (context_p, &scanner_context);
2773-
#else /* !ENABLED (JERRY_ESNEXT) */
2774-
scanner_append_argument (context_p, &scanner_context);
2775-
#endif /* ENABLED (JERRY_ESNEXT) */
2776-
27772766
lexer_next_token (context_p);
27782767

27792768
if (context_p->token.type != LEXER_COMMA)
27802769
{
27812770
break;
27822771
}
2772+
27832773
lexer_next_token (context_p);
27842774
}
2775+
while (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS);
27852776

2786-
#if ENABLED (JERRY_ESNEXT)
27872777
if (argument_literal_p == NULL)
27882778
{
27892779
scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED;
@@ -2824,8 +2814,30 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
28242814
parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT);
28252815
break;
28262816
}
2827-
#endif /* ENABLED (JERRY_ESNEXT) */
28282817
}
2818+
#else /* !ENABLED (JERRY_ESNEXT) */
2819+
if (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS)
2820+
{
2821+
while (true)
2822+
{
2823+
if (context_p->token.type != LEXER_LITERAL
2824+
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
2825+
{
2826+
scanner_raise_error (context_p);
2827+
}
2828+
2829+
scanner_append_argument (context_p, &scanner_context);
2830+
lexer_next_token (context_p);
2831+
2832+
if (context_p->token.type != LEXER_COMMA)
2833+
{
2834+
break;
2835+
}
2836+
2837+
lexer_next_token (context_p);
2838+
}
2839+
}
2840+
#endif /* ENABLED (JERRY_ESNEXT) */
28292841

28302842
if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_SCRIPT_FUNCTION)
28312843
{

tests/jerry/es.next/arrow-function.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,8 @@ must_throw ("var x => x;");
138138
must_throw ("(()) => 0");
139139
must_throw ("((x)) => 0");
140140
must_throw ("(((x))) => 0");
141-
must_throw ("(x,) => 0");
142141
must_throw ("(x==6) => 0");
143142
must_throw ("(x y) => 0");
144-
must_throw ("(x,y,) => 0");
145143
must_throw ("x\n => 0");
146144
must_throw ("this => 0");
147145
must_throw ("(true) => 0");
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
function check_syntax_error (code)
16+
{
17+
try {
18+
eval (code)
19+
assert (false)
20+
} catch (e) {
21+
assert (e instanceof SyntaxError)
22+
}
23+
}
24+
25+
check_syntax_error ("function f(,) {}")
26+
check_syntax_error ("function f(...a,) {}")
27+
check_syntax_error ("function f(a = 1 + 1,,) {}")
28+
check_syntax_error ("function f(a,,b) {}")
29+
check_syntax_error ("function f(,a) {}")
30+
31+
function f1(a,) {}
32+
assert(f1.length === 1)
33+
34+
function f2(a = 1,) {}
35+
assert(f2.length === 1)
36+
37+
function f3(a = 1, b = 1 + 1, c,) {}
38+
assert(f3.length === 3)
39+
40+
var f4 = async(a,) => {}
41+
assert(f4.length === 1)
42+
43+
var f5 = async(a = 1,) => {}
44+
assert(f5.length === 1)
45+
46+
assert(((a = 1, b = 1 + 1, c,) => {}).length === 3)
47+
48+
assert(((a = 1, b, c = 1 + 1,) => {}).length === 3)

0 commit comments

Comments
 (0)