prism 1.4.0 → 1.7.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -1
  3. data/Makefile +7 -5
  4. data/README.md +3 -1
  5. data/config.yml +294 -41
  6. data/docs/build_system.md +2 -2
  7. data/docs/cruby_compilation.md +1 -1
  8. data/docs/design.md +2 -2
  9. data/docs/parser_translation.md +8 -23
  10. data/docs/releasing.md +6 -25
  11. data/docs/ripper_translation.md +1 -1
  12. data/ext/prism/api_node.c +9 -3
  13. data/ext/prism/extconf.rb +1 -1
  14. data/ext/prism/extension.c +24 -3
  15. data/ext/prism/extension.h +1 -1
  16. data/include/prism/ast.h +360 -70
  17. data/include/prism/diagnostic.h +7 -0
  18. data/include/prism/options.h +49 -3
  19. data/include/prism/parser.h +3 -0
  20. data/include/prism/regexp.h +2 -2
  21. data/include/prism/util/pm_buffer.h +8 -0
  22. data/include/prism/util/pm_integer.h +4 -0
  23. data/include/prism/util/pm_list.h +6 -0
  24. data/include/prism/util/pm_string.h +12 -2
  25. data/include/prism/version.h +2 -2
  26. data/include/prism.h +40 -15
  27. data/lib/prism/compiler.rb +456 -151
  28. data/lib/prism/desugar_compiler.rb +1 -0
  29. data/lib/prism/dispatcher.rb +16 -0
  30. data/lib/prism/dot_visitor.rb +10 -1
  31. data/lib/prism/dsl.rb +5 -2
  32. data/lib/prism/ffi.rb +28 -10
  33. data/lib/prism/inspect_visitor.rb +4 -0
  34. data/lib/prism/lex_compat.rb +1 -0
  35. data/lib/prism/mutation_compiler.rb +3 -0
  36. data/lib/prism/node.rb +559 -349
  37. data/lib/prism/node_ext.rb +4 -1
  38. data/lib/prism/pack.rb +2 -0
  39. data/lib/prism/parse_result/comments.rb +1 -0
  40. data/lib/prism/parse_result/errors.rb +1 -0
  41. data/lib/prism/parse_result/newlines.rb +1 -0
  42. data/lib/prism/parse_result.rb +3 -15
  43. data/lib/prism/pattern.rb +1 -0
  44. data/lib/prism/polyfill/scan_byte.rb +14 -0
  45. data/lib/prism/polyfill/warn.rb +36 -0
  46. data/lib/prism/reflection.rb +4 -1
  47. data/lib/prism/relocation.rb +1 -0
  48. data/lib/prism/serialize.rb +30 -22
  49. data/lib/prism/string_query.rb +1 -0
  50. data/lib/prism/translation/parser/builder.rb +1 -0
  51. data/lib/prism/translation/parser/compiler.rb +63 -41
  52. data/lib/prism/translation/parser/lexer.rb +29 -21
  53. data/lib/prism/translation/parser.rb +25 -4
  54. data/lib/prism/translation/parser33.rb +1 -0
  55. data/lib/prism/translation/parser34.rb +1 -0
  56. data/lib/prism/translation/parser35.rb +2 -6
  57. data/lib/prism/translation/parser40.rb +13 -0
  58. data/lib/prism/translation/parser41.rb +13 -0
  59. data/lib/prism/translation/parser_current.rb +26 -0
  60. data/lib/prism/translation/ripper/sexp.rb +1 -0
  61. data/lib/prism/translation/ripper.rb +19 -3
  62. data/lib/prism/translation/ruby_parser.rb +340 -22
  63. data/lib/prism/translation.rb +4 -0
  64. data/lib/prism/visitor.rb +457 -152
  65. data/lib/prism.rb +22 -0
  66. data/prism.gemspec +9 -1
  67. data/rbi/prism/dsl.rbi +6 -6
  68. data/rbi/prism/node.rbi +42 -17
  69. data/rbi/prism/translation/parser35.rbi +0 -2
  70. data/rbi/prism/translation/parser40.rbi +6 -0
  71. data/rbi/prism/translation/parser41.rbi +6 -0
  72. data/sig/prism/dispatcher.rbs +3 -0
  73. data/sig/prism/dsl.rbs +5 -5
  74. data/sig/prism/node.rbs +462 -38
  75. data/sig/prism/node_ext.rbs +84 -17
  76. data/sig/prism/parse_result/comments.rbs +38 -0
  77. data/sig/prism/parse_result.rbs +4 -0
  78. data/sig/prism/reflection.rbs +1 -1
  79. data/sig/prism.rbs +4 -0
  80. data/src/diagnostic.c +13 -1
  81. data/src/encoding.c +172 -67
  82. data/src/node.c +11 -0
  83. data/src/options.c +17 -7
  84. data/src/prettyprint.c +18 -0
  85. data/src/prism.c +1495 -2021
  86. data/src/serialize.c +9 -1
  87. data/src/token_type.c +38 -36
  88. data/src/util/pm_constant_pool.c +1 -1
  89. data/src/util/pm_string.c +6 -8
  90. metadata +11 -3
@@ -6,34 +6,19 @@ Prism ships with the ability to translate its syntax tree into the syntax tree u
6
6
 
7
7
  The `parser` gem provides multiple parsers to support different versions of the Ruby grammar. This includes all of the Ruby versions going back to 1.8, as well as third-party parsers like MacRuby and RubyMotion. The `prism` gem provides another parser that uses the `prism` parser to build the syntax tree.
8
8
 
9
- You can use the `prism` parser like you would any other. After requiring the parser, you should be able to call any of the regular `Parser::Base` APIs that you would normally use.
9
+ You can use the `prism` parser like you would any other. After requiring `prism`, you should be able to call any of the regular `Parser::Base` APIs that you would normally use.
10
10
 
11
11
  ```ruby
12
12
  require "prism"
13
13
 
14
- Prism::Translation::Parser.parse_file("path/to/file.rb")
15
- ```
16
-
17
- ### RuboCop
18
-
19
- Prism as a parser engine is directly supported since RuboCop 1.62. The class used for parsing is `Prism::Translation::Parser`.
20
-
21
- First, specify `prism` in your Gemfile:
22
-
23
- ```ruby
24
- gem "prism"
25
- ```
26
-
27
- To use Prism with RuboCop, specify `ParserEngine` and `TargetRubyVersion` in your RuboCop configuration file:
14
+ # Same as `Parser::Ruby34`
15
+ Prism::Translation::Parser34.parse_file("path/to/file.rb")
28
16
 
29
- ```yaml
30
- AllCops:
31
- ParserEngine: parser_prism
32
- TargetRubyVersion: 3.3
17
+ # Same as `Parser::CurrentRuby`
18
+ Prism::Translation::ParserCurrent.parse("puts 'Hello World!'")
33
19
  ```
34
20
 
35
- The default value for `ParserEngine` is `parser_whitequark`, which indicates the Parser gem. You need to explicitly switch it to `parser_prism` to indicate Prism. Additionally, the value for `TargetRubyVersion` must be specified as `3.3` or higher, as Prism supports parsing versions of Ruby 3.3 and higher.
36
- The parser class is determined by the combination of values for `ParserEngine` and `TargetRubyVersion`. For example, if `TargetRubyVersion: 3.3`, parsing is performed by `Prism::Translation::Parser33`, and for `TargetRubyVersion 3.4`, parsing is performed by `Prism::Translation::Parser34`.
21
+ All the parsers are autoloaded, so you don't have to worry about requiring them yourself.
37
22
 
38
- For further information, please refer to the RuboCop documentation:
39
- https://docs.rubocop.org/rubocop/configuration.html#setting-the-parser-engine
23
+ If you also need to parse Ruby versions below 3.3 (for which the `prism` translation layer does not have explicit support), check out
24
+ [this guide](https://github.com/whitequark/parser/blob/master/doc/PRISM_TRANSLATION.md) from the `parser` gem on how to use both in conjunction.
data/docs/releasing.md CHANGED
@@ -40,14 +40,17 @@ ruby -pi -e 'gsub(/^ruby-prism-sys = \{ version = ".+?"/, %Q{ruby-prism-sys = \{
40
40
  * Update the `Gemfile.lock` file:
41
41
 
42
42
  ```sh
43
- chruby ruby-3.5.0-dev
43
+ chruby ruby-4.0.0-dev
44
44
  bundle install
45
45
  ```
46
46
 
47
47
  * Update the version-specific lockfiles:
48
48
 
49
49
  ```sh
50
- bin/prism bundle install
50
+ for VERSION in "2.7" "3.0" "3.1" "3.2" "3.3" "3.4"; do docker run -it --rm -v "$PWD":/usr/src/app -w /usr/src/app -e BUNDLE_GEMFILE="gemfiles/$VERSION/Gemfile" "ruby:$VERSION" bundle update; done
51
+ docker run -it --rm -v "$PWD":/usr/src/app -w /usr/src/app -e BUNDLE_GEMFILE="gemfiles/4.0/Gemfile" ruby:4.0.0-preview2 bundle update
52
+ docker run -it --rm -v "$PWD":/usr/src/app -w /usr/src/app -e BUNDLE_GEMFILE="gemfiles/jruby/Gemfile" jruby:latest bundle update
53
+ BUNDLE_GEMFILE=gemfiles/truffleruby/Gemfile chruby-exec truffleruby -- bundle update
51
54
  ```
52
55
 
53
56
  * Update the cargo lockfiles:
@@ -71,26 +74,4 @@ git push
71
74
  ## Publishing
72
75
 
73
76
  * Update the GitHub release page with a copy of the latest entry in the `CHANGELOG.md` file.
74
- * Publish the gem to [rubygems.org](rubygems.org). Note that you must have access to the `prism` gem to do this.
75
-
76
- ```sh
77
- bundle exec rake release
78
- ```
79
-
80
- * Generate the `wasm` artifact (or download it from GitHub actions and put it in `javascript/src/prism.wasm`).
81
-
82
- ```sh
83
- make wasm
84
- ```
85
-
86
- * Publish the JavaScript package to [npmjs.com](npmjs.com). Note that you must have access to the `@ruby/prism` package to do this.
87
-
88
- ```sh
89
- npm publish
90
- ```
91
-
92
- * Publish the rust crate to [crates.io](crates.io). Note that you must have access to the `ruby-prism-sys` and `ruby-prism` crates to do this.
93
-
94
- ```sh
95
- bundle exec rake cargo:publish:real
96
- ```
77
+ * Push a new tag to the GitHub repository, following the `vX.Y.Z` format.
@@ -55,7 +55,7 @@ It is helpful to understand the differences between the `Ripper` library and the
55
55
 
56
56
  ### Design
57
57
 
58
- `Ripper` is a streaming parser. This means as it is parsing Ruby code, it dispatches events back to the consumer. This allows quite a bit of flexibility. You can use it to build your own syntax tree or to find specific patterns in the code. `Prism` on the other hand returns to your the completed syntax tree _before_ it allows you to manipulate it. This means the tree that you get back is the only representation that can be generated by the parser _at parse time_ (but of course can be manipulated later).
58
+ `Ripper` is a streaming parser. This means as it is parsing Ruby code, it dispatches events back to the consumer. This allows quite a bit of flexibility. You can use it to build your own syntax tree or to find specific patterns in the code. `Prism` on the other hand returns to you the completed syntax tree _before_ it allows you to manipulate it. This means the tree that you get back is the only representation that can be generated by the parser _at parse time_ (but of course can be manipulated later).
59
59
 
60
60
  ### Fields
61
61
 
data/ext/prism/api_node.c CHANGED
@@ -1,3 +1,5 @@
1
+ /* :markup: markdown */
2
+
1
3
  /*----------------------------------------------------------------------------*/
2
4
  /* This file is generated by the templates/template.rb script and should not */
3
5
  /* be modified manually. See */
@@ -1787,7 +1789,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
1787
1789
  #line 190 "prism/templates/ext/prism/api_node.c.erb"
1788
1790
  case PM_CALL_NODE: {
1789
1791
  pm_call_node_t *cast = (pm_call_node_t *) node;
1790
- VALUE argv[12];
1792
+ VALUE argv[13];
1791
1793
 
1792
1794
  // source
1793
1795
  argv[0] = source;
@@ -1830,11 +1832,15 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
1830
1832
  #line 243 "prism/templates/ext/prism/api_node.c.erb"
1831
1833
  argv[10] = cast->closing_loc.start == NULL ? Qnil : pm_location_new(parser, cast->closing_loc.start, cast->closing_loc.end, source, freeze);
1832
1834
 
1835
+ // equal_loc
1836
+ #line 243 "prism/templates/ext/prism/api_node.c.erb"
1837
+ argv[11] = cast->equal_loc.start == NULL ? Qnil : pm_location_new(parser, cast->equal_loc.start, cast->equal_loc.end, source, freeze);
1838
+
1833
1839
  // block
1834
1840
  #line 213 "prism/templates/ext/prism/api_node.c.erb"
1835
- argv[11] = rb_ary_pop(value_stack);
1841
+ argv[12] = rb_ary_pop(value_stack);
1836
1842
 
1837
- VALUE value = rb_class_new_instance(12, argv, rb_cPrismCallNode);
1843
+ VALUE value = rb_class_new_instance(13, argv, rb_cPrismCallNode);
1838
1844
  if (freeze) rb_obj_freeze(value);
1839
1845
 
1840
1846
  rb_ary_push(value_stack, value);
data/ext/prism/extconf.rb CHANGED
@@ -37,7 +37,7 @@ end
37
37
  def generate_templates
38
38
  Dir.chdir(File.expand_path("../..", __dir__)) do
39
39
  if !File.exist?("include/prism/ast.h") && Dir.exist?(".git")
40
- system("templates/template.rb", exception: true)
40
+ system(RbConfig.ruby, "templates/template.rb", exception: true)
41
41
  end
42
42
  end
43
43
  end
@@ -25,6 +25,7 @@ VALUE rb_cPrismLexResult;
25
25
  VALUE rb_cPrismParseLexResult;
26
26
  VALUE rb_cPrismStringQuery;
27
27
  VALUE rb_cPrismScope;
28
+ VALUE rb_cPrismCurrentVersionError;
28
29
 
29
30
  VALUE rb_cPrismDebugEncoding;
30
31
 
@@ -199,7 +200,12 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
199
200
  if (!NIL_P(value)) {
200
201
  const char *version = check_string(value);
201
202
 
202
- if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
203
+ if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
204
+ const char *current_version = RSTRING_PTR(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")));
205
+ if (!pm_options_version_set(options, current_version, 3)) {
206
+ rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, current_version));
207
+ }
208
+ } else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
203
209
  rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
204
210
  }
205
211
  }
@@ -888,7 +894,7 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
888
894
  * version of Ruby syntax (which you can trigger with `nil` or
889
895
  * `"latest"`). You may also restrict the syntax to a specific version of
890
896
  * Ruby, e.g., with `"3.3.0"`. To parse with the same syntax version that
891
- * the current Ruby is running use `version: RUBY_VERSION`. Raises
897
+ * the current Ruby is running use `version: "current"`. Raises
892
898
  * ArgumentError if the version is not currently supported by Prism.
893
899
  */
894
900
  static VALUE
@@ -994,6 +1000,14 @@ profile_file(int argc, VALUE *argv, VALUE self) {
994
1000
  return Qnil;
995
1001
  }
996
1002
 
1003
+ static int
1004
+ parse_stream_eof(void *stream) {
1005
+ if (rb_funcall((VALUE) stream, rb_intern("eof?"), 0)) {
1006
+ return 1;
1007
+ }
1008
+ return 0;
1009
+ }
1010
+
997
1011
  /**
998
1012
  * An implementation of fgets that is suitable for use with Ruby IO objects.
999
1013
  */
@@ -1034,7 +1048,7 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
1034
1048
  pm_parser_t parser;
1035
1049
  pm_buffer_t buffer;
1036
1050
 
1037
- pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, &options);
1051
+ pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, parse_stream_eof, &options);
1038
1052
  rb_encoding *encoding = rb_enc_find(parser.encoding->name);
1039
1053
 
1040
1054
  VALUE source = pm_source_new(&parser, encoding, options.freeze);
@@ -1331,6 +1345,11 @@ Init_prism(void) {
1331
1345
  );
1332
1346
  }
1333
1347
 
1348
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1349
+ // Mark this extension as Ractor-safe.
1350
+ rb_ext_ractor_safe(true);
1351
+ #endif
1352
+
1334
1353
  // Grab up references to all of the constants that we're going to need to
1335
1354
  // reference throughout this extension.
1336
1355
  rb_cPrism = rb_define_module("Prism");
@@ -1351,6 +1370,8 @@ Init_prism(void) {
1351
1370
  rb_cPrismStringQuery = rb_define_class_under(rb_cPrism, "StringQuery", rb_cObject);
1352
1371
  rb_cPrismScope = rb_define_class_under(rb_cPrism, "Scope", rb_cObject);
1353
1372
 
1373
+ rb_cPrismCurrentVersionError = rb_const_get(rb_cPrism, rb_intern("CurrentVersionError"));
1374
+
1354
1375
  // Intern all of the IDs eagerly that we support so that we don't have to do
1355
1376
  // it every time we parse.
1356
1377
  rb_id_option_command_line = rb_intern_const("command_line");
@@ -1,7 +1,7 @@
1
1
  #ifndef PRISM_EXT_NODE_H
2
2
  #define PRISM_EXT_NODE_H
3
3
 
4
- #define EXPECTED_PRISM_VERSION "1.4.0"
4
+ #define EXPECTED_PRISM_VERSION "1.7.0"
5
5
 
6
6
  #include <ruby.h>
7
7
  #include <ruby/encoding.h>