prism 1.3.0 → 1.4.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -1
  3. data/config.yml +9 -0
  4. data/docs/releasing.md +1 -1
  5. data/docs/ruby_api.md +1 -1
  6. data/ext/prism/api_node.c +1814 -1303
  7. data/ext/prism/extension.c +230 -109
  8. data/ext/prism/extension.h +4 -4
  9. data/include/prism/ast.h +16 -0
  10. data/include/prism/defines.h +4 -1
  11. data/include/prism/options.h +47 -1
  12. data/include/prism/util/pm_buffer.h +10 -0
  13. data/include/prism/version.h +2 -2
  14. data/include/prism.h +4 -4
  15. data/lib/prism/dot_visitor.rb +16 -0
  16. data/lib/prism/dsl.rb +10 -2
  17. data/lib/prism/ffi.rb +45 -27
  18. data/lib/prism/inspect_visitor.rb +2 -1
  19. data/lib/prism/node.rb +48 -10
  20. data/lib/prism/parse_result/newlines.rb +1 -1
  21. data/lib/prism/parse_result.rb +52 -0
  22. data/lib/prism/polyfill/append_as_bytes.rb +15 -0
  23. data/lib/prism/reflection.rb +2 -2
  24. data/lib/prism/serialize.rb +1252 -765
  25. data/lib/prism/translation/parser/builder.rb +61 -0
  26. data/lib/prism/translation/parser/compiler.rb +192 -136
  27. data/lib/prism/translation/parser/lexer.rb +435 -61
  28. data/lib/prism/translation/parser.rb +51 -3
  29. data/lib/prism/translation/parser35.rb +12 -0
  30. data/lib/prism/translation/ripper.rb +13 -3
  31. data/lib/prism/translation/ruby_parser.rb +5 -4
  32. data/lib/prism/translation.rb +1 -0
  33. data/lib/prism.rb +3 -3
  34. data/prism.gemspec +5 -1
  35. data/rbi/prism/dsl.rbi +6 -3
  36. data/rbi/prism/node.rbi +22 -7
  37. data/rbi/prism/parse_result.rbi +17 -0
  38. data/rbi/prism/translation/parser35.rbi +6 -0
  39. data/rbi/prism.rbi +39 -36
  40. data/sig/prism/dsl.rbs +4 -2
  41. data/sig/prism/node.rbs +17 -7
  42. data/sig/prism/parse_result.rbs +10 -0
  43. data/sig/prism/serialize.rbs +4 -2
  44. data/sig/prism.rbs +22 -1
  45. data/src/diagnostic.c +2 -2
  46. data/src/node.c +21 -0
  47. data/src/options.c +31 -0
  48. data/src/prettyprint.c +30 -0
  49. data/src/prism.c +374 -118
  50. data/src/serialize.c +6 -0
  51. data/src/util/pm_buffer.c +40 -0
  52. data/src/util/pm_constant_pool.c +6 -2
  53. data/src/util/pm_strncasecmp.c +13 -1
  54. metadata +7 -7
@@ -9,6 +9,8 @@ module Prism
9
9
  attr_reader offsets: Array[Integer]
10
10
 
11
11
  def initialize: (String source, ?Integer start_line, ?Array[Integer] offsets) -> void
12
+ def replace_start_line: (Integer start_line) -> void
13
+ def replace_offsets: (Array[Integer] offsets) -> void
12
14
  def encoding: () -> Encoding
13
15
  def lines: () -> Array[String]
14
16
  def slice: (Integer byte_offset, Integer length) -> String
@@ -84,6 +86,7 @@ module Prism
84
86
 
85
87
  def initialize: (Location location) -> void
86
88
  def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
89
+ def slice: () -> String
87
90
  end
88
91
 
89
92
  interface _Comment
@@ -179,4 +182,11 @@ module Prism
179
182
  def pretty_print: (untyped q) -> untyped
180
183
  def ==: (untyped other) -> bool
181
184
  end
185
+
186
+ class Scope
187
+ attr_reader locals: Array[Symbol]
188
+ attr_reader forwarding: Array[Symbol]
189
+
190
+ def initialize: (Array[Symbol] locals, Array[Symbol] forwarding) -> void
191
+ end
182
192
  end
@@ -1,6 +1,8 @@
1
1
  module Prism
2
2
  module Serialize
3
- def self.load: (String, String) -> ParseResult
4
- def self.load_tokens: (Source, String) -> LexResult
3
+ def self.load_parse: (String, String, bool) -> ParseResult
4
+ def self.load_lex: (String, String, bool) -> LexResult
5
+ def self.load_parse_comments: (String, String, bool) -> Array[comment]
6
+ def self.load_parse_lex: (String, String, bool) -> ParseLexResult
5
7
  end
6
8
  end
data/sig/prism.rbs CHANGED
@@ -12,6 +12,7 @@ module Prism
12
12
  String source,
13
13
  ?encoding: Encoding | false,
14
14
  ?filepath: String,
15
+ ?freeze: bool,
15
16
  ?frozen_string_literal: bool,
16
17
  ?line: Integer,
17
18
  ?main_script: bool,
@@ -24,6 +25,7 @@ module Prism
24
25
  String source,
25
26
  ?encoding: Encoding | false,
26
27
  ?filepath: String,
28
+ ?freeze: bool,
27
29
  ?frozen_string_literal: bool,
28
30
  ?line: Integer,
29
31
  ?main_script: bool,
@@ -36,6 +38,7 @@ module Prism
36
38
  String source,
37
39
  ?encoding: Encoding | false,
38
40
  ?filepath: String,
41
+ ?freeze: bool,
39
42
  ?frozen_string_literal: bool,
40
43
  ?line: Integer,
41
44
  ?main_script: bool,
@@ -48,6 +51,7 @@ module Prism
48
51
  String source,
49
52
  ?encoding: Encoding | false,
50
53
  ?filepath: String,
54
+ ?freeze: bool,
51
55
  ?frozen_string_literal: bool,
52
56
  ?line: Integer,
53
57
  ?main_script: bool,
@@ -60,6 +64,7 @@ module Prism
60
64
  String source,
61
65
  ?encoding: Encoding | false,
62
66
  ?filepath: String,
67
+ ?freeze: bool,
63
68
  ?frozen_string_literal: bool,
64
69
  ?line: Integer,
65
70
  ?main_script: bool,
@@ -72,6 +77,7 @@ module Prism
72
77
  String source,
73
78
  ?encoding: Encoding | false,
74
79
  ?filepath: String,
80
+ ?freeze: bool,
75
81
  ?frozen_string_literal: bool,
76
82
  ?line: Integer,
77
83
  ?main_script: bool,
@@ -84,6 +90,7 @@ module Prism
84
90
  String source,
85
91
  ?encoding: Encoding | false,
86
92
  ?filepath: String,
93
+ ?freeze: bool,
87
94
  ?frozen_string_literal: bool,
88
95
  ?line: Integer,
89
96
  ?main_script: bool,
@@ -96,6 +103,7 @@ module Prism
96
103
  String source,
97
104
  ?encoding: Encoding | false,
98
105
  ?filepath: String,
106
+ ?freeze: bool,
99
107
  ?frozen_string_literal: bool,
100
108
  ?line: Integer,
101
109
  ?main_script: bool,
@@ -108,6 +116,7 @@ module Prism
108
116
  String source,
109
117
  ?encoding: Encoding | false,
110
118
  ?filepath: String,
119
+ ?freeze: bool,
111
120
  ?frozen_string_literal: bool,
112
121
  ?line: Integer,
113
122
  ?main_script: bool,
@@ -118,7 +127,8 @@ module Prism
118
127
 
119
128
  def self.load: (
120
129
  String source,
121
- String serialized
130
+ String serialized,
131
+ ?bool freeze
122
132
  ) -> ParseResult
123
133
 
124
134
  def self.lex_ripper: (
@@ -130,6 +140,7 @@ module Prism
130
140
  def self.parse_file: (
131
141
  String filepath,
132
142
  ?encoding: Encoding | false,
143
+ ?freeze: bool,
133
144
  ?frozen_string_literal: bool,
134
145
  ?line: Integer,
135
146
  ?main_script: bool,
@@ -141,6 +152,7 @@ module Prism
141
152
  def self.profile_file: (
142
153
  String filepath,
143
154
  ?encoding: Encoding | false,
155
+ ?freeze: bool,
144
156
  ?frozen_string_literal: bool,
145
157
  ?line: Integer,
146
158
  ?main_script: bool,
@@ -152,6 +164,7 @@ module Prism
152
164
  def self.lex_file: (
153
165
  String filepath,
154
166
  ?encoding: Encoding | false,
167
+ ?freeze: bool,
155
168
  ?frozen_string_literal: bool,
156
169
  ?line: Integer,
157
170
  ?main_script: bool,
@@ -163,6 +176,7 @@ module Prism
163
176
  def self.parse_lex_file: (
164
177
  String filepath,
165
178
  ?encoding: Encoding | false,
179
+ ?freeze: bool,
166
180
  ?frozen_string_literal: bool,
167
181
  ?line: Integer,
168
182
  ?main_script: bool,
@@ -174,6 +188,7 @@ module Prism
174
188
  def self.dump_file: (
175
189
  String filepath,
176
190
  ?encoding: Encoding | false,
191
+ ?freeze: bool,
177
192
  ?frozen_string_literal: bool,
178
193
  ?line: Integer,
179
194
  ?main_script: bool,
@@ -185,6 +200,7 @@ module Prism
185
200
  def self.parse_file_comments: (
186
201
  String filepath,
187
202
  ?encoding: Encoding | false,
203
+ ?freeze: bool,
188
204
  ?frozen_string_literal: bool,
189
205
  ?line: Integer,
190
206
  ?main_script: bool,
@@ -196,6 +212,7 @@ module Prism
196
212
  def self.parse_file_success?: (
197
213
  String filepath,
198
214
  ?encoding: Encoding | false,
215
+ ?freeze: bool,
199
216
  ?frozen_string_literal: bool,
200
217
  ?line: Integer,
201
218
  ?main_script: bool,
@@ -207,6 +224,7 @@ module Prism
207
224
  def self.parse_file_failure?: (
208
225
  String filepath,
209
226
  ?encoding: Encoding | false,
227
+ ?freeze: bool,
210
228
  ?frozen_string_literal: bool,
211
229
  ?line: Integer,
212
230
  ?main_script: bool,
@@ -223,6 +241,7 @@ module Prism
223
241
  _Stream stream,
224
242
  ?encoding: Encoding | false,
225
243
  ?filepath: String,
244
+ ?freeze: bool,
226
245
  ?frozen_string_literal: bool,
227
246
  ?line: Integer,
228
247
  ?main_script: bool,
@@ -230,4 +249,6 @@ module Prism
230
249
  ?scopes: Array[Array[Symbol]],
231
250
  ?verbose: bool
232
251
  ) -> ParseResult
252
+
253
+ def self.scope: (?locals: Array[Symbol], ?forwarding: Array[Symbol]) -> Scope
233
254
  end
data/src/diagnostic.c CHANGED
@@ -257,8 +257,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
257
257
  [PM_ERR_INVALID_VARIABLE_GLOBAL_3_3] = { "`%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
258
258
  [PM_ERR_INVALID_VARIABLE_GLOBAL] = { "'%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
259
259
  [PM_ERR_INVALID_YIELD] = { "Invalid yield", PM_ERROR_LEVEL_SYNTAX },
260
- [PM_ERR_IT_NOT_ALLOWED_NUMBERED] = { "`it` is not allowed when a numbered parameter is already used", PM_ERROR_LEVEL_SYNTAX },
261
- [PM_ERR_IT_NOT_ALLOWED_ORDINARY] = { "`it` is not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_SYNTAX },
260
+ [PM_ERR_IT_NOT_ALLOWED_NUMBERED] = { "'it' is not allowed when a numbered parameter is already used", PM_ERROR_LEVEL_SYNTAX },
261
+ [PM_ERR_IT_NOT_ALLOWED_ORDINARY] = { "'it' is not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_SYNTAX },
262
262
  [PM_ERR_LAMBDA_OPEN] = { "expected a `do` keyword or a `{` to open the lambda block", PM_ERROR_LEVEL_SYNTAX },
263
263
  [PM_ERR_LAMBDA_TERM_BRACE] = { "expected a lambda block beginning with `{` to end with `}`", PM_ERROR_LEVEL_SYNTAX },
264
264
  [PM_ERR_LAMBDA_TERM_END] = { "expected a lambda block beginning with `do` to end with `end`", PM_ERROR_LEVEL_SYNTAX },
data/src/node.c CHANGED
@@ -7347,6 +7347,18 @@ pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *no
7347
7347
  const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
7348
7348
  pm_dump_json_location(buffer, parser, &cast->base.location);
7349
7349
 
7350
+ // Dump the ParenthesesNodeFlags field
7351
+ pm_buffer_append_byte(buffer, ',');
7352
+ pm_buffer_append_string(buffer, "\"ParenthesesNodeFlags\":", 23);
7353
+ size_t flags = 0;
7354
+ pm_buffer_append_byte(buffer, '[');
7355
+ if (PM_NODE_FLAG_P(cast, PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS)) {
7356
+ if (flags != 0) pm_buffer_append_byte(buffer, ',');
7357
+ pm_buffer_append_string(buffer, "\"MULTIPLE_STATEMENTS\"", 21);
7358
+ flags++;
7359
+ }
7360
+ pm_buffer_append_byte(buffer, ']');
7361
+
7350
7362
  // Dump the body field
7351
7363
  pm_buffer_append_byte(buffer, ',');
7352
7364
  pm_buffer_append_string(buffer, "\"body\":", 7);
@@ -7824,6 +7836,15 @@ pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *no
7824
7836
  pm_buffer_append_string(buffer, "null", 4);
7825
7837
  }
7826
7838
 
7839
+ // Dump the then_keyword_loc field
7840
+ pm_buffer_append_byte(buffer, ',');
7841
+ pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19);
7842
+ if (cast->then_keyword_loc.start != NULL) {
7843
+ pm_dump_json_location(buffer, parser, &cast->then_keyword_loc);
7844
+ } else {
7845
+ pm_buffer_append_string(buffer, "null", 4);
7846
+ }
7847
+
7827
7848
  // Dump the statements field
7828
7849
  pm_buffer_append_byte(buffer, ',');
7829
7850
  pm_buffer_append_string(buffer, "\"statements\":", 13);
data/src/options.c CHANGED
@@ -84,6 +84,11 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
84
84
  }
85
85
 
86
86
  if (strncmp(version, "3.4", 3) == 0) {
87
+ options->version = PM_OPTIONS_VERSION_CRUBY_3_4;
88
+ return true;
89
+ }
90
+
91
+ if (strncmp(version, "3.5", 3) == 0) {
87
92
  options->version = PM_OPTIONS_VERSION_LATEST;
88
93
  return true;
89
94
  }
@@ -98,6 +103,11 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
98
103
  }
99
104
 
100
105
  if (strncmp(version, "3.4.", 4) == 0 && is_number(version + 4, length - 4)) {
106
+ options->version = PM_OPTIONS_VERSION_CRUBY_3_4;
107
+ return true;
108
+ }
109
+
110
+ if (strncmp(version, "3.5.", 4) == 0 && is_number(version + 4, length - 4)) {
101
111
  options->version = PM_OPTIONS_VERSION_LATEST;
102
112
  return true;
103
113
  }
@@ -129,6 +139,14 @@ pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
129
139
  options->partial_script = partial_script;
130
140
  }
131
141
 
142
+ /**
143
+ * Set the freeze option on the given options struct.
144
+ */
145
+ PRISM_EXPORTED_FUNCTION void
146
+ pm_options_freeze_set(pm_options_t *options, bool freeze) {
147
+ options->freeze = freeze;
148
+ }
149
+
132
150
  // For some reason, GCC analyzer thinks we're leaking allocated scopes and
133
151
  // locals here, even though we definitely aren't. This is a false positive.
134
152
  // Ideally we wouldn't need to suppress this.
@@ -163,6 +181,7 @@ PRISM_EXPORTED_FUNCTION bool
163
181
  pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
164
182
  scope->locals_count = locals_count;
165
183
  scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
184
+ scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
166
185
  return scope->locals != NULL;
167
186
  }
168
187
 
@@ -174,6 +193,14 @@ pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index) {
174
193
  return &scope->locals[index];
175
194
  }
176
195
 
196
+ /**
197
+ * Set the forwarding option on the given scope struct.
198
+ */
199
+ PRISM_EXPORTED_FUNCTION void
200
+ pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
201
+ scope->forwarding = forwarding;
202
+ }
203
+
177
204
  /**
178
205
  * Free the internal memory associated with the options.
179
206
  */
@@ -264,6 +291,7 @@ pm_options_read(pm_options_t *options, const char *data) {
264
291
  options->encoding_locked = ((uint8_t) *data++) > 0;
265
292
  options->main_script = ((uint8_t) *data++) > 0;
266
293
  options->partial_script = ((uint8_t) *data++) > 0;
294
+ options->freeze = ((uint8_t) *data++) > 0;
267
295
 
268
296
  uint32_t scopes_count = pm_options_read_u32(data);
269
297
  data += 4;
@@ -281,6 +309,9 @@ pm_options_read(pm_options_t *options, const char *data) {
281
309
  return;
282
310
  }
283
311
 
312
+ uint8_t forwarding = (uint8_t) *data++;
313
+ pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding);
314
+
284
315
  for (size_t local_index = 0; local_index < locals_count; local_index++) {
285
316
  uint32_t local_length = pm_options_read_u32(data);
286
317
  data += 4;
data/src/prettyprint.c CHANGED
@@ -6950,6 +6950,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
6950
6950
  prettyprint_location(output_buffer, parser, &node->location);
6951
6951
  pm_buffer_append_string(output_buffer, ")\n", 2);
6952
6952
 
6953
+ // ParenthesesNodeFlags
6954
+ {
6955
+ pm_buffer_concat(output_buffer, prefix_buffer);
6956
+ pm_buffer_append_string(output_buffer, "+-- ParenthesesNodeFlags:", 25);
6957
+ bool found = false;
6958
+ if (cast->base.flags & PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS) {
6959
+ if (found) pm_buffer_append_byte(output_buffer, ',');
6960
+ pm_buffer_append_string(output_buffer, " multiple_statements", 20);
6961
+ found = true;
6962
+ }
6963
+ if (!found) pm_buffer_append_string(output_buffer, " nil", 4);
6964
+ pm_buffer_append_byte(output_buffer, '\n');
6965
+ }
6966
+
6953
6967
  // body
6954
6968
  {
6955
6969
  pm_buffer_concat(output_buffer, prefix_buffer);
@@ -7676,6 +7690,22 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
7676
7690
  }
7677
7691
  }
7678
7692
 
7693
+ // then_keyword_loc
7694
+ {
7695
+ pm_buffer_concat(output_buffer, prefix_buffer);
7696
+ pm_buffer_append_string(output_buffer, "+-- then_keyword_loc:", 21);
7697
+ pm_location_t *location = &cast->then_keyword_loc;
7698
+ if (location->start == NULL) {
7699
+ pm_buffer_append_string(output_buffer, " nil\n", 5);
7700
+ } else {
7701
+ pm_buffer_append_byte(output_buffer, ' ');
7702
+ prettyprint_location(output_buffer, parser, location);
7703
+ pm_buffer_append_string(output_buffer, " = \"", 4);
7704
+ pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY);
7705
+ pm_buffer_append_string(output_buffer, "\"\n", 2);
7706
+ }
7707
+ }
7708
+
7679
7709
  // statements
7680
7710
  {
7681
7711
  pm_buffer_concat(output_buffer, prefix_buffer);