@@ -887,6 +887,22 @@ pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
887887 node->flags &= (pm_node_flags_t) ~flag;
888888}
889889
890+ /**
891+ * Set the repeated parameter flag on the given node.
892+ */
893+ static inline void
894+ pm_node_flag_set_repeated_parameter(pm_node_t *node) {
895+ assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
896+ PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
897+ PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
898+ PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
899+ PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
900+ PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
901+ PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
902+ PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
903+
904+ pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
905+ }
890906
891907/******************************************************************************/
892908/* Node creation functions */
@@ -5995,23 +6011,28 @@ pm_parser_local_add_owned(pm_parser_t *parser, const uint8_t *start, size_t leng
59956011/**
59966012 * Add a parameter name to the current scope and check whether the name of the
59976013 * parameter is unique or not.
6014+ *
6015+ * Returns `true` if this is a duplicate parameter name, otherwise returns
6016+ * false.
59986017 */
5999- static void
6018+ static bool
60006019pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
60016020 // We want to check whether the parameter name is a numbered parameter or
60026021 // not.
60036022 pm_refute_numbered_parameter(parser, name->start, name->end);
60046023
6005- // We want to ignore any parameter name that starts with an underscore.
6006- if ((name->start < name->end) && (*name->start == '_')) return;
6007-
60086024 // Otherwise we'll fetch the constant id for the parameter name and check
60096025 // whether it's already in the current scope.
60106026 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
60116027
60126028 if (pm_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
6013- pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_REPEAT);
6029+ // Add an error if the parameter doesn't start with _ and has been seen before
6030+ if ((name->start < name->end) && (*name->start != '_')) {
6031+ pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_REPEAT);
6032+ }
6033+ return true;
60146034 }
6035+ return false;
60156036}
60166037
60176038/**
@@ -11466,7 +11487,9 @@ parse_required_destructured_parameter(pm_parser_t *parser) {
1146611487 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
1146711488 pm_token_t name = parser->previous;
1146811489 value = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
11469- pm_parser_parameter_name_check(parser, &name);
11490+ if (pm_parser_parameter_name_check(parser, &name)) {
11491+ pm_node_flag_set_repeated_parameter(value);
11492+ }
1147011493 pm_parser_local_add_token(parser, &name);
1147111494 }
1147211495
@@ -11476,7 +11499,9 @@ parse_required_destructured_parameter(pm_parser_t *parser) {
1147611499 pm_token_t name = parser->previous;
1147711500
1147811501 param = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
11479- pm_parser_parameter_name_check(parser, &name);
11502+ if (pm_parser_parameter_name_check(parser, &name)) {
11503+ pm_node_flag_set_repeated_parameter(param);
11504+ }
1148011505 pm_parser_local_add_token(parser, &name);
1148111506 }
1148211507
@@ -11593,9 +11618,10 @@ parse_parameters(
1159311618 pm_token_t operator = parser->previous;
1159411619 pm_token_t name;
1159511620
11621+ bool repeated = false;
1159611622 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
1159711623 name = parser->previous;
11598- pm_parser_parameter_name_check(parser, &name);
11624+ repeated = pm_parser_parameter_name_check(parser, &name);
1159911625 pm_parser_local_add_token(parser, &name);
1160011626 } else {
1160111627 name = not_provided(parser);
@@ -11606,6 +11632,9 @@ parse_parameters(
1160611632 }
1160711633
1160811634 pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &operator);
11635+ if (repeated) {
11636+ pm_node_flag_set_repeated_parameter((pm_node_t *)param);
11637+ }
1160911638 if (params->block == NULL) {
1161011639 pm_parameters_node_block_set(params, param);
1161111640 } else {
@@ -11678,7 +11707,7 @@ parse_parameters(
1167811707 }
1167911708
1168011709 pm_token_t name = parser->previous;
11681- pm_parser_parameter_name_check(parser, &name);
11710+ bool repeated = pm_parser_parameter_name_check(parser, &name);
1168211711 pm_parser_local_add_token(parser, &name);
1168311712
1168411713 if (accept1(parser, PM_TOKEN_EQUAL)) {
@@ -11689,6 +11718,9 @@ parse_parameters(
1168911718 pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT);
1169011719
1169111720 pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value);
11721+ if (repeated) {
11722+ pm_node_flag_set_repeated_parameter((pm_node_t *)param);
11723+ }
1169211724 pm_parameters_node_optionals_append(params, param);
1169311725
1169411726 parser->current_param_name = old_param_name;
@@ -11703,9 +11735,15 @@ parse_parameters(
1170311735 }
1170411736 } else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
1170511737 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
11738+ if (repeated) {
11739+ pm_node_flag_set_repeated_parameter((pm_node_t *)param);
11740+ }
1170611741 pm_parameters_node_requireds_append(params, (pm_node_t *) param);
1170711742 } else {
1170811743 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
11744+ if (repeated) {
11745+ pm_node_flag_set_repeated_parameter((pm_node_t *)param);
11746+ }
1170911747 pm_parameters_node_posts_append(params, (pm_node_t *) param);
1171011748 }
1171111749
@@ -11720,14 +11758,17 @@ parse_parameters(
1172011758 pm_token_t local = name;
1172111759 local.end -= 1;
1172211760
11723- pm_parser_parameter_name_check(parser, &local);
11761+ bool repeated = pm_parser_parameter_name_check(parser, &local);
1172411762 pm_parser_local_add_token(parser, &local);
1172511763
1172611764 switch (parser->current.type) {
1172711765 case PM_TOKEN_COMMA:
1172811766 case PM_TOKEN_PARENTHESIS_RIGHT:
1172911767 case PM_TOKEN_PIPE: {
1173011768 pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
11769+ if (repeated) {
11770+ pm_node_flag_set_repeated_parameter(param);
11771+ }
1173111772 pm_parameters_node_keywords_append(params, param);
1173211773 break;
1173311774 }
@@ -11739,6 +11780,9 @@ parse_parameters(
1173911780 }
1174011781
1174111782 pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
11783+ if (repeated) {
11784+ pm_node_flag_set_repeated_parameter(param);
11785+ }
1174211786 pm_parameters_node_keywords_append(params, param);
1174311787 break;
1174411788 }
@@ -11758,6 +11802,9 @@ parse_parameters(
1175811802 param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
1175911803 }
1176011804
11805+ if (repeated) {
11806+ pm_node_flag_set_repeated_parameter(param);
11807+ }
1176111808 pm_parameters_node_keywords_append(params, param);
1176211809
1176311810 // If parsing the value of the parameter resulted in error recovery,
@@ -11780,10 +11827,10 @@ parse_parameters(
1178011827
1178111828 pm_token_t operator = parser->previous;
1178211829 pm_token_t name;
11783-
11830+ bool repeated = false;
1178411831 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
1178511832 name = parser->previous;
11786- pm_parser_parameter_name_check(parser, &name);
11833+ repeated = pm_parser_parameter_name_check(parser, &name);
1178711834 pm_parser_local_add_token(parser, &name);
1178811835 } else {
1178911836 name = not_provided(parser);
@@ -11794,6 +11841,9 @@ parse_parameters(
1179411841 }
1179511842
1179611843 pm_node_t *param = (pm_node_t *) pm_rest_parameter_node_create(parser, &operator, &name);
11844+ if (repeated) {
11845+ pm_node_flag_set_repeated_parameter(param);
11846+ }
1179711847 if (params->rest == NULL) {
1179811848 pm_parameters_node_rest_set(params, param);
1179911849 } else {
@@ -11816,9 +11866,10 @@ parse_parameters(
1181611866 } else {
1181711867 pm_token_t name;
1181811868
11869+ bool repeated = false;
1181911870 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
1182011871 name = parser->previous;
11821- pm_parser_parameter_name_check(parser, &name);
11872+ repeated = pm_parser_parameter_name_check(parser, &name);
1182211873 pm_parser_local_add_token(parser, &name);
1182311874 } else {
1182411875 name = not_provided(parser);
@@ -11829,6 +11880,9 @@ parse_parameters(
1182911880 }
1183011881
1183111882 param = (pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &operator, &name);
11883+ if (repeated) {
11884+ pm_node_flag_set_repeated_parameter(param);
11885+ }
1183211886 }
1183311887
1183411888 if (params->keyword_rest == NULL) {
@@ -12064,10 +12118,13 @@ parse_block_parameters(
1206412118 if ((opening->type != PM_TOKEN_NOT_PROVIDED) && accept1(parser, PM_TOKEN_SEMICOLON)) {
1206512119 do {
1206612120 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
12067- pm_parser_parameter_name_check(parser, &parser->previous);
12121+ bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
1206812122 pm_parser_local_add_token(parser, &parser->previous);
1206912123
1207012124 pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous);
12125+ if (repeated) {
12126+ pm_node_flag_set_repeated_parameter((pm_node_t *)local);
12127+ }
1207112128 pm_block_parameters_node_append_local(block_parameters, local);
1207212129 } while (accept1(parser, PM_TOKEN_COMMA));
1207312130 }
0 commit comments