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
         |