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.
@@ -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(
@@ -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&.flat_map { |(key, value)| [key, value || nil] },
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.any?
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] if doc.break_contents
794
- elsif mode == MODE_FLAT
795
- commands << [indent, mode, doc.flat_contents] if 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] if doc.break_contents
1121
- else
1122
- commands << [indent, mode, doc.flat_contents] if 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?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "2.1.1"
4
+ VERSION = "2.3.1"
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.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-17 00:00:00.000000000 Z
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.3.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