prism 0.30.0 → 1.0.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -1
  3. data/README.md +3 -1
  4. data/config.yml +185 -126
  5. data/docs/serialization.md +3 -0
  6. data/ext/prism/api_node.c +2843 -2085
  7. data/ext/prism/extconf.rb +1 -1
  8. data/ext/prism/extension.c +35 -25
  9. data/ext/prism/extension.h +2 -2
  10. data/include/prism/ast.h +1048 -69
  11. data/include/prism/defines.h +9 -0
  12. data/include/prism/diagnostic.h +11 -3
  13. data/include/prism/options.h +55 -1
  14. data/include/prism/parser.h +27 -3
  15. data/include/prism/regexp.h +2 -1
  16. data/include/prism/util/pm_integer.h +6 -6
  17. data/include/prism/util/pm_newline_list.h +11 -0
  18. data/include/prism/util/pm_string.h +1 -0
  19. data/include/prism/version.h +3 -3
  20. data/lib/prism/desugar_compiler.rb +111 -74
  21. data/lib/prism/dispatcher.rb +2 -1
  22. data/lib/prism/dot_visitor.rb +21 -31
  23. data/lib/prism/dsl.rb +656 -471
  24. data/lib/prism/ffi.rb +3 -0
  25. data/lib/prism/inspect_visitor.rb +285 -57
  26. data/lib/prism/mutation_compiler.rb +5 -5
  27. data/lib/prism/node.rb +2282 -4754
  28. data/lib/prism/node_ext.rb +72 -11
  29. data/lib/prism/parse_result/errors.rb +65 -0
  30. data/lib/prism/parse_result/newlines.rb +28 -28
  31. data/lib/prism/parse_result.rb +25 -2
  32. data/lib/prism/reflection.rb +7 -7
  33. data/lib/prism/serialize.rb +468 -610
  34. data/lib/prism/translation/parser/compiler.rb +18 -18
  35. data/lib/prism/translation/parser/lexer.rb +1 -1
  36. data/lib/prism/translation/parser.rb +3 -3
  37. data/lib/prism/translation/ripper.rb +14 -14
  38. data/lib/prism/translation/ruby_parser.rb +43 -7
  39. data/prism.gemspec +3 -1
  40. data/rbi/prism/dsl.rbi +521 -0
  41. data/rbi/prism/node.rbi +1456 -5616
  42. data/rbi/prism.rbi +16 -16
  43. data/sig/prism/dsl.rbs +189 -305
  44. data/sig/prism/node.rbs +702 -603
  45. data/sig/prism/parse_result.rbs +2 -0
  46. data/src/diagnostic.c +22 -6
  47. data/src/node.c +277 -284
  48. data/src/options.c +18 -0
  49. data/src/prettyprint.c +99 -108
  50. data/src/prism.c +1282 -760
  51. data/src/regexp.c +72 -4
  52. data/src/serialize.c +165 -50
  53. data/src/token_type.c +2 -2
  54. data/src/util/pm_integer.c +14 -14
  55. data/src/util/pm_newline_list.c +29 -0
  56. data/src/util/pm_string.c +9 -5
  57. metadata +4 -2
@@ -118,6 +118,15 @@
118
118
  # endif
119
119
  #endif
120
120
 
121
+ /**
122
+ * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem
123
+ * related code from the library. All filesystem related code should be guarded
124
+ * by PRISM_HAS_FILESYSTEM.
125
+ */
126
+ #ifndef PRISM_HAS_NO_FILESYSTEM
127
+ # define PRISM_HAS_FILESYSTEM
128
+ #endif
129
+
121
130
  /**
122
131
  * isinf on Windows is defined as accepting a float, but on POSIX systems it
123
132
  * accepts a float, a double, or a long double. We want to mirror this behavior
@@ -1,10 +1,10 @@
1
- /******************************************************************************/
1
+ /*----------------------------------------------------------------------------*/
2
2
  /* This file is generated by the templates/template.rb script and should not */
3
3
  /* be modified manually. See */
4
4
  /* templates/include/prism/diagnostic.h.erb */
5
5
  /* if you are looking to modify the */
6
6
  /* template */
7
- /******************************************************************************/
7
+ /*----------------------------------------------------------------------------*/
8
8
 
9
9
  /**
10
10
  * @file diagnostic.h
@@ -110,8 +110,10 @@ typedef enum {
110
110
  PM_ERR_ESCAPE_INVALID_META_REPEAT,
111
111
  PM_ERR_ESCAPE_INVALID_UNICODE,
112
112
  PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS,
113
+ PM_ERR_ESCAPE_INVALID_UNICODE_LIST,
113
114
  PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL,
114
115
  PM_ERR_ESCAPE_INVALID_UNICODE_LONG,
116
+ PM_ERR_ESCAPE_INVALID_UNICODE_SHORT,
115
117
  PM_ERR_ESCAPE_INVALID_UNICODE_TERM,
116
118
  PM_ERR_EXPECT_ARGUMENT,
117
119
  PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
@@ -237,6 +239,7 @@ typedef enum {
237
239
  PM_ERR_PARAMETER_UNEXPECTED_FWD,
238
240
  PM_ERR_PARAMETER_UNEXPECTED_NO_KW,
239
241
  PM_ERR_PARAMETER_WILD_LOOSE_COMMA,
242
+ PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS,
240
243
  PM_ERR_PATTERN_CAPTURE_DUPLICATE,
241
244
  PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET,
242
245
  PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA,
@@ -248,6 +251,7 @@ typedef enum {
248
251
  PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE,
249
252
  PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE,
250
253
  PM_ERR_PATTERN_EXPRESSION_AFTER_REST,
254
+ PM_ERR_PATTERN_FIND_MISSING_INNER,
251
255
  PM_ERR_PATTERN_HASH_IMPLICIT,
252
256
  PM_ERR_PATTERN_HASH_KEY,
253
257
  PM_ERR_PATTERN_HASH_KEY_DUPLICATE,
@@ -290,11 +294,14 @@ typedef enum {
290
294
  PM_ERR_TERNARY_COLON,
291
295
  PM_ERR_TERNARY_EXPRESSION_FALSE,
292
296
  PM_ERR_TERNARY_EXPRESSION_TRUE,
297
+ PM_ERR_UNARY_DISALLOWED,
293
298
  PM_ERR_UNARY_RECEIVER,
294
299
  PM_ERR_UNDEF_ARGUMENT,
295
300
  PM_ERR_UNEXPECTED_BLOCK_ARGUMENT,
296
301
  PM_ERR_UNEXPECTED_INDEX_BLOCK,
297
302
  PM_ERR_UNEXPECTED_INDEX_KEYWORDS,
303
+ PM_ERR_UNEXPECTED_MULTI_WRITE,
304
+ PM_ERR_UNEXPECTED_RANGE_OPERATOR,
298
305
  PM_ERR_UNEXPECTED_SAFE_NAVIGATION,
299
306
  PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
300
307
  PM_ERR_UNEXPECTED_TOKEN_IGNORE,
@@ -323,10 +330,11 @@ typedef enum {
323
330
  PM_WARN_DUPLICATED_WHEN_CLAUSE,
324
331
  PM_WARN_FLOAT_OUT_OF_RANGE,
325
332
  PM_WARN_IGNORED_FROZEN_STRING_LITERAL,
333
+ PM_WARN_INDENTATION_MISMATCH,
326
334
  PM_WARN_INTEGER_IN_FLIP_FLOP,
327
335
  PM_WARN_INVALID_CHARACTER,
336
+ PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
328
337
  PM_WARN_INVALID_NUMBERED_REFERENCE,
329
- PM_WARN_INVALID_SHAREABLE_CONSTANT_VALUE,
330
338
  PM_WARN_KEYWORD_EOL,
331
339
  PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
332
340
  PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
@@ -40,6 +40,23 @@ typedef struct pm_options_scope {
40
40
  pm_string_t *locals;
41
41
  } pm_options_scope_t;
42
42
 
43
+ // Forward declaration needed by the callback typedef.
44
+ struct pm_options;
45
+
46
+ /**
47
+ * The callback called when additional switches are found in a shebang comment
48
+ * that need to be processed by the runtime.
49
+ *
50
+ * @param options The options struct that may be updated by this callback.
51
+ * Certain fields will be checked for changes, specifically encoding,
52
+ * command_line, and frozen_string_literal.
53
+ * @param source The source of the shebang comment.
54
+ * @param length The length of the source.
55
+ * @param shebang_callback_data Any additional data that should be passed along
56
+ * to the callback.
57
+ */
58
+ typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const uint8_t *source, size_t length, void *shebang_callback_data);
59
+
43
60
  /**
44
61
  * The version of Ruby syntax that we should be parsing with. This is used to
45
62
  * allow consumers to specify which behavior they want in case they need to
@@ -56,7 +73,19 @@ typedef enum {
56
73
  /**
57
74
  * The options that can be passed to the parser.
58
75
  */
59
- typedef struct {
76
+ typedef struct pm_options {
77
+ /**
78
+ * The callback to call when additional switches are found in a shebang
79
+ * comment.
80
+ */
81
+ pm_options_shebang_callback_t shebang_callback;
82
+
83
+ /**
84
+ * Any additional data that should be passed along to the shebang callback
85
+ * if one was set.
86
+ */
87
+ void *shebang_callback_data;
88
+
60
89
  /** The name of the file that is currently being parsed. */
61
90
  pm_string_t filepath;
62
91
 
@@ -103,6 +132,13 @@ typedef struct {
103
132
  * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
104
133
  */
105
134
  int8_t frozen_string_literal;
135
+
136
+ /**
137
+ * Whether or not the encoding magic comments should be respected. This is a
138
+ * niche use-case where you want to parse a file with a specific encoding
139
+ * but ignore any encoding magic comments at the top of the file.
140
+ */
141
+ bool encoding_locked;
106
142
  } pm_options_t;
107
143
 
108
144
  /**
@@ -142,6 +178,16 @@ static const uint8_t PM_OPTIONS_COMMAND_LINE_P = 0x10;
142
178
  */
143
179
  static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
144
180
 
181
+ /**
182
+ * Set the shebang callback option on the given options struct.
183
+ *
184
+ * @param options The options struct to set the shebang callback on.
185
+ * @param shebang_callback The shebang callback to set.
186
+ * @param shebang_callback_data Any additional data that should be passed along
187
+ * to the callback.
188
+ */
189
+ PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data);
190
+
145
191
  /**
146
192
  * Set the filepath option on the given options struct.
147
193
  *
@@ -166,6 +212,14 @@ PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t
166
212
  */
167
213
  PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding);
168
214
 
215
+ /**
216
+ * Set the encoding_locked option on the given options struct.
217
+ *
218
+ * @param options The options struct to set the encoding_locked value on.
219
+ * @param encoding_locked The encoding_locked value to set.
220
+ */
221
+ PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked);
222
+
169
223
  /**
170
224
  * Set the frozen string literal option on the given options struct.
171
225
  *
@@ -364,6 +364,9 @@ typedef enum {
364
364
  /** a rescue statement within a lambda expression */
365
365
  PM_CONTEXT_LAMBDA_RESCUE,
366
366
 
367
+ /** the predicate clause of a loop statement */
368
+ PM_CONTEXT_LOOP_PREDICATE,
369
+
367
370
  /** the top level context */
368
371
  PM_CONTEXT_MAIN,
369
372
 
@@ -505,9 +508,9 @@ typedef struct {
505
508
  /** The type of shareable constant value that can be set. */
506
509
  typedef uint8_t pm_shareable_constant_value_t;
507
510
  static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0;
508
- static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = 0x1;
509
- static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = 0x2;
510
- static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = 0x4;
511
+ static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL;
512
+ static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING;
513
+ static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY;
511
514
 
512
515
  /**
513
516
  * This tracks an individual local variable in a certain lexical context, as
@@ -622,6 +625,13 @@ typedef uint32_t pm_state_stack_t;
622
625
  * it's considering.
623
626
  */
624
627
  struct pm_parser {
628
+ /**
629
+ * The next node identifier that will be assigned. This is a unique
630
+ * identifier used to track nodes such that the syntax tree can be dropped
631
+ * but the node can be found through another parse.
632
+ */
633
+ uint32_t node_id;
634
+
625
635
  /** The current state of the lexer. */
626
636
  pm_lex_state_t lex_state;
627
637
 
@@ -857,6 +867,14 @@ struct pm_parser {
857
867
  /** Whether or not we're currently recovering from a syntax error. */
858
868
  bool recovering;
859
869
 
870
+ /**
871
+ * This is very specialized behavior for when you want to parse in a context
872
+ * that does not respect encoding comments. Its main use case is translating
873
+ * into the whitequark/parser AST which re-encodes source files in UTF-8
874
+ * before they are parsed and ignores encoding comments.
875
+ */
876
+ bool encoding_locked;
877
+
860
878
  /**
861
879
  * Whether or not the encoding has been changed by a magic comment. We use
862
880
  * this to provide a fast path for the lexer instead of going through the
@@ -884,6 +902,12 @@ struct pm_parser {
884
902
  * characters.
885
903
  */
886
904
  bool current_regular_expression_ascii_only;
905
+
906
+ /**
907
+ * By default, Ruby always warns about mismatched indentation. This can be
908
+ * toggled with a magic comment.
909
+ */
910
+ bool warn_mismatched_indentation;
887
911
  };
888
912
 
889
913
  #endif
@@ -32,11 +32,12 @@ typedef void (*pm_regexp_error_callback_t)(const uint8_t *start, const uint8_t *
32
32
  * @param parser The parser that is currently being used.
33
33
  * @param source The source code to parse.
34
34
  * @param size The size of the source code.
35
+ * @param extended_mode Whether to parse the regular expression in extended mode.
35
36
  * @param name_callback The optional callback to call when a named capture group is found.
36
37
  * @param name_data The optional data to pass to the name callback.
37
38
  * @param error_callback The callback to call when a parse error is found.
38
39
  * @param error_data The data to pass to the error callback.
39
40
  */
40
- PRISM_EXPORTED_FUNCTION void 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);
41
+ PRISM_EXPORTED_FUNCTION void pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data);
41
42
 
42
43
  #endif
@@ -18,12 +18,6 @@
18
18
  * A structure represents an arbitrary-sized integer.
19
19
  */
20
20
  typedef struct {
21
- /**
22
- * Embedded value for small integer. This value is set to 0 if the value
23
- * does not fit into uint32_t.
24
- */
25
- uint32_t value;
26
-
27
21
  /**
28
22
  * The number of allocated values. length is set to 0 if the integer fits
29
23
  * into uint32_t.
@@ -35,6 +29,12 @@ typedef struct {
35
29
  */
36
30
  uint32_t *values;
37
31
 
32
+ /**
33
+ * Embedded value for small integer. This value is set to 0 if the value
34
+ * does not fit into uint32_t.
35
+ */
36
+ uint32_t value;
37
+
38
38
  /**
39
39
  * Whether or not the integer is negative. It is stored this way so that a
40
40
  * zeroed pm_integer_t is always positive zero.
@@ -80,6 +80,17 @@ pm_newline_list_clear(pm_newline_list_t *list);
80
80
  */
81
81
  bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor);
82
82
 
83
+ /**
84
+ * Returns the line of the given offset. If the offset is not in the list, the
85
+ * line of the closest offset less than the given offset is returned.
86
+ *
87
+ * @param list The list to search.
88
+ * @param cursor A pointer to the offset to search for.
89
+ * @param start_line The line to start counting from.
90
+ * @return The line of the given offset.
91
+ */
92
+ int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line);
93
+
83
94
  /**
84
95
  * Returns the line and column of the given offset. If the offset is not in the
85
96
  * list, the line and column of the closest offset less than the given offset
@@ -9,6 +9,7 @@
9
9
  #include "prism/defines.h"
10
10
 
11
11
  #include <assert.h>
12
+ #include <errno.h>
12
13
  #include <stdbool.h>
13
14
  #include <stddef.h>
14
15
  #include <stdlib.h>
@@ -9,12 +9,12 @@
9
9
  /**
10
10
  * The major version of the Prism library as an int.
11
11
  */
12
- #define PRISM_VERSION_MAJOR 0
12
+ #define PRISM_VERSION_MAJOR 1
13
13
 
14
14
  /**
15
15
  * The minor version of the Prism library as an int.
16
16
  */
17
- #define PRISM_VERSION_MINOR 30
17
+ #define PRISM_VERSION_MINOR 0
18
18
 
19
19
  /**
20
20
  * The patch version of the Prism library as an int.
@@ -24,6 +24,6 @@
24
24
  /**
25
25
  * The version of the Prism library as a constant string.
26
26
  */
27
- #define PRISM_VERSION "0.30.0"
27
+ #define PRISM_VERSION "1.0.0"
28
28
 
29
29
  #endif
@@ -2,11 +2,13 @@
2
2
 
3
3
  module Prism
4
4
  class DesugarAndWriteNode # :nodoc:
5
- attr_reader :node, :source, :read_class, :write_class, :arguments
5
+ include DSL
6
6
 
7
- def initialize(node, source, read_class, write_class, *arguments)
7
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
8
+
9
+ def initialize(node, default_source, read_class, write_class, **arguments)
8
10
  @node = node
9
- @source = source
11
+ @default_source = default_source
10
12
  @read_class = read_class
11
13
  @write_class = write_class
12
14
  @arguments = arguments
@@ -14,22 +16,30 @@ module Prism
14
16
 
15
17
  # Desugar `x &&= y` to `x && x = y`
16
18
  def compile
17
- AndNode.new(
18
- source,
19
- read_class.new(source, *arguments, node.name_loc),
20
- write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location),
21
- node.operator_loc,
22
- node.location
19
+ and_node(
20
+ location: node.location,
21
+ left: public_send(read_class, location: node.name_loc, **arguments),
22
+ right: public_send(
23
+ write_class,
24
+ location: node.location,
25
+ **arguments,
26
+ name_loc: node.name_loc,
27
+ value: node.value,
28
+ operator_loc: node.operator_loc
29
+ ),
30
+ operator_loc: node.operator_loc
23
31
  )
24
32
  end
25
33
  end
26
34
 
27
35
  class DesugarOrWriteDefinedNode # :nodoc:
28
- attr_reader :node, :source, :read_class, :write_class, :arguments
36
+ include DSL
37
+
38
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
29
39
 
30
- def initialize(node, source, read_class, write_class, *arguments)
40
+ def initialize(node, default_source, read_class, write_class, **arguments)
31
41
  @node = node
32
- @source = source
42
+ @default_source = default_source
33
43
  @read_class = read_class
34
44
  @write_class = write_class
35
45
  @arguments = arguments
@@ -37,35 +47,50 @@ module Prism
37
47
 
38
48
  # Desugar `x ||= y` to `defined?(x) ? x : x = y`
39
49
  def compile
40
- IfNode.new(
41
- source,
42
- node.operator_loc,
43
- DefinedNode.new(source, nil, read_class.new(source, *arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
44
- node.operator_loc,
45
- StatementsNode.new(source, [read_class.new(source, *arguments, node.name_loc)], node.location),
46
- ElseNode.new(
47
- source,
48
- node.operator_loc,
49
- StatementsNode.new(
50
- source,
51
- [write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location)],
52
- node.location
50
+ if_node(
51
+ location: node.location,
52
+ if_keyword_loc: node.operator_loc,
53
+ predicate: defined_node(
54
+ location: node.name_loc,
55
+ value: public_send(read_class, location: node.name_loc, **arguments),
56
+ keyword_loc: node.operator_loc
57
+ ),
58
+ then_keyword_loc: node.operator_loc,
59
+ statements: statements_node(
60
+ location: node.location,
61
+ body: [public_send(read_class, location: node.name_loc, **arguments)]
62
+ ),
63
+ subsequent: else_node(
64
+ location: node.location,
65
+ else_keyword_loc: node.operator_loc,
66
+ statements: statements_node(
67
+ location: node.location,
68
+ body: [
69
+ public_send(
70
+ write_class,
71
+ location: node.location,
72
+ **arguments,
73
+ name_loc: node.name_loc,
74
+ value: node.value,
75
+ operator_loc: node.operator_loc
76
+ )
77
+ ]
53
78
  ),
54
- node.operator_loc,
55
- node.location
79
+ end_keyword_loc: node.operator_loc
56
80
  ),
57
- node.operator_loc,
58
- node.location
81
+ end_keyword_loc: node.operator_loc
59
82
  )
60
83
  end
61
84
  end
62
85
 
63
86
  class DesugarOperatorWriteNode # :nodoc:
64
- attr_reader :node, :source, :read_class, :write_class, :arguments
87
+ include DSL
65
88
 
66
- def initialize(node, source, read_class, write_class, *arguments)
89
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
90
+
91
+ def initialize(node, default_source, read_class, write_class, **arguments)
67
92
  @node = node
68
- @source = source
93
+ @default_source = default_source
69
94
  @read_class = read_class
70
95
  @write_class = write_class
71
96
  @arguments = arguments
@@ -75,35 +100,41 @@ module Prism
75
100
  def compile
76
101
  binary_operator_loc = node.binary_operator_loc.chop
77
102
 
78
- write_class.new(
79
- source,
80
- *arguments,
81
- node.name_loc,
82
- CallNode.new(
83
- source,
84
- 0,
85
- read_class.new(source, *arguments, node.name_loc),
86
- nil,
87
- binary_operator_loc.slice.to_sym,
88
- binary_operator_loc,
89
- nil,
90
- ArgumentsNode.new(source, 0, [node.value], node.value.location),
91
- nil,
92
- nil,
93
- node.location
103
+ public_send(
104
+ write_class,
105
+ location: node.location,
106
+ **arguments,
107
+ name_loc: node.name_loc,
108
+ value: call_node(
109
+ location: node.location,
110
+ receiver: public_send(
111
+ read_class,
112
+ location: node.name_loc,
113
+ **arguments
114
+ ),
115
+ name: binary_operator_loc.slice.to_sym,
116
+ message_loc: binary_operator_loc,
117
+ arguments: arguments_node(
118
+ location: node.value.location,
119
+ arguments: [node.value]
120
+ )
94
121
  ),
95
- node.binary_operator_loc.copy(start_offset: node.binary_operator_loc.end_offset - 1, length: 1),
96
- node.location
122
+ operator_loc: node.binary_operator_loc.copy(
123
+ start_offset: node.binary_operator_loc.end_offset - 1,
124
+ length: 1
125
+ )
97
126
  )
98
127
  end
99
128
  end
100
129
 
101
130
  class DesugarOrWriteNode # :nodoc:
102
- attr_reader :node, :source, :read_class, :write_class, :arguments
131
+ include DSL
103
132
 
104
- def initialize(node, source, read_class, write_class, *arguments)
133
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
134
+
135
+ def initialize(node, default_source, read_class, write_class, **arguments)
105
136
  @node = node
106
- @source = source
137
+ @default_source = default_source
107
138
  @read_class = read_class
108
139
  @write_class = write_class
109
140
  @arguments = arguments
@@ -111,12 +142,18 @@ module Prism
111
142
 
112
143
  # Desugar `x ||= y` to `x || x = y`
113
144
  def compile
114
- OrNode.new(
115
- source,
116
- read_class.new(source, *arguments, node.name_loc),
117
- write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location),
118
- node.operator_loc,
119
- node.location
145
+ or_node(
146
+ location: node.location,
147
+ left: public_send(read_class, location: node.name_loc, **arguments),
148
+ right: public_send(
149
+ write_class,
150
+ location: node.location,
151
+ **arguments,
152
+ name_loc: node.name_loc,
153
+ value: node.value,
154
+ operator_loc: node.operator_loc
155
+ ),
156
+ operator_loc: node.operator_loc
120
157
  )
121
158
  end
122
159
  end
@@ -125,91 +162,91 @@ module Prism
125
162
 
126
163
  class ClassVariableAndWriteNode
127
164
  def desugar # :nodoc:
128
- DesugarAndWriteNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
165
+ DesugarAndWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
129
166
  end
130
167
  end
131
168
 
132
169
  class ClassVariableOrWriteNode
133
170
  def desugar # :nodoc:
134
- DesugarOrWriteDefinedNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
171
+ DesugarOrWriteDefinedNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
135
172
  end
136
173
  end
137
174
 
138
175
  class ClassVariableOperatorWriteNode
139
176
  def desugar # :nodoc:
140
- DesugarOperatorWriteNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
177
+ DesugarOperatorWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
141
178
  end
142
179
  end
143
180
 
144
181
  class ConstantAndWriteNode
145
182
  def desugar # :nodoc:
146
- DesugarAndWriteNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
183
+ DesugarAndWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
147
184
  end
148
185
  end
149
186
 
150
187
  class ConstantOrWriteNode
151
188
  def desugar # :nodoc:
152
- DesugarOrWriteDefinedNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
189
+ DesugarOrWriteDefinedNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
153
190
  end
154
191
  end
155
192
 
156
193
  class ConstantOperatorWriteNode
157
194
  def desugar # :nodoc:
158
- DesugarOperatorWriteNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
195
+ DesugarOperatorWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
159
196
  end
160
197
  end
161
198
 
162
199
  class GlobalVariableAndWriteNode
163
200
  def desugar # :nodoc:
164
- DesugarAndWriteNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
201
+ DesugarAndWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
165
202
  end
166
203
  end
167
204
 
168
205
  class GlobalVariableOrWriteNode
169
206
  def desugar # :nodoc:
170
- DesugarOrWriteDefinedNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
207
+ DesugarOrWriteDefinedNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
171
208
  end
172
209
  end
173
210
 
174
211
  class GlobalVariableOperatorWriteNode
175
212
  def desugar # :nodoc:
176
- DesugarOperatorWriteNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
213
+ DesugarOperatorWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
177
214
  end
178
215
  end
179
216
 
180
217
  class InstanceVariableAndWriteNode
181
218
  def desugar # :nodoc:
182
- DesugarAndWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
219
+ DesugarAndWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
183
220
  end
184
221
  end
185
222
 
186
223
  class InstanceVariableOrWriteNode
187
224
  def desugar # :nodoc:
188
- DesugarOrWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
225
+ DesugarOrWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
189
226
  end
190
227
  end
191
228
 
192
229
  class InstanceVariableOperatorWriteNode
193
230
  def desugar # :nodoc:
194
- DesugarOperatorWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
231
+ DesugarOperatorWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
195
232
  end
196
233
  end
197
234
 
198
235
  class LocalVariableAndWriteNode
199
236
  def desugar # :nodoc:
200
- DesugarAndWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
237
+ DesugarAndWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
201
238
  end
202
239
  end
203
240
 
204
241
  class LocalVariableOrWriteNode
205
242
  def desugar # :nodoc:
206
- DesugarOrWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
243
+ DesugarOrWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
207
244
  end
208
245
  end
209
246
 
210
247
  class LocalVariableOperatorWriteNode
211
248
  def desugar # :nodoc:
212
- DesugarOperatorWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
249
+ DesugarOperatorWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
213
250
  end
214
251
  end
215
252
 
@@ -22,7 +22,8 @@ module Prism
22
22
  # end
23
23
  # end
24
24
  #
25
- # dispatcher = Dispatcher.new
25
+ # listener = OctalListener.new
26
+ # dispatcher = Prism::Dispatcher.new
26
27
  # dispatcher.register(listener, :on_integer_node_enter)
27
28
  #
28
29
  # Then, you can walk any number of trees and dispatch events to the listeners: