ruby-next-core 0.15.3 → 1.0.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 +34 -0
- data/README.md +127 -54
- 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 +59 -12
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +83 -3
- data/lib/.rbnext/2.3/ruby-next/config.rb +79 -0
- data/lib/.rbnext/2.3/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +4 -4
- 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 +163 -0
- data/lib/.rbnext/2.7/ruby-next/core/data.rb +163 -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 +85 -3
- data/lib/ruby-next/config.rb +29 -2
- data/lib/ruby-next/core/data.rb +163 -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/eval.rb +4 -4
- 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 +31 -6
- 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.1/shorthand_hash.rb +2 -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 +59 -12
- 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 +63 -10
@@ -4,57 +4,65 @@
|
|
4
4
|
# So, we use a defined method instead (and transpile source code to use it).
|
5
5
|
# NOTE: We have to transpile the source code anyway, since we need to pass a binding.
|
6
6
|
RubyNext::Core.singleton_class.module_eval do
|
7
|
-
def import_methods(
|
7
|
+
def import_methods(*others, bind)
|
8
8
|
import = []
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
# First, validate passed modules
|
11
|
+
others.each do |other|
|
12
|
+
raise TypeError, "wrong argument type #{other.class} (expected Module)" unless other.is_a?(::Module)
|
13
|
+
raise TypeError, "wrong argument type Class (expected Module)" if other.is_a?(::Class)
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
others.each do |other|
|
17
|
+
(other.instance_methods(false) + other.private_instance_methods(false)).each do |mid|
|
18
|
+
# check for non-Ruby methods
|
19
|
+
meth = other.instance_method(mid)
|
20
|
+
location = meth.source_location
|
18
21
|
|
19
|
-
|
22
|
+
if location.nil? || location.first.match?(/(<internal:|resource:\/truffleruby\/core|uri:classloader:\/jruby)/)
|
23
|
+
raise ArgumentError, "Can't import method which is not defined with Ruby code: #{other}##{mid} from #{location}"
|
24
|
+
end
|
20
25
|
|
21
|
-
|
26
|
+
source_file, lineno = *location
|
22
27
|
|
23
|
-
|
28
|
+
raise ArgumentError, "Can't import dynamicly added methods: #{other}##{mid}" unless File.file?(source_file)
|
24
29
|
|
25
|
-
|
30
|
+
lines = File.open(source_file).readlines
|
26
31
|
|
27
|
-
|
28
|
-
buffer << line + "\n"
|
32
|
+
buffer = []
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
lines[(lineno - 1)..-1].each do |line|
|
35
|
+
buffer << line + "\n"
|
36
|
+
|
37
|
+
begin
|
38
|
+
if defined?(::RubyNext::Language) && ::RubyNext::Language.runtime?
|
39
|
+
new_source = ::RubyNext::Language.transform(buffer.join, rewriters: RubyNext::Language.current_rewriters, using: false)
|
40
|
+
# Transformed successfully => valid method => evaluate transpiled code
|
41
|
+
import << [new_source, source_file, lineno]
|
42
|
+
buffer.clear
|
43
|
+
break
|
44
|
+
end
|
38
45
|
|
39
|
-
|
40
|
-
|
41
|
-
|
46
|
+
# Borrowed from https://github.com/banister/method_source/blob/81d039c966ffd95d26e12eb2e205c0eb8377f49d/lib/method_source/code_helpers.rb#L66
|
47
|
+
catch(:valid) do
|
48
|
+
eval("BEGIN{throw :valid}\nObject.new.instance_eval { #{buffer.join} }") # rubocop:disable all
|
49
|
+
end
|
50
|
+
break
|
51
|
+
rescue SyntaxError
|
42
52
|
end
|
43
|
-
break
|
44
|
-
rescue SyntaxError
|
45
53
|
end
|
46
|
-
end
|
47
54
|
|
48
|
-
|
49
|
-
|
55
|
+
import << [buffer.join, source_file, lineno] unless buffer.empty?
|
56
|
+
end
|
50
57
|
|
51
|
-
|
52
|
-
|
53
|
-
|
58
|
+
import.each do |(definition, file, lino)|
|
59
|
+
Kernel.eval definition, bind, file, lino
|
60
|
+
end
|
54
61
|
|
55
|
-
|
56
|
-
|
57
|
-
|
62
|
+
# Copy constants (they could be accessed from methods)
|
63
|
+
other.constants.each do |name|
|
64
|
+
Kernel.eval "#{name} = #{other}::#{name}", bind # rubocop:disable Style/EvalWithLocation
|
65
|
+
end
|
58
66
|
end
|
59
67
|
end
|
60
68
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RubyNext::Core.patch Time, method: :deconstruct_keys, version: "3.2" do
|
4
|
+
<<-'RUBY'
|
5
|
+
def deconstruct_keys(keys)
|
6
|
+
raise TypeError, "wrong argument type #{keys.class} (expected Array or nil)" if keys && !keys.is_a?(Array)
|
7
|
+
|
8
|
+
if !keys
|
9
|
+
return {
|
10
|
+
year: year,
|
11
|
+
month: month,
|
12
|
+
day: day,
|
13
|
+
yday: yday,
|
14
|
+
wday: wday,
|
15
|
+
hour: hour,
|
16
|
+
min: min,
|
17
|
+
sec: sec,
|
18
|
+
subsec: subsec,
|
19
|
+
dst: dst?,
|
20
|
+
zone: zone
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
keys.each_with_object({}) do |key, hash|
|
25
|
+
hash[key] = public_send(key) if key.is_a?(Symbol) && respond_to?(key)
|
26
|
+
hash
|
27
|
+
end
|
28
|
+
end
|
29
|
+
RUBY
|
30
|
+
end
|
data/lib/ruby-next/core.rb
CHANGED
@@ -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"
|
data/lib/ruby-next/irb.rb
CHANGED
@@ -9,14 +9,14 @@ require "ruby-next/language"
|
|
9
9
|
# IRB extension to transpile code before evaluating
|
10
10
|
module RubyNext
|
11
11
|
module IRBExt
|
12
|
-
def
|
12
|
+
def eval(statements, *args)
|
13
13
|
new_statements = ::RubyNext::Language.transform(
|
14
14
|
statements,
|
15
15
|
rewriters: ::RubyNext::Language.current_rewriters,
|
16
16
|
using: false
|
17
17
|
)
|
18
18
|
|
19
|
-
super(
|
19
|
+
super(new_statements, *args)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -1,28 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require "ruby-next/utils"
|
5
|
-
require "ruby-next/language"
|
3
|
+
warn "[DEPRECATED] Using ruby-next/language/bootsnap is deprecated. Please use ruby-next/language/runtime instead."
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
# Patch bootsnap to transform source code.
|
10
|
-
# Based on https://github.com/kddeisz/preval/blob/master/lib/preval.rb
|
11
|
-
load_iseq = RubyVM::InstructionSequence.method(:load_iseq)
|
12
|
-
|
13
|
-
if load_iseq.source_location[0].include?("/bootsnap/")
|
14
|
-
Bootsnap::CompileCache::ISeq.singleton_class.prepend(
|
15
|
-
Module.new do
|
16
|
-
def input_to_storage(source, path, *)
|
17
|
-
return super unless RubyNext::Language.transformable?(path)
|
18
|
-
source = RubyNext::Language.transform(source, rewriters: RubyNext::Language.current_rewriters)
|
19
|
-
|
20
|
-
RubyNext.debug_source(source, path)
|
21
|
-
|
22
|
-
RubyVM::InstructionSequence.compile(source, path, path).to_binary
|
23
|
-
rescue SyntaxError
|
24
|
-
raise Bootsnap::CompileCache::Uncompilable, "syntax error"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
)
|
28
|
-
end
|
5
|
+
require "ruby-next/language/runtime"
|
@@ -11,7 +11,7 @@ module RubyNext
|
|
11
11
|
using: bind&.receiver == TOPLEVEL_BINDING.receiver || bind&.receiver&.is_a?(Module)
|
12
12
|
)
|
13
13
|
RubyNext.debug_source(new_source, "(#{caller_locations(1, 1).first})")
|
14
|
-
super
|
14
|
+
super(new_source, bind, *args)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -25,7 +25,7 @@ module RubyNext
|
|
25
25
|
source = args.shift
|
26
26
|
new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
|
27
27
|
RubyNext.debug_source(new_source, "(#{caller_locations(1, 1).first})")
|
28
|
-
super
|
28
|
+
super(new_source, *args)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -39,7 +39,7 @@ module RubyNext
|
|
39
39
|
new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
|
40
40
|
|
41
41
|
RubyNext.debug_source(new_source, "(#{caller_locations(1, 1).first})")
|
42
|
-
super
|
42
|
+
super(new_source, *args)
|
43
43
|
end
|
44
44
|
|
45
45
|
def class_eval(*args, &block)
|
@@ -48,7 +48,7 @@ module RubyNext
|
|
48
48
|
source = args.shift
|
49
49
|
new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
|
50
50
|
RubyNext.debug_source(new_source, "(#{caller_locations(1, 1).first})")
|
51
|
-
super
|
51
|
+
super(new_source, *args)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module PacoParsers
|
6
|
+
class Base
|
7
|
+
include Paco
|
8
|
+
|
9
|
+
def parse(io)
|
10
|
+
default.parse(io)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def anything_between(left, right)
|
16
|
+
seq(
|
17
|
+
left,
|
18
|
+
many(not_followed_by(right).bind { any_char }).join,
|
19
|
+
right
|
20
|
+
).join
|
21
|
+
end
|
22
|
+
|
23
|
+
def starting_string(str)
|
24
|
+
index.bind do |index|
|
25
|
+
(index.column > 1) ? failed("1 column") : string(str)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def balanced(l, r, inner)
|
30
|
+
left = string(l)
|
31
|
+
right = string(r)
|
32
|
+
|
33
|
+
many(
|
34
|
+
alt(
|
35
|
+
seq(
|
36
|
+
left,
|
37
|
+
lazy { balanced(l, r, inner) },
|
38
|
+
right
|
39
|
+
),
|
40
|
+
not_followed_by(right).bind { inner }
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module PacoParsers
|
6
|
+
class Comments < Base
|
7
|
+
def default
|
8
|
+
alt(
|
9
|
+
line_comment,
|
10
|
+
block_comment
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Matches a Ruby line comment (from `#` till the end of the line)
|
15
|
+
def line_comment
|
16
|
+
anything_between(string("#"), end_of_line)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Matches a Ruby block comment (from `=begin` till `=end`)
|
20
|
+
def block_comment
|
21
|
+
anything_between(starting_string("=begin"), starting_string("=end"))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -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 { [: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 { [: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
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
begin
|
4
|
+
require "parser/prism"
|
5
|
+
rescue LoadError
|
6
|
+
require "parser/ruby33"
|
7
|
+
end
|
4
8
|
|
5
9
|
module RubyNext
|
6
10
|
module Language
|
@@ -22,11 +26,18 @@ module RubyNext
|
|
22
26
|
unless method_defined?(:match_pattern_p)
|
23
27
|
include BuilderExt
|
24
28
|
end
|
29
|
+
|
30
|
+
def check_reserved_for_numparam(name, loc)
|
31
|
+
# We don't want to raise SyntaxError, 'cause we want to use _x vars for older Rubies.
|
32
|
+
# The exception should be raised by Ruby itself for versions supporting numbered parameters
|
33
|
+
end
|
25
34
|
end
|
26
35
|
|
27
36
|
class << self
|
37
|
+
attr_accessor :parser_class, :parser_syntax_errors
|
38
|
+
|
28
39
|
def parser
|
29
|
-
|
40
|
+
parser_class.new(Builder.new).tap do |prs|
|
30
41
|
prs.diagnostics.tap do |diagnostics|
|
31
42
|
diagnostics.all_errors_are_fatal = true
|
32
43
|
end
|
@@ -39,8 +50,8 @@ module RubyNext
|
|
39
50
|
end
|
40
51
|
|
41
52
|
parser.parse(buffer)
|
42
|
-
rescue
|
43
|
-
raise ::SyntaxError, e.message
|
53
|
+
rescue *parser_syntax_errors => e
|
54
|
+
raise ::SyntaxError, e.message, e.backtrace
|
44
55
|
end
|
45
56
|
|
46
57
|
def parse_with_comments(source, file = "(string)")
|
@@ -49,8 +60,22 @@ module RubyNext
|
|
49
60
|
end
|
50
61
|
|
51
62
|
parser.parse_with_comments(buffer)
|
52
|
-
rescue
|
53
|
-
raise ::SyntaxError, e.message
|
63
|
+
rescue *parser_syntax_errors => e
|
64
|
+
raise ::SyntaxError, e.message, e.backtrace
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
self.parser_syntax_errors = [::Parser::SyntaxError]
|
69
|
+
|
70
|
+
# Set up default parser
|
71
|
+
unless parser_class
|
72
|
+
self.parser_class = if defined?(::Parser::RubyNext)
|
73
|
+
::Parser::RubyNext
|
74
|
+
elsif defined?(::Parser::Prism)
|
75
|
+
parser_syntax_errors << ::Prism::ParserCompiler::CompilationError
|
76
|
+
::Parser::Prism
|
77
|
+
else
|
78
|
+
::Parser::Ruby33
|
54
79
|
end
|
55
80
|
end
|
56
81
|
end
|
@@ -50,7 +50,7 @@ module RubyNext
|
|
50
50
|
|
51
51
|
return false unless fargs
|
52
52
|
|
53
|
-
node.children.index(fargs) > (node.type == :send ? 2 : 0)
|
53
|
+
node.children.index(fargs) > ((node.type == :send) ? 2 : 0)
|
54
54
|
end
|
55
55
|
|
56
56
|
def method_with_leading_arg(node)
|
@@ -62,7 +62,7 @@ module RubyNext
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def def_with_leading_farg(node)
|
65
|
-
args = node.type == :defs ? node.children[2] : node.children[1]
|
65
|
+
args = (node.type == :defs) ? node.children[2] : node.children[1]
|
66
66
|
args = args.children
|
67
67
|
|
68
68
|
farg = args.detect { |child| child.type == :forward_arg }
|
@@ -25,7 +25,7 @@ module RubyNext
|
|
25
25
|
|
26
26
|
context.track! self
|
27
27
|
|
28
|
-
left_p, right_p = pattern.type == :array_pattern ? %w([ ]) : %w[{ }]
|
28
|
+
left_p, right_p = (pattern.type == :array_pattern) ? %w([ ]) : %w[{ }]
|
29
29
|
|
30
30
|
insert_before(pattern.loc.expression, left_p)
|
31
31
|
insert_after(pattern.loc.expression, right_p)
|
@@ -9,7 +9,8 @@ module RubyNext
|
|
9
9
|
MIN_SUPPORTED_VERSION = Gem::Version.new("3.1.0")
|
10
10
|
|
11
11
|
def on_pair(node)
|
12
|
-
return super(node) unless node.children[0].loc.last_column == node.children[1].loc.last_column
|
12
|
+
return super(node) unless (node.children[0].loc.last_column == node.children[1].loc.last_column) &&
|
13
|
+
(node.children[1].loc.first_line == node.children[1].loc.last_line)
|
13
14
|
|
14
15
|
context.track! self
|
15
16
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class AnonymousRestArgs < Base
|
7
|
+
NAME = "anonymous-rest-args"
|
8
|
+
SYNTAX_PROBE = "obj = Object.new; def obj.foo(*) bar(*); end"
|
9
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("3.2.0")
|
10
|
+
|
11
|
+
REST = :__rest__
|
12
|
+
KWREST = :__kwrest__
|
13
|
+
|
14
|
+
def on_args(node)
|
15
|
+
rest = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :restarg && child.children.first.nil? }
|
16
|
+
kwrest = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :kwrestarg && child.children.first.nil? }
|
17
|
+
|
18
|
+
return super unless rest || kwrest
|
19
|
+
|
20
|
+
context.track! self
|
21
|
+
|
22
|
+
replace(rest.loc.expression, "*#{REST}") if rest
|
23
|
+
replace(kwrest.loc.expression, "**#{KWREST}") if kwrest
|
24
|
+
|
25
|
+
new_args = node.children.map do |child|
|
26
|
+
if child == rest
|
27
|
+
s(:restarg, REST)
|
28
|
+
elsif child == kwrest
|
29
|
+
s(:kwrestarg, KWREST)
|
30
|
+
else
|
31
|
+
child
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
node.updated(:args, new_args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_send(node)
|
39
|
+
return super unless forwarded_args?(node)
|
40
|
+
|
41
|
+
process_send_args(node)
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_super(node)
|
45
|
+
return super unless forwarded_args?(node)
|
46
|
+
|
47
|
+
process_send_args(node)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def forwarded_args?(node)
|
53
|
+
node.children.each do |child|
|
54
|
+
next unless child.is_a?(::Parser::AST::Node)
|
55
|
+
|
56
|
+
if child.type == :forwarded_restarg
|
57
|
+
return true
|
58
|
+
elsif child.type == :kwargs
|
59
|
+
child.children.each do |kwarg|
|
60
|
+
next unless kwarg.is_a?(::Parser::AST::Node)
|
61
|
+
|
62
|
+
return true if kwarg.type == :forwarded_kwrestarg
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def process_send_args(node)
|
71
|
+
process(
|
72
|
+
node.updated(
|
73
|
+
nil,
|
74
|
+
node.children.map do |child|
|
75
|
+
next child unless child.is_a?(::Parser::AST::Node)
|
76
|
+
|
77
|
+
if child.type == :forwarded_restarg
|
78
|
+
replace(child.loc.expression, "*#{REST}")
|
79
|
+
s(:ksplat, s(:lvar, REST))
|
80
|
+
elsif child.type == :kwargs
|
81
|
+
child.updated(
|
82
|
+
nil,
|
83
|
+
child.children.map do |kwarg|
|
84
|
+
next kwarg unless kwarg.is_a?(::Parser::AST::Node)
|
85
|
+
|
86
|
+
if kwarg.type == :forwarded_kwrestarg
|
87
|
+
replace(kwarg.loc.expression, "**#{KWREST}")
|
88
|
+
s(:kwsplat, s(:lvar, KWREST))
|
89
|
+
else
|
90
|
+
kwarg
|
91
|
+
end
|
92
|
+
end
|
93
|
+
)
|
94
|
+
else
|
95
|
+
child
|
96
|
+
end
|
97
|
+
end
|
98
|
+
)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|