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 +4 -4
- data/CHANGELOG.md +15 -1
- data/Gemfile +0 -5
- data/Gemfile.lock +3 -19
- data/bin/bench +11 -6
- data/bin/profile +16 -7
- data/lib/syntax_tree/node.rb +35 -3
- data/lib/syntax_tree/parser.rb +76 -7
- data/lib/syntax_tree/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adfcb697cee07c1c1fa0ad15538079a1fb7f40cfe622317b4cff91546555e463
|
4
|
+
data.tar.gz: 27fc9fe177d07ba066314a8b80f542ae8e6e94fff85f9edaf82cefc32616a7d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
data/Gemfile.lock
CHANGED
@@ -1,46 +1,30 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_tree (2.
|
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.
|
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.
|
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/
|
5
|
-
require "benchmark/ips"
|
4
|
+
require "bundler/inline"
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
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/
|
5
|
-
require "stackprof"
|
4
|
+
require "bundler/inline"
|
6
5
|
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
19
|
-
|
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`
|
data/lib/syntax_tree/node.rb
CHANGED
@@ -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
|
data/lib/syntax_tree/parser.rb
CHANGED
@@ -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:
|
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
|
-
|
1377
|
-
|
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:
|
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.
|
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
|
)
|
data/lib/syntax_tree/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2022-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|