syntax_tree 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd341a51ce36b230703bfbe86078641e7670058a3e41d0dbb125548c0821a65a
4
- data.tar.gz: 9ebdca60f2956e24f83a58749266c89eb0eed88003a06699432956a0ecfa735a
3
+ metadata.gz: adfcb697cee07c1c1fa0ad15538079a1fb7f40cfe622317b4cff91546555e463
4
+ data.tar.gz: 27fc9fe177d07ba066314a8b80f542ae8e6e94fff85f9edaf82cefc32616a7d1
5
5
  SHA512:
6
- metadata.gz: b8292d8020afa5ece8afdbaa60e959902357e769f098c75894d2b85686a20f824cf510563b2cd31e86b3f8f781f74cf8aaafac76e0e156e26897999ccb72ae36
7
- data.tar.gz: 968a355401a9bd1ca6a3e67d60e5587485de9ad3ad2a5f9e8cbe7add95622364e4c094a757035482c35377ab75cb14926af1f5ab8a0df0e5069ba69f7bed1851
6
+ metadata.gz: 975dc25af26617665dec05c4a902732b693045be67917dba0f0b1e4c8a7e3016a8c69d1556f850c8be2b9f2d6fb07d06d6ee0d69245cd71ab5067f4d0690e909
7
+ data.tar.gz: 302d3744abc6cea5ce13d094322ff4071dc3c9487442f7c74fccd2a1ff7bb93ddc98017a5b5997369795df80b098981f8cbbe34c54315db4ccffc7a8e92f546c
data/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.2.0] - 2022-04-19
10
+
11
+ ### Added
12
+
13
+ - [#51](https://github.com/ruby-syntax-tree/syntax_tree/pull/51) - `SyntaxTree::Location` nodes now have pattern matching.
14
+ - [#51](https://github.com/ruby-syntax-tree/syntax_tree/pull/51) - `SyntaxTree::Heredoc` now have a `dedent` field that indicates the number of spaces to strip from the beginning of the string content.
15
+
16
+ ### Changed
17
+
18
+ - [#51](https://github.com/ruby-syntax-tree/syntax_tree/pull/51) - `SyntaxTree::HshPtn` will now add a `then` if you use a bare `**` and `SyntaxTree::AryPtn` will do the same for a bare `*` on the end.
19
+ - [#51](https://github.com/ruby-syntax-tree/syntax_tree/pull/51) - `SyntaxTree::MLHSParen` now has a comma field in case a trailing comma has been added to a parenthesis destructuring, as in `((foo,))`.
20
+ - [#51](https://github.com/ruby-syntax-tree/syntax_tree/pull/51) - `SyntaxTree::FndPtn` has much improved parsing now.
21
+
9
22
  ## [2.1.1] - 2022-04-16
10
23
 
11
24
  ### Changed
@@ -153,7 +166,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
153
166
 
154
167
  - 🎉 Initial release! 🎉
155
168
 
156
- [unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.1.1...HEAD
169
+ [unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.2.0...HEAD
170
+ [2.2.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.1.1...v2.2.0
157
171
  [2.1.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.1.0...v2.1.1
158
172
  [2.1.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.0.1...v2.1.0
159
173
  [2.0.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.0.0...v2.0.1
data/Gemfile CHANGED
@@ -3,8 +3,3 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
-
7
- gem "benchmark-ips"
8
- gem "parser"
9
- gem "ruby_parser"
10
- gem "stackprof"
data/Gemfile.lock CHANGED
@@ -1,46 +1,30 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- syntax_tree (2.1.1)
4
+ syntax_tree (2.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- ast (2.4.2)
10
- benchmark-ips (2.10.0)
11
9
  docile (1.4.0)
12
10
  minitest (5.15.0)
13
- parser (3.1.2.0)
14
- ast (~> 2.4.1)
15
11
  rake (13.0.6)
16
- ruby_parser (3.19.1)
17
- sexp_processor (~> 4.16)
18
- sexp_processor (4.16.0)
19
12
  simplecov (0.21.2)
20
13
  docile (~> 1.1)
21
14
  simplecov-html (~> 0.11)
22
15
  simplecov_json_formatter (~> 0.1)
23
16
  simplecov-html (0.12.3)
24
- simplecov_json_formatter (0.1.3)
25
- stackprof (0.2.19)
17
+ simplecov_json_formatter (0.1.4)
26
18
 
27
19
  PLATFORMS
28
- arm64-darwin-21
29
- ruby
30
- x86_64-darwin-19
31
20
  x86_64-darwin-21
32
- x86_64-linux
33
21
 
34
22
  DEPENDENCIES
35
- benchmark-ips
36
23
  bundler
37
24
  minitest
38
- parser
39
25
  rake
40
- ruby_parser
41
26
  simplecov
42
- stackprof
43
27
  syntax_tree!
44
28
 
45
29
  BUNDLED WITH
46
- 2.2.31
30
+ 2.3.6
data/bin/bench CHANGED
@@ -1,12 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "benchmark/ips"
4
+ require "bundler/inline"
6
5
 
7
- require_relative "../lib/syntax_tree"
8
- require "ruby_parser"
9
- require "parser/current"
6
+ gemfile do
7
+ source "https://rubygems.org"
8
+ gem "benchmark-ips"
9
+ gem "parser", require: "parser/current"
10
+ gem "ruby_parser"
11
+ end
12
+
13
+ $:.unshift(File.expand_path("../lib", __dir__))
14
+ require "syntax_tree"
10
15
 
11
16
  def compare(filepath)
12
17
  prefix = "#{File.expand_path("..", __dir__)}/"
@@ -30,7 +35,7 @@ filepaths = ARGV
30
35
  if filepaths.empty?
31
36
  filepaths = [
32
37
  File.expand_path("bench", __dir__),
33
- File.expand_path("../lib/syntax_tree.rb", __dir__)
38
+ File.expand_path("../lib/syntax_tree/node.rb", __dir__)
34
39
  ]
35
40
  end
36
41
 
data/bin/profile CHANGED
@@ -1,19 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "stackprof"
4
+ require "bundler/inline"
6
5
 
7
- filepath = File.expand_path("../lib/syntax_tree", __dir__)
8
- require_relative filepath
6
+ gemfile do
7
+ source "https://rubygems.org"
8
+ gem "stackprof"
9
+ end
10
+
11
+ $:.unshift(File.expand_path("../lib", __dir__))
12
+ require "syntax_tree"
9
13
 
10
14
  GC.disable
11
15
 
12
16
  StackProf.run(mode: :cpu, out: "tmp/profile.dump", raw: true) do
13
- SyntaxTree.format(File.read("#{filepath}.rb"))
17
+ filepath = File.expand_path("../lib/syntax_tree/node.rb", __dir__)
18
+ SyntaxTree.format(File.read(filepath))
14
19
  end
15
20
 
16
21
  GC.enable
17
22
 
18
- `bundle exec stackprof --d3-flamegraph tmp/profile.dump > tmp/flamegraph.html`
19
- puts "open tmp/flamegraph.html"
23
+ File.open("tmp/flamegraph.html", "w") do |file|
24
+ report = Marshal.load(IO.binread("tmp/profile.dump"))
25
+ StackProf::Report.new(report).print_d3_flamegraph(file)
26
+ end
27
+
28
+ `open tmp/flamegraph.html`
@@ -35,6 +35,21 @@ module SyntaxTree
35
35
  )
36
36
  end
37
37
 
38
+ def deconstruct
39
+ [start_line, start_char, start_column, end_line, end_char, end_column]
40
+ end
41
+
42
+ def deconstruct_keys(keys)
43
+ {
44
+ start_line: start_line,
45
+ start_char: start_char,
46
+ start_column: start_column,
47
+ end_line: end_line,
48
+ end_char: end_char,
49
+ end_column: end_column
50
+ }
51
+ end
52
+
38
53
  def self.token(line:, char:, column:, size:)
39
54
  new(
40
55
  start_line: line,
@@ -4334,6 +4349,9 @@ module SyntaxTree
4334
4349
  # [String] the ending of the heredoc
4335
4350
  attr_reader :ending
4336
4351
 
4352
+ # [Integer] how far to dedent the heredoc
4353
+ attr_reader :dedent
4354
+
4337
4355
  # [Array[ StringEmbExpr | StringDVar | TStringContent ]] the parts of the
4338
4356
  # heredoc string literal
4339
4357
  attr_reader :parts
@@ -4341,9 +4359,10 @@ module SyntaxTree
4341
4359
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
4342
4360
  attr_reader :comments
4343
4361
 
4344
- def initialize(beginning:, ending: nil, parts: [], location:, comments: [])
4362
+ def initialize(beginning:, ending: nil, dedent: 0, parts: [], location:, comments: [])
4345
4363
  @beginning = beginning
4346
4364
  @ending = ending
4365
+ @dedent = dedent
4347
4366
  @parts = parts
4348
4367
  @location = location
4349
4368
  @comments = comments
@@ -4538,7 +4557,12 @@ module SyntaxTree
4538
4557
  parts << KeywordRestFormatter.new(keyword_rest) if keyword_rest
4539
4558
 
4540
4559
  contents = -> do
4541
- q.seplist(parts) { |part| q.format(part, stackable: false) }
4560
+ q.group { q.seplist(parts) { |part| q.format(part, stackable: false) } }
4561
+
4562
+ # If there isn't a constant, and there's a blank keyword_rest, then we
4563
+ # have an plain ** that needs to have a `then` after it in order to
4564
+ # parse correctly on the next parse.
4565
+ q.text(" then") if !constant && keyword_rest && keyword_rest.value.nil?
4542
4566
  end
4543
4567
 
4544
4568
  if constant
@@ -5594,11 +5618,17 @@ module SyntaxTree
5594
5618
  # [MLHS | MLHSParen] the contents inside of the parentheses
5595
5619
  attr_reader :contents
5596
5620
 
5621
+ # [boolean] whether or not there is a trailing comma at the end of this
5622
+ # list, which impacts destructuring. It's an attr_accessor so that while
5623
+ # the syntax tree is being built it can be set by its parent node
5624
+ attr_accessor :comma
5625
+
5597
5626
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
5598
5627
  attr_reader :comments
5599
5628
 
5600
- def initialize(contents:, location:, comments: [])
5629
+ def initialize(contents:, comma: false, location:, comments: [])
5601
5630
  @contents = contents
5631
+ @comma = comma
5602
5632
  @location = location
5603
5633
  @comments = comments
5604
5634
  end
@@ -5622,6 +5652,7 @@ module SyntaxTree
5622
5652
 
5623
5653
  if parent.is_a?(MAssign) || parent.is_a?(MLHSParen)
5624
5654
  q.format(contents)
5655
+ q.text(",") if comma
5625
5656
  else
5626
5657
  q.group(0, "(", ")") do
5627
5658
  q.indent do
@@ -5629,6 +5660,7 @@ module SyntaxTree
5629
5660
  q.format(contents)
5630
5661
  end
5631
5662
 
5663
+ q.text(",") if comma
5632
5664
  q.breakable("")
5633
5665
  end
5634
5666
  end
@@ -516,12 +516,46 @@ module SyntaxTree
516
516
  def on_aryptn(constant, requireds, rest, posts)
517
517
  parts = [constant, *requireds, rest, *posts].compact
518
518
 
519
+ # If there aren't any parts (no constant, no positional arguments), then
520
+ # we're matching an empty array. In this case, we're going to look for the
521
+ # left and right brackets explicitly. Otherwise, we'll just use the bounds
522
+ # of the various parts.
523
+ location =
524
+ if parts.empty?
525
+ find_token(LBracket).location.to(find_token(RBracket).location)
526
+ else
527
+ parts[0].location.to(parts[-1].location)
528
+ end
529
+
530
+ # If there's the optional then keyword, then we'll delete that and use it
531
+ # as the end bounds of the location.
532
+ if token = find_token(Kw, "then", consume: false)
533
+ tokens.delete(token)
534
+ location = location.to(token.location)
535
+ end
536
+
537
+ # If there is a plain *, then we're going to fix up the location of it
538
+ # here because it currently doesn't have anything to use for its precise
539
+ # location. If we hit a comma, then we've gone too far.
540
+ if rest.is_a?(VarField) && rest.value.nil?
541
+ tokens.rindex do |token|
542
+ case token
543
+ in Op[value: "*"]
544
+ rest = VarField.new(value: nil, location: token.location)
545
+ break
546
+ in Comma
547
+ break
548
+ else
549
+ end
550
+ end
551
+ end
552
+
519
553
  AryPtn.new(
520
554
  constant: constant,
521
555
  requireds: requireds || [],
522
556
  rest: rest,
523
557
  posts: posts || [],
524
- location: parts[0].location.to(parts[-1].location)
558
+ location: location
525
559
  )
526
560
  end
527
561
 
@@ -1373,15 +1407,35 @@ module SyntaxTree
1373
1407
  # VarField right
1374
1408
  # ) -> FndPtn
1375
1409
  def on_fndptn(constant, left, values, right)
1376
- beginning = constant || find_token(LBracket)
1377
- ending = find_token(RBracket)
1410
+ # The opening of this find pattern is either going to be a left bracket, a
1411
+ # right left parenthesis, or the left splat. We're going to use this to
1412
+ # determine how to find the closing of the pattern, as well as determining
1413
+ # the location of the node.
1414
+ opening =
1415
+ find_token(LBracket, consume: false) ||
1416
+ find_token(LParen, consume: false) ||
1417
+ left
1418
+
1419
+ # The closing is based on the opening, which is either the matched
1420
+ # punctuation or the right splat.
1421
+ closing =
1422
+ case opening
1423
+ in LBracket
1424
+ tokens.delete(opening)
1425
+ find_token(RBracket)
1426
+ in LParen
1427
+ tokens.delete(opening)
1428
+ find_token(RParen)
1429
+ else
1430
+ right
1431
+ end
1378
1432
 
1379
1433
  FndPtn.new(
1380
1434
  constant: constant,
1381
1435
  left: left,
1382
1436
  values: values,
1383
1437
  right: right,
1384
- location: beginning.location.to(ending.location)
1438
+ location: (constant || opening).location.to(closing.location)
1385
1439
  )
1386
1440
  end
1387
1441
 
@@ -1468,6 +1522,7 @@ module SyntaxTree
1468
1522
  @heredocs[-1] = Heredoc.new(
1469
1523
  beginning: heredoc.beginning,
1470
1524
  ending: heredoc.ending,
1525
+ dedent: width,
1471
1526
  parts: string.parts,
1472
1527
  location: heredoc.location
1473
1528
  )
@@ -1481,6 +1536,7 @@ module SyntaxTree
1481
1536
  @heredocs[-1] = Heredoc.new(
1482
1537
  beginning: heredoc.beginning,
1483
1538
  ending: value.chomp,
1539
+ dedent: heredoc.dedent,
1484
1540
  parts: heredoc.parts,
1485
1541
  location:
1486
1542
  Location.new(
@@ -1501,12 +1557,23 @@ module SyntaxTree
1501
1557
  # (nil | VarField) keyword_rest
1502
1558
  # ) -> HshPtn
1503
1559
  def on_hshptn(constant, keywords, keyword_rest)
1560
+ # Create an artificial VarField if we find an extra ** on the end
1561
+ if !keyword_rest && (token = find_token(Op, "**", consume: false))
1562
+ tokens.delete(token)
1563
+ keyword_rest = VarField.new(value: nil, location: token.location)
1564
+ end
1565
+
1566
+ # Delete the optional then keyword
1567
+ if token = find_token(Kw, "then", consume: false)
1568
+ tokens.delete(token)
1569
+ end
1570
+
1504
1571
  parts = [constant, *keywords&.flatten(1), keyword_rest].compact
1505
1572
  location =
1506
- if parts.empty?
1507
- find_token(LBrace).location.to(find_token(RBrace).location)
1508
- else
1573
+ if parts.any?
1509
1574
  parts[0].location.to(parts[-1].location)
1575
+ else
1576
+ find_token(LBrace).location.to(find_token(RBrace).location)
1510
1577
  end
1511
1578
 
1512
1579
  HshPtn.new(
@@ -2638,6 +2705,7 @@ module SyntaxTree
2638
2705
  Heredoc.new(
2639
2706
  beginning: heredoc.beginning,
2640
2707
  ending: heredoc.ending,
2708
+ dedent: heredoc.dedent,
2641
2709
  parts: string.parts,
2642
2710
  location: heredoc.location
2643
2711
  )
@@ -3190,6 +3258,7 @@ module SyntaxTree
3190
3258
  Heredoc.new(
3191
3259
  beginning: heredoc.beginning,
3192
3260
  ending: heredoc.ending,
3261
+ dedent: heredoc.dedent,
3193
3262
  parts: xstring.parts,
3194
3263
  location: heredoc.location
3195
3264
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syntax_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Newton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-17 00:00:00.000000000 Z
11
+ date: 2022-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler