prism 0.16.0 → 0.17.0
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 +16 -1
 - data/Makefile +6 -0
 - data/README.md +1 -1
 - data/config.yml +50 -35
 - data/docs/fuzzing.md +1 -1
 - data/docs/serialization.md +28 -29
 - data/ext/prism/api_node.c +802 -770
 - data/ext/prism/api_pack.c +20 -9
 - data/ext/prism/extension.c +464 -162
 - data/ext/prism/extension.h +1 -1
 - data/include/prism/ast.h +3173 -763
 - data/include/prism/defines.h +32 -9
 - data/include/prism/diagnostic.h +36 -3
 - data/include/prism/enc/pm_encoding.h +118 -28
 - data/include/prism/node.h +38 -13
 - data/include/prism/options.h +204 -0
 - data/include/prism/pack.h +44 -33
 - data/include/prism/parser.h +445 -200
 - data/include/prism/prettyprint.h +12 -1
 - data/include/prism/regexp.h +16 -2
 - data/include/prism/util/pm_buffer.h +94 -16
 - data/include/prism/util/pm_char.h +162 -48
 - data/include/prism/util/pm_constant_pool.h +126 -32
 - data/include/prism/util/pm_list.h +68 -38
 - data/include/prism/util/pm_memchr.h +18 -3
 - data/include/prism/util/pm_newline_list.h +70 -27
 - data/include/prism/util/pm_state_stack.h +25 -7
 - data/include/prism/util/pm_string.h +115 -27
 - data/include/prism/util/pm_string_list.h +25 -6
 - data/include/prism/util/pm_strncasecmp.h +32 -0
 - data/include/prism/util/pm_strpbrk.h +31 -17
 - data/include/prism/version.h +27 -2
 - data/include/prism.h +224 -31
 - data/lib/prism/compiler.rb +6 -3
 - data/lib/prism/debug.rb +23 -7
 - data/lib/prism/dispatcher.rb +33 -18
 - data/lib/prism/dsl.rb +10 -5
 - data/lib/prism/ffi.rb +132 -80
 - data/lib/prism/lex_compat.rb +25 -15
 - data/lib/prism/mutation_compiler.rb +10 -5
 - data/lib/prism/node.rb +370 -135
 - data/lib/prism/node_ext.rb +1 -1
 - data/lib/prism/node_inspector.rb +1 -1
 - data/lib/prism/pack.rb +79 -40
 - data/lib/prism/parse_result/comments.rb +7 -2
 - data/lib/prism/parse_result/newlines.rb +4 -0
 - data/lib/prism/parse_result.rb +150 -30
 - data/lib/prism/pattern.rb +11 -0
 - data/lib/prism/ripper_compat.rb +28 -10
 - data/lib/prism/serialize.rb +86 -54
 - data/lib/prism/visitor.rb +10 -3
 - data/lib/prism.rb +20 -2
 - data/prism.gemspec +4 -2
 - data/rbi/prism.rbi +104 -60
 - data/rbi/prism_static.rbi +16 -2
 - data/sig/prism.rbs +72 -43
 - data/sig/prism_static.rbs +14 -1
 - data/src/diagnostic.c +56 -53
 - data/src/enc/pm_big5.c +1 -0
 - data/src/enc/pm_euc_jp.c +1 -0
 - data/src/enc/pm_gbk.c +1 -0
 - data/src/enc/pm_shift_jis.c +1 -0
 - data/src/enc/pm_tables.c +316 -80
 - data/src/enc/pm_unicode.c +53 -8
 - data/src/enc/pm_windows_31j.c +1 -0
 - data/src/node.c +334 -321
 - data/src/options.c +170 -0
 - data/src/prettyprint.c +74 -47
 - data/src/prism.c +1642 -856
 - data/src/regexp.c +151 -95
 - data/src/serialize.c +44 -20
 - data/src/token_type.c +3 -1
 - data/src/util/pm_buffer.c +45 -15
 - data/src/util/pm_char.c +103 -57
 - data/src/util/pm_constant_pool.c +51 -21
 - data/src/util/pm_list.c +12 -4
 - data/src/util/pm_memchr.c +5 -3
 - data/src/util/pm_newline_list.c +20 -12
 - data/src/util/pm_state_stack.c +9 -3
 - data/src/util/pm_string.c +95 -85
 - data/src/util/pm_string_list.c +14 -15
 - data/src/util/pm_strncasecmp.c +10 -3
 - data/src/util/pm_strpbrk.c +25 -19
 - metadata +5 -3
 - data/docs/prism.png +0 -0
 
    
        data/lib/prism/node_ext.rb
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            # Here we are reopening the prism module to provide methods on nodes that aren't
         
     | 
| 
       4 
4 
     | 
    
         
             
            # templated and are meant as convenience methods.
         
     | 
| 
       5 
5 
     | 
    
         
             
            module Prism
         
     | 
| 
       6 
     | 
    
         
            -
              module RegularExpressionOptions
         
     | 
| 
      
 6 
     | 
    
         
            +
              module RegularExpressionOptions # :nodoc:
         
     | 
| 
       7 
7 
     | 
    
         
             
                # Returns a numeric value that represents the flags that were used to create
         
     | 
| 
       8 
8 
     | 
    
         
             
                # the regular expression.
         
     | 
| 
       9 
9 
     | 
    
         
             
                def options
         
     | 
    
        data/lib/prism/node_inspector.rb
    CHANGED
    
    
    
        data/lib/prism/pack.rb
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Prism
         
     | 
| 
      
 4 
     | 
    
         
            +
              # A parser for the pack template language.
         
     | 
| 
       4 
5 
     | 
    
         
             
              module Pack
         
     | 
| 
       5 
6 
     | 
    
         
             
                %i[
         
     | 
| 
       6 
7 
     | 
    
         
             
                  SPACE
         
     | 
| 
         @@ -54,9 +55,36 @@ module Prism 
     | 
|
| 
       54 
55 
     | 
    
         
             
                  const_set(const, const)
         
     | 
| 
       55 
56 
     | 
    
         
             
                end
         
     | 
| 
       56 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
                # A directive in the pack template language.
         
     | 
| 
       57 
59 
     | 
    
         
             
                class Directive
         
     | 
| 
       58 
     | 
    
         
            -
                   
     | 
| 
      
 60 
     | 
    
         
            +
                  # A symbol representing the version of Ruby.
         
     | 
| 
      
 61 
     | 
    
         
            +
                  attr_reader :version
         
     | 
| 
       59 
62 
     | 
    
         | 
| 
      
 63 
     | 
    
         
            +
                  # A symbol representing whether or not we are packing or unpacking.
         
     | 
| 
      
 64 
     | 
    
         
            +
                  attr_reader :variant
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  # A byteslice of the source string that this directive represents.
         
     | 
| 
      
 67 
     | 
    
         
            +
                  attr_reader :source
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  # The type of the directive.
         
     | 
| 
      
 70 
     | 
    
         
            +
                  attr_reader :type
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  # The type of signedness of the directive.
         
     | 
| 
      
 73 
     | 
    
         
            +
                  attr_reader :signed
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  # The type of endianness of the directive.
         
     | 
| 
      
 76 
     | 
    
         
            +
                  attr_reader :endian
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  # The size of the directive.
         
     | 
| 
      
 79 
     | 
    
         
            +
                  attr_reader :size
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  # The length type of this directive (used for integers).
         
     | 
| 
      
 82 
     | 
    
         
            +
                  attr_reader :length_type
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  # The length of this directive (used for integers).
         
     | 
| 
      
 85 
     | 
    
         
            +
                  attr_reader :length
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  # Initialize a new directive with the given values.
         
     | 
| 
       60 
88 
     | 
    
         
             
                  def initialize(version, variant, source, type, signed, endian, size, length_type, length)
         
     | 
| 
       61 
89 
     | 
    
         
             
                    @version = version
         
     | 
| 
       62 
90 
     | 
    
         
             
                    @variant = variant
         
     | 
| 
         @@ -69,38 +97,42 @@ module Prism 
     | 
|
| 
       69 
97 
     | 
    
         
             
                    @length = length
         
     | 
| 
       70 
98 
     | 
    
         
             
                  end
         
     | 
| 
       71 
99 
     | 
    
         | 
| 
      
 100 
     | 
    
         
            +
                  # The descriptions of the various types of endianness.
         
     | 
| 
       72 
101 
     | 
    
         
             
                  ENDIAN_DESCRIPTIONS = {
         
     | 
| 
       73 
     | 
    
         
            -
                    AGNOSTIC_ENDIAN:  
     | 
| 
       74 
     | 
    
         
            -
                    LITTLE_ENDIAN:  
     | 
| 
       75 
     | 
    
         
            -
                    BIG_ENDIAN:  
     | 
| 
       76 
     | 
    
         
            -
                    NATIVE_ENDIAN:  
     | 
| 
       77 
     | 
    
         
            -
                    ENDIAN_NA:  
     | 
| 
      
 102 
     | 
    
         
            +
                    AGNOSTIC_ENDIAN: "agnostic",
         
     | 
| 
      
 103 
     | 
    
         
            +
                    LITTLE_ENDIAN: "little-endian (VAX)",
         
     | 
| 
      
 104 
     | 
    
         
            +
                    BIG_ENDIAN: "big-endian (network)",
         
     | 
| 
      
 105 
     | 
    
         
            +
                    NATIVE_ENDIAN: "native-endian",
         
     | 
| 
      
 106 
     | 
    
         
            +
                    ENDIAN_NA: "n/a"
         
     | 
| 
       78 
107 
     | 
    
         
             
                  }
         
     | 
| 
       79 
108 
     | 
    
         | 
| 
      
 109 
     | 
    
         
            +
                  # The descriptions of the various types of signedness.
         
     | 
| 
       80 
110 
     | 
    
         
             
                  SIGNED_DESCRIPTIONS = {
         
     | 
| 
       81 
     | 
    
         
            -
                    UNSIGNED:  
     | 
| 
       82 
     | 
    
         
            -
                    SIGNED:  
     | 
| 
       83 
     | 
    
         
            -
                    SIGNED_NA:  
     | 
| 
      
 111 
     | 
    
         
            +
                    UNSIGNED: "unsigned",
         
     | 
| 
      
 112 
     | 
    
         
            +
                    SIGNED: "signed",
         
     | 
| 
      
 113 
     | 
    
         
            +
                    SIGNED_NA: "n/a"
         
     | 
| 
       84 
114 
     | 
    
         
             
                  }
         
     | 
| 
       85 
115 
     | 
    
         | 
| 
      
 116 
     | 
    
         
            +
                  # The descriptions of the various types of sizes.
         
     | 
| 
       86 
117 
     | 
    
         
             
                  SIZE_DESCRIPTIONS = {
         
     | 
| 
       87 
     | 
    
         
            -
                    SIZE_SHORT:  
     | 
| 
       88 
     | 
    
         
            -
                    SIZE_INT:  
     | 
| 
       89 
     | 
    
         
            -
                    SIZE_LONG:  
     | 
| 
       90 
     | 
    
         
            -
                    SIZE_LONG_LONG:  
     | 
| 
       91 
     | 
    
         
            -
                    SIZE_8:  
     | 
| 
       92 
     | 
    
         
            -
                    SIZE_16:  
     | 
| 
       93 
     | 
    
         
            -
                    SIZE_32:  
     | 
| 
       94 
     | 
    
         
            -
                    SIZE_64:  
     | 
| 
       95 
     | 
    
         
            -
                    SIZE_P:  
     | 
| 
      
 118 
     | 
    
         
            +
                    SIZE_SHORT: "short",
         
     | 
| 
      
 119 
     | 
    
         
            +
                    SIZE_INT: "int-width",
         
     | 
| 
      
 120 
     | 
    
         
            +
                    SIZE_LONG: "long",
         
     | 
| 
      
 121 
     | 
    
         
            +
                    SIZE_LONG_LONG: "long long",
         
     | 
| 
      
 122 
     | 
    
         
            +
                    SIZE_8: "8-bit",
         
     | 
| 
      
 123 
     | 
    
         
            +
                    SIZE_16: "16-bit",
         
     | 
| 
      
 124 
     | 
    
         
            +
                    SIZE_32: "32-bit",
         
     | 
| 
      
 125 
     | 
    
         
            +
                    SIZE_64: "64-bit",
         
     | 
| 
      
 126 
     | 
    
         
            +
                    SIZE_P: "pointer-width"
         
     | 
| 
       96 
127 
     | 
    
         
             
                  }
         
     | 
| 
       97 
128 
     | 
    
         | 
| 
      
 129 
     | 
    
         
            +
                  # Provide a human-readable description of the directive.
         
     | 
| 
       98 
130 
     | 
    
         
             
                  def describe
         
     | 
| 
       99 
131 
     | 
    
         
             
                    case type
         
     | 
| 
       100 
132 
     | 
    
         
             
                    when SPACE
         
     | 
| 
       101 
     | 
    
         
            -
                       
     | 
| 
      
 133 
     | 
    
         
            +
                      "whitespace"
         
     | 
| 
       102 
134 
     | 
    
         
             
                    when COMMENT
         
     | 
| 
       103 
     | 
    
         
            -
                       
     | 
| 
      
 135 
     | 
    
         
            +
                      "comment"
         
     | 
| 
       104 
136 
     | 
    
         
             
                    when INTEGER
         
     | 
| 
       105 
137 
     | 
    
         
             
                      if size == SIZE_8
         
     | 
| 
       106 
138 
     | 
    
         
             
                        base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} integer"
         
     | 
| 
         @@ -115,58 +147,65 @@ module Prism 
     | 
|
| 
       115 
147 
     | 
    
         
             
                          base
         
     | 
| 
       116 
148 
     | 
    
         
             
                        end
         
     | 
| 
       117 
149 
     | 
    
         
             
                      when LENGTH_MAX
         
     | 
| 
       118 
     | 
    
         
            -
                        base +  
     | 
| 
      
 150 
     | 
    
         
            +
                        base + ", as many as possible"
         
     | 
| 
       119 
151 
     | 
    
         
             
                      end
         
     | 
| 
       120 
152 
     | 
    
         
             
                    when UTF8
         
     | 
| 
       121 
     | 
    
         
            -
                       
     | 
| 
      
 153 
     | 
    
         
            +
                      "UTF-8 character"
         
     | 
| 
       122 
154 
     | 
    
         
             
                    when BER
         
     | 
| 
       123 
     | 
    
         
            -
                       
     | 
| 
      
 155 
     | 
    
         
            +
                      "BER-compressed integer"
         
     | 
| 
       124 
156 
     | 
    
         
             
                    when FLOAT
         
     | 
| 
       125 
157 
     | 
    
         
             
                      "#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float"
         
     | 
| 
       126 
158 
     | 
    
         
             
                    when STRING_SPACE_PADDED
         
     | 
| 
       127 
     | 
    
         
            -
                       
     | 
| 
      
 159 
     | 
    
         
            +
                      "arbitrary binary string (space padded)"
         
     | 
| 
       128 
160 
     | 
    
         
             
                    when STRING_NULL_PADDED
         
     | 
| 
       129 
     | 
    
         
            -
                       
     | 
| 
      
 161 
     | 
    
         
            +
                      "arbitrary binary string (null padded, count is width)"
         
     | 
| 
       130 
162 
     | 
    
         
             
                    when STRING_NULL_TERMINATED
         
     | 
| 
       131 
     | 
    
         
            -
                       
     | 
| 
      
 163 
     | 
    
         
            +
                      "arbitrary binary string (null padded, count is width), except that null is added with *"
         
     | 
| 
       132 
164 
     | 
    
         
             
                    when STRING_MSB
         
     | 
| 
       133 
     | 
    
         
            -
                       
     | 
| 
      
 165 
     | 
    
         
            +
                      "bit string (MSB first)"
         
     | 
| 
       134 
166 
     | 
    
         
             
                    when STRING_LSB
         
     | 
| 
       135 
     | 
    
         
            -
                       
     | 
| 
      
 167 
     | 
    
         
            +
                      "bit string (LSB first)"
         
     | 
| 
       136 
168 
     | 
    
         
             
                    when STRING_HEX_HIGH
         
     | 
| 
       137 
     | 
    
         
            -
                       
     | 
| 
      
 169 
     | 
    
         
            +
                      "hex string (high nibble first)"
         
     | 
| 
       138 
170 
     | 
    
         
             
                    when STRING_HEX_LOW
         
     | 
| 
       139 
     | 
    
         
            -
                       
     | 
| 
      
 171 
     | 
    
         
            +
                      "hex string (low nibble first)"
         
     | 
| 
       140 
172 
     | 
    
         
             
                    when STRING_UU
         
     | 
| 
       141 
     | 
    
         
            -
                       
     | 
| 
      
 173 
     | 
    
         
            +
                      "UU-encoded string"
         
     | 
| 
       142 
174 
     | 
    
         
             
                    when STRING_MIME
         
     | 
| 
       143 
     | 
    
         
            -
                       
     | 
| 
      
 175 
     | 
    
         
            +
                      "quoted printable, MIME encoding"
         
     | 
| 
       144 
176 
     | 
    
         
             
                    when STRING_BASE64
         
     | 
| 
       145 
     | 
    
         
            -
                       
     | 
| 
      
 177 
     | 
    
         
            +
                      "base64 encoded string"
         
     | 
| 
       146 
178 
     | 
    
         
             
                    when STRING_FIXED
         
     | 
| 
       147 
     | 
    
         
            -
                       
     | 
| 
      
 179 
     | 
    
         
            +
                      "pointer to a structure (fixed-length string)"
         
     | 
| 
       148 
180 
     | 
    
         
             
                    when STRING_POINTER
         
     | 
| 
       149 
     | 
    
         
            -
                       
     | 
| 
      
 181 
     | 
    
         
            +
                      "pointer to a null-terminated string"
         
     | 
| 
       150 
182 
     | 
    
         
             
                    when MOVE
         
     | 
| 
       151 
     | 
    
         
            -
                       
     | 
| 
      
 183 
     | 
    
         
            +
                      "move to absolute position"
         
     | 
| 
       152 
184 
     | 
    
         
             
                    when BACK
         
     | 
| 
       153 
     | 
    
         
            -
                       
     | 
| 
      
 185 
     | 
    
         
            +
                      "back up a byte"
         
     | 
| 
       154 
186 
     | 
    
         
             
                    when NULL
         
     | 
| 
       155 
     | 
    
         
            -
                       
     | 
| 
      
 187 
     | 
    
         
            +
                      "null byte"
         
     | 
| 
       156 
188 
     | 
    
         
             
                    else
         
     | 
| 
       157 
189 
     | 
    
         
             
                      raise
         
     | 
| 
       158 
190 
     | 
    
         
             
                    end
         
     | 
| 
       159 
191 
     | 
    
         
             
                  end
         
     | 
| 
       160 
192 
     | 
    
         
             
                end
         
     | 
| 
       161 
193 
     | 
    
         | 
| 
      
 194 
     | 
    
         
            +
                # The result of parsing a pack template.
         
     | 
| 
       162 
195 
     | 
    
         
             
                class Format
         
     | 
| 
       163 
     | 
    
         
            -
                   
     | 
| 
      
 196 
     | 
    
         
            +
                  # A list of the directives in the template.
         
     | 
| 
      
 197 
     | 
    
         
            +
                  attr_reader :directives
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                  # The encoding of the template.
         
     | 
| 
      
 200 
     | 
    
         
            +
                  attr_reader :encoding
         
     | 
| 
       164 
201 
     | 
    
         | 
| 
      
 202 
     | 
    
         
            +
                  # Create a new Format with the given directives and encoding.
         
     | 
| 
       165 
203 
     | 
    
         
             
                  def initialize(directives, encoding)
         
     | 
| 
       166 
204 
     | 
    
         
             
                    @directives = directives
         
     | 
| 
       167 
205 
     | 
    
         
             
                    @encoding = encoding
         
     | 
| 
       168 
206 
     | 
    
         
             
                  end
         
     | 
| 
       169 
207 
     | 
    
         | 
| 
      
 208 
     | 
    
         
            +
                  # Provide a human-readable description of the format.
         
     | 
| 
       170 
209 
     | 
    
         
             
                  def describe
         
     | 
| 
       171 
210 
     | 
    
         
             
                    source_width = directives.map { |d| d.source.inspect.length }.max
         
     | 
| 
       172 
211 
     | 
    
         
             
                    directive_lines = directives.map do |directive|
         
     | 
| 
         @@ -178,7 +217,7 @@ module Prism 
     | 
|
| 
       178 
217 
     | 
    
         
             
                      "  #{source.ljust(source_width)}  #{directive.describe}"
         
     | 
| 
       179 
218 
     | 
    
         
             
                    end
         
     | 
| 
       180 
219 
     | 
    
         | 
| 
       181 
     | 
    
         
            -
                    ([ 
     | 
| 
      
 220 
     | 
    
         
            +
                    (["Directives:"] + directive_lines + ["Encoding:", "  #{encoding}"]).join("\n")
         
     | 
| 
       182 
221 
     | 
    
         
             
                  end
         
     | 
| 
       183 
222 
     | 
    
         
             
                end
         
     | 
| 
       184 
223 
     | 
    
         
             
              end
         
     | 
| 
         @@ -19,7 +19,7 @@ module Prism 
     | 
|
| 
       19 
19 
     | 
    
         
             
                class Comments
         
     | 
| 
       20 
20 
     | 
    
         
             
                  # A target for attaching comments that is based on a specific node's
         
     | 
| 
       21 
21 
     | 
    
         
             
                  # location.
         
     | 
| 
       22 
     | 
    
         
            -
                  class NodeTarget
         
     | 
| 
      
 22 
     | 
    
         
            +
                  class NodeTarget # :nodoc:
         
     | 
| 
       23 
23 
     | 
    
         
             
                    attr_reader :node
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                    def initialize(node)
         
     | 
| 
         @@ -46,7 +46,7 @@ module Prism 
     | 
|
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                  # A target for attaching comments that is based on a location field on a
         
     | 
| 
       48 
48 
     | 
    
         
             
                  # node. For example, the `end` token of a ClassNode.
         
     | 
| 
       49 
     | 
    
         
            -
                  class LocationTarget
         
     | 
| 
      
 49 
     | 
    
         
            +
                  class LocationTarget # :nodoc:
         
     | 
| 
       50 
50 
     | 
    
         
             
                    attr_reader :location
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
52 
     | 
    
         
             
                    def initialize(location)
         
     | 
| 
         @@ -70,12 +70,17 @@ module Prism 
     | 
|
| 
       70 
70 
     | 
    
         
             
                    end
         
     | 
| 
       71 
71 
     | 
    
         
             
                  end
         
     | 
| 
       72 
72 
     | 
    
         | 
| 
      
 73 
     | 
    
         
            +
                  # The parse result that we are attaching comments to.
         
     | 
| 
       73 
74 
     | 
    
         
             
                  attr_reader :parse_result
         
     | 
| 
       74 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                  # Create a new Comments object that will attach comments to the given
         
     | 
| 
      
 77 
     | 
    
         
            +
                  # parse result.
         
     | 
| 
       75 
78 
     | 
    
         
             
                  def initialize(parse_result)
         
     | 
| 
       76 
79 
     | 
    
         
             
                    @parse_result = parse_result
         
     | 
| 
       77 
80 
     | 
    
         
             
                  end
         
     | 
| 
       78 
81 
     | 
    
         | 
| 
      
 82 
     | 
    
         
            +
                  # Attach the comments to their respective locations in the tree by
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # mutating the parse result.
         
     | 
| 
       79 
84 
     | 
    
         
             
                  def attach!
         
     | 
| 
       80 
85 
     | 
    
         
             
                    parse_result.comments.each do |comment|
         
     | 
| 
       81 
86 
     | 
    
         
             
                      preceding, enclosing, following = nearest_targets(parse_result.value, comment)
         
     | 
| 
         @@ -18,10 +18,12 @@ module Prism 
     | 
|
| 
       18 
18 
     | 
    
         
             
                # MarkNewlinesVisitor, since that visitor is responsible for marking the
         
     | 
| 
       19 
19 
     | 
    
         
             
                # newlines for JRuby/TruffleRuby.
         
     | 
| 
       20 
20 
     | 
    
         
             
                class Newlines < Visitor
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # Create a new Newlines visitor with the given newline offsets.
         
     | 
| 
       21 
22 
     | 
    
         
             
                  def initialize(newline_marked)
         
     | 
| 
       22 
23 
     | 
    
         
             
                    @newline_marked = newline_marked
         
     | 
| 
       23 
24 
     | 
    
         
             
                  end
         
     | 
| 
       24 
25 
     | 
    
         | 
| 
      
 26 
     | 
    
         
            +
                  # Permit block/lambda nodes to mark newlines within themselves.
         
     | 
| 
       25 
27 
     | 
    
         
             
                  def visit_block_node(node)
         
     | 
| 
       26 
28 
     | 
    
         
             
                    old_newline_marked = @newline_marked
         
     | 
| 
       27 
29 
     | 
    
         
             
                    @newline_marked = Array.new(old_newline_marked.size, false)
         
     | 
| 
         @@ -35,6 +37,7 @@ module Prism 
     | 
|
| 
       35 
37 
     | 
    
         | 
| 
       36 
38 
     | 
    
         
             
                  alias_method :visit_lambda_node, :visit_block_node
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
                  # Mark if/unless nodes as newlines.
         
     | 
| 
       38 
41 
     | 
    
         
             
                  def visit_if_node(node)
         
     | 
| 
       39 
42 
     | 
    
         
             
                    node.set_newline_flag(@newline_marked)
         
     | 
| 
       40 
43 
     | 
    
         
             
                    super(node)
         
     | 
| 
         @@ -42,6 +45,7 @@ module Prism 
     | 
|
| 
       42 
45 
     | 
    
         | 
| 
       43 
46 
     | 
    
         
             
                  alias_method :visit_unless_node, :visit_if_node
         
     | 
| 
       44 
47 
     | 
    
         | 
| 
      
 48 
     | 
    
         
            +
                  # Permit statements lists to mark newlines within themselves.
         
     | 
| 
       45 
49 
     | 
    
         
             
                  def visit_statements_node(node)
         
     | 
| 
       46 
50 
     | 
    
         
             
                    node.body.each do |child|
         
     | 
| 
       47 
51 
     | 
    
         
             
                      child.set_newline_flag(@newline_marked)
         
     | 
    
        data/lib/prism/parse_result.rb
    CHANGED
    
    | 
         @@ -5,20 +5,52 @@ module Prism 
     | 
|
| 
       5 
5 
     | 
    
         
             
              # conjunction with locations to allow them to resolve line numbers and source
         
     | 
| 
       6 
6 
     | 
    
         
             
              # ranges.
         
     | 
| 
       7 
7 
     | 
    
         
             
              class Source
         
     | 
| 
       8 
     | 
    
         
            -
                 
     | 
| 
      
 8 
     | 
    
         
            +
                # The source code that this source object represents.
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :source
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                 
     | 
| 
      
 11 
     | 
    
         
            +
                # The line number where this source starts.
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_accessor :start_line
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                # The list of newline byte offsets in the source code.
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :offsets
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                # Create a new source object with the given source code and newline byte
         
     | 
| 
      
 18 
     | 
    
         
            +
                # offsets. If no newline byte offsets are given, they will be computed from
         
     | 
| 
      
 19 
     | 
    
         
            +
                # the source code.
         
     | 
| 
      
 20 
     | 
    
         
            +
                def initialize(source, start_line = 1, offsets = compute_offsets(source))
         
     | 
| 
       11 
21 
     | 
    
         
             
                  @source = source
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @start_line = start_line
         
     | 
| 
       12 
23 
     | 
    
         
             
                  @offsets = offsets
         
     | 
| 
       13 
24 
     | 
    
         
             
                end
         
     | 
| 
       14 
25 
     | 
    
         | 
| 
      
 26 
     | 
    
         
            +
                # Perform a byteslice on the source code using the given byte offset and
         
     | 
| 
      
 27 
     | 
    
         
            +
                # byte length.
         
     | 
| 
       15 
28 
     | 
    
         
             
                def slice(offset, length)
         
     | 
| 
       16 
29 
     | 
    
         
             
                  source.byteslice(offset, length)
         
     | 
| 
       17 
30 
     | 
    
         
             
                end
         
     | 
| 
       18 
31 
     | 
    
         | 
| 
       19 
32 
     | 
    
         
             
                # Binary search through the offsets to find the line number for the given
         
     | 
| 
       20 
     | 
    
         
            -
                # offset.
         
     | 
| 
      
 33 
     | 
    
         
            +
                # byte offset.
         
     | 
| 
       21 
34 
     | 
    
         
             
                def line(value)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  start_line + find_line(value)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                # Return the byte offset of the start of the line corresponding to the given
         
     | 
| 
      
 39 
     | 
    
         
            +
                # byte offset.
         
     | 
| 
      
 40 
     | 
    
         
            +
                def line_offset(value)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  offsets[find_line(value)]
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                # Return the column number for the given byte offset.
         
     | 
| 
      
 45 
     | 
    
         
            +
                def column(value)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  value - offsets[find_line(value)]
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                private
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                # Binary search through the offsets to find the line number for the given
         
     | 
| 
      
 52 
     | 
    
         
            +
                # byte offset.
         
     | 
| 
      
 53 
     | 
    
         
            +
                def find_line(value)
         
     | 
| 
       22 
54 
     | 
    
         
             
                  left = 0
         
     | 
| 
       23 
55 
     | 
    
         
             
                  right = offsets.length - 1
         
     | 
| 
       24 
56 
     | 
    
         | 
| 
         @@ -36,16 +68,8 @@ module Prism 
     | 
|
| 
       36 
68 
     | 
    
         
             
                  left - 1
         
     | 
| 
       37 
69 
     | 
    
         
             
                end
         
     | 
| 
       38 
70 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                 
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                def column(value)
         
     | 
| 
       44 
     | 
    
         
            -
                  value - offsets[line(value)]
         
     | 
| 
       45 
     | 
    
         
            -
                end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                private
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                # Find all of the newlines in the source code and return their byte offsets
         
     | 
| 
      
 72 
     | 
    
         
            +
                # from the start of the string an array.
         
     | 
| 
       49 
73 
     | 
    
         
             
                def compute_offsets(code)
         
     | 
| 
       50 
74 
     | 
    
         
             
                  offsets = [0]
         
     | 
| 
       51 
75 
     | 
    
         
             
                  code.b.scan("\n") { offsets << $~.end(0) }
         
     | 
| 
         @@ -69,6 +93,8 @@ module Prism 
     | 
|
| 
       69 
93 
     | 
    
         
             
                # The list of comments attached to this location
         
     | 
| 
       70 
94 
     | 
    
         
             
                attr_reader :comments
         
     | 
| 
       71 
95 
     | 
    
         | 
| 
      
 96 
     | 
    
         
            +
                # Create a new location object with the given source, start byte offset, and
         
     | 
| 
      
 97 
     | 
    
         
            +
                # byte length.
         
     | 
| 
       72 
98 
     | 
    
         
             
                def initialize(source, start_offset, length)
         
     | 
| 
       73 
99 
     | 
    
         
             
                  @source = source
         
     | 
| 
       74 
100 
     | 
    
         
             
                  @start_offset = start_offset
         
     | 
| 
         @@ -102,7 +128,7 @@ module Prism 
     | 
|
| 
       102 
128 
     | 
    
         | 
| 
       103 
129 
     | 
    
         
             
                # The line number where this location starts.
         
     | 
| 
       104 
130 
     | 
    
         
             
                def start_line
         
     | 
| 
       105 
     | 
    
         
            -
                  source.line(start_offset) 
     | 
| 
      
 131 
     | 
    
         
            +
                  source.line(start_offset)
         
     | 
| 
       106 
132 
     | 
    
         
             
                end
         
     | 
| 
       107 
133 
     | 
    
         | 
| 
       108 
134 
     | 
    
         
             
                # The content of the line where this location starts before this location.
         
     | 
| 
         @@ -113,7 +139,7 @@ module Prism 
     | 
|
| 
       113 
139 
     | 
    
         | 
| 
       114 
140 
     | 
    
         
             
                # The line number where this location ends.
         
     | 
| 
       115 
141 
     | 
    
         
             
                def end_line
         
     | 
| 
       116 
     | 
    
         
            -
                  source.line(end_offset) 
     | 
| 
      
 142 
     | 
    
         
            +
                  source.line(end_offset)
         
     | 
| 
       117 
143 
     | 
    
         
             
                end
         
     | 
| 
       118 
144 
     | 
    
         | 
| 
       119 
145 
     | 
    
         
             
                # The column number in bytes where this location starts from the start of
         
     | 
| 
         @@ -128,14 +154,17 @@ module Prism 
     | 
|
| 
       128 
154 
     | 
    
         
             
                  source.column(end_offset)
         
     | 
| 
       129 
155 
     | 
    
         
             
                end
         
     | 
| 
       130 
156 
     | 
    
         | 
| 
      
 157 
     | 
    
         
            +
                # Implement the hash pattern matching interface for Location.
         
     | 
| 
       131 
158 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       132 
159 
     | 
    
         
             
                  { start_offset: start_offset, end_offset: end_offset }
         
     | 
| 
       133 
160 
     | 
    
         
             
                end
         
     | 
| 
       134 
161 
     | 
    
         | 
| 
      
 162 
     | 
    
         
            +
                # Implement the pretty print interface for Location.
         
     | 
| 
       135 
163 
     | 
    
         
             
                def pretty_print(q)
         
     | 
| 
       136 
164 
     | 
    
         
             
                  q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})")
         
     | 
| 
       137 
165 
     | 
    
         
             
                end
         
     | 
| 
       138 
166 
     | 
    
         | 
| 
      
 167 
     | 
    
         
            +
                # Returns true if the given other location is equal to this location.
         
     | 
| 
       139 
168 
     | 
    
         
             
                def ==(other)
         
     | 
| 
       140 
169 
     | 
    
         
             
                  other.is_a?(Location) &&
         
     | 
| 
       141 
170 
     | 
    
         
             
                    other.start_offset == start_offset &&
         
     | 
| 
         @@ -152,57 +181,99 @@ module Prism 
     | 
|
| 
       152 
181 
     | 
    
         
             
                  Location.new(source, start_offset, other.end_offset - start_offset)
         
     | 
| 
       153 
182 
     | 
    
         
             
                end
         
     | 
| 
       154 
183 
     | 
    
         | 
| 
      
 184 
     | 
    
         
            +
                # Returns a null location that does not correspond to a source and points to
         
     | 
| 
      
 185 
     | 
    
         
            +
                # the beginning of the file. Useful for when you want a location object but
         
     | 
| 
      
 186 
     | 
    
         
            +
                # do not care where it points.
         
     | 
| 
       155 
187 
     | 
    
         
             
                def self.null
         
     | 
| 
       156 
188 
     | 
    
         
             
                  new(nil, 0, 0)
         
     | 
| 
       157 
189 
     | 
    
         
             
                end
         
     | 
| 
       158 
190 
     | 
    
         
             
              end
         
     | 
| 
       159 
191 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
              # This represents a comment that was encountered during parsing.
         
     | 
| 
      
 192 
     | 
    
         
            +
              # This represents a comment that was encountered during parsing. It is the
         
     | 
| 
      
 193 
     | 
    
         
            +
              # base class for all comment types.
         
     | 
| 
       161 
194 
     | 
    
         
             
              class Comment
         
     | 
| 
       162 
     | 
    
         
            -
                 
     | 
| 
      
 195 
     | 
    
         
            +
                # The location of this comment in the source.
         
     | 
| 
      
 196 
     | 
    
         
            +
                attr_reader :location
         
     | 
| 
       163 
197 
     | 
    
         | 
| 
       164 
     | 
    
         
            -
                 
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
                def initialize(type, location)
         
     | 
| 
       167 
     | 
    
         
            -
                  @type = type
         
     | 
| 
      
 198 
     | 
    
         
            +
                # Create a new comment object with the given location.
         
     | 
| 
      
 199 
     | 
    
         
            +
                def initialize(location)
         
     | 
| 
       168 
200 
     | 
    
         
             
                  @location = location
         
     | 
| 
       169 
201 
     | 
    
         
             
                end
         
     | 
| 
       170 
202 
     | 
    
         | 
| 
      
 203 
     | 
    
         
            +
                # Implement the hash pattern matching interface for Comment.
         
     | 
| 
       171 
204 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       172 
     | 
    
         
            -
                  {  
     | 
| 
      
 205 
     | 
    
         
            +
                  { location: location }
         
     | 
| 
       173 
206 
     | 
    
         
             
                end
         
     | 
| 
       174 
207 
     | 
    
         | 
| 
       175 
     | 
    
         
            -
                #  
     | 
| 
      
 208 
     | 
    
         
            +
                # This can only be true for inline comments.
         
     | 
| 
       176 
209 
     | 
    
         
             
                def trailing?
         
     | 
| 
       177 
     | 
    
         
            -
                   
     | 
| 
      
 210 
     | 
    
         
            +
                  false
         
     | 
| 
       178 
211 
     | 
    
         
             
                end
         
     | 
| 
      
 212 
     | 
    
         
            +
              end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
              # InlineComment objects are the most common. They correspond to comments in
         
     | 
| 
      
 215 
     | 
    
         
            +
              # the source file like this one that start with #.
         
     | 
| 
      
 216 
     | 
    
         
            +
              class InlineComment < Comment
         
     | 
| 
      
 217 
     | 
    
         
            +
                # Returns true if this comment happens on the same line as other code and
         
     | 
| 
      
 218 
     | 
    
         
            +
                # false if the comment is by itself.
         
     | 
| 
      
 219 
     | 
    
         
            +
                def trailing?
         
     | 
| 
      
 220 
     | 
    
         
            +
                  !location.start_line_slice.strip.empty?
         
     | 
| 
      
 221 
     | 
    
         
            +
                end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                # Returns a string representation of this comment.
         
     | 
| 
      
 224 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 225 
     | 
    
         
            +
                  "#<Prism::InlineComment @location=#{location.inspect}>"
         
     | 
| 
      
 226 
     | 
    
         
            +
                end
         
     | 
| 
      
 227 
     | 
    
         
            +
              end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
              # EmbDocComment objects correspond to comments that are surrounded by =begin
         
     | 
| 
      
 230 
     | 
    
         
            +
              # and =end.
         
     | 
| 
      
 231 
     | 
    
         
            +
              class EmbDocComment < Comment
         
     | 
| 
      
 232 
     | 
    
         
            +
                # Returns a string representation of this comment.
         
     | 
| 
      
 233 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 234 
     | 
    
         
            +
                  "#<Prism::EmbDocComment @location=#{location.inspect}>"
         
     | 
| 
      
 235 
     | 
    
         
            +
                end
         
     | 
| 
      
 236 
     | 
    
         
            +
              end
         
     | 
| 
       179 
237 
     | 
    
         | 
| 
      
 238 
     | 
    
         
            +
              # DATAComment objects correspond to comments that are after the __END__
         
     | 
| 
      
 239 
     | 
    
         
            +
              # keyword in a source file.
         
     | 
| 
      
 240 
     | 
    
         
            +
              class DATAComment < Comment
         
     | 
| 
      
 241 
     | 
    
         
            +
                # Returns a string representation of this comment.
         
     | 
| 
       180 
242 
     | 
    
         
             
                def inspect
         
     | 
| 
       181 
     | 
    
         
            -
                  "#<Prism:: 
     | 
| 
      
 243 
     | 
    
         
            +
                  "#<Prism::DATAComment @location=#{location.inspect}>"
         
     | 
| 
       182 
244 
     | 
    
         
             
                end
         
     | 
| 
       183 
245 
     | 
    
         
             
              end
         
     | 
| 
       184 
246 
     | 
    
         | 
| 
       185 
247 
     | 
    
         
             
              # This represents a magic comment that was encountered during parsing.
         
     | 
| 
       186 
248 
     | 
    
         
             
              class MagicComment
         
     | 
| 
       187 
     | 
    
         
            -
                 
     | 
| 
      
 249 
     | 
    
         
            +
                # A Location object representing the location of the key in the source.
         
     | 
| 
      
 250 
     | 
    
         
            +
                attr_reader :key_loc
         
     | 
| 
       188 
251 
     | 
    
         | 
| 
      
 252 
     | 
    
         
            +
                # A Location object representing the location of the value in the source.
         
     | 
| 
      
 253 
     | 
    
         
            +
                attr_reader :value_loc
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                # Create a new magic comment object with the given key and value locations.
         
     | 
| 
       189 
256 
     | 
    
         
             
                def initialize(key_loc, value_loc)
         
     | 
| 
       190 
257 
     | 
    
         
             
                  @key_loc = key_loc
         
     | 
| 
       191 
258 
     | 
    
         
             
                  @value_loc = value_loc
         
     | 
| 
       192 
259 
     | 
    
         
             
                end
         
     | 
| 
       193 
260 
     | 
    
         | 
| 
      
 261 
     | 
    
         
            +
                # Returns the key of the magic comment by slicing it from the source code.
         
     | 
| 
       194 
262 
     | 
    
         
             
                def key
         
     | 
| 
       195 
263 
     | 
    
         
             
                  key_loc.slice
         
     | 
| 
       196 
264 
     | 
    
         
             
                end
         
     | 
| 
       197 
265 
     | 
    
         | 
| 
      
 266 
     | 
    
         
            +
                # Returns the value of the magic comment by slicing it from the source code.
         
     | 
| 
       198 
267 
     | 
    
         
             
                def value
         
     | 
| 
       199 
268 
     | 
    
         
             
                  value_loc.slice
         
     | 
| 
       200 
269 
     | 
    
         
             
                end
         
     | 
| 
       201 
270 
     | 
    
         | 
| 
      
 271 
     | 
    
         
            +
                # Implement the hash pattern matching interface for MagicComment.
         
     | 
| 
       202 
272 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       203 
273 
     | 
    
         
             
                  { key_loc: key_loc, value_loc: value_loc }
         
     | 
| 
       204 
274 
     | 
    
         
             
                end
         
     | 
| 
       205 
275 
     | 
    
         | 
| 
      
 276 
     | 
    
         
            +
                # Returns a string representation of this magic comment.
         
     | 
| 
       206 
277 
     | 
    
         
             
                def inspect
         
     | 
| 
       207 
278 
     | 
    
         
             
                  "#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>"
         
     | 
| 
       208 
279 
     | 
    
         
             
                end
         
     | 
| 
         @@ -210,17 +281,24 @@ module Prism 
     | 
|
| 
       210 
281 
     | 
    
         | 
| 
       211 
282 
     | 
    
         
             
              # This represents an error that was encountered during parsing.
         
     | 
| 
       212 
283 
     | 
    
         
             
              class ParseError
         
     | 
| 
       213 
     | 
    
         
            -
                 
     | 
| 
      
 284 
     | 
    
         
            +
                # The message associated with this error.
         
     | 
| 
      
 285 
     | 
    
         
            +
                attr_reader :message
         
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
                # A Location object representing the location of this error in the source.
         
     | 
| 
      
 288 
     | 
    
         
            +
                attr_reader :location
         
     | 
| 
       214 
289 
     | 
    
         | 
| 
      
 290 
     | 
    
         
            +
                # Create a new error object with the given message and location.
         
     | 
| 
       215 
291 
     | 
    
         
             
                def initialize(message, location)
         
     | 
| 
       216 
292 
     | 
    
         
             
                  @message = message
         
     | 
| 
       217 
293 
     | 
    
         
             
                  @location = location
         
     | 
| 
       218 
294 
     | 
    
         
             
                end
         
     | 
| 
       219 
295 
     | 
    
         | 
| 
      
 296 
     | 
    
         
            +
                # Implement the hash pattern matching interface for ParseError.
         
     | 
| 
       220 
297 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       221 
298 
     | 
    
         
             
                  { message: message, location: location }
         
     | 
| 
       222 
299 
     | 
    
         
             
                end
         
     | 
| 
       223 
300 
     | 
    
         | 
| 
      
 301 
     | 
    
         
            +
                # Returns a string representation of this error.
         
     | 
| 
       224 
302 
     | 
    
         
             
                def inspect
         
     | 
| 
       225 
303 
     | 
    
         
             
                  "#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
         
     | 
| 
       226 
304 
     | 
    
         
             
                end
         
     | 
| 
         @@ -228,17 +306,24 @@ module Prism 
     | 
|
| 
       228 
306 
     | 
    
         | 
| 
       229 
307 
     | 
    
         
             
              # This represents a warning that was encountered during parsing.
         
     | 
| 
       230 
308 
     | 
    
         
             
              class ParseWarning
         
     | 
| 
       231 
     | 
    
         
            -
                 
     | 
| 
      
 309 
     | 
    
         
            +
                # The message associated with this warning.
         
     | 
| 
      
 310 
     | 
    
         
            +
                attr_reader :message
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                # A Location object representing the location of this warning in the source.
         
     | 
| 
      
 313 
     | 
    
         
            +
                attr_reader :location
         
     | 
| 
       232 
314 
     | 
    
         | 
| 
      
 315 
     | 
    
         
            +
                # Create a new warning object with the given message and location.
         
     | 
| 
       233 
316 
     | 
    
         
             
                def initialize(message, location)
         
     | 
| 
       234 
317 
     | 
    
         
             
                  @message = message
         
     | 
| 
       235 
318 
     | 
    
         
             
                  @location = location
         
     | 
| 
       236 
319 
     | 
    
         
             
                end
         
     | 
| 
       237 
320 
     | 
    
         | 
| 
      
 321 
     | 
    
         
            +
                # Implement the hash pattern matching interface for ParseWarning.
         
     | 
| 
       238 
322 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       239 
323 
     | 
    
         
             
                  { message: message, location: location }
         
     | 
| 
       240 
324 
     | 
    
         
             
                end
         
     | 
| 
       241 
325 
     | 
    
         | 
| 
      
 326 
     | 
    
         
            +
                # Returns a string representation of this warning.
         
     | 
| 
       242 
327 
     | 
    
         
             
                def inspect
         
     | 
| 
       243 
328 
     | 
    
         
             
                  "#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
         
     | 
| 
       244 
329 
     | 
    
         
             
                end
         
     | 
| 
         @@ -248,8 +333,27 @@ module Prism 
     | 
|
| 
       248 
333 
     | 
    
         
             
              # the AST, any comments that were encounters, and any errors that were
         
     | 
| 
       249 
334 
     | 
    
         
             
              # encountered.
         
     | 
| 
       250 
335 
     | 
    
         
             
              class ParseResult
         
     | 
| 
       251 
     | 
    
         
            -
                 
     | 
| 
      
 336 
     | 
    
         
            +
                # The value that was generated by parsing. Normally this holds the AST, but
         
     | 
| 
      
 337 
     | 
    
         
            +
                # it can sometimes how a list of tokens or other results passed back from
         
     | 
| 
      
 338 
     | 
    
         
            +
                # the parser.
         
     | 
| 
      
 339 
     | 
    
         
            +
                attr_reader :value
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
                # The list of comments that were encountered during parsing.
         
     | 
| 
      
 342 
     | 
    
         
            +
                attr_reader :comments
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
                # The list of magic comments that were encountered during parsing.
         
     | 
| 
      
 345 
     | 
    
         
            +
                attr_reader :magic_comments
         
     | 
| 
       252 
346 
     | 
    
         | 
| 
      
 347 
     | 
    
         
            +
                # The list of errors that were generated during parsing.
         
     | 
| 
      
 348 
     | 
    
         
            +
                attr_reader :errors
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
                # The list of warnings that were generated during parsing.
         
     | 
| 
      
 351 
     | 
    
         
            +
                attr_reader :warnings
         
     | 
| 
      
 352 
     | 
    
         
            +
             
     | 
| 
      
 353 
     | 
    
         
            +
                # A Source instance that represents the source code that was parsed.
         
     | 
| 
      
 354 
     | 
    
         
            +
                attr_reader :source
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
                # Create a new parse result object with the given values.
         
     | 
| 
       253 
357 
     | 
    
         
             
                def initialize(value, comments, magic_comments, errors, warnings, source)
         
     | 
| 
       254 
358 
     | 
    
         
             
                  @value = value
         
     | 
| 
       255 
359 
     | 
    
         
             
                  @comments = comments
         
     | 
| 
         @@ -259,14 +363,19 @@ module Prism 
     | 
|
| 
       259 
363 
     | 
    
         
             
                  @source = source
         
     | 
| 
       260 
364 
     | 
    
         
             
                end
         
     | 
| 
       261 
365 
     | 
    
         | 
| 
      
 366 
     | 
    
         
            +
                # Implement the hash pattern matching interface for ParseResult.
         
     | 
| 
       262 
367 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       263 
368 
     | 
    
         
             
                  { value: value, comments: comments, magic_comments: magic_comments, errors: errors, warnings: warnings }
         
     | 
| 
       264 
369 
     | 
    
         
             
                end
         
     | 
| 
       265 
370 
     | 
    
         | 
| 
      
 371 
     | 
    
         
            +
                # Returns true if there were no errors during parsing and false if there
         
     | 
| 
      
 372 
     | 
    
         
            +
                # were.
         
     | 
| 
       266 
373 
     | 
    
         
             
                def success?
         
     | 
| 
       267 
374 
     | 
    
         
             
                  errors.empty?
         
     | 
| 
       268 
375 
     | 
    
         
             
                end
         
     | 
| 
       269 
376 
     | 
    
         | 
| 
      
 377 
     | 
    
         
            +
                # Returns true if there were errors during parsing and false if there were
         
     | 
| 
      
 378 
     | 
    
         
            +
                # not.
         
     | 
| 
       270 
379 
     | 
    
         
             
                def failure?
         
     | 
| 
       271 
380 
     | 
    
         
             
                  !success?
         
     | 
| 
       272 
381 
     | 
    
         
             
                end
         
     | 
| 
         @@ -274,18 +383,28 @@ module Prism 
     | 
|
| 
       274 
383 
     | 
    
         | 
| 
       275 
384 
     | 
    
         
             
              # This represents a token from the Ruby source.
         
     | 
| 
       276 
385 
     | 
    
         
             
              class Token
         
     | 
| 
       277 
     | 
    
         
            -
                 
     | 
| 
      
 386 
     | 
    
         
            +
                # The type of token that this token is.
         
     | 
| 
      
 387 
     | 
    
         
            +
                attr_reader :type
         
     | 
| 
      
 388 
     | 
    
         
            +
             
     | 
| 
      
 389 
     | 
    
         
            +
                # A byteslice of the source that this token represents.
         
     | 
| 
      
 390 
     | 
    
         
            +
                attr_reader :value
         
     | 
| 
      
 391 
     | 
    
         
            +
             
     | 
| 
      
 392 
     | 
    
         
            +
                # A Location object representing the location of this token in the source.
         
     | 
| 
      
 393 
     | 
    
         
            +
                attr_reader :location
         
     | 
| 
       278 
394 
     | 
    
         | 
| 
      
 395 
     | 
    
         
            +
                # Create a new token object with the given type, value, and location.
         
     | 
| 
       279 
396 
     | 
    
         
             
                def initialize(type, value, location)
         
     | 
| 
       280 
397 
     | 
    
         
             
                  @type = type
         
     | 
| 
       281 
398 
     | 
    
         
             
                  @value = value
         
     | 
| 
       282 
399 
     | 
    
         
             
                  @location = location
         
     | 
| 
       283 
400 
     | 
    
         
             
                end
         
     | 
| 
       284 
401 
     | 
    
         | 
| 
      
 402 
     | 
    
         
            +
                # Implement the hash pattern matching interface for Token.
         
     | 
| 
       285 
403 
     | 
    
         
             
                def deconstruct_keys(keys)
         
     | 
| 
       286 
404 
     | 
    
         
             
                  { type: type, value: value, location: location }
         
     | 
| 
       287 
405 
     | 
    
         
             
                end
         
     | 
| 
       288 
406 
     | 
    
         | 
| 
      
 407 
     | 
    
         
            +
                # Implement the pretty print interface for Token.
         
     | 
| 
       289 
408 
     | 
    
         
             
                def pretty_print(q)
         
     | 
| 
       290 
409 
     | 
    
         
             
                  q.group do
         
     | 
| 
       291 
410 
     | 
    
         
             
                    q.text(type.to_s)
         
     | 
| 
         @@ -300,6 +419,7 @@ module Prism 
     | 
|
| 
       300 
419 
     | 
    
         
             
                  end
         
     | 
| 
       301 
420 
     | 
    
         
             
                end
         
     | 
| 
       302 
421 
     | 
    
         | 
| 
      
 422 
     | 
    
         
            +
                # Returns true if the given other token is equal to this token.
         
     | 
| 
       303 
423 
     | 
    
         
             
                def ==(other)
         
     | 
| 
       304 
424 
     | 
    
         
             
                  other.is_a?(Token) &&
         
     | 
| 
       305 
425 
     | 
    
         
             
                    other.type == type &&
         
     | 
    
        data/lib/prism/pattern.rb
    CHANGED
    
    | 
         @@ -38,6 +38,8 @@ module Prism 
     | 
|
| 
       38 
38 
     | 
    
         
             
                # Raised when the query given to a pattern is either invalid Ruby syntax or
         
     | 
| 
       39 
39 
     | 
    
         
             
                # is using syntax that we don't yet support.
         
     | 
| 
       40 
40 
     | 
    
         
             
                class CompilationError < StandardError
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # Create a new CompilationError with the given representation of the node
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # that caused the error.
         
     | 
| 
       41 
43 
     | 
    
         
             
                  def initialize(repr)
         
     | 
| 
       42 
44 
     | 
    
         
             
                    super(<<~ERROR)
         
     | 
| 
       43 
45 
     | 
    
         
             
                      prism was unable to compile the pattern you provided into a usable
         
     | 
| 
         @@ -53,18 +55,27 @@ module Prism 
     | 
|
| 
       53 
55 
     | 
    
         
             
                  end
         
     | 
| 
       54 
56 
     | 
    
         
             
                end
         
     | 
| 
       55 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
                # The query that this pattern was initialized with.
         
     | 
| 
       56 
59 
     | 
    
         
             
                attr_reader :query
         
     | 
| 
       57 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
                # Create a new pattern with the given query. The query should be a string
         
     | 
| 
      
 62 
     | 
    
         
            +
                # containing a Ruby pattern matching expression.
         
     | 
| 
       58 
63 
     | 
    
         
             
                def initialize(query)
         
     | 
| 
       59 
64 
     | 
    
         
             
                  @query = query
         
     | 
| 
       60 
65 
     | 
    
         
             
                  @compiled = nil
         
     | 
| 
       61 
66 
     | 
    
         
             
                end
         
     | 
| 
       62 
67 
     | 
    
         | 
| 
      
 68 
     | 
    
         
            +
                # Compile the query into a callable object that can be used to match against
         
     | 
| 
      
 69 
     | 
    
         
            +
                # nodes.
         
     | 
| 
       63 
70 
     | 
    
         
             
                def compile
         
     | 
| 
       64 
71 
     | 
    
         
             
                  result = Prism.parse("case nil\nin #{query}\nend")
         
     | 
| 
       65 
72 
     | 
    
         
             
                  compile_node(result.value.statements.body.last.conditions.last.pattern)
         
     | 
| 
       66 
73 
     | 
    
         
             
                end
         
     | 
| 
       67 
74 
     | 
    
         | 
| 
      
 75 
     | 
    
         
            +
                # Scan the given node and all of its children for nodes that match the
         
     | 
| 
      
 76 
     | 
    
         
            +
                # pattern. If a block is given, it will be called with each node that
         
     | 
| 
      
 77 
     | 
    
         
            +
                # matches the pattern. If no block is given, an enumerator will be returned
         
     | 
| 
      
 78 
     | 
    
         
            +
                # that will yield each node that matches the pattern.
         
     | 
| 
       68 
79 
     | 
    
         
             
                def scan(root)
         
     | 
| 
       69 
80 
     | 
    
         
             
                  return to_enum(__method__, root) unless block_given?
         
     | 
| 
       70 
81 
     | 
    
         |