prism 0.30.0 → 1.0.0

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