syntax_tree 2.1.1 → 2.2.0

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 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