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.
@@ -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