prism 0.25.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }