syntax_tree 2.1.1 → 2.3.1
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 +43 -1
- data/Gemfile +0 -5
- data/Gemfile.lock +3 -15
- data/bin/bench +11 -6
- data/bin/profile +16 -7
- data/lib/syntax_tree/formatter.rb +8 -1
- data/lib/syntax_tree/node.rb +651 -92
- data/lib/syntax_tree/parser.rb +81 -8
- data/lib/syntax_tree/prettyprint.rb +25 -13
- data/lib/syntax_tree/version.rb +1 -1
- metadata +3 -3
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(
|
@@ -2012,12 +2079,16 @@ module SyntaxTree
|
|
2012
2079
|
keyword_rest,
|
2013
2080
|
block
|
2014
2081
|
)
|
2082
|
+
# This is to make it so that required keyword arguments
|
2083
|
+
# have a `nil` for the value instead of a `false`.
|
2084
|
+
keywords&.map! { |(key, value)| [key, value || nil] }
|
2085
|
+
|
2015
2086
|
parts = [
|
2016
2087
|
*requireds,
|
2017
2088
|
*optionals&.flatten(1),
|
2018
2089
|
rest,
|
2019
2090
|
*posts,
|
2020
|
-
*keywords&.
|
2091
|
+
*keywords&.flatten(1),
|
2021
2092
|
(keyword_rest if keyword_rest != :nil),
|
2022
2093
|
(block if block != :&)
|
2023
2094
|
].compact
|
@@ -2638,6 +2709,7 @@ module SyntaxTree
|
|
2638
2709
|
Heredoc.new(
|
2639
2710
|
beginning: heredoc.beginning,
|
2640
2711
|
ending: heredoc.ending,
|
2712
|
+
dedent: heredoc.dedent,
|
2641
2713
|
parts: string.parts,
|
2642
2714
|
location: heredoc.location
|
2643
2715
|
)
|
@@ -3190,6 +3262,7 @@ module SyntaxTree
|
|
3190
3262
|
Heredoc.new(
|
3191
3263
|
beginning: heredoc.beginning,
|
3192
3264
|
ending: heredoc.ending,
|
3265
|
+
dedent: heredoc.dedent,
|
3193
3266
|
parts: xstring.parts,
|
3194
3267
|
location: heredoc.location
|
3195
3268
|
)
|
@@ -79,7 +79,7 @@ class PrettyPrint
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def pretty_print(q)
|
82
|
-
q.group(2, "align([", "])") do
|
82
|
+
q.group(2, "align#{indent}([", "])") do
|
83
83
|
q.seplist(contents) { |content| q.pp(content) }
|
84
84
|
end
|
85
85
|
end
|
@@ -161,7 +161,7 @@ class PrettyPrint
|
|
161
161
|
end
|
162
162
|
|
163
163
|
def pretty_print(q)
|
164
|
-
q.group(2, "group([", "])") do
|
164
|
+
q.group(2, break? ? "breakGroup([" : "group([", "])") do
|
165
165
|
q.seplist(contents) { |content| q.pp(content) }
|
166
166
|
end
|
167
167
|
end
|
@@ -458,6 +458,10 @@ class PrettyPrint
|
|
458
458
|
IfBreakBuilder.new
|
459
459
|
end
|
460
460
|
|
461
|
+
# Also effectively unnecessary, but here for compatibility.
|
462
|
+
def if_flat
|
463
|
+
end
|
464
|
+
|
461
465
|
# A noop that immediately yields.
|
462
466
|
def indent
|
463
467
|
yield
|
@@ -759,9 +763,7 @@ class PrettyPrint
|
|
759
763
|
|
760
764
|
# This is a linear stack instead of a mutually recursive call defined on
|
761
765
|
# the individual doc nodes for efficiency.
|
762
|
-
while commands.
|
763
|
-
indent, mode, doc = commands.pop
|
764
|
-
|
766
|
+
while (indent, mode, doc = commands.pop)
|
765
767
|
case doc
|
766
768
|
when Text
|
767
769
|
doc.objects.each { |object| buffer << object }
|
@@ -789,10 +791,10 @@ class PrettyPrint
|
|
789
791
|
end
|
790
792
|
end
|
791
793
|
when IfBreak
|
792
|
-
if mode == MODE_BREAK
|
793
|
-
commands << [indent, mode, doc.break_contents]
|
794
|
-
elsif mode == MODE_FLAT
|
795
|
-
commands << [indent, mode, doc.flat_contents]
|
794
|
+
if mode == MODE_BREAK && doc.break_contents.any?
|
795
|
+
commands << [indent, mode, doc.break_contents]
|
796
|
+
elsif mode == MODE_FLAT && doc.flat_contents.any?
|
797
|
+
commands << [indent, mode, doc.flat_contents]
|
796
798
|
end
|
797
799
|
when LineSuffix
|
798
800
|
line_suffixes << [indent, mode, doc.contents, doc.priority]
|
@@ -1011,6 +1013,16 @@ class PrettyPrint
|
|
1011
1013
|
IfBreakBuilder.new(self, doc)
|
1012
1014
|
end
|
1013
1015
|
|
1016
|
+
# This is similar to if_break in that it also inserts an IfBreak node into the
|
1017
|
+
# print tree, however it's starting from the flat contents, and cannot be used
|
1018
|
+
# to build the break contents.
|
1019
|
+
def if_flat
|
1020
|
+
doc = IfBreak.new
|
1021
|
+
target << doc
|
1022
|
+
|
1023
|
+
with_target(doc.flat_contents) { yield }
|
1024
|
+
end
|
1025
|
+
|
1014
1026
|
# Very similar to the #nest method, this indents the nested content by one
|
1015
1027
|
# level by inserting an Indent node into the print tree. The contents of the
|
1016
1028
|
# node are determined by the block.
|
@@ -1116,10 +1128,10 @@ class PrettyPrint
|
|
1116
1128
|
when Group
|
1117
1129
|
commands << [indent, doc.break? ? MODE_BREAK : mode, doc.contents]
|
1118
1130
|
when IfBreak
|
1119
|
-
if mode == MODE_BREAK
|
1120
|
-
commands << [indent, mode, doc.break_contents]
|
1121
|
-
|
1122
|
-
commands << [indent, mode, doc.flat_contents]
|
1131
|
+
if mode == MODE_BREAK && doc.break_contents.any?
|
1132
|
+
commands << [indent, mode, doc.break_contents]
|
1133
|
+
elsif mode == MODE_FLAT && doc.flat_contents.any?
|
1134
|
+
commands << [indent, mode, doc.flat_contents]
|
1123
1135
|
end
|
1124
1136
|
when Breakable
|
1125
1137
|
if mode == MODE_FLAT && !doc.force?
|
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.3.1
|
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-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
requirements: []
|
126
|
-
rubygems_version: 3.
|
126
|
+
rubygems_version: 3.4.0.dev
|
127
127
|
signing_key:
|
128
128
|
specification_version: 4
|
129
129
|
summary: A parser based on ripper
|