prism 0.28.0 → 0.30.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/CONTRIBUTING.md +0 -4
  4. data/README.md +1 -0
  5. data/config.yml +95 -26
  6. data/docs/fuzzing.md +1 -1
  7. data/docs/ripper_translation.md +22 -0
  8. data/ext/prism/api_node.c +70 -52
  9. data/ext/prism/extconf.rb +27 -23
  10. data/ext/prism/extension.c +107 -372
  11. data/ext/prism/extension.h +1 -1
  12. data/include/prism/ast.h +170 -102
  13. data/include/prism/diagnostic.h +18 -3
  14. data/include/prism/node.h +0 -21
  15. data/include/prism/parser.h +23 -25
  16. data/include/prism/regexp.h +17 -8
  17. data/include/prism/static_literals.h +3 -2
  18. data/include/prism/util/pm_char.h +1 -2
  19. data/include/prism/util/pm_constant_pool.h +0 -8
  20. data/include/prism/util/pm_integer.h +16 -9
  21. data/include/prism/util/pm_string.h +0 -8
  22. data/include/prism/version.h +2 -2
  23. data/include/prism.h +0 -11
  24. data/lib/prism/compiler.rb +3 -0
  25. data/lib/prism/desugar_compiler.rb +4 -4
  26. data/lib/prism/dispatcher.rb +14 -0
  27. data/lib/prism/dot_visitor.rb +54 -35
  28. data/lib/prism/dsl.rb +23 -18
  29. data/lib/prism/ffi.rb +25 -4
  30. data/lib/prism/inspect_visitor.rb +26 -24
  31. data/lib/prism/mutation_compiler.rb +6 -1
  32. data/lib/prism/node.rb +314 -389
  33. data/lib/prism/node_ext.rb +175 -17
  34. data/lib/prism/parse_result/comments.rb +1 -8
  35. data/lib/prism/parse_result/newlines.rb +102 -12
  36. data/lib/prism/parse_result.rb +17 -0
  37. data/lib/prism/reflection.rb +11 -9
  38. data/lib/prism/serialize.rb +91 -68
  39. data/lib/prism/translation/parser/compiler.rb +288 -138
  40. data/lib/prism/translation/parser.rb +7 -2
  41. data/lib/prism/translation/ripper.rb +24 -22
  42. data/lib/prism/translation/ruby_parser.rb +32 -14
  43. data/lib/prism/visitor.rb +3 -0
  44. data/lib/prism.rb +0 -4
  45. data/prism.gemspec +2 -4
  46. data/rbi/prism/node.rbi +114 -57
  47. data/rbi/prism/node_ext.rbi +5 -0
  48. data/rbi/prism/parse_result.rbi +1 -1
  49. data/rbi/prism/visitor.rbi +3 -0
  50. data/rbi/prism.rbi +6 -0
  51. data/sig/prism/dsl.rbs +13 -10
  52. data/sig/prism/lex_compat.rbs +10 -0
  53. data/sig/prism/mutation_compiler.rbs +1 -0
  54. data/sig/prism/node.rbs +72 -48
  55. data/sig/prism/node_ext.rbs +4 -0
  56. data/sig/prism/visitor.rbs +1 -0
  57. data/sig/prism.rbs +21 -0
  58. data/src/diagnostic.c +56 -27
  59. data/src/node.c +432 -1690
  60. data/src/prettyprint.c +97 -54
  61. data/src/prism.c +1286 -1196
  62. data/src/regexp.c +133 -68
  63. data/src/serialize.c +22 -17
  64. data/src/static_literals.c +63 -84
  65. data/src/token_type.c +4 -4
  66. data/src/util/pm_constant_pool.c +0 -8
  67. data/src/util/pm_integer.c +39 -11
  68. data/src/util/pm_string.c +0 -12
  69. data/src/util/pm_strpbrk.c +32 -6
  70. metadata +3 -5
  71. data/include/prism/util/pm_string_list.h +0 -44
  72. data/lib/prism/debug.rb +0 -249
  73. data/src/util/pm_string_list.c +0 -28
data/src/regexp.c CHANGED
@@ -1,9 +1,14 @@
1
1
  #include "prism/regexp.h"
2
2
 
3
+ #define PM_REGEXP_PARSE_DEPTH_MAX 4096
4
+
3
5
  /**
4
6
  * This is the parser that is going to handle parsing regular expressions.
5
7
  */
6
8
  typedef struct {
9
+ /** The parser that is currently being used. */
10
+ pm_parser_t *parser;
11
+
7
12
  /** A pointer to the start of the source that we are parsing. */
8
13
  const uint8_t *start;
9
14
 
@@ -13,39 +18,42 @@ typedef struct {
13
18
  /** A pointer to the end of the source that we are parsing. */
14
19
  const uint8_t *end;
15
20
 
16
- /** A list of named captures that we've found. */
17
- pm_string_list_t *named_captures;
18
-
19
21
  /** Whether the encoding has changed from the default. */
20
22
  bool encoding_changed;
21
23
 
22
24
  /** The encoding of the source. */
23
25
  const pm_encoding_t *encoding;
26
+
27
+ /** The callback to call when a named capture group is found. */
28
+ pm_regexp_name_callback_t name_callback;
29
+
30
+ /** The data to pass to the name callback. */
31
+ void *name_data;
32
+
33
+ /** The callback to call when a parse error is found. */
34
+ pm_regexp_error_callback_t error_callback;
35
+
36
+ /** The data to pass to the error callback. */
37
+ void *error_data;
24
38
  } pm_regexp_parser_t;
25
39
 
26
40
  /**
27
- * This initializes a new parser with the given source.
41
+ * Append an error to the parser.
28
42
  */
29
- static void
30
- pm_regexp_parser_init(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_string_list_t *named_captures, bool encoding_changed, const pm_encoding_t *encoding) {
31
- *parser = (pm_regexp_parser_t) {
32
- .start = start,
33
- .cursor = start,
34
- .end = end,
35
- .named_captures = named_captures,
36
- .encoding_changed = encoding_changed,
37
- .encoding = encoding
38
- };
43
+ static inline void
44
+ pm_regexp_parse_error(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end, const char *message) {
45
+ parser->error_callback(start, end, message, parser->error_data);
39
46
  }
40
47
 
41
48
  /**
42
- * This appends a new string to the list of named captures.
49
+ * This appends a new string to the list of named captures. This function
50
+ * assumes the caller has already checked the validity of the name callback.
43
51
  */
44
52
  static void
45
53
  pm_regexp_parser_named_capture(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
46
54
  pm_string_t string;
47
55
  pm_string_shared_init(&string, start, end);
48
- pm_string_list_append(parser->named_captures, &string);
56
+ parser->name_callback(&string, parser->name_data);
49
57
  pm_string_free(&string);
50
58
  }
51
59
 
@@ -217,21 +225,24 @@ pm_regexp_parse_range_quantifier(pm_regexp_parser_t *parser) {
217
225
  */
218
226
  static bool
219
227
  pm_regexp_parse_quantifier(pm_regexp_parser_t *parser) {
220
- if (pm_regexp_char_is_eof(parser)) return true;
221
-
222
- switch (*parser->cursor) {
223
- case '*':
224
- case '+':
225
- case '?':
226
- parser->cursor++;
227
- return true;
228
- case '{':
229
- parser->cursor++;
230
- return pm_regexp_parse_range_quantifier(parser);
231
- default:
232
- // In this case there is no quantifier.
233
- return true;
228
+ while (!pm_regexp_char_is_eof(parser)) {
229
+ switch (*parser->cursor) {
230
+ case '*':
231
+ case '+':
232
+ case '?':
233
+ parser->cursor++;
234
+ break;
235
+ case '{':
236
+ parser->cursor++;
237
+ if (!pm_regexp_parse_range_quantifier(parser)) return false;
238
+ break;
239
+ default:
240
+ // In this case there is no quantifier.
241
+ return true;
242
+ }
234
243
  }
244
+
245
+ return true;
235
246
  }
236
247
 
237
248
  /**
@@ -255,20 +266,20 @@ pm_regexp_parse_posix_class(pm_regexp_parser_t *parser) {
255
266
 
256
267
  // Forward declaration because character sets can be nested.
257
268
  static bool
258
- pm_regexp_parse_lbracket(pm_regexp_parser_t *parser);
269
+ pm_regexp_parse_lbracket(pm_regexp_parser_t *parser, uint16_t depth);
259
270
 
260
271
  /**
261
272
  * match-char-set : '[' '^'? (match-range | match-char)* ']'
262
273
  * ;
263
274
  */
264
275
  static bool
265
- pm_regexp_parse_character_set(pm_regexp_parser_t *parser) {
276
+ pm_regexp_parse_character_set(pm_regexp_parser_t *parser, uint16_t depth) {
266
277
  pm_regexp_char_accept(parser, '^');
267
278
 
268
279
  while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ']') {
269
280
  switch (*parser->cursor++) {
270
281
  case '[':
271
- pm_regexp_parse_lbracket(parser);
282
+ pm_regexp_parse_lbracket(parser, (uint16_t) (depth + 1));
272
283
  break;
273
284
  case '\\':
274
285
  if (!pm_regexp_char_is_eof(parser)) {
@@ -288,7 +299,18 @@ pm_regexp_parse_character_set(pm_regexp_parser_t *parser) {
288
299
  * A left bracket can either mean a POSIX class or a character set.
289
300
  */
290
301
  static bool
291
- pm_regexp_parse_lbracket(pm_regexp_parser_t *parser) {
302
+ pm_regexp_parse_lbracket(pm_regexp_parser_t *parser, uint16_t depth) {
303
+ if (depth >= PM_REGEXP_PARSE_DEPTH_MAX) {
304
+ pm_regexp_parse_error(parser, parser->start, parser->end, "parse depth limit over");
305
+ return false;
306
+ }
307
+
308
+ if ((parser->cursor < parser->end) && parser->cursor[0] == ']') {
309
+ parser->cursor++;
310
+ pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "empty char-class");
311
+ return true;
312
+ }
313
+
292
314
  const uint8_t *reset = parser->cursor;
293
315
 
294
316
  if ((parser->cursor + 2 < parser->end) && parser->cursor[0] == '[' && parser->cursor[1] == ':') {
@@ -298,13 +320,13 @@ pm_regexp_parse_lbracket(pm_regexp_parser_t *parser) {
298
320
  parser->cursor = reset;
299
321
  }
300
322
 
301
- return pm_regexp_parse_character_set(parser);
323
+ return pm_regexp_parse_character_set(parser, depth);
302
324
  }
303
325
 
304
326
  // Forward declaration here since parsing groups needs to go back up the grammar
305
327
  // to parse expressions within them.
306
328
  static bool
307
- pm_regexp_parse_expression(pm_regexp_parser_t *parser);
329
+ pm_regexp_parse_expression(pm_regexp_parser_t *parser, uint16_t depth);
308
330
 
309
331
  /**
310
332
  * These are the states of the options that are configurable on the regular
@@ -418,17 +440,27 @@ pm_regexp_options_remove(pm_regexp_options_t *options, uint8_t key) {
418
440
  * * (?imxdau-imx:subexp) - turn on and off configuration for an expression
419
441
  */
420
442
  static bool
421
- pm_regexp_parse_group(pm_regexp_parser_t *parser) {
443
+ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) {
444
+ const uint8_t *group_start = parser->cursor;
445
+
422
446
  // First, parse any options for the group.
423
447
  if (pm_regexp_char_accept(parser, '?')) {
424
448
  if (pm_regexp_char_is_eof(parser)) {
449
+ pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern in group");
425
450
  return false;
426
451
  }
452
+
427
453
  pm_regexp_options_t options;
428
454
  pm_regexp_options_init(&options);
429
455
 
430
456
  switch (*parser->cursor) {
431
457
  case '#': { // inline comments
458
+ parser->cursor++;
459
+ if (pm_regexp_char_is_eof(parser)) {
460
+ pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern in group");
461
+ return false;
462
+ }
463
+
432
464
  if (parser->encoding_changed && parser->encoding->multibyte) {
433
465
  bool escaped = false;
434
466
 
@@ -472,6 +504,7 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser) {
472
504
  case '<':
473
505
  parser->cursor++;
474
506
  if (pm_regexp_char_is_eof(parser)) {
507
+ pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern with unmatched parenthesis");
475
508
  return false;
476
509
  }
477
510
 
@@ -485,7 +518,15 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser) {
485
518
  if (!pm_regexp_char_find(parser, '>')) {
486
519
  return false;
487
520
  }
488
- pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
521
+
522
+ if (parser->cursor - start == 1) {
523
+ pm_regexp_parse_error(parser, start, parser->cursor, "group name is empty");
524
+ }
525
+
526
+ if (parser->name_callback != NULL) {
527
+ pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
528
+ }
529
+
489
530
  break;
490
531
  }
491
532
  }
@@ -496,7 +537,10 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser) {
496
537
  return false;
497
538
  }
498
539
 
499
- pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
540
+ if (parser->name_callback != NULL) {
541
+ pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
542
+ }
543
+
500
544
  break;
501
545
  }
502
546
  case '(': // conditional expression
@@ -535,20 +579,25 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser) {
535
579
  }
536
580
  break;
537
581
  default:
538
- return false;
582
+ parser->cursor++;
583
+ pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "undefined group option");
584
+ break;
539
585
  }
540
586
  }
541
587
 
542
588
  // Now, parse the expressions within this group.
543
589
  while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ')') {
544
- if (!pm_regexp_parse_expression(parser)) {
590
+ if (!pm_regexp_parse_expression(parser, (uint16_t) (depth + 1))) {
545
591
  return false;
546
592
  }
547
593
  pm_regexp_char_accept(parser, '|');
548
594
  }
549
595
 
550
596
  // Finally, make sure we have a closing parenthesis.
551
- return pm_regexp_char_expect(parser, ')');
597
+ if (pm_regexp_char_expect(parser, ')')) return true;
598
+
599
+ pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern with unmatched parenthesis");
600
+ return false;
552
601
  }
553
602
 
554
603
  /**
@@ -564,12 +613,12 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser) {
564
613
  * ;
565
614
  */
566
615
  static bool
567
- pm_regexp_parse_item(pm_regexp_parser_t *parser) {
616
+ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
568
617
  switch (*parser->cursor) {
569
618
  case '^':
570
619
  case '$':
571
620
  parser->cursor++;
572
- return true;
621
+ return pm_regexp_parse_quantifier(parser);
573
622
  case '\\':
574
623
  parser->cursor++;
575
624
  if (!pm_regexp_char_is_eof(parser)) {
@@ -578,10 +627,20 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser) {
578
627
  return pm_regexp_parse_quantifier(parser);
579
628
  case '(':
580
629
  parser->cursor++;
581
- return pm_regexp_parse_group(parser) && pm_regexp_parse_quantifier(parser);
630
+ return pm_regexp_parse_group(parser, depth) && pm_regexp_parse_quantifier(parser);
582
631
  case '[':
583
632
  parser->cursor++;
584
- return pm_regexp_parse_lbracket(parser) && pm_regexp_parse_quantifier(parser);
633
+ return pm_regexp_parse_lbracket(parser, depth) && pm_regexp_parse_quantifier(parser);
634
+ case '*':
635
+ case '?':
636
+ case '+':
637
+ parser->cursor++;
638
+ pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "target of repeat operator is not specified");
639
+ return true;
640
+ case ')':
641
+ parser->cursor++;
642
+ pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "unmatched close parenthesis");
643
+ return true;
585
644
  default: {
586
645
  size_t width;
587
646
  if (!parser->encoding_changed) {
@@ -603,13 +662,18 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser) {
603
662
  * ;
604
663
  */
605
664
  static bool
606
- pm_regexp_parse_expression(pm_regexp_parser_t *parser) {
607
- if (!pm_regexp_parse_item(parser)) {
665
+ pm_regexp_parse_expression(pm_regexp_parser_t *parser, uint16_t depth) {
666
+ if (depth >= PM_REGEXP_PARSE_DEPTH_MAX) {
667
+ pm_regexp_parse_error(parser, parser->start, parser->end, "parse depth limit over");
668
+ return false;
669
+ }
670
+
671
+ if (!pm_regexp_parse_item(parser, depth)) {
608
672
  return false;
609
673
  }
610
674
 
611
675
  while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ')' && *parser->cursor != '|') {
612
- if (!pm_regexp_parse_item(parser)) {
676
+ if (!pm_regexp_parse_item(parser, depth)) {
613
677
  return false;
614
678
  }
615
679
  }
@@ -625,29 +689,30 @@ pm_regexp_parse_expression(pm_regexp_parser_t *parser) {
625
689
  */
626
690
  static bool
627
691
  pm_regexp_parse_pattern(pm_regexp_parser_t *parser) {
628
- return (
629
- (
630
- // Exit early if the pattern is empty.
631
- pm_regexp_char_is_eof(parser) ||
632
- // Parse the first expression in the pattern.
633
- pm_regexp_parse_expression(parser)
634
- ) &&
635
- (
636
- // Return now if we've parsed the entire pattern.
637
- pm_regexp_char_is_eof(parser) ||
638
- // Otherwise, we should have a pipe character.
639
- (pm_regexp_char_expect(parser, '|') && pm_regexp_parse_pattern(parser))
640
- )
641
- );
692
+ do {
693
+ if (pm_regexp_char_is_eof(parser)) return true;
694
+ if (!pm_regexp_parse_expression(parser, 0)) return false;
695
+ } while (pm_regexp_char_accept(parser, '|'));
696
+
697
+ return pm_regexp_char_is_eof(parser);
642
698
  }
643
699
 
644
700
  /**
645
701
  * Parse a regular expression and extract the names of all of the named capture
646
702
  * groups.
647
703
  */
648
- PRISM_EXPORTED_FUNCTION bool
649
- pm_regexp_named_capture_group_names(const uint8_t *source, size_t size, pm_string_list_t *named_captures, bool encoding_changed, const pm_encoding_t *encoding) {
650
- pm_regexp_parser_t parser;
651
- pm_regexp_parser_init(&parser, source, source + size, named_captures, encoding_changed, encoding);
652
- return pm_regexp_parse_pattern(&parser);
704
+ PRISM_EXPORTED_FUNCTION void
705
+ pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data) {
706
+ pm_regexp_parse_pattern(&(pm_regexp_parser_t) {
707
+ .parser = parser,
708
+ .start = source,
709
+ .cursor = source,
710
+ .end = source + size,
711
+ .encoding_changed = parser->encoding_changed,
712
+ .encoding = parser->encoding,
713
+ .name_callback = name_callback,
714
+ .name_data = name_data,
715
+ .error_callback = error_callback,
716
+ .error_data = error_data
717
+ });
653
718
  }
data/src/serialize.c CHANGED
@@ -407,8 +407,8 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
407
407
  }
408
408
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->read_name));
409
409
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->write_name));
410
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->operator));
411
- pm_serialize_location(parser, &((pm_call_operator_write_node_t *)node)->operator_loc, buffer);
410
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->binary_operator));
411
+ pm_serialize_location(parser, &((pm_call_operator_write_node_t *)node)->binary_operator_loc, buffer);
412
412
  pm_serialize_node(parser, (pm_node_t *)((pm_call_operator_write_node_t *)node)->value, buffer);
413
413
  break;
414
414
  }
@@ -529,9 +529,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
529
529
  case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE: {
530
530
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_class_variable_operator_write_node_t *)node)->name));
531
531
  pm_serialize_location(parser, &((pm_class_variable_operator_write_node_t *)node)->name_loc, buffer);
532
- pm_serialize_location(parser, &((pm_class_variable_operator_write_node_t *)node)->operator_loc, buffer);
532
+ pm_serialize_location(parser, &((pm_class_variable_operator_write_node_t *)node)->binary_operator_loc, buffer);
533
533
  pm_serialize_node(parser, (pm_node_t *)((pm_class_variable_operator_write_node_t *)node)->value, buffer);
534
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_class_variable_operator_write_node_t *)node)->operator));
534
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_class_variable_operator_write_node_t *)node)->binary_operator));
535
535
  break;
536
536
  }
537
537
  case PM_CLASS_VARIABLE_OR_WRITE_NODE: {
@@ -566,9 +566,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
566
566
  case PM_CONSTANT_OPERATOR_WRITE_NODE: {
567
567
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_constant_operator_write_node_t *)node)->name));
568
568
  pm_serialize_location(parser, &((pm_constant_operator_write_node_t *)node)->name_loc, buffer);
569
- pm_serialize_location(parser, &((pm_constant_operator_write_node_t *)node)->operator_loc, buffer);
569
+ pm_serialize_location(parser, &((pm_constant_operator_write_node_t *)node)->binary_operator_loc, buffer);
570
570
  pm_serialize_node(parser, (pm_node_t *)((pm_constant_operator_write_node_t *)node)->value, buffer);
571
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_constant_operator_write_node_t *)node)->operator));
571
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_constant_operator_write_node_t *)node)->binary_operator));
572
572
  break;
573
573
  }
574
574
  case PM_CONSTANT_OR_WRITE_NODE: {
@@ -597,9 +597,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
597
597
  }
598
598
  case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: {
599
599
  pm_serialize_node(parser, (pm_node_t *)((pm_constant_path_operator_write_node_t *)node)->target, buffer);
600
- pm_serialize_location(parser, &((pm_constant_path_operator_write_node_t *)node)->operator_loc, buffer);
600
+ pm_serialize_location(parser, &((pm_constant_path_operator_write_node_t *)node)->binary_operator_loc, buffer);
601
601
  pm_serialize_node(parser, (pm_node_t *)((pm_constant_path_operator_write_node_t *)node)->value, buffer);
602
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_constant_path_operator_write_node_t *)node)->operator));
602
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_constant_path_operator_write_node_t *)node)->binary_operator));
603
603
  break;
604
604
  }
605
605
  case PM_CONSTANT_PATH_OR_WRITE_NODE: {
@@ -852,9 +852,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
852
852
  case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: {
853
853
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_global_variable_operator_write_node_t *)node)->name));
854
854
  pm_serialize_location(parser, &((pm_global_variable_operator_write_node_t *)node)->name_loc, buffer);
855
- pm_serialize_location(parser, &((pm_global_variable_operator_write_node_t *)node)->operator_loc, buffer);
855
+ pm_serialize_location(parser, &((pm_global_variable_operator_write_node_t *)node)->binary_operator_loc, buffer);
856
856
  pm_serialize_node(parser, (pm_node_t *)((pm_global_variable_operator_write_node_t *)node)->value, buffer);
857
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_global_variable_operator_write_node_t *)node)->operator));
857
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_global_variable_operator_write_node_t *)node)->binary_operator));
858
858
  break;
859
859
  }
860
860
  case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: {
@@ -1032,8 +1032,8 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
1032
1032
  } else {
1033
1033
  pm_serialize_node(parser, (pm_node_t *)((pm_index_operator_write_node_t *)node)->block, buffer);
1034
1034
  }
1035
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_index_operator_write_node_t *)node)->operator));
1036
- pm_serialize_location(parser, &((pm_index_operator_write_node_t *)node)->operator_loc, buffer);
1035
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_index_operator_write_node_t *)node)->binary_operator));
1036
+ pm_serialize_location(parser, &((pm_index_operator_write_node_t *)node)->binary_operator_loc, buffer);
1037
1037
  pm_serialize_node(parser, (pm_node_t *)((pm_index_operator_write_node_t *)node)->value, buffer);
1038
1038
  break;
1039
1039
  }
@@ -1093,9 +1093,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
1093
1093
  case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: {
1094
1094
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_instance_variable_operator_write_node_t *)node)->name));
1095
1095
  pm_serialize_location(parser, &((pm_instance_variable_operator_write_node_t *)node)->name_loc, buffer);
1096
- pm_serialize_location(parser, &((pm_instance_variable_operator_write_node_t *)node)->operator_loc, buffer);
1096
+ pm_serialize_location(parser, &((pm_instance_variable_operator_write_node_t *)node)->binary_operator_loc, buffer);
1097
1097
  pm_serialize_node(parser, (pm_node_t *)((pm_instance_variable_operator_write_node_t *)node)->value, buffer);
1098
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_instance_variable_operator_write_node_t *)node)->operator));
1098
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_instance_variable_operator_write_node_t *)node)->binary_operator));
1099
1099
  break;
1100
1100
  }
1101
1101
  case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: {
@@ -1198,6 +1198,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
1198
1198
  pm_serialize_location(parser, &((pm_interpolated_x_string_node_t *)node)->closing_loc, buffer);
1199
1199
  break;
1200
1200
  }
1201
+ case PM_IT_LOCAL_VARIABLE_READ_NODE: {
1202
+ break;
1203
+ }
1201
1204
  case PM_IT_PARAMETERS_NODE: {
1202
1205
  break;
1203
1206
  }
@@ -1253,10 +1256,10 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
1253
1256
  }
1254
1257
  case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: {
1255
1258
  pm_serialize_location(parser, &((pm_local_variable_operator_write_node_t *)node)->name_loc, buffer);
1256
- pm_serialize_location(parser, &((pm_local_variable_operator_write_node_t *)node)->operator_loc, buffer);
1259
+ pm_serialize_location(parser, &((pm_local_variable_operator_write_node_t *)node)->binary_operator_loc, buffer);
1257
1260
  pm_serialize_node(parser, (pm_node_t *)((pm_local_variable_operator_write_node_t *)node)->value, buffer);
1258
1261
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_local_variable_operator_write_node_t *)node)->name));
1259
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_local_variable_operator_write_node_t *)node)->operator));
1262
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_local_variable_operator_write_node_t *)node)->binary_operator));
1260
1263
  pm_buffer_append_varuint(buffer, ((pm_local_variable_operator_write_node_t *)node)->depth);
1261
1264
  break;
1262
1265
  }
@@ -1550,7 +1553,9 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
1550
1553
  break;
1551
1554
  }
1552
1555
  case PM_RATIONAL_NODE: {
1553
- pm_serialize_node(parser, (pm_node_t *)((pm_rational_node_t *)node)->numeric, buffer);
1556
+ pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK));
1557
+ pm_serialize_integer(&((pm_rational_node_t *)node)->numerator, buffer);
1558
+ pm_serialize_integer(&((pm_rational_node_t *)node)->denominator, buffer);
1554
1559
  break;
1555
1560
  }
1556
1561
  case PM_REDO_NODE: {