prism 0.23.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/prism/ffi.rb CHANGED
@@ -119,15 +119,12 @@ module Prism
119
119
 
120
120
  # Initialize a new buffer and yield it to the block. The buffer will be
121
121
  # automatically freed when the block returns.
122
- def self.with(&block)
123
- pointer = FFI::MemoryPointer.new(SIZEOF)
124
-
125
- begin
122
+ def self.with
123
+ FFI::MemoryPointer.new(SIZEOF) do |pointer|
126
124
  raise unless LibRubyParser.pm_buffer_init(pointer)
127
- yield new(pointer)
125
+ return yield new(pointer)
128
126
  ensure
129
127
  LibRubyParser.pm_buffer_free(pointer)
130
- pointer.free
131
128
  end
132
129
  end
133
130
  end
@@ -137,39 +134,47 @@ module Prism
137
134
  class PrismString # :nodoc:
138
135
  SIZEOF = LibRubyParser.pm_string_sizeof
139
136
 
140
- attr_reader :pointer
137
+ attr_reader :pointer, :length
141
138
 
142
- def initialize(pointer)
139
+ def initialize(pointer, length, from_string)
143
140
  @pointer = pointer
144
- end
145
-
146
- def source
147
- LibRubyParser.pm_string_source(pointer)
148
- end
149
-
150
- def length
151
- LibRubyParser.pm_string_length(pointer)
141
+ @length = length
142
+ @from_string = from_string
152
143
  end
153
144
 
154
145
  def read
155
- source.read_string(length)
146
+ raise "should use the original String instead" if @from_string
147
+ @pointer.read_string(@length)
156
148
  end
157
149
 
158
150
  # Yields a pm_string_t pointer to the given block.
159
- def self.with(filepath, &block)
160
- pointer = FFI::MemoryPointer.new(SIZEOF)
161
-
162
- begin
163
- raise TypeError unless filepath.is_a?(String)
151
+ def self.with_string(string)
152
+ raise TypeError unless string.is_a?(String)
153
+
154
+ length = string.bytesize
155
+ # + 1 to never get an address of 0, which pm_parser_init() asserts
156
+ FFI::MemoryPointer.new(:char, length + 1, false) do |pointer|
157
+ pointer.write_string(string)
158
+ # since we have the extra byte we might as well \0-terminate
159
+ pointer.put_char(length, 0)
160
+ return yield new(pointer, length, true)
161
+ end
162
+ end
164
163
 
165
- if LibRubyParser.pm_string_mapped_init(pointer, filepath)
166
- yield new(pointer)
164
+ # Yields a pm_string_t pointer to the given block.
165
+ def self.with_file(filepath)
166
+ raise TypeError unless filepath.is_a?(String)
167
+
168
+ FFI::MemoryPointer.new(SIZEOF) do |pm_string|
169
+ if LibRubyParser.pm_string_mapped_init(pm_string, filepath)
170
+ pointer = LibRubyParser.pm_string_source(pm_string)
171
+ length = LibRubyParser.pm_string_length(pm_string)
172
+ return yield new(pointer, length, false)
167
173
  else
168
174
  raise SystemCallError.new(filepath, FFI.errno)
169
175
  end
170
176
  ensure
171
- LibRubyParser.pm_string_free(pointer)
172
- pointer.free
177
+ LibRubyParser.pm_string_free(pm_string)
173
178
  end
174
179
  end
175
180
  end
@@ -185,52 +190,100 @@ module Prism
185
190
  class << self
186
191
  # Mirror the Prism.dump API by using the serialization API.
187
192
  def dump(code, **options)
188
- LibRubyParser::PrismBuffer.with do |buffer|
189
- LibRubyParser.pm_serialize_parse(buffer.pointer, code, code.bytesize, dump_options(options))
190
- buffer.read
191
- end
193
+ LibRubyParser::PrismString.with_string(code) { |string| dump_common(string, options) }
192
194
  end
193
195
 
194
196
  # Mirror the Prism.dump_file API by using the serialization API.
195
197
  def dump_file(filepath, **options)
196
- LibRubyParser::PrismString.with(filepath) do |string|
197
- dump(string.read, **options, filepath: filepath)
198
- end
198
+ options[:filepath] = filepath
199
+ LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) }
199
200
  end
200
201
 
201
202
  # Mirror the Prism.lex API by using the serialization API.
202
203
  def lex(code, **options)
203
- LibRubyParser::PrismBuffer.with do |buffer|
204
- LibRubyParser.pm_serialize_lex(buffer.pointer, code, code.bytesize, dump_options(options))
205
- Serialize.load_tokens(Source.new(code), buffer.read)
206
- end
204
+ LibRubyParser::PrismString.with_string(code) { |string| lex_common(string, code, options) }
207
205
  end
208
206
 
209
207
  # Mirror the Prism.lex_file API by using the serialization API.
210
208
  def lex_file(filepath, **options)
211
- LibRubyParser::PrismString.with(filepath) do |string|
212
- lex(string.read, **options, filepath: filepath)
213
- end
209
+ options[:filepath] = filepath
210
+ LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) }
214
211
  end
215
212
 
216
213
  # Mirror the Prism.parse API by using the serialization API.
217
214
  def parse(code, **options)
218
- Prism.load(code, dump(code, **options))
215
+ LibRubyParser::PrismString.with_string(code) { |string| parse_common(string, code, options) }
219
216
  end
220
217
 
221
218
  # Mirror the Prism.parse_file API by using the serialization API. This uses
222
219
  # native strings instead of Ruby strings because it allows us to use mmap when
223
220
  # it is available.
224
221
  def parse_file(filepath, **options)
225
- LibRubyParser::PrismString.with(filepath) do |string|
226
- parse(string.read, **options, filepath: filepath)
227
- end
222
+ options[:filepath] = filepath
223
+ LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
228
224
  end
229
225
 
230
226
  # Mirror the Prism.parse_comments API by using the serialization API.
231
227
  def parse_comments(code, **options)
228
+ LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) }
229
+ end
230
+
231
+ # Mirror the Prism.parse_file_comments API by using the serialization
232
+ # API. This uses native strings instead of Ruby strings because it allows us
233
+ # to use mmap when it is available.
234
+ def parse_file_comments(filepath, **options)
235
+ options[:filepath] = filepath
236
+ LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
237
+ end
238
+
239
+ # Mirror the Prism.parse_lex API by using the serialization API.
240
+ def parse_lex(code, **options)
241
+ LibRubyParser::PrismString.with_string(code) { |string| parse_lex_common(string, code, options) }
242
+ end
243
+
244
+ # Mirror the Prism.parse_lex_file API by using the serialization API.
245
+ def parse_lex_file(filepath, **options)
246
+ options[:filepath] = filepath
247
+ LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
248
+ end
249
+
250
+ # Mirror the Prism.parse_success? API by using the serialization API.
251
+ def parse_success?(code, **options)
252
+ LibRubyParser::PrismString.with_string(code) { |string| parse_file_success_common(string, options) }
253
+ end
254
+
255
+ # Mirror the Prism.parse_file_success? API by using the serialization API.
256
+ def parse_file_success?(filepath, **options)
257
+ options[:filepath] = filepath
258
+ LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) }
259
+ end
260
+
261
+ private
262
+
263
+ def dump_common(string, options) # :nodoc:
264
+ LibRubyParser::PrismBuffer.with do |buffer|
265
+ LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
266
+ buffer.read
267
+ end
268
+ end
269
+
270
+ def lex_common(string, code, options) # :nodoc:
271
+ serialized = LibRubyParser::PrismBuffer.with do |buffer|
272
+ LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
273
+ buffer.read
274
+ end
275
+
276
+ Serialize.load_tokens(Source.new(code), serialized)
277
+ end
278
+
279
+ def parse_common(string, code, options) # :nodoc:
280
+ serialized = dump_common(string, options)
281
+ Prism.load(code, serialized)
282
+ end
283
+
284
+ def parse_comments_common(string, code, options) # :nodoc:
232
285
  LibRubyParser::PrismBuffer.with do |buffer|
233
- LibRubyParser.pm_serialize_parse_comments(buffer.pointer, code, code.bytesize, dump_options(options))
286
+ LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
234
287
 
235
288
  source = Source.new(code)
236
289
  loader = Serialize::Loader.new(source, buffer.read)
@@ -242,19 +295,9 @@ module Prism
242
295
  end
243
296
  end
244
297
 
245
- # Mirror the Prism.parse_file_comments API by using the serialization
246
- # API. This uses native strings instead of Ruby strings because it allows us
247
- # to use mmap when it is available.
248
- def parse_file_comments(filepath, **options)
249
- LibRubyParser::PrismString.with(filepath) do |string|
250
- parse_comments(string.read, **options, filepath: filepath)
251
- end
252
- end
253
-
254
- # Mirror the Prism.parse_lex API by using the serialization API.
255
- def parse_lex(code, **options)
298
+ def parse_lex_common(string, code, options) # :nodoc:
256
299
  LibRubyParser::PrismBuffer.with do |buffer|
257
- LibRubyParser.pm_serialize_parse_lex(buffer.pointer, code, code.bytesize, dump_options(options))
300
+ LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
258
301
 
259
302
  source = Source.new(code)
260
303
  loader = Serialize::Loader.new(source, buffer.read)
@@ -267,27 +310,10 @@ module Prism
267
310
  end
268
311
  end
269
312
 
270
- # Mirror the Prism.parse_lex_file API by using the serialization API.
271
- def parse_lex_file(filepath, **options)
272
- LibRubyParser::PrismString.with(filepath) do |string|
273
- parse_lex(string.read, **options, filepath: filepath)
274
- end
275
- end
276
-
277
- # Mirror the Prism.parse_success? API by using the serialization API.
278
- def parse_success?(code, **options)
279
- LibRubyParser.pm_parse_success_p(code, code.bytesize, dump_options(options))
280
- end
281
-
282
- # Mirror the Prism.parse_file_success? API by using the serialization API.
283
- def parse_file_success?(filepath, **options)
284
- LibRubyParser::PrismString.with(filepath) do |string|
285
- parse_success?(string.read, **options, filepath: filepath)
286
- end
313
+ def parse_file_success_common(string, options) # :nodoc:
314
+ LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
287
315
  end
288
316
 
289
- private
290
-
291
317
  # Convert the given options into a serialized options string.
292
318
  def dump_options(options)
293
319
  template = +""