parser 2.7.1.2 → 2.7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -6
  3. data/CHANGELOG.md +17 -1
  4. data/README.md +1 -2
  5. data/Rakefile +1 -1
  6. data/doc/AST_FORMAT.md +22 -0
  7. data/lib/parser/ast/processor.rb +3 -0
  8. data/lib/parser/builders/default.rb +9 -0
  9. data/lib/parser/diagnostic.rb +1 -1
  10. data/lib/parser/diagnostic/engine.rb +1 -2
  11. data/lib/parser/lexer.rl +7 -0
  12. data/lib/parser/messages.rb +15 -0
  13. data/lib/parser/meta.rb +1 -1
  14. data/lib/parser/ruby28.y +62 -20
  15. data/lib/parser/runner.rb +21 -2
  16. data/lib/parser/runner/ruby_rewrite.rb +2 -2
  17. data/lib/parser/source/buffer.rb +3 -1
  18. data/lib/parser/source/comment/associator.rb +14 -4
  19. data/lib/parser/source/range.rb +7 -0
  20. data/lib/parser/source/tree_rewriter.rb +1 -1
  21. data/lib/parser/tree_rewriter.rb +1 -2
  22. data/lib/parser/version.rb +1 -1
  23. data/parser.gemspec +1 -1
  24. data/test/helper.rb +24 -6
  25. data/test/parse_helper.rb +9 -16
  26. data/test/test_ast_processor.rb +32 -0
  27. data/test/test_base.rb +1 -1
  28. data/test/test_diagnostic.rb +6 -7
  29. data/test/test_diagnostic_engine.rb +5 -8
  30. data/test/test_lexer.rb +5 -8
  31. data/test/test_meta.rb +12 -0
  32. data/test/test_parser.rb +84 -13
  33. data/test/test_runner_parse.rb +22 -1
  34. data/test/test_runner_rewrite.rb +1 -1
  35. data/test/test_source_buffer.rb +4 -1
  36. data/test/test_source_comment.rb +2 -2
  37. data/test/test_source_comment_associator.rb +47 -15
  38. data/test/test_source_map.rb +1 -2
  39. data/test/test_source_range.rb +16 -11
  40. data/test/test_source_rewriter.rb +4 -4
  41. data/test/test_source_rewriter_action.rb +2 -2
  42. data/test/test_source_tree_rewriter.rb +3 -3
  43. metadata +11 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e95a182ac672d1917e517628161ab896f34d4518df71430e0b349998817308e0
4
- data.tar.gz: 24175a8fa5f50956127930f697ba4f09ae0561c359d9fea4ea19883c8c7c072a
3
+ metadata.gz: bab855c4abc633b9ba13f855d816f20948ee539f27bea7878b574f4d0b3232f7
4
+ data.tar.gz: 929aa201a2c06738c6202c8efb2afd2dda77e630805738007c39f3b8274fa717
5
5
  SHA512:
6
- metadata.gz: 95e17dd645e2240c9b3f6d7972a03d2c0df0305548920643c9d930ed3fa8b6aee8da77211b11d80a4d3f651aa75c1c2d43e51daa46aca163bd292ba91e9bcc0e
7
- data.tar.gz: e9b989147352537fb1460a71585ace1165f5bca6d3baa01fde8f83a5b951c305bb37bab9ac93b019c70b728e6152ecd178f07935c335aab5e0f3a8ee4caf83a8
6
+ metadata.gz: 78e2e37d1ef61d2c125c1462ecb2e48ab8f76a06fd97bcba28ea4acd5fa60f77a296f859fd6ad67a787027b7a9e62d0fc34bedc8c23522bce21213d1ca49d780
7
+ data.tar.gz: 07fa5ad8fe63b8503ced8fa0143062385f1d2f99e542f80cc32375269a9ad75f07cc2b0e00838232a71a9e797ba5cab28b661d8a58765f558e29353462641f06
@@ -19,10 +19,10 @@ matrix:
19
19
  script: bundle exec rake test_cov
20
20
  - name: jruby-9.1.15.0 / Parser tests
21
21
  rvm: jruby-9.1.15.0
22
- script: bundle exec rake test_cov
23
- - name: rbx-2 / Parser tests
24
- rvm: rbx-2
25
- script: bundle exec rake test_cov
22
+ script: bundle exec rake test
23
+ - name: truffleruby / Parser tests
24
+ rvm: truffleruby
25
+ script: bundle exec rake test
26
26
  - name: 2.5.8 / Rubocop tests
27
27
  rvm: 2.5.8
28
28
  script: ./ci/run_rubocop_specs
@@ -34,9 +34,7 @@ matrix:
34
34
  script: ./ci/run_rubocop_specs
35
35
  allow_failures:
36
36
  - rvm: ruby-head
37
- - rvm: rbx-2
38
37
  - script: ./ci/run_rubocop_specs
39
38
  before_install:
40
- - gem install bundler -v '< 2'
41
39
  - bundle --version
42
40
  - gem --version
@@ -1,9 +1,25 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- Not released (2020-04-30)
4
+ Not released (2020-05-26)
5
5
  -------------------------
6
6
 
7
+ API modifications:
8
+ * fixed all warnings. tests are running in verbose mode now. (#685) (Ilya Bylich)
9
+
10
+ Features implemented:
11
+ * ruby-[parse, rewrite]: add legacy switches (#699) (Marc-André Lafortune)
12
+ * Added Parser::Source::Range#to_range. (#697) (Ilya Bylich)
13
+ * ruby28.y: support rescue modifier in endless method definition. (#696) (Ilya Bylich)
14
+ * ruby28.y: unify kwrest and no-kwrest rules. (#694) (Ilya Bylich)
15
+ * ruby28.y: add right hand assignment (#682) (Vladimir Dementyev)
16
+
17
+ Bugs fixed:
18
+ * fix Comment.associate for postfix conditions/loops (#688) (Marc-André Lafortune)
19
+
20
+ v2.7.1.2 (2020-04-30)
21
+ ---------------------
22
+
7
23
  Features implemented:
8
24
  * ruby28.y: endless method definition (#676) (Vladimir Dementyev)
9
25
  * ruby28.y: branch parser (#677) (Vladimir Dementyev)
data/README.md CHANGED
@@ -59,8 +59,7 @@ Parse a chunk of code and display all diagnostics:
59
59
  puts diag.render
60
60
  end
61
61
 
62
- buffer = Parser::Source::Buffer.new('(string)')
63
- buffer.source = "foo *bar"
62
+ buffer = Parser::Source::Buffer.new('(string)', source: "foo *bar")
64
63
 
65
64
  p parser.parse(buffer)
66
65
  # (string):1:5: warning: `*' interpreted as argument prefix
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ task :default => [:test]
11
11
  Rake::TestTask.new do |t|
12
12
  t.libs = %w(test/ lib/)
13
13
  t.test_files = FileList["test/**/test_*.rb"]
14
- t.warning = false
14
+ t.warning = true
15
15
  end
16
16
 
17
17
  task :test_cov do
@@ -730,6 +730,28 @@ Format:
730
730
 
731
731
  ~~~
732
732
 
733
+ ### Right-hand assignment
734
+
735
+ Format:
736
+
737
+ ~~~
738
+ (rasgn (int 1) (lvasgn :a))
739
+ "1 => a"
740
+ ~~~~~~ expression
741
+ ~~ operator
742
+ ~~~
743
+
744
+ #### Multiple right-hand assignment
745
+
746
+ Format:
747
+
748
+ ~~~
749
+ (mrasgn (send (int 13) :divmod (int 5)) (mlhs (lvasgn :a) (lvasgn :b)))
750
+ "13.divmod(5) => a,b"
751
+ ~~~~~~~~~~~~~~~~~~~ expression
752
+ ^^ operator
753
+ ~~~
754
+
733
755
  ## Class and module definition
734
756
 
735
757
  ### Module
@@ -75,6 +75,9 @@ module Parser
75
75
  alias on_mlhs process_regular_node
76
76
  alias on_masgn process_regular_node
77
77
 
78
+ alias on_rasgn process_regular_node
79
+ alias on_mrasgn process_regular_node
80
+
78
81
  def on_const(node)
79
82
  scope_node, name = *node
80
83
 
@@ -619,6 +619,15 @@ module Parser
619
619
  binary_op_map(lhs, eql_t, rhs))
620
620
  end
621
621
 
622
+ def rassign(lhs, assoc_t, rhs)
623
+ n(:rasgn, [lhs, rhs], binary_op_map(lhs, assoc_t, rhs))
624
+ end
625
+
626
+ def multi_rassign(lhs, assoc_t, rhs)
627
+ n(:mrasgn, [ lhs, rhs ],
628
+ binary_op_map(lhs, assoc_t, rhs))
629
+ end
630
+
622
631
  #
623
632
  # Class and module definition
624
633
  #
@@ -67,7 +67,7 @@ module Parser
67
67
  # @return [String] the rendered message.
68
68
  #
69
69
  def message
70
- MESSAGES[@reason] % @arguments
70
+ Messages.compile(@reason, @arguments)
71
71
  end
72
72
 
73
73
  ##
@@ -7,8 +7,7 @@ module Parser
7
7
  # diagnostics by delegating them to registered consumers.
8
8
  #
9
9
  # @example
10
- # buffer = Parser::Source::Buffer.new(__FILE__)
11
- # buffer.code = 'foobar'
10
+ # buffer = Parser::Source::Buffer.new(__FILE__, source: 'foobar')
12
11
  #
13
12
  # consumer = lambda do |diagnostic|
14
13
  # puts diagnostic.message
@@ -283,6 +283,13 @@ class Parser::Lexer
283
283
  %% write exec;
284
284
  # %
285
285
 
286
+ # Ragel creates a local variable called `testEof` but it doesn't use
287
+ # it in any assignment. This dead code is here to swallow the warning.
288
+ # It has no runtime cost because Ruby doesn't produce any instructions from it.
289
+ if false
290
+ testEof
291
+ end
292
+
286
293
  @p = p
287
294
 
288
295
  if @token_queue.any?
@@ -93,4 +93,19 @@ module Parser
93
93
  :crossing_insertions => 'the rewriting action on:',
94
94
  :crossing_insertions_conflict => 'is crossing that on:',
95
95
  }.freeze
96
+
97
+ # @api private
98
+ module Messages
99
+ # Formats the message, returns a raw template if there's nothing to interpolate
100
+ #
101
+ # Code like `format("", {})` gives a warning, and so this method tries interpolating
102
+ # only if `arguments` hash is not empty.
103
+ #
104
+ # @api private
105
+ def self.compile(reason, arguments)
106
+ template = MESSAGES[reason]
107
+ return template if Hash === arguments && arguments.empty?
108
+ format(template, arguments)
109
+ end
110
+ end
96
111
  end
@@ -12,7 +12,7 @@ module Parser
12
12
  sym dsym xstr regopt regexp array splat
13
13
  pair kwsplat hash irange erange self
14
14
  lvar ivar cvar gvar const defined? lvasgn
15
- ivasgn cvasgn gvasgn casgn mlhs masgn
15
+ ivasgn cvasgn gvasgn casgn mlhs masgn rasgn mrasgn
16
16
  op_asgn and_asgn ensure rescue arg_expr
17
17
  or_asgn back_ref nth_ref
18
18
  match_with_lvasgn match_current_line
@@ -206,8 +206,26 @@ rule
206
206
  {
207
207
  result = @builder.multi_assign(val[0], val[1], val[2])
208
208
  }
209
+ | rassign
209
210
  | expr
210
211
 
212
+ rassign: arg_value tASSOC lhs
213
+ {
214
+ result = @builder.rassign(val[0], val[1], val[2])
215
+ }
216
+ | arg_value tASSOC mlhs
217
+ {
218
+ result = @builder.multi_rassign(val[0], val[1], val[2])
219
+ }
220
+ | rassign tASSOC lhs
221
+ {
222
+ result = @builder.rassign(val[0], val[1], val[2])
223
+ }
224
+ | rassign tASSOC mlhs
225
+ {
226
+ result = @builder.multi_rassign(val[0], val[1], val[2])
227
+ }
228
+
211
229
  command_asgn: lhs tEQL command_rhs
212
230
  {
213
231
  result = @builder.assign(val[0], val[1], val[2])
@@ -851,6 +869,23 @@ rule
851
869
  result = @builder.def_endless_method(*val[0],
852
870
  val[1], val[2], val[3])
853
871
 
872
+ @lexer.cmdarg.pop
873
+ @lexer.cond.pop
874
+ @static_env.unextend
875
+ @context.pop
876
+ @current_arg_stack.pop
877
+ }
878
+ | defn_head f_paren_args tEQL arg kRESCUE_MOD arg
879
+ {
880
+ rescue_body = @builder.rescue_body(val[4],
881
+ nil, nil, nil,
882
+ nil, val[5])
883
+
884
+ method_body = @builder.begin_body(val[3], [ rescue_body ])
885
+
886
+ result = @builder.def_endless_method(*val[0],
887
+ val[1], val[2], method_body)
888
+
854
889
  @lexer.cmdarg.pop
855
890
  @lexer.cond.pop
856
891
  @static_env.unextend
@@ -862,6 +897,23 @@ rule
862
897
  result = @builder.def_endless_singleton(*val[0],
863
898
  val[1], val[2], val[3])
864
899
 
900
+ @lexer.cmdarg.pop
901
+ @lexer.cond.pop
902
+ @static_env.unextend
903
+ @context.pop
904
+ @current_arg_stack.pop
905
+ }
906
+ | defs_head f_paren_args tEQL arg kRESCUE_MOD arg
907
+ {
908
+ rescue_body = @builder.rescue_body(val[4],
909
+ nil, nil, nil,
910
+ nil, val[5])
911
+
912
+ method_body = @builder.begin_body(val[3], [ rescue_body ])
913
+
914
+ result = @builder.def_endless_singleton(*val[0],
915
+ val[1], val[2], method_body)
916
+
865
917
  @lexer.cmdarg.pop
866
918
  @lexer.cond.pop
867
919
  @static_env.unextend
@@ -1401,6 +1453,9 @@ rule
1401
1453
  result = @builder.restarg(val[0])
1402
1454
  }
1403
1455
 
1456
+ f_any_kwrest: f_kwrest
1457
+ | f_no_kwarg
1458
+
1404
1459
  block_args_tail: f_block_kwarg tCOMMA f_kwrest opt_f_block_arg
1405
1460
  {
1406
1461
  result = val[0].concat(val[2]).concat(val[3])
@@ -1409,11 +1464,7 @@ rule
1409
1464
  {
1410
1465
  result = val[0].concat(val[1])
1411
1466
  }
1412
- | f_kwrest opt_f_block_arg
1413
- {
1414
- result = val[0].concat(val[1])
1415
- }
1416
- | f_no_kwarg opt_f_block_arg
1467
+ | f_any_kwrest opt_f_block_arg
1417
1468
  {
1418
1469
  result = val[0].concat(val[1])
1419
1470
  }
@@ -2012,7 +2063,7 @@ opt_block_args_tail:
2012
2063
 
2013
2064
  p_arg: p_expr
2014
2065
 
2015
- p_kwargs: p_kwarg tCOMMA p_kwrest
2066
+ p_kwargs: p_kwarg tCOMMA p_any_kwrest
2016
2067
  {
2017
2068
  result = [ *val[0], *val[2] ]
2018
2069
  }
@@ -2024,18 +2075,10 @@ opt_block_args_tail:
2024
2075
  {
2025
2076
  result = val[0]
2026
2077
  }
2027
- | p_kwrest
2078
+ | p_any_kwrest
2028
2079
  {
2029
2080
  result = val[0]
2030
2081
  }
2031
- | p_kwarg tCOMMA p_kwnorest
2032
- {
2033
- result = [ *val[0], *val[2] ]
2034
- }
2035
- | p_kwnorest
2036
- {
2037
- result = [ *val[0], *val[2] ]
2038
- }
2039
2082
 
2040
2083
  p_kwarg: p_kw
2041
2084
  {
@@ -2079,6 +2122,9 @@ opt_block_args_tail:
2079
2122
  result = [ @builder.match_nil_pattern(val[0], val[1]) ]
2080
2123
  }
2081
2124
 
2125
+ p_any_kwrest: p_kwrest
2126
+ | p_kwnorest
2127
+
2082
2128
  p_value: p_primitive
2083
2129
  | p_primitive tDOT2 p_primitive
2084
2130
  {
@@ -2579,11 +2625,7 @@ keyword_variable: kNIL
2579
2625
  {
2580
2626
  result = val[0].concat(val[1])
2581
2627
  }
2582
- | f_kwrest opt_f_block_arg
2583
- {
2584
- result = val[0].concat(val[1])
2585
- }
2586
- | f_no_kwarg opt_f_block_arg
2628
+ | f_any_kwrest opt_f_block_arg
2587
2629
  {
2588
2630
  result = val[0].concat(val[1])
2589
2631
  }
@@ -14,9 +14,8 @@ module Parser
14
14
  end
15
15
 
16
16
  def initialize
17
- Parser::Builders::Default.modernize
18
-
19
17
  @option_parser = OptionParser.new { |opts| setup_option_parsing(opts) }
18
+ @legacy = {}
20
19
  @parser_class = nil
21
20
  @parser = nil
22
21
  @files = []
@@ -30,6 +29,7 @@ module Parser
30
29
 
31
30
  def execute(options)
32
31
  parse_options(options)
32
+ setup_builder_default
33
33
  prepare_parser
34
34
 
35
35
  process_all_input
@@ -37,6 +37,8 @@ module Parser
37
37
 
38
38
  private
39
39
 
40
+ LEGACY_MODES = %i[lambda procarg0 encoding index arg_inside_procarg0].freeze
41
+
40
42
  def runner_name
41
43
  raise NotImplementedError, "implement #{self.class}##{__callee__}"
42
44
  end
@@ -126,6 +128,17 @@ module Parser
126
128
  @parser_class = Parser::RubyMotion
127
129
  end
128
130
 
131
+ opts.on '--legacy', "Parse with all legacy modes" do
132
+ @legacy = Hash.new(true)
133
+ end
134
+
135
+ LEGACY_MODES.each do |mode|
136
+ opt_name = "--legacy-#{mode.to_s.gsub('_', '-')}"
137
+ opts.on opt_name, "Parse with legacy mode for emit_#{mode}" do
138
+ @legacy[mode] = true
139
+ end
140
+ end
141
+
129
142
  opts.on '-w', '--warnings', 'Enable warnings' do |w|
130
143
  @warnings = w
131
144
  end
@@ -164,6 +177,12 @@ module Parser
164
177
  end
165
178
  end
166
179
 
180
+ def setup_builder_default
181
+ LEGACY_MODES.each do |mode|
182
+ Parser::Builders::Default.send(:"emit_#{mode}=", !@legacy[mode])
183
+ end
184
+ end
185
+
167
186
  def prepare_parser
168
187
  @parser = @parser_class.new
169
188
 
@@ -55,8 +55,8 @@ module Parser
55
55
  new_source = rewriter.rewrite(buffer, ast)
56
56
 
57
57
  new_buffer = Source::Buffer.new(initial_buffer.name +
58
- '|after ' + rewriter_class.name)
59
- new_buffer.source = new_source
58
+ '|after ' + rewriter_class.name,
59
+ source: new_source)
60
60
 
61
61
  @parser.reset
62
62
  new_ast = @parser.parse(new_buffer)
@@ -102,7 +102,7 @@ module Parser
102
102
  end
103
103
  end
104
104
 
105
- def initialize(name, first_line = 1)
105
+ def initialize(name, first_line = 1, source: nil)
106
106
  @name = name.to_s
107
107
  @source = nil
108
108
  @first_line = first_line
@@ -116,6 +116,8 @@ module Parser
116
116
  # Cache for fast lookup
117
117
  @line_for_position = {}
118
118
  @column_for_position = {}
119
+
120
+ self.source = source if source
119
121
  end
120
122
 
121
123
  ##
@@ -107,6 +107,19 @@ module Parser
107
107
 
108
108
  private
109
109
 
110
+ POSTFIX_TYPES = Set[:if, :while, :while_post, :until, :until_post].freeze
111
+ def children_in_source_order(node)
112
+ if POSTFIX_TYPES.include?(node.type)
113
+ # All these types have either nodes with expressions, or `nil`
114
+ # so a compact will do, but they need to be sorted.
115
+ node.children.compact.sort_by { |child| child.loc.expression.begin_pos }
116
+ else
117
+ node.children.select do |child|
118
+ child.is_a?(AST::Node) && child.loc && child.loc.expression
119
+ end
120
+ end
121
+ end
122
+
110
123
  def do_associate
111
124
  @mapping = Hash.new { |h, k| h[k] = [] }
112
125
  @comment_num = -1
@@ -131,10 +144,7 @@ module Parser
131
144
  node_loc = node.location
132
145
  if @current_comment.location.line <= node_loc.last_line ||
133
146
  node_loc.is_a?(Map::Heredoc)
134
- node.children.each do |child|
135
- next unless child.is_a?(AST::Node) && child.loc && child.loc.expression
136
- visit(child)
137
- end
147
+ children_in_source_order(node).each { |child| visit(child) }
138
148
 
139
149
  process_trailing_comments(node)
140
150
  end