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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/README.md +118 -48
- data/bin/mspec +11 -0
- data/lib/.rbnext/2.1/ruby-next/commands/nextify.rb +295 -0
- data/lib/.rbnext/2.1/ruby-next/core.rb +10 -2
- data/lib/.rbnext/2.1/ruby-next/language.rb +54 -10
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +82 -2
- data/lib/.rbnext/2.3/ruby-next/config.rb +79 -0
- data/lib/.rbnext/2.3/ruby-next/core/data.rb +159 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/pattern_matching.rb +2 -2
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +6 -32
- data/lib/.rbnext/2.3/ruby-next/utils.rb +3 -22
- data/lib/.rbnext/2.6/ruby-next/core/data.rb +159 -0
- data/lib/.rbnext/2.7/ruby-next/core/data.rb +159 -0
- data/lib/.rbnext/2.7/ruby-next/core.rb +10 -2
- data/lib/.rbnext/2.7/ruby-next/language/paco_parsers/string_literals.rb +109 -0
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/2.7/pattern_matching.rb +2 -2
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/text.rb +132 -0
- data/lib/.rbnext/3.2/ruby-next/commands/base.rb +55 -0
- data/lib/.rbnext/3.2/ruby-next/language/rewriters/2.7/pattern_matching.rb +1095 -0
- data/lib/.rbnext/3.2/ruby-next/rubocop.rb +210 -0
- data/lib/ruby-next/commands/nextify.rb +84 -2
- data/lib/ruby-next/config.rb +27 -0
- data/lib/ruby-next/core/data.rb +159 -0
- data/lib/ruby-next/core/matchdata/deconstruct.rb +9 -0
- data/lib/ruby-next/core/matchdata/deconstruct_keys.rb +20 -0
- data/lib/ruby-next/core/matchdata/named_captures.rb +11 -0
- data/lib/ruby-next/core/refinement/import.rb +44 -36
- data/lib/ruby-next/core/time/deconstruct_keys.rb +30 -0
- data/lib/ruby-next/core.rb +10 -2
- data/lib/ruby-next/irb.rb +2 -2
- data/lib/ruby-next/language/bootsnap.rb +2 -25
- data/lib/ruby-next/language/paco_parser.rb +7 -0
- data/lib/ruby-next/language/paco_parsers/base.rb +47 -0
- data/lib/ruby-next/language/paco_parsers/comments.rb +26 -0
- data/lib/ruby-next/language/paco_parsers/string_literals.rb +109 -0
- data/lib/ruby-next/language/parser.rb +24 -2
- data/lib/ruby-next/language/rewriters/3.0/args_forward_leading.rb +2 -2
- data/lib/ruby-next/language/rewriters/3.1/oneline_pattern_parensless.rb +1 -1
- data/lib/ruby-next/language/rewriters/3.2/anonymous_restargs.rb +104 -0
- data/lib/ruby-next/language/rewriters/abstract.rb +57 -0
- data/lib/ruby-next/language/rewriters/base.rb +6 -32
- data/lib/ruby-next/language/rewriters/edge/it_param.rb +58 -0
- data/lib/ruby-next/language/rewriters/edge.rb +12 -0
- data/lib/ruby-next/language/rewriters/proposed/bind_vars_pattern.rb +3 -0
- data/lib/ruby-next/language/rewriters/proposed/method_reference.rb +9 -20
- data/lib/ruby-next/language/rewriters/text.rb +132 -0
- data/lib/ruby-next/language/runtime.rb +9 -86
- data/lib/ruby-next/language/setup.rb +5 -2
- data/lib/ruby-next/language/unparser.rb +5 -0
- data/lib/ruby-next/language.rb +54 -10
- data/lib/ruby-next/pry.rb +1 -1
- data/lib/ruby-next/rubocop.rb +2 -0
- data/lib/ruby-next/utils.rb +3 -22
- data/lib/ruby-next/version.rb +1 -1
- data/lib/uby-next.rb +2 -2
- 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
|