prism 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/src/prism.c CHANGED
@@ -1005,7 +1005,7 @@ pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) {
1005
1005
  * written but not read in certain contexts.
1006
1006
  */
1007
1007
  static void
1008
- pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool warn_unused) {
1008
+ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) {
1009
1009
  pm_constant_id_list_init_capacity(list, locals->size);
1010
1010
 
1011
1011
  // If we're still below the threshold for switching to a hash, then we only
@@ -1013,6 +1013,10 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals,
1013
1013
  // stored in a list.
1014
1014
  uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1015
1015
 
1016
+ // We will only warn for unused variables if we're not at the top level, or
1017
+ // if we're parsing a file outside of eval or -e.
1018
+ bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1019
+
1016
1020
  for (uint32_t index = 0; index < capacity; index++) {
1017
1021
  pm_local_t *local = &locals->locals[index];
1018
1022
 
@@ -1178,6 +1182,156 @@ pm_assert_value_expression(pm_parser_t *parser, pm_node_t *node) {
1178
1182
  }
1179
1183
  }
1180
1184
 
1185
+ /**
1186
+ * Warn if the given node is a "void" statement.
1187
+ */
1188
+ static void
1189
+ pm_void_statement_check(pm_parser_t *parser, const pm_node_t *node) {
1190
+ const char *type = NULL;
1191
+ int length = 0;
1192
+
1193
+ switch (PM_NODE_TYPE(node)) {
1194
+ case PM_BACK_REFERENCE_READ_NODE:
1195
+ case PM_CLASS_VARIABLE_READ_NODE:
1196
+ case PM_GLOBAL_VARIABLE_READ_NODE:
1197
+ case PM_INSTANCE_VARIABLE_READ_NODE:
1198
+ case PM_LOCAL_VARIABLE_READ_NODE:
1199
+ case PM_NUMBERED_REFERENCE_READ_NODE:
1200
+ type = "a variable";
1201
+ length = 10;
1202
+ break;
1203
+ case PM_CALL_NODE: {
1204
+ const pm_call_node_t *cast = (const pm_call_node_t *) node;
1205
+ if (cast->call_operator_loc.start != NULL || cast->message_loc.start == NULL) break;
1206
+
1207
+ const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->name);
1208
+ switch (message->length) {
1209
+ case 1:
1210
+ switch (message->start[0]) {
1211
+ case '+':
1212
+ case '-':
1213
+ case '*':
1214
+ case '/':
1215
+ case '%':
1216
+ case '|':
1217
+ case '^':
1218
+ case '&':
1219
+ case '>':
1220
+ case '<':
1221
+ type = (const char *) message->start;
1222
+ length = 1;
1223
+ break;
1224
+ }
1225
+ break;
1226
+ case 2:
1227
+ switch (message->start[1]) {
1228
+ case '=':
1229
+ if (message->start[0] == '<' || message->start[0] == '>' || message->start[0] == '!' || message->start[0] == '=') {
1230
+ type = (const char *) message->start;
1231
+ length = 2;
1232
+ }
1233
+ break;
1234
+ case '@':
1235
+ if (message->start[0] == '+' || message->start[0] == '-') {
1236
+ type = (const char *) message->start;
1237
+ length = 2;
1238
+ }
1239
+ break;
1240
+ case '*':
1241
+ if (message->start[0] == '*') {
1242
+ type = (const char *) message->start;
1243
+ length = 2;
1244
+ }
1245
+ break;
1246
+ }
1247
+ break;
1248
+ case 3:
1249
+ if (memcmp(message->start, "<=>", 3) == 0) {
1250
+ type = "<=>";
1251
+ length = 3;
1252
+ }
1253
+ break;
1254
+ }
1255
+
1256
+ break;
1257
+ }
1258
+ case PM_CONSTANT_PATH_NODE:
1259
+ type = "::";
1260
+ length = 2;
1261
+ break;
1262
+ case PM_CONSTANT_READ_NODE:
1263
+ type = "a constant";
1264
+ length = 10;
1265
+ break;
1266
+ case PM_DEFINED_NODE:
1267
+ type = "defined?";
1268
+ length = 8;
1269
+ break;
1270
+ case PM_FALSE_NODE:
1271
+ type = "false";
1272
+ length = 5;
1273
+ break;
1274
+ case PM_FLOAT_NODE:
1275
+ case PM_IMAGINARY_NODE:
1276
+ case PM_INTEGER_NODE:
1277
+ case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1278
+ case PM_INTERPOLATED_STRING_NODE:
1279
+ case PM_RATIONAL_NODE:
1280
+ case PM_REGULAR_EXPRESSION_NODE:
1281
+ case PM_SOURCE_ENCODING_NODE:
1282
+ case PM_SOURCE_FILE_NODE:
1283
+ case PM_SOURCE_LINE_NODE:
1284
+ case PM_STRING_NODE:
1285
+ case PM_SYMBOL_NODE:
1286
+ type = "a literal";
1287
+ length = 9;
1288
+ break;
1289
+ case PM_NIL_NODE:
1290
+ type = "nil";
1291
+ length = 3;
1292
+ break;
1293
+ case PM_RANGE_NODE: {
1294
+ const pm_range_node_t *cast = (const pm_range_node_t *) node;
1295
+
1296
+ if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1297
+ type = "...";
1298
+ length = 3;
1299
+ } else {
1300
+ type = "..";
1301
+ length = 2;
1302
+ }
1303
+
1304
+ break;
1305
+ }
1306
+ case PM_SELF_NODE:
1307
+ type = "self";
1308
+ length = 4;
1309
+ break;
1310
+ case PM_TRUE_NODE:
1311
+ type = "true";
1312
+ length = 4;
1313
+ break;
1314
+ default:
1315
+ break;
1316
+ }
1317
+
1318
+ if (type != NULL) {
1319
+ PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length, type);
1320
+ }
1321
+ }
1322
+
1323
+ /**
1324
+ * Warn if any of the statements that are not the last statement in the list are
1325
+ * a "void" statement.
1326
+ */
1327
+ static void
1328
+ pm_void_statements_check(pm_parser_t *parser, const pm_statements_node_t *node) {
1329
+ assert(node->body.size > 0);
1330
+ for (size_t index = 0; index < node->body.size - 1; index++) {
1331
+ pm_void_statement_check(parser, node->body.nodes[index]);
1332
+ }
1333
+ }
1334
+
1181
1335
  /**
1182
1336
  * When we're handling the predicate of a conditional, we need to know our
1183
1337
  * context in order to determine the kind of warning we should deliver to the
@@ -1741,7 +1895,7 @@ static pm_statements_node_t *
1741
1895
  pm_statements_node_create(pm_parser_t *parser);
1742
1896
 
1743
1897
  static void
1744
- pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement);
1898
+ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement);
1745
1899
 
1746
1900
  static size_t
1747
1901
  pm_statements_node_body_length(pm_statements_node_t *node);
@@ -2620,6 +2774,7 @@ pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *me
2620
2774
  if (arguments->closing_loc.start != NULL) {
2621
2775
  node->base.location.end = arguments->closing_loc.end;
2622
2776
  } else {
2777
+ assert(receiver != NULL);
2623
2778
  node->base.location.end = receiver->location.end;
2624
2779
  }
2625
2780
 
@@ -4400,7 +4555,7 @@ pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_t
4400
4555
  pm_if_node_t *node = PM_ALLOC_NODE(parser, pm_if_node_t);
4401
4556
 
4402
4557
  pm_statements_node_t *statements = pm_statements_node_create(parser);
4403
- pm_statements_node_body_append(statements, statement);
4558
+ pm_statements_node_body_append(parser, statements, statement);
4404
4559
 
4405
4560
  *node = (pm_if_node_t) {
4406
4561
  {
@@ -4431,10 +4586,10 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_to
4431
4586
  pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4432
4587
 
4433
4588
  pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4434
- pm_statements_node_body_append(if_statements, true_expression);
4589
+ pm_statements_node_body_append(parser, if_statements, true_expression);
4435
4590
 
4436
4591
  pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4437
- pm_statements_node_body_append(else_statements, false_expression);
4592
+ pm_statements_node_body_append(parser, else_statements, false_expression);
4438
4593
 
4439
4594
  pm_token_t end_keyword = not_provided(parser);
4440
4595
  pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
@@ -6455,8 +6610,25 @@ pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement)
6455
6610
  * Append a new node to the given StatementsNode node's body.
6456
6611
  */
6457
6612
  static void
6458
- pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement) {
6613
+ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement) {
6459
6614
  pm_statements_node_body_update(node, statement);
6615
+
6616
+ if (node->body.size > 0) {
6617
+ const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6618
+
6619
+ switch (PM_NODE_TYPE(previous)) {
6620
+ case PM_BREAK_NODE:
6621
+ case PM_NEXT_NODE:
6622
+ case PM_REDO_NODE:
6623
+ case PM_RETRY_NODE:
6624
+ case PM_RETURN_NODE:
6625
+ pm_parser_warn_node(parser, previous, PM_WARN_UNREACHABLE_STATEMENT);
6626
+ break;
6627
+ default:
6628
+ break;
6629
+ }
6630
+ }
6631
+
6460
6632
  pm_node_list_append(&node->body, statement);
6461
6633
  pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6462
6634
  }
@@ -7019,7 +7191,7 @@ pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const
7019
7191
  pm_unless_node_t *node = PM_ALLOC_NODE(parser, pm_unless_node_t);
7020
7192
 
7021
7193
  pm_statements_node_t *statements = pm_statements_node_create(parser);
7022
- pm_statements_node_body_append(statements, statement);
7194
+ pm_statements_node_body_append(parser, statements, statement);
7023
7195
 
7024
7196
  *node = (pm_unless_node_t) {
7025
7197
  {
@@ -7460,6 +7632,30 @@ pm_parser_scope_pop(pm_parser_t *parser) {
7460
7632
  /* Stack helpers */
7461
7633
  /******************************************************************************/
7462
7634
 
7635
+ /**
7636
+ * Pushes a value onto the stack.
7637
+ */
7638
+ static inline void
7639
+ pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7640
+ *stack = (*stack << 1) | (value & 1);
7641
+ }
7642
+
7643
+ /**
7644
+ * Pops a value off the stack.
7645
+ */
7646
+ static inline void
7647
+ pm_state_stack_pop(pm_state_stack_t *stack) {
7648
+ *stack >>= 1;
7649
+ }
7650
+
7651
+ /**
7652
+ * Returns the value at the top of the stack.
7653
+ */
7654
+ static inline bool
7655
+ pm_state_stack_p(const pm_state_stack_t *stack) {
7656
+ return *stack & 1;
7657
+ }
7658
+
7463
7659
  static inline void
7464
7660
  pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7465
7661
  // Use the negation of the value to prevent stack overflow.
@@ -8400,6 +8596,10 @@ lex_global_variable(pm_parser_t *parser) {
8400
8596
  do {
8401
8597
  parser->current.end += width;
8402
8598
  } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
8599
+ } else if (pm_char_is_whitespace(peek(parser))) {
8600
+ // If we get here, then we have a $ followed by whitespace,
8601
+ // which is not allowed.
8602
+ pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8403
8603
  } else {
8404
8604
  // If we get here, then we have a $ followed by something that
8405
8605
  // isn't recognized as a global variable.
@@ -9430,15 +9630,23 @@ lex_embdoc(pm_parser_t *parser) {
9430
9630
  pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9431
9631
  if (comment == NULL) return PM_TOKEN_EOF;
9432
9632
 
9433
- // Now, loop until we find the end of the embedded documentation or the end of
9434
- // the file.
9633
+ // Now, loop until we find the end of the embedded documentation or the end
9634
+ // of the file.
9435
9635
  while (parser->current.end + 4 <= parser->end) {
9436
9636
  parser->current.start = parser->current.end;
9437
9637
 
9438
- // If we've hit the end of the embedded documentation then we'll return that
9439
- // token here.
9440
- if (memcmp(parser->current.end, "=end", 4) == 0 &&
9441
- (parser->current.end + 4 == parser->end || pm_char_is_whitespace(parser->current.end[4]))) {
9638
+ // If we've hit the end of the embedded documentation then we'll return
9639
+ // that token here.
9640
+ if (
9641
+ (memcmp(parser->current.end, "=end", 4) == 0) &&
9642
+ (
9643
+ (parser->current.end + 4 == parser->end) || // end of file
9644
+ pm_char_is_whitespace(parser->current.end[4]) || // whitespace
9645
+ (parser->current.end[4] == '\0') || // NUL or end of script
9646
+ (parser->current.end[4] == '\004') || // ^D
9647
+ (parser->current.end[4] == '\032') // ^Z
9648
+ )
9649
+ ) {
9442
9650
  const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9443
9651
 
9444
9652
  if (newline == NULL) {
@@ -10250,9 +10458,13 @@ parser_lex(pm_parser_t *parser) {
10250
10458
 
10251
10459
  // = => =~ == === =begin
10252
10460
  case '=':
10253
- if (current_token_starts_line(parser) && (parser->current.end + 5 <= parser->end) && memcmp(parser->current.end, "begin", 5) == 0 && pm_char_is_whitespace(peek_offset(parser, 5))) {
10461
+ if (
10462
+ current_token_starts_line(parser) &&
10463
+ (parser->current.end + 5 <= parser->end) &&
10464
+ memcmp(parser->current.end, "begin", 5) == 0 &&
10465
+ (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) == '\0'))
10466
+ ) {
10254
10467
  pm_token_type_t type = lex_embdoc(parser);
10255
-
10256
10468
  if (type == PM_TOKEN_EOF) {
10257
10469
  LEX(type);
10258
10470
  }
@@ -12329,7 +12541,8 @@ static pm_node_t *
12329
12541
  parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id);
12330
12542
 
12331
12543
  /**
12332
- * This is a wrapper of parse_expression, which also checks whether the resulting node is value expression.
12544
+ * This is a wrapper of parse_expression, which also checks whether the
12545
+ * resulting node is a value expression.
12333
12546
  */
12334
12547
  static pm_node_t *
12335
12548
  parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
@@ -12757,6 +12970,32 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
12757
12970
  }
12758
12971
  }
12759
12972
 
12973
+ /**
12974
+ * Certain expressions are not writable, but in order to provide a better
12975
+ * experience we give a specific error message. In order to maintain as much
12976
+ * information in the tree as possible, we replace them with local variable
12977
+ * writes.
12978
+ */
12979
+ static pm_node_t *
12980
+ parse_unwriteable_write(pm_parser_t *parser, pm_node_t *target, const pm_token_t *equals, pm_node_t *value) {
12981
+ switch (PM_NODE_TYPE(target)) {
12982
+ case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING); break;
12983
+ case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE); break;
12984
+ case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE); break;
12985
+ case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE); break;
12986
+ case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL); break;
12987
+ case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF); break;
12988
+ case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE); break;
12989
+ default: break;
12990
+ }
12991
+
12992
+ pm_constant_id_t name = pm_parser_constant_id_location(parser, target->location.start, target->location.end);
12993
+ pm_local_variable_write_node_t *result = pm_local_variable_write_node_create(parser, name, 0, value, &target->location, equals);
12994
+
12995
+ pm_node_destroy(parser, target);
12996
+ return (pm_node_t *) result;
12997
+ }
12998
+
12760
12999
  /**
12761
13000
  * Parse a list of targets for assignment. This is used in the case of a for
12762
13001
  * loop or a multi-assignment. For example, in the following code:
@@ -12848,7 +13087,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
12848
13087
 
12849
13088
  while (true) {
12850
13089
  pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION);
12851
- pm_statements_node_body_append(statements, node);
13090
+ pm_statements_node_body_append(parser, statements, node);
12852
13091
 
12853
13092
  // If we're recovering from a syntax error, then we need to stop parsing the
12854
13093
  // statements now.
@@ -12902,6 +13141,8 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
12902
13141
  }
12903
13142
 
12904
13143
  context_pop(parser);
13144
+ pm_void_statements_check(parser, statements);
13145
+
12905
13146
  return statements;
12906
13147
  }
12907
13148
 
@@ -13134,7 +13375,6 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
13134
13375
  if (token_begins_expression_p(parser->current.type)) {
13135
13376
  expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_ARGUMENT);
13136
13377
  } else {
13137
- // A block forwarding in a method having `...` parameter (e.g. `def foo(...); bar(&); end`) is available.
13138
13378
  pm_parser_scope_forwarding_block_check(parser, &operator);
13139
13379
  }
13140
13380
 
@@ -13217,7 +13457,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
13217
13457
  pm_static_literals_t literals = { 0 };
13218
13458
  pm_hash_key_static_literals_add(parser, &literals, argument);
13219
13459
 
13220
- // Finish parsing the one we are part way through
13460
+ // Finish parsing the one we are part way through.
13221
13461
  pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE);
13222
13462
  argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value);
13223
13463
 
@@ -13477,7 +13717,6 @@ parse_parameters(
13477
13717
  update_parameter_state(parser, &parser->current, &order);
13478
13718
  parser_lex(parser);
13479
13719
 
13480
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
13481
13720
  parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
13482
13721
 
13483
13722
  pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
@@ -13850,6 +14089,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
13850
14089
  case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE; break;
13851
14090
  case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE; break;
13852
14091
  case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE; break;
14092
+ default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break;
13853
14093
  }
13854
14094
 
13855
14095
  pm_statements_node_t *statements = parse_statements(parser, context);
@@ -13897,6 +14137,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
13897
14137
  case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE; break;
13898
14138
  case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE; break;
13899
14139
  case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE; break;
14140
+ default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break;
13900
14141
  }
13901
14142
 
13902
14143
  else_statements = parse_statements(parser, context);
@@ -13926,6 +14167,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
13926
14167
  case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE; break;
13927
14168
  case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE; break;
13928
14169
  case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE; break;
14170
+ default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break;
13929
14171
  }
13930
14172
 
13931
14173
  ensure_statements = parse_statements(parser, context);
@@ -14014,9 +14256,8 @@ parse_block_parameters(
14014
14256
  pm_parser_local_add_token(parser, &parser->previous, 1);
14015
14257
 
14016
14258
  pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous);
14017
- if (repeated) {
14018
- pm_node_flag_set_repeated_parameter((pm_node_t *)local);
14019
- }
14259
+ if (repeated) pm_node_flag_set_repeated_parameter((pm_node_t *) local);
14260
+
14020
14261
  pm_block_parameters_node_append_local(block_parameters, local);
14021
14262
  } while (accept1(parser, PM_TOKEN_COMMA));
14022
14263
  }
@@ -14118,7 +14359,7 @@ parse_block(pm_parser_t *parser) {
14118
14359
  }
14119
14360
 
14120
14361
  pm_constant_id_list_t locals;
14121
- pm_locals_order(parser, &parser->current_scope->locals, &locals, !pm_parser_scope_toplevel_p(parser));
14362
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
14122
14363
  pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &opening, &parser->previous);
14123
14364
 
14124
14365
  pm_parser_scope_pop(parser);
@@ -14145,9 +14386,14 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
14145
14386
  } else {
14146
14387
  pm_accepts_block_stack_push(parser, true);
14147
14388
  parse_arguments(parser, arguments, true, PM_TOKEN_PARENTHESIS_RIGHT);
14148
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_ARGUMENT_TERM_PAREN);
14149
- pm_accepts_block_stack_pop(parser);
14150
14389
 
14390
+ if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14391
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_type_human(parser->current.type));
14392
+ parser->previous.start = parser->previous.end;
14393
+ parser->previous.type = PM_TOKEN_MISSING;
14394
+ }
14395
+
14396
+ pm_accepts_block_stack_pop(parser);
14151
14397
  arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
14152
14398
  }
14153
14399
  } else if (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
@@ -15091,6 +15337,7 @@ parse_method_definition_name(pm_parser_t *parser) {
15091
15337
  parser_lex(parser);
15092
15338
  return parser->previous;
15093
15339
  default:
15340
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_NAME, pm_token_type_human(parser->current.type));
15094
15341
  return (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->current.start, .end = parser->current.end };
15095
15342
  }
15096
15343
  }
@@ -16601,7 +16848,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16601
16848
  // and we didn't return a multiple assignment node, then we can return a
16602
16849
  // regular parentheses node now.
16603
16850
  pm_statements_node_t *statements = pm_statements_node_create(parser);
16604
- pm_statements_node_body_append(statements, statement);
16851
+ pm_statements_node_body_append(parser, statements, statement);
16605
16852
 
16606
16853
  return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
16607
16854
  }
@@ -16611,7 +16858,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16611
16858
  // We'll do that here.
16612
16859
  context_push(parser, PM_CONTEXT_PARENS);
16613
16860
  pm_statements_node_t *statements = pm_statements_node_create(parser);
16614
- pm_statements_node_body_append(statements, statement);
16861
+ pm_statements_node_body_append(parser, statements, statement);
16615
16862
 
16616
16863
  // If we didn't find a terminator and we didn't find a right
16617
16864
  // parenthesis, then this is a syntax error.
@@ -16622,7 +16869,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16622
16869
  // Parse each statement within the parentheses.
16623
16870
  while (true) {
16624
16871
  pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION);
16625
- pm_statements_node_body_append(statements, node);
16872
+ pm_statements_node_body_append(parser, statements, node);
16626
16873
 
16627
16874
  // If we're recovering from a syntax error, then we need to stop
16628
16875
  // parsing the statements now.
@@ -16656,6 +16903,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16656
16903
  pop_block_exits(parser, previous_block_exits);
16657
16904
  pm_node_list_free(&current_block_exits);
16658
16905
 
16906
+ pm_void_statements_check(parser, statements);
16659
16907
  return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
16660
16908
  }
16661
16909
  case PM_TOKEN_BRACE_LEFT: {
@@ -17410,6 +17658,16 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17410
17658
  pm_arguments_t arguments = { 0 };
17411
17659
  parse_arguments_list(parser, &arguments, false, accepts_command_call);
17412
17660
 
17661
+ // It's possible that we've parsed a block argument through our
17662
+ // call to parse_arguments_list. If we found one, we should mark it
17663
+ // as invalid and destroy it, as we don't have a place for it on the
17664
+ // yield node.
17665
+ if (arguments.block != NULL) {
17666
+ pm_parser_err_node(parser, arguments.block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
17667
+ pm_node_destroy(parser, arguments.block);
17668
+ arguments.block = NULL;
17669
+ }
17670
+
17413
17671
  pm_node_t *node = (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc);
17414
17672
  if (!parser->parsing_eval) parse_yield(parser, node);
17415
17673
 
@@ -17442,7 +17700,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17442
17700
  expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
17443
17701
 
17444
17702
  pm_constant_id_list_t locals;
17445
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true);
17703
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
17446
17704
 
17447
17705
  pm_parser_scope_pop(parser);
17448
17706
  pm_do_loop_stack_pop(parser);
@@ -17502,7 +17760,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17502
17760
  }
17503
17761
 
17504
17762
  pm_constant_id_list_t locals;
17505
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true);
17763
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
17506
17764
 
17507
17765
  pm_parser_scope_pop(parser);
17508
17766
  pm_do_loop_stack_pop(parser);
@@ -17521,7 +17779,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17521
17779
 
17522
17780
  pm_node_t *receiver = NULL;
17523
17781
  pm_token_t operator = not_provided(parser);
17524
- pm_token_t name = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = def_keyword.end, .end = def_keyword.end };
17782
+ pm_token_t name;
17525
17783
 
17526
17784
  // This context is necessary for lexing `...` in a bare params
17527
17785
  // correctly. It must be pushed before lexing the first param, so it
@@ -17603,7 +17861,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17603
17861
  receiver = (pm_node_t *) pm_true_node_create(parser, &identifier);
17604
17862
  break;
17605
17863
  case PM_TOKEN_KEYWORD_FALSE:
17606
- receiver = (pm_node_t *)pm_false_node_create(parser, &identifier);
17864
+ receiver = (pm_node_t *) pm_false_node_create(parser, &identifier);
17607
17865
  break;
17608
17866
  case PM_TOKEN_KEYWORD___FILE__:
17609
17867
  receiver = (pm_node_t *) pm_source_file_node_create(parser, &identifier);
@@ -17625,9 +17883,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17625
17883
  break;
17626
17884
  }
17627
17885
  case PM_TOKEN_PARENTHESIS_LEFT: {
17628
- // The current context is `PM_CONTEXT_DEF_PARAMS`, however the inner expression
17629
- // of this parenthesis should not be processed under this context.
17630
- // Thus, the context is popped here.
17886
+ // The current context is `PM_CONTEXT_DEF_PARAMS`, however
17887
+ // the inner expression of this parenthesis should not be
17888
+ // processed under this context. Thus, the context is popped
17889
+ // here.
17631
17890
  context_pop(parser);
17632
17891
  parser_lex(parser);
17633
17892
 
@@ -17644,7 +17903,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17644
17903
  operator = parser->previous;
17645
17904
  receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
17646
17905
 
17647
- // To push `PM_CONTEXT_DEF_PARAMS` again is for the same reason as described the above.
17906
+ // To push `PM_CONTEXT_DEF_PARAMS` again is for the same
17907
+ // reason as described the above.
17648
17908
  pm_parser_scope_push(parser, true);
17649
17909
  context_push(parser, PM_CONTEXT_DEF_PARAMS);
17650
17910
  name = parse_method_definition_name(parser);
@@ -17656,12 +17916,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17656
17916
  break;
17657
17917
  }
17658
17918
 
17659
- // If, after all that, we were unable to find a method name, add an
17660
- // error to the error list.
17661
- if (name.type == PM_TOKEN_MISSING) {
17662
- pm_parser_err_previous(parser, PM_ERR_DEF_NAME);
17663
- }
17664
-
17665
17919
  pm_token_t lparen;
17666
17920
  pm_token_t rparen;
17667
17921
  pm_parameters_node_t *params;
@@ -17731,7 +17985,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17731
17985
  statement = (pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
17732
17986
  }
17733
17987
 
17734
- pm_statements_node_body_append((pm_statements_node_t *) statements, statement);
17988
+ pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement);
17735
17989
  pm_do_loop_stack_pop(parser);
17736
17990
  context_pop(parser);
17737
17991
  end_keyword = not_provided(parser);
@@ -17767,7 +18021,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17767
18021
  }
17768
18022
 
17769
18023
  pm_constant_id_list_t locals;
17770
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true);
18024
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
17771
18025
  pm_parser_scope_pop(parser);
17772
18026
 
17773
18027
  /**
@@ -18029,7 +18283,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18029
18283
  }
18030
18284
 
18031
18285
  pm_constant_id_list_t locals;
18032
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true);
18286
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
18033
18287
 
18034
18288
  pm_parser_scope_pop(parser);
18035
18289
  expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
@@ -18795,7 +19049,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18795
19049
  }
18796
19050
 
18797
19051
  pm_constant_id_list_t locals;
18798
- pm_locals_order(parser, &parser->current_scope->locals, &locals, !pm_parser_scope_toplevel_p(parser));
19052
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
18799
19053
  pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &operator, &parser->previous);
18800
19054
 
18801
19055
  pm_parser_scope_pop(parser);
@@ -18851,11 +19105,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18851
19105
  }
18852
19106
  }
18853
19107
 
18854
- static inline pm_node_t *
19108
+ /**
19109
+ * Parse a value that is going to be written to some kind of variable or method
19110
+ * call. We need to handle this separately because the rescue modifier is
19111
+ * permitted on the end of the these expressions, which is a deviation from its
19112
+ * normal binding power.
19113
+ *
19114
+ * Note that this will only be called after an operator write, as in &&=, ||=,
19115
+ * or any of the binary operators that can be written to a variable.
19116
+ */
19117
+ static pm_node_t *
18855
19118
  parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
18856
19119
  pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
18857
19120
 
18858
- // Contradicting binding powers, the right-hand-side value of rthe assignment allows the `rescue` modifier.
19121
+ // Contradicting binding powers, the right-hand-side value of the assignment
19122
+ // allows the `rescue` modifier.
18859
19123
  if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18860
19124
  context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18861
19125
 
@@ -18871,14 +19135,63 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_
18871
19135
  return value;
18872
19136
  }
18873
19137
 
19138
+ /**
19139
+ * When a local variable write node is the value being written in a different
19140
+ * write, the local variable is considered "used".
19141
+ */
19142
+ static void
19143
+ parse_assignment_value_local(pm_parser_t *parser, const pm_node_t *node) {
19144
+ switch (PM_NODE_TYPE(node)) {
19145
+ case PM_BEGIN_NODE: {
19146
+ const pm_begin_node_t *cast = (const pm_begin_node_t *) node;
19147
+ if (cast->statements != NULL) parse_assignment_value_local(parser, (const pm_node_t *) cast->statements);
19148
+ break;
19149
+ }
19150
+ case PM_LOCAL_VARIABLE_WRITE_NODE: {
19151
+ const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node;
19152
+ pm_locals_read(&pm_parser_scope_find(parser, cast->depth)->locals, cast->name);
19153
+ break;
19154
+ }
19155
+ case PM_PARENTHESES_NODE: {
19156
+ const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
19157
+ if (cast->body != NULL) parse_assignment_value_local(parser, cast->body);
19158
+ break;
19159
+ }
19160
+ case PM_STATEMENTS_NODE: {
19161
+ const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
19162
+ const pm_node_t *statement;
18874
19163
 
18875
- static inline pm_node_t *
19164
+ PM_NODE_LIST_FOREACH(&cast->body, index, statement) {
19165
+ parse_assignment_value_local(parser, statement);
19166
+ }
19167
+ break;
19168
+ }
19169
+ default:
19170
+ break;
19171
+ }
19172
+ }
19173
+
19174
+ /**
19175
+ * Parse the value (or values, through an implicit array) that is going to be
19176
+ * written to some kind of variable or method call. We need to handle this
19177
+ * separately because the rescue modifier is permitted on the end of the these
19178
+ * expressions, which is a deviation from its normal binding power.
19179
+ *
19180
+ * Additionally, if the value is a local variable write node (e.g., a = a = 1),
19181
+ * the "a" is marked as being used so the parser should not warn on it.
19182
+ *
19183
+ * Note that this will only be called after an = operator, as that is the only
19184
+ * operator that allows multiple values after it.
19185
+ */
19186
+ static pm_node_t *
18876
19187
  parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
18877
19188
  pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
18878
- bool single_value = true;
19189
+ parse_assignment_value_local(parser, value);
18879
19190
 
19191
+ bool single_value = true;
18880
19192
  if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
18881
19193
  single_value = false;
19194
+
18882
19195
  pm_token_t opening = not_provided(parser);
18883
19196
  pm_array_node_t *array = pm_array_node_create(parser, &opening);
18884
19197
 
@@ -18887,8 +19200,11 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
18887
19200
 
18888
19201
  while (accept1(parser, PM_TOKEN_COMMA)) {
18889
19202
  pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT);
19203
+
18890
19204
  pm_array_node_elements_append(array, element);
18891
19205
  if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
19206
+
19207
+ parse_assignment_value_local(parser, element);
18892
19208
  }
18893
19209
  }
18894
19210
 
@@ -19092,13 +19408,25 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19092
19408
  pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
19093
19409
  return parse_write(parser, (pm_node_t *) multi_target, &token, value);
19094
19410
  }
19411
+ case PM_SOURCE_ENCODING_NODE:
19412
+ case PM_FALSE_NODE:
19413
+ case PM_SOURCE_FILE_NODE:
19414
+ case PM_SOURCE_LINE_NODE:
19415
+ case PM_NIL_NODE:
19416
+ case PM_SELF_NODE:
19417
+ case PM_TRUE_NODE: {
19418
+ // In these special cases, we have specific error messages
19419
+ // and we will replace them with local variable writes.
19420
+ parser_lex(parser);
19421
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
19422
+ return parse_unwriteable_write(parser, node, &token, value);
19423
+ }
19095
19424
  default:
19425
+ // In this case we have an = sign, but we don't know what
19426
+ // it's for. We need to treat it as an error. We'll mark it
19427
+ // as an error and skip past it.
19096
19428
  parser_lex(parser);
19097
-
19098
- // In this case we have an = sign, but we don't know what it's for. We
19099
- // need to treat it as an error. For now, we'll mark it as an error
19100
- // and just skip right past it.
19101
- pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
19429
+ pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
19102
19430
  return node;
19103
19431
  }
19104
19432
  }
@@ -19173,7 +19501,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19173
19501
  pm_location_t *message_loc = &cast->message_loc;
19174
19502
  pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
19175
19503
 
19176
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 0);
19504
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
19177
19505
  pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
19178
19506
  pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
19179
19507
 
@@ -19286,7 +19614,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19286
19614
  pm_location_t *message_loc = &cast->message_loc;
19287
19615
  pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
19288
19616
 
19289
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 0);
19617
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
19290
19618
  pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
19291
19619
  pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
19292
19620
 
@@ -19409,7 +19737,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19409
19737
  pm_location_t *message_loc = &cast->message_loc;
19410
19738
  pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
19411
19739
 
19412
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 0);
19740
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
19413
19741
  pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
19414
19742
  pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
19415
19743
 
@@ -19593,7 +19921,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19593
19921
  break;
19594
19922
  }
19595
19923
  default: {
19596
- pm_parser_err_current(parser, PM_ERR_DEF_NAME);
19924
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_type_human(parser->current.type));
19597
19925
  message = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
19598
19926
  }
19599
19927
  }
@@ -19640,7 +19968,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19640
19968
  case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
19641
19969
  parser_lex(parser);
19642
19970
  pm_statements_node_t *statements = pm_statements_node_create(parser);
19643
- pm_statements_node_body_append(statements, node);
19971
+ pm_statements_node_body_append(parser, statements, node);
19644
19972
 
19645
19973
  pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19646
19974
  return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
@@ -19648,7 +19976,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19648
19976
  case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
19649
19977
  parser_lex(parser);
19650
19978
  pm_statements_node_t *statements = pm_statements_node_create(parser);
19651
- pm_statements_node_body_append(statements, node);
19979
+ pm_statements_node_body_append(parser, statements, node);
19652
19980
 
19653
19981
  pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19654
19982
  return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
@@ -19993,7 +20321,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
19993
20321
  (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2))
19994
20322
  );
19995
20323
 
19996
- pm_statements_node_body_append(statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
20324
+ pm_statements_node_body_append(parser, statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
19997
20325
  parser,
19998
20326
  arguments,
19999
20327
  pm_parser_constant_id_constant(parser, "print", 5)
@@ -20039,7 +20367,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
20039
20367
  }
20040
20368
 
20041
20369
  pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
20042
- pm_statements_node_body_append(wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
20370
+ pm_statements_node_body_append(parser, wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
20043
20371
  parser,
20044
20372
  (pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser, "gets", 4)),
20045
20373
  statements
@@ -20065,12 +20393,19 @@ parse_program(pm_parser_t *parser) {
20065
20393
 
20066
20394
  parser_lex(parser);
20067
20395
  pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_MAIN);
20068
- if (!statements) {
20396
+
20397
+ if (statements == NULL) {
20069
20398
  statements = pm_statements_node_create(parser);
20399
+ } else if (!parser->parsing_eval) {
20400
+ // If we have statements, then the top-level statement should be
20401
+ // explicitly checked as well. We have to do this here because
20402
+ // everywhere else we check all but the last statement.
20403
+ assert(statements->body.size > 0);
20404
+ pm_void_statement_check(parser, statements->body.nodes[statements->body.size - 1]);
20070
20405
  }
20071
20406
 
20072
20407
  pm_constant_id_list_t locals;
20073
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
20408
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, true);
20074
20409
  pm_parser_scope_pop(parser);
20075
20410
 
20076
20411
  // If this is an empty file, then we're still going to parse all of the
@@ -20517,7 +20852,7 @@ pm_parse_success_p(const uint8_t *source, size_t size, const char *data) {
20517
20852
  pm_node_t *node = pm_parse(&parser);
20518
20853
  pm_node_destroy(&parser, node);
20519
20854
 
20520
- bool result = parser.error_list.size == 0 && parser.warning_list.size == 0;
20855
+ bool result = parser.error_list.size == 0;
20521
20856
  pm_parser_free(&parser);
20522
20857
  pm_options_free(&options);
20523
20858
 
@@ -20919,6 +21254,8 @@ pm_parser_errors_format(const pm_parser_t *parser, const pm_list_t *error_list,
20919
21254
 
20920
21255
  if (inline_messages) {
20921
21256
  pm_buffer_append_byte(buffer, ' ');
21257
+ assert(error->error != NULL);
21258
+
20922
21259
  const char *message = error->error->message;
20923
21260
  pm_buffer_append_string(buffer, message, strlen(message));
20924
21261
  }