syntax_tree 2.1.1 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|