Skip to content

Commit ef26b28

Browse files
committed
Fix nested default value error
1 parent 48e23f8 commit ef26b28

File tree

3 files changed

+91
-37
lines changed

3 files changed

+91
-37
lines changed

include/prism/util/pm_constant_pool.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
#include <stdlib.h>
1919
#include <string.h>
2020

21+
/**
22+
* When we allocate constants into the pool, we reserve 0 to mean that the slot
23+
* is not yet filled. This constant is reused in other places to indicate the
24+
* lack of a constant id.
25+
*/
26+
#define PM_CONSTANT_ID_UNSET 0
27+
2128
/**
2229
* A constant id is a unique identifier for a constant in the constant pool.
2330
*/

src/prism.c

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5932,6 +5932,33 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) {
59325932
return true;
59335933
}
59345934

5935+
/**
5936+
* Save the current param name as the return value and set it to the given
5937+
* constant id.
5938+
*/
5939+
static inline pm_constant_id_t
5940+
pm_parser_current_param_name_set(pm_parser_t *parser, pm_constant_id_t current_param_name) {
5941+
pm_constant_id_t saved_param_name = parser->current_param_name;
5942+
parser->current_param_name = current_param_name;
5943+
return saved_param_name;
5944+
}
5945+
5946+
/**
5947+
* Save the current param name as the return value and clear it.
5948+
*/
5949+
static inline pm_constant_id_t
5950+
pm_parser_current_param_name_unset(pm_parser_t *parser) {
5951+
return pm_parser_current_param_name_set(parser, PM_CONSTANT_ID_UNSET);
5952+
}
5953+
5954+
/**
5955+
* Restore the current param name from the given value.
5956+
*/
5957+
static inline void
5958+
pm_parser_current_param_name_restore(pm_parser_t *parser, pm_constant_id_t saved_param_name) {
5959+
parser->current_param_name = saved_param_name;
5960+
}
5961+
59355962
/**
59365963
* Check if any of the currently visible scopes contain a local variable
59375964
* described by the given constant id.
@@ -11715,8 +11742,8 @@ parse_parameters(
1171511742
if (accept1(parser, PM_TOKEN_EQUAL)) {
1171611743
pm_token_t operator = parser->previous;
1171711744
context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
11718-
pm_constant_id_t old_param_name = parser->current_param_name;
11719-
parser->current_param_name = pm_parser_constant_id_token(parser, &name);
11745+
11746+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_set(parser, pm_parser_constant_id_token(parser, &name));
1172011747
pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT);
1172111748

1172211749
pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value);
@@ -11725,7 +11752,7 @@ parse_parameters(
1172511752
}
1172611753
pm_parameters_node_optionals_append(params, param);
1172711754

11728-
parser->current_param_name = old_param_name;
11755+
pm_parser_current_param_name_restore(parser, saved_param_name);
1172911756
context_pop(parser);
1173011757

1173111758
// If parsing the value of the parameter resulted in error recovery,
@@ -11793,11 +11820,13 @@ parse_parameters(
1179311820

1179411821
if (token_begins_expression_p(parser->current.type)) {
1179511822
context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
11796-
pm_constant_id_t old_param_name = parser->current_param_name;
11797-
parser->current_param_name = pm_parser_constant_id_token(parser, &local);
11823+
11824+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_set(parser, pm_parser_constant_id_token(parser, &local));
1179811825
pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT_KW);
11799-
parser->current_param_name = old_param_name;
11826+
11827+
pm_parser_current_param_name_restore(parser, saved_param_name);
1180011828
context_pop(parser);
11829+
1180111830
param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
1180211831
}
1180311832
else {
@@ -12142,8 +12171,10 @@ parse_block(pm_parser_t *parser) {
1214212171
pm_token_t opening = parser->previous;
1214312172
accept1(parser, PM_TOKEN_NEWLINE);
1214412173

12174+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_unset(parser);
1214512175
pm_accepts_block_stack_push(parser, true);
1214612176
pm_parser_scope_push(parser, false);
12177+
1214712178
pm_block_parameters_node_t *block_parameters = NULL;
1214812179

1214912180
if (accept1(parser, PM_TOKEN_PIPE)) {
@@ -12207,6 +12238,8 @@ parse_block(pm_parser_t *parser) {
1220712238
pm_constant_id_list_t locals = parser->current_scope->locals;
1220812239
pm_parser_scope_pop(parser);
1220912240
pm_accepts_block_stack_pop(parser);
12241+
pm_parser_current_param_name_restore(parser, saved_param_name);
12242+
1221012243
return pm_block_node_create(parser, &locals, locals_body_index, &opening, parameters, statements, &parser->previous);
1221112244
}
1221212245

@@ -14910,8 +14943,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1491014943
pm_token_t operator = parser->previous;
1491114944
pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_NOT, true, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS);
1491214945

14913-
pm_constant_id_t old_param_name = parser->current_param_name;
14914-
parser->current_param_name = 0;
14946+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_unset(parser);
1491514947
pm_parser_scope_push(parser, true);
1491614948
accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
1491714949

@@ -14928,11 +14960,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1492814960
}
1492914961

1493014962
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
14931-
1493214963
pm_constant_id_list_t locals = parser->current_scope->locals;
14964+
1493314965
pm_parser_scope_pop(parser);
14934-
parser->current_param_name = old_param_name;
1493514966
pm_do_loop_stack_pop(parser);
14967+
pm_parser_current_param_name_restore(parser, saved_param_name);
14968+
1493614969
return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
1493714970
}
1493814971

@@ -14958,9 +14991,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1495814991
superclass = NULL;
1495914992
}
1496014993

14961-
pm_constant_id_t old_param_name = parser->current_param_name;
14962-
parser->current_param_name = 0;
14994+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_unset(parser);
1496314995
pm_parser_scope_push(parser, true);
14996+
1496414997
if (inheritance_operator.type != PM_TOKEN_NOT_PROVIDED) {
1496514998
expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
1496614999
} else {
@@ -14986,9 +15019,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1498615019
}
1498715020

1498815021
pm_constant_id_list_t locals = parser->current_scope->locals;
15022+
1498915023
pm_parser_scope_pop(parser);
14990-
parser->current_param_name = old_param_name;
1499115024
pm_do_loop_stack_pop(parser);
15025+
pm_parser_current_param_name_restore(parser, saved_param_name);
1499215026

1499315027
if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
1499415028
pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
@@ -15003,18 +15037,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1500315037
pm_token_t operator = not_provided(parser);
1500415038
pm_token_t name = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = def_keyword.end, .end = def_keyword.end };
1500515039

15006-
// This context is necessary for lexing `...` in a bare params correctly.
15007-
// It must be pushed before lexing the first param, so it is here.
15040+
// This context is necessary for lexing `...` in a bare params
15041+
// correctly. It must be pushed before lexing the first param, so it
15042+
// is here.
1500815043
context_push(parser, PM_CONTEXT_DEF_PARAMS);
15044+
pm_constant_id_t saved_param_name;
15045+
1500915046
parser_lex(parser);
15010-
pm_constant_id_t old_param_name = parser->current_param_name;
1501115047

1501215048
switch (parser->current.type) {
1501315049
case PM_CASE_OPERATOR:
15050+
saved_param_name = pm_parser_current_param_name_unset(parser);
1501415051
pm_parser_scope_push(parser, true);
15015-
parser->current_param_name = 0;
1501615052
lex_state_set(parser, PM_LEX_STATE_ENDFN);
1501715053
parser_lex(parser);
15054+
1501815055
name = parser->previous;
1501915056
break;
1502015057
case PM_TOKEN_IDENTIFIER: {
@@ -15023,17 +15060,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1502315060
if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
1502415061
receiver = parse_variable_call(parser);
1502515062

15063+
saved_param_name = pm_parser_current_param_name_unset(parser);
1502615064
pm_parser_scope_push(parser, true);
15027-
parser->current_param_name = 0;
1502815065
lex_state_set(parser, PM_LEX_STATE_FNAME);
1502915066
parser_lex(parser);
1503015067

1503115068
operator = parser->previous;
1503215069
name = parse_method_definition_name(parser);
1503315070
} else {
15071+
saved_param_name = pm_parser_current_param_name_unset(parser);
1503415072
pm_refute_numbered_parameter(parser, parser->previous.start, parser->previous.end);
1503515073
pm_parser_scope_push(parser, true);
15036-
parser->current_param_name = 0;
15074+
1503715075
name = parser->previous;
1503815076
}
1503915077

@@ -15050,9 +15088,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1505015088
case PM_TOKEN_KEYWORD___FILE__:
1505115089
case PM_TOKEN_KEYWORD___LINE__:
1505215090
case PM_TOKEN_KEYWORD___ENCODING__: {
15091+
saved_param_name = pm_parser_current_param_name_unset(parser);
1505315092
pm_parser_scope_push(parser, true);
15054-
parser->current_param_name = 0;
1505515093
parser_lex(parser);
15094+
1505615095
pm_token_t identifier = parser->previous;
1505715096

1505815097
if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
@@ -15124,17 +15163,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1512415163
operator = parser->previous;
1512515164
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
1512615165

15166+
saved_param_name = pm_parser_current_param_name_unset(parser);
1512715167
pm_parser_scope_push(parser, true);
15128-
parser->current_param_name = 0;
1512915168

1513015169
// To push `PM_CONTEXT_DEF_PARAMS` again is for the same reason as described the above.
1513115170
context_push(parser, PM_CONTEXT_DEF_PARAMS);
1513215171
name = parse_method_definition_name(parser);
1513315172
break;
1513415173
}
1513515174
default:
15175+
saved_param_name = pm_parser_current_param_name_unset(parser);
1513615176
pm_parser_scope_push(parser, true);
15137-
parser->current_param_name = 0;
15177+
1513815178
name = parse_method_definition_name(parser);
1513915179
break;
1514015180
}
@@ -15249,8 +15289,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1524915289
}
1525015290

1525115291
pm_constant_id_list_t locals = parser->current_scope->locals;
15252-
parser->current_param_name = old_param_name;
15292+
1525315293
pm_parser_scope_pop(parser);
15294+
pm_parser_current_param_name_restore(parser, saved_param_name);
1525415295

1525515296
return (pm_node_t *) pm_def_node_create(
1525615297
parser,
@@ -15478,9 +15519,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1547815519
pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
1547915520
}
1548015521

15481-
pm_constant_id_t old_param_name = parser->current_param_name;
15482-
parser->current_param_name = 0;
15522+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_unset(parser);
1548315523
pm_parser_scope_push(parser, true);
15524+
1548415525
accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
1548515526
pm_node_t *statements = NULL;
1548615527

@@ -15497,7 +15538,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1549715538

1549815539
pm_constant_id_list_t locals = parser->current_scope->locals;
1549915540
pm_parser_scope_pop(parser);
15500-
parser->current_param_name = old_param_name;
15541+
pm_parser_current_param_name_restore(parser, saved_param_name);
1550115542

1550215543
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
1550315544

@@ -16164,7 +16205,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1616416205
parser_lex(parser);
1616516206

1616616207
pm_token_t operator = parser->previous;
16208+
pm_constant_id_t saved_param_name = pm_parser_current_param_name_unset(parser);
1616716209
pm_parser_scope_push(parser, false);
16210+
1616816211
pm_block_parameters_node_t *block_parameters;
1616916212

1617016213
switch (parser->current.type) {
@@ -16243,8 +16286,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1624316286
}
1624416287

1624516288
pm_constant_id_list_t locals = parser->current_scope->locals;
16289+
1624616290
pm_parser_scope_pop(parser);
1624716291
pm_accepts_block_stack_pop(parser);
16292+
pm_parser_current_param_name_restore(parser, saved_param_name);
16293+
1624816294
return (pm_node_t *) pm_lambda_node_create(parser, &locals, locals_body_index, &operator, &opening, &parser->previous, parameters, body);
1624916295
}
1625016296
case PM_TOKEN_UPLUS: {

src/util/pm_constant_pool.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,13 @@ pm_constant_pool_resize(pm_constant_pool_t *pool) {
124124

125125
// If an id is set on this constant, then we know we have content here.
126126
// In this case we need to insert it into the next constant pool.
127-
if (bucket->id != 0) {
127+
if (bucket->id != PM_CONSTANT_ID_UNSET) {
128128
uint32_t next_index = bucket->hash & mask;
129129

130130
// This implements linear scanning to find the next available slot
131131
// in case this index is already taken. We don't need to bother
132132
// comparing the values since we know that the hash is unique.
133-
while (next_buckets[next_index].id != 0) {
133+
while (next_buckets[next_index].id != PM_CONSTANT_ID_UNSET) {
134134
next_index = (next_index + 1) & mask;
135135
}
136136

@@ -177,7 +177,7 @@ pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity) {
177177
*/
178178
pm_constant_t *
179179
pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id) {
180-
assert(constant_id > 0 && constant_id <= pool->size);
180+
assert(constant_id != PM_CONSTANT_ID_UNSET && constant_id <= pool->size);
181181
return &pool->constants[constant_id - 1];
182182
}
183183

@@ -187,7 +187,7 @@ pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t
187187
static inline pm_constant_id_t
188188
pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t length, pm_constant_pool_bucket_type_t type) {
189189
if (pool->size >= (pool->capacity / 4 * 3)) {
190-
if (!pm_constant_pool_resize(pool)) return 0;
190+
if (!pm_constant_pool_resize(pool)) return PM_CONSTANT_ID_UNSET;
191191
}
192192

193193
assert(is_power_of_two(pool->capacity));
@@ -197,7 +197,7 @@ pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t l
197197
uint32_t index = hash & mask;
198198
pm_constant_pool_bucket_t *bucket;
199199

200-
while (bucket = &pool->buckets[index], bucket->id != 0) {
200+
while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
201201
// If there is a collision, then we need to check if the content is the
202202
// same as the content we are trying to insert. If it is, then we can
203203
// return the id of the existing constant.
@@ -248,8 +248,8 @@ pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t l
248248
}
249249

250250
/**
251-
* Insert a constant into a constant pool. Returns the id of the constant, or 0
252-
* if any potential calls to resize fail.
251+
* Insert a constant into a constant pool. Returns the id of the constant, or
252+
* PM_CONSTANT_ID_UNSET if any potential calls to resize fail.
253253
*/
254254
pm_constant_id_t
255255
pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
@@ -258,8 +258,8 @@ pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, s
258258

259259
/**
260260
* Insert a constant into a constant pool from memory that is now owned by the
261-
* constant pool. Returns the id of the constant, or 0 if any potential calls to
262-
* resize fail.
261+
* constant pool. Returns the id of the constant, or PM_CONSTANT_ID_UNSET if any
262+
* potential calls to resize fail.
263263
*/
264264
pm_constant_id_t
265265
pm_constant_pool_insert_owned(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
@@ -268,7 +268,8 @@ pm_constant_pool_insert_owned(pm_constant_pool_t *pool, const uint8_t *start, si
268268

269269
/**
270270
* Insert a constant into a constant pool from memory that is constant. Returns
271-
* the id of the constant, or 0 if any potential calls to resize fail.
271+
* the id of the constant, or PM_CONSTANT_ID_UNSET if any potential calls to
272+
* resize fail.
272273
*/
273274
pm_constant_id_t
274275
pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
@@ -286,7 +287,7 @@ pm_constant_pool_free(pm_constant_pool_t *pool) {
286287
pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
287288

288289
// If an id is set on this constant, then we know we have content here.
289-
if (bucket->id != 0 && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
290+
if (bucket->id != PM_CONSTANT_ID_UNSET && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
290291
pm_constant_t *constant = &pool->constants[bucket->id - 1];
291292
free((void *) constant->start);
292293
}

0 commit comments

Comments
 (0)