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