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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/Makefile +6 -0
  4. data/README.md +1 -1
  5. data/config.yml +50 -35
  6. data/docs/fuzzing.md +1 -1
  7. data/docs/serialization.md +28 -29
  8. data/ext/prism/api_node.c +802 -770
  9. data/ext/prism/api_pack.c +20 -9
  10. data/ext/prism/extension.c +464 -162
  11. data/ext/prism/extension.h +1 -1
  12. data/include/prism/ast.h +3173 -763
  13. data/include/prism/defines.h +32 -9
  14. data/include/prism/diagnostic.h +36 -3
  15. data/include/prism/enc/pm_encoding.h +118 -28
  16. data/include/prism/node.h +38 -13
  17. data/include/prism/options.h +204 -0
  18. data/include/prism/pack.h +44 -33
  19. data/include/prism/parser.h +445 -200
  20. data/include/prism/prettyprint.h +12 -1
  21. data/include/prism/regexp.h +16 -2
  22. data/include/prism/util/pm_buffer.h +94 -16
  23. data/include/prism/util/pm_char.h +162 -48
  24. data/include/prism/util/pm_constant_pool.h +126 -32
  25. data/include/prism/util/pm_list.h +68 -38
  26. data/include/prism/util/pm_memchr.h +18 -3
  27. data/include/prism/util/pm_newline_list.h +70 -27
  28. data/include/prism/util/pm_state_stack.h +25 -7
  29. data/include/prism/util/pm_string.h +115 -27
  30. data/include/prism/util/pm_string_list.h +25 -6
  31. data/include/prism/util/pm_strncasecmp.h +32 -0
  32. data/include/prism/util/pm_strpbrk.h +31 -17
  33. data/include/prism/version.h +27 -2
  34. data/include/prism.h +224 -31
  35. data/lib/prism/compiler.rb +6 -3
  36. data/lib/prism/debug.rb +23 -7
  37. data/lib/prism/dispatcher.rb +33 -18
  38. data/lib/prism/dsl.rb +10 -5
  39. data/lib/prism/ffi.rb +132 -80
  40. data/lib/prism/lex_compat.rb +25 -15
  41. data/lib/prism/mutation_compiler.rb +10 -5
  42. data/lib/prism/node.rb +370 -135
  43. data/lib/prism/node_ext.rb +1 -1
  44. data/lib/prism/node_inspector.rb +1 -1
  45. data/lib/prism/pack.rb +79 -40
  46. data/lib/prism/parse_result/comments.rb +7 -2
  47. data/lib/prism/parse_result/newlines.rb +4 -0
  48. data/lib/prism/parse_result.rb +150 -30
  49. data/lib/prism/pattern.rb +11 -0
  50. data/lib/prism/ripper_compat.rb +28 -10
  51. data/lib/prism/serialize.rb +86 -54
  52. data/lib/prism/visitor.rb +10 -3
  53. data/lib/prism.rb +20 -2
  54. data/prism.gemspec +4 -2
  55. data/rbi/prism.rbi +104 -60
  56. data/rbi/prism_static.rbi +16 -2
  57. data/sig/prism.rbs +72 -43
  58. data/sig/prism_static.rbs +14 -1
  59. data/src/diagnostic.c +56 -53
  60. data/src/enc/pm_big5.c +1 -0
  61. data/src/enc/pm_euc_jp.c +1 -0
  62. data/src/enc/pm_gbk.c +1 -0
  63. data/src/enc/pm_shift_jis.c +1 -0
  64. data/src/enc/pm_tables.c +316 -80
  65. data/src/enc/pm_unicode.c +53 -8
  66. data/src/enc/pm_windows_31j.c +1 -0
  67. data/src/node.c +334 -321
  68. data/src/options.c +170 -0
  69. data/src/prettyprint.c +74 -47
  70. data/src/prism.c +1642 -856
  71. data/src/regexp.c +151 -95
  72. data/src/serialize.c +44 -20
  73. data/src/token_type.c +3 -1
  74. data/src/util/pm_buffer.c +45 -15
  75. data/src/util/pm_char.c +103 -57
  76. data/src/util/pm_constant_pool.c +51 -21
  77. data/src/util/pm_list.c +12 -4
  78. data/src/util/pm_memchr.c +5 -3
  79. data/src/util/pm_newline_list.c +20 -12
  80. data/src/util/pm_state_stack.c +9 -3
  81. data/src/util/pm_string.c +95 -85
  82. data/src/util/pm_string_list.c +14 -15
  83. data/src/util/pm_strncasecmp.c +10 -3
  84. data/src/util/pm_strpbrk.c +25 -19
  85. metadata +5 -3
  86. data/docs/prism.png +0 -0
@@ -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
@@ -3,7 +3,7 @@
3
3
  module Prism
4
4
  # This object is responsible for generating the output for the inspect method
5
5
  # implementations of child nodes.
6
- class NodeInspector
6
+ class NodeInspector # :nodoc:
7
7
  attr_reader :prefix, :output
8
8
 
9
9
  def initialize(prefix = "")
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
- attr_reader :version, :variant, :source, :type, :signed, :endian, :size, :length_type, :length
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: 'agnostic',
74
- LITTLE_ENDIAN: 'little-endian (VAX)',
75
- BIG_ENDIAN: 'big-endian (network)',
76
- NATIVE_ENDIAN: 'native-endian',
77
- ENDIAN_NA: 'n/a'
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: 'unsigned',
82
- SIGNED: 'signed',
83
- SIGNED_NA: 'n/a'
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: 'short',
88
- SIZE_INT: 'int-width',
89
- SIZE_LONG: 'long',
90
- SIZE_LONG_LONG: 'long long',
91
- SIZE_8: '8-bit',
92
- SIZE_16: '16-bit',
93
- SIZE_32: '32-bit',
94
- SIZE_64: '64-bit',
95
- SIZE_P: 'pointer-width'
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
- 'whitespace'
133
+ "whitespace"
102
134
  when COMMENT
103
- 'comment'
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 + ', as many as possible'
150
+ base + ", as many as possible"
119
151
  end
120
152
  when UTF8
121
- 'UTF-8 character'
153
+ "UTF-8 character"
122
154
  when BER
123
- 'BER-compressed integer'
155
+ "BER-compressed integer"
124
156
  when FLOAT
125
157
  "#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float"
126
158
  when STRING_SPACE_PADDED
127
- 'arbitrary binary string (space padded)'
159
+ "arbitrary binary string (space padded)"
128
160
  when STRING_NULL_PADDED
129
- 'arbitrary binary string (null padded, count is width)'
161
+ "arbitrary binary string (null padded, count is width)"
130
162
  when STRING_NULL_TERMINATED
131
- 'arbitrary binary string (null padded, count is width), except that null is added with *'
163
+ "arbitrary binary string (null padded, count is width), except that null is added with *"
132
164
  when STRING_MSB
133
- 'bit string (MSB first)'
165
+ "bit string (MSB first)"
134
166
  when STRING_LSB
135
- 'bit string (LSB first)'
167
+ "bit string (LSB first)"
136
168
  when STRING_HEX_HIGH
137
- 'hex string (high nibble first)'
169
+ "hex string (high nibble first)"
138
170
  when STRING_HEX_LOW
139
- 'hex string (low nibble first)'
171
+ "hex string (low nibble first)"
140
172
  when STRING_UU
141
- 'UU-encoded string'
173
+ "UU-encoded string"
142
174
  when STRING_MIME
143
- 'quoted printable, MIME encoding'
175
+ "quoted printable, MIME encoding"
144
176
  when STRING_BASE64
145
- 'base64 encoded string'
177
+ "base64 encoded string"
146
178
  when STRING_FIXED
147
- 'pointer to a structure (fixed-length string)'
179
+ "pointer to a structure (fixed-length string)"
148
180
  when STRING_POINTER
149
- 'pointer to a null-terminated string'
181
+ "pointer to a null-terminated string"
150
182
  when MOVE
151
- 'move to absolute position'
183
+ "move to absolute position"
152
184
  when BACK
153
- 'back up a byte'
185
+ "back up a byte"
154
186
  when NULL
155
- 'null byte'
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
- attr_reader :directives, :encoding
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
- (['Directives:'] + directive_lines + ['Encoding:', " #{encoding}"]).join("\n")
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)
@@ -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
- attr_reader :source, :offsets
8
+ # The source code that this source object represents.
9
+ attr_reader :source
9
10
 
10
- def initialize(source, offsets = compute_offsets(source))
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
- def line_offset(value)
40
- offsets[line(value)]
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) + 1
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) + 1
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
- TYPES = [:inline, :embdoc, :__END__]
195
+ # The location of this comment in the source.
196
+ attr_reader :location
163
197
 
164
- attr_reader :type, :location
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
- { type: type, location: location }
205
+ { location: location }
173
206
  end
174
207
 
175
- # Returns true if the comment happens on the same line as other code and false if the comment is by itself
208
+ # This can only be true for inline comments.
176
209
  def trailing?
177
- type == :inline && !location.start_line_slice.strip.empty?
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::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"
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
- attr_reader :key_loc, :value_loc
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
- attr_reader :message, :location
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
- attr_reader :message, :location
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
- attr_reader :value, :comments, :magic_comments, :errors, :warnings, :source
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
- attr_reader :type, :value, :location
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