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

Sign up to get free protection for your applications and to get access to all the features.
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