Skip to content

Commit 83fc0aa

Browse files
zherczegLaszloLango
authored andcommitted
Add support for function argument initializers. (#2571)
EcmaScript 2015 14.1. Note: arrow functions with default arguments are not supported yet. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
1 parent aeddb1c commit 83fc0aa

File tree

8 files changed

+164
-18
lines changed

8 files changed

+164
-18
lines changed

jerry-core/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
# define CONFIG_DISABLE_ES2015_ARROW_FUNCTION
4040
# define CONFIG_DISABLE_ES2015_BUILTIN
4141
# define CONFIG_DISABLE_ES2015_CLASS
42+
# define CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
4243
# define CONFIG_DISABLE_ES2015_MAP_BUILTIN
4344
# define CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
4445
# define CONFIG_DISABLE_ES2015_PROMISE_BUILTIN

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ typedef enum
7474
SCAN_STACK_CLASS, /**< class language element */
7575
SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */
7676
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
77+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
78+
SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */
79+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
7780
} scan_stack_modes_t;
7881

7982
/**
@@ -420,6 +423,22 @@ parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */
420423
}
421424
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
422425

426+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
427+
if (context_p->token.type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_FUNCTION_PARAMETERS)
428+
{
429+
lexer_next_token (context_p);
430+
431+
parser_stack_pop_uint8 (context_p);
432+
433+
if (context_p->token.type != LEXER_LEFT_BRACE)
434+
{
435+
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
436+
}
437+
*mode = SCAN_MODE_STATEMENT;
438+
return false;
439+
}
440+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
441+
423442
/* Check whether we can enter to statement mode. */
424443
if (stack_top != SCAN_STACK_BLOCK_STATEMENT
425444
&& stack_top != SCAN_STACK_BLOCK_EXPRESSION
@@ -861,6 +880,15 @@ parser_scan_until (parser_context_t *context_p, /**< context */
861880
}
862881
}
863882

883+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
884+
if (context_p->token.type == LEXER_ASSIGN)
885+
{
886+
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS);
887+
mode = SCAN_MODE_PRIMARY_EXPRESSION;
888+
break;
889+
}
890+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
891+
864892
if (context_p->token.type != LEXER_RIGHT_PAREN)
865893
{
866894
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);

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

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,6 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
324324

325325
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
326326

327-
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
328-
329327
lexer_next_token (context_p);
330328

331329
if (context_p->token.type == LEXER_ASSIGN)
@@ -334,19 +332,11 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
334332
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
335333
&& ident_line_counter != context_p->last_breakpoint_line)
336334
{
337-
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
338-
339-
cbc_argument_t last_cbc = context_p->last_cbc;
340-
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
341-
342335
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
343336
parser_flush_cbc (context_p);
344337

345338
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter);
346339

347-
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
348-
context_p->last_cbc = last_cbc;
349-
350340
context_p->last_breakpoint_line = ident_line_counter;
351341
}
352342
#endif /* JERRY_DEBUGGER */
@@ -358,16 +348,10 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
358348
}
359349
#endif /* JERRY_ENABLE_LINE_INFO */
360350

351+
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
361352
parser_parse_expression (context_p,
362353
PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL);
363354
}
364-
else
365-
{
366-
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
367-
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL);
368-
/* We don't need to assign anything to this variable. */
369-
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
370-
}
371355

372356
if (context_p->token.type != LEXER_COMMA)
373357
{

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,12 @@ parser_error_to_string (parser_error_t error) /**< error code */
10381038
{
10391039
return "Duplicated label.";
10401040
}
1041+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
1042+
case PARSER_ERR_DUPLICATED_ARGUMENT_NAMES:
1043+
{
1044+
return "Duplicated function argument names are not allowed here.";
1045+
}
1046+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
10411047
case PARSER_ERR_OBJECT_PROPERTY_REDEFINED:
10421048
{
10431049
return "Property of object literal redefined.";

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,6 +2177,11 @@ static void
21772177
parser_parse_function_arguments (parser_context_t *context_p, /**< context */
21782178
lexer_token_type_t end_type) /**< expected end type */
21792179
{
2180+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
2181+
bool duplicated_argument_names = false;
2182+
bool initializer_found = false;
2183+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
2184+
21802185
if (context_p->token.type == end_type)
21812186
{
21822187
return;
@@ -2218,6 +2223,14 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
22182223
{
22192224
lexer_literal_t *literal_p;
22202225

2226+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
2227+
if (initializer_found)
2228+
{
2229+
parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES);
2230+
}
2231+
duplicated_argument_names = true;
2232+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
2233+
22212234
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
22222235
{
22232236
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
@@ -2254,6 +2267,29 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
22542267

22552268
lexer_next_token (context_p);
22562269

2270+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
2271+
if (context_p->token.type == LEXER_ASSIGN)
2272+
{
2273+
parser_branch_t skip_init;
2274+
2275+
if (duplicated_argument_names)
2276+
{
2277+
parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES);
2278+
}
2279+
initializer_found = true;
2280+
2281+
/* LEXER_ASSIGN does not overwrite lit_object. */
2282+
parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
2283+
parser_emit_cbc_literal (context_p, CBC_STRICT_EQUAL_RIGHT_LITERAL, context_p->lit_object.index);
2284+
parser_emit_cbc_forward_branch (context_p, CBC_BRANCH_IF_FALSE_FORWARD, &skip_init);
2285+
2286+
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
2287+
parser_parse_expression (context_p, PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL);
2288+
2289+
parser_set_branch_to_current_position (context_p, &skip_init);
2290+
}
2291+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
2292+
22572293
if (context_p->token.type != LEXER_COMMA)
22582294
{
22592295
break;

jerry-core/parser/js/js-parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ typedef enum
119119
PARSER_ERR_INVALID_RETURN, /**< return must be inside a function */
120120
PARSER_ERR_INVALID_RIGHT_SQUARE, /**< right square must terminate a block */
121121
PARSER_ERR_DUPLICATED_LABEL, /**< duplicated label */
122+
#ifndef CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
123+
PARSER_ERR_DUPLICATED_ARGUMENT_NAMES, /**< duplicated argument names */
124+
#endif /* !CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER */
122125
PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */
123126
PARSER_ERR_NON_STRICT_ARG_DEFINITION /**< non-strict argument definition */
124127
} parser_error_t;

jerry-core/profiles/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Alternatively, if you want to use a custom profile at
3232
# Turn off every ES2015 feature EXCEPT the arrow functions
3333
CONFIG_DISABLE_ES2015_BUILTIN
3434
CONFIG_DISABLE_ES2015_CLASS
35+
CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER
36+
CONFIG_DISABLE_ES2015_MAP_BUILTIN
37+
CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
3538
CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
3639
CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
3740
CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
@@ -87,6 +90,8 @@ In JerryScript all of the features are enabled by default, so an empty profile f
8790
Disable the built-in updates of the 5.1 standard. There are some differences in those built-ins which available in both [5.1](http://www.ecma-international.org/ecma-262/5.1/) and [2015](http://www.ecma-international.org/ecma-262/6.0/) versions of the standard. JerryScript uses the latest definition by default.
8891
* `CONFIG_DISABLE_ES2015_CLASS`:
8992
Disable the [class](https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions) language element.
93+
* `CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER`:
94+
Disable the [default value](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) for formal parameters.
9095
* `CONFIG_DISABLE_ES2015_MAP_BUILTIN`:
9196
Disable the [Map](http://www.ecma-international.org/ecma-262/6.0/#sec-keyed-collection) built-ins.
9297
* `CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER`:
@@ -98,4 +103,6 @@ In JerryScript all of the features are enabled by default, so an empty profile f
98103
* `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`:
99104
Disable the [ArrayBuffer](http://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-objects) and [TypedArray](http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects) built-ins.
100105
* `CONFIG_DISABLE_ES2015`: Disable all of the implemented [ECMAScript2015 features](http://www.ecma-international.org/ecma-262/6.0/).
101-
(equivalent to `CONFIG_DISABLE_ES2015_ARROW_FUNCTION`, `CONFIG_DISABLE_ES2015_BUILTIN`, `CONFIG_DISABLE_ES2015_CLASS`, `CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`, `CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS`, and `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`).
106+
(equivalent to `CONFIG_DISABLE_ES2015_ARROW_FUNCTION`, `CONFIG_DISABLE_ES2015_BUILTIN`, `CONFIG_DISABLE_ES2015_CLASS`,
107+
`CONFIG_DISABLE_ES2015_FUNCTION_PARAMETER_INITIALIZER`, `CONFIG_DISABLE_ES2015_MAP_BUILTIN`, `CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER`,
108+
`CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`, `CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS`, and `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`).
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
var local = 0;
16+
17+
switch(0) { /* This switch forces a pre-scanner run. */
18+
default:
19+
20+
function f(a = (5, local = 6),
21+
b = ((5 + function(a = 6) { return a }() * 3)),
22+
c,
23+
d = true ? 1 : 2)
24+
{
25+
return "" + a + ", " + b + ", " + c + ", " + d;
26+
}
27+
28+
assert(f() === "6, 23, undefined, 1");
29+
assert(local === 6);
30+
31+
var obj = {
32+
f: function(a = [10,,20],
33+
b,
34+
c = Math.cos(0),
35+
d)
36+
{
37+
return "" + a + ", " + b + ", " + c + ", " + d;
38+
}
39+
};
40+
41+
assert(obj.f() === "10,,20, undefined, 1, undefined");
42+
43+
function g(a, b = (local = 7)) { }
44+
45+
local = 0;
46+
g();
47+
assert(local === 7);
48+
49+
local = 0;
50+
g(0);
51+
assert(local === 7);
52+
53+
local = 0;
54+
g(0, undefined);
55+
assert(local === 7);
56+
57+
local = 0;
58+
g(0, null);
59+
assert(local === 0);
60+
61+
local = 0;
62+
g(0, false);
63+
assert(local === 0);
64+
break;
65+
}
66+
67+
function CheckSyntaxError(str)
68+
{
69+
try {
70+
eval(str);
71+
assert(false);
72+
} catch (e) {
73+
assert(e instanceof SyntaxError);
74+
}
75+
}
76+
77+
CheckSyntaxError('function x(a += 5) {}');
78+
CheckSyntaxError('function x(a =, b) {}');
79+
CheckSyntaxError('function x(a = (b) {}');
80+
CheckSyntaxError('function x(a, a = 5) {}');
81+
CheckSyntaxError('function x(a = 5, a) {}');

0 commit comments

Comments
 (0)