prism 0.28.0 → 0.30.0

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