ruby-next-core 0.15.3 → 1.0.0.rc.1

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +118 -48
  4. data/bin/mspec +11 -0
  5. data/lib/.rbnext/2.1/ruby-next/commands/nextify.rb +295 -0
  6. data/lib/.rbnext/2.1/ruby-next/core.rb +10 -2
  7. data/lib/.rbnext/2.1/ruby-next/language.rb +54 -10
  8. data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +82 -2
  9. data/lib/.rbnext/2.3/ruby-next/config.rb +79 -0
  10. data/lib/.rbnext/2.3/ruby-next/core/data.rb +159 -0
  11. data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/pattern_matching.rb +2 -2
  12. data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +6 -32
  13. data/lib/.rbnext/2.3/ruby-next/utils.rb +3 -22
  14. data/lib/.rbnext/2.6/ruby-next/core/data.rb +159 -0
  15. data/lib/.rbnext/2.7/ruby-next/core/data.rb +159 -0
  16. data/lib/.rbnext/2.7/ruby-next/core.rb +10 -2
  17. data/lib/.rbnext/2.7/ruby-next/language/paco_parsers/string_literals.rb +109 -0
  18. data/lib/.rbnext/2.7/ruby-next/language/rewriters/2.7/pattern_matching.rb +2 -2
  19. data/lib/.rbnext/2.7/ruby-next/language/rewriters/text.rb +132 -0
  20. data/lib/.rbnext/3.2/ruby-next/commands/base.rb +55 -0
  21. data/lib/.rbnext/3.2/ruby-next/language/rewriters/2.7/pattern_matching.rb +1095 -0
  22. data/lib/.rbnext/3.2/ruby-next/rubocop.rb +210 -0
  23. data/lib/ruby-next/commands/nextify.rb +84 -2
  24. data/lib/ruby-next/config.rb +27 -0
  25. data/lib/ruby-next/core/data.rb +159 -0
  26. data/lib/ruby-next/core/matchdata/deconstruct.rb +9 -0
  27. data/lib/ruby-next/core/matchdata/deconstruct_keys.rb +20 -0
  28. data/lib/ruby-next/core/matchdata/named_captures.rb +11 -0
  29. data/lib/ruby-next/core/refinement/import.rb +44 -36
  30. data/lib/ruby-next/core/time/deconstruct_keys.rb +30 -0
  31. data/lib/ruby-next/core.rb +10 -2
  32. data/lib/ruby-next/irb.rb +2 -2
  33. data/lib/ruby-next/language/bootsnap.rb +2 -25
  34. data/lib/ruby-next/language/paco_parser.rb +7 -0
  35. data/lib/ruby-next/language/paco_parsers/base.rb +47 -0
  36. data/lib/ruby-next/language/paco_parsers/comments.rb +26 -0
  37. data/lib/ruby-next/language/paco_parsers/string_literals.rb +109 -0
  38. data/lib/ruby-next/language/parser.rb +24 -2
  39. data/lib/ruby-next/language/rewriters/3.0/args_forward_leading.rb +2 -2
  40. data/lib/ruby-next/language/rewriters/3.1/oneline_pattern_parensless.rb +1 -1
  41. data/lib/ruby-next/language/rewriters/3.2/anonymous_restargs.rb +104 -0
  42. data/lib/ruby-next/language/rewriters/abstract.rb +57 -0
  43. data/lib/ruby-next/language/rewriters/base.rb +6 -32
  44. data/lib/ruby-next/language/rewriters/edge/it_param.rb +58 -0
  45. data/lib/ruby-next/language/rewriters/edge.rb +12 -0
  46. data/lib/ruby-next/language/rewriters/proposed/bind_vars_pattern.rb +3 -0
  47. data/lib/ruby-next/language/rewriters/proposed/method_reference.rb +9 -20
  48. data/lib/ruby-next/language/rewriters/text.rb +132 -0
  49. data/lib/ruby-next/language/runtime.rb +9 -86
  50. data/lib/ruby-next/language/setup.rb +5 -2
  51. data/lib/ruby-next/language/unparser.rb +5 -0
  52. data/lib/ruby-next/language.rb +54 -10
  53. data/lib/ruby-next/pry.rb +1 -1
  54. data/lib/ruby-next/rubocop.rb +2 -0
  55. data/lib/ruby-next/utils.rb +3 -22
  56. data/lib/ruby-next/version.rb +1 -1
  57. data/lib/uby-next.rb +2 -2
  58. metadata +65 -12
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
3
+ require "set" # rubocop:disable Lint/RedundantRequireStatement
4
4
 
5
5
  require "ruby-next/config"
6
6
  require "ruby-next/utils"
@@ -78,7 +78,7 @@ module RubyNext
78
78
  end
79
79
 
80
80
  def native_location?(location)
81
- location.nil? || location.first.match?(/(<internal:|resource:\/truffleruby\/core)/)
81
+ location.nil? || location.first.match?(/(<internal:|resource:\/truffleruby\/core|uri:classloader:\/jruby)/)
82
82
  end
83
83
  end
84
84
 
@@ -197,6 +197,11 @@ require "ruby-next/core/matchdata/match"
197
197
  require "ruby-next/core/enumerable/compact"
198
198
  require "ruby-next/core/integer/try_convert"
199
199
 
200
+ require "ruby-next/core/matchdata/deconstruct"
201
+ require "ruby-next/core/matchdata/deconstruct_keys"
202
+ require "ruby-next/core/matchdata/named_captures"
203
+ require "ruby-next/core/time/deconstruct_keys"
204
+
200
205
  # Generate refinements
201
206
  RubyNext.module_eval do
202
207
  RubyNext::Core.patches.refined.each do |mod, patches|
@@ -210,3 +215,6 @@ RubyNext.module_eval do
210
215
  end
211
216
  end
212
217
  end
218
+
219
+ # Load backports
220
+ require "ruby-next/core/data" unless ENV["RUBY_NEXT_DISABLE_DATA"] == "true"
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module PacoParsers
6
+ class StringLiterals < Base
7
+ PAIRS = {"[" => "]", "{" => "}", "<" => ">"}.freeze
8
+
9
+ def default
10
+ all_strings.fmap do |result|
11
+ reduce_tokens(result.flatten)
12
+ end
13
+ end
14
+
15
+ def all_strings
16
+ alt(
17
+ single_quoted,
18
+ double_quoted,
19
+ external_cmd_exec,
20
+ quoted,
21
+ quoted_expanded
22
+ )
23
+ # heredoc,
24
+ # heredoc_expanded
25
+ end
26
+
27
+ def quoted
28
+ seq(
29
+ string("%q"),
30
+ any_char.bind do |char|
31
+ end_symbol = string(PAIRS[char] || char)
32
+ escapable_string(succeed(char), end_symbol)
33
+ end
34
+ )
35
+ end
36
+
37
+ def single_quoted
38
+ escapable_string(string("'"))
39
+ end
40
+
41
+ def quoted_expanded
42
+ seq(
43
+ alt(string("%Q"), string("%")),
44
+ any_char.bind do |char|
45
+ end_symbol = string(PAIRS[char] || char)
46
+ escapable_string(succeed(char), end_symbol, interpolate: true)
47
+ end
48
+ )
49
+ end
50
+
51
+ def external_cmd_exec
52
+ escapable_string(string("`"), interpolate: true)
53
+ end
54
+
55
+ def double_quoted
56
+ escapable_string(string('"'), interpolate: true)
57
+ end
58
+
59
+ def escapable_string(left, right = nil, interpolate: false)
60
+ right ||= left
61
+ seq(
62
+ left,
63
+ many(
64
+ alt(
65
+ *[
66
+ seq(string("\\"), right).fmap { |_1| [:literal, _1] },
67
+ interpolate ? seq(
68
+ string('#{'),
69
+ lazy { alt(balanced("{", "}", alt(all_strings, any_char)), many(none_of("}"))) },
70
+ string("}")
71
+ ) : nil,
72
+ not_followed_by(right).bind { any_char }.fmap { |_1| [:literal, _1] }
73
+ ].compact
74
+ )
75
+ ),
76
+ right
77
+ )
78
+ end
79
+
80
+ private
81
+
82
+ def reduce_tokens(tokens)
83
+ state = :literal
84
+
85
+ tokens.each_with_object([]) do |v, acc|
86
+ if v == :literal
87
+ acc << [:literal, +""] unless state == :literal
88
+ state = :next_literal
89
+ next acc
90
+ end
91
+
92
+ if state == :next_literal
93
+ state = :literal
94
+ acc.last[1] << v
95
+ next acc
96
+ end
97
+
98
+ if state == :literal
99
+ acc << [:code, +""]
100
+ end
101
+
102
+ state = :code
103
+ acc.last[1] << v
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -185,7 +185,7 @@ module RubyNext
185
185
  # rubocop:disable Style/MissingRespondToMissing
186
186
  class Noop < Base
187
187
  # Return node itself, no memoization
188
- def method_missing(mid, node, *)
188
+ def method_missing(mid, node, *__rest__)
189
189
  node
190
190
  end
191
191
  end
@@ -1035,7 +1035,7 @@ module RubyNext
1035
1035
  s(:send, node, :respond_to?, mid.to_ast_node)
1036
1036
  end
1037
1037
 
1038
- def respond_to_missing?(mid, *)
1038
+ def respond_to_missing?(mid, *__rest__)
1039
1039
  return true if mid.to_s.match?(/_(clause|array_element)/)
1040
1040
  super
1041
1041
  end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-next/language/paco_parser"
4
+
5
+ module RubyNext
6
+ module Language
7
+ module Rewriters
8
+ class Text < Abstract
9
+ using RubyNext
10
+
11
+ class Normalizer < PacoParsers::Base
12
+ attr_reader :store
13
+
14
+ def initialize
15
+ @store = []
16
+ end
17
+
18
+ def normalizing(source)
19
+ many(
20
+ alt(
21
+ ruby_comment,
22
+ ruby_string,
23
+ ruby_code
24
+ )
25
+ ).parse(source, with_callstack: true)
26
+ .then(&:join)
27
+ .then do |_1|
28
+ if block_given?
29
+ yield _1
30
+ else
31
+ _1
32
+ end
33
+ end
34
+ .then do |new_source|
35
+ restore(new_source)
36
+ end
37
+ end
38
+
39
+ def ruby_comment
40
+ parse_comments.fmap do |result|
41
+ store << result
42
+ "# A#{store.size}Я\n"
43
+ end
44
+ end
45
+
46
+ def ruby_string
47
+ parse_strings.fmap do |result|
48
+ result.each_with_object([]) do |(type, str), acc|
49
+ if type == :literal
50
+ store << str
51
+ acc << "_A#{store.size}Я_"
52
+ else
53
+ acc << str
54
+ end
55
+ acc
56
+ end.join
57
+ end
58
+ end
59
+
60
+ def ruby_code
61
+ any_char
62
+ end
63
+
64
+ def restore(source)
65
+ source.gsub(/(?:\# |_)A(\d+)Я(?:_|\n)/m) do |*args|
66
+ store[$1.to_i - 1]
67
+ end
68
+ end
69
+
70
+ def parse_comments
71
+ memoize { PacoParsers::Comments.new.default }
72
+ end
73
+
74
+ def parse_strings
75
+ memoize { PacoParsers::StringLiterals.new.default }
76
+ end
77
+ end
78
+
79
+ # Base class for rewriting parsers which adds the #track! method
80
+ class PacoParser < PacoParsers::Base
81
+ attr_reader :rewriter, :context
82
+
83
+ def initialize(rewriter, context)
84
+ @rewriter = rewriter
85
+ @context = context
86
+ end
87
+
88
+ def track!
89
+ context.track!(rewriter)
90
+ end
91
+ end
92
+
93
+ class << self
94
+ def parser(&block)
95
+ @paco_parser = Class.new(PacoParser, &block)
96
+ end
97
+
98
+ def paco_parser
99
+ return @paco_parser if @paco_parser
100
+
101
+ superclass.paco_parser if superclass.respond_to?(:paco_parser)
102
+ end
103
+
104
+ def text?
105
+ true
106
+ end
107
+ end
108
+
109
+ # Rewrite source code by ignoring string literals and comments
110
+ def rewrite(source)
111
+ Normalizer.new.normalizing(source) do |normalized|
112
+ safe_rewrite(normalized)
113
+ end
114
+ end
115
+
116
+ def safe_rewrite(source)
117
+ source
118
+ end
119
+
120
+ private
121
+
122
+ def parse(source)
123
+ parser_class = self.class.paco_parser
124
+ raise "No parser defined for #{self.class}" unless parser_class
125
+
126
+ paco_parser = self.class.paco_parser.new(self, context)
127
+ paco_parser.parse(source)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+
5
+ module RubyNext
6
+ module Commands
7
+ class Base
8
+ class << self
9
+ def run(args)
10
+ new(args).run
11
+ end
12
+ end
13
+
14
+ attr_reader :dry_run
15
+ alias dry_run? dry_run
16
+
17
+ def initialize(args)
18
+ parse! args
19
+ end
20
+
21
+ def parse!(*__rest__)
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def run
26
+ raise NotImplementedError
27
+ end
28
+
29
+ def log(msg)
30
+ return unless CLI.verbose?
31
+
32
+ if CLI.dry_run?
33
+ $stdout.puts "[DRY RUN] #{msg}"
34
+ else
35
+ $stdout.puts msg
36
+ end
37
+ end
38
+
39
+ def base_parser
40
+ OptionParser.new do |opts|
41
+ yield opts
42
+
43
+ opts.on("-V", "Turn on verbose mode") do
44
+ CLI.verbose = true
45
+ end
46
+
47
+ opts.on("--dry-run", "Print verbose output without generating files") do
48
+ CLI.dry_run = true
49
+ CLI.verbose = true
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end